1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-08-22 01:49:28 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
07338325e5 devices: fix name handling
- Fix cases where incorrect device paths were left
  on the dev->aliases list.  Leaving incorrect paths
  on dev->aliases could result in using the wrong device.

- Fix a widespread incorrect assumption that dev_name()
  always returns a valid path (or NULL).  dev_name()
  returns "[unknown]" when there are no paths to a
  device, and is mainly meant to be used in messages.

- Check for valid dev paths in cases that want to use
  the from dev_name() for things other than a message.
2022-02-24 15:37:53 -06:00
972 changed files with 42544 additions and 91768 deletions

32
.gitignore vendored
View File

@ -14,14 +14,8 @@
*.so *.so
*.so.* *.so.*
*.sw* *.sw*
*.su
*.patch
*~ *~
# gcov files:
*.gcda
*.gcno
.export.sym .export.sym
.exported_symbols_generated .exported_symbols_generated
.gdb_history .gdb_history
@ -45,19 +39,12 @@ make.tmpl
coverity/coverity_model.xml coverity/coverity_model.xml
/.cache/ # gcov files:
/compile_commands.json *.gcda
*.gcno
/doc/.ikiwiki
/public
/libdm/.symver_check
daemons/clvmd
daemons/dmfilemapd
daemons/lvmetad/
tools/man-generator tools/man-generator
tools/man-generator.c
test/.lib-dir-stamp test/.lib-dir-stamp
test/.tests-stamp test/.tests-stamp
@ -115,8 +102,6 @@ test/api/thin_percent.t
test/api/vglist.t test/api/vglist.t
test/api/vgtest.t test/api/vgtest.t
test/lib/aux test/lib/aux
test/lib/cache-mq.profile
test/lib/cache-smq.profile
test/lib/check test/lib/check
test/lib/clvmd test/lib/clvmd
test/lib/dm-version-expected test/lib/dm-version-expected
@ -126,7 +111,6 @@ test/lib/dmstats
test/lib/fail test/lib/fail
test/lib/flavour-ndev-cluster test/lib/flavour-ndev-cluster
test/lib/flavour-ndev-cluster-lvmpolld test/lib/flavour-ndev-cluster-lvmpolld
test/lib/flavour-ndev-devicesfile
test/lib/flavour-ndev-lvmetad test/lib/flavour-ndev-lvmetad
test/lib/flavour-ndev-lvmetad-lvmpolld test/lib/flavour-ndev-lvmetad-lvmpolld
test/lib/flavour-ndev-lvmpolld test/lib/flavour-ndev-lvmpolld
@ -136,7 +120,6 @@ test/lib/flavour-udev-cluster-lvmpolld
test/lib/flavour-udev-lvmetad test/lib/flavour-udev-lvmetad
test/lib/flavour-udev-lvmetad-lvmpolld test/lib/flavour-udev-lvmetad-lvmpolld
test/lib/flavour-udev-lvmlockd-dlm test/lib/flavour-udev-lvmlockd-dlm
test/lib/flavour-udev-lvmlockd-idm
test/lib/flavour-udev-lvmlockd-sanlock test/lib/flavour-udev-lvmlockd-sanlock
test/lib/flavour-udev-lvmlockd-test test/lib/flavour-udev-lvmlockd-test
test/lib/flavour-udev-lvmpolld test/lib/flavour-udev-lvmpolld
@ -149,13 +132,8 @@ test/lib/lvm
test/lib/lvm-wrapper test/lib/lvm-wrapper
test/lib/lvmchange test/lib/lvmchange
test/lib/lvmdbusd.profile test/lib/lvmdbusd.profile
test/lib/lvmdevices
test/lib/lvmetad test/lib/lvmetad
test/lib/lvmlockctl
test/lib/lvmlockd
test/lib/lvmpolld test/lib/lvmpolld
test/lib/lvm_import_vdo
test/lib/lvm_vdo_wrapper
test/lib/not test/lib/not
test/lib/paths test/lib/paths
test/lib/paths-common test/lib/paths-common
@ -165,7 +143,5 @@ test/lib/test
test/lib/thin-performance.profile test/lib/thin-performance.profile
test/lib/utils test/lib/utils
test/lib/version-expected test/lib/version-expected
test/lib/vgimportdevices
test/unit/dmraid_t.c test/unit/dmraid_t.c
test/unit/unit-test test/unit/unit-test

View File

@ -1,104 +0,0 @@
stages:
- approve
- test
approve1:
stage: approve
script:
- echo "Approved..."
rules:
# TODO: Filter only safe repositories, or user in developers
- if: $CI_PROJECT_PATH != "csonto/lvm2" && $CI_PROJECT_PATH != "lvmteam/lvm2"
when: manual
# TODO: for other branches than main/rhel: run pipeline only when requested:
- if: $CI_COMMIT_BRANCH != "main" && $CI_COMMIT_BRANCH !~ "^rhel.*"
when: manual
- when: on_success
allow_failure: false
pages:
image: elecnix/ikiwiki
stage: test
script:
- ikiwiki --setup ikiwiki.setup --libdir themes/ikistrap/lib
artifacts:
paths:
- public
only:
refs:
- main
changes:
- doc/**/*
- ikiwiki.setup
# TODO:
# - check results of autoreconf and make generate - may need additional commit
# - we need a particular setup (rawhide OR latest supported fedora?)
# - do make rpm and publish results as artifacts - we will use packit/COPR for this eventually
# Run on any commits to main (master), rhel8, rhel9 branches
test-job:
stage: test
parallel:
matrix:
- TAG: rhel8
CONFIGURE: >
--with-cluster=internal
--enable-cmirrord
- TAG: rhel9
CONFIGURE: >
--with-default-use-devices-file=1
--enable-app-machineid
--enable-editline
--disable-readline
artifacts:
paths:
- test/results/
expire_in: 1 week
tags:
- ${TAG}
timeout: 2h
script:
# Common options go here, diffs to the above matrix
- >
./configure ${CONFIGURE}
--enable-fsadm
--enable-write_install
--enable-pkgconfig
--enable-cmdlib
--enable-dmeventd
--enable-blkid_wiping
--enable-udev_sync
--with-thin=internal
--with-cache=internal
--enable-lvmpolld
--enable-lvmlockd-dlm --enable-lvmlockd-dlmcontrol
--enable-lvmlockd-sanlock
--enable-dbus-service --enable-notify-dbus
--enable-dmfilemapd
--with-writecache=internal
--with-vdo=internal --with-vdo-format=/usr/bin/vdoformat
--with-integrity=internal
--disable-silent-rules
- make
- rm -rf test/results
- mkdir -p /dev/shm/lvm2-test
- mount -o remount,dev /dev/shm
# TODO: Need to distinguish failed test from failed harness
# TODO: Also need a way to find if run is incomplete, e.g. full disk resulting in many skipped tests
- VERBOSE=0 BATCH=1 LVM_TEST_DIR=/dev/shm/lvm2-test make check || true
- rm -rf /dev/shm/lvm2-test
- cut -d' ' -f2 test/results/list | sort | uniq -c
# Filter artifacts - keep only logs from tests which are not pass
- cd test/results && rm $(grep 'passed$' list | cut -d' ' -f1 | sed -e 's|/|_|g' -e 's|.*|\0.txt|')
# TODO: Keep a list of known failures, and translate into regexp - or simply use python...
- if grep failed test/results/list | grep -v '\\\(dbustest\|lvconvert-mirror\)\.sh' | sort; then false; else true; fi
rules:
# Filter only safe repositories, or user in developers:
# NOTE: Already done in approve stage, may be more caution than necessary
- if: $CI_PROJECT_PATH != "csonto/lvm2" && $CI_PROJECT_PATH != "lvmteam/lvm2"
when: manual
- when: on_success

View File

@ -38,7 +38,7 @@ ifeq ($(MAKECMDGOALS),distclean)
udev po udev po
tools.distclean: test.distclean tools.distclean: test.distclean
endif endif
DISTCLEAN_DIRS += lcov_reports* autom4te.cache DISTCLEAN_DIRS += lcov_reports*
DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
include make.tmpl include make.tmpl
@ -47,7 +47,7 @@ include $(top_srcdir)/base/Makefile
include $(top_srcdir)/device_mapper/Makefile include $(top_srcdir)/device_mapper/Makefile
include $(top_srcdir)/test/unit/Makefile include $(top_srcdir)/test/unit/Makefile
lib: include libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET) lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
daemons: lib libdaemon tools daemons: lib libdaemon tools
scripts: lib scripts: lib
tools: lib libdaemon tools: lib libdaemon
@ -55,7 +55,7 @@ po: tools daemons
man: tools man: tools
all_man: tools all_man: tools
test: tools daemons test: tools daemons
unit-test run-unit-test: test libdm unit-test run-unit-test: test
daemons.device-mapper: libdm.device-mapper daemons.device-mapper: libdm.device-mapper
tools.device-mapper: libdm.device-mapper tools.device-mapper: libdm.device-mapper
@ -127,7 +127,6 @@ all_man:
install_system_dirs: install_system_dirs:
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR) $(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)/devices
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR) $(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_BACKUP_DIR) $(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_BACKUP_DIR)
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_CACHE_DIR) $(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_CACHE_DIR)
@ -172,7 +171,6 @@ help:
@echo " lcov-dated Generate lcov with timedate suffix." @echo " lcov-dated Generate lcov with timedate suffix."
@echo " lcov-reset Reset lcov counters" @echo " lcov-reset Reset lcov counters"
@echo " man Build man pages." @echo " man Build man pages."
@echo " print-VARIABLE Resolve make variable."
@echo " rpm Build rpm." @echo " rpm Build rpm."
@echo " run-unit-test Run unit tests." @echo " run-unit-test Run unit tests."
@echo " tags Generate c/etags." @echo " tags Generate c/etags."
@ -194,8 +192,7 @@ ifneq ("$(GENHTML)", "")
lcov: lcov:
$(RM) -rf $(LCOV_REPORTS_DIR) $(RM) -rf $(LCOV_REPORTS_DIR)
$(MKDIR_P) $(LCOV_REPORTS_DIR) $(MKDIR_P) $(LCOV_REPORTS_DIR)
-find . -name '*.gc[dn][ao]' ! -newer make.tmpl -delete $(LCOV) --capture --directory $(top_builddir) --ignore-errors source \
-$(LCOV) --capture --directory $(top_builddir) --ignore-errors source,negative,gcov \
--output-file $(LCOV_REPORTS_DIR)/out.info --output-file $(LCOV_REPORTS_DIR)/out.info
-test ! -s $(LCOV_REPORTS_DIR)/out.info || \ -test ! -s $(LCOV_REPORTS_DIR)/out.info || \
$(GENHTML) -o $(LCOV_REPORTS_DIR) --ignore-errors source \ $(GENHTML) -o $(LCOV_REPORTS_DIR) --ignore-errors source \

29
README
View File

@ -1,5 +1,7 @@
This tree contains the LVM2 and device-mapper tools and libraries. This tree contains the LVM2 and device-mapper tools and libraries.
This is development branch, for stable 2.02 release see stable-2.02 branch.
For more information about LVM2 read the changelog in the WHATS_NEW file. For more information about LVM2 read the changelog in the WHATS_NEW file.
Installation instructions are in INSTALL. Installation instructions are in INSTALL.
@ -10,30 +12,20 @@ Tarballs are available from:
https://github.com/lvmteam/lvm2/releases https://github.com/lvmteam/lvm2/releases
The source code is stored in git: The source code is stored in git:
https://gitlab.com/lvmteam/lvm2 https://sourceware.org/git/?p=lvm2.git
Clone: git clone git://sourceware.org/git/lvm2.git
git clone git@gitlab.com:lvmteam/lvm2.git mirrored to:
Anonymous access: https://github.com/lvmteam/lvm2
git clone https://gitlab.com/lvmteam/lvm2.git
Mirrored to:
* https://github.com/lvmteam/lvm2
git clone https://github.com/lvmteam/lvm2.git git clone https://github.com/lvmteam/lvm2.git
git clone git@github.com:lvmteam/lvm2.git git clone git@github.com:lvmteam/lvm2.git
* https://sourceware.org/git/?p=lvm2.git
git clone https://sourceware.org/git/lvm2.git
git clone git://sourceware.org/git/lvm2.git
Mailing list for general discussion related to LVM2: Mailing list for general discussion related to LVM2:
linux-lvm@lists.linux.dev linux-lvm@redhat.com
Subscribe via email to: linux-lvm+subscribe@lists.linux.dev Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm
Archive https://lore.kernel.org/linux-lvm/
Older archive https://listman.redhat.com/archives/linux-lvm/
Mailing lists for LVM2 development, patches and commits: Mailing lists for LVM2 development, patches and commits:
lvm-devel@lists.linux.dev lvm-devel@redhat.com
Subscribe via email to: lvm-devel+subscribe@lists.linux.dev Subscribe from https://www.redhat.com/mailman/listinfo/lvm-devel
Archive https://lore.kernel.org/lvm-devel/
Older archive https://listman.redhat.com/archives/lvm-devel/
lvm2-commits@lists.fedorahosted.org (Read-only archive of commits) lvm2-commits@lists.fedorahosted.org (Read-only archive of commits)
Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits
@ -49,7 +41,6 @@ Website:
Report upstream bugs at: Report upstream bugs at:
https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper
or open issues at: or open issues at:
https://gitlab.com/groups/lvmteam/-/issues
https://github.com/lvmteam/lvm2/issues https://github.com/lvmteam/lvm2/issues
The source code repository used until 7th June 2012 is accessible using CVS: The source code repository used until 7th June 2012 is accessible using CVS:

View File

@ -21,15 +21,10 @@ You MUST disable (or mask) any LVM daemons:
- clvmd - clvmd
- cmirrord - cmirrord
Some lvm.conf options should be set:
- global/event_activation = 0
- activation/monitoring = 0
For running cluster tests, we are using singlenode locking. Pass For running cluster tests, we are using singlenode locking. Pass
`--with-clvmd=singlenode` to configure. `--with-clvmd=singlenode` to configure.
NOTE: This is useful only for testing, and should not be used in production NOTE: This is useful only for testing, and should not be used in produciton
code. code.
To run D-Bus daemon tests, existing D-Bus session is required. To run D-Bus daemon tests, existing D-Bus session is required.

View File

@ -1 +1 @@
2.03.35(2)-git (2025-07-30) 2.03.16(2)-git (2022-02-07)

View File

@ -1 +1 @@
1.02.209-git (2025-07-30) 1.02.185-git (2022-02-07)

432
WHATS_NEW
View File

@ -1,279 +1,5 @@
Version 2.03.35 - Version 2.03.16 -
==================
Fix possible report output format inconsistencies while processing PVs.
Allow report options for pv/vg/lvdisplay only if used with -C|--columns.
Fix vgsplit failing to split a VG with RAID+integrity or cache with cachevol.
Optimize dmeventd when remonitoring active devices.
Version 2.03.34 - 30th July 2025
================================
Support dmeventd restart when there are no monitored devices.
Dmeventd no longer calls 'action commands' on removed devices.
Fix reader of VDO metadata on 32bit architecture.
Fix lvmdevices --deldev/--delpvid to error out if devices file not writeable.
Fix lvresize corruption in LV->crypt->FS stack if near crypt min size limit.
Enhanced lvresize -r support for btrfs.
Use glibc standard functions htoX, Xtoh functions for endian conversion.
Fix structure copying within sanlock's release_rename().
Fix autoactivation on top of loop dev PVs to trigger once for change uevents.
Add lvmlockd --lockopt repair to reinitialize corrupted sanlock leases.
Fix support for lvcreate -T --setautoactivation.
Add lvm.conf global/lvresize_fs_helper_executable.
Enable lvm to use persistent reservations on a VG.
Version 2.03.33 - 27th June 2025
================================
Various spelling, grammar, formatting, test, and build script improvements.
Override LC_NUMERIC locale if unsuitable for json_std report format.
Repair raid arrays with transiently lost devices.
Version 2.03.32 - 05th May 2025
===============================
Lvconvert vdopool conversion properly validates acceptable LVs.
Accept thin pool data LV as cacheable LV.
Allow using zram block devices (likely for testing).
Fix lvresize when resizing COW snapshots already covering origin.
Fix lvmdbusd read of executed lvm commands output.
Fix construction of DM UUID for cachevol _cdata and _cmeta devices.
Ignore PV claims from old metadata when then PV belongs to a new VG.
Fix integrity metadata rounding.
Accept --autobackup option in pvresize.
Version 2.03.31 - 27th February 2025
==================================== ====================================
Reduce 'mandoc -T lint' reported issues for man pages.
Restore support for LVM_SUPPRESS_FD_WARNINGS (2.03.24).
Fix uncache and split cache restoring original state of volume.
Extend use of lockopt skip to more scenarios.
Enhance error path resolving in polling code.
Disallow shared activation of LV with CoW snapshot.
Fix lvmlockd use in lvremove of CoW snapshot, VDO pool, and uncache.
Improve mirror split with opened temporary volumes.
Improve pvmove finish with opened temporary volumes.
Fix backup limit for devices file, handle over 10,000 files.
Ignore reported optimal_io_size not divisible by 4096.
Fix busy-loop in config reading when read returned 0.
Fix DM cache preserving logic (2.03.28).
Improve use of lvmlockd for usecases involving thin volumes and pools.
Version 2.03.30 - 14th January 2025
===================================
Lvresize reports origin vdo volume cannot be resized.
Support setting reserved_memory|stack of --config cmdline.
Fix support for disabling memory locking (2.03.27).
Do not extend an LV if FS resize unsupported and '--fs resize' used.
Prevent leftover temporary device when converting in use volume to a pool.
lvconvert detects early volume in use when converting it to a pool.
Handle NVMe with quirk changed WWID not matching WWID in devices file.
Version 2.03.29 - 09th December 2024
====================================
Configure --enable/disable-sd-notify to control lvmlockd build with sd-notify.
Allow test mode when lvmlockd is built without dlm support.
Add a note about RAID + integrity synchronization to lvmraid(7) man page.
Add a function for running lvconvert --repair on RAID LVs to lvmdbusd.
Improve option section of man pages for listing commands ({pv,lv,vg}{s,display}).
Fix renaming of raid sub LVs when converting a volume to raid (2.03.28).
Fix segfault/VG write error for raid LV lvextend -i|--stripes -I|--stripesize.
Revert ignore -i|--stripes, -I|--stripesize for lvextend on raid0 LV (2.03.27).
Version 2.03.28 - 04th November 2024
====================================
Use radix_tree to lookup for UUID within committed metadata.
Use radix_tree to lookup LV list entry within VG struct.
Introduce setting config/validate_metadata = full | none.
Restore fs resize call for lvresize -r on the same size LV (2.03.17).
Correct off-by-one devicesfile backup counting.
Replace use of dm_hash with radix_tree for lv names and uuids.
Refactor vg_validate with uniq_insert and better use of CPU caches.
Add radix_tree_uniq_insert.
Update DM cache when taking next VG lock instead of dropping it.
Generate json string id only for json reporting.
For vgsummary use new API call dm_config_parse_only_section().
Use radix_tree for PV names mapping.
Split check_lv_segment into separate _in/complete_vg variant.
Use find_lv instead of find_lv_in_vg when possible.
Do a mirror fixup only when mirrors with logs are imported.
Add faster crc32 calculation from zlib code for x86_64.
Fall back to direct zeroing if BLKZEROOUT fails during new LV initialization.
Version 2.03.27 - 02nd October 2024
===================================
Fix swap device size detection using blkid for lvresize/lvreduce/lvextend.
Detect GPT partition table and pass partition filter if no partitions defined.
Add global/sanlock_align_size option to configure sanlock lease size.
Disable mem locking when activation/reserved_stack or reserved_memory is 0.
Fix locking issues in lvmlockd leaving thin pool locked.
Deprecate vdo settings vdo_write_policy and vdo_write_policy.
Lots of typo fixes across lvm2 code base (codespell).
Corrected integrity parameter interleave_sectors for DM table line.
Ignore -i|--stripes, -I|--stripesize for lvextend on raid0 LV, like raid10.
Do not accept duplicate device names for pvcreate.
Version 2.03.26 - 23rd August 2024
==================================
Fix internal error reported by pvmove on a VG with single PV.
Also accept --mknodes --refresh for vgscan.
Fix vgmknodes --refresh to wait for udev before checking /dev content.
Use log/report_command_log=1 config setting by default for JSON output format.
Fix unreleased memory pools on RAID lvextend.
Add --integritysettings option to manipulate dm-integrity settings.
Version 2.03.25 - 12nd July 2024
================================
Utilize more radix_tree instead of dm_hash and btree.
Refactor DM uuid caching from device_mapper directory.
Enhance checking for DM uuid device.
Fix lvm shell command completion on tab key (2.03.24).
Avoid lockd_vg call to lvmlockd for local VGs.
Allow forced change of locktype from none.
Handle OPTIONS defined in /etc/sysconfig/lvmlockd.
Version 2.03.24 - 16th May 2024
===============================
Lvconvert supports VDO options for thin-pool with vdo conversion.
Improve placement to .data.rel.ro and .rodata sections.
Fix support for -y and -W when creating thinpool with vdo.
Better support for runtime valgrind detection.
Allow command interruption when communicating with dmeventd.
Fix resize of VDO volume used for thin pool data volume.
Use -Wl,-z,now and -Wl,--as-needed for compilation by default.
Require 3.7 as minimal version for sanlock.
Share code for closing opened descriptors on program startup.
Fix memleak in lvmcache.
Add configure --with-default-event-activation=ON setting.
Fix return value from reporter function when hitting internal error.
Skip checking of pools for lvremove and vgremove commands.
VDO modprobes dm-vdo for 6.9 kernel and kvdo for older kernel version.
Fix lvs reporting for VDO volumes with new upstream kernel driver.
Don't import DM_UDEV_DISABLE_OTHER_RULES_FLAG in LVM rules, DM rules cover it.
Fix table line generation for cache snapshots using cachevol.
Enhance lvconvert support for external origins stacking.
When swapping LV names also swap properties like hostname, time and data.
Fix removal of stacked external origins.
Lock filesystem when converting volume to read-only external origin.
Support external origin between different thin-pool.
Improve validation of acceptable volumes for external origins.
Reduce amount of preloaded devices for complex device trees.
Avoid logging problems from monitoring snapshots with inactive origins.
Check for cache policy module presence in kernel's builtin modules file.
Add configure --with-modulesdir to select kernel modules directory.
Support creation of thin-pool with VDO use for its data volume.
Version 2.03.23 - 21st November 2023
====================================
Set the first lv_attr flag for raid integrity images to i or I.
Add -A option for pvs and pvscan to show PVs outside devices file.
Improve searched_devnames temp file usage to prevent redundant scanning.
Change default search_for_devnames from auto to all.
Add lvmdevices --refresh to search for missing PVIDs on all devices.
Add comparison between old and new entries in lvmdevices --check.
Fix device_id matching order - match non-devname first.
Fix "lvconvert -m 0" when there is other than first in-sync leg.
Use system.devices as default for dmeventd when dmeventd.devices is undefined.
Accept WWIDs containing QEMU HARDDISK for device_id.
Improve handling of non-standard WWID prefixes used for device_id.
Configure automatically enables cmdlib for dmeventd and notify-dbus for dbus.
Fix hint calculation for pools with zero or error segment.
Configure supports --disable-shared to build only static binaries.
Configure supports --without-{blkid|systemd|udev} for easier static build.
Refresh device ids if the system changes.
Fix pvmove when specifying raid components as moved LVs.
Enhance error detection for lvm_import_vdo.
Support PV lists with thin lvconvert.
Fix support for lvm_import_vdo with SCSI VDO volumes.
Fix locking issue leading to hanging concurrent vgchange --refresh.
Recognise lvm.conf report/headings=2 for full column names in report headings.
Add --headings none|abbrev|full cmd line option to set report headings type.
Fix conversion to thin pool using lvmlockd.
Fix conversion from thick into thin volume using lvmlockd.
Require writable LV for conversion to vdo pool.
Fix return value from lvconvert integrity remove.
Preserve UUID for pool metadata spare.
Preserve UUID for swapped pool metadata.
Rewrite validation of device name entries used as device_id.
version 2.03.22 - 02nd August 2023
==================================
Fix pv_major/pv_minor report field types so they are integers, not strings.
Add lvmdevices --delnotfound to delete entries for missing devices.
Always use cachepool name for metadata backup LV for lvconvert --repair.
Make metadata backup LVs read-only after pool's lvconvert --repair.
Improve VDO and Thin support with lvmlockd.
Handle 'lvextend --usepolicies' for pools for all activation variants.
Fix memleak in vgchange autoactivation setup.
Update py-compile building script.
Support conversion from thick to fully provisioned thin LV.
Cache/Thin-pool can use error and zero volumes for testing.
Individual thin volume can be cached, but cannot take snapshot.
Better internal support for handling error and zero target (for testing).
Resize COW above trimmed maximal size is does not return error.
Support parsing of vdo geometry format version 4.
Add lvm.conf thin_restore and cache_restore settings.
Handle multiple mounts while resizing volume with a FS.
Handle leading/trailing spaces in sys_wwid and sys_serial used by device_id.
Enhance lvm_import_vdo and use snapshot when converting VDO volume.
Fix parsing of VDO metadata.
Fix failing -S|--select for non-reporting cmds if using LV info/status fields.
Allow snapshots of raid+integrity LV.
Fix multisegment RAID1 allocator to prevent using single disk for more legs.
version 2.03.21 - 21st April 2023
=================================
Fix activation of vdo-pool for with 0 length headers (converted pools).
Avoid printing internal init messages when creation integration devices.
Allow (write)cache over raid+integrity LV.
version 2.03.20 - 21st March 2023
=================================
Fix segfault if using -S|--select with log/report_command_log=1 setting.
Configure now fails when requested lvmlockd dependencies are missing.
Add some configure Gentoo enhancements for static builds.
version 2.03.19 - 21st February 2023
====================================
Configure supports --with-systemd-run executed from udev rules.
Enhancement for build with MuslC systemd and non-bash system shells (dash).
Do not reset SYSTEMD_READY variable in udev for PVs on MD and loop devices.
Ensure udev is processing origin LV before its thick snapshots LVs.
Fix and improve runtime memory size detection for VDO volumes.
version 2.03.18 - 22nd December 2022
====================================
Fix issues reported by coverity scan.
Fix warning for thin pool overprovisioning on lvextend (2.03.17).
Add support for writecache metadata_only and pause_writeback settings.
Fix missing error messages in lvmdbusd.
Version 2.03.17 - 10th November 2022
====================================
Add new options (--fs, --fsmode) for FS handling when resizing LVs.
Fix 'lvremove -S|--select LV' to not also remove its historical LV right away.
Fix lv_active field type to binary so --select and --binary applies properly.
Switch to use mallinfo2 and use it only with glibc.
Error out in lvm shell if using a cmd argument not supported in the shell.
Fix lvm shell's lastlog command to report previous pre-command failures.
Keep libaio locked in memory in critical section.
Extend VDO and VDOPOOL without flushing and locking fs.
Add --valuesonly option to lvmconfig to print only values without keys.
Updates configure with recent autoconf tooling.
Fix lvconvert --test --type vdo-pool execution.
Add json_std output format for more JSON standard compliant version of output.
Fix vdo_slab_size_mb value for converted VDO volume.
Fix many corner cases in device_id, including handling of S/N duplicates.
Fix various issues in lvmdbusd.
Version 2.03.16 - 18th May 2022
===============================
Fix segfault when handling selection with historical LVs.
Add support --vdosettings with lvcreate, lvconvert, lvchange.
Filtering multipath devices respects blacklist setting from multipath
configuration.
lvmdevices support for removing by device id using --deviceidtype and
--deldev.
Display writecache block size with lvs -o writecache_block_size.
Improve cachesettings description in man lvmcache.
Fix losing of delete message on thin-pool extension.
Version 2.03.15 - 07th February 2022 Version 2.03.15 - 07th February 2022
==================================== ====================================
@ -360,8 +86,8 @@ Version 2.03.12 - 07th May 2021
Fix problem with unbound variable usage within fsadm. Fix problem with unbound variable usage within fsadm.
Fix IMSM MD RAID detection on 4k devices. Fix IMSM MD RAID detection on 4k devices.
Check for presence of VDO target before starting any conversion. Check for presence of VDO target before starting any conversion.
Support metadata profiles with volume VDO pool conversions. Support metatadata profiles with volume VDO pool conversions.
Support -Zn for conversion of already formatted VDO pools. Support -Zn for conversion of already formated VDO pools.
Avoid removing LVs on error path of lvconvert during creation volumes. Avoid removing LVs on error path of lvconvert during creation volumes.
Fix crashing lvdisplay when thin volume was waiting for merge. Fix crashing lvdisplay when thin volume was waiting for merge.
Support option --errorwhenfull when converting volume to thin-pool. Support option --errorwhenfull when converting volume to thin-pool.
@ -391,7 +117,7 @@ Version 2.03.11 - 08th January 2021
Enhance error handling for fsadm and handle correct fsck result. Enhance error handling for fsadm and handle correct fsck result.
Dmeventd lvm plugin ignores higher reserved_stack lvm.conf values. Dmeventd lvm plugin ignores higher reserved_stack lvm.conf values.
Support using BLKZEROOUT for clearing devices. Support using BLKZEROOUT for clearing devices.
Support interruption when wiping LVs. Support interruption when wipping LVs.
Support interruption for bcache waiting. Support interruption for bcache waiting.
Fix bcache when device has too many failing writes. Fix bcache when device has too many failing writes.
Fix bcache waiting for IO completion with failing disks. Fix bcache waiting for IO completion with failing disks.
@ -434,7 +160,7 @@ Version 2.03.10 - 09th August 2020
Version 2.03.09 - 26th March 2020 Version 2.03.09 - 26th March 2020
================================= =================================
Fix formatting of vdopool (vdo_slab_size_mb was smaller by 2 bits). Fix formating of vdopool (vdo_slab_size_mb was smaller by 2 bits).
Fix showing of a dm kernel error when uncaching a volume with cachevol. Fix showing of a dm kernel error when uncaching a volume with cachevol.
Version 2.03.08 - 11th February 2020 Version 2.03.08 - 11th February 2020
@ -518,7 +244,7 @@ Version 2.03.03 - 07th June 2019
Ignore foreign and shared PVs for pvscan online files. Ignore foreign and shared PVs for pvscan online files.
Add config setting to control fields in debug file and verbose output. Add config setting to control fields in debug file and verbose output.
Add command[pid] and timestamp to debug file and verbose output. Add command[pid] and timestamp to debug file and verbose output.
Fix missing growth of _pmspare volume when extending _tmeta volume. Fix missing growth of _pmsmare volume when extending _tmeta volume.
Automatically grow thin metadata, when thin data gets too big. Automatically grow thin metadata, when thin data gets too big.
Add synchronization with udev before removing cached devices. Add synchronization with udev before removing cached devices.
Add support for caching VDO LVs and VDOPOOL LVs. Add support for caching VDO LVs and VDOPOOL LVs.
@ -531,14 +257,14 @@ Version 2.03.03 - 07th June 2019
Change scan_lvs default to 0 so LVs are not scanned for PVs. Change scan_lvs default to 0 so LVs are not scanned for PVs.
Thin-pool selects power-of-2 chunk size by default. Thin-pool selects power-of-2 chunk size by default.
Cache selects power-of-2 chunk size by default. Cache selects power-of-2 chunk size by default.
Support resizing for VDOPoolLV and VDOLV. Support reszing for VDOPoolLV and VDOLV.
Improve -lXXX%VG modifier which improves cache segment estimation. Improve -lXXX%VG modifier which improves cache segment estimation.
Ensure migration_threshold for cache is at least 8 chunks. Ensure migration_threshold for cache is at least 8 chunks.
Restore missing man info lvcreate --zero for thin-pools. Restore missing man info lvcreate --zero for thin-pools.
Drop misleading comment for metadata minimum_io_size for VDO segment. Drop misleadning comment for metadata minimum_io_size for VDO segment.
Add device hints to reduce scanning. Add device hints to reduce scanning.
Introduce LVM_SUPPRESS_SYSLOG to suppress syslog usage by generator. Introduce LVM_SUPPRESS_SYSLOG to suppress syslog usage by generator.
Fix generator querying lvmconfig unpresent config option. Fix generator quering lvmconfig unpresent config option.
Fix memleak on bcache error path code. Fix memleak on bcache error path code.
Fix missing unlock on lvm2 dmeventd plugin error path initialization. Fix missing unlock on lvm2 dmeventd plugin error path initialization.
Improve Makefile dependency tracking. Improve Makefile dependency tracking.
@ -600,7 +326,7 @@ Version 2.02.178-rc1 - 24th May 2018
--with-cache switch for ./configure has been removed. --with-cache switch for ./configure has been removed.
Include new unit-test framework and unit tests. Include new unit-test framework and unit tests.
Extend validation of region_size for mirror segment. Extend validation of region_size for mirror segment.
Reload whole device stack when reinitializing mirror log. Reload whole device stack when reinitilizing mirror log.
Mirrors without monitoring are WARNING and not blocking on error. Mirrors without monitoring are WARNING and not blocking on error.
Detect too big region_size with clustered mirrors. Detect too big region_size with clustered mirrors.
Fix evaluation of maximal region size for mirror log. Fix evaluation of maximal region size for mirror log.
@ -645,7 +371,7 @@ Version 2.02.178-rc1 - 24th May 2018
Restore pvmove support for wide-clustered active volumes (2.02.177). Restore pvmove support for wide-clustered active volumes (2.02.177).
Avoid non-exclusive activation of exclusive segment types. Avoid non-exclusive activation of exclusive segment types.
Fix trimming sibling PVs when doing a pvmove of raid subLVs. Fix trimming sibling PVs when doing a pvmove of raid subLVs.
Preserve exclusive activation during thin snapshot merge. Preserve exclusive activation during thin snaphost merge.
Avoid exceeding array bounds in allocation tag processing. Avoid exceeding array bounds in allocation tag processing.
Add --lockopt to common options and add option to skip selected locks. Add --lockopt to common options and add option to skip selected locks.
@ -661,7 +387,7 @@ Version 2.02.177 - 18th December 2017
Fix lvmlockd to use pool lock when accessing _tmeta volume. Fix lvmlockd to use pool lock when accessing _tmeta volume.
Report expected sanlock_convert errors only when retries fail. Report expected sanlock_convert errors only when retries fail.
Avoid blocking in sanlock_convert on SH to EX lock conversion. Avoid blocking in sanlock_convert on SH to EX lock conversion.
Deactivate missing raid LV legs (_rimage_X-missing_Y_Z) on deactivation. Deactivate missing raid LV legs (_rimage_X-missing_Y_Z) on decativation.
Skip read-modify-write when entire block is replaced. Skip read-modify-write when entire block is replaced.
Categorise I/O with reason annotations in debug messages. Categorise I/O with reason annotations in debug messages.
Allow extending of raid LVs created with --nosync after a failed repair. Allow extending of raid LVs created with --nosync after a failed repair.
@ -683,7 +409,7 @@ Version 2.02.177 - 18th December 2017
Check raid reshape flags in vg_validate(). Check raid reshape flags in vg_validate().
Add support for pvmove of cache and snapshot origins. Add support for pvmove of cache and snapshot origins.
Avoid using precommitted metadata for suspending pvmove tree. Avoid using precommitted metadata for suspending pvmove tree.
Enhance pvmove locking. Ehnance pvmove locking.
Deactivate activated LVs on error path when pvmove activation fails. Deactivate activated LVs on error path when pvmove activation fails.
Add "io" to log/debug_classes for logging low-level I/O. Add "io" to log/debug_classes for logging low-level I/O.
Eliminate redundant nested VG metadata in VG struct. Eliminate redundant nested VG metadata in VG struct.
@ -773,13 +499,13 @@ Version 2.02.173 - 20th July 2017
Version 2.02.172 - 28th June 2017 Version 2.02.172 - 28th June 2017
================================= =================================
Add missing NULL to argv array when splitting cmdline arguments. Add missing NULL to argv array when spliting cmdline arguments.
Add display_percent helper function for printing percent values. Add display_percent helper function for printing percent values.
lvconvert --repair handles failing raid legs (present but marked 'D'ead). lvconvert --repair handles failing raid legs (present but marked 'D'ead).
Do not lvdisplay --maps unset settings of cache pool. Do not lvdisplay --maps unset settings of cache pool.
Fix lvdisplay --maps for cache pool without policy settings. Fix lvdisplay --maps for cache pool without policy settings.
Support aborting of flushing cache LV. Support aborting of flushing cache LV.
Re-enable conversion of data and metadata thin-pool volumes to raid. Reenable conversion of data and metadata thin-pool volumes to raid.
Improve raid status reporting with lvs. Improve raid status reporting with lvs.
No longer necessary to '--force' a repair for RAID1. No longer necessary to '--force' a repair for RAID1.
Linear to RAID1 upconverts now use "recover" sync action, not "resync". Linear to RAID1 upconverts now use "recover" sync action, not "resync".
@ -847,7 +573,7 @@ Version 2.02.169 - 28th March 2017
Support cache segment with configurable metadata format. Support cache segment with configurable metadata format.
Add allocation/cache_metadata_format profilable settings. Add allocation/cache_metadata_format profilable settings.
Use function cache_set_params() for both lvcreate and lvconvert. Use function cache_set_params() for both lvcreate and lvconvert.
Skip rounding on cache chunk size boundary when create cache LV. Skip rounding on cache chunk size boudary when create cache LV.
Improve cache_set_params support for chunk_size selection. Improve cache_set_params support for chunk_size selection.
Fix metadata profile allocation/cache_[mode|policy] setting. Fix metadata profile allocation/cache_[mode|policy] setting.
Fix missing support for using allocation/cache_pool_chunk_size setting. Fix missing support for using allocation/cache_pool_chunk_size setting.
@ -897,8 +623,8 @@ Version 2.02.169 - 28th March 2017
Extend metadata validation of external origin LV use count. Extend metadata validation of external origin LV use count.
Fix dm table when the last user of active external origin is removed. Fix dm table when the last user of active external origin is removed.
Improve reported lvs status for active external origin volume. Improve reported lvs status for active external origin volume.
Fix table load for split RAID LV and require explicit activation. Fix table load for splitted RAID LV and require explicit activation.
Always active split RAID LV exclusively locally. Always active splitted RAID LV exclusively locally.
Do not use LV RAID status bit for segment status. Do not use LV RAID status bit for segment status.
Check segtype directly instead of checking RAID in segment status. Check segtype directly instead of checking RAID in segment status.
Reusing exiting code for raid image removal. Reusing exiting code for raid image removal.
@ -961,7 +687,7 @@ Version 2.02.166 - 26th September 2016
Use --alloc normal for mirror logs even if the mimages were stricter. Use --alloc normal for mirror logs even if the mimages were stricter.
Use O_DIRECT to gather metadata in lvmdump. Use O_DIRECT to gather metadata in lvmdump.
Ignore creation_time when checking for matching metadata for lvmetad. Ignore creation_time when checking for matching metadata for lvmetad.
Fix possible NULL pointer dereference when checking for monitoring. Fix possible NULL pointer derefence when checking for monitoring.
Add lvmreport(7) man page. Add lvmreport(7) man page.
Don't install lvmraid(7) man page when raid excluded. (2.02.165) Don't install lvmraid(7) man page when raid excluded. (2.02.165)
Report 0% as dirty (copy%) for cache without any used block. Report 0% as dirty (copy%) for cache without any used block.
@ -1001,7 +727,7 @@ Version 2.02.164 - 15th August 2016
Version 2.02.163 - 10th August 2016 Version 2.02.163 - 10th August 2016
=================================== ===================================
Add profile for lvmdbusd which uses lvm shell json report output. Add profile for lvmdbusd which uses lvm shell json report output.
Restrict in-command modification of some params in lvm shell. Restrict in-command modification of some parms in lvm shell.
Apply LVM_COMMAND_PROFILE early for lvm shell. Apply LVM_COMMAND_PROFILE early for lvm shell.
Refactor reporting so lvm shell log report collects whole of cmd execution. Refactor reporting so lvm shell log report collects whole of cmd execution.
Support LVM_*_FD envvars to redirect output to file descriptors. Support LVM_*_FD envvars to redirect output to file descriptors.
@ -1154,11 +880,11 @@ Version 2.02.152 - 30th April 2016
================================== ==================================
Use any inherited tags when wiping metadata sub LVs to ensure activation. Use any inherited tags when wiping metadata sub LVs to ensure activation.
Add str_list_wipe. Add str_list_wipe.
Improve support for interrupting processing of volumes during lvchange. Improve support for interrupting procesing of volumes during lvchange.
Use failed command return code when lvchanging read-only volume. Use failed command return code when lvchanging read-only volume.
Show creation transaction_id and zeroing state of pool with thin volume. Show creation transaction_id and zeroing state of pool with thin volume.
Stop checking for dm_cache_mq policy with cache target 1.9 (alias to smq). Stop checking for dm_cache_mq policy with cache target 1.9 (alias to smq).
Check first /sys/module/dm_* dir existence before using modprobe. Check first /sys/module/dm_* dir existance before using modprobe.
Remove mpath from 10-dm.rules, superseded by 11-dm-mpath.rules (mpath>=0.6.0). Remove mpath from 10-dm.rules, superseded by 11-dm-mpath.rules (mpath>=0.6.0).
Version 2.02.151 - 23rd April 2016 Version 2.02.151 - 23rd April 2016
@ -1183,7 +909,7 @@ Version 2.02.150 - 9th April 2016
================================= =================================
Avoid using flushing dm status ioctl when checking for usable DM device. Avoid using flushing dm status ioctl when checking for usable DM device.
Check for devices without LVM- uuid prefix only with kernels < 3.X. Check for devices without LVM- uuid prefix only with kernels < 3.X.
Reuse %FREE size approximation with lvcreate -l%PVS thin-pool. Reuse %FREE size aproximation with lvcreate -l%PVS thin-pool.
Allow the lvmdump directory to exist already provided it is empty. Allow the lvmdump directory to exist already provided it is empty.
Show lvconverted percentage with 2 decimal digits. Show lvconverted percentage with 2 decimal digits.
Fix regression in suspend when repairing --type mirror (2.02.133). Fix regression in suspend when repairing --type mirror (2.02.133).
@ -1260,7 +986,7 @@ Version 2.02.143 - 21st February 2016
Fix error path when sending thin-pool message fails in update_pool_lv(). Fix error path when sending thin-pool message fails in update_pool_lv().
Support reporting CheckNeeded and Fail state for thin-pool and thin LV. Support reporting CheckNeeded and Fail state for thin-pool and thin LV.
For failing thin-pool and thin volume correctly report percentage as INVALID. For failing thin-pool and thin volume correctly report percentage as INVALID.
Report -1, not 'unknown' for lv_{snapshot_invalid,merge_failed} with --binary. Report -1, not 'unkown' for lv_{snapshot_invalid,merge_failed} with --binary.
Add configure --enable-dbus-service for an LVM D-Bus service. Add configure --enable-dbus-service for an LVM D-Bus service.
Replace configure --enable-python_bindings with python2 and python3 versions. Replace configure --enable-python_bindings with python2 and python3 versions.
If PV belongs to some VG and metadata missing, skip it if system ID is used. If PV belongs to some VG and metadata missing, skip it if system ID is used.
@ -1289,7 +1015,7 @@ Version 2.02.141 - 25th January 2016
Restore support for command breaking in process_each_lv_in_vg() (2.02.118). Restore support for command breaking in process_each_lv_in_vg() (2.02.118).
Use correct mempool when process_each_lv_in_vg() (2.02.118). Use correct mempool when process_each_lv_in_vg() (2.02.118).
Fix lvm.8 man to show again prohibited suffixes. Fix lvm.8 man to show again prohibited suffixes.
Fix configure to set proper use_blkid_wiping if autodetection as disabled. Fix configure to set proper use_blkid_wiping if autodetected as disabled.
Initialise udev in clvmd for use in device scanning. (2.02.116) Initialise udev in clvmd for use in device scanning. (2.02.116)
Add seg_le_ranges report field for common format when displaying seg devices. Add seg_le_ranges report field for common format when displaying seg devices.
Honour report/list_item_separator for seg_metadata_le_ranges report field. Honour report/list_item_separator for seg_metadata_le_ranges report field.
@ -1439,7 +1165,7 @@ Version 2.02.129 - 26th August 2015
Fix shared library generation to stop exporting internal functions.(2.02.120) Fix shared library generation to stop exporting internal functions.(2.02.120)
Accept --cachemode with lvconvert. Accept --cachemode with lvconvert.
Fix and improve reporting properties of cache-pool. Fix and improve reporting properties of cache-pool.
Enable usage of --cachepolicy and --cachesettings with lvconvert. Enable usage of --cachepolicy and --cachesetting with lvconvert.
Don't allow to reduce size of thin-pool metadata. Don't allow to reduce size of thin-pool metadata.
Fix debug buffer overflows in cmirrord logging. Fix debug buffer overflows in cmirrord logging.
Add --foreground and --help to cmirrord. Add --foreground and --help to cmirrord.
@ -1596,7 +1322,7 @@ Version 2.02.119 - 2nd May 2015
Add --enable-halvm and --disable-halvm options to lvmconf script. Add --enable-halvm and --disable-halvm options to lvmconf script.
Add --services, --mirrorservice and --startstopservices option to lvmconf. Add --services, --mirrorservice and --startstopservices option to lvmconf.
Use proper default value of global/use_lvmetad when processing lvmconf script. Use proper default value of global/use_lvmetad when processing lvmconf script.
Respect allocation/cling_tag_list during initial contiguous allocation. Respect allocation/cling_tag_list during intial contiguous allocation.
Add A_PARTITION_BY_TAGS set when allocated areas should not share tags. Add A_PARTITION_BY_TAGS set when allocated areas should not share tags.
Make changes persist with python addTag/removeTag. Make changes persist with python addTag/removeTag.
Set correct vgid when updating cache when writing PV metadata. Set correct vgid when updating cache when writing PV metadata.
@ -1674,7 +1400,7 @@ Version 2.02.116 - 30th January 2015
Scan pools in for_each_sub_lv() and add for_each_sub_lv_except_pools(). 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 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). Fix lvm2app regression in lvm_lv_get_attr causing unknown values (2.02.115).
Set default cache_mode to writethrough when missing in metadata. Set default cache_mode to writehrough when missing in metadata.
Preserve chunk size with repair and metadata swap of a thin pool. Preserve chunk size with repair and metadata swap of a thin pool.
Fix raid --splitmirror 1 functionality (2.02.112). Fix raid --splitmirror 1 functionality (2.02.112).
Fix tree preload to handle splitting raid images. Fix tree preload to handle splitting raid images.
@ -1740,13 +1466,13 @@ Version 2.02.112 - 11th November 2014
Properly report error when taking snapshot of any cache type LV. Properly report error when taking snapshot of any cache type LV.
Add basic thread debugging messages to dmeventd. Add basic thread debugging messages to dmeventd.
Include threads being shutdown in dmeventd device registration responses. Include threads being shutdown in dmeventd device registration responses.
Initial support for external users of thin pools based on transaction_id. Inital support for external users of thin pools based on transaction_id.
Report some basic percentage info for cache pools. Report some basic percentage info for cache pools.
Introduce size_mb_arg_with_percent() for advanced size arg reading. Introduce size_mb_arg_with_percent() for advanced size arg reading.
Add extra support for '.' as decimal point in size args. Add extra support for '.' as decimal point in size args.
Add configure parameters for default segment type choices. Add configure parameters for default segment type choices.
Add global/sparse_segtype_default setting to use thin for --type sparse. Add global/sparse_segtype_default setting to use thin for --type sparse.
Update and correct lvcreate and lvconvert man pages. Update and correct lvcreate and lvcovert man pages.
Mark pools and snapshots as unzeroable volumes. Mark pools and snapshots as unzeroable volumes.
Check for zeroing of volume after segment type is fully detected. Check for zeroing of volume after segment type is fully detected.
Better support for persistent major and minor options with lvcreate. Better support for persistent major and minor options with lvcreate.
@ -1799,7 +1525,7 @@ Version 2.02.112 - 11th November 2014
Support DEBUG_MEMLOCK to trap unsupported mmap usage. Support DEBUG_MEMLOCK to trap unsupported mmap usage.
Enable cache segment type by default. Enable cache segment type by default.
Ensure only supported volume types are used with cache segments. Ensure only supported volume types are used with cache segments.
Fix inability to specify cachemode when 'lvconvert'ing to cache-pool. Fix inablility to specify cachemode when 'lvconvert'ing to cache-pool.
Grab cluster lock for active LVs when setting clustered attribute. Grab cluster lock for active LVs when setting clustered attribute.
Use va_copy to properly pass va_list through functions. Use va_copy to properly pass va_list through functions.
Add function to detect rotational devices. Add function to detect rotational devices.
@ -1867,7 +1593,7 @@ Version 2.02.108 - 23rd July 2014
Enhance lvconvert thin, thinpool, cache and cachepool command line support. Enhance lvconvert thin, thinpool, cache and cachepool command line support.
Display 'C' only for cache and cache-pool target types in lvs. Display 'C' only for cache and cache-pool target types in lvs.
Prompt for confirmation before change LV into a snapshot exception store. Prompt for confirmation before change LV into a snapshot exception store.
Return proper error codes for some failing lvconvert functions. Return proper error codes for some failing lvconvert funtions.
Add initial code to use cache tools (cache_check|dump|repair|restore). Add initial code to use cache tools (cache_check|dump|repair|restore).
Support lvdisplay --maps for raid. Support lvdisplay --maps for raid.
Add --activationmode degraded to activate degraded raid volumes by default. Add --activationmode degraded to activate degraded raid volumes by default.
@ -1886,7 +1612,7 @@ Version 2.02.108 - 23rd July 2014
Support lvremove -ff to remove thin volumes from broken thin pools. Support lvremove -ff to remove thin volumes from broken thin pools.
Require --yes to skip raid repair prompt. Require --yes to skip raid repair prompt.
Change makefile %.d generation to handle filename changes without make clean. Change makefile %.d generation to handle filename changes without make clean.
Fix use of builddir in make pofile. Fix use of buildir in make pofile.
Enhance private volumes UUIDs with suffixed for easier detection. Enhance private volumes UUIDs with suffixed for easier detection.
Do not use reserved _[tc]meta volumes for temporary LVs. Do not use reserved _[tc]meta volumes for temporary LVs.
Leave backup pool metadata with _meta%d suffix instead of reserved _tmeta%d. Leave backup pool metadata with _meta%d suffix instead of reserved _tmeta%d.
@ -1991,7 +1717,7 @@ Version 2.02.106 - 10th April 2014
Include 'lvm dumpconfig --type missing' and '--type diff' output to lvmdump. Include 'lvm dumpconfig --type missing' and '--type diff' output to lvmdump.
Return failure when specifying negative size for pvresize. Return failure when specifying negative size for pvresize.
Fix memory corruption in cmd context refresh if clvmd leaks opened device. Fix memory corruption in cmd context refresh if clvmd leaks opened device.
Reinitialize lvmcache properly on fork to fix premature polldaemon exit. Reinitialise lvmcache properly on fork to fix premature polldaemon exit.
Add 'lvm dumpconfig --type diff' to show differences from defaults. Add 'lvm dumpconfig --type diff' to show differences from defaults.
Fix swap signature detection for devices smaller then 2MB. Fix swap signature detection for devices smaller then 2MB.
Use dm_malloc function in clvmd.c. Use dm_malloc function in clvmd.c.
@ -2018,7 +1744,7 @@ Version 2.02.106 - 10th April 2014
Don't print an error and accept empty value for global/thin_disabled_features. Don't print an error and accept empty value for global/thin_disabled_features.
Update API for internal function build_dm_uuid(). Update API for internal function build_dm_uuid().
Do not try to check empty pool with scheduled messages. Do not try to check empty pool with scheduled messages.
Fix return value in pool_has_message() when querying for any message. Fix return value in pool_has_message() when quering for any message.
Cleanup all client resources on clvmd exit. Cleanup all client resources on clvmd exit.
Use dm_zalloc to clear members of clvmd client struct. Use dm_zalloc to clear members of clvmd client struct.
Use BLKID_CFLAGS when compiling with blkid support. Use BLKID_CFLAGS when compiling with blkid support.
@ -2060,7 +1786,7 @@ Version 2.02.106 - 10th April 2014
Fix test when checking target version for available thin features. Fix test when checking target version for available thin features.
Detect thin feature external_origin_extend and limit extend when missing. Detect thin feature external_origin_extend and limit extend when missing.
Rename internal pool_can_resize_metadata() to thin_pool_feature_supported(). Rename internal pool_can_resize_metadata() to thin_pool_feature_supported().
Issue error if libblkid detects signature and fails to return offset/length. Issue error if libbblkid detects signature and fails to return offset/length.
Update autoconf config.guess/sub to 2014-01-01. Update autoconf config.guess/sub to 2014-01-01.
Online thin pool metadata resize requires 1.10 kernel thin pool target. Online thin pool metadata resize requires 1.10 kernel thin pool target.
@ -2133,7 +1859,7 @@ Version 2.02.104 - 13th November 2013
===================================== =====================================
Workaround VG refresh race during autoactivation by retrying the refresh. Workaround VG refresh race during autoactivation by retrying the refresh.
Handle failures in temporary mirror used when adding images to mirrors. Handle failures in temporary mirror used when adding images to mirrors.
Fix and improve logic for implicitly exclusive activations. Fix and improve logic for implicitely exclusive activations.
Return success when LV cannot be activated because of volume_list filter. Return success when LV cannot be activated because of volume_list filter.
Return proper error state for remote exclusive activation. Return proper error state for remote exclusive activation.
Fix missing lvmetad scan for PVs found on MD partitions. Fix missing lvmetad scan for PVs found on MD partitions.
@ -2296,11 +2022,11 @@ Version 2.02.99 - 24th July 2013
Add support for persistent flagging of LVs to be skipped during activation. Add support for persistent flagging of LVs to be skipped during activation.
Add --type profilable to lvm dumpconfig to show profilable config settings. Add --type profilable to lvm dumpconfig to show profilable config settings.
Add --mergedconfig to lvm dumpconfig for merged --config/--profile/lvm.conf. Add --mergedconfig to lvm dumpconfig for merged --config/--profile/lvm.conf.
Release memory and unblock signals in lock_vol error path. Relase memory and unblock signals in lock_vol error path.
Define LVM2_* command errors in lvm2cmd.h and use in dmeventd plugins. Define LVM2_* command errors in lvm2cmd.h and use in dmeventd plugins.
Move errors.h to tools dir. Move errors.h to tools dir.
Add man page entries for profile configuration and related options. Add man page entries for profile configuration and related options.
Improve error logging when user tries to interrupt commands. Improve error loging when user tries to interrupt commands.
Rename _swap_lv to _swap_lv_identifiers and move to allow an additional user. Rename _swap_lv to _swap_lv_identifiers and move to allow an additional user.
Rename snapshot segment returning methods from find_*_cow to find_*_snapshot. Rename snapshot segment returning methods from find_*_cow to find_*_snapshot.
liblvm/python API: Additions: PV create/removal/resize/listing liblvm/python API: Additions: PV create/removal/resize/listing
@ -2501,7 +2227,7 @@ Version 2.02.98 - 15th October 2012
Do not start dmeventd for lvchange --resync when monitoring is off. Do not start dmeventd for lvchange --resync when monitoring is off.
Remove pvscan --cache from lvm2-lvmetad init script. Remove pvscan --cache from lvm2-lvmetad init script.
Remove ExecStartPost with pvscan --cache from lvm2-lvmetad.service. Remove ExecStartPost with pvscan --cache from lvm2-lvmetad.service.
Report invalid percentage for property snap_percent of non-snapshot LVs. Report invalid percentage for property snap_percent of non-snaphot LVs.
Disallow conversion of thin LVs to mirrors. Disallow conversion of thin LVs to mirrors.
Fix lvm2api data_percent reporting for thin volumes. Fix lvm2api data_percent reporting for thin volumes.
Do not allow RAID LVs in a clustered volume group. Do not allow RAID LVs in a clustered volume group.
@ -2551,7 +2277,7 @@ Version 2.02.98 - 15th October 2012
Version 2.02.97 - 7th August 2012 Version 2.02.97 - 7th August 2012
================================= =================================
Improve documentation of allocation policies in lvm.8. Improve documention of allocation policies in lvm.8.
Increase limit for major:minor to 4095:1048575 when using -My option. Increase limit for major:minor to 4095:1048575 when using -My option.
Add make install_systemd_generators. Add make install_systemd_generators.
Add generator for lvm2 activation systemd units. Add generator for lvm2 activation systemd units.
@ -2635,7 +2361,7 @@ Version 2.02.96 - 8th June 2012
Check for buffer overwrite in get_cluster_type() in clvmd. Check for buffer overwrite in get_cluster_type() in clvmd.
Fix global/detect_internal_vg_cache_corruption config check. Fix global/detect_internal_vg_cache_corruption config check.
Update lcov Makefile target to support all dmeventd plugins. Update lcov Makefile target to support all dmeventd plugins.
Fix initialization of thin monitoring. (2.02.92) Fix initializiation of thin monitoring. (2.02.92)
Cope with improperly formatted device numbers in /proc/devices. (2.02.91) Cope with improperly formatted device numbers in /proc/devices. (2.02.91)
Exit if LISTEN_PID environment variable incorrect in lvmetad systemd handover. Exit if LISTEN_PID environment variable incorrect in lvmetad systemd handover.
Use pvscan --cache instead of vgscan in lvmetad scripts. Use pvscan --cache instead of vgscan in lvmetad scripts.
@ -2648,7 +2374,7 @@ Version 2.02.96 - 8th June 2012
Add --with-thin-check configure option for path to thin_check. Add --with-thin-check configure option for path to thin_check.
Fix error message when pvmove LV activation fails with name already in use. Fix error message when pvmove LV activation fails with name already in use.
Better structure layout for device_info in dev_subsystem_name(). Better structure layout for device_info in dev_subsystem_name().
Change message severity for creation of VG over uninitialized devices. Change message severity for creation of VG over uninitialised devices.
Fix error path for failed toolcontext creation. Fix error path for failed toolcontext creation.
Detect lvm binary path in lvmetad udev rules. Detect lvm binary path in lvmetad udev rules.
Don't unlink socket on lvmetad shutdown if instantiated from systemd. Don't unlink socket on lvmetad shutdown if instantiated from systemd.
@ -2683,7 +2409,7 @@ Version 2.02.94 - 3rd March 2012
Add some close() and dev_close() error path backtraces. Add some close() and dev_close() error path backtraces.
Set stdin/stdout/stderr to /dev/null for polldaemon. Set stdin/stdout/stderr to /dev/null for polldaemon.
Limit the max size of processed clvmd message to ~8KB. Limit the max size of processed clvmd message to ~8KB.
Do not send uninitialized bytes in cluster error reply messages. Do not send uninitialised bytes in cluster error reply messages.
Use unsigned type for bitmask instead of enum type for lvm properties. Use unsigned type for bitmask instead of enum type for lvm properties.
Add missing cleanup of excl_uuid hash on some exit paths of clvmd. Add missing cleanup of excl_uuid hash on some exit paths of clvmd.
Check for existence of vg_name in _format1/_pool_vg_read(). Check for existence of vg_name in _format1/_pool_vg_read().
@ -2756,7 +2482,7 @@ Version 2.02.91 - 12th February 2012
Version 2.02.90 - 1st February 2012 Version 2.02.90 - 1st February 2012
=================================== ===================================
sync_local_dev_names before (re)activating mirror log for initialization. sync_local_dev_names before (re)activating mirror log for initialisation.
Disable partial activation for thin LVs and LVs with all missing segments. Disable partial activation for thin LVs and LVs with all missing segments.
Do not print warning for pv_min_size between 512KB and 2MB. Do not print warning for pv_min_size between 512KB and 2MB.
Clean up systemd unit ordering and requirements. Clean up systemd unit ordering and requirements.
@ -2775,7 +2501,7 @@ Version 2.02.89 - 26th January 2012
Add data_percent and metadata_percent for thin pools to lvs -v. Add data_percent and metadata_percent for thin pools to lvs -v.
Add data_lv & metadata_lv fields to lvs for thin pools. Add data_lv & metadata_lv fields to lvs for thin pools.
Add data_percent & pool_lv fields to lvs for thin volumes. Add data_percent & pool_lv fields to lvs for thin volumes.
Rename origin_only param to use_layer for lv_info and use with thin LVs. Rename origin_only parm to use_layer for lv_info and use with thin LVs.
Add lv_thin_pool_transaction_id to read the transaction_id value. Add lv_thin_pool_transaction_id to read the transaction_id value.
Use {suspend,resume}_origin_only when up-converting RAID, as mirrors do. Use {suspend,resume}_origin_only when up-converting RAID, as mirrors do.
Always add RAID metadata LVs to deptree (even when origin_only is set). Always add RAID metadata LVs to deptree (even when origin_only is set).
@ -2805,7 +2531,7 @@ Version 2.02.89 - 26th January 2012
Add _dev_init to initialize common struct device members. Add _dev_init to initialize common struct device members.
Always zalloc struct device during initialization. Always zalloc struct device during initialization.
Fix missing thread list manipulation protection in dmeventd. Fix missing thread list manipulation protection in dmeventd.
Do not dereference lv pointer in _percent_run() function before NULL check. Do not derefence lv pointer in _percent_run() function before NULL check.
Allow empty strings for description and creation_host config fields. Allow empty strings for description and creation_host config fields.
Issue deprecation warning when removing last lvm1-format snapshot. Issue deprecation warning when removing last lvm1-format snapshot.
Reinstate support for snapshot removal with lvm1 format. (2.02.86) Reinstate support for snapshot removal with lvm1 format. (2.02.86)
@ -2876,11 +2602,11 @@ Version 2.02.89 - 26th January 2012
Change vg_revert to void and remove superfluous calls after failed vg_commit. Change vg_revert to void and remove superfluous calls after failed vg_commit.
Use execvp for CLVMD restart to preserve environment settings. Use execvp for CLVMD restart to preserve environment settings.
Restart CLVMD with same cluster manager. Restart CLVMD with same cluster manager.
Fix log_error() usage in raid and unknown segtype initialization. Fix log_error() usage in raid and unknown segtype initialisation.
Improve testing Makefile. Improve testing Makefile.
Fix install_ocf make target when srcdir != builddir. (2.02.80) Fix install_ocf make target when srcdir != builddir. (2.02.80)
Support env vars LVM_CLVMD_BINARY and LVM_BINARY in clvmd. Support env vars LVM_CLVMD_BINARY and LVM_BINARY in clvmd.
Fix restart of clvmd (preserve exclusive locks). (2.02.64) Fix restart of clvmd (preserve exlusive locks). (2.02.64)
Add 'Volume Type' lv_attr characters for RAID and RAID_IMAGE. Add 'Volume Type' lv_attr characters for RAID and RAID_IMAGE.
Add activation/retry_deactivation to lvm.conf to retry deactivation of an LV. Add activation/retry_deactivation to lvm.conf to retry deactivation of an LV.
Replace open_count check with holders/mounted_fs check on lvremove path. Replace open_count check with holders/mounted_fs check on lvremove path.
@ -2946,13 +2672,13 @@ Version 2.02.87 - 12th August 2011
Cache and share generated VG structs. Cache and share generated VG structs.
Fix possible format instance memory leaks and premature releases in _vg_read. Fix possible format instance memory leaks and premature releases in _vg_read.
Suppress locking error messages in monitoring init scripts. Suppress locking error messages in monitoring init scripts.
If pipe in clvmd fails return busy instead of using uninitialized descriptors. If pipe in clvmd fails return busy instead of using uninitialised descriptors.
Add ability to reduce the number of mirrors in raid1 arrays to lvconvert. Add ability to reduce the number of mirrors in raid1 arrays to lvconvert.
Add dmeventd plugin for raid. Add dmeventd plugin for raid.
Replace free_vg with release_vg and move it to vg.c. Replace free_vg with release_vg and move it to vg.c.
Remove INCONSISTENT_VG flag from the code. Remove INCONSISTENT_VG flag from the code.
Remove lock from cache in _lock_vol even if unlock fails. Remove lock from cache in _lock_vol even if unlock fails.
Initialize clvmd locks before lvm context to avoid open descriptor leaks. Initialise clvmd locks before lvm context to avoid open descriptor leaks.
Remove obsolete gulm clvmd cluster locking support. Remove obsolete gulm clvmd cluster locking support.
Suppress low-level locking errors and warnings while using --sysinit. Suppress low-level locking errors and warnings while using --sysinit.
Remove unused inconsistent_seqno variable in _vg_read(). Remove unused inconsistent_seqno variable in _vg_read().
@ -3025,7 +2751,7 @@ Version 2.02.85 - 29th April 2011
Issue discards on lvremove and lvreduce etc. if enabled and supported. Issue discards on lvremove and lvreduce etc. if enabled and supported.
Add seg_pe_ranges and devices fields to liblvm. Add seg_pe_ranges and devices fields to liblvm.
Fix incorrect tests for dm_snprintf() failure. Fix incorrect tests for dm_snprintf() failure.
Fix some unmatching sign comparison gcc warnings in the code. Fix some unmatching sign comparation gcc warnings in the code.
Support lv_extend() on empty LVs. Support lv_extend() on empty LVs.
Avoid regenerating cache content when exported VG buffer is unchanged. Avoid regenerating cache content when exported VG buffer is unchanged.
Extend the set of memory regions that are not locked to memory. Extend the set of memory regions that are not locked to memory.
@ -3051,7 +2777,7 @@ Version 2.02.85 - 29th April 2011
Use only vg_set_fid and new pv_set_fid fn to assign the format instance. Use only vg_set_fid and new pv_set_fid fn to assign the format instance.
Make create_text_context fn static and move it inside create_instance fn. Make create_text_context fn static and move it inside create_instance fn.
Add mem and ref_count fields to struct format_instance for own mempool use. Add mem and ref_count fields to struct format_instance for own mempool use.
Use new alloc_fid fn for common format instance initialization. Use new alloc_fid fn for common format instance initialisation.
Optimise _get_token() and _eat_space(). Optimise _get_token() and _eat_space().
Add _lv_postorder_vg() to improve efficiency for all LVs in VG. Add _lv_postorder_vg() to improve efficiency for all LVs in VG.
Add gdbinit script for debugging. Add gdbinit script for debugging.
@ -3060,10 +2786,10 @@ Version 2.02.85 - 29th April 2011
Avoid possible endless loop in _free_vginfo when 4 or more VGs have same name. Avoid possible endless loop in _free_vginfo when 4 or more VGs have same name.
Use empty string instead of /dev// for LV path when there's no VG. Use empty string instead of /dev// for LV path when there's no VG.
Don't allocate unused VG mempool in _pvsegs_sub_single. Don't allocate unused VG mempool in _pvsegs_sub_single.
Do not send uninitialized bytes in local clvmd messages. Do not send uninitialised bytes in local clvmd messages.
Support --help option for clvmd and return error for unknown option. Support --help option for clvmd and return error for unknown option.
Avoid reading freed memory when printing LV segment type. Avoid reading freed memory when printing LV segment type.
Fix syslog initialization in clvmd to respect lvm.conf setting. Fix syslog initialisation in clvmd to respect lvm.conf setting.
Fix possible overflow in maximum stripe size and physical extent size. Fix possible overflow in maximum stripe size and physical extent size.
Improve pvremove error message when PV belongs to a VG. Improve pvremove error message when PV belongs to a VG.
Extend normal policy to allow mirror logs on same PVs as images if necessary. Extend normal policy to allow mirror logs on same PVs as images if necessary.
@ -3077,7 +2803,7 @@ Version 2.02.85 - 29th April 2011
Restructure existing pv_setup and pv_write and add pv_initialise. Restructure existing pv_setup and pv_write and add pv_initialise.
Add internal interface to support adding and removing metadata areas. Add internal interface to support adding and removing metadata areas.
Allow internal indexing of metadata areas (PV id + mda order). Allow internal indexing of metadata areas (PV id + mda order).
Generalise internal format_instance infrastructure for PV and VG use. Generalise internal format_instance infrastrusture for PV and VG use.
Handle decimal digits with --units instead of ignoring them silently. Handle decimal digits with --units instead of ignoring them silently.
Fix remaining warnings and compile with -Wpointer-arith. Fix remaining warnings and compile with -Wpointer-arith.
Fix gcc warnings for unused variables and const casts. Fix gcc warnings for unused variables and const casts.
@ -3091,7 +2817,7 @@ Version 2.02.85 - 29th April 2011
Make pv_min_size configurable and increase to 2048KB to exclude floppy drives. Make pv_min_size configurable and increase to 2048KB to exclude floppy drives.
Add find_config_tree_int64 to read 64-bit ints from config. Add find_config_tree_int64 to read 64-bit ints from config.
Ensure resuming exclusive cluster mirror continues to use local mirror target. Ensure resuming exclusive cluster mirror continues to use local mirror target.
Clear temporary postorder LV status flags to allow reuse with same LV struct. Clear temporary postorder LV status flags to allow re-use with same LV struct.
Remove invalid snapshot umount mesg which floods syslog from dmeventd plugin. Remove invalid snapshot umount mesg which floods syslog from dmeventd plugin.
Add extended examples to pvmove man page. Add extended examples to pvmove man page.
Support LVM_TEST_DEVDIR env var for private /dev during testing. Support LVM_TEST_DEVDIR env var for private /dev during testing.
@ -3146,7 +2872,7 @@ Version 2.02.80 - 10th January 2011
Speed up command processing by caching resolved config tree. Speed up command processing by caching resolved config tree.
Pass config_tree to renamed function import_vg_from_config_tree(). Pass config_tree to renamed function import_vg_from_config_tree().
Detect NULL handle in get_property(). Detect NULL handle in get_property().
Fix superfluous /usr in ocf_scriptdir installation path. Fix superfluous /usr in ocf_scriptdir instalation path.
Add --with-ocfdir configurable option. Add --with-ocfdir configurable option.
Add aclocal.m4 (for pkgconfig). Add aclocal.m4 (for pkgconfig).
Fix memory leak in persistent filter creation error path. Fix memory leak in persistent filter creation error path.
@ -3178,7 +2904,7 @@ Version 2.02.79 - 20th December 2010
Add copy_percent and snap_percent to liblvm. Add copy_percent and snap_percent to liblvm.
Enhance vg_validate to ensure integrity of LV and PV structs referenced. Enhance vg_validate to ensure integrity of LV and PV structs referenced.
Enhance vg_validate to check composition of pvmove LVs. Enhance vg_validate to check composition of pvmove LVs.
Create /var/run/lvm directory during clvmd initialization if missing. Create /var/run/lvm directory during clvmd initialisation if missing.
Use new dm_prepare_selinux_context instead of dm_set_selinux_context. Use new dm_prepare_selinux_context instead of dm_set_selinux_context.
Avoid revalidating the label cache immediately after scanning. Avoid revalidating the label cache immediately after scanning.
Support scanning for a single VG in independent mdas. Support scanning for a single VG in independent mdas.
@ -3447,7 +3173,7 @@ Version 2.02.68 - 23rd June 2010
Add device name and offset to raw_read_mda_header error messages. Add device name and offset to raw_read_mda_header error messages.
Honour log argument when down-converting stacked mirror. Honour log argument when down-converting stacked mirror.
Sleep to workaround clvmd -S race: socket closed early and server drops cmd. Sleep to workaround clvmd -S race: socket closed early and server drops cmd.
Use early udev synchronization and update of dev nodes for clustered mirrors. Use early udev synchronisation and update of dev nodes for clustered mirrors.
Remove incorrect inclusion of kdev_t.h from cmirrord/functions.h. Remove incorrect inclusion of kdev_t.h from cmirrord/functions.h.
Add man pages for lvmconf and non-existent lvmsadc and lvmsar tools. Add man pages for lvmconf and non-existent lvmsadc and lvmsar tools.
Exit successfully when using -o help (but not -o +help) with LVM reports. Exit successfully when using -o help (but not -o +help) with LVM reports.
@ -3475,7 +3201,7 @@ Version 2.02.67 - 4th June 2010
Avoid selecting names under /dev/block if there is an alternative. Avoid selecting names under /dev/block if there is an alternative.
Update clustered log kernel module name to log-userspace for 2.6.31 onwards. Update clustered log kernel module name to log-userspace for 2.6.31 onwards.
Add replicators' LVs to dtree for activation. Add replicators' LVs to dtree for activation.
Suppress activation message if there is a missing replicator VG. Supress activation message if there is a missing replicator VG.
Fix scripts/relpath.awk to work in mawk Fix scripts/relpath.awk to work in mawk
Extend lock_vol to check for missing replicator VGs first. Extend lock_vol to check for missing replicator VGs first.
Update _process_one_vg and process_each_lv_in_vg to populate cmd_vg. Update _process_one_vg and process_each_lv_in_vg to populate cmd_vg.
@ -3526,7 +3252,7 @@ Version 2.02.65 - 17th May 2010
Version 2.02.64 - 30th April 2010 Version 2.02.64 - 30th April 2010
================================= =================================
Avoid pointless initialization when the 'version' command is run directly. Avoid pointless initialisation when the 'version' command is run directly.
Fix memory leak for invalid regex pattern input. Fix memory leak for invalid regex pattern input.
Display invalid regex pattern for filter configuration in case of error. Display invalid regex pattern for filter configuration in case of error.
Remove no-longer-used arg_ptr_value. Remove no-longer-used arg_ptr_value.
@ -3685,7 +3411,7 @@ Version 2.02.60 - 23rd January 2010
Disable memory debugging if dmeventd is configured. (Not thread-safe.) Disable memory debugging if dmeventd is configured. (Not thread-safe.)
Fix first log message prefix in syslog for dmeventd plugins. Fix first log message prefix in syslog for dmeventd plugins.
Fix exported symbols names for dmeventd lvm2 wrapper plugin. Fix exported symbols names for dmeventd lvm2 wrapper plugin.
Make failed locking initialization messages more descriptive. Make failed locking initialisation messages more descriptive.
Version 2.02.59 - 21st January 2010 Version 2.02.59 - 21st January 2010
=================================== ===================================
@ -3701,7 +3427,7 @@ Version 2.02.59 - 21st January 2010
Fix detection of completed snapshot merge. Fix detection of completed snapshot merge.
Add Red Hat cmirror initscript (unfinished). Add Red Hat cmirror initscript (unfinished).
Add cmirrord man page (incomplete). Add cmirrord man page (incomplete).
Make cluster log communication structures architecture independent. Make cluster log communication structures architecture independant.
Fix cluster log in-memory bitmap handling. Fix cluster log in-memory bitmap handling.
Improve snapshot merge metadata import validation. Improve snapshot merge metadata import validation.
Improve target type compatibility checking in _percent_run(). Improve target type compatibility checking in _percent_run().
@ -3777,7 +3503,7 @@ Version 2.02.57 - 12th January 2010
Impose limit of 8 mirror images to match the in-kernel kcopyd restriction. Impose limit of 8 mirror images to match the in-kernel kcopyd restriction.
Use locking_type 3 (compiled in) for lvmconf --enable-cluster. Use locking_type 3 (compiled in) for lvmconf --enable-cluster.
Remove list.c and list.h with no-longer-used dm_list macros and functions. Remove list.c and list.h with no-longer-used dm_list macros and functions.
Log failure type and recognize type 'F' (flush) in dmeventd mirror plugin. Log failure type and recognise type 'F' (flush) in dmeventd mirror plugin.
Extend internal PV/VG/LV/segment status variables from 32-bit to 64-bit. Extend internal PV/VG/LV/segment status variables from 32-bit to 64-bit.
Version 2.02.56 - 24th November 2009 Version 2.02.56 - 24th November 2009
@ -3815,14 +3541,14 @@ Version 2.02.54 - 26th October 2009
Fix clvmd segfault when refresh_toolcontext fails. Fix clvmd segfault when refresh_toolcontext fails.
Remember to clear 'global lock held during cache refresh' state after use. Remember to clear 'global lock held during cache refresh' state after use.
Use udev flags support in LVM and apply various fixes to udev rules. Use udev flags support in LVM and apply various fixes to udev rules.
Delay announcing mirror monitoring to syslog until initialization succeeded. Delay announcing mirror monitoring to syslog until initialisation succeeded.
Handle metadata with unknown segment types more gracefully. Handle metadata with unknown segment types more gracefully.
Set default owner and group to null. Set default owner and group to null.
Add dmeventd.static to the build. Add dmeventd.static to the build.
Disable realtime support code by default. Disable realtime support code by default.
Make clvmd return 0 on success rather than 1. Make clvmd return 0 on success rather than 1.
Add --pvmetadatacopies for pvcreate, vgcreate, vgextend, vgconvert. Add --pvmetadatacopies for pvcreate, vgcreate, vgextend, vgconvert.
Add implicit pvcreate support to vgcreate and vgextend. Add implict pvcreate support to vgcreate and vgextend.
Correct example.conf to indicate that lvm2 not lvm1 is the default format. Correct example.conf to indicate that lvm2 not lvm1 is the default format.
Remove an unused stray LVM1_SUPPORT ifdef. Remove an unused stray LVM1_SUPPORT ifdef.
Only include selinux libs in libdevmapper.pc when selinux build enabled. Only include selinux libs in libdevmapper.pc when selinux build enabled.
@ -4002,7 +3728,7 @@ Version 2.02.48 - 30th June 2009
Reinstate partial activation support in clustered mode. (2.02.40) Reinstate partial activation support in clustered mode. (2.02.40)
Allow metadata correction even when PVs are missing. Allow metadata correction even when PVs are missing.
Use 'lvm lvresize' instead of 'lvresize' in fsadm. Use 'lvm lvresize' instead of 'lvresize' in fsadm.
Do not use '-n' realine option in fsadm for busybox compatibility. Do not use '-n' realine option in fsadm for busybox compatiblity.
Add vg_lock_newname() library function for vgrename, vgsplit and vgcreate. Add vg_lock_newname() library function for vgrename, vgsplit and vgcreate.
Round up requested readahead to at least one page and print warning. Round up requested readahead to at least one page and print warning.
Try to repair vg before actual vgremove when force flag provided. Try to repair vg before actual vgremove when force flag provided.
@ -4063,7 +3789,7 @@ Version 2.02.46 - 21st May 2009
Fix first_seg() call for empty segment list. Fix first_seg() call for empty segment list.
Add install_lvm2 makefile target to install only the LVM2 components. Add install_lvm2 makefile target to install only the LVM2 components.
Reject missing PVs from allocation in toollib. Reject missing PVs from allocation in toollib.
Fix PV dataalignment for values starting prior to MDA area. (2.02.45) Fix PV datalignment for values starting prior to MDA area. (2.02.45)
Add sparse devices: lvcreate -s --virtualoriginsize (hidden zero origin). Add sparse devices: lvcreate -s --virtualoriginsize (hidden zero origin).
Fix minimum width of devices column in reports. Fix minimum width of devices column in reports.
Add lvs origin_size field. Add lvs origin_size field.
@ -4136,7 +3862,7 @@ Version 2.02.45 - 3rd March 2009
Separate PV label attributes which do not need parse metadata when reporting. Separate PV label attributes which do not need parse metadata when reporting.
Remove external dependency on the 'cut' command from fsadm. Remove external dependency on the 'cut' command from fsadm.
Fix pvs segfault when pv mda attributes requested for not available PV. Fix pvs segfault when pv mda attributes requested for not available PV.
Add fsadm support for resizing ext4 filesystems. Add fsadm support for reszing ext4 filesysystems.
Move locking_type reading inside init_locking(). Move locking_type reading inside init_locking().
Rename get_vgs() to get_vgnames() and clarify related error messages. Rename get_vgs() to get_vgnames() and clarify related error messages.
Allow clvmd to be built with all cluster managers & select one on cmdline. Allow clvmd to be built with all cluster managers & select one on cmdline.
@ -4313,7 +4039,7 @@ Version 2.02.37 - 6th June 2008
Refactor some vginfo manipulation code. Refactor some vginfo manipulation code.
Add assertions to trap deprecated P_ and V_ lock usage. Add assertions to trap deprecated P_ and V_ lock usage.
Add missing mutex around clvmd lvmcache_drop_metadata library call. Add missing mutex around clvmd lvmcache_drop_metadata library call.
Fix uninitialized mutex in clvmd if all daemons are not running at startup. Fix uninitialised mutex in clvmd if all daemons are not running at startup.
Avoid using DLM locks with LCK_CACHE type P_ lock requests. Avoid using DLM locks with LCK_CACHE type P_ lock requests.
When asked to drop cached committed VG metadata, invalidate cached PV labels. When asked to drop cached committed VG metadata, invalidate cached PV labels.
Drop metadata cache before writing precommitted metadata instead of after. Drop metadata cache before writing precommitted metadata instead of after.
@ -4360,7 +4086,7 @@ Version 2.02.34 - 10th April 2008
Mention default --clustered setting in vgcreate man page. Mention default --clustered setting in vgcreate man page.
Add config file overrides to clvmd when it reads the active LVs list. Add config file overrides to clvmd when it reads the active LVs list.
Fix vgreduce to use vg_split_mdas to check sufficient mdas remain. Fix vgreduce to use vg_split_mdas to check sufficient mdas remain.
Add (empty) orphan VGs to lvmcache during initialization. Add (empty) orphan VGs to lvmcache during initialisation.
Fix orphan VG name used for format_pool. Fix orphan VG name used for format_pool.
Create a fid for internal orphan VGs. Create a fid for internal orphan VGs.
Update lvmcache VG lock state for all locking types now. Update lvmcache VG lock state for all locking types now.
@ -4378,7 +4104,7 @@ Version 2.02.34 - 10th April 2008
Fix redundant lvresize message if vg doesn't exist. Fix redundant lvresize message if vg doesn't exist.
Fix another allocation bug with clvmd and large node IDs. Fix another allocation bug with clvmd and large node IDs.
Add find_lv_in_lv_list() and find_pv_in_pv_list(). Add find_lv_in_lv_list() and find_pv_in_pv_list().
Fix uninitialized variable in clvmd that could cause odd hangs. Fix uninitialised variable in clvmd that could cause odd hangs.
Add vgmerge tests. Add vgmerge tests.
Add pvseg_is_allocated() for identifying a PV segment allocated to a LV. Add pvseg_is_allocated() for identifying a PV segment allocated to a LV.
Add list_move() for moving elements from one list to another. Add list_move() for moving elements from one list to another.
@ -4386,7 +4112,7 @@ Version 2.02.34 - 10th April 2008
Correct command name in lvmdiskscan man page. Correct command name in lvmdiskscan man page.
clvmd no longer crashes if it sees nodeids over 50. clvmd no longer crashes if it sees nodeids over 50.
Fix potential deadlock in clvmd thread handling. Fix potential deadlock in clvmd thread handling.
Refactor text format initialization into _init_text_import. Refactor text format initialisation into _init_text_import.
Escape double quotes and backslashes in external metadata and config data. Escape double quotes and backslashes in external metadata and config data.
Add functions for escaping double quotes in strings. Add functions for escaping double quotes in strings.
Rename count_chars_len to count_chars. Rename count_chars_len to count_chars.
@ -4436,7 +4162,7 @@ Version 2.02.31 - 19th January 2008
Version 2.02.30 - 17th January 2008 Version 2.02.30 - 17th January 2008
=================================== ===================================
Set default readahead to twice maximum stripe size. Set default readahead to twice maximium stripe size.
Reinstate VG extent size and stripe size defaults (halved). (2.02.29) Reinstate VG extent size and stripe size defaults (halved). (2.02.29)
Add lists of stacked LV segments using each LV to the internal metadata. Add lists of stacked LV segments using each LV to the internal metadata.
Change vgsplit -l (for unimplemented --list) into --maxlogicalvolumes. Change vgsplit -l (for unimplemented --list) into --maxlogicalvolumes.
@ -4808,7 +4534,7 @@ Version 2.02.11 - 12th October 2006
Capture error messages in clvmd and pass them back to the user. Capture error messages in clvmd and pass them back to the user.
Remove unused #defines from filter-md.c. Remove unused #defines from filter-md.c.
Make clvmd restart init script wait until clvmd has died before starting it. Make clvmd restart init script wait until clvmd has died before starting it.
Add -R to clvmd which tells running clvmd to reload their device cache. Add -R to clvmd which tells running clvmds to reload their device cache.
Add LV column to reports listing kernel modules needed for activation. Add LV column to reports listing kernel modules needed for activation.
Show available fields if report given invalid field. (e.g. lvs -o list) Show available fields if report given invalid field. (e.g. lvs -o list)
Add timestamp functions with --disable-realtime configure option. Add timestamp functions with --disable-realtime configure option.
@ -5135,7 +4861,7 @@ Version 2.01.08 - 22nd March 2005
Improve detection of external changes affecting internal cache. Improve detection of external changes affecting internal cache.
Add 'already in device cache' debug message. Add 'already in device cache' debug message.
Add -a to pvdisplay -C. Add -a to pvdisplay -C.
Avoid rmdir opendir error messages when dir was already removed. Avoid rmdir opendir error messsages when dir was already removed.
Tighten signal handlers. Tighten signal handlers.
Avoid some compiler warnings. Avoid some compiler warnings.
Additional rename failure error message. Additional rename failure error message.
@ -5366,7 +5092,7 @@ Version 2.00.17 - 20 June 2004
fsadm support for fsck and resizing - needs testing. fsadm support for fsck and resizing - needs testing.
Add read-only GFS pool support. Add read-only GFS pool support.
Add lvm2create_initrd script from http://poochiereds.net/svn/lvm2/ Add lvm2create_initrd script from http://poochiereds.net/svn/lvm2/
Fix rounding of large displayed sizes. Fix rounding of large diplayed sizes.
Suppress decimal point when using units of sectors/bytes. Suppress decimal point when using units of sectors/bytes.
Additional kernel target checks before pvmove & snapshot creation. Additional kernel target checks before pvmove & snapshot creation.
Add i2o_block. Add i2o_block.
@ -5581,5 +5307,3 @@ Display output. Some metadata information cannot yet be displayed.
Recovery tools to salvage "lost" metadata directly from the disks: Recovery tools to salvage "lost" metadata directly from the disks:
but we hope the new format will mean such tools are hardly ever needed! but we hope the new format will mean such tools are hardly ever needed!

View File

@ -1,101 +1,5 @@
Version 1.02.209 - Version 1.02.185 -
===================
Version 1.02.208 - 30th July 2025
=================================
Version 1.02.207 - 27th June 2025
=================================
Escape the escape character itself on JSON report format output.
Fail dm_report_group_create if radix char from locale unsuitable for JSON_STD.
Version 1.02.206 - 05th May 2025
================================
Add support for using regex in selection criteria for string lists.
Fix string list selection when using [<item> || <item> ...].
Version 1.02.205 - 27th February 2025
===================================== =====================================
Restore missing symbol dm_tree_node_size_changed@Base (1.02.175).
Restore missing symbol dm_bitset_parse_list@@DM_1_02_138 (1.02.175).
Version 1.02.204 - 14th January 2025
====================================
Create /dev/disk/by-diskseq/<DISKSEQ> symlink for public DM devices.
Version 1.02.203 - 09th December 2024
=====================================
Version 1.02.202 - 04th November 2024
=====================================
Introduce dm_config_parse_only_section to stop parsing after section.
For shorter string use on stack buffers when generating sections.
Enhance dm_config tokenizer.
Version 1.02.201 - 02nd October 2024
====================================
Cleanup udev sync semaphore if dm_{udev_create,task_set}_cookie fails.
Improve error messages on failed udev cookie create/inc/dec operation.
Version 1.02.200 - 23rd August 2024
===================================
Version 1.02.199 - 12nd July 2024
=================================
Version 1.02.198 - 16th May 2024
================================
Fix static only compilation of libdevmapper.a and dmsetup tool.
Use better code for closing opened descriptors when starting dmeventd.
Correct dmeventd -R for systemd environment.
Restart of dmeventd -R checks pid file to detect running dmeventd first.
Query with dmeventd -i quickly ends when there is no running dmeventd.
Enhance dm_get_status_raid to handle mismatching status or reported legs.
Create /dev/disk/by-label symlinks for DM devs that have crypto as next layer.
Persist udev db for DM devs on cleanup used in initrd to rootfs transition.
Process synthetic udev events other than 'add/change' as 'change' events.
Increase DM_UDEV_RULES_VSN to 3 to indicate changed udev rules.
Rename DM_NOSCAN to .DM_NOSCAN so it's not stored in udev db.
Rename DM_SUSPENDED to .DM_SUSPENDED so it's not stored in udev db.
Do not import DM_UDEV_DISABLE_OTHER_RULES_FLAG from db in 10-dm-disk.rules.
Test DISK_RO after importing properties from db in 10-dm.rules.
Also import ID_FS_TYPE in 13-dm-disk.rules from db if needed.
Version 1.02.197 - 21st November 2023
=====================================
Fix invalid JSON report if using DM_REPORT_OUTPUT_MULTIPLE_TIMES and selection.
Propagate ioctl errno from dm_task_run when creating new table line.
Add support for group aliases in dmstats.
Add support for exit-on file for dmeventd to reduce shutdown delays.
Add configure option --with-dmeventd-exit-on-path to specify default path.
Add dmsetup --headings none|abbrev|full to set report headings type.
Add DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS to provide alternative headings.
Version 1.02.196 - 02nd August 2023
===================================
Version 1.02.195 - 21st April 2023
==================================
Version 1.02.193 - 21st March 2023
==================================
Version 1.02.191 - 21st February 2023
=====================================
Improve parallel creation of /dev/mapper/control device node.
Import previous ID_FS_* udev records in 13-dm-disk.rules for suspended DM dev.
Remove NAME="mapper/control" rule from 10-dm.rules to avoid udev warnings.
Version 1.02.189 - 22nd December 2022
=====================================
Improve 'dmsetup create' without given table line with new kernels.
Version 1.02.187 - 10th November 2022
=====================================
Add DM_REPORT_GROUP_JSON_STD for more JSON standard compliant output format.
Version 1.02.185 - 18th May 2022
================================
Version 1.02.183 - 07th February 2022 Version 1.02.183 - 07th February 2022
===================================== =====================================
@ -127,7 +31,7 @@ Version 1.02.173 - 09th August 2020
Version 1.02.171 - 26th March 2020 Version 1.02.171 - 26th March 2020
================================== ==================================
Try to remove all created devices on dm preload tree error path. Try to remove all created devices on dm preload tree error path.
Fix dm_list iterators with gcc 10 optimization (-ftree-pta). Fix dm_list interators with gcc 10 optimization (-ftree-pta).
Dmeventd handles timer without looping on short intervals. Dmeventd handles timer without looping on short intervals.
Version 1.02.169 - 11th February 2020 Version 1.02.169 - 11th February 2020
@ -158,7 +62,7 @@ Version 1.02.155 - 18th December 2018
===================================== =====================================
Include correct internal header inside libdm list.c. Include correct internal header inside libdm list.c.
Enhance ioctl flattening and add parameters only when needed. Enhance ioctl flattening and add parameters only when needed.
Add DM_DEVICE_ARM_POLL for API completeness matching kernel. Add DM_DEVICE_ARM_POLL for API completness matching kernel.
Do not add parameters for RESUME with DM_DEVICE_CREATE dm task. Do not add parameters for RESUME with DM_DEVICE_CREATE dm task.
Fix dmstats report printing no output. Fix dmstats report printing no output.
@ -187,7 +91,7 @@ Version 1.02.147-rc1 - 24th May 2018
Reuse uname() result for mirror target. Reuse uname() result for mirror target.
Recognize also mounted btrfs through dm_device_has_mounted_fs(). Recognize also mounted btrfs through dm_device_has_mounted_fs().
Add missing log_error() into dm_stats_populate() returning 0. Add missing log_error() into dm_stats_populate() returning 0.
Avoid calling dm_stats_populate() for DM devices without any stats regions. Avoid calling dm_stats_populat() for DM devices without any stats regions.
Support DM_DEBUG_WITH_LINE_NUMBERS envvar for debug msg with source:line. Support DM_DEBUG_WITH_LINE_NUMBERS envvar for debug msg with source:line.
Configured command for thin pool threshold handling gets whole environment. Configured command for thin pool threshold handling gets whole environment.
Fix tests for failing dm_snprintf() in stats code. Fix tests for failing dm_snprintf() in stats code.
@ -236,7 +140,7 @@ Version 1.02.141 - 28th June 2017
Add dm_percent_to_round_float for adjusted percentage rounding. Add dm_percent_to_round_float for adjusted percentage rounding.
Reset array with dead rimage devices once raid gets in sync. Reset array with dead rimage devices once raid gets in sync.
Drop unneeded --config option from raid dmeventd plugin. Drop unneeded --config option from raid dmeventd plugin.
dm_get_status_raid() handle better some inconsistent md statuses. dm_get_status_raid() handle better some incosistent md statuses.
Accept truncated files in calls to dm_stats_update_regions_from_fd(). Accept truncated files in calls to dm_stats_update_regions_from_fd().
Restore Warning by 5% increment when thin-pool is over 80% (1.02.138). Restore Warning by 5% increment when thin-pool is over 80% (1.02.138).
@ -291,7 +195,7 @@ Version 1.02.136 - 5th November 2016
Still produce output when dmsetup dependency tree building finds dev missing. Still produce output when dmsetup dependency tree building finds dev missing.
Check and report pthread_sigmask() failure in dmeventd. Check and report pthread_sigmask() failure in dmeventd.
Check mem alloc fail in _canonicalize_field_ids(). Check mem alloc fail in _canonicalize_field_ids().
Use unsigned math when checking more than 31 legs of raid. Use unsigned math when checking more then 31 legs of raid.
Fix 'dmstats delete' with dmsetup older than v1.02.129 Fix 'dmstats delete' with dmsetup older than v1.02.129
Fix stats walk segfault with dmsetup older than v1.02.129 Fix stats walk segfault with dmsetup older than v1.02.129
@ -431,7 +335,7 @@ Version 1.02.112 - 28th November 2015
===================================== =====================================
Show error message when trying to create unsupported raid type. Show error message when trying to create unsupported raid type.
Improve preloading sequence of an active thin-pool target. Improve preloading sequence of an active thin-pool target.
Drop extra space from cache target line to fix unneeded table reloads. Drop extra space from cache target line to fix unneded table reloads.
Version 1.02.111 - 23rd November 2015 Version 1.02.111 - 23rd November 2015
===================================== =====================================
@ -446,7 +350,7 @@ Version 1.02.110 - 30th October 2015
Disable thin monitoring plugin when it fails too often (>10 times). Disable thin monitoring plugin when it fails too often (>10 times).
Fix/restore parsing of empty field '-' when processing dmeventd event. Fix/restore parsing of empty field '-' when processing dmeventd event.
Enhance dm_tree_node_size_changed() to recognize size reduction. Enhance dm_tree_node_size_changed() to recognize size reduction.
Support exit on idle for dmeventd (1 hour). Support exit on idle for dmenventd (1 hour).
Add support to allow unmonitor device from plugin itself. Add support to allow unmonitor device from plugin itself.
New design for thread co-operation in dmeventd. New design for thread co-operation in dmeventd.
Dmeventd read device status with 'noflush'. Dmeventd read device status with 'noflush'.
@ -619,7 +523,7 @@ Version 1.02.93 - 21st January 2015
Version 1.02.92 - 24th November 2014 Version 1.02.92 - 24th November 2014
==================================== ====================================
Fix memory corruption with sorting empty string lists (1.02.86). Fix memory corruption with sorting empty string lists (1.02.86).
Fix man dmsetup.8 syntax warning of Groff. Fix man dmsetup.8 syntax warning of Groff
Accept unquoted strings and / in place of {} when parsing configs. Accept unquoted strings and / in place of {} when parsing configs.
Version 1.02.91 - 11th November 2014 Version 1.02.91 - 11th November 2014
@ -638,7 +542,7 @@ Version 1.02.90 - 1st September 2014
Version 1.02.89 - 26th August 2014 Version 1.02.89 - 26th August 2014
================================== ==================================
Improve libdevmapper-event select() error handling. Improve libdevmapper-event select() error handling.
Add extra check for matching transaction_id after message submitting. Add extra check for matching transation_id after message submitting.
Add dm_report_field_string_list_unsorted for str. list report without sorting. Add dm_report_field_string_list_unsorted for str. list report without sorting.
Support --deferred with dmsetup remove to defer removal of open devices. Support --deferred with dmsetup remove to defer removal of open devices.
Update dm-ioctl.h to include DM_DEFERRED_REMOVE flag. Update dm-ioctl.h to include DM_DEFERRED_REMOVE flag.
@ -725,7 +629,7 @@ Version 1.02.82 - 4th October 2013
Version 1.02.81 - 23rd September 2013 Version 1.02.81 - 23rd September 2013
===================================== =====================================
Tidy dmeventd fifo initialization. Tidy dmeventd fifo initialisation.
Version 1.02.80 - 20th September 2013 Version 1.02.80 - 20th September 2013
===================================== =====================================
@ -750,7 +654,7 @@ Version 1.02.78 - 24th July 2013
Always return success on dmeventd -V command call. Always return success on dmeventd -V command call.
Fix parsing of 64bit snapshot status in dmeventd snapshot plugin. Fix parsing of 64bit snapshot status in dmeventd snapshot plugin.
Add dm_get_status_snapshot() for parsing snapshot status. Add dm_get_status_snapshot() for parsing snapshot status.
Detect mounted fs also via reading /proc/self/mountinfo. Detecte mounted fs also via reading /proc/self/mountinfo.
Add dm_mountinfo_read() for parsing /proc/self/mountinfo. Add dm_mountinfo_read() for parsing /proc/self/mountinfo.
Report error for nonexisting devices in dmeventd communication. Report error for nonexisting devices in dmeventd communication.
Prevent double free error after dmeventd call of _fill_device_data(). Prevent double free error after dmeventd call of _fill_device_data().
@ -847,7 +751,7 @@ Version 1.02.71 - 20th February 2012
Add "watch" rule to 13-dm-disk.rules. Add "watch" rule to 13-dm-disk.rules.
Detect failing fifo and skip 20s retry communication period. Detect failing fifo and skip 20s retry communication period.
Add DM_DEFAULT_NAME_MANGLING_MODE environment variable as an override. Add DM_DEFAULT_NAME_MANGLING_MODE environment variable as an override.
Add dm_lib_init to automatically initialize device-mapper library on load. Add dm_lib_init to automatically initialise device-mapper library on load.
Replace any '\' char with '\\' in dm table specification on input. Replace any '\' char with '\\' in dm table specification on input.
Add mangle command to dmsetup to provide renaming to correct mangled form. Add mangle command to dmsetup to provide renaming to correct mangled form.
Add 'mangled_name' and 'unmangled_name' fields to dmsetup info -c -o. Add 'mangled_name' and 'unmangled_name' fields to dmsetup info -c -o.
@ -941,7 +845,7 @@ Version 1.02.66 - 12th August 2011
Fix memory leak in dmsetup _message() memory allocation error path. Fix memory leak in dmsetup _message() memory allocation error path.
Use new oom killer adjustment interface (oom_score_adj) when available. Use new oom killer adjustment interface (oom_score_adj) when available.
Add systemd unit files for dmeventd. Add systemd unit files for dmeventd.
Fix read-only identical table reload suppression. Fix read-only identical table reload supression.
Version 1.02.65 - 8th July 2011 Version 1.02.65 - 8th July 2011
=============================== ===============================
@ -956,7 +860,7 @@ Version 1.02.65 - 8th July 2011
Add dm_get_suspended_counter() for number of devs in suspended state by lib. Add dm_get_suspended_counter() for number of devs in suspended state by lib.
Fix "all" report field prefix matching to include label fields with pv_all. Fix "all" report field prefix matching to include label fields with pv_all.
Delay resuming new preloaded mirror devices with core logs in deptree code. Delay resuming new preloaded mirror devices with core logs in deptree code.
Accept new kernel version 3 uname formats in initialization. Accept new kernel version 3 uname formats in initialisation.
Version 1.02.64 - 29th April 2011 Version 1.02.64 - 29th April 2011
================================== ==================================
@ -970,7 +874,7 @@ Version 1.02.64 - 29th April 2011
Improve stack debug reporting in dm_task_create(). Improve stack debug reporting in dm_task_create().
Fallback to control node creation only if node doesn't exist yet. Fallback to control node creation only if node doesn't exist yet.
Change dm_hash binary functions to take void *key instead of char *. Change dm_hash binary functions to take void *key instead of char *.
Fix uninitialized memory use with empty params in _reload_with_suppression_v4. Fix uninitialised memory use with empty params in _reload_with_suppression_v4.
Lower severity of selabel_lookup and matchpathcon failure to log_debug. Lower severity of selabel_lookup and matchpathcon failure to log_debug.
Add test for failed allocation from dm_task_set_uuid() in dmeventd. Add test for failed allocation from dm_task_set_uuid() in dmeventd.
Add dm_event_get_version to dmeventd for use with -R. Add dm_event_get_version to dmeventd for use with -R.
@ -1139,7 +1043,7 @@ Version 1.02.44 - 15th February 2010
Version 1.02.43 - 21st January 2010 Version 1.02.43 - 21st January 2010
=================================== ===================================
Remove bitset, hash and pool headers superseded by libdevmapper.h. Remove bitset, hash and pool headers superceded by libdevmapper.h.
Fix off-by-one error causing bad cluster mirror table construction. Fix off-by-one error causing bad cluster mirror table construction.
Version 1.02.42 - 14th January 2010 Version 1.02.42 - 14th January 2010
@ -1195,7 +1099,7 @@ Version 1.02.37 - 15th September 2009
Version 1.02.36 - 6th August 2009 Version 1.02.36 - 6th August 2009
================================= =================================
Add udevcookies, udevcomplete, udevcomplete_all and --noudevwait to dmsetup. Add udevcookies, udevcomplete, udevcomplete_all and --noudevwait to dmsetup.
Add libdevmapper functions to support synchronization with udev. Add libdevmapper functions to support synchronisation with udev.
Version 1.02.35 - 28th July 2009 Version 1.02.35 - 28th July 2009
================================ ================================
@ -1263,7 +1167,7 @@ Version 1.02.27 - 25th June 2008
Version 1.02.26 - 6th June 2008 Version 1.02.26 - 6th June 2008
=============================== ===============================
Initialize params buffer to empty string in _emit_segment. Initialise params buffer to empty string in _emit_segment.
Skip add_dev_node when ioctls disabled. Skip add_dev_node when ioctls disabled.
Make dm_hash_iter safe against deletion. Make dm_hash_iter safe against deletion.
Accept a NULL pointer to dm_free silently. Accept a NULL pointer to dm_free silently.
@ -1319,7 +1223,7 @@ Version 1.02.20 - 15th June 2007
Version 1.02.19 - 27th April 2007 Version 1.02.19 - 27th April 2007
================================= =================================
Standardize protective include file #defines. Standardise protective include file #defines.
Add regex functions to library. Add regex functions to library.
Avoid trailing separator in reports when there are hidden sort fields. Avoid trailing separator in reports when there are hidden sort fields.
Fix segfault in 'dmsetup status' without --showkeys against crypt target. Fix segfault in 'dmsetup status' without --showkeys against crypt target.
@ -1350,7 +1254,7 @@ Version 1.02.16 - 25th January 2007
Streamline dm_report_field_* interface. Streamline dm_report_field_* interface.
Add cmdline debug & version options to dmeventd. Add cmdline debug & version options to dmeventd.
Add DM_LIB_VERSION definition to configure.h. Add DM_LIB_VERSION definition to configure.h.
Suppress 'Unrecognized field' error if report field is 'help'. Suppress 'Unrecognised field' error if report field is 'help'.
Add --separator and --sort to dmsetup (unused). Add --separator and --sort to dmsetup (unused).
Make alignment flag optional when specifying report fields. Make alignment flag optional when specifying report fields.
@ -1598,5 +1502,3 @@ Version 1.00.08 - 27 Feb 2004
Fixed DESTDIR for make install/install_static_lib. Fixed DESTDIR for make install/install_static_lib.
Updated README/INSTALL to reflect move to sources.redhat.com. Updated README/INSTALL to reflect move to sources.redhat.com.
Updated autoconf files to 2003-06-17. Updated autoconf files to 2003-06-17.

View File

@ -62,24 +62,6 @@ AC_DEFUN([AC_TRY_LDFLAGS],
fi fi
]) ])
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl -------------------------------------------
dnl Since: 0.28
dnl
dnl Retrieves the value of the pkg-config variable for the given module.
AC_DEFUN([PKG_CHECK_VAR],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
_PKG_CONFIG([$1], [variable="][$3]["], [$2])
AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])dnl PKG_CHECK_VAR
# =========================================================================== # ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html # http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html
# =========================================================================== # ===========================================================================

351
aclocal.m4 vendored
View File

@ -1,6 +1,6 @@
# generated automatically by aclocal 1.18.1 -*- Autoconf -*- # generated automatically by aclocal 1.16.2 -*- Autoconf -*-
# Copyright (C) 1996-2025 Free Software Foundation, Inc. # Copyright (C) 1996-2020 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
@ -69,8 +69,8 @@ AC_DEFUN([AX_PYTHON_MODULE],[
fi fi
]) ])
# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 12 (pkg-config-0.29.2) # serial 11 (pkg-config-0.29.1)
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>. dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com> dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
@ -112,13 +112,13 @@ dnl
dnl See the "Since" comment for each macro you use to see what version dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require. dnl of the macros you require.
m4_defun([PKG_PREREQ], m4_defun([PKG_PREREQ],
[m4_define([PKG_MACROS_VERSION], [0.29.2]) [m4_define([PKG_MACROS_VERSION], [0.29.1])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ ])dnl PKG_PREREQ
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION], [ACTION-IF-NOT-FOUND]) dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
dnl --------------------------------------------------------- dnl ----------------------------------
dnl Since: 0.16 dnl Since: 0.16
dnl dnl
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
@ -126,12 +126,6 @@ dnl first found in the path. Checks that the version of pkg-config found
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
dnl used since that's the first version where most current features of dnl used since that's the first version where most current features of
dnl pkg-config existed. dnl pkg-config existed.
dnl
dnl If pkg-config is not found or older than specified, it will result
dnl in an empty PKG_CONFIG variable. To avoid widespread issues with
dnl scripts not checking it, ACTION-IF-NOT-FOUND defaults to aborting.
dnl You can specify [PKG_CONFIG=false] as an action instead, which would
dnl result in pkg-config tests failing, but no bogus error messages.
AC_DEFUN([PKG_PROG_PKG_CONFIG], AC_DEFUN([PKG_PROG_PKG_CONFIG],
[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) [m4_pattern_forbid([^_?PKG_[A-Z_]+$])
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
@ -152,9 +146,6 @@ if test -n "$PKG_CONFIG"; then
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
PKG_CONFIG="" PKG_CONFIG=""
fi fi
fi
if test -z "$PKG_CONFIG"; then
m4_default([$2], [AC_MSG_ERROR([pkg-config not found])])
fi[]dnl fi[]dnl
])dnl PKG_PROG_PKG_CONFIG ])dnl PKG_PROG_PKG_CONFIG
@ -166,7 +157,7 @@ dnl Check to see whether a particular set of modules exists. Similar to
dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
dnl dnl
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
dnl only at the first occurrence in configure.ac, so if the first place dnl only at the first occurence in configure.ac, so if the first place
dnl it's called might be skipped (such as if it is within an "if", you dnl it's called might be skipped (such as if it is within an "if", you
dnl have to call PKG_CHECK_EXISTS manually dnl have to call PKG_CHECK_EXISTS manually
AC_DEFUN([PKG_CHECK_EXISTS], AC_DEFUN([PKG_CHECK_EXISTS],
@ -222,7 +213,7 @@ AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no pkg_failed=no
AC_MSG_CHECKING([for $2]) AC_MSG_CHECKING([for $1])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2])
@ -232,17 +223,17 @@ and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.]) See the pkg-config man page for more details.])
if test $pkg_failed = yes; then if test $pkg_failed = yes; then
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED _PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
else else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
fi fi
# Put the nasty error message in config.log where it belongs # Put the nasty error message in config.log where it belongs
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
m4_default([$4], [AC_MSG_ERROR( m4_default([$4], [AC_MSG_ERROR(
[Package requirements ($2) were not met: [Package requirements ($2) were not met:
$$1_PKG_ERRORS $$1_PKG_ERRORS
@ -253,8 +244,8 @@ installed software in a non-standard prefix.
_PKG_TEXT])[]dnl _PKG_TEXT])[]dnl
]) ])
elif test $pkg_failed = untried; then elif test $pkg_failed = untried; then
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE( m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old. Make sure it [The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config. path to pkg-config.
@ -264,10 +255,10 @@ _PKG_TEXT
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
]) ])
else else
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
AC_MSG_RESULT([yes]) AC_MSG_RESULT([yes])
$3 $3
fi[]dnl fi[]dnl
])dnl PKG_CHECK_MODULES ])dnl PKG_CHECK_MODULES
@ -422,7 +413,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
])dnl PKG_HAVE_DEFINE_WITH_MODULES ])dnl PKG_HAVE_DEFINE_WITH_MODULES
# Copyright (C) 1999-2025 Free Software Foundation, Inc. # Copyright (C) 1999-2020 Free Software Foundation, Inc.
# #
# This file is free software; the Free Software Foundation # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
@ -456,12 +447,9 @@ AC_DEFUN([AM_PATH_PYTHON],
dnl Find a Python interpreter. Python versions prior to 2.0 are not dnl Find a Python interpreter. Python versions prior to 2.0 are not
dnl supported. (2.0 was released on October 16, 2000). dnl supported. (2.0 was released on October 16, 2000).
m4_define_default([_AM_PYTHON_INTERPRETER_LIST], m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
[python python3 dnl [python python2 python3 dnl
python3.20 python3.19 python3.18 python3.17 python3.16 dnl
python3.15 python3.14 python3.13 python3.12 python3.11 python3.10 dnl
python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 dnl python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 dnl
python3.2 python3.1 python3.0 dnl python3.2 python3.1 python3.0 dnl
python2 dnl
python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl
python2.0]) python2.0])
@ -504,7 +492,7 @@ AC_DEFUN([AM_PATH_PYTHON],
]) ])
if test "$PYTHON" = :; then if test "$PYTHON" = :; then
dnl Run any user-specified action, or abort. dnl Run any user-specified action, or abort.
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
else else
@ -513,132 +501,27 @@ AC_DEFUN([AM_PATH_PYTHON],
dnl trailing zero was eliminated. So now we output just the major dnl trailing zero was eliminated. So now we output just the major
dnl and minor version numbers, as numbers. Apparently the tertiary dnl and minor version numbers, as numbers. Apparently the tertiary
dnl version is not of interest. dnl version is not of interest.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
[am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[[:2]])"`]) [am_cv_python_version=`$PYTHON -c "import sys; print('%u.%u' % sys.version_info[[:2]])"`])
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
dnl At times, e.g., when building shared libraries, you may want dnl Use the values of $prefix and $exec_prefix for the corresponding
dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
dnl distinct variables so they can be overridden if need be. However,
dnl general consensus is that you shouldn't need this ability.
AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
dnl At times (like when building shared libraries) you may want
dnl to know which OS platform Python thinks this is. dnl to know which OS platform Python thinks this is.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
[am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
dnl emacs-page # Just factor out some code duplication.
dnl If --with-python-sys-prefix is given, use the values of sys.prefix
dnl and sys.exec_prefix for the corresponding values of PYTHON_PREFIX
dnl and PYTHON_EXEC_PREFIX. Otherwise, use the GNU ${prefix} and
dnl ${exec_prefix} variables.
dnl
dnl The two are made distinct variables so they can be overridden if
dnl need be, although general consensus is that you shouldn't need
dnl this separation.
dnl
dnl Also allow directly setting the prefixes via configure options,
dnl overriding any default.
dnl
if test "x$prefix" = xNONE; then
am__usable_prefix=$ac_default_prefix
else
am__usable_prefix=$prefix
fi
# Allow user to request using sys.* values from Python,
# instead of the GNU $prefix values.
AC_ARG_WITH([python-sys-prefix],
[AS_HELP_STRING([--with-python-sys-prefix],
[use Python's sys.prefix and sys.exec_prefix values])],
[am_use_python_sys=:],
[am_use_python_sys=false])
# Allow user to override whatever the default Python prefix is.
AC_ARG_WITH([python_prefix],
[AS_HELP_STRING([--with-python_prefix],
[override the default PYTHON_PREFIX])],
[am_python_prefix_subst=$withval
am_cv_python_prefix=$withval
AC_MSG_CHECKING([for explicit $am_display_PYTHON prefix])
AC_MSG_RESULT([$am_cv_python_prefix])],
[
if $am_use_python_sys; then
# using python sys.prefix value, not GNU
AC_CACHE_CHECK([for python default $am_display_PYTHON prefix],
[am_cv_python_prefix],
[am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"`])
dnl If sys.prefix is a subdir of $prefix, replace the literal value of
dnl $prefix with a variable reference so it can be overridden.
case $am_cv_python_prefix in
$am__usable_prefix*)
am__strip_prefix=`echo "$am__usable_prefix" | sed 's|.|.|g'`
am_python_prefix_subst=`echo "$am_cv_python_prefix" | sed "s,^$am__strip_prefix,\\${prefix},"`
;;
*)
am_python_prefix_subst=$am_cv_python_prefix
;;
esac
else # using GNU prefix value, not python sys.prefix
am_python_prefix_subst='${prefix}'
am_python_prefix=$am_python_prefix_subst
AC_MSG_CHECKING([for GNU default $am_display_PYTHON prefix])
AC_MSG_RESULT([$am_python_prefix])
fi])
# Substituting python_prefix_subst value.
AC_SUBST([PYTHON_PREFIX], [$am_python_prefix_subst])
# emacs-page Now do it all over again for Python exec_prefix, but with yet
# another conditional: fall back to regular prefix if that was specified.
AC_ARG_WITH([python_exec_prefix],
[AS_HELP_STRING([--with-python_exec_prefix],
[override the default PYTHON_EXEC_PREFIX])],
[am_python_exec_prefix_subst=$withval
am_cv_python_exec_prefix=$withval
AC_MSG_CHECKING([for explicit $am_display_PYTHON exec_prefix])
AC_MSG_RESULT([$am_cv_python_exec_prefix])],
[
# no explicit --with-python_exec_prefix, but if
# --with-python_prefix was given, use its value for python_exec_prefix too.
AS_IF([test -n "$with_python_prefix"],
[am_python_exec_prefix_subst=$with_python_prefix
am_cv_python_exec_prefix=$with_python_prefix
AC_MSG_CHECKING([for python_prefix-given $am_display_PYTHON exec_prefix])
AC_MSG_RESULT([$am_cv_python_exec_prefix])],
[
# Set am__usable_exec_prefix whether using GNU or Python values,
# since we use that variable for pyexecdir.
if test "x$exec_prefix" = xNONE; then
am__usable_exec_prefix=$am__usable_prefix
else
am__usable_exec_prefix=$exec_prefix
fi
#
if $am_use_python_sys; then # using python sys.exec_prefix, not GNU
AC_CACHE_CHECK([for python default $am_display_PYTHON exec_prefix],
[am_cv_python_exec_prefix],
[am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"`])
dnl If sys.exec_prefix is a subdir of $exec_prefix, replace the
dnl literal value of $exec_prefix with a variable reference so it can
dnl be overridden.
case $am_cv_python_exec_prefix in
$am__usable_exec_prefix*)
am__strip_prefix=`echo "$am__usable_exec_prefix" | sed 's|.|.|g'`
am_python_exec_prefix_subst=`echo "$am_cv_python_exec_prefix" | sed "s,^$am__strip_prefix,\\${exec_prefix},"`
;;
*)
am_python_exec_prefix_subst=$am_cv_python_exec_prefix
;;
esac
else # using GNU $exec_prefix, not python sys.exec_prefix
am_python_exec_prefix_subst='${exec_prefix}'
am_python_exec_prefix=$am_python_exec_prefix_subst
AC_MSG_CHECKING([for GNU default $am_display_PYTHON exec_prefix])
AC_MSG_RESULT([$am_python_exec_prefix])
fi])])
# Substituting python_exec_prefix_subst.
AC_SUBST([PYTHON_EXEC_PREFIX], [$am_python_exec_prefix_subst])
# Factor out some code duplication into this shell variable.
am_python_setup_sysconfig="\ am_python_setup_sysconfig="\
import sys import sys
# Prefer sysconfig over distutils.sysconfig, for better compatibility # Prefer sysconfig over distutils.sysconfig, for better compatibility
@ -656,120 +539,98 @@ try:
if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7': if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7':
can_use_sysconfig = 0 can_use_sysconfig = 0
except ImportError: except ImportError:
pass" # end of am_python_setup_sysconfig pass"
# More repeated code, for figuring out the installation scheme to use. dnl Set up 4 directories:
am_python_setup_scheme="if hasattr(sysconfig, 'get_default_scheme'):
scheme = sysconfig.get_default_scheme()
else:
scheme = sysconfig._get_default_scheme()
if scheme == 'posix_local':
if '$am_py_prefix' == '/usr':
scheme = 'deb_system' # should only happen during Debian package builds
else:
# Debian's default scheme installs to /usr/local/ but we want to
# follow the prefix, as we always have.
# See bugs#54412, #64837, et al.
scheme = 'posix_prefix'" # end of am_python_setup_scheme
dnl emacs-page Set up 4 directories: dnl pythondir -- where to install python scripts. This is the
dnl site-packages directory, not the python standard library
dnl 1. pythondir: where to install python scripts. This is the dnl directory like in previous automake betas. This behavior
dnl site-packages directory, not the python standard library dnl is more consistent with lispdir.m4 for example.
dnl directory as in early automake betas. This behavior dnl Query distutils for this directory.
dnl is more consistent with lispdir.m4 for example. AC_CACHE_CHECK([for $am_display_PYTHON script directory],
dnl Query sysconfig or distutils (per above) for this directory. [am_cv_python_pythondir],
dnl [if test "x$prefix" = xNONE
AC_CACHE_CHECK([for $am_display_PYTHON script directory (pythondir)], then
[am_cv_python_pythondir], am_py_prefix=$ac_default_prefix
[if test "x$am_cv_python_prefix" = x; then else
am_py_prefix=$am__usable_prefix am_py_prefix=$prefix
else fi
am_py_prefix=$am_cv_python_prefix am_cv_python_pythondir=`$PYTHON -c "
fi
am_cv_python_pythondir=`$PYTHON -c "
$am_python_setup_sysconfig $am_python_setup_sysconfig
if can_use_sysconfig: if can_use_sysconfig:
try:
$am_python_setup_scheme
sitedir = sysconfig.get_path('purelib', scheme, vars={'base':'$am_py_prefix'})
except:
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
else: else:
from distutils import sysconfig from distutils import sysconfig
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"` sys.stdout.write(sitedir)"`
# case $am_cv_python_pythondir in
case $am_cv_python_pythondir in $am_py_prefix*)
$am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,\\${PYTHON_PREFIX},"` ;;
;; *)
*) case $am_py_prefix in
case $am_py_prefix in /usr|/System*) ;;
/usr|/System*) ;; *)
*) am_cv_python_pythondir="\${PYTHON_PREFIX}/lib/python$PYTHON_VERSION/site-packages" am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
;; ;;
esac
;;
esac esac
;; ])
esac
])
AC_SUBST([pythondir], [$am_cv_python_pythondir]) AC_SUBST([pythondir], [$am_cv_python_pythondir])
dnl 2. pkgpythondir: $PACKAGE directory under pythondir. Was dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
dnl more consistent with the rest of automake. dnl more consistent with the rest of automake.
dnl
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
dnl 3. pyexecdir: directory for installing python extension modules dnl pyexecdir -- directory for installing python extension modules
dnl (shared libraries). dnl (shared libraries)
dnl Query sysconfig or distutils for this directory. dnl Query distutils for this directory.
dnl Much of this is the same as for prefix setup above. AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
dnl [am_cv_python_pyexecdir],
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory (pyexecdir)], [if test "x$exec_prefix" = xNONE
[am_cv_python_pyexecdir], then
[if test "x$am_cv_python_exec_prefix" = x; then am_py_exec_prefix=$am_py_prefix
am_py_exec_prefix=$am__usable_exec_prefix else
else am_py_exec_prefix=$exec_prefix
am_py_exec_prefix=$am_cv_python_exec_prefix fi
fi am_cv_python_pyexecdir=`$PYTHON -c "
am_cv_python_pyexecdir=`$PYTHON -c "
$am_python_setup_sysconfig $am_python_setup_sysconfig
if can_use_sysconfig: if can_use_sysconfig:
try: sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
$am_python_setup_scheme
sitedir = sysconfig.get_path('platlib', scheme, vars={'platbase':'$am_py_exec_prefix'})
except:
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_exec_prefix'})
else: else:
from distutils import sysconfig from distutils import sysconfig
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix') sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"` sys.stdout.write(sitedir)"`
# case $am_cv_python_pyexecdir in
case $am_cv_python_pyexecdir in $am_py_exec_prefix*)
$am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,\\${PYTHON_EXEC_PREFIX},"` ;;
;; *)
*) case $am_py_exec_prefix in
case $am_py_exec_prefix in /usr|/System*) ;;
/usr|/System*) ;; *)
*) am_cv_python_pyexecdir="\${PYTHON_EXEC_PREFIX}/lib/python$PYTHON_VERSION/site-packages" am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
;; ;;
esac
;;
esac esac
;; ])
esac
])
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
dnl 4. pkgpyexecdir: $(pyexecdir)/$(PACKAGE) dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
dnl
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
dnl Run any user-specified action. dnl Run any user-specified action.
$2 $2
fi fi
]) ])
@ -792,7 +653,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
sys.exit(sys.hexversion < minverhex)" sys.exit(sys.hexversion < minverhex)"
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
# Copyright (C) 2001-2025 Free Software Foundation, Inc. # Copyright (C) 2001-2020 Free Software Foundation, Inc.
# #
# This file is free software; the Free Software Foundation # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,

1712
autoconf/config.guess vendored

File diff suppressed because it is too large Load Diff

2881
autoconf/config.sub vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
#!/usr/bin/sh #!/bin/sh
# install - install a program, script, or datafile # install - install a program, script, or datafile
scriptversion=2020-11-14.01; # UTC scriptversion=2006-10-14.15
# This originates from X11R5 (mit/util/scripts/install.sh), which was # This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the # later released in X11R6 (xc/config/util/install.sh) with the
@ -35,62 +35,57 @@ scriptversion=2020-11-14.01; # UTC
# FSF changes to this file are in the public domain. # FSF changes to this file are in the public domain.
# #
# Calling this script install-sh is preferred over install.sh, to prevent # Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it # `make' implicit rules from creating a file called install from it
# when there is no Makefile. # when there is no Makefile.
# #
# This script is compatible with the BSD install script, but was written # This script is compatible with the BSD install script, but was written
# from scratch. # from scratch.
tab=' '
nl=' nl='
' '
IFS=" $tab$nl" IFS=" "" $nl"
# Set DOITPROG to "echo" to test this script. # set DOITPROG to echo to test this script
doit=${DOITPROG-} # Don't use :- since 4.3BSD and earlier shells don't like it.
doit_exec=${doit:-exec} doit="${DOITPROG-}"
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path; # Put in absolute file names if you don't have them in your path;
# or use environment vars. # or use environment vars.
chgrpprog=${CHGRPPROG-chgrp} mvprog="${MVPROG-mv}"
chmodprog=${CHMODPROG-chmod} cpprog="${CPPROG-cp}"
chownprog=${CHOWNPROG-chown} chmodprog="${CHMODPROG-chmod}"
cmpprog=${CMPPROG-cmp} chownprog="${CHOWNPROG-chown}"
cpprog=${CPPROG-cp} chgrpprog="${CHGRPPROG-chgrp}"
mkdirprog=${MKDIRPROG-mkdir} stripprog="${STRIPPROG-strip}"
mvprog=${MVPROG-mv} rmprog="${RMPROG-rm}"
rmprog=${RMPROG-rm} mkdirprog="${MKDIRPROG-mkdir}"
stripprog=${STRIPPROG-strip}
posix_glob=
posix_mkdir= posix_mkdir=
# Desired mode of installed file. # Desired mode of installed file.
mode=0755 mode=0755
# Create dirs (including intermediate dirs) using mode 755.
# This is like GNU 'install' as of coreutils 8.32 (2020).
mkdir_umask=22
backupsuffix=
chgrpcmd=
chmodcmd=$chmodprog chmodcmd=$chmodprog
chowncmd= chowncmd=
mvcmd=$mvprog chgrpcmd=
rmcmd="$rmprog -f"
stripcmd= stripcmd=
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src= src=
dst= dst=
dir_arg= dir_arg=
dst_arg= dstarg=
no_target_directory=
copy_on_change=false usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES... or: $0 [OPTION]... -d DIRECTORIES...
@ -100,116 +95,91 @@ In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES. In the 4th, create DIRECTORIES.
Options: Options:
--help display this help and exit. -c (ignored)
--version display version info and exit. -d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-c (ignored) -m MODE $chmodprog installed files to MODE.
-C install only if different (preserve data modification time) -o USER $chownprog installed files to USER.
-d create directories instead of installing files. -s $stripprog installed files.
-g GROUP $chgrpprog installed files to GROUP. -t DIRECTORY install into DIRECTORY.
-m MODE $chmodprog installed files to MODE. -T report an error if DSTFILE is a directory.
-o USER $chownprog installed files to USER. --help display this help and exit.
-p pass -p to $cpprog. --version display version info and exit.
-s $stripprog installed files.
-S SUFFIX attempt to back up existing files, with suffix SUFFIX.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands: Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
RMPROG STRIPPROG
By default, rm is invoked with -f; when overridden with RMPROG,
it's up to you to specify -f if you want it.
If -S is not specified, no backups are attempted.
Email bug reports to bug-automake@gnu.org.
Automake home page: https://www.gnu.org/software/automake/
" "
while test $# -ne 0; do while test $# -ne 0; do
case $1 in case $1 in
-c) ;; -c) shift
continue;;
-C) copy_on_change=true;; -d) dir_arg=true
shift
-d) dir_arg=true;; continue;;
-g) chgrpcmd="$chgrpprog $2" -g) chgrpcmd="$chgrpprog $2"
shift;; shift
shift
continue;;
--help) echo "$usage"; exit $?;; --help) echo "$usage"; exit $?;;
-m) mode=$2 -m) mode=$2
case $mode in shift
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) shift
echo "$0: invalid mode: $mode" >&2 case $mode in
exit 1;; *' '* | *' '* | *'
esac '* | *'*'* | *'?'* | *'['*)
shift;; echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
continue;;
-o) chowncmd="$chownprog $2" -o) chowncmd="$chownprog $2"
shift;; shift
shift
continue;;
-p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog
shift
continue;;
-s) stripcmd=$stripprog;; -t) dstarg=$2
shift
shift
continue;;
-S) backupsuffix="$2" -T) no_target_directory=true
shift;; shift
continue;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;; --version) echo "$0 $scriptversion"; exit $?;;
--) shift --) shift
break;; break;;
-*) echo "$0: invalid option: $1" >&2 -*) echo "$0: invalid option: $1" >&2
exit 1;; exit 1;;
*) break;; *) break;;
esac esac
shift
done done
# We allow the use of options -d and -T together, by making -d if test $# -ne 0 && test -z "$dir_arg$dstarg"; then
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create. # When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified. # When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@. # Otherwise, the last argument is the destination. Remove it from $@.
for arg for arg
do do
if test -n "$dst_arg"; then if test -n "$dstarg"; then
# $@ is not empty: it contains at least $arg. # $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg" set fnord "$@" "$dstarg"
shift # fnord shift # fnord
fi fi
shift # arg shift # arg
dst_arg=$arg dstarg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done done
fi fi
@ -218,26 +188,13 @@ if test $# -eq 0; then
echo "$0: no input file specified." >&2 echo "$0: no input file specified." >&2
exit 1 exit 1
fi fi
# It's OK to call 'install-sh -d' without argument. # It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories. # This can happen when creating conditional directories.
exit 0 exit 0
fi fi
if test -z "$dir_arg"; then if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then trap '(exit $?); exit' 1 2 13 15
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes. # Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps. # However, 'strip' requires both read and write access to temps.
@ -248,16 +205,16 @@ if test -z "$dir_arg"; then
*[0-7]) *[0-7])
if test -z "$stripcmd"; then if test -z "$stripcmd"; then
u_plus_rw= u_plus_rw=
else else
u_plus_rw='% 200' u_plus_rw='% 200'
fi fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*) *)
if test -z "$stripcmd"; then if test -z "$stripcmd"; then
u_plus_rw= u_plus_rw=
else else
u_plus_rw=,u+rw u_plus_rw=,u+rw
fi fi
cp_umask=$mode$u_plus_rw;; cp_umask=$mode$u_plus_rw;;
esac esac
@ -265,9 +222,9 @@ fi
for src for src
do do
# Protect names problematic for 'test' and other utilities. # Protect names starting with `-'.
case $src in case $src in
-* | [=\(\)!]) src=./$src;; -*) src=./$src ;;
esac esac
if test -n "$dir_arg"; then if test -n "$dir_arg"; then
@ -275,10 +232,6 @@ do
dstdir=$dst dstdir=$dst
test -d "$dstdir" test -d "$dstdir"
dstdir_status=$? dstdir_status=$?
# Don't chown directories that already exist.
if test $dstdir_status = 0; then
chowncmd=""
fi
else else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
@ -289,154 +242,196 @@ do
exit 1 exit 1
fi fi
if test -z "$dst_arg"; then if test -z "$dstarg"; then
echo "$0: no destination specified." >&2 echo "$0: no destination specified." >&2
exit 1 exit 1
fi fi
dst=$dst_arg
# If destination is a directory, append the input filename. dst=$dstarg
# Protect names starting with `-'.
case $dst in
-*) dst=./$dst ;;
esac
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then if test -d "$dst"; then
if test "$is_target_a_directory" = never; then if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2 echo "$0: $dstarg: Is a directory" >&2
exit 1 exit 1
fi fi
dstdir=$dst dstdir=$dst
dstbase=`basename "$src"` dst=$dstdir/`basename "$src"`
case $dst in
*/) dst=$dst$dstbase;;
*) dst=$dst/$dstbase;;
esac
dstdir_status=0 dstdir_status=0
else else
dstdir=`dirname "$dst"` # Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir" test -d "$dstdir"
dstdir_status=$? dstdir_status=$?
fi fi
fi fi
case $dstdir in
*/) dstdirslash=$dstdir;;
*) dstdirslash=$dstdir/;;
esac
obsolete_mkdir_used=false obsolete_mkdir_used=false
if test $dstdir_status != 0; then if test $dstdir_status != 0; then
case $posix_mkdir in case $posix_mkdir in
'') '')
# With -d, create the new directory with the user-specified mode. # Create intermediate dirs using mode 755 as modified by the umask.
# Otherwise, rely on $mkdir_umask. # This is like FreeBSD 'install' as of 1997-10-28.
if test -n "$dir_arg"; then umask=`umask`
mkdir_mode=-m$mode case $stripcmd.$umask in
else # Optimize common cases.
mkdir_mode= *[2367][2367]) mkdir_umask=$umask;;
fi .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
posix_mkdir=false *[0-7])
# The $RANDOM variable is not portable (e.g., dash). Use it mkdir_umask=`expr $umask + 22 \
# here however when possible just to lower collision chance. - $umask % 100 % 40 + $umask % 20 \
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
trap ' # With -d, create the new directory with the user-specified mode.
ret=$? # Otherwise, rely on $mkdir_umask.
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null if test -n "$dir_arg"; then
exit $ret mkdir_mode=-m$mode
' 0
# Because "mkdir -p" follows existing symlinks and we likely work
# directly in world-writeable /tmp, make sure that the '$tmpdir'
# directory is successfully created first before we actually test
# 'mkdir -p'.
if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a"
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
else else
# Remove any dirs left behind by ancient mkdir implementations. mkdir_mode=
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
fi fi
trap '' 0;;
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writeable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac esac
if if
$posix_mkdir && ( $posix_mkdir && (
umask $mkdir_umask && umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
) )
then : then :
else else
# mkdir does not conform to POSIX, # The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the # or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go. # directory the slow way, step by step, checking for races as we go.
case $dstdir in case $dstdir in
/*) prefix='/';; /*) prefix=/ ;;
[-=\(\)!]*) prefix='./';; -*) prefix=./ ;;
*) prefix='';; *) prefix= ;;
esac
case $posix_glob in
'')
if (set -f) 2>/dev/null; then
posix_glob=true
else
posix_glob=false
fi ;;
esac esac
oIFS=$IFS oIFS=$IFS
IFS=/ IFS=/
set -f $posix_glob && set -f
set fnord $dstdir set fnord $dstdir
shift shift
set +f $posix_glob && set +f
IFS=$oIFS IFS=$oIFS
prefixes= prefixes=
for d for d
do do
test X"$d" = X && continue test -z "$d" && continue
prefix=$prefix$d prefix=$prefix$d
if test -d "$prefix"; then if test -d "$prefix"; then
prefixes= prefixes=
else else
if $posix_mkdir; then if $posix_mkdir; then
(umask $mkdir_umask && (umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently. # Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1 test -d "$prefix" || exit 1
else else
case $prefix in case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;; *) qprefix=$prefix;;
esac esac
prefixes="$prefixes '$qprefix'" prefixes="$prefixes '$qprefix'"
fi fi
fi fi
prefix=$prefix/ prefix=$prefix/
done done
if test -n "$prefixes"; then if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently. # Don't fail if two instances are running concurrently.
(umask $mkdir_umask && (umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") || eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1 test -d "$dstdir" || exit 1
obsolete_mkdir_used=true obsolete_mkdir_used=true
fi fi
fi fi
fi fi
@ -449,25 +444,14 @@ do
else else
# Make a couple of temp file names in the proper directory. # Make a couple of temp file names in the proper directory.
dsttmp=${dstdirslash}_inst.$$_ dsttmp=$dstdir/_inst.$$_
rmtmp=${dstdirslash}_rm.$$_ rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit. # Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name. # Copy the file name to the temp name.
(umask $cp_umask && (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
{ test -z "$stripcmd" || {
# Create $dsttmp read-write so that cp doesn't create it read-only,
# which would cause strip to fail.
if test -z "$doit"; then
: >"$dsttmp" # No need to fork-exec 'touch'.
else
$doit touch "$dsttmp"
fi
}
} &&
$doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits. # and set any options; do chmod last to preserve setuid bits.
# #
@ -475,67 +459,49 @@ do
# ignore errors from any of these, just make sure not to ignore # ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command. # errors from the above "$doit $cpprog $src $dsttmp" command.
# #
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file. # Now rename the file to the real destination.
if $copy_on_change && { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && || {
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && # The rename failed, perhaps because mv can't rename something else
set -f && # to itself, or perhaps because mv is so ancient that it does not
set X $old && old=:$2:$4:$5:$6 && # support -f.
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# If $backupsuffix is set, and the file being installed
# already exists, attempt a backup. Don't worry if it fails,
# e.g., if mv doesn't support -f.
if test -n "$backupsuffix" && test -f "$dst"; then
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
fi
# Rename the file to the real destination. # Now remove or move aside any old file at destination location.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
if test -f "$dst"; then
$doit $rmcmd -f "$dst" 2>/dev/null \
|| { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \
&& { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\
|| {
echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
else
:
fi
} &&
# The rename failed, perhaps because mv can't rename something else # Now rename the file to the real destination.
# to itself, or perhaps because mv is so ancient that it does not $doit $mvcmd "$dsttmp" "$dst"
# support -f. }
{ } || exit 1
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0 trap '' 0
fi fi
done done
# Local variables: # Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp) # eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion=" # time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0" # time-stamp-end: "$"
# time-stamp-end: "; # UTC"
# End: # End:

View File

@ -1,9 +1,9 @@
#!/bin/sh #!/bin/sh
# py-compile - Compile a Python program # py-compile - Compile a Python program
scriptversion=2023-03-30.00; # UTC scriptversion=2011-06-08.12; # UTC
# Copyright (C) 2000-2023 Free Software Foundation, Inc. # Copyright (C) 2000-2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -16,7 +16,7 @@ scriptversion=2023-03-30.00; # UTC
# GNU General Public License for more details. # GNU General Public License for more details.
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you # As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a # distribute this file as part of a program that contains a
@ -27,7 +27,7 @@ scriptversion=2023-03-30.00; # UTC
# bugs to <bug-automake@gnu.org> or send patches to # bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>. # <automake-patches@gnu.org>.
if test -z "$PYTHON"; then if [ -z "$PYTHON" ]; then
PYTHON=python PYTHON=python
fi fi
@ -62,19 +62,13 @@ while test $# -ne 0; do
;; ;;
-h|--help) -h|--help)
cat <<\EOF cat <<\EOF
Usage: py-compile [options] FILES... Usage: py-compile [--help] [--version] [--basedir DIR] [--destdir DIR] FILES..."
Byte compile some python scripts FILES. Use --destdir to specify any Byte compile some python scripts FILES. Use --destdir to specify any
leading directory path to the FILES that you don't want to include in the leading directory path to the FILES that you don't want to include in the
byte compiled file. Specify --basedir for any additional path information you byte compiled file. Specify --basedir for any additional path information you
do want to be shown in the byte compiled file. do want to be shown in the byte compiled file.
Options:
--basedir DIR Prefix all FILES with DIR, and include in error messages.
--destdir DIR Prefix all FILES with DIR before compiling.
-v, --version Display version information.
-h, --help This help screen.
Example: Example:
py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py
@ -100,143 +94,77 @@ EOF
shift shift
done done
if test $# -eq 0; then files=$*
usage_error "no files given" if test -z "$files"; then
usage_error "no files given"
fi fi
# if basedir was given, then it should be prepended to filenames before # if basedir was given, then it should be prepended to filenames before
# byte compilation. # byte compilation.
if test -z "$basedir"; then if [ -z "$basedir" ]; then
pathtrans="path = file" pathtrans="path = file"
else else
pathtrans="path = os.path.join('$basedir', file)" pathtrans="path = os.path.join('$basedir', file)"
fi fi
# if destdir was given, then it needs to be prepended to the filename to # if destdir was given, then it needs to be prepended to the filename to
# byte compile but not go into the compiled file. # byte compile but not go into the compiled file.
if test -z "$destdir"; then if [ -z "$destdir" ]; then
filetrans="filepath = path" filetrans="filepath = path"
else else
filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)" filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
fi fi
python_major=`$PYTHON -c 'import sys; print(sys.version_info[0])'`
if test -z "$python_major"; then
usage_error "could not determine $PYTHON major version"
fi
case $python_major in
[01])
usage_error "python version 0.x and 1.x not supported"
;;
esac
python_minor=`$PYTHON -c 'import sys; print(sys.version_info[1])'`
# NB: When adding support for newer versions, prefer copying & adding new cases
# rather than try to keep things merged with shell variables.
# First byte compile (no optimization) all the modules.
# This works for all currently known Python versions.
$PYTHON -c " $PYTHON -c "
import sys, os, py_compile import sys, os, py_compile, imp
try: files = '''$files'''
import importlib
except ImportError:
importlib = None
# importlib.util.cache_from_source was added in 3.4
if (
hasattr(importlib, 'util')
and hasattr(importlib.util, 'cache_from_source')
):
destpath = importlib.util.cache_from_source
else:
destpath = lambda filepath: filepath + 'c'
sys.stdout.write('Byte-compiling python modules...\n') sys.stdout.write('Byte-compiling python modules...\n')
for file in sys.argv[1:]: for file in files.split():
$pathtrans $pathtrans
$filetrans $filetrans
if ( if not os.path.exists(filepath) or not (len(filepath) >= 3
not os.path.exists(filepath) and filepath[-3:] == '.py'):
or not (len(filepath) >= 3 and filepath[-3:] == '.py') continue
): sys.stdout.write(file)
continue
sys.stdout.write(file + ' ')
sys.stdout.flush() sys.stdout.flush()
py_compile.compile(filepath, destpath(filepath), path) if hasattr(imp, 'get_tag'):
sys.stdout.write('\n')" "$@" || exit $? py_compile.compile(filepath, imp.cache_from_source(filepath), path)
else:
py_compile.compile(filepath, filepath + 'c', path)
sys.stdout.write('\n')" || exit $?
# Then byte compile w/optimization all the modules. # this will fail for python < 1.5, but that doesn't matter ...
$PYTHON -O -c " $PYTHON -O -c "
import sys, os, py_compile import sys, os, py_compile, imp
try: # pypy does not use .pyo optimization
import importlib if hasattr(sys, 'pypy_translation_info'):
except ImportError:
importlib = None
# importlib.util.cache_from_source was added in 3.4
if (
hasattr(importlib, 'util')
and hasattr(importlib.util, 'cache_from_source')
):
destpath = importlib.util.cache_from_source
else:
destpath = lambda filepath: filepath + 'o'
# pypy2 does not use .pyo optimization
if sys.version_info.major <= 2 and hasattr(sys, 'pypy_translation_info'):
sys.exit(0) sys.exit(0)
files = '''$files'''
sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n') sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n')
for file in sys.argv[1:]: for file in files.split():
$pathtrans $pathtrans
$filetrans $filetrans
if ( if not os.path.exists(filepath) or not (len(filepath) >= 3
not os.path.exists(filepath) and filepath[-3:] == '.py'):
or not (len(filepath) >= 3 and filepath[-3:] == '.py') continue
): sys.stdout.write(file)
continue
sys.stdout.write(file + ' ')
sys.stdout.flush() sys.stdout.flush()
py_compile.compile(filepath, destpath(filepath), path) if hasattr(imp, 'get_tag'):
sys.stdout.write('\n')" "$@" 2>/dev/null || exit $? py_compile.compile(filepath, imp.cache_from_source(filepath, False), path)
else:
# Then byte compile w/more optimization. py_compile.compile(filepath, filepath + 'o', path)
# Only do this for Python 3.5+, see https://bugs.gnu.org/38043 for background. sys.stdout.write('\n')" 2>/dev/null || :
case $python_major.$python_minor in
2.*|3.[0-4])
;;
*)
$PYTHON -OO -c "
import sys, os, py_compile, importlib
sys.stdout.write('Byte-compiling python modules (more optimized versions)'
' ...\n')
for file in sys.argv[1:]:
$pathtrans
$filetrans
if (
not os.path.exists(filepath)
or not (len(filepath) >= 3 and filepath[-3:] == '.py')
):
continue
sys.stdout.write(file + ' ')
sys.stdout.flush()
py_compile.compile(filepath, importlib.util.cache_from_source(filepath), path)
sys.stdout.write('\n')" "$@" 2>/dev/null || exit $?
;;
esac
# Local Variables: # Local Variables:
# mode: shell-script # mode: shell-script
# sh-indentation: 2 # sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp) # eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion=" # time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0" # time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC" # time-stamp-end: "; # UTC"
# End: # End:

View File

@ -31,10 +31,10 @@ CLEAN_TARGETS += $(BASE_DEPENDS) $(BASE_OBJECTS) \
$(BASE_TARGET) $(BASE_TARGET)
$(BASE_TARGET): $(BASE_OBJECTS) $(BASE_TARGET): $(BASE_OBJECTS)
$(SHOW) " [AR] $@" @echo " [AR] $@"
$(Q) $(RM) $@ $(Q) $(RM) $@
$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null $(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null
ifeq ("$(USE_TRACKING)","yes") ifeq ("$(DEPENDS)","yes")
-include $(BASE_DEPENDS) -include $(BASE_DEPENDS)
endif endif

View File

@ -30,10 +30,10 @@ struct dm_hash_table {
unsigned num_nodes; unsigned num_nodes;
unsigned num_hint; unsigned num_hint;
unsigned mask_slots; /* (slots - 1) -> used as hash mask */ unsigned mask_slots; /* (slots - 1) -> used as hash mask */
unsigned collisions; /* Collisions of hash keys */ unsigned collisions; /* Collissions of hash keys */
unsigned search; /* How many keys were searched */ unsigned search; /* How many keys were searched */
unsigned found; /* How many nodes were found */ unsigned found; /* How many nodes were found */
unsigned same_hash; /* Was there a collision with same masked hash and len ? */ unsigned same_hash; /* Was there a colision with same masked hash and len ? */
struct dm_hash_node **slots; struct dm_hash_node **slots;
}; };
@ -41,7 +41,7 @@ struct dm_hash_table {
static unsigned _hash(const void *key, unsigned len) static unsigned _hash(const void *key, unsigned len)
{ {
/* Permutation of the Integers 0 through 255 */ /* Permutation of the Integers 0 through 255 */
static const unsigned char _nums[] = { static unsigned char _nums[] = {
1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51, 1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65, 87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28, 49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
@ -348,7 +348,7 @@ int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key,
/* /*
* Look through multiple entries with the same key for one that has a * Look through multiple entries with the same key for one that has a
* matching val and return that. If none have matching val, return NULL. * matching val and return that. If none have maching val, return NULL.
*/ */
void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key, void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key,
const void *val, uint32_t val_len) const void *val, uint32_t val_len)

View File

@ -19,7 +19,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <ctype.h>
//---------------------------------------------------------------- //----------------------------------------------------------------
@ -70,7 +69,7 @@ struct node48 {
}; };
struct node256 { struct node256 {
uint32_t nr_entries; uint32_t nr_entries;
struct value values[256]; struct value values[256];
}; };
@ -100,7 +99,7 @@ struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context)
static inline void _dtr(struct radix_tree *rt, union radix_value v) static inline void _dtr(struct radix_tree *rt, union radix_value v)
{ {
if (rt->dtr) if (rt->dtr)
rt->dtr(rt->dtr_context, v); rt->dtr(rt->dtr_context, v);
} }
// Returns the number of values removed // Returns the number of values removed
@ -119,8 +118,8 @@ static unsigned _free_node(struct radix_tree *rt, struct value v)
break; break;
case VALUE: case VALUE:
_dtr(rt, v.value); _dtr(rt, v.value);
nr = 1; nr = 1;
break; break;
case VALUE_CHAIN: case VALUE_CHAIN:
@ -179,9 +178,9 @@ unsigned radix_tree_size(struct radix_tree *rt)
return rt->nr_entries; return rt->nr_entries;
} }
static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv); static bool _insert(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv);
static bool _insert_unset(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv) static bool _insert_unset(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{ {
unsigned len = ke - kb; unsigned len = ke - kb;
@ -208,7 +207,7 @@ static bool _insert_unset(struct radix_tree *rt, struct value *v, const uint8_t
return true; return true;
} }
static bool _insert_value(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv) static bool _insert_value(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{ {
unsigned len = ke - kb; unsigned len = ke - kb;
@ -235,7 +234,7 @@ static bool _insert_value(struct radix_tree *rt, struct value *v, const uint8_t
return true; return true;
} }
static bool _insert_value_chain(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv) static bool _insert_value_chain(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{ {
struct value_chain *vc = v->value.ptr; struct value_chain *vc = v->value.ptr;
return _insert(rt, &vc->child, kb, ke, rv); return _insert(rt, &vc->child, kb, ke, rv);
@ -249,7 +248,7 @@ static unsigned min(unsigned lhs, unsigned rhs)
return rhs; return rhs;
} }
static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv) static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{ {
struct prefix_chain *pc = v->value.ptr; struct prefix_chain *pc = v->value.ptr;
@ -279,7 +278,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
pc->len = i; pc->len = i;
if (!_insert(rt, &pc->child, kb + i, ke, rv)) { if (!_insert(rt, &pc->child, kb + i, ke, rv)) {
free(pc->child.value.ptr); free(pc2);
return false; return false;
} }
@ -293,7 +292,6 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
if (pc->len == 1) { if (pc->len == 1) {
n4->values[0] = pc->child; n4->values[0] = pc->child;
free(pc); free(pc);
v->value.ptr = NULL;
} else { } else {
memmove(pc->prefix, pc->prefix + 1, pc->len - 1); memmove(pc->prefix, pc->prefix + 1, pc->len - 1);
pc->len--; pc->len--;
@ -315,7 +313,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
return true; return true;
} }
static bool _insert_node4(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv) static bool _insert_node4(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{ {
struct node4 *n4 = v->value.ptr; struct node4 *n4 = v->value.ptr;
if (n4->nr_entries == 4) { if (n4->nr_entries == 4) {
@ -345,7 +343,7 @@ static bool _insert_node4(struct radix_tree *rt, struct value *v, const uint8_t
return true; return true;
} }
static bool _insert_node16(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv) static bool _insert_node16(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{ {
struct node16 *n16 = v->value.ptr; struct node16 *n16 = v->value.ptr;
@ -384,7 +382,7 @@ static bool _insert_node16(struct radix_tree *rt, struct value *v, const uint8_t
return true; return true;
} }
static bool _insert_node48(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv) static bool _insert_node48(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{ {
struct node48 *n48 = v->value.ptr; struct node48 *n48 = v->value.ptr;
if (n48->nr_entries == 48) { if (n48->nr_entries == 48) {
@ -419,20 +417,20 @@ static bool _insert_node48(struct radix_tree *rt, struct value *v, const uint8_t
return true; return true;
} }
static bool _insert_node256(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv) static bool _insert_node256(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{ {
struct node256 *n256 = v->value.ptr; struct node256 *n256 = v->value.ptr;
bool r, was_unset = n256->values[*kb].type == UNSET; bool r, was_unset = n256->values[*kb].type == UNSET;
r = _insert(rt, n256->values + *kb, kb + 1, ke, rv); r = _insert(rt, n256->values + *kb, kb + 1, ke, rv);
if (r && was_unset) if (r && was_unset)
n256->nr_entries++; n256->nr_entries++;
return r; return r;
} }
// FIXME: the tree should not be touched if insert fails (eg, OOM) // FIXME: the tree should not be touched if insert fails (eg, OOM)
static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv) static bool _insert(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{ {
if (kb == ke) { if (kb == ke) {
if (v->type == UNSET) { if (v->type == UNSET) {
@ -489,10 +487,10 @@ static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, c
struct lookup_result { struct lookup_result {
struct value *v; struct value *v;
const uint8_t *kb; uint8_t *kb;
}; };
static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, const uint8_t *ke) static struct lookup_result _lookup_prefix(struct value *v, uint8_t *kb, uint8_t *ke)
{ {
unsigned i; unsigned i;
struct value_chain *vc; struct value_chain *vc;
@ -502,7 +500,7 @@ static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, c
struct node48 *n48; struct node48 *n48;
struct node256 *n256; struct node256 *n256;
if (kb == ke || !kb) /* extra check for !kb for coverity */ if (kb == ke)
return (struct lookup_result) {.v = v, .kb = kb}; return (struct lookup_result) {.v = v, .kb = kb};
switch (v->type) { switch (v->type) {
@ -557,32 +555,23 @@ static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, c
return (struct lookup_result) {.v = v, .kb = kb}; return (struct lookup_result) {.v = v, .kb = kb};
} }
bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value rv) bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value rv)
{ {
const uint8_t *kb = key;
const uint8_t *ke = kb + keylen;
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke); struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
return _insert(rt, lr.v, lr.kb, ke, rv); return _insert(rt, lr.v, lr.kb, ke, rv);
} }
int radix_tree_uniq_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value rv)
{
unsigned entries = rt->nr_entries;
return radix_tree_insert(rt, key, keylen, rv) ?
((entries != rt->nr_entries) ? 1 : -1) : 0;
}
// Note the degrade functions also free the original node. // Note the degrade functions also free the original node.
static void _degrade_to_n4(struct node16 *n16, struct value *result) static void _degrade_to_n4(struct node16 *n16, struct value *result)
{ {
struct node4 *n4 = zalloc(sizeof(*n4)); struct node4 *n4 = zalloc(sizeof(*n4));
assert(n4 != NULL); assert(n4 != NULL);
n4->nr_entries = n16->nr_entries; n4->nr_entries = n16->nr_entries;
memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys)); memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys));
memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values)); memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values));
free(n16); free(n16);
result->type = NODE4; result->type = NODE4;
result->value.ptr = n4; result->value.ptr = n4;
@ -591,20 +580,20 @@ static void _degrade_to_n4(struct node16 *n16, struct value *result)
static void _degrade_to_n16(struct node48 *n48, struct value *result) static void _degrade_to_n16(struct node48 *n48, struct value *result)
{ {
unsigned i, count = 0; unsigned i, count = 0;
struct node16 *n16 = zalloc(sizeof(*n16)); struct node16 *n16 = zalloc(sizeof(*n16));
assert(n16 != NULL); assert(n16 != NULL);
n16->nr_entries = n48->nr_entries; n16->nr_entries = n48->nr_entries;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
if (n48->keys[i] < 48) { if (n48->keys[i] < 48) {
n16->keys[count] = i; n16->keys[count] = i;
n16->values[count] = n48->values[n48->keys[i]]; n16->values[count] = n48->values[n48->keys[i]];
count++; count++;
} }
} }
free(n48); free(n48);
result->type = NODE16; result->type = NODE16;
result->value.ptr = n16; result->value.ptr = n16;
@ -612,13 +601,13 @@ static void _degrade_to_n16(struct node48 *n48, struct value *result)
static void _degrade_to_n48(struct node256 *n256, struct value *result) static void _degrade_to_n48(struct node256 *n256, struct value *result)
{ {
unsigned i, count = 0; unsigned i, count = 0;
struct node48 *n48 = zalloc(sizeof(*n48)); struct node48 *n48 = zalloc(sizeof(*n48));
assert(n48 != NULL); assert(n48 != NULL);
n48->nr_entries = n256->nr_entries; n48->nr_entries = n256->nr_entries;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
if (n256->values[i].type == UNSET) if (n256->values[i].type == UNSET)
n48->keys[i] = 48; n48->keys[i] = 48;
@ -627,9 +616,9 @@ static void _degrade_to_n48(struct node256 *n256, struct value *result)
n48->values[count] = n256->values[i]; n48->values[count] = n256->values[i];
count++; count++;
} }
} }
free(n256); free(n256);
result->type = NODE48; result->type = NODE48;
result->value.ptr = n48; result->value.ptr = n48;
@ -643,14 +632,14 @@ static void _erase_elt(void *array, size_t obj_size, unsigned count, unsigned id
return; return;
memmove(((uint8_t *) array) + (obj_size * idx), memmove(((uint8_t *) array) + (obj_size * idx),
((uint8_t *) array) + (obj_size * (idx + 1)), ((uint8_t *) array) + (obj_size * (idx + 1)),
obj_size * (count - idx - 1)); obj_size * (count - idx - 1));
// Zero the now unused last elt (set's v.type to UNSET) // Zero the now unused last elt (set's v.type to UNSET)
memset(((uint8_t *) array) + (count - 1) * obj_size, 0, obj_size); memset(((uint8_t *) array) + (count - 1) * obj_size, 0, obj_size);
} }
static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb, const uint8_t *ke) static bool _remove(struct radix_tree *rt, struct value *root, uint8_t *kb, uint8_t *ke)
{ {
bool r; bool r;
unsigned i, j; unsigned i, j;
@ -662,27 +651,27 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
struct node256 *n256; struct node256 *n256;
if (kb == ke) { if (kb == ke) {
if (root->type == VALUE) { if (root->type == VALUE) {
root->type = UNSET; root->type = UNSET;
_dtr(rt, root->value); _dtr(rt, root->value);
return true; return true;
} else if (root->type == VALUE_CHAIN) { } else if (root->type == VALUE_CHAIN) {
vc = root->value.ptr; vc = root->value.ptr;
_dtr(rt, vc->value); _dtr(rt, vc->value);
memcpy(root, &vc->child, sizeof(*root)); memcpy(root, &vc->child, sizeof(*root));
free(vc); free(vc);
return true; return true;
} else } else
return false; return false;
} }
switch (root->type) { switch (root->type) {
case UNSET: case UNSET:
case VALUE: case VALUE:
// this is a value for a prefix of the key // this is a value for a prefix of the key
return false; return false;
case VALUE_CHAIN: case VALUE_CHAIN:
vc = root->value.ptr; vc = root->value.ptr;
@ -697,11 +686,11 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
case PREFIX_CHAIN: case PREFIX_CHAIN:
pc = root->value.ptr; pc = root->value.ptr;
if (ke - kb < pc->len) if (ke - kb < pc->len)
return false; return false;
for (i = 0; i < pc->len; i++) for (i = 0; i < pc->len; i++)
if (kb[i] != pc->prefix[i]) if (kb[i] != pc->prefix[i])
return false; return false;
r = _remove(rt, &pc->child, kb + pc->len, ke); r = _remove(rt, &pc->child, kb + pc->len, ke);
if (r && pc->child.type == UNSET) { if (r && pc->child.type == UNSET) {
@ -716,12 +705,12 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
if (n4->keys[i] == *kb) { if (n4->keys[i] == *kb) {
r = _remove(rt, n4->values + i, kb + 1, ke); r = _remove(rt, n4->values + i, kb + 1, ke);
if (r && n4->values[i].type == UNSET) { if (r && n4->values[i].type == UNSET) {
if (i < n4->nr_entries) { if (i < n4->nr_entries) {
_erase_elt(n4->keys, sizeof(*n4->keys), n4->nr_entries, i); _erase_elt(n4->keys, sizeof(*n4->keys), n4->nr_entries, i);
_erase_elt(n4->values, sizeof(*n4->values), n4->nr_entries, i); _erase_elt(n4->values, sizeof(*n4->values), n4->nr_entries, i);
} }
n4->nr_entries--; n4->nr_entries--;
if (!n4->nr_entries) { if (!n4->nr_entries) {
free(n4); free(n4);
root->type = UNSET; root->type = UNSET;
@ -733,19 +722,19 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
return false; return false;
case NODE16: case NODE16:
n16 = root->value.ptr; n16 = root->value.ptr;
for (i = 0; i < n16->nr_entries; i++) { for (i = 0; i < n16->nr_entries; i++) {
if (n16->keys[i] == *kb) { if (n16->keys[i] == *kb) {
r = _remove(rt, n16->values + i, kb + 1, ke); r = _remove(rt, n16->values + i, kb + 1, ke);
if (r && n16->values[i].type == UNSET) { if (r && n16->values[i].type == UNSET) {
if (i < n16->nr_entries) { if (i < n16->nr_entries) {
_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i); _erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i);
_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i); _erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i);
} }
n16->nr_entries--; n16->nr_entries--;
if (n16->nr_entries <= 4) { if (n16->nr_entries <= 4) {
_degrade_to_n4(n16, root); _degrade_to_n4(n16, root);
} }
} }
return r; return r;
@ -757,18 +746,18 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
n48 = root->value.ptr; n48 = root->value.ptr;
i = n48->keys[*kb]; i = n48->keys[*kb];
if (i < 48) { if (i < 48) {
r = _remove(rt, n48->values + i, kb + 1, ke); r = _remove(rt, n48->values + i, kb + 1, ke);
if (r && n48->values[i].type == UNSET) { if (r && n48->values[i].type == UNSET) {
n48->keys[*kb] = 48; n48->keys[*kb] = 48;
for (j = 0; j < 256; j++) for (j = 0; j < 256; j++)
if (n48->keys[j] < 48 && n48->keys[j] > i) if (n48->keys[j] < 48 && n48->keys[j] > i)
n48->keys[j]--; n48->keys[j]--;
_erase_elt(n48->values, sizeof(*n48->values), n48->nr_entries, i); _erase_elt(n48->values, sizeof(*n48->values), n48->nr_entries, i);
n48->nr_entries--; n48->nr_entries--;
if (n48->nr_entries <= 16) if (n48->nr_entries <= 16)
_degrade_to_n16(n48, root); _degrade_to_n16(n48, root);
} }
return r; return r;
} }
return false; return false;
@ -778,7 +767,7 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
if (r && n256->values[*kb].type == UNSET) { if (r && n256->values[*kb].type == UNSET) {
n256->nr_entries--; n256->nr_entries--;
if (n256->nr_entries <= 48) if (n256->nr_entries <= 48)
_degrade_to_n48(n256, root); _degrade_to_n48(n256, root);
} }
return r; return r;
} }
@ -786,14 +775,11 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
return false; return false;
} }
bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen) bool radix_tree_remove(struct radix_tree *rt, uint8_t *key_begin, uint8_t *key_end)
{ {
const uint8_t *kb = key; if (_remove(rt, &rt->root, key_begin, key_end)) {
const uint8_t *ke = kb + keylen; rt->nr_entries--;
return true;
if (_remove(rt, &rt->root, kb, ke)) {
rt->nr_entries--;
return true;
} }
return false; return false;
@ -801,25 +787,25 @@ bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen)
//---------------------------------------------------------------- //----------------------------------------------------------------
static bool _prefix_chain_matches(const struct lookup_result *lr, const uint8_t *ke) static bool _prefix_chain_matches(struct lookup_result *lr, uint8_t *ke)
{ {
// It's possible the top node is a prefix chain, and // It's possible the top node is a prefix chain, and
// the remaining key matches part of it. // the remaining key matches part of it.
if (lr->v->type == PREFIX_CHAIN) { if (lr->v->type == PREFIX_CHAIN) {
unsigned i, rlen = ke - lr->kb; unsigned i, rlen = ke - lr->kb;
const struct prefix_chain *pc = lr->v->value.ptr; struct prefix_chain *pc = lr->v->value.ptr;
if (rlen < pc->len) { if (rlen < pc->len) {
for (i = 0; i < rlen; i++) for (i = 0; i < rlen; i++)
if (pc->prefix[i] != lr->kb[i]) if (pc->prefix[i] != lr->kb[i])
return false; return false;
return true; return true;
} }
} }
return false; return false;
} }
static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uint8_t *kb, const uint8_t *ke, unsigned *count) static bool _remove_subtree(struct radix_tree *rt, struct value *root, uint8_t *kb, uint8_t *ke, unsigned *count)
{ {
bool r; bool r;
unsigned i, j, len; unsigned i, j, len;
@ -840,7 +826,7 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
case UNSET: case UNSET:
case VALUE: case VALUE:
// No entries with the given prefix // No entries with the given prefix
return true; return true;
case VALUE_CHAIN: case VALUE_CHAIN:
vc = root->value.ptr; vc = root->value.ptr;
@ -857,7 +843,7 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
len = min(pc->len, ke - kb); len = min(pc->len, ke - kb);
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
if (kb[i] != pc->prefix[i]) if (kb[i] != pc->prefix[i])
return true; return true;
r = _remove_subtree(rt, &pc->child, len < pc->len ? ke : (kb + pc->len), ke, count); r = _remove_subtree(rt, &pc->child, len < pc->len ? ke : (kb + pc->len), ke, count);
if (r && pc->child.type == UNSET) { if (r && pc->child.type == UNSET) {
@ -872,12 +858,12 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
if (n4->keys[i] == *kb) { if (n4->keys[i] == *kb) {
r = _remove_subtree(rt, n4->values + i, kb + 1, ke, count); r = _remove_subtree(rt, n4->values + i, kb + 1, ke, count);
if (r && n4->values[i].type == UNSET) { if (r && n4->values[i].type == UNSET) {
if (i < n4->nr_entries) { if (i < n4->nr_entries) {
_erase_elt(n4->keys, sizeof(*n4->keys), n4->nr_entries, i); _erase_elt(n4->keys, sizeof(*n4->keys), n4->nr_entries, i);
_erase_elt(n4->values, sizeof(*n4->values), n4->nr_entries, i); _erase_elt(n4->values, sizeof(*n4->values), n4->nr_entries, i);
} }
n4->nr_entries--; n4->nr_entries--;
if (!n4->nr_entries) { if (!n4->nr_entries) {
free(n4); free(n4);
root->type = UNSET; root->type = UNSET;
@ -889,19 +875,19 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
return true; return true;
case NODE16: case NODE16:
n16 = root->value.ptr; n16 = root->value.ptr;
for (i = 0; i < n16->nr_entries; i++) { for (i = 0; i < n16->nr_entries; i++) {
if (n16->keys[i] == *kb) { if (n16->keys[i] == *kb) {
r = _remove_subtree(rt, n16->values + i, kb + 1, ke, count); r = _remove_subtree(rt, n16->values + i, kb + 1, ke, count);
if (r && n16->values[i].type == UNSET) { if (r && n16->values[i].type == UNSET) {
if (i < n16->nr_entries) { if (i < n16->nr_entries) {
_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i); _erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i);
_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i); _erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i);
} }
n16->nr_entries--; n16->nr_entries--;
if (n16->nr_entries <= 4) if (n16->nr_entries <= 4)
_degrade_to_n4(n16, root); _degrade_to_n4(n16, root);
} }
return r; return r;
} }
@ -912,18 +898,18 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
n48 = root->value.ptr; n48 = root->value.ptr;
i = n48->keys[*kb]; i = n48->keys[*kb];
if (i < 48) { if (i < 48) {
r = _remove_subtree(rt, n48->values + i, kb + 1, ke, count); r = _remove_subtree(rt, n48->values + i, kb + 1, ke, count);
if (r && n48->values[i].type == UNSET) { if (r && n48->values[i].type == UNSET) {
n48->keys[*kb] = 48; n48->keys[*kb] = 48;
for (j = 0; j < 256; j++) for (j = 0; j < 256; j++)
if (n48->keys[j] < 48 && n48->keys[j] > i) if (n48->keys[j] < 48 && n48->keys[j] > i)
n48->keys[j]--; n48->keys[j]--;
_erase_elt(n48->values, sizeof(*n48->values), n48->nr_entries, i); _erase_elt(n48->values, sizeof(*n48->values), n48->nr_entries, i);
n48->nr_entries--; n48->nr_entries--;
if (n48->nr_entries <= 16) if (n48->nr_entries <= 16)
_degrade_to_n16(n48, root); _degrade_to_n16(n48, root);
} }
return r; return r;
} }
return true; return true;
@ -936,7 +922,7 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
if (r && n256->values[*kb].type == UNSET) { if (r && n256->values[*kb].type == UNSET) {
n256->nr_entries--; n256->nr_entries--;
if (n256->nr_entries <= 48) if (n256->nr_entries <= 48)
_degrade_to_n48(n256, root); _degrade_to_n48(n256, root);
} }
return r; return r;
} }
@ -945,13 +931,11 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
return false; return false;
} }
unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, size_t prefix_len) unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
{ {
const uint8_t *kb = prefix; unsigned count = 0;
const uint8_t *ke = kb + prefix_len;
unsigned count = 0;
if (_remove_subtree(rt, &rt->root, kb, ke, &count)) if (_remove_subtree(rt, &rt->root, kb, ke, &count))
rt->nr_entries -= count; rt->nr_entries -= count;
return count; return count;
@ -959,11 +943,9 @@ unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, siz
//---------------------------------------------------------------- //----------------------------------------------------------------
bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen, bool radix_tree_lookup(struct radix_tree *rt,
union radix_value *result) uint8_t *kb, uint8_t *ke, union radix_value *result)
{ {
const uint8_t *kb = key;
const uint8_t *ke = kb + keylen;
struct value_chain *vc; struct value_chain *vc;
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke); struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
if (lr.kb == ke) { if (lr.kb == ke) {
@ -986,58 +968,58 @@ bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
} }
// FIXME: build up the keys too // FIXME: build up the keys too
static bool _iterate(struct radix_tree_iterator *it, const struct value *v) static bool _iterate(struct value *v, struct radix_tree_iterator *it)
{ {
unsigned i; unsigned i;
const struct value_chain *vc; struct value_chain *vc;
const struct prefix_chain *pc; struct prefix_chain *pc;
const struct node4 *n4; struct node4 *n4;
const struct node16 *n16; struct node16 *n16;
const struct node48 *n48; struct node48 *n48;
const struct node256 *n256; struct node256 *n256;
switch (v->type) { switch (v->type) {
case UNSET: case UNSET:
// can't happen // can't happen
break; break;
case VALUE: case VALUE:
return it->visit(it, NULL, 0, v->value); return it->visit(it, NULL, NULL, v->value);
case VALUE_CHAIN: case VALUE_CHAIN:
vc = v->value.ptr; vc = v->value.ptr;
return it->visit(it, NULL, 0, vc->value) && _iterate(it, &vc->child); return it->visit(it, NULL, NULL, vc->value) && _iterate(&vc->child, it);
case PREFIX_CHAIN: case PREFIX_CHAIN:
pc = v->value.ptr; pc = v->value.ptr;
return _iterate(it, &pc->child); return _iterate(&pc->child, it);
case NODE4: case NODE4:
n4 = (const struct node4 *) v->value.ptr; n4 = (struct node4 *) v->value.ptr;
for (i = 0; i < n4->nr_entries; i++) for (i = 0; i < n4->nr_entries; i++)
if (!_iterate(it, n4->values + i)) if (!_iterate(n4->values + i, it))
return false; return false;
return true; return true;
case NODE16: case NODE16:
n16 = (const struct node16 *) v->value.ptr; n16 = (struct node16 *) v->value.ptr;
for (i = 0; i < n16->nr_entries; i++) for (i = 0; i < n16->nr_entries; i++)
if (!_iterate(it, n16->values + i)) if (!_iterate(n16->values + i, it))
return false; return false;
return true; return true;
case NODE48: case NODE48:
n48 = (const struct node48 *) v->value.ptr; n48 = (struct node48 *) v->value.ptr;
for (i = 0; i < n48->nr_entries; i++) for (i = 0; i < n48->nr_entries; i++)
if (!_iterate(it, n48->values + i)) if (!_iterate(n48->values + i, it))
return false; return false;
return true; return true;
case NODE256: case NODE256:
n256 = (const struct node256 *) v->value.ptr; n256 = (struct node256 *) v->value.ptr;
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
if (n256->values[i].type != UNSET && !_iterate(it, n256->values + i)) if (n256->values[i].type != UNSET && !_iterate(n256->values + i, it))
return false; return false;
return true; return true;
} }
@ -1045,14 +1027,12 @@ static bool _iterate(struct radix_tree_iterator *it, const struct value *v)
return false; return false;
} }
void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen, void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
struct radix_tree_iterator *it) struct radix_tree_iterator *it)
{ {
const uint8_t *kb = key;
const uint8_t *ke = kb + keylen;
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke); struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
if (lr.kb == ke || _prefix_chain_matches(&lr, ke)) if (lr.kb == ke || _prefix_chain_matches(&lr, ke))
(void) _iterate(it, lr.v); (void) _iterate(lr.v, it);
} }
//---------------------------------------------------------------- //----------------------------------------------------------------
@ -1150,7 +1130,7 @@ static bool _check_nodes(struct value *v, unsigned *count)
if (ncount != n48->nr_entries) { if (ncount != n48->nr_entries) {
fprintf(stderr, "incorrect number of entries in n48, n48->nr_entries = %u, actual = %u\n", fprintf(stderr, "incorrect number of entries in n48, n48->nr_entries = %u, actual = %u\n",
n48->nr_entries, ncount); n48->nr_entries, ncount);
return false; return false;
} }
@ -1186,7 +1166,7 @@ static bool _check_nodes(struct value *v, unsigned *count)
if (ncount != n256->nr_entries) { if (ncount != n256->nr_entries) {
fprintf(stderr, "incorrect number of entries in n256, n256->nr_entries = %u, actual = %u\n", fprintf(stderr, "incorrect number of entries in n256, n256->nr_entries = %u, actual = %u\n",
n256->nr_entries, ncount); n256->nr_entries, ncount);
return false; return false;
} }
@ -1209,7 +1189,7 @@ bool radix_tree_is_well_formed(struct radix_tree *rt)
if (rt->nr_entries != count) { if (rt->nr_entries != count) {
fprintf(stderr, "incorrect entry count: rt->nr_entries = %u, actual = %u\n", fprintf(stderr, "incorrect entry count: rt->nr_entries = %u, actual = %u\n",
rt->nr_entries, count); rt->nr_entries, count);
return false; return false;
} }
@ -1227,7 +1207,6 @@ static void _dump(FILE *out, struct value v, unsigned indent)
struct node16 *n16; struct node16 *n16;
struct node48 *n48; struct node48 *n48;
struct node256 *n256; struct node256 *n256;
unsigned printable;
if (v.type == UNSET) if (v.type == UNSET)
return; return;
@ -1252,22 +1231,9 @@ static void _dump(FILE *out, struct value v, unsigned indent)
case PREFIX_CHAIN: case PREFIX_CHAIN:
pc = v.value.ptr; pc = v.value.ptr;
fprintf(out, "<prefix(%u): ", pc->len); fprintf(out, "<prefix: ");
printable = 1;
for (i = 0; i < pc->len; i++) for (i = 0; i < pc->len; i++)
if (!isprint(pc->prefix[i])) { fprintf(out, "%x.", (unsigned) *(pc->prefix + i));
printable = 0;
break;
}
if (printable)
fputc('"', out);
for (i = 0; i < pc->len; i++)
if (printable)
fprintf(out, "%c", pc->prefix[i]);
else
fprintf(out, "%02x.", (unsigned) *(pc->prefix + i));
if (printable)
fputc('"', out);
fprintf(out, ">\n"); fprintf(out, ">\n");
_dump(out, pc->child, indent + 1); _dump(out, pc->child, indent + 1);
break; break;
@ -1276,7 +1242,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
n4 = v.value.ptr; n4 = v.value.ptr;
fprintf(out, "<n4: "); fprintf(out, "<n4: ");
for (i = 0; i < n4->nr_entries; i++) for (i = 0; i < n4->nr_entries; i++)
fprintf(out, "%02x ", (unsigned) n4->keys[i]); fprintf(out, "%x ", (unsigned) n4->keys[i]);
fprintf(out, ">\n"); fprintf(out, ">\n");
for (i = 0; i < n4->nr_entries; i++) for (i = 0; i < n4->nr_entries; i++)
@ -1287,7 +1253,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
n16 = v.value.ptr; n16 = v.value.ptr;
fprintf(out, "<n16: "); fprintf(out, "<n16: ");
for (i = 0; i < n16->nr_entries; i++) for (i = 0; i < n16->nr_entries; i++)
fprintf(out, "%02x ", (unsigned) n16->keys[i]); fprintf(out, "%x ", (unsigned) n16->keys[i]);
fprintf(out, ">\n"); fprintf(out, ">\n");
for (i = 0; i < n16->nr_entries; i++) for (i = 0; i < n16->nr_entries; i++)
@ -1299,7 +1265,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
fprintf(out, "<n48: "); fprintf(out, "<n48: ");
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
if (n48->keys[i] < 48) if (n48->keys[i] < 48)
fprintf(out, "%02x ", i); fprintf(out, "%x ", i);
fprintf(out, ">\n"); fprintf(out, ">\n");
for (i = 0; i < n48->nr_entries; i++) { for (i = 0; i < n48->nr_entries; i++) {
@ -1313,7 +1279,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
fprintf(out, "<n256: "); fprintf(out, "<n256: ");
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
if (n256->values[i].type != UNSET) if (n256->values[i].type != UNSET)
fprintf(out, "%02x ", i); fprintf(out, "%x ", i);
fprintf(out, ">\n"); fprintf(out, ">\n");
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)

View File

@ -1,5 +1,5 @@
// Copyright (C) 2018 Red Hat, Inc. All rights reserved. // Copyright (C) 2018 Red Hat, Inc. All rights reserved.
// //
// This file is part of LVM2. // This file is part of LVM2.
// //
// This copyrighted material is made available to anyone wishing to use, // This copyrighted material is made available to anyone wishing to use,
@ -18,7 +18,6 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <ctype.h>
//---------------------------------------------------------------- //----------------------------------------------------------------
// This implementation is based around nested binary trees. Very // This implementation is based around nested binary trees. Very
@ -38,12 +37,12 @@ struct node {
struct radix_tree { struct radix_tree {
radix_value_dtr dtr; radix_value_dtr dtr;
void *dtr_context; void *dtr_context;
unsigned nr_entries;
struct node *root; struct node *root;
}; };
struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context) struct radix_tree *
radix_tree_create(radix_value_dtr dtr, void *dtr_context)
{ {
struct radix_tree *rt = zalloc(sizeof(*rt)); struct radix_tree *rt = zalloc(sizeof(*rt));
@ -106,7 +105,7 @@ unsigned radix_tree_size(struct radix_tree *rt)
return _count(rt->root); return _count(rt->root);
} }
static struct node **_lookup(struct node **pn, const uint8_t *kb, const uint8_t *ke) static struct node **_lookup(struct node **pn, uint8_t *kb, uint8_t *ke)
{ {
struct node *n = *pn; struct node *n = *pn;
@ -123,7 +122,7 @@ static struct node **_lookup(struct node **pn, const uint8_t *kb, const uint8_t
return _lookup(&n->center, kb + 1, ke); return _lookup(&n->center, kb + 1, ke);
} }
static bool _insert(struct node **pn, const uint8_t *kb, const uint8_t *ke, union radix_value v) static bool _insert(struct node **pn, uint8_t *kb, uint8_t *ke, union radix_value v)
{ {
struct node *n = *pn; struct node *n = *pn;
@ -152,53 +151,41 @@ static bool _insert(struct node **pn, const uint8_t *kb, const uint8_t *ke, unio
return _insert(&n->center, kb + 1, ke, v); return _insert(&n->center, kb + 1, ke, v);
} }
bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen, bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v)
union radix_value v)
{ {
const uint8_t *kb = key; return _insert(&rt->root, kb, ke, v);
const uint8_t *ke = kb + keylen;
if (!_insert(&rt->root, kb, ke, v))
return false;
rt->nr_entries++;
return true;
} }
bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen) bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
{ {
const uint8_t *kb = key;
const uint8_t *ke = kb + keylen;
struct node **pn = _lookup(&rt->root, kb, ke); struct node **pn = _lookup(&rt->root, kb, ke);
struct node *n = *pn; struct node *n = *pn;
if (!n || !n->has_value) if (!n || !n->has_value)
return false; return false;
rt->nr_entries--; else {
if (rt->dtr)
rt->dtr(rt->dtr_context, n->value);
if (rt->dtr) if (n->left || n->center || n->right) {
rt->dtr(rt->dtr_context, n->value); n->has_value = false;
return true;
if (n->left || n->center || n->right) { } else {
n->has_value = false; // FIXME: delete parent if this was the last entry
return true; free(n);
*pn = NULL;
}
return true;
} }
// FIXME: delete parent if this was the last entry
free(n);
*pn = NULL;
return true;
} }
unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, size_t prefix_len) unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
{ {
const uint8_t *kb = prefix;
const uint8_t *ke = kb + prefix_len;
struct node **pn; struct node **pn;
unsigned count = 0; unsigned count;
pn = _lookup(&rt->root, kb, ke); pn = _lookup(&rt->root, kb, ke);
@ -210,20 +197,17 @@ unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, siz
return count; return count;
} }
bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen, bool
union radix_value *result) radix_tree_lookup(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value *result)
{ {
const uint8_t *kb = key;
const uint8_t *ke = kb + keylen;
struct node **pn = _lookup(&rt->root, kb, ke); struct node **pn = _lookup(&rt->root, kb, ke);
struct node *n = *pn; struct node *n = *pn;
if (n && n->has_value) { if (n && n->has_value) {
*result = n->value; *result = n->value;
return true; return true;
} } else
return false;
return false;
} }
static void _iterate(struct node *n, struct radix_tree_iterator *it) static void _iterate(struct node *n, struct radix_tree_iterator *it)
@ -235,18 +219,15 @@ static void _iterate(struct node *n, struct radix_tree_iterator *it)
if (n->has_value) if (n->has_value)
// FIXME: fill out the key // FIXME: fill out the key
it->visit(it, NULL, 0, n->value); it->visit(it, NULL, NULL, n->value);
_iterate(n->center, it); _iterate(n->center, it);
_iterate(n->right, it); _iterate(n->right, it);
} }
void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen, void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
struct radix_tree_iterator *it) struct radix_tree_iterator *it)
{ {
const uint8_t *kb = key;
const uint8_t *ke = kb + keylen;
if (kb == ke) if (kb == ke)
_iterate(rt->root, it); _iterate(rt->root, it);
@ -256,7 +237,7 @@ void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
if (n) { if (n) {
if (n->has_value) if (n->has_value)
it->visit(it, NULL, 0, n->value); it->visit(it, NULL, NULL, n->value);
_iterate(n->center, it); _iterate(n->center, it);
} }
} }
@ -267,32 +248,8 @@ bool radix_tree_is_well_formed(struct radix_tree *rt)
return true; return true;
} }
static void _dump(FILE *out, struct node *n, unsigned indent)
{
unsigned i;
if (!n)
return;
_dump(out, n->left, indent + 1);
for (i = 0; i < 2 * indent; i++)
fprintf(out, " ");
if (n->has_value) {
fprintf(out, "value: %lu\n", (unsigned long) n->value.n);
} else {
fprintf(out, "key: '%c' [0x%02x] %u\n",
isprint(n->key) ? n->key : ' ', n->key, indent);
}
_dump(out, n->center, indent + 1);
_dump(out, n->right, indent + 1);
}
void radix_tree_dump(struct radix_tree *rt, FILE *out) void radix_tree_dump(struct radix_tree *rt, FILE *out)
{ {
_dump(out, rt->root, 0);
} }
//---------------------------------------------------------------- //----------------------------------------------------------------

View File

@ -19,45 +19,3 @@
#endif #endif
//---------------------------------------------------------------- //----------------------------------------------------------------
struct visitor {
struct radix_tree_iterator it;
unsigned pos, nr_entries;
union radix_value *values;
};
static bool _visitor(struct radix_tree_iterator *it,
const void *key, size_t keylen,
union radix_value v)
{
struct visitor *vt = container_of(it, struct visitor, it);
if (vt->pos >= vt->nr_entries)
return false;
vt->values[vt->pos++] = v;
return true;
}
bool radix_tree_values(struct radix_tree *rt, const void *key, size_t keylen,
union radix_value **values, unsigned *nr_values)
{
struct visitor vt = {
.it.visit = _visitor,
.nr_entries = rt->nr_entries,
.values = calloc(rt->nr_entries + 1, sizeof(union radix_value)),
};
if (vt.values) {
// build set of all values in current radix tree
radix_tree_iterate(rt, key, keylen, &vt.it);
*nr_values = vt.pos;
*values = vt.values;
return true;
}
return false;
}
//----------------------------------------------------------------

View File

@ -33,61 +33,32 @@ struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context);
void radix_tree_destroy(struct radix_tree *rt); void radix_tree_destroy(struct radix_tree *rt);
unsigned radix_tree_size(struct radix_tree *rt); unsigned radix_tree_size(struct radix_tree *rt);
bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value v); bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v);
bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen); bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke);
// Returns: 1 success
// 0 failure during insert
// -1 key had already existing value (that was updated)
int radix_tree_uniq_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value v);
// Returns the number of values removed // Returns the number of values removed
unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, size_t prefix_len); unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *prefix_b, uint8_t *prefix_e);
bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen, bool radix_tree_lookup(struct radix_tree *rt,
union radix_value *result); uint8_t *kb, uint8_t *ke, union radix_value *result);
// The radix tree stores entries in lexicographical order. Which means // The radix tree stores entries in lexicographical order. Which means
// we can iterate entries, in order. Or iterate entries with a particular // we can iterate entries, in order. Or iterate entries with a particular
// prefix. // prefix.
struct radix_tree_iterator { struct radix_tree_iterator {
// Returns false if the iteration should end. // Returns false if the iteration should end.
bool (*visit)(struct radix_tree_iterator *it, bool (*visit)(struct radix_tree_iterator *it,
const void *key, size_t keylen, union radix_value v); uint8_t *kb, uint8_t *ke, union radix_value v);
}; };
void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen, void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
struct radix_tree_iterator *it); struct radix_tree_iterator *it);
// Alternative traversing radix_tree.
// Builds whole set all radix_tree nr_values values.
// After use, free(values).
bool radix_tree_values(struct radix_tree *rt, const void *key, size_t keylen,
union radix_value **values, unsigned *nr_values);
// Checks that some constraints on the shape of the tree are // Checks that some constraints on the shape of the tree are
// being held. For debug only. // being held. For debug only.
bool radix_tree_is_well_formed(struct radix_tree *rt); bool radix_tree_is_well_formed(struct radix_tree *rt);
void radix_tree_dump(struct radix_tree *rt, FILE *out); void radix_tree_dump(struct radix_tree *rt, FILE *out);
// Shortcut for ptr value return
// Note: if value would be NULL, it's same result for not/found case.
static inline void *radix_tree_lookup_ptr(struct radix_tree *rt, const void *key, size_t keylen)
{
union radix_value v;
return radix_tree_lookup(rt, key, keylen, &v) ? v.ptr : NULL;
}
static inline bool radix_tree_insert_ptr(struct radix_tree *rt, const void *key, size_t keylen, void *ptr)
{
union radix_value v = { .ptr = ptr };
return radix_tree_insert(rt, key, keylen, v);
}
static inline int radix_tree_uniq_insert_ptr(struct radix_tree *rt, const void *key, size_t keylen, void *ptr)
{
union radix_value v = { .ptr = ptr };
return radix_tree_uniq_insert(rt, key, keylen, v);
}
//---------------------------------------------------------------- //----------------------------------------------------------------
#endif #endif

View File

@ -49,7 +49,7 @@ install_localconf: $(CONFLOCAL)
fi fi
install_profiles: $(PROFILES) install_profiles: $(PROFILES)
$(SHOW) " [INSTALL] $<" @echo " [INSTALL] $<"
$(Q) $(INSTALL_DIR) $(profiledir) $(Q) $(INSTALL_DIR) $(profiledir)
$(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/ $(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/

View File

@ -36,19 +36,6 @@ config {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# checks = 1 # checks = 1
# Configuration option config/validate_metadata.
# Allows to select the level of validation after metadata transformation.
# Validation takes extra CPU time to verify internal consistency.
# Accepted values:
# full
# Do a full metadata validation before disk write.
# none
# Skip any checks (unrecommended, slightly faster).
#
# This configuration option is advanced.
# This configuration option has an automatic default value.
# validate_metadata = "full"
# Configuration option config/abort_on_errors. # Configuration option config/abort_on_errors.
# Abort the LVM process if a configuration mismatch is found. # Abort the LVM process if a configuration mismatch is found.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
@ -135,11 +122,11 @@ devices {
# Configuration option devices/use_devicesfile. # Configuration option devices/use_devicesfile.
# Enable or disable the use of a devices file. # Enable or disable the use of a devices file.
# When enabled, lvm will only use devices that # When enabled, lvm will only use devices that
# are listed in the devices file. A devices file will # are lised in the devices file. A devices file will
# be used, regardless of this setting, when the --devicesfile # be used, regardless of this setting, when the --devicesfile
# option is set to a specific file name. # option is set to a specific file name.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# use_devicesfile = @DEFAULT_USE_DEVICES_FILE@ # use_devicesfile = 0
# Configuration option devices/devicesfile. # Configuration option devices/devicesfile.
# The name of the system devices file, listing devices that LVM should use. # The name of the system devices file, listing devices that LVM should use.
@ -148,16 +135,6 @@ devices {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# devicesfile = "system.devices" # devicesfile = "system.devices"
# Configuration option devices/devicesfile_backup_limit.
# The max number of backup files to keep in /etc/lvm/devices/backup.
# LVM creates a backup of the devices file each time a new
# version is created, or each time a modification is detected.
# When the max number of backups is reached, the oldest are
# removed to remain at the limit. Set to 0 to disable backups.
# Only the system devices file is backed up.
# This configuration option has an automatic default value.
# devicesfile_backup_limit = 50
# Configuration option devices/search_for_devnames. # Configuration option devices/search_for_devnames.
# Look outside of the devices file for missing devname entries. # Look outside of the devices file for missing devname entries.
# A devname entry is used for a device that does not have a stable # A devname entry is used for a device that does not have a stable
@ -172,27 +149,7 @@ devices {
# at other devices, but only those that are likely to have the PV. # at other devices, but only those that are likely to have the PV.
# If "all", lvm will look at all devices on the system. # If "all", lvm will look at all devices on the system.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# search_for_devnames = "all" # search_for_devnames = "auto"
# Configuration option devices/device_ids_refresh.
# Find PVs on new devices and update the device IDs in the devices file.
# If PVs are restored or moved to a new system with new devices, but
# an old system.devices remains with old device IDs, then search for
# the PVIDs on new devices and update the device IDs in system.devices.
# The original device IDs must also not be found on the new system.
# See device_ids_refresh_check for conditions that trigger the refresh.
# This configuration option has an automatic default value.
# device_ids_refresh = 1
# Configuration option devices/device_ids_refresh_checks.
# Conditions that trigger device_ids_refresh to locate PVIDs on new devices.
# product_uuid: refresh if /sys/devices/virtual/dmi/id/product_uuid does not
# match the value saved in system.devices.
# hostname: refresh if hostname does not match the value saved in system.devices.
# (hostname is used if product_uuid is not available.)
# Remove values from this list to prevent lvm from using them.
# This configuration option has an automatic default value.
# device_ids_refresh_checks = [ "product_uuid", "hostname" ]
# Configuration option devices/filter. # Configuration option devices/filter.
# Limit the block devices that are used by LVM commands. # Limit the block devices that are used by LVM commands.
@ -254,12 +211,17 @@ devices {
# sysfs_scan = 1 # sysfs_scan = 1
# Configuration option devices/scan_lvs. # Configuration option devices/scan_lvs.
# Allow LVM LVs to be used as PVs. When enabled, LVM commands will # Scan LVM LVs for layered PVs, allowing LVs to be used as PVs.
# scan active LVs to look for other PVs. Caution is required to # When 1, LVM will detect PVs layered on LVs, and caution must be
# avoid using PVs that belong to guest images stored on LVs. # taken to avoid a host accessing a layered VG that may not belong
# When enabled, the LVs scanned should be restricted using the # to it, e.g. from a guest image. This generally requires excluding
# devices file or the filter. This option does not enable autoactivation # the LVs with device filters. Also, when this setting is enabled,
# of layered VGs, which requires editing LVM udev rules (see LVM_PVSCAN_ON_LVS.) # every LVM command will scan every active LV on the system (unless
# filtered), which can cause performance problems on systems with
# many active LVs. When this setting is 0, LVM will not detect or
# use PVs that exist on LVs, and will not allow a PV to be created on
# an LV. The LVs are ignored using a built in device filter that
# identifies and excludes LVs.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# scan_lvs = 0 # scan_lvs = 0
@ -575,7 +537,7 @@ allocation {
# Configuration option allocation/cache_pool_max_chunks. # Configuration option allocation/cache_pool_max_chunks.
# The maximum number of chunks in a cache pool. # The maximum number of chunks in a cache pool.
# For cache target v1.9 the recommended maximum is 1000000 chunks. # For cache target v1.9 the recommended maximumm is 1000000 chunks.
# Using cache pool with more chunks may degrade cache performance. # Using cache pool with more chunks may degrade cache performance.
# This configuration option does not have a default value defined. # This configuration option does not have a default value defined.
@ -586,7 +548,7 @@ allocation {
# Configuration option allocation/thin_pool_crop_metadata. # Configuration option allocation/thin_pool_crop_metadata.
# Older version of lvm2 cropped pool's metadata size to 15.81 GiB. # Older version of lvm2 cropped pool's metadata size to 15.81 GiB.
# This is slightly less than the actual maximum 15.88 GiB. # This is slightly less then the actual maximum 15.88 GiB.
# For compatibility with older version and use of cropped size set to 1. # For compatibility with older version and use of cropped size set to 1.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# thin_pool_crop_metadata = 0 # thin_pool_crop_metadata = 0
@ -659,9 +621,17 @@ allocation {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# vdo_use_deduplication = 1 # vdo_use_deduplication = 1
# Configuration option allocation/vdo_use_metadata_hints.
# Enables or disables whether VDO volume should tag its latency-critical
# writes with the REQ_SYNC flag. Some device mapper targets such as dm-raid5
# process writes with this flag at a higher priority.
# Default is enabled.
# This configuration option has an automatic default value.
# vdo_use_metadata_hints = 1
# Configuration option allocation/vdo_minimum_io_size. # Configuration option allocation/vdo_minimum_io_size.
# The minimum IO size for VDO volume to accept, in bytes. # The minimum IO size for VDO volume to accept, in bytes.
# Valid values are 512 or 4096. The recommended value is 4096. # Valid values are 512 or 4096. The recommended and default value is 4096.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# vdo_minimum_io_size = 4096 # vdo_minimum_io_size = 4096
@ -681,6 +651,11 @@ allocation {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# vdo_block_map_period = 16380 # vdo_block_map_period = 16380
# Configuration option allocation/vdo_check_point_frequency.
# The default check point frequency for VDO volume.
# This configuration option has an automatic default value.
# vdo_check_point_frequency = 0
# Configuration option allocation/vdo_use_sparse_index. # Configuration option allocation/vdo_use_sparse_index.
# Enables sparse indexing for VDO volume. # Enables sparse indexing for VDO volume.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
@ -709,7 +684,7 @@ allocation {
# Configuration option allocation/vdo_bio_threads. # Configuration option allocation/vdo_bio_threads.
# Specifies the number of threads to use for submitting I/O # Specifies the number of threads to use for submitting I/O
# operations to the storage device of VDO volume. # operations to the storage device of VDO volume.
# The value must be in range [1..100]. # The value must be in range [1..100]
# Each additional thread after the first will use an additional 18MiB of RAM, # Each additional thread after the first will use an additional 18MiB of RAM,
# plus 1.12 MiB of RAM per megabyte of configured read cache size. # plus 1.12 MiB of RAM per megabyte of configured read cache size.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
@ -723,7 +698,7 @@ allocation {
# Configuration option allocation/vdo_cpu_threads. # Configuration option allocation/vdo_cpu_threads.
# Specifies the number of threads to use for CPU-intensive work such as # Specifies the number of threads to use for CPU-intensive work such as
# hashing or compression for VDO volume. The value must be in range [1..100]. # hashing or compression for VDO volume. The value must be in range [1..100]
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# vdo_cpu_threads = 2 # vdo_cpu_threads = 2
@ -741,7 +716,7 @@ allocation {
# processing based on the hash value computed from the block data. # processing based on the hash value computed from the block data.
# A logical thread count of 9 or more will require explicitly specifying # A logical thread count of 9 or more will require explicitly specifying
# a sufficiently large block map cache size, as well. # a sufficiently large block map cache size, as well.
# The value must be in range [0..60]. # The value must be in range [0..100].
# vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be # vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
# either all zero or all non-zero. # either all zero or all non-zero.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
@ -757,6 +732,19 @@ allocation {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# vdo_physical_threads = 1 # vdo_physical_threads = 1
# Configuration option allocation/vdo_write_policy.
# Specifies the write policy:
# auto - VDO will check the storage device and determine whether it supports flushes.
# If it does, VDO will run in async mode, otherwise it will run in sync mode.
# sync - Writes are acknowledged only after data is stably written.
# This policy is not supported if the underlying storage is not also synchronous.
# async - Writes are acknowledged after data has been cached for writing to stable storage.
# Data which has not been flushed is not guaranteed to persist in this mode.
# async-unsafe - Writes are handled like 'async' but there is no guarantee of the atomicity async provides.
# This mode should only be used for better performance when atomicity is not required.
# This configuration option has an automatic default value.
# vdo_write_policy = "auto"
# Configuration option allocation/vdo_max_discard. # Configuration option allocation/vdo_max_discard.
# Specified the maximum size of discard bio accepted, in 4096 byte blocks. # Specified the maximum size of discard bio accepted, in 4096 byte blocks.
# I/O requests to a VDO volume are normally split into 4096-byte blocks, # I/O requests to a VDO volume are normally split into 4096-byte blocks,
@ -770,7 +758,7 @@ allocation {
# vdo_max_discard = 1 # vdo_max_discard = 1
# Configuration option allocation/vdo_pool_header_size. # Configuration option allocation/vdo_pool_header_size.
# Specified the empty header size in KiB at the front and end of vdo pool device. # Specified the emptry header size in KiB at the front and end of vdo pool device.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# vdo_pool_header_size = 512 # vdo_pool_header_size = 512
} }
@ -794,9 +782,6 @@ log {
# to define fields to display and sort fields for the log report. # to define fields to display and sort fields for the log report.
# You can also use log/command_log_selection to define selection # You can also use log/command_log_selection to define selection
# criteria used each time the log is reported. # criteria used each time the log is reported.
# Note that if report/output_format (or --reportformat command line
# option) is set to json or json_std, then log/report_command_log=1
# is default.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# report_command_log = 0 # report_command_log = 0
@ -826,9 +811,8 @@ log {
# define selection criteria for log report on command line directly # define selection criteria for log report on command line directly
# using <lvm command> --configreport log -S <selection criteria> # using <lvm command> --configreport log -S <selection criteria>
# which has precedence over log/command_log_selection setting. # which has precedence over log/command_log_selection setting.
# To make all the command log lines visible, use "all" value # For more information about selection criteria in general, see
# for the command log selection. For more information about selection # lvm(8) man page.
# criteria in general, see lvmreport(7) man page.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# command_log_selection = "!(log_type=status && message=success)" # command_log_selection = "!(log_type=status && message=success)"
@ -953,7 +937,7 @@ backup {
# archive = 1 # archive = 1
# Configuration option backup/archive_dir. # Configuration option backup/archive_dir.
# Location of the metadata archive files. # Location of the metdata archive files.
# Remember to back up this directory regularly! # Remember to back up this directory regularly!
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# archive_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@" # archive_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@"
@ -1029,7 +1013,7 @@ global {
# Location of proc filesystem. # Location of proc filesystem.
# This configuration option is advanced. # This configuration option is advanced.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# proc = "@DEFAULT_PROC_DIR@" # proc = "/proc"
# Configuration option global/etc. # Configuration option global/etc.
# Location of /etc system configuration directory. # Location of /etc system configuration directory.
@ -1173,7 +1157,7 @@ global {
# services (via the lvm2-activation-generator), but the autoactivation # services (via the lvm2-activation-generator), but the autoactivation
# services and generator have been removed. # services and generator have been removed.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# event_activation = @DEFAULT_EVENT_ACTIVATION@ # event_activation = 1
# Configuration option global/use_aio. # Configuration option global/use_aio.
# Use async I/O when reading and writing devices. # Use async I/O when reading and writing devices.
@ -1205,16 +1189,6 @@ global {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# sanlock_lv_extend = 256 # sanlock_lv_extend = 256
# Configuration option global/sanlock_align_size.
# The sanlock lease size in MiB to use on disks with a 4K sector size.
# Possible values are 1,2,4,8. The default is 8, which supports up to
# 2000 hosts (and max host_id 2000.) Smaller values support smaller
# numbers of max hosts (and max host_ids): 250, 500, 1000, 2000 for
# lease sizes 1,2,4,8. Disks with 512 byte sectors always use 1MiB
# leases and support 2000 hosts, and are not affected by this setting.
# This configuration option has an automatic default value.
# sanlock_align_size = 8
# Configuration option global/lvmlockctl_kill_command. # Configuration option global/lvmlockctl_kill_command.
# The command that lvmlockctl --kill should use to force LVs offline. # The command that lvmlockctl --kill should use to force LVs offline.
# The lvmlockctl --kill command is run when a shared VG has lost # The lvmlockctl --kill command is run when a shared VG has lost
@ -1228,7 +1202,7 @@ global {
# Configuration option global/thin_check_executable. # Configuration option global/thin_check_executable.
# The full path to the thin_check command. # The full path to the thin_check command.
# LVM uses this command to check that a thin pool metadata device is in a # LVM uses this command to check that a thin metadata device is in a
# usable state. When a thin pool is activated and after it is # usable state. When a thin pool is activated and after it is
# deactivated, this command is run. Activation will only proceed if # deactivated, this command is run. Activation will only proceed if
# the command has an exit status of 0. Set to "" to skip this check. # the command has an exit status of 0. Set to "" to skip this check.
@ -1252,14 +1226,6 @@ global {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# thin_repair_executable = "@THIN_REPAIR_CMD@" # thin_repair_executable = "@THIN_REPAIR_CMD@"
# Configuration option global/thin_restore_executable.
# The full path to the thin_restore command.
# LVM uses this command to restore generated data for a thin pool metadata device.
# Also see thin_restore_options.
# (See package device-mapper-persistent-data or thin-provisioning-tools)
# This configuration option has an automatic default value.
# thin_restore_executable = "@THIN_RESTORE_CMD@"
# Configuration option global/thin_check_options. # Configuration option global/thin_check_options.
# List of options passed to the thin_check command. # List of options passed to the thin_check command.
# With thin_check version 2.1 or newer you can add the option # With thin_check version 2.1 or newer you can add the option
@ -1274,11 +1240,6 @@ global {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# thin_repair_options = [ "" ] # thin_repair_options = [ "" ]
# Configuration option global/thin_restore_options.
# List of options passed to the thin_restore command.
# This configuration option has an automatic default value.
# thin_restore_options = [ "" ]
# Configuration option global/thin_disabled_features. # Configuration option global/thin_disabled_features.
# Features to not use in the thin driver. # Features to not use in the thin driver.
# This can be helpful for testing, or to avoid using a feature that is # This can be helpful for testing, or to avoid using a feature that is
@ -1327,14 +1288,6 @@ global {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# cache_repair_executable = "@CACHE_REPAIR_CMD@" # cache_repair_executable = "@CACHE_REPAIR_CMD@"
# Configuration option global/cache_restore_executable.
# The full path to the cache_restore command.
# LVM uses this command to restore generated data for a cache metadata device.
# Also see cache_restore_options.
# (See package device-mapper-persistent-data or thin-provisioning-tools)
# This configuration option has an automatic default value.
# cache_restore_executable = "@CACHE_RESTORE_CMD@"
# Configuration option global/cache_check_options. # Configuration option global/cache_check_options.
# List of options passed to the cache_check command. # List of options passed to the cache_check command.
# With cache_check version 5.0 or newer you should include the option # With cache_check version 5.0 or newer you should include the option
@ -1347,11 +1300,6 @@ global {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# cache_repair_options = [ "" ] # cache_repair_options = [ "" ]
# Configuration option global/cache_restore_options.
# List of options passed to the cache_restore command.
# This configuration option has an automatic default value.
# cache_restore_options = [ "" ]
# Configuration option global/vdo_format_executable. # Configuration option global/vdo_format_executable.
# The full path to the vdoformat command. # The full path to the vdoformat command.
# LVM uses this command to initial data volume for VDO type logical volume # LVM uses this command to initial data volume for VDO type logical volume
@ -1366,10 +1314,10 @@ global {
# Configuration option global/vdo_disabled_features. # Configuration option global/vdo_disabled_features.
# Features to not use in the vdo driver. # Features to not use in the vdo driver.
# This can be helpful for testing, or to avoid using a feature that is # This can be helpful for testing, or to avoid using a feature that is
# causing problems. Features include: online_rename, version4 # causing problems. Features include: online_rename
# #
# Example # Example
# vdo_disabled_features = [ "online_rename", "version4" ] # vdo_disabled_features = [ "online_rename" ]
# #
# This configuration option does not have a default value defined. # This configuration option does not have a default value defined.
@ -1379,12 +1327,6 @@ global {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# fsadm_executable = "@FSADM_PATH@" # fsadm_executable = "@FSADM_PATH@"
# Configuration option global/lvresize_fs_helper_executable.
# The full path to the lvresize_fs_helper command.
# LVM uses this command to help with filesystem operations during lvresize.
# This configuration option has an automatic default value.
# lvresize_fs_helper_executable = "@LVRESIZE_FS_HELPER_PATH@"
# Configuration option global/system_id_source. # Configuration option global/system_id_source.
# The method LVM uses to set the local system ID. # The method LVM uses to set the local system ID.
# Volume Groups can also be given a system ID (by vgcreate, vgchange, # Volume Groups can also be given a system ID (by vgcreate, vgchange,
@ -1405,9 +1347,8 @@ global {
# Use an LVM-specific derivation of the local machine-id as the # Use an LVM-specific derivation of the local machine-id as the
# system ID. See 'man machine-id'. # system ID. See 'man machine-id'.
# machineid # machineid
# Use the contents of the machine-id file to set the system ID. # Use the contents of the machine-id file to set the system ID
# (appmachineid is recommended to avoid exposing the confidential # (appmachineid is recommended.)
# machine-id.)
# file # file
# Use the contents of another file (system_id_file) to set the # Use the contents of another file (system_id_file) to set the
# system ID. # system ID.
@ -1523,15 +1464,13 @@ activation {
# Configuration option activation/reserved_stack. # Configuration option activation/reserved_stack.
# Stack size in KiB to reserve for use while devices are suspended. # Stack size in KiB to reserve for use while devices are suspended.
# Insufficient reserve risks I/O deadlock during device suspension. # Insufficent reserve risks I/O deadlock during device suspension.
# Value 0 disables memory locking.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# reserved_stack = 64 # reserved_stack = 64
# Configuration option activation/reserved_memory. # Configuration option activation/reserved_memory.
# Memory size in KiB to reserve for use while devices are suspended. # Memory size in KiB to reserve for use while devices are suspended.
# Insufficient reserve risks I/O deadlock during device suspension. # Insufficent reserve risks I/O deadlock during device suspension.
# Value 0 disables memory locking.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# reserved_memory = 8192 # reserved_memory = 8192
@ -1666,7 +1605,7 @@ activation {
# This includes LVs that have the following segment types: # This includes LVs that have the following segment types:
# raid1, raid4, raid5*, and raid6*. # raid1, raid4, raid5*, and raid6*.
# If a device in the LV fails, the policy determines the steps # If a device in the LV fails, the policy determines the steps
# performed by dmeventd automatically, and the steps performed by the # performed by dmeventd automatically, and the steps perfomed by the
# manual command lvconvert --repair --use-policies. # manual command lvconvert --repair --use-policies.
# Automatic handling requires dmeventd to be monitoring the LV. # Automatic handling requires dmeventd to be monitoring the LV.
# #
@ -1690,7 +1629,7 @@ activation {
# (copies) and a mirror log. A disk log ensures that a mirror LV does # (copies) and a mirror log. A disk log ensures that a mirror LV does
# not need to be re-synced (all copies made the same) every time a # not need to be re-synced (all copies made the same) every time a
# machine reboots or crashes. If a device in the LV fails, this policy # machine reboots or crashes. If a device in the LV fails, this policy
# determines the steps performed by dmeventd automatically, and the steps # determines the steps perfomed by dmeventd automatically, and the steps
# performed by the manual command lvconvert --repair --use-policies. # performed by the manual command lvconvert --repair --use-policies.
# Automatic handling requires dmeventd to be monitoring the LV. # Automatic handling requires dmeventd to be monitoring the LV.
# #
@ -1852,7 +1791,7 @@ activation {
# Configuration option activation/polling_interval. # Configuration option activation/polling_interval.
# Check pvmove or lvconvert progress at this interval (seconds). # Check pvmove or lvconvert progress at this interval (seconds).
# When pvmove or lvconvert must wait for the kernel to finish # When pvmove or lvconvert must wait for the kernel to finish
# synchronizing or merging data, they check and report progress at # synchronising or merging data, they check and report progress at
# intervals of this number of seconds. If this is set to 0 and there # intervals of this number of seconds. If this is set to 0 and there
# is only one thing to wait for, there are no progress reports, but # is only one thing to wait for, there are no progress reports, but
# the process is awoken immediately once the operation is complete. # the process is awoken immediately once the operation is complete.
@ -1880,7 +1819,7 @@ activation {
# uses are present. Other PVs in the Volume Group may be missing. # uses are present. Other PVs in the Volume Group may be missing.
# degraded # degraded
# Like complete, but additionally RAID LVs of segment type raid1, # Like complete, but additionally RAID LVs of segment type raid1,
# raid4, raid5, raid6 and raid10 will be activated if there is no # raid4, raid5, radid6 and raid10 will be activated if there is no
# data loss, i.e. they have sufficient redundancy to present the # data loss, i.e. they have sufficient redundancy to present the
# entire addressable range of the Logical Volume. # entire addressable range of the Logical Volume.
# partial # partial
@ -1997,14 +1936,15 @@ activation {
# Configuration section report. # Configuration section report.
# LVM report command output formatting. # LVM report command output formatting.
report { # This configuration section has an automatic default value.
# report {
# Configuration option report/output_format. # Configuration option report/output_format.
# Format of LVM command's report output. # Format of LVM command's report output.
# If there is more than one report per command, then the format # If there is more than one report per command, then the format
# is applied for all reports. You can also change output format # is applied for all reports. You can also change output format
# directly on command line using --reportformat option which # directly on command line using --reportformat option which
# has precedence over report/output_format setting. # has precedence over log/output_format setting.
# Accepted values: # Accepted values:
# basic # basic
# Original format with columns and rows. If there is more than # Original format with columns and rows. If there is more than
@ -2012,13 +1952,6 @@ report {
# name for identification. # name for identification.
# json # json
# JSON format. # JSON format.
# json_std
# JSON format that is more compliant with JSON standard.
# Compared to original "json" format:
# - it does not use double quotes around numeric values,
# - it uses 'null' for undefined numeric values,
# - it prints string list as proper JSON array of strings instead of a single string.
# Note that if json or json_std output format is used, then log/command_log_report=1 is default.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# output_format = "basic" # output_format = "basic"
@ -2058,11 +1991,7 @@ report {
# buffered = 1 # buffered = 1
# Configuration option report/headings. # Configuration option report/headings.
# Format of LVM command's report output headings. # Show headings for columns on report.
# Accepted values:
# 0 no headings,
# 1 headings with column abbreviations,
# 2 headings with full column names.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# headings = 1 # headings = 1
@ -2141,7 +2070,7 @@ report {
# %F # %F
# Equivalent to %Y-%m-%d (the ISO 8601 date format). # Equivalent to %Y-%m-%d (the ISO 8601 date format).
# %G # %G
# The ISO 8601 week-based year with century as a decimal number. # The ISO 8601 week-based year with century as adecimal number.
# The 4-digit year corresponding to the ISO week number (see %V). # The 4-digit year corresponding to the ISO week number (see %V).
# This has the same format and value as %Y, except that if the # This has the same format and value as %Y, except that if the
# ISO week number belongs to the previous or next year, that year # ISO week number belongs to the previous or next year, that year
@ -2412,7 +2341,7 @@ report {
# This is displayed when the device for a PV is not known. # This is displayed when the device for a PV is not known.
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# two_word_unknown_device = 0 # two_word_unknown_device = 0
} # }
# Configuration section dmeventd. # Configuration section dmeventd.
# Settings for the LVM event daemon. # Settings for the LVM event daemon.

View File

@ -38,14 +38,6 @@ local {
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# system_id = "" # system_id = ""
# Configuration option local/pr_key.
# The local persistent reservation key in hexidecimal.
# The value must be unique among all hosts using the same VG.
# The max length is 16 hex characters (8 bytes), plus an optional
# 0x prefix. If pr_key is not set, host_id will be used to create a key.
# This configuration option has an automatic default value.
# pr_key = ""
# Configuration option local/extra_system_ids. # Configuration option local/extra_system_ids.
# A list of extra VG system IDs the local host can access. # 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 # VGs with the system IDs listed here (in addition to the host's own
@ -57,12 +49,9 @@ local {
# This configuration option does not have a default value defined. # This configuration option does not have a default value defined.
# Configuration option local/host_id. # Configuration option local/host_id.
# The sanlock host_id used by lvmlockd. This must be unique among all the hosts # The lvmlockd sanlock host_id.
# using shared VGs with sanlock. Accepted values are 1-2000, except when sanlock_align_size # This must be unique among all hosts, and must be between 1 and 2000.
# is configured to 1, 2 or 4, which correspond to max host_id values of 250, 500, or 1000. # Applicable only if LVM is compiled with lockd support
# When using persistent reservations, lvm will generate a PR key from the host_id
# if pr_key is not defined. All hosts using a sanlock shared VG with PR must use
# the same approach for configuring their PR key (pr_key or host_id.)
# This configuration option has an automatic default value. # This configuration option has an automatic default value.
# host_id = 0 # host_id = 0
} }

View File

@ -4,9 +4,11 @@
allocation { allocation {
vdo_use_compression=1 vdo_use_compression=1
vdo_use_deduplication=1 vdo_use_deduplication=1
vdo_use_metadata_hints=1
vdo_minimum_io_size=4096 vdo_minimum_io_size=4096
vdo_block_map_cache_size_mb=128 vdo_block_map_cache_size_mb=128
vdo_block_map_period=16380 vdo_block_map_period=16380
vdo_check_point_frequency=0
vdo_use_sparse_index=0 vdo_use_sparse_index=0
vdo_index_memory_size_mb=256 vdo_index_memory_size_mb=256
vdo_slab_size_mb=2048 vdo_slab_size_mb=2048
@ -17,5 +19,6 @@ allocation {
vdo_hash_zone_threads=1 vdo_hash_zone_threads=1
vdo_logical_threads=1 vdo_logical_threads=1
vdo_physical_threads=1 vdo_physical_threads=1
vdo_write_policy="auto"
vdo_max_discard=1 vdo_max_discard=1
} }

14551
configure vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@
* compile (using outdir 'cov'): * compile (using outdir 'cov'):
* cov-build --dir=cov make CC=gcc * cov-build --dir=cov make CC=gcc
* *
* analyze (aggressively, using 'cov') * analyze (agressively, using 'cov')
* cov-analyze --dir cov --wait-for-license --hfa --concurrency --enable-fnptr --enable-constraint-fpp --security --all --aggressiveness-level=high --field-offset-escape --user-model-file=coverity/coverity_model.xml * cov-analyze --dir cov --wait-for-license --hfa --concurrency --enable-fnptr --enable-constraint-fpp --security --all --aggressiveness-level=high --field-offset-escape --user-model-file=coverity/coverity_model.xml
* *
* generate html output (to 'html' from 'cov'): * generate html output (to 'html' from 'cov'):
@ -30,8 +30,6 @@
struct lv_segment; struct lv_segment;
struct logical_volume; struct logical_volume;
struct cmd_context;
struct profile;
struct lv_segment *first_seg(const struct logical_volume *lv) struct lv_segment *first_seg(const struct logical_volume *lv)
{ {
@ -59,7 +57,7 @@ struct logical_volume *origin_from_cow(const struct logical_volume *lv)
*/ */
/* simple_memccpy() from glibc */ /* simple_memccpy() from glibc */
void *memccpy(void *dest, const void *src, int c, unsigned long n) void *memccpy(void *dest, const void *src, int c, size_t n)
{ {
const char *s = src; const char *s = src;
char *d = dest; char *d = dest;
@ -72,7 +70,7 @@ void *memccpy(void *dest, const void *src, int c, unsigned long n)
} }
/* /*
* 2 lines below needs to be placed in coverity/config/user_nodefs.h * 2 lines bellow needs to be placed in coverity/config/user_nodefs.h
* Not sure about any other way. * Not sure about any other way.
* Without them, coverity shows warning since x86 system header files * Without them, coverity shows warning since x86 system header files
* are using inline assembly to reset fdset * are using inline assembly to reset fdset
@ -92,14 +90,9 @@ void model_FD_ZERO(void *fdset)
/* Resent Coverity reports quite weird errors... */ /* Resent Coverity reports quite weird errors... */
int *__errno_location(void) int *__errno_location(void)
{ {
static int _i = 0;
return &_i;
} }
const unsigned short **__ctype_b_loc (void) const unsigned short **__ctype_b_loc (void)
{ {
static const unsigned short *_a[1] = { 0 };
return _a;
} }

View File

@ -32,12 +32,12 @@ CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS)
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
cmirrord: $(OBJECTS) cmirrord: $(OBJECTS)
$(SHOW) " [CC] $@" @echo " [CC] $@"
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS) $(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS)
install_cluster: $(TARGETS) install_cluster: $(TARGETS)
$(SHOW) " [INSTALL] $<" @echo " [INSTALL] $<"
$(Q) $(INSTALL_PROGRAM) -D $< $(usrsbindir)/$(<F) $(Q) $(INSTALL_PROGRAM) -D $< $(usrsbindir)/$(<F)
install: install_cluster install: install_cluster

View File

@ -43,14 +43,14 @@ static void usage (FILE *dest)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int foreground_mode = 0; int foreground_mode = 0;
static const struct option _long_options[] = { struct option longopts[] = {
{ "foreground", no_argument, NULL, 'f' }, { "foreground", no_argument, NULL, 'f' },
{ "help" , no_argument, NULL, 'h' }, { "help" , no_argument, NULL, 'h' },
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
int opt; int opt;
while ((opt = getopt_long (argc, argv, "fh", _long_options, NULL)) != -1) { while ((opt = getopt_long (argc, argv, "fh", longopts, NULL)) != -1) {
switch (opt) { switch (opt) {
case 'f': case 'f':
foreground_mode = 1; foreground_mode = 1;

View File

@ -197,7 +197,7 @@ int cluster_send(struct clog_request *rq)
iov.iov_base = rq; iov.iov_base = rq;
iov.iov_len = sizeof(struct clog_request) + rq->u_rq.data_size; iov.iov_len = sizeof(struct clog_request) + rq->u_rq.data_size;
rq->u.version[0] = htole64(CLOG_TFR_VERSION); rq->u.version[0] = xlate64(CLOG_TFR_VERSION);
rq->u.version[1] = CLOG_TFR_VERSION; rq->u.version[1] = CLOG_TFR_VERSION;
r = clog_request_to_network(rq); r = clog_request_to_network(rq);
@ -279,7 +279,7 @@ static int handle_cluster_request(struct clog_cpg *entry __attribute__((unused))
* With resumes, we only handle our own. * With resumes, we only handle our own.
* Resume is a special case that requires * Resume is a special case that requires
* local action (to set up CPG), followed by * local action (to set up CPG), followed by
* a cluster action to coordinate reading * a cluster action to co-ordinate reading
* the disk and checkpointing * the disk and checkpointing
*/ */
if (tmp->u_rq.request_type == DM_ULOG_RESUME) { if (tmp->u_rq.request_type == DM_ULOG_RESUME) {
@ -1091,7 +1091,6 @@ static void cpg_message_callback(cpg_handle_t handle, const struct cpg_name *gna
(rq->u_rq.request_type != DM_ULOG_RESUME) && (rq->u_rq.request_type != DM_ULOG_RESUME) &&
(rq->u_rq.request_type != DM_ULOG_CLEAR_REGION) && (rq->u_rq.request_type != DM_ULOG_CLEAR_REGION) &&
(rq->u_rq.request_type != DM_ULOG_CHECKPOINT_READY)) { (rq->u_rq.request_type != DM_ULOG_CHECKPOINT_READY)) {
/* coverity[suspicious_sizeof] allocation is using varargs data @end */
tmp_rq = malloc(DM_ULOG_REQUEST_SIZE); tmp_rq = malloc(DM_ULOG_REQUEST_SIZE);
if (!tmp_rq) { if (!tmp_rq) {
/* /*
@ -1341,7 +1340,6 @@ static void cpg_join_callback(struct clog_cpg *match,
goto out; goto out;
} }
/* coverity[suspicious_sizeof] allocation is using varargs data @end */
rq = malloc(DM_ULOG_REQUEST_SIZE); rq = malloc(DM_ULOG_REQUEST_SIZE);
if (!rq) { if (!rq) {
LOG_ERROR("cpg_config_callback: " LOG_ERROR("cpg_config_callback: "
@ -1634,7 +1632,7 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
size = ((strlen(uuid) + 1) > CPG_MAX_NAME_LENGTH) ? size = ((strlen(uuid) + 1) > CPG_MAX_NAME_LENGTH) ?
CPG_MAX_NAME_LENGTH : (strlen(uuid) + 1); CPG_MAX_NAME_LENGTH : (strlen(uuid) + 1);
dm_strncpy(new->name.value, uuid, size); (void) dm_strncpy(new->name.value, uuid, size);
new->name.length = (uint32_t)size; new->name.length = (uint32_t)size;
new->luid = luid; new->luid = luid;

View File

@ -52,19 +52,19 @@ static void v5_data_endian_switch(struct clog_request *rq, int to_network __attr
case DM_ULOG_GET_REGION_SIZE: case DM_ULOG_GET_REGION_SIZE:
case DM_ULOG_GET_SYNC_COUNT: case DM_ULOG_GET_SYNC_COUNT:
pu64 = (uint64_t *)rq->u_rq.data; pu64 = (uint64_t *)rq->u_rq.data;
*pu64 = htole64(*pu64); *pu64 = xlate64(*pu64);
break; break;
case DM_ULOG_IS_CLEAN: case DM_ULOG_IS_CLEAN:
case DM_ULOG_IN_SYNC: case DM_ULOG_IN_SYNC:
pi64 = (int64_t *)rq->u_rq.data; pi64 = (int64_t *)rq->u_rq.data;
*pi64 = htole64(*pi64); *pi64 = xlate64(*pi64);
break; break;
case DM_ULOG_GET_RESYNC_WORK: case DM_ULOG_GET_RESYNC_WORK:
case DM_ULOG_IS_REMOTE_RECOVERING: case DM_ULOG_IS_REMOTE_RECOVERING:
pi64 = (int64_t *)rq->u_rq.data; pi64 = (int64_t *)rq->u_rq.data;
pu64 = ((uint64_t *)rq->u_rq.data) + 1; pu64 = ((uint64_t *)rq->u_rq.data) + 1;
*pi64 = htole64(*pi64); *pi64 = xlate64(*pi64);
*pu64 = htole64(*pu64); *pu64 = xlate64(*pu64);
break; break;
default: default:
LOG_ERROR("Unknown request type, %u", rq_type); LOG_ERROR("Unknown request type, %u", rq_type);
@ -94,7 +94,7 @@ static void v5_data_endian_switch(struct clog_request *rq, int to_network __attr
case DM_ULOG_IN_SYNC: case DM_ULOG_IN_SYNC:
case DM_ULOG_IS_REMOTE_RECOVERING: case DM_ULOG_IS_REMOTE_RECOVERING:
pu64 = (uint64_t *)rq->u_rq.data; pu64 = (uint64_t *)rq->u_rq.data;
*pu64 = htole64(*pu64); *pu64 = xlate64(*pu64);
break; break;
case DM_ULOG_MARK_REGION: case DM_ULOG_MARK_REGION:
case DM_ULOG_CLEAR_REGION: case DM_ULOG_CLEAR_REGION:
@ -102,13 +102,13 @@ static void v5_data_endian_switch(struct clog_request *rq, int to_network __attr
pu64 = (uint64_t *)rq->u_rq.data; pu64 = (uint64_t *)rq->u_rq.data;
for (i = 0; i < end; i++) for (i = 0; i < end; i++)
pu64[i] = htole64(pu64[i]); pu64[i] = xlate64(pu64[i]);
break; break;
case DM_ULOG_SET_REGION_SYNC: case DM_ULOG_SET_REGION_SYNC:
pu64 = (uint64_t *)rq->u_rq.data; pu64 = (uint64_t *)rq->u_rq.data;
pi64 = ((int64_t *)rq->u_rq.data) + 1; pi64 = ((int64_t *)rq->u_rq.data) + 1;
*pu64 = htole64(*pu64); *pu64 = xlate64(*pu64);
*pi64 = htole64(*pi64); *pi64 = xlate64(*pi64);
break; break;
default: default:
LOG_ERROR("Unknown request type, %u", rq_type); LOG_ERROR("Unknown request type, %u", rq_type);
@ -124,15 +124,15 @@ static int v5_endian_to_network(struct clog_request *rq)
size = sizeof(*rq) + u_rq->data_size; size = sizeof(*rq) + u_rq->data_size;
u_rq->error = htole32(u_rq->error); u_rq->error = xlate32(u_rq->error);
u_rq->seq = htole32(u_rq->seq); u_rq->seq = xlate32(u_rq->seq);
rq->originator = htole32(rq->originator); rq->originator = xlate32(rq->originator);
v5_data_endian_switch(rq, 1); v5_data_endian_switch(rq, 1);
u_rq->request_type = htole32(u_rq->request_type); u_rq->request_type = xlate32(u_rq->request_type);
u_rq->data_size = htole32(u_rq->data_size); u_rq->data_size = xlate32(u_rq->data_size);
return size; return size;
} }
@ -142,7 +142,7 @@ int clog_request_to_network(struct clog_request *rq)
int r; int r;
/* FIXME: Remove this safety check */ /* FIXME: Remove this safety check */
if (rq->u.version[0] != htole64(rq->u.version[1])) { if (rq->u.version[0] != xlate64(rq->u.version[1])) {
LOG_ERROR("Programmer error: version[0] must be LE"); LOG_ERROR("Programmer error: version[0] must be LE");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -165,12 +165,12 @@ static int v5_endian_from_network(struct clog_request *rq)
int size; int size;
struct dm_ulog_request *u_rq = &rq->u_rq; struct dm_ulog_request *u_rq = &rq->u_rq;
u_rq->error = htole32(u_rq->error); u_rq->error = xlate32(u_rq->error);
u_rq->seq = htole32(u_rq->seq); u_rq->seq = xlate32(u_rq->seq);
u_rq->request_type = htole32(u_rq->request_type); u_rq->request_type = xlate32(u_rq->request_type);
u_rq->data_size = htole32(u_rq->data_size); u_rq->data_size = xlate32(u_rq->data_size);
rq->originator = htole32(rq->originator); rq->originator = xlate32(rq->originator);
size = sizeof(*rq) + u_rq->data_size; size = sizeof(*rq) + u_rq->data_size;
@ -182,7 +182,7 @@ static int v5_endian_from_network(struct clog_request *rq)
int clog_request_from_network(void *data, size_t data_len) int clog_request_from_network(void *data, size_t data_len)
{ {
uint64_t *vp = data; uint64_t *vp = data;
uint64_t version = htole64(vp[0]); uint64_t version = xlate64(vp[0]);
struct clog_request *rq = data; struct clog_request *rq = data;
switch (version) { switch (version) {

View File

@ -8,8 +8,6 @@
#ifndef _LVM_CLOG_COMPAT_H #ifndef _LVM_CLOG_COMPAT_H
#define _LVM_CLOG_COMPAT_H #define _LVM_CLOG_COMPAT_H
#include <stddef.h>
/* /*
* The intermachine communication structure version are: * The intermachine communication structure version are:
* 0: Unused * 0: Unused
@ -21,8 +19,6 @@
*/ */
#define CLOG_TFR_VERSION 5 #define CLOG_TFR_VERSION 5
struct clog_request;
int clog_request_to_network(struct clog_request *rq); int clog_request_to_network(struct clog_request *rq);
int clog_request_from_network(void *data, size_t data_len); int clog_request_from_network(void *data, size_t data_len);

View File

@ -67,7 +67,7 @@ struct log_c {
uint32_t recoverer; uint32_t recoverer;
uint64_t recovering_region; /* -1 means not recovering */ uint64_t recovering_region; /* -1 means not recovering */
uint64_t skip_bit_warning; /* used to warn if region skipped */ uint64_t skip_bit_warning; /* used to warn if region skipped */
unsigned sync_search; int sync_search;
int resume_override; int resume_override;
@ -220,7 +220,7 @@ static int rw_log(struct log_c *lc, int do_write)
if (r < 0) if (r < 0)
LOG_ERROR("[%s] rw_log: read failure: %s", LOG_ERROR("[%s] rw_log: read failure: %s",
SHORT_UUID(lc->uuid), strerror(errno)); SHORT_UUID(lc->uuid), strerror(errno));
if ((unsigned) r != lc->disk_size) if (r != lc->disk_size)
return -EIO; /* Failed disk read */ return -EIO; /* Failed disk read */
return 0; return 0;
} }
@ -254,7 +254,7 @@ static int read_log(struct log_c *lc)
bitset_size = lc->region_count / 8; bitset_size = lc->region_count / 8;
bitset_size += (lc->region_count % 8) ? 1 : 0; bitset_size += (lc->region_count % 8) ? 1 : 0;
/* 'lc->clean_bits + 1' because dm_bitset_t leads with a uint32_t */ /* 'lc->clean_bits + 1' becasue dm_bitset_t leads with a uint32_t */
memcpy(lc->clean_bits + 1, (char *)lc->disk_buffer + 1024, bitset_size); memcpy(lc->clean_bits + 1, (char *)lc->disk_buffer + 1024, bitset_size);
return 0; return 0;
@ -281,7 +281,7 @@ static int write_log(struct log_c *lc)
bitset_size = lc->region_count / 8; bitset_size = lc->region_count / 8;
bitset_size += (lc->region_count % 8) ? 1 : 0; bitset_size += (lc->region_count % 8) ? 1 : 0;
/* 'lc->clean_bits + 1' because dm_bitset_t leads with a uint32_t */ /* 'lc->clean_bits + 1' becasue dm_bitset_t leads with a uint32_t */
memcpy((char *)lc->disk_buffer + 1024, lc->clean_bits + 1, bitset_size); memcpy((char *)lc->disk_buffer + 1024, lc->clean_bits + 1, bitset_size);
if (rw_log(lc, 1)) { if (rw_log(lc, 1)) {
@ -292,13 +292,13 @@ static int write_log(struct log_c *lc)
} }
/* FIXME Rewrite this function taking advantage of the udev changes (where in use) to improve its efficiency! */ /* FIXME Rewrite this function taking advantage of the udev changes (where in use) to improve its efficiency! */
static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int *unlink_path __attribute__((unused))) static int find_disk_path(char *major_minor_str, char *path_rtn, int *unlink_path __attribute__((unused)))
{ {
int r; int r;
DIR *dp; DIR *dp;
struct dirent *dep; struct dirent *dep;
struct stat statbuf; struct stat statbuf;
unsigned major, minor; int major, minor;
if (!strstr(major_minor_str, ":")) { if (!strstr(major_minor_str, ":")) {
r = stat(major_minor_str, &statbuf); r = stat(major_minor_str, &statbuf);
@ -306,7 +306,7 @@ static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int
return -errno; return -errno;
if (!S_ISBLK(statbuf.st_mode)) if (!S_ISBLK(statbuf.st_mode))
return -EINVAL; return -EINVAL;
dm_strncpy(path_rtn, major_minor_str, sz); sprintf(path_rtn, "%s", major_minor_str);
return 0; return 0;
} }
@ -329,7 +329,7 @@ static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int
* wanted. * wanted.
*/ */
snprintf(path_rtn, sz, "/dev/mapper/%s", dep->d_name); sprintf(path_rtn, "/dev/mapper/%s", dep->d_name);
if (stat(path_rtn, &statbuf) < 0) { if (stat(path_rtn, &statbuf) < 0) {
LOG_DBG("Unable to stat %s", path_rtn); LOG_DBG("Unable to stat %s", path_rtn);
continue; continue;
@ -380,8 +380,8 @@ static int _clog_ctr(char *uuid, uint64_t luid,
int disk_log; int disk_log;
char disk_path[PATH_MAX] = { 0 }; char disk_path[PATH_MAX] = { 0 };
int unlink_path = 0; int unlink_path = 0;
long ps; long page_size;
size_t pages, page_size; int pages;
/* If core log request, then argv[0] will be region_size */ /* If core log request, then argv[0] will be region_size */
if (!strtoll(argv[0], &p, 0) || *p) { if (!strtoll(argv[0], &p, 0) || *p) {
@ -394,7 +394,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
goto fail; goto fail;
} }
r = find_disk_path(argv[0], disk_path, sizeof(disk_path), &unlink_path); r = find_disk_path(argv[0], disk_path, &unlink_path);
if (r) { if (r) {
LOG_ERROR("Unable to find path to device %s", argv[0]); LOG_ERROR("Unable to find path to device %s", argv[0]);
goto fail; goto fail;
@ -452,7 +452,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
lc->skip_bit_warning = region_count; lc->skip_bit_warning = region_count;
lc->disk_fd = -1; lc->disk_fd = -1;
lc->log_dev_failed = 0; lc->log_dev_failed = 0;
if (!_dm_strncpy(lc->uuid, uuid, DM_UUID_LEN)) { if (!dm_strncpy(lc->uuid, uuid, DM_UUID_LEN)) {
LOG_ERROR("Cannot use too long UUID %s.", uuid); LOG_ERROR("Cannot use too long UUID %s.", uuid);
r = -EINVAL; r = -EINVAL;
goto fail; goto fail;
@ -488,15 +488,14 @@ static int _clog_ctr(char *uuid, uint64_t luid,
lc->sync_count = (log_sync == NOSYNC) ? region_count : 0; lc->sync_count = (log_sync == NOSYNC) ? region_count : 0;
if (disk_log) { if (disk_log) {
if (((ps = sysconf(_SC_PAGESIZE)) <= 0) || if ((page_size = sysconf(_SC_PAGESIZE)) < 0) {
(ps > (1 << 24))) {
LOG_ERROR("Unable to read pagesize: %s", LOG_ERROR("Unable to read pagesize: %s",
strerror(errno)); strerror(errno));
r = errno; r = errno;
goto fail; goto fail;
} }
page_size = (size_t)ps; pages = *(lc->clean_bits) / page_size;
pages = (*(lc->clean_bits) + page_size - 1) / page_size; pages += *(lc->clean_bits) % page_size ? 1 : 0;
pages += 1; /* for header */ pages += 1; /* for header */
r = open(disk_path, O_RDWR | O_DIRECT); r = open(disk_path, O_RDWR | O_DIRECT);
@ -928,7 +927,7 @@ int local_resume(struct dm_ulog_request *rq)
* *
* Since this value doesn't change, the kernel * Since this value doesn't change, the kernel
* should not need to talk to server to get this * should not need to talk to server to get this
* The function is here for completeness * The function is here for completness
* *
* Returns: 0 on success, -EXXX on failure * Returns: 0 on success, -EXXX on failure
*/ */
@ -1019,7 +1018,7 @@ static int clog_in_sync(struct dm_ulog_request *rq)
* happen for reads is that additional read attempts may be * happen for reads is that additional read attempts may be
* taken. * taken.
* *
* Further investigation may be required to determine if there are * Futher investigation may be required to determine if there are
* similar possible outcomes when the mirror is in the process of * similar possible outcomes when the mirror is in the process of
* recovering. In that case, lc->in_sync would not have been set * recovering. In that case, lc->in_sync would not have been set
* yet. * yet.

View File

@ -13,7 +13,6 @@
#define _LVM_CLOG_FUNCTIONS_H #define _LVM_CLOG_FUNCTIONS_H
#include "libdm/libdevmapper.h" #include "libdm/libdevmapper.h"
#include "libdm/dm-tools/util.h"
#include "libdm/misc/dm-log-userspace.h" #include "libdm/misc/dm-log-userspace.h"
#include "cluster.h" #include "cluster.h"

View File

@ -266,7 +266,7 @@ static int do_local_work(void *data __attribute__((unused)))
RQ_TYPE(u_rq->request_type)); RQ_TYPE(u_rq->request_type));
break; break;
} }
/* ELSE */ /* fall through */ /* ELSE, fall through */
case DM_ULOG_IS_CLEAN: case DM_ULOG_IS_CLEAN:
case DM_ULOG_FLUSH: case DM_ULOG_FLUSH:
case DM_ULOG_MARK_REGION: case DM_ULOG_MARK_REGION:
@ -326,11 +326,10 @@ static int do_local_work(void *data __attribute__((unused)))
* *
* Returns: 0 on success, -EXXX on failure * Returns: 0 on success, -EXXX on failure
*/ */
int kernel_send(void *data) int kernel_send(struct dm_ulog_request *u_rq)
{ {
int r; int r;
uint16_t size; uint16_t size;
struct dm_ulog_request *u_rq = data;
if (!u_rq) if (!u_rq)
return -EINVAL; return -EINVAL;
@ -354,7 +353,7 @@ int kernel_send(void *data)
size = sizeof(struct dm_ulog_request); size = sizeof(struct dm_ulog_request);
} }
r = kernel_send_helper(data, size); r = kernel_send_helper(u_rq, size);
if (r) if (r)
LOG_ERROR("Failed to send msg to kernel."); LOG_ERROR("Failed to send msg to kernel.");

View File

@ -12,11 +12,9 @@
#ifndef _LVM_CLOG_LOCAL_H #ifndef _LVM_CLOG_LOCAL_H
#define _LVM_CLOG_LOCAL_H #define _LVM_CLOG_LOCAL_H
struct dm_ulog_request;
int init_local(void); int init_local(void);
void cleanup_local(void); void cleanup_local(void);
int kernel_send(void *data); int kernel_send(struct dm_ulog_request *rq);
#endif /* _LVM_CLOG_LOCAL_H */ #endif /* _LVM_CLOG_LOCAL_H */

View File

@ -11,7 +11,7 @@
*/ */
#include "logging.h" #include "logging.h"
const char * const __rq_types_off_by_one[] = { const char *__rq_types_off_by_one[] = {
"DM_ULOG_CTR", "DM_ULOG_CTR",
"DM_ULOG_DTR", "DM_ULOG_DTR",
"DM_ULOG_PRESUSPEND", "DM_ULOG_PRESUSPEND",

View File

@ -20,7 +20,7 @@
/* SHORT_UUID - print last 8 chars of a string */ /* SHORT_UUID - print last 8 chars of a string */
#define SHORT_UUID(x) (strlen(x) > 8) ? ((x) + (strlen(x) - 8)) : (x) #define SHORT_UUID(x) (strlen(x) > 8) ? ((x) + (strlen(x) - 8)) : (x)
extern const char * const __rq_types_off_by_one[]; extern const char *__rq_types_off_by_one[];
#define RQ_TYPE(x) __rq_types_off_by_one[(x) - 1] #define RQ_TYPE(x) __rq_types_off_by_one[(x) - 1]
extern int log_tabbing; extern int log_tabbing;

View File

@ -70,13 +70,13 @@ plugins.device-mapper: $(LIB_SHARED)
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS) CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
dmeventd: $(LIB_SHARED) dmeventd.o dmeventd: $(LIB_SHARED) dmeventd.o
$(SHOW) " [CC] $@" @echo " [CC] $@"
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) -o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
dmeventd.static: $(LIB_STATIC) dmeventd.o dmeventd.static: $(LIB_STATIC) dmeventd.o
$(SHOW) " [CC] $@" @echo " [CC] $@"
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(STATIC_LDFLAGS) -static dmeventd.o \ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static dmeventd.o \
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS) -o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
ifeq ("@PKGCONFIG@", "yes") ifeq ("@PKGCONFIG@", "yes")
@ -84,27 +84,27 @@ ifeq ("@PKGCONFIG@", "yes")
endif endif
install_include: $(srcdir)/libdevmapper-event.h install_include: $(srcdir)/libdevmapper-event.h
$(SHOW) " [INSTALL] $(<F)" @echo " [INSTALL] $(<F)"
$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F) $(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F)
install_pkgconfig: libdevmapper-event.pc install_pkgconfig: libdevmapper-event.pc
$(SHOW) " [INSTALL] $<" @echo " [INSTALL] $<"
$(Q) $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc $(Q) $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
install_lib_dynamic: install_lib_shared install_lib_dynamic: install_lib_shared
install_lib_static: $(LIB_STATIC) install_lib_static: $(LIB_STATIC)
$(SHOW) " [INSTALL] $<" @echo " [INSTALL] $<"
$(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F) $(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
install_lib: $(INSTALL_LIB_TARGETS) install_lib: $(INSTALL_LIB_TARGETS)
install_dmeventd_dynamic: dmeventd install_dmeventd_dynamic: dmeventd
$(SHOW) " [INSTALL] $<" @echo " [INSTALL] $<"
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F) $(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
install_dmeventd_static: dmeventd.static install_dmeventd_static: dmeventd.static
$(SHOW) " [INSTALL] $<" @echo " [INSTALL] $<"
$(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F) $(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
install_dmeventd: $(INSTALL_DMEVENTD_TARGETS) install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,6 @@
#ifndef __DMEVENTD_DOT_H__ #ifndef __DMEVENTD_DOT_H__
#define __DMEVENTD_DOT_H__ #define __DMEVENTD_DOT_H__
#include <stdint.h>
/* FIXME This stuff must be configurable. */ /* FIXME This stuff must be configurable. */
#define DM_EVENT_FIFO_CLIENT DEFAULT_DM_RUN_DIR "/dmeventd-client" #define DM_EVENT_FIFO_CLIENT DEFAULT_DM_RUN_DIR "/dmeventd-client"
@ -70,7 +68,7 @@ struct dm_event_fifos {
int daemon_talk(struct dm_event_fifos *fifos, int daemon_talk(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg, int cmd, struct dm_event_daemon_message *msg, int cmd,
const char *dso_name, const char *dev_name, const char *dso_name, const char *dev_name,
unsigned evmask, uint32_t timeout); enum dm_event_mask evmask, uint32_t timeout);
int init_fifos(struct dm_event_fifos *fifos); int init_fifos(struct dm_event_fifos *fifos);
void fini_fifos(struct dm_event_fifos *fifos); void fini_fifos(struct dm_event_fifos *fifos);
int dm_event_get_version(struct dm_event_fifos *fifos, int *version); int dm_event_get_version(struct dm_event_fifos *fifos, int *version);

View File

@ -352,7 +352,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
int daemon_talk(struct dm_event_fifos *fifos, int daemon_talk(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg, int cmd, struct dm_event_daemon_message *msg, int cmd,
const char *dso_name, const char *dev_name, const char *dso_name, const char *dev_name,
unsigned evmask, uint32_t timeout) enum dm_event_mask evmask, uint32_t timeout)
{ {
int msg_size; int msg_size;
memset(msg, 0, sizeof(*msg)); memset(msg, 0, sizeof(*msg));
@ -400,16 +400,25 @@ int daemon_talk(struct dm_event_fifos *fifos,
return (int32_t) msg->cmd; return (int32_t) msg->cmd;
} }
/* /*
* Check for usable client fifo file * start_daemon
* *
* Returns: 2 client path does not exists, dmeventd should be restarted * This function forks off a process (dmeventd) that will handle
* 1 on success, 0 otherwise * the events. I am currently test opening one of the fifos to
* ensure that the daemon is running and listening... I thought
* this would be less expensive than fork/exec'ing every time.
* Perhaps there is an even quicker/better way (no, checking the
* lock file is _not_ a better way).
*
* Returns: 1 on success, 0 otherwise
*/ */
static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *fifos) static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
{ {
int pid, ret = 0;
int status;
struct stat statbuf; struct stat statbuf;
char default_dmeventd_path[] = DMEVENTD_PATH;
char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
/* /*
* FIXME Explicitly verify the code's requirement that client_path is secure: * FIXME Explicitly verify the code's requirement that client_path is secure:
@ -420,7 +429,7 @@ static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *f
if ((lstat(fifos->client_path, &statbuf) < 0)) { if ((lstat(fifos->client_path, &statbuf) < 0)) {
if (errno == ENOENT) if (errno == ENOENT)
/* Jump ahead if fifo does not already exist. */ /* Jump ahead if fifo does not already exist. */
return 2; goto start_server;
else { else {
log_sys_error("stat", fifos->client_path); log_sys_error("stat", fifos->client_path);
return 0; return 0;
@ -446,14 +455,12 @@ static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *f
log_error("%s is no longer a secure root-owned fifo with mode 0600.", fifos->client_path); log_error("%s is no longer a secure root-owned fifo with mode 0600.", fifos->client_path);
if (close(fifos->client)) if (close(fifos->client))
log_sys_debug("close", fifos->client_path); log_sys_debug("close", fifos->client_path);
fifos->client = -1;
return 0; return 0;
} }
/* server is running and listening */ /* server is running and listening */
if (close(fifos->client)) if (close(fifos->client))
log_sys_debug("close", fifos->client_path); log_sys_debug("close", fifos->client_path);
fifos->client = -1;
return 1; return 1;
} }
if (errno != ENXIO && errno != ENOENT) { if (errno != ENXIO && errno != ENOENT) {
@ -462,36 +469,9 @@ static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *f
return 0; return 0;
} }
return 2; start_server:
}
/*
* start_daemon
*
* This function forks off a process (dmeventd) that will handle
* the events. I am currently test opening one of the fifos to
* ensure that the daemon is running and listening... I thought
* this would be less expensive than fork/exec'ing every time.
* Perhaps there is an even quicker/better way (no, checking the
* lock file is _not_ a better way).
*
* Returns: 1 on success, 0 otherwise
*/
static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
{
struct stat statbuf;
char default_dmeventd_path[] = DMEVENTD_PATH;
char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
int pid, ret = 0;
int status;
switch (_check_for_usable_fifos(dmeventd_path, fifos)) {
case 0: return_0;
case 1: return 1; /* Already running dmeventd */
}
/* server is not running */ /* server is not running */
if ((args[0][0] == '/') && stat(args[0], &statbuf)) { if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
log_sys_error("stat", args[0]); log_sys_error("stat", args[0]);
return 0; return 0;
@ -512,17 +492,8 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
strerror(errno)); strerror(errno));
else if (WEXITSTATUS(status)) else if (WEXITSTATUS(status))
log_error("Unable to start dmeventd."); log_error("Unable to start dmeventd.");
else { else
/* Loop here till forked dmeventd is serving fifos */ ret = 1;
for (ret = 100; ret > 0; --ret)
switch (_check_for_usable_fifos(dmeventd_path, fifos)) {
case 0: return_0;
case 1: return 1;
case 2: usleep(1000); break;
}
/* ret == 0 */
log_error("Dmeventd is not serving fifos.");
}
} }
return ret; return ret;
@ -542,7 +513,7 @@ int init_fifos(struct dm_event_fifos *fifos)
/* Lock out anyone else trying to do communication with the daemon. */ /* Lock out anyone else trying to do communication with the daemon. */
if (flock(fifos->server, LOCK_EX) < 0) { if (flock(fifos->server, LOCK_EX) < 0) {
log_sys_error("flock", fifos->server_path); log_sys_error("flock", fifos->server_path);
goto bad_no_unlock; goto bad;
} }
/* if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/ /* if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/
@ -553,9 +524,6 @@ int init_fifos(struct dm_event_fifos *fifos)
return 1; return 1;
bad: bad:
if (flock(fifos->server, LOCK_UN))
log_sys_debug("flock unlock", fifos->server_path);
bad_no_unlock:
if (close(fifos->server)) if (close(fifos->server))
log_sys_debug("close", fifos->server_path); log_sys_debug("close", fifos->server_path);
fifos->server = -1; fifos->server = -1;
@ -584,8 +552,6 @@ void fini_fifos(struct dm_event_fifos *fifos)
if (close(fifos->server)) if (close(fifos->server))
log_sys_debug("close", fifos->server_path); log_sys_debug("close", fifos->server_path);
} }
fifos->client = fifos->server = -1;
} }
/* Get uuid of a device */ /* Get uuid of a device */
@ -754,7 +720,7 @@ static char *_fetch_string(char **src, const int delimiter)
/* Parse a device message from the daemon. */ /* Parse a device message from the daemon. */
static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name, static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
char **uuid, unsigned *evmask) char **uuid, enum dm_event_mask *evmask)
{ {
char *id; char *id;
char *p = msg->data; char *p = msg->data;
@ -779,7 +745,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
int ret = 0; int ret = 0;
const char *uuid = NULL; const char *uuid = NULL;
char *reply_dso = NULL, *reply_uuid = NULL; char *reply_dso = NULL, *reply_uuid = NULL;
unsigned reply_mask = 0; enum dm_event_mask reply_mask = 0;
struct dm_task *dmt = NULL; struct dm_task *dmt = NULL;
struct dm_event_daemon_message msg = { 0 }; struct dm_event_daemon_message msg = { 0 };
struct dm_info info; struct dm_info info;
@ -829,7 +795,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
} }
dm_event_handler_set_dso(dmevh, reply_dso); dm_event_handler_set_dso(dmevh, reply_dso);
dm_event_handler_set_event_mask(dmevh, (enum dm_event_mask) reply_mask); dm_event_handler_set_event_mask(dmevh, reply_mask);
free(reply_dso); free(reply_dso);
reply_dso = NULL; reply_dso = NULL;
@ -878,7 +844,6 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
int dm_event_get_version(struct dm_event_fifos *fifos, int *version) { int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
char *p; char *p;
struct dm_event_daemon_message msg = { 0 }; struct dm_event_daemon_message msg = { 0 };
int ret = 0;
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0)) if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0))
return 0; return 0;
@ -886,17 +851,13 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
*version = 0; *version = 0;
if (!p || !(p = strchr(p, ' '))) /* Message ID */ if (!p || !(p = strchr(p, ' '))) /* Message ID */
goto out; return 0;
if (!(p = strchr(p + 1, ' '))) /* HELLO */ if (!(p = strchr(p + 1, ' '))) /* HELLO */
goto out; return 0;
if ((p = strchr(p + 1, ' '))) /* HELLO, once more */ if ((p = strchr(p + 1, ' '))) /* HELLO, once more */
*version = atoi(p); *version = atoi(p);
ret = 1; return 1;
out:
free(msg.data);
return ret;
} }
void dm_event_log_set(int debug_log_level, int use_syslog) void dm_event_log_set(int debug_log_level, int use_syslog)
@ -911,11 +872,11 @@ void dm_event_log(const char *subsys, int level, const char *file,
{ {
static int _abort_on_internal_errors = -1; static int _abort_on_internal_errors = -1;
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
static long long _start = 0; static time_t start = 0;
const char *indent = ""; const char *indent = "";
FILE *stream = log_stderr(level) ? stderr : stdout; FILE *stream = log_stderr(level) ? stderr : stdout;
int prio; int prio;
long long now, now_nsec; time_t now;
int log_with_debug = 0; int log_with_debug = 0;
if (subsys[0] == '#') { if (subsys[0] == '#') {
@ -962,33 +923,22 @@ void dm_event_log(const char *subsys, int level, const char *file,
if (_use_syslog) { if (_use_syslog) {
vsyslog(prio, format, ap); vsyslog(prio, format, ap);
} else { } else {
if (_debug_level) { now = time(NULL);
#define _NSEC_PER_SEC (1000000000LL) if (!start)
#ifdef HAVE_REALTIME start = now;
struct timespec mono_time = { 0 }; now -= start;
if (clock_gettime(CLOCK_MONOTONIC, &mono_time) == 0) if (_debug_level)
now = mono_time.tv_sec * _NSEC_PER_SEC + mono_time.tv_nsec; fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
else (int)now / 60, (int)now % 60,
#endif
now = time(NULL) * _NSEC_PER_SEC;
if (!_start)
_start = now;
now -= _start;
now_nsec = now %_NSEC_PER_SEC;
now /= _NSEC_PER_SEC;
fprintf(stream, "[%2lld:%02lld.%06lld] %8x:%-6s%s",
now / 60, now % 60, now_nsec / 1000,
// TODO: Maybe use shorter ID // TODO: Maybe use shorter ID
// ((int)(pthread_self()) >> 6) & 0xffff, // ((int)(pthread_self()) >> 6) & 0xffff,
(int)pthread_self(), subsys, (int)pthread_self(), subsys,
(_debug_level > 3) ? "" : indent); (_debug_level > 3) ? "" : indent);
}
if (_debug_level > 3) if (_debug_level > 3)
fprintf(stream, "%28s:%4d %s", file, line, indent); fprintf(stream, "%28s:%4d %s", file, line, indent);
vfprintf(stream, _(format), ap); vfprintf(stream, _(format), ap);
fputc('\n', stream); fputc('\n', stream);
(void) fflush(stream); fflush(stream);
} }
pthread_mutex_unlock(&_log_mutex); pthread_mutex_unlock(&_log_mutex);
@ -1007,7 +957,7 @@ void dm_event_log(const char *subsys, int level, const char *file,
static char *_skip_string(char *src, const int delimiter) static char *_skip_string(char *src, const int delimiter)
{ {
src = strchr(src, delimiter); src = srtchr(src, delimiter);
if (src && *(src + 1)) if (src && *(src + 1))
return src + 1; return src + 1;
return NULL; return NULL;

View File

@ -29,22 +29,19 @@
*/ */
enum dm_event_mask { enum dm_event_mask {
DM_EVENT_SETTINGS_MASK = 0x0000FF,
DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */ DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */
DM_EVENT_MULTI = 0x000002, /* Report all of them. */ DM_EVENT_MULTI = 0x000002, /* Report all of them. */
DM_EVENT_SETTINGS_MASK = 0x0000FF,
DM_EVENT_ERROR_MASK = 0x00FF00,
DM_EVENT_SECTOR_ERROR = 0x000100, /* Failure on a particular sector. */ DM_EVENT_SECTOR_ERROR = 0x000100, /* Failure on a particular sector. */
DM_EVENT_DEVICE_ERROR = 0x000200, /* Device failure. */ DM_EVENT_DEVICE_ERROR = 0x000200, /* Device failure. */
DM_EVENT_PATH_ERROR = 0x000400, /* Failure on an io path. */ DM_EVENT_PATH_ERROR = 0x000400, /* Failure on an io path. */
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */ DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */
DM_EVENT_ERROR_MASK = 0x00FF00,
DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
DM_EVENT_TIMEOUT = 0x020000, /* Timeout has occurred */
DM_EVENT_ERROR_AND_TIMEOUT_MASK = 0x02FF00,
DM_EVENT_STATUS_MASK = 0xFF0000, DM_EVENT_STATUS_MASK = 0xFF0000,
DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
DM_EVENT_TIMEOUT = 0x020000, /* Timeout has occured */
DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */ DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */
}; };
@ -73,10 +70,10 @@ int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path);
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path); int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path);
/* /*
* Identify the device to monitor by exactly one of dev_name, uuid or * Identify the device to monitor by exactly one of device_name, uuid or
* device number. String arguments are duplicated, see above. * device number. String arguments are duplicated, see above.
*/ */
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name); int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *device_name);
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid); int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid);
@ -112,7 +109,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
/* Set debug level for logging, and whether to log on stdout/stderr or syslog */ /* Set debug level for logging, and whether to log on stdout/stderr or syslog */
void dm_event_log_set(int debug_log_level, int use_syslog); void dm_event_log_set(int debug_log_level, int use_syslog);
/* Log messages according to current debug level */ /* Log messages acroding to current debug level */
__attribute__((format(printf, 6, 0))) __attribute__((format(printf, 6, 0)))
void dm_event_log(const char *subsys, int level, const char *file, void dm_event_log(const char *subsys, int level, const char *file,
int line, int dm_errno_or_class, int line, int dm_errno_or_class,

View File

@ -87,7 +87,7 @@ int dmeventd_lvm2_init(void)
lvm2_disable_dmeventd_monitoring(_lvm_handle); lvm2_disable_dmeventd_monitoring(_lvm_handle);
/* FIXME Temporary: move to dmeventd core */ /* FIXME Temporary: move to dmeventd core */
lvm2_run(_lvm_handle, "_memlock_inc"); lvm2_run(_lvm_handle, "_memlock_inc");
log_debug("lvm plugin initialized."); log_debug("lvm plugin initilized.");
} }
_register_count++; _register_count++;
@ -103,7 +103,7 @@ void dmeventd_lvm2_exit(void)
pthread_mutex_lock(&_register_mutex); pthread_mutex_lock(&_register_mutex);
if (!--_register_count) { if (!--_register_count) {
log_debug("lvm plugin shutting down."); log_debug("lvm plugin shuting down.");
lvm2_run(_lvm_handle, "_memlock_dec"); lvm2_run(_lvm_handle, "_memlock_dec");
dm_pool_destroy(_mem_pool); dm_pool_destroy(_mem_pool);
_mem_pool = NULL; _mem_pool = NULL;
@ -123,7 +123,6 @@ struct dm_pool *dmeventd_lvm2_pool(void)
int dmeventd_lvm2_run(const char *cmdline) int dmeventd_lvm2_run(const char *cmdline)
{ {
/* coverity[missing_lock] no locking for run part */
return (lvm2_run(_lvm_handle, cmdline) == LVM2_COMMAND_SUCCEEDED); return (lvm2_run(_lvm_handle, cmdline) == LVM2_COMMAND_SUCCEEDED);
} }

View File

@ -25,8 +25,6 @@
#ifndef _DMEVENTD_LVMWRAP_H #ifndef _DMEVENTD_LVMWRAP_H
#define _DMEVENTD_LVMWRAP_H #define _DMEVENTD_LVMWRAP_H
#include <stddef.h>
struct dm_pool; struct dm_pool;
int dmeventd_lvm2_init(void); int dmeventd_lvm2_init(void);

View File

@ -38,7 +38,7 @@ static void _process_status_code(dm_status_mirror_health_t health,
* A => Alive - No failures * A => Alive - No failures
* D => Dead - A write failure occurred leaving mirror out-of-sync * D => Dead - A write failure occurred leaving mirror out-of-sync
* F => Flush failed. * F => Flush failed.
* S => Sync - A synchronization failure occurred, mirror out-of-sync * S => Sync - A sychronization failure occurred, mirror out-of-sync
* R => Read - A read failure occurred, mirror data unaffected * R => Read - A read failure occurred, mirror data unaffected
* U => Unclassified failure (bug) * U => Unclassified failure (bug)
*/ */
@ -112,7 +112,7 @@ static int _remove_failed_devices(const char *cmd_lvconvert, const char *device)
} }
void process_event(struct dm_task *dmt, void process_event(struct dm_task *dmt,
enum dm_event_mask evmask __attribute__((unused)), enum dm_event_mask event __attribute__((unused)),
void **user) void **user)
{ {
struct dso_state *state = *user; struct dso_state *state = *user;

View File

@ -17,7 +17,7 @@
#include "daemons/dmeventd/libdevmapper-event.h" #include "daemons/dmeventd/libdevmapper-event.h"
#include "lib/config/defaults.h" #include "lib/config/defaults.h"
/* Hold enough elements for the maximum number of RAID images */ /* Hold enough elements for the mximum number of RAID images */
#define RAID_DEVS_ELEMS ((DEFAULT_RAID_MAX_IMAGES + 63) / 64) #define RAID_DEVS_ELEMS ((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
struct dso_state { struct dso_state {
@ -84,7 +84,7 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
*/ */
if (!state->warned && status->insync_regions < status->total_regions) { if (!state->warned && status->insync_regions < status->total_regions) {
state->warned = 1; state->warned = 1;
log_warn("WARNING: Waiting for resynchronization to finish " log_warn("WARNING: waiting for resynchronization to finish "
"before initiating repair on RAID device %s.", device); "before initiating repair on RAID device %s.", device);
/* Fall through to allow lvconvert to run. */ /* Fall through to allow lvconvert to run. */
} }
@ -114,7 +114,7 @@ out:
} }
void process_event(struct dm_task *dmt, void process_event(struct dm_task *dmt,
enum dm_event_mask evmask __attribute__((unused)), enum dm_event_mask event __attribute__((unused)),
void **user) void **user)
{ {
struct dso_state *state = *user; struct dso_state *state = *user;

View File

@ -163,7 +163,7 @@ static void _umount(const char *device, int major, int minor)
} }
void process_event(struct dm_task *dmt, void process_event(struct dm_task *dmt,
enum dm_event_mask evmask __attribute__((unused)), enum dm_event_mask event __attribute__((unused)),
void **user) void **user)
{ {
struct dso_state *state = *user; struct dso_state *state = *user;

View File

@ -45,10 +45,10 @@
struct dso_state { struct dso_state {
struct dm_pool *mem; struct dm_pool *mem;
dm_percent_t metadata_percent_check; int metadata_percent_check;
dm_percent_t metadata_percent; int metadata_percent;
dm_percent_t data_percent_check; int data_percent_check;
dm_percent_t data_percent; int data_percent;
uint64_t known_metadata_size; uint64_t known_metadata_size;
uint64_t known_data_size; uint64_t known_data_size;
unsigned fails; unsigned fails;
@ -87,7 +87,7 @@ static int _run_command(struct dso_state *state)
log_verbose("Executing command: %s", state->cmd_str); log_verbose("Executing command: %s", state->cmd_str);
/* TODO: /* TODO:
* Support parallel run of 'task' and it's waitpid maintenance * Support parallel run of 'task' and it's waitpid maintainence
* ATM we can't handle signaling of SIGALRM * ATM we can't handle signaling of SIGALRM
* as signalling is not allowed while 'process_event()' is running * as signalling is not allowed while 'process_event()' is running
*/ */
@ -155,7 +155,7 @@ static int _wait_for_pid(struct dso_state *state)
} }
void process_event(struct dm_task *dmt, void process_event(struct dm_task *dmt,
enum dm_event_mask evmask, enum dm_event_mask event __attribute__((unused)),
void **user) void **user)
{ {
const char *device = dm_task_get_name(dmt); const char *device = dm_task_get_name(dmt);
@ -179,7 +179,7 @@ void process_event(struct dm_task *dmt,
return; return;
} }
if (evmask & DM_EVENT_DEVICE_ERROR) { if (event & DM_EVENT_DEVICE_ERROR) {
/* Error -> no need to check and do instant resize */ /* Error -> no need to check and do instant resize */
state->data_percent = state->metadata_percent = 0; state->data_percent = state->metadata_percent = 0;
if (_use_policy(dmt, state)) if (_use_policy(dmt, state))
@ -223,12 +223,10 @@ void process_event(struct dm_task *dmt,
} }
#if THIN_DEBUG #if THIN_DEBUG
log_debug("Thin pool status " FMTu64 "/" FMTu64 " (" FMTu64 ") " log_debug("Thin pool status " FMTu64 "/" FMTu64 " "
FMTu64 "/" FMTu64 " (" FMTu64").", FMTu64 "/" FMTu64 ".",
tps->used_data_blocks, tps->total_data_blocks,
state->known_data_size,
tps->used_metadata_blocks, tps->total_metadata_blocks, tps->used_metadata_blocks, tps->total_metadata_blocks,
state->known_metadata_size); tps->used_data_blocks, tps->total_data_blocks);
#endif #endif
/* Thin pool size had changed. Clear the threshold. */ /* Thin pool size had changed. Clear the threshold. */
@ -247,7 +245,7 @@ void process_event(struct dm_task *dmt,
/* /*
* Trigger action when threshold boundary is exceeded. * Trigger action when threshold boundary is exceeded.
* Report 80% threshold warning when it's used above 80%. * Report 80% threshold warning when it's used above 80%.
* Only 100% is exception as it cannot be surpassed so policy * Only 100% is exception as it cannot be surpased so policy
* action is called for: >50%, >55% ... >95%, 100% * action is called for: >50%, >55% ... >95%, 100%
*/ */
state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks); state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
@ -381,13 +379,14 @@ int register_device(const char *device,
state->argv[1] = str + 1; /* 1 argument - vg/lv */ state->argv[1] = str + 1; /* 1 argument - vg/lv */
_init_thread_signals(state); _init_thread_signals(state);
} else /* Unsupported command format */ } else /* Unuspported command format */
goto inval; goto inval;
state->max_fails = 1;
state->pid = -1; state->pid = -1;
*user = state; *user = state;
log_info("Monitoring thin pool %s.", device);
return 1; return 1;
inval: inval:
log_error("Invalid command for monitoring: %s.", cmd_str); log_error("Invalid command for monitoring: %s.", cmd_str);
@ -431,6 +430,7 @@ int unregister_device(const char *device,
_restore_thread_signals(state); _restore_thread_signals(state);
dmeventd_lvm2_exit_with_pool(state); dmeventd_lvm2_exit_with_pool(state);
log_info("No longer monitoring thin pool %s.", device);
return 1; return 1;
} }

View File

@ -19,7 +19,7 @@
/* /*
* Use parser from new device_mapper library. * Use parser from new device_mapper library.
* Although during compilation we can see dm_vdo_status_parse() * Although during compilation we can see dm_vdo_status_parse()
* in runtime we are linked against systems libdm 'older' library * in runtime we are linked agains systems libdm 'older' library
* which does not provide this symbol and plugin fails to load * which does not provide this symbol and plugin fails to load
*/ */
/* coverity[unnecessary_header] used for parsing */ /* coverity[unnecessary_header] used for parsing */
@ -78,7 +78,7 @@ static int _run_command(struct dso_state *state)
log_verbose("Executing command: %s", state->cmd_str); log_verbose("Executing command: %s", state->cmd_str);
/* TODO: /* TODO:
* Support parallel run of 'task' and it's waitpid maintenance * Support parallel run of 'task' and it's waitpid maintainence
* ATM we can't handle signaling of SIGALRM * ATM we can't handle signaling of SIGALRM
* as signalling is not allowed while 'process_event()' is running * as signalling is not allowed while 'process_event()' is running
*/ */
@ -146,7 +146,7 @@ static int _wait_for_pid(struct dso_state *state)
} }
void process_event(struct dm_task *dmt, void process_event(struct dm_task *dmt,
enum dm_event_mask evmask __attribute__((unused)), enum dm_event_mask event __attribute__((unused)),
void **user) void **user)
{ {
const char *device = dm_task_get_name(dmt); const char *device = dm_task_get_name(dmt);
@ -169,7 +169,7 @@ void process_event(struct dm_task *dmt,
return; return;
} }
if (evmask & DM_EVENT_DEVICE_ERROR) { if (event & DM_EVENT_DEVICE_ERROR) {
#if VDO_DEBUG #if VDO_DEBUG
log_debug("VDO event error."); log_debug("VDO event error.");
#endif #endif
@ -227,7 +227,7 @@ void process_event(struct dm_task *dmt,
/* /*
* Trigger action when threshold boundary is exceeded. * Trigger action when threshold boundary is exceeded.
* Report 80% threshold warning when it's used above 80%. * Report 80% threshold warning when it's used above 80%.
* Only 100% is exception as it cannot be surpassed so policy * Only 100% is exception as it cannot be surpased so policy
* action is called for: >50%, >55% ... >95%, 100% * action is called for: >50%, >55% ... >95%, 100%
*/ */
if ((state->percent > WARNING_THRESH) && if ((state->percent > WARNING_THRESH) &&
@ -354,7 +354,7 @@ int register_device(const char *device,
_init_thread_signals(state); _init_thread_signals(state);
} else if (cmd[0] == 0) { } else if (cmd[0] == 0) {
state->name = "volume"; /* What to use with 'others?' */ state->name = "volume"; /* What to use with 'others?' */
} else/* Unsupported command format */ } else/* Unuspported command format */
goto inval; goto inval;
state->pid = -1; state->pid = -1;

View File

@ -51,14 +51,18 @@ include $(top_builddir)/make.tmpl
.PHONY: install_lvmdbusd .PHONY: install_lvmdbusd
all:
$(Q) test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
install_lvmdbusd: $(LVMDBUSD) install_lvmdbusd: $(LVMDBUSD)
$(SHOW) " [INSTALL] $<" @echo " [INSTALL] $<"
$(Q) $(INSTALL_DIR) $(sbindir) $(Q) $(INSTALL_DIR) $(sbindir)
$(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir) $(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
$(Q) $(INSTALL_DIR) $(lvmdbusdir) $(lvmdbusdir)/__pycache__ $(Q) $(INSTALL_DIR) $(lvmdbusdir)
$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(lvmdbusdir)) $(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(lvmdbusdir))
$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir) $(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir)
$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbuspydir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES) $(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbuspydir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
$(Q) $(CHMOD) 755 $(lvmdbusdir)/__pycache__
$(Q) $(CHMOD) 444 $(lvmdbusdir)/__pycache__/*.py[co] $(Q) $(CHMOD) 444 $(lvmdbusdir)/__pycache__/*.py[co]
install_lvm2: install_lvmdbusd install_lvm2: install_lvmdbusd

View File

@ -44,10 +44,10 @@ class AutomatedProperties(dbus.service.Object):
def set_interface(self, interface): def set_interface(self, interface):
""" """
With inheritance, we can't easily tell what interfaces a class provides, With inheritance we can't easily tell what interfaces a class provides
so we will have each class that implements an interface tell the so we will have each class that implements an interface tell the
base AutomatedProperties what it is they do provide. This is kind of base AutomatedProperties what it is they do provide. This is kind of
clunky, and perhaps we can figure out a better way to do this later. clunky and perhaps we can figure out a better way to do this later.
:param interface: An interface the object supports :param interface: An interface the object supports
:return: :return:
""" """
@ -88,6 +88,7 @@ class AutomatedProperties(dbus.service.Object):
cb, cbe, False) cb, cbe, False)
cfg.worker_q.put(r) cfg.worker_q.put(r)
@staticmethod @staticmethod
def _get_all_prop(obj, interface_name): def _get_all_prop(obj, interface_name):
if interface_name in obj.interface(True): if interface_name in obj.interface(True):

View File

@ -7,13 +7,16 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import subprocess
from . import cfg from . import cfg
from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm
import dbus import dbus
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
mt_async_call
from .request import RequestEntry from .request import RequestEntry
import threading import threading
import time import time
import traceback
def pv_move_lv_cmd(move_options, lv_full_name, def pv_move_lv_cmd(move_options, lv_full_name,
@ -62,15 +65,18 @@ def _move_callback(job_state, line_str):
def _move_merge(interface_name, command, job_state): def _move_merge(interface_name, command, job_state):
# We need to execute these command stand alone by forking & exec'ing # We need to execute these command stand alone by forking & exec'ing
# the command always as we will be getting periodic output from them on # the command always as we will be getting periodic output from them on
# the status of the long-running operation. # the status of the long running operation.
meta = LvmExecutionMeta(time.time(), 0, command) meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
cfg.flightrecorder.add(meta) cfg.blackbox.add(meta)
ec, stdout, stderr = call_lvm(command, line_cb=_move_callback, ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
cb_data=job_state) cb_data=job_state)
ended = time.time()
meta.completed(ended, ec, stdout, stderr) with meta.lock:
meta.ended = time.time()
meta.ec = ec
meta.stderr_txt = stderr
if ec == 0: if ec == 0:
job_state.Percent = 100 job_state.Percent = 100

View File

@ -11,18 +11,11 @@ import os
import multiprocessing import multiprocessing
import queue import queue
import itertools import itertools
from lvmdbusd.utils import LvmDebugData
from lvmdbusd import path from lvmdbusd import path
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY) LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
LOCK_FILE = os.getenv("LVM_DBUSD_LOCKFILE", "/var/lock/lvm/lvmdbusd")
# Save off the debug data needed for lvm team to debug issues
# only used for 'fullreport' at this time.
lvmdebug = LvmDebugData(os.getenv('LVM_DBUSD_COLLECT_LVM_DEBUG', False))
# This is the global object manager # This is the global object manager
om = None om = None
@ -32,13 +25,13 @@ bus = None
# Command line args # Command line args
args = None args = None
# Set to true if we depend on external events for updates # Set to true if we are depending on external events for updates
got_external_event = False got_external_event = False
# Shared state variable across all processes # Shared state variable across all processes
run = multiprocessing.Value('i', 1) run = multiprocessing.Value('i', 1)
# If this is set to true, the current setup support lvm shell, and we are # If this is set to true, the current setup support lvm shell and we are
# running in that mode of operation # running in that mode of operation
SHELL_IN_USE = None SHELL_IN_USE = None
@ -50,11 +43,6 @@ worker_q = queue.Queue()
# Main event loop # Main event loop
loop = None loop = None
G_LOOP_TMO = 0.5
# Used to instruct the daemon if we should ignore SIGTERM
ignore_sigterm = False
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1') BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
BASE_INTERFACE = 'com.redhat.lvmdbus1' BASE_INTERFACE = 'com.redhat.lvmdbus1'
PV_INTERFACE = BASE_INTERFACE + '.Pv' PV_INTERFACE = BASE_INTERFACE + '.Pv'
@ -102,14 +90,11 @@ vdo_support = False
db = None db = None
# lvm flight recorder # lvm flight recorder
flightrecorder = None blackbox = None
# RequestEntry ctor # RequestEntry ctor
create_request_entry = None create_request_entry = None
# Circular debug log
debug = None
def exit_daemon(): def exit_daemon():
""" """
@ -119,6 +104,3 @@ def exit_daemon():
if run and loop: if run and loop:
run.value = 0 run.value = 0
loop.quit() loop.quit()
systemd = False

View File

@ -6,18 +6,19 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import errno
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
import select import select
import time import time
import threading import threading
from itertools import chain from itertools import chain
import collections import collections
import traceback
import os import os
from lvmdbusd import cfg from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\ from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
make_non_block, read_decoded, extract_stack_trace, LvmBug, add_config_option, get_error_msg make_non_block, read_decoded
from lvmdbusd.lvm_shell_proxy import LVMShellProxy from lvmdbusd.lvm_shell_proxy import LVMShellProxy
try: try:
@ -25,6 +26,7 @@ try:
except ImportError: except ImportError:
import json import json
SEP = '{|}'
total_time = 0.0 total_time = 0.0
total_count = 0 total_count = 0
@ -36,7 +38,7 @@ cmd_lock = threading.RLock()
class LvmExecutionMeta(object): class LvmExecutionMeta(object):
def __init__(self, start, ended, cmd, ec=-1000, stdout_txt=None, stderr_txt=None): def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
self.lock = threading.RLock() self.lock = threading.RLock()
self.start = start self.start = start
self.ended = ended self.ended = ended
@ -47,49 +49,32 @@ class LvmExecutionMeta(object):
def __str__(self): def __str__(self):
with self.lock: with self.lock:
if self.ended == 0: return "EC= %d for %s\n" \
ended_txt = "still running" "STARTED: %f, ENDED: %f\n" \
self.ended = time.time()
else:
ended_txt = str(time.ctime(self.ended))
return 'EC= %d for "%s"\n' \
"STARTED: %s, ENDED: %s, DURATION: %f\n" \
"STDOUT=%s\n" \ "STDOUT=%s\n" \
"STDERR=%s\n" % \ "STDERR=%s\n" % \
(self.ec, " ".join(self.cmd), time.ctime(self.start), ended_txt, float(self.ended) - self.start, (self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
self.stdout_txt, self.stderr_txt)
self.stderr_txt)
def completed(self, end_time, ec, stdout_txt, stderr_txt):
with self.lock:
self.ended = end_time
self.ec = ec
self.stdout_txt = stdout_txt
self.stderr_txt = stderr_txt
class LvmFlightRecorder(object): class LvmFlightRecorder(object):
def __init__(self, size=16): def __init__(self, size=16):
self.queue = collections.deque(maxlen=size) self.queue = collections.deque(maxlen=size)
self.lock = threading.RLock()
def add(self, lvm_exec_meta): def add(self, lvm_exec_meta):
with self.lock: self.queue.append(lvm_exec_meta)
self.queue.append(lvm_exec_meta)
def dump(self): def dump(self):
with self.lock: with cmd_lock:
if len(self.queue): if len(self.queue):
log_error("LVM dbus flight recorder START (in order of newest to oldest)") log_error("LVM dbus flight recorder START")
for c in reversed(self.queue): for c in reversed(self.queue):
log_error(str(c)) log_error(str(c))
log_error("LVM dbus flight recorder END") log_error("LVM dbus flight recorder END")
self.queue.clear()
cfg.flightrecorder = LvmFlightRecorder() cfg.blackbox = LvmFlightRecorder()
def _debug_c(cmd, exit_code, out): def _debug_c(cmd, exit_code, out):
@ -109,7 +94,7 @@ def call_lvm(command, debug=False, line_cb=None,
stdin, CALL MUST EXECUTE QUICKLY and not *block* stdin, CALL MUST EXECUTE QUICKLY and not *block*
otherwise call_lvm function will fail to read otherwise call_lvm function will fail to read
stdin/stdout. Return value of call back is ignored stdin/stdout. Return value of call back is ignored
:param cb_data: Supplied to call back to allow caller access to :param cb_data: Supplied to callback to allow caller access to
its own data its own data
# Callback signature # Callback signature
@ -121,9 +106,6 @@ def call_lvm(command, debug=False, line_cb=None,
command.insert(0, cfg.LVM_CMD) command.insert(0, cfg.LVM_CMD)
command = add_no_notify(command) command = add_no_notify(command)
# Ensure we get an error message when we fork & exec the lvm command line
command = add_config_option(command, "--config", 'log/command_log_selection="log_context!=''"')
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True, process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
env=os.environ) env=os.environ)
@ -133,10 +115,10 @@ def call_lvm(command, debug=False, line_cb=None,
make_non_block(process.stdout) make_non_block(process.stdout)
make_non_block(process.stderr) make_non_block(process.stderr)
while True and cfg.run.value != 0: while True:
try: try:
rd_fd = [process.stdout.fileno(), process.stderr.fileno()] rd_fd = [process.stdout.fileno(), process.stderr.fileno()]
ready = select.select(rd_fd, [], [], cfg.G_LOOP_TMO) ready = select.select(rd_fd, [], [], 2)
for r in ready[0]: for r in ready[0]:
if r == process.stdout.fileno(): if r == process.stdout.fileno():
@ -151,8 +133,8 @@ def call_lvm(command, debug=False, line_cb=None,
if i != -1: if i != -1:
try: try:
line_cb(cb_data, stdout_text[stdout_index:i]) line_cb(cb_data, stdout_text[stdout_index:i])
except BaseException as be: except:
st = extract_stack_trace(be) st = traceback.format_exc()
log_error("call_lvm: line_cb exception: \n %s" % st) log_error("call_lvm: line_cb exception: \n %s" % st)
stdout_index = i + 1 stdout_index = i + 1
else: else:
@ -160,36 +142,15 @@ def call_lvm(command, debug=False, line_cb=None,
# Check to see if process has terminated, None when running # Check to see if process has terminated, None when running
if process.poll() is not None: if process.poll() is not None:
stdout_text += read_decoded(process.stdout)
stderr_text += read_decoded(process.stderr)
break break
except IOError as ioe: except IOError as ioe:
log_debug("call_lvm:" + str(ioe)) log_debug("call_lvm:" + str(ioe))
break pass
if process.returncode is not None: if debug or process.returncode != 0:
cfg.lvmdebug.lvm_complete() _debug_c(command, process.returncode, (stdout_text, stderr_text))
if debug or (process.returncode != 0 and (process.returncode != 5 and "fullreport" in command)):
_debug_c(command, process.returncode, (stdout_text, stderr_text))
try:
report_json = json.loads(stdout_text)
except json.decoder.JSONDecodeError:
# Some lvm commands don't return json even though we are asking for it to do so.
return process.returncode, stdout_text, stderr_text
error_msg = get_error_msg(report_json)
if error_msg:
stderr_text += error_msg
return process.returncode, report_json, stderr_text
else:
if cfg.run.value == 0:
raise SystemExit
# We can bail out before the lvm command finished when we get a signal
# which is requesting we exit
return -errno.EINTR, "", "operation interrupted"
return process.returncode, stdout_text, stderr_text
# The actual method which gets called to invoke the lvm command, can vary # The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell # from forking a new process to using lvm shell
@ -204,18 +165,18 @@ def _shell_cfg():
_t_call = lvm_shell.call_lvm _t_call = lvm_shell.call_lvm
cfg.SHELL_IN_USE = lvm_shell cfg.SHELL_IN_USE = lvm_shell
return True return True
except Exception as e: except Exception:
_t_call = call_lvm _t_call = call_lvm
cfg.SHELL_IN_USE = None cfg.SHELL_IN_USE = None
log_error("Unable to utilize lvm shell, dropping " log_error(traceback.format_exc())
"back to fork & exec\n%s" % extract_stack_trace(e)) log_error("Unable to utilize lvm shell, dropping back to fork & exec")
return False return False
def set_execution(shell): def set_execution(shell):
global _t_call global _t_call
with cmd_lock: with cmd_lock:
# If the user requested lvm shell, and we are currently setup that # If the user requested lvm shell and we are currently setup that
# way, just return # way, just return
if cfg.SHELL_IN_USE and shell: if cfg.SHELL_IN_USE and shell:
return True return True
@ -239,15 +200,11 @@ def time_wrapper(command, debug=False):
with cmd_lock: with cmd_lock:
start = time.time() start = time.time()
meta = LvmExecutionMeta(start, 0, command)
# Add the partial metadata to flight recorder, so if the command hangs
# we will see what it was.
cfg.flightrecorder.add(meta)
results = _t_call(command, debug) results = _t_call(command, debug)
ended = time.time() ended = time.time()
total_time += (ended - start) total_time += (ended - start)
total_count += 1 total_count += 1
meta.completed(ended, *results) cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
return results return results
@ -257,11 +214,44 @@ call = time_wrapper
# Default cmd # Default cmd
# Place default arguments for every command here. # Place default arguments for every command here.
def _dc(cmd, args): def _dc(cmd, args):
c = [cmd, '--nosuffix', '--unbuffered', '--units', 'b'] c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
'--unbuffered', '--units', 'b']
c.extend(args) c.extend(args)
return c return c
def parse(out):
rc = []
for line in out.split('\n'):
# This line includes separators, so process them
if SEP in line:
elem = line.split(SEP)
cleaned_elem = []
for e in elem:
e = e.strip()
cleaned_elem.append(e)
if len(cleaned_elem) > 1:
rc.append(cleaned_elem)
else:
t = line.strip()
if len(t) > 0:
rc.append(t)
return rc
def parse_column_names(out, column_names):
lines = parse(out)
rc = []
for i in range(0, len(lines)):
d = dict(list(zip(column_names, lines[i])))
rc.append(d)
return rc
def options_to_cli_args(options): def options_to_cli_args(options):
rc = [] rc = []
for k, v in list(dict(options).items()): for k, v in list(dict(options).items()):
@ -326,12 +316,10 @@ def vg_rename(vg_uuid, new_name, rename_options):
return call(cmd) return call(cmd)
def vg_remove(vg_id, remove_options): def vg_remove(vg_name, remove_options):
cmd = ['vgremove'] cmd = ['vgremove']
cmd.extend(options_to_cli_args(remove_options)) cmd.extend(options_to_cli_args(remove_options))
cmd.extend(['-f', vg_id]) cmd.extend(['-f', vg_name])
# https://bugzilla.redhat.com/show_bug.cgi?id=2175220 is preventing us from doing the following
# cmd.extend(['-f', "--select", "vg_uuid=%s" % vg_id])
return call(cmd) return call(cmd)
@ -554,14 +542,6 @@ def lv_vdo_deduplication(lv_path, enable, dedup_options):
return call(cmd) return call(cmd)
def lv_raid_repair(lv_path, new_pvs, repair_options):
cmd = ['lvconvert', '-y', '--repair']
cmd.append(lv_path)
cmd.extend(new_pvs)
cmd.extend(options_to_cli_args(repair_options))
return call(cmd)
def supports_json(): def supports_json():
cmd = ['help'] cmd = ['help']
rc, out, err = call(cmd) rc, out, err = call(cmd)
@ -633,25 +613,68 @@ def lvm_full_report_json():
'--configreport', 'vg', '-o', ','.join(vg_columns), '--configreport', 'vg', '-o', ','.join(vg_columns),
'--configreport', 'lv', '-o', ','.join(lv_columns), '--configreport', 'lv', '-o', ','.join(lv_columns),
'--configreport', 'seg', '-o', ','.join(lv_seg_columns), '--configreport', 'seg', '-o', ','.join(lv_seg_columns),
'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns) '--configreport', 'pvseg', '-o', ','.join(pv_seg_columns),
'--reportformat', 'json'
]) ])
# We are running the fullreport command, we will ask lvm to output the debug
# data, so we can have the required information for lvm to debug the fullreport failures.
# Note: this is disabled by default and can be enabled with env. var.
# LVM_DBUSD_COLLECT_LVM_DEBUG=True
fn = cfg.lvmdebug.setup()
if fn is not None:
add_config_option(cmd, "--config", "log {level=7 file=%s syslog=0}" % fn)
rc, out, err = call(cmd) rc, out, err = call(cmd)
# When we have an exported vg the exit code of lvs or fullreport will be 5 # When we have an exported vg the exit code of lvs or fullreport will be 5
if rc == 0 or rc == 5: if rc == 0 or rc == 5:
if type(out) != dict: # With the current implementation, if we are using the shell then we
raise LvmBug("lvm likely returned invalid JSON, lvm exit code = %d, output = %s, err= %s" % # are using JSON and JSON is returned back to us as it was parsed to
(rc, str(out), str(err))) # figure out if we completed OK or not
return out if cfg.SHELL_IN_USE:
raise LvmBug("'fullreport' exited with code '%d'" % rc) assert(type(out) == dict)
return out
else:
try:
return json.loads(out)
except json.decoder.JSONDecodeError as joe:
log_error("JSONDecodeError %s, \n JSON=\n%s\n" %
(str(joe), out))
raise joe
return None
def pv_retrieve_with_segs(device=None):
d = []
err = ""
out = ""
rc = 0
columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing']
# Lvm has some issues where it returns failure when querying pvs when other
# operations are in process, see:
# https://bugzilla.redhat.com/show_bug.cgi?id=1274085
for i in range(0, 10):
cmd = _dc('pvs', ['-o', ','.join(columns)])
if device:
cmd.extend(device)
rc, out, err = call(cmd)
if rc == 0:
d = parse_column_names(out, columns)
break
else:
time.sleep(0.2)
log_debug("LVM Bug workaround, retrying pvs command...")
if rc != 0:
msg = "We were unable to get pvs to return without error after " \
"trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \
(rc, err, out)
log_error(msg)
raise RuntimeError(msg)
return d
def pv_resize(device, size_bytes, create_options): def pv_resize(device, size_bytes, create_options):
@ -797,10 +820,6 @@ def activate_deactivate(op, name, activate, control_flags, options):
if (1 << 5) & control_flags: if (1 << 5) & control_flags:
cmd.append('--ignoreactivationskip') cmd.append('--ignoreactivationskip')
# Shared locking (Cluster)
if (1 << 6) & control_flags:
op += 's'
if activate: if activate:
op += 'y' op += 'y'
else: else:
@ -812,6 +831,53 @@ def activate_deactivate(op, name, activate, control_flags, options):
return call(cmd) return call(cmd)
def vg_retrieve(vg_specific):
if vg_specific:
assert isinstance(vg_specific, list)
columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free',
'vg_sysid', 'vg_extent_size', 'vg_extent_count',
'vg_free_count', 'vg_profile', 'max_lv', 'max_pv',
'pv_count', 'lv_count', 'snap_count', 'vg_seqno',
'vg_mda_count', 'vg_mda_free', 'vg_mda_size',
'vg_mda_used_count', 'vg_attr', 'vg_tags']
cmd = _dc('vgs', ['-o', ','.join(columns)])
if vg_specific:
cmd.extend(vg_specific)
d = []
rc, out, err = call(cmd)
if rc == 0:
d = parse_column_names(out, columns)
return d
def lv_retrieve_with_segments():
columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size',
'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid',
'origin', 'data_percent',
'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
'metadata_lv', 'seg_pe_ranges', 'segtype', 'lv_parent',
'lv_role', 'lv_layout',
'snap_percent', 'metadata_percent', 'copy_percent',
'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
cmd = _dc('lvs', ['-a', '-o', ','.join(columns)])
rc, out, err = call(cmd)
d = []
if rc == 0:
d = parse_column_names(out, columns)
return d
if __name__ == '__main__': if __name__ == '__main__':
# Leave this for future debug as needed pv_data = pv_retrieve_with_segs()
pass
for p in pv_data:
print(str(p))

View File

@ -6,16 +6,16 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import errno
from .pv import load_pvs from .pv import load_pvs
from .vg import load_vgs from .vg import load_vgs
from .lv import load_lvs from .lv import load_lvs
from . import cfg from . import cfg
from .utils import MThreadRunner, log_debug, log_error, LvmBug, extract_stack_trace from .utils import MThreadRunner, log_debug, log_error
import threading import threading
import queue import queue
import time import time
import traceback
def _main_thread_load(refresh=True, emit_signal=True): def _main_thread_load(refresh=True, emit_signal=True):
@ -120,125 +120,89 @@ class StateUpdate(object):
@staticmethod @staticmethod
def update_thread(obj): def update_thread(obj):
exception_count = 0 exception_count = 0
queued_requests = [] queued_requests = []
def set_results(val):
nonlocal queued_requests
for idx in queued_requests:
idx.set_result(val)
# Only clear out the requests after we have given them a result
# otherwise we can orphan the waiting threads, and they never
# wake up if we get an exception
queued_requests = []
def bailing(rv):
set_results(rv)
try:
while True:
item = obj.queue.get(False)
item.set_result(rv)
except queue.Empty:
pass
def _load_args(requests):
"""
If we have multiple requests in the queue, they might not all have the same options. If any of the requests
have an option set we need to honor it.
"""
refresh = any([r.refresh for r in requests])
emit_signal = any([r.emit_signal for r in requests])
cache_refresh = any([r.cache_refresh for r in requests])
log = any([r.log for r in requests])
need_main_thread = any([r.need_main_thread for r in requests])
return refresh, emit_signal, cache_refresh, log, need_main_thread
def _drain_queue(queued, incoming):
try:
while True:
queued.append(incoming.get(block=False))
except queue.Empty:
pass
def _handle_error():
nonlocal exception_count
exception_count += 1
if exception_count >= 5:
log_error("Too many errors in update_thread, exiting daemon")
cfg.debug.dump()
cfg.flightrecorder.dump()
bailing(errno.EFAULT)
cfg.exit_daemon()
else:
# Slow things down when encountering errors
cfg.lvmdebug.complete()
time.sleep(1)
while cfg.run.value != 0: while cfg.run.value != 0:
# noinspection PyBroadException # noinspection PyBroadException
try: try:
refresh = True
emit_signal = True
cache_refresh = True
log = True
need_main_thread = True
with obj.lock: with obj.lock:
wait = not obj.deferred wait = not obj.deferred
obj.deferred = False obj.deferred = False
if len(queued_requests) == 0 and wait: if len(queued_requests) == 0 and wait:
# Note: If we don't have anything for N seconds we will queued_requests.append(obj.queue.get(True, 2))
# get a queue.Empty exception raised here
queued_requests.append(obj.queue.get(block=True, timeout=cfg.G_LOOP_TMO))
# Ok we have one or the deferred queue has some, # Ok we have one or the deferred queue has some,
# check if any others and grab them too # check if any others
_drain_queue(queued_requests, obj.queue) try:
while True:
queued_requests.append(obj.queue.get(False))
except queue.Empty:
pass
if len(queued_requests) > 1: if len(queued_requests) > 1:
log_debug("Processing %d updates!" % len(queued_requests), log_debug("Processing %d updates!" % len(queued_requests),
'bg_black', 'fg_light_green') 'bg_black', 'fg_light_green')
num_changes = load(*_load_args(queued_requests)) # We have what we can, run the update with the needed options
for i in queued_requests:
if not i.refresh:
refresh = False
if not i.emit_signal:
emit_signal = False
if not i.cache_refresh:
cache_refresh = False
if not i.log:
log = False
if not i.need_main_thread:
need_main_thread = False
num_changes = load(refresh, emit_signal, cache_refresh, log,
need_main_thread)
# Update is done, let everyone know! # Update is done, let everyone know!
set_results(num_changes) for i in queued_requests:
i.set_result(num_changes)
# Only clear out the requests after we have given them a result
# otherwise we can orphan the waiting threads and they never
# wake up if we get an exception
queued_requests = []
# We retrieved OK, clear exception count # We retrieved OK, clear exception count
exception_count = 0 exception_count = 0
except queue.Empty: except queue.Empty:
pass pass
except SystemExit:
break
except LvmBug as bug:
# If a lvm bug occurred, we will dump the lvm debug data if
# we have it.
cfg.lvmdebug.dump()
log_error(str(bug))
_handle_error()
except Exception as e: except Exception as e:
log_error("update_thread: \n%s" % extract_stack_trace(e)) st = traceback.format_exc()
_handle_error() log_error("update_thread exception: \n%s" % st)
finally: cfg.blackbox.dump()
cfg.lvmdebug.complete() exception_count += 1
if exception_count >= 5:
for i in queued_requests:
i.set_result(e)
# Make sure to unblock any that may be waiting before we exit this thread log_error("Too many errors in update_thread, exiting daemon")
# otherwise they hang forever ... cfg.exit_daemon()
bailing(Exception("update thread exiting"))
log_debug("update thread exiting!") else:
# Slow things down when encountering errors
time.sleep(1)
def __init__(self): def __init__(self):
self.lock = threading.RLock() self.lock = threading.RLock()
self.queue = queue.Queue() self.queue = queue.Queue()
self.deferred = False self.deferred = False
# Do initial load, with retries. During error injection testing we can and do fail here. # Do initial load
count = 0 load(refresh=False, emit_signal=False, need_main_thread=False)
need_refresh = False # First attempt we are building from new, any subsequent will be true
while count < 5:
try:
load(refresh=need_refresh, emit_signal=False, need_main_thread=False)
break
except LvmBug as bug:
count += 1
need_refresh = True
log_error("We encountered an lvm bug on initial load, trying again %s" % str(bug))
self.thread = threading.Thread(target=StateUpdate.update_thread, self.thread = threading.Thread(target=StateUpdate.update_thread,
args=(self,), args=(self,),

View File

@ -44,7 +44,7 @@ class WaitingClient(object):
self.timer_id = GLib.timeout_add_seconds( self.timer_id = GLib.timeout_add_seconds(
tmo, WaitingClient._timeout, self) tmo, WaitingClient._timeout, self)
# The job finished before the timer popped, and we are being notified that # The job finished before the timer popped and we are being notified that
# it's done # it's done
def notify(self): def notify(self):
with self.rlock: with self.rlock:
@ -71,7 +71,7 @@ class JobState(object):
self._stderr = '' self._stderr = ''
self._waiting_clients = [] self._waiting_clients = []
# This is a lvm command that is just taking too long and doesn't # This is an lvm command that is just taking too long and doesn't
# support background operation # support background operation
if self._request: if self._request:
# Faking the percentage when we don't have one # Faking the percentage when we don't have one
@ -138,7 +138,7 @@ class JobState(object):
# If a waiting client timer pops before the job is done we will allow # If a waiting client timer pops before the job is done we will allow
# the client to remove themselves from the list. As we have a lock # the client to remove themselves from the list. As we have a lock
# here and a lock in the waiting client too, and they can be obtained # here and a lock in the waiting client too, and they can be obtained
# in different orders, a deadlock can occur. # in different orders, a dead lock can occur.
# As this remove is really optional, we will try to acquire the lock # As this remove is really optional, we will try to acquire the lock
# and remove. If we are unsuccessful it's not fatal, we just delay # and remove. If we are unsuccessful it's not fatal, we just delay
# the time when the objects can be garbage collected by python # the time when the objects can be garbage collected by python
@ -226,21 +226,3 @@ class Job(AutomatedProperties):
def Uuid(self): def Uuid(self):
import uuid import uuid
return uuid.uuid1() return uuid.uuid1()
# Override the property "getters" implementation for the job interface, so a user can query a job while the queue
# is processing items. Originally all the property get methods were this way, but we changed this in
# e53454d6de07de56736303dd2157c3859f6fa848
# Properties
# noinspection PyUnusedLocal
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='ss', out_signature='v')
def Get(self, interface_name, property_name):
# Note: If we get an exception in this handler we won't know about it,
# only the side effect of no returned value!
return AutomatedProperties._get_prop(self, interface_name, property_name)
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='s', out_signature='a{sv}')
def GetAll(self, interface_name):
return AutomatedProperties._get_all_prop(self, interface_name)

View File

@ -42,7 +42,7 @@ def common(retrieve, o_type, search_keys,
existing_paths = cfg.om.object_paths_by_type(o_type) existing_paths = cfg.om.object_paths_by_type(o_type)
for o in objects: for o in objects:
# Assume we need to add this one to dbus, unless we are refreshing, # Assume we need to add this one to dbus, unless we are refreshing
# and it's already present # and it's already present
return_object = True return_object = True

View File

@ -10,7 +10,7 @@
from .automatedproperties import AutomatedProperties from .automatedproperties import AutomatedProperties
from . import utils from . import utils
from .utils import vg_obj_path_generate, log_error, _handle_execute, LvmBug from .utils import vg_obj_path_generate, log_error, _handle_execute
import dbus import dbus
from . import cmdhandler from . import cmdhandler
from . import cfg from . import cfg
@ -21,12 +21,14 @@ from .utils import n, n32, d
from .loader import common from .loader import common
from .state import State from .state import State
from . import background from . import background
from .utils import round_size, mt_remove_dbus_objects, lvm_column_key from .utils import round_size, mt_remove_dbus_objects
from .job import JobState from .job import JobState
import traceback
# Try and build a key for a LV, so that we sort the LVs with the least dependencies
# first. This may be error-prone because of the flexibility LVM # Try and build a key for a LV, so that we sort the LVs with least dependencies
# first. This may be error prone because of the flexibility LVM
# provides and what you can stack. # provides and what you can stack.
def get_key(i): def get_key(i):
@ -65,80 +67,73 @@ def lvs_state_retrieve(selection, cache_refresh=True):
if cache_refresh: if cache_refresh:
cfg.db.refresh() cfg.db.refresh()
try: # When building up the model, it's best to process LVs with the least
# When building up the model, it's best to process LVs with the least # dependencies to those that are dependant upon other LVs. Otherwise, when
# dependencies to those that are dependent upon other LVs. Otherwise, when # we are trying to gather information we could be in a position where we
# we are trying to gather information we could be in a position where we # don't have information available yet.
# don't have information available yet. lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
for l in lvs: for l in lvs:
if cfg.vdo_support: if cfg.vdo_support:
rc.append(LvStateVdo( rc.append(LvStateVdo(
l['lv_uuid'], l['lv_name'], l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']), l['lv_path'], n(l['lv_size']),
l['vg_name'], l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'], l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'], l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'], n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'], l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'], l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'], l['lv_layout'],
n32(l['snap_percent']), n32(l['snap_percent']),
n32(l['metadata_percent']), n32(l['metadata_percent']),
n32(l['copy_percent']), n32(l['copy_percent']),
n32(l['sync_percent']), n32(l['sync_percent']),
n(l['lv_metadata_size']), n(l['lv_metadata_size']),
l['move_pv'], l['move_pv'],
l['move_pv_uuid'], l['move_pv_uuid'],
l['vdo_operating_mode'], l['vdo_operating_mode'],
l['vdo_compression_state'], l['vdo_compression_state'],
l['vdo_index_state'], l['vdo_index_state'],
n(l['vdo_used_size']), n(l['vdo_used_size']),
d(l['vdo_saving_percent']), d(l['vdo_saving_percent']),
l['vdo_compression'], l['vdo_compression'],
l['vdo_deduplication'], l['vdo_deduplication'],
l['vdo_use_metadata_hints'], l['vdo_use_metadata_hints'],
n32(l['vdo_minimum_io_size']), n32(l['vdo_minimum_io_size']),
n(l['vdo_block_map_cache_size']), n(l['vdo_block_map_cache_size']),
n32(l['vdo_block_map_era_length']), n32(l['vdo_block_map_era_length']),
l['vdo_use_sparse_index'], l['vdo_use_sparse_index'],
n(l['vdo_index_memory_size']), n(l['vdo_index_memory_size']),
n(l['vdo_slab_size']), n(l['vdo_slab_size']),
n32(l['vdo_ack_threads']), n32(l['vdo_ack_threads']),
n32(l['vdo_bio_threads']), n32(l['vdo_bio_threads']),
n32(l['vdo_bio_rotation']), n32(l['vdo_bio_rotation']),
n32(l['vdo_cpu_threads']), n32(l['vdo_cpu_threads']),
n32(l['vdo_hash_zone_threads']), n32(l['vdo_hash_zone_threads']),
n32(l['vdo_logical_threads']), n32(l['vdo_logical_threads']),
n32(l['vdo_physical_threads']), n32(l['vdo_physical_threads']),
n32(l['vdo_max_discard']), n32(l['vdo_max_discard']),
l['vdo_write_policy'], l['vdo_write_policy'],
n32(l['vdo_header_size']))) n32(l['vdo_header_size'])))
else: else:
rc.append(LvState( rc.append(LvState(
l['lv_uuid'], l['lv_name'], l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']), l['lv_path'], n(l['lv_size']),
l['vg_name'], l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'], l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'], l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'], n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'], l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'], l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'], l['lv_layout'],
n32(l['snap_percent']), n32(l['snap_percent']),
n32(l['metadata_percent']), n32(l['metadata_percent']),
n32(l['copy_percent']), n32(l['copy_percent']),
n32(l['sync_percent']), n32(l['sync_percent']),
n(l['lv_metadata_size']), n(l['lv_metadata_size']),
l['move_pv'], l['move_pv'],
l['move_pv_uuid'])) l['move_pv_uuid']))
except KeyError as ke:
# Sometimes lvm omits returning one of the keys we requested.
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
return rc return rc
@ -279,15 +274,15 @@ class LvStateVdo(LvState):
MetaDataPercent, CopyPercent, SyncPercent, MetaDataPercent, CopyPercent, SyncPercent,
MetaDataSizeBytes, move_pv, move_pv_uuid, MetaDataSizeBytes, move_pv, move_pv_uuid,
vdo_operating_mode, vdo_compression_state, vdo_index_state, vdo_operating_mode, vdo_compression_state, vdo_index_state,
vdo_used_size, vdo_saving_percent, vdo_compression, vdo_used_size,vdo_saving_percent,vdo_compression,
vdo_deduplication, vdo_use_metadata_hints, vdo_deduplication,vdo_use_metadata_hints,
vdo_minimum_io_size, vdo_block_map_cache_size, vdo_minimum_io_size,vdo_block_map_cache_size,
vdo_block_map_era_length, vdo_use_sparse_index, vdo_block_map_era_length,vdo_use_sparse_index,
vdo_index_memory_size, vdo_slab_size, vdo_ack_threads, vdo_index_memory_size,vdo_slab_size,vdo_ack_threads,
vdo_bio_threads, vdo_bio_rotation, vdo_cpu_threads, vdo_bio_threads,vdo_bio_rotation,vdo_cpu_threads,
vdo_hash_zone_threads, vdo_logical_threads, vdo_hash_zone_threads,vdo_logical_threads,
vdo_physical_threads, vdo_max_discard, vdo_physical_threads,vdo_max_discard,
vdo_write_policy, vdo_header_size): vdo_write_policy,vdo_header_size):
super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes, super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
vg_name, vg_uuid, pool_lv_uuid, PoolLv, vg_name, vg_uuid, pool_lv_uuid, PoolLv,
origin_uuid, OriginLv, DataPercent, Attr, Tags, active, origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
@ -376,8 +371,8 @@ class LvCommon(AutomatedProperties):
return dbus.Struct((self.state.Attr[index], return dbus.Struct((self.state.Attr[index],
type_map.get(self.state.Attr[index], default)), type_map.get(self.state.Attr[index], default)),
signature="(ss)") signature="(ss)")
except BaseException as b: except BaseException:
st = utils.extract_stack_trace(b) st = traceback.format_exc()
log_error("attr_struct: \n%s" % st) log_error("attr_struct: \n%s" % st)
return dbus.Struct(('?', 'Unavailable'), signature="(ss)") return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
@ -600,7 +595,7 @@ class Lv(LvCommon):
optional_size = space + 512 - remainder optional_size = space + 512 - remainder
LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot( LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
lv_name, snapshot_options, name, optional_size)) lv_name, snapshot_options,name, optional_size))
full_name = "%s/%s" % (dbo.vg_name_lookup(), name) full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
return cfg.om.get_object_path_by_lvm_id(full_name) return cfg.om.get_object_path_by_lvm_id(full_name)
@ -640,7 +635,7 @@ class Lv(LvCommon):
size_change = new_size_bytes - dbo.SizeBytes size_change = new_size_bytes - dbo.SizeBytes
LvCommon.handle_execute(*cmdhandler.lv_resize( LvCommon.handle_execute(*cmdhandler.lv_resize(
dbo.lvm_id, size_change, pv_dests, resize_options)) dbo.lvm_id, size_change,pv_dests, resize_options))
return "/" return "/"
@dbus.service.method( @dbus.service.method(
@ -749,7 +744,7 @@ class Lv(LvCommon):
cfg.worker_q.put(r) cfg.worker_q.put(r)
@staticmethod @staticmethod
def _caching_common(method, lv_uuid, lv_name, lv_object_path, cache_options): def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
# Make sure we have a dbus object representing it # Make sure we have a dbus object representing it
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name) dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
@ -758,7 +753,7 @@ class Lv(LvCommon):
if lv_to_cache: if lv_to_cache:
fcn = lv_to_cache.lv_full_name() fcn = lv_to_cache.lv_full_name()
rc, out, err = method( rc, out, err = cmdhandler.lv_writecache_lv(
dbo.lv_full_name(), fcn, cache_options) dbo.lv_full_name(), fcn, cache_options)
if rc == 0: if rc == 0:
# When we cache an LV, the cache pool and the lv that is getting # When we cache an LV, the cache pool and the lv that is getting
@ -775,14 +770,9 @@ class Lv(LvCommon):
else: else:
raise dbus.exceptions.DBusException( raise dbus.exceptions.DBusException(
LV_INTERFACE, 'LV to cache with object path %s not present!' % LV_INTERFACE, 'LV to cache with object path %s not present!' %
lv_object_path) lv_object_path)
return lv_converted return lv_converted
@staticmethod
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
return Lv._caching_common(cmdhandler.lv_writecache_lv, lv_uuid,
lv_name, lv_object_path, cache_options)
@dbus.service.method( @dbus.service.method(
dbus_interface=LV_INTERFACE, dbus_interface=LV_INTERFACE,
in_signature='oia{sv}', in_signature='oia{sv}',
@ -795,39 +785,6 @@ class Lv(LvCommon):
cache_options), cb, cbe) cache_options), cb, cbe)
cfg.worker_q.put(r) cfg.worker_q.put(r)
@staticmethod
def _repair_raid_lv(lv_uuid, lv_name, new_pvs, repair_options):
# Make sure we have a dbus object representing it
pv_dests = []
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
# If we have PVs, verify them
if len(new_pvs):
for pv in new_pvs:
pv_dbus_obj = cfg.om.get_object_by_path(pv)
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'PV Destination (%s) not found' % pv)
pv_dests.append(pv_dbus_obj.lvm_id)
LvCommon.handle_execute(*cmdhandler.lv_raid_repair(
dbo.lvm_id, pv_dests, repair_options))
return "/"
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='aoia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def RepairRaidLv(self, new_pvs, tmo, repair_options, cb, cbe):
r = RequestEntry(
tmo, Lv._repair_raid_lv,
(self.Uuid, self.lvm_id, new_pvs,
repair_options), cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
# noinspection PyPep8Naming # noinspection PyPep8Naming
@utils.dbus_property(VDO_POOL_INTERFACE, 'OperatingMode', 's') @utils.dbus_property(VDO_POOL_INTERFACE, 'OperatingMode', 's')
@ -888,10 +845,10 @@ class LvVdoPool(Lv):
cfg.worker_q.put(r) cfg.worker_q.put(r)
@dbus.service.method( @dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE, dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}', in_signature='ia{sv}',
out_signature='o', out_signature='o',
async_callbacks=('cb', 'cbe')) async_callbacks=('cb', 'cbe'))
def DisableCompression(self, tmo, comp_options, cb, cbe): def DisableCompression(self, tmo, comp_options, cb, cbe):
r = RequestEntry( r = RequestEntry(
tmo, LvVdoPool._enable_disable_compression, tmo, LvVdoPool._enable_disable_compression,
@ -921,10 +878,10 @@ class LvVdoPool(Lv):
cfg.worker_q.put(r) cfg.worker_q.put(r)
@dbus.service.method( @dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE, dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}', in_signature='ia{sv}',
out_signature='o', out_signature='o',
async_callbacks=('cb', 'cbe')) async_callbacks=('cb', 'cbe'))
def DisableDeduplication(self, tmo, dedup_options, cb, cbe): def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
r = RequestEntry( r = RequestEntry(
tmo, LvVdoPool._enable_disable_deduplication, tmo, LvVdoPool._enable_disable_deduplication,
@ -995,8 +952,33 @@ class LvCachePool(Lv):
@staticmethod @staticmethod
def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options): def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
return Lv._caching_common(cmdhandler.lv_cache_lv, lv_uuid, lv_name, # Make sure we have a dbus object representing cache pool
lv_object_path, cache_options) dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
# Make sure we have dbus object representing lv to cache
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
if lv_to_cache:
fcn = lv_to_cache.lv_full_name()
rc, out, err = cmdhandler.lv_cache_lv(
dbo.lv_full_name(), fcn, cache_options)
if rc == 0:
# When we cache an LV, the cache pool and the lv that is getting
# cached need to be removed from the object manager and
# re-created as their interfaces have changed!
mt_remove_dbus_objects((dbo, lv_to_cache))
cfg.load()
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE, 'LV to cache with object path %s not present!' %
lv_object_path)
return lv_converted
@dbus.service.method( @dbus.service.method(
dbus_interface=CACHE_POOL_INTERFACE, dbus_interface=CACHE_POOL_INTERFACE,

View File

@ -14,12 +14,12 @@
import subprocess import subprocess
import shlex import shlex
import os import os
import pty import traceback
import sys import sys
import tempfile import tempfile
import time import time
import threading
import select import select
import copy
try: try:
import simplejson as json import simplejson as json
@ -27,9 +27,9 @@ except ImportError:
import json import json
import lvmdbusd.cfg as cfg from lvmdbusd.cfg import LVM_CMD
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\ from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
read_decoded, extract_stack_trace, LvmBug, get_error_msg read_decoded
SHELL_PROMPT = "lvm> " SHELL_PROMPT = "lvm> "
@ -43,11 +43,10 @@ def _quote_arg(arg):
class LVMShellProxy(object): class LVMShellProxy(object):
# Read REPORT FD until we have a complete and valid JSON record or give # Read until we get prompt back and a result
# up trying to get one. # @param: no_output Caller expects no output to report FD
# # Returns stdout, report, stderr (report is JSON!)
# Returns stdout, report (JSON), stderr def _read_until_prompt(self, no_output=False):
def _read_response(self, no_output=False):
stdout = "" stdout = ""
report = "" report = ""
stderr = "" stderr = ""
@ -59,27 +58,24 @@ class LVMShellProxy(object):
# Try reading from all FDs to prevent one from filling up and causing # Try reading from all FDs to prevent one from filling up and causing
# a hang. Keep reading until we get the prompt back and the report # a hang. Keep reading until we get the prompt back and the report
# FD does not contain valid JSON # FD does not contain valid JSON
while keep_reading:
while keep_reading and cfg.run.value != 0:
try: try:
rd_fd = [ rd_fd = [
self.parent_stdout_fd, self.lvm_shell.stdout.fileno(),
self.report_stream.fileno(), self.report_stream.fileno(),
self.parent_stderr_fd] self.lvm_shell.stderr.fileno()]
ready = select.select(rd_fd, [], [], cfg.G_LOOP_TMO) ready = select.select(rd_fd, [], [], 2)
for r in ready[0]: for r in ready[0]:
if r == self.parent_stdout_fd: if r == self.lvm_shell.stdout.fileno():
for line in self.parent_stdout.readlines(): stdout += read_decoded(self.lvm_shell.stdout)
stdout += line
elif r == self.report_stream.fileno(): elif r == self.report_stream.fileno():
report += read_decoded(self.report_stream) report += read_decoded(self.report_stream)
elif r == self.parent_stderr_fd: elif r == self.lvm_shell.stderr.fileno():
for line in self.parent_stderr.readlines(): stderr += read_decoded(self.lvm_shell.stderr)
stderr += line
# Check to see if the lvm process died on us # Check to see if the lvm process died on us
if self.lvm_shell.poll() is not None: if self.lvm_shell.poll():
raise Exception(self.lvm_shell.returncode, "%s" % stderr) raise Exception(self.lvm_shell.returncode, "%s" % stderr)
if stdout.endswith(SHELL_PROMPT): if stdout.endswith(SHELL_PROMPT):
@ -103,106 +99,91 @@ class LVMShellProxy(object):
extra_passes -= 1 extra_passes -= 1
if extra_passes <= 0: if extra_passes <= 0:
if len(report): if len(report):
raise LvmBug("Invalid json: %s" % raise ValueError("Invalid json: %s" %
report) report)
else: else:
raise LvmBug( raise ValueError(
"lvm returned no JSON output!") "lvm returned no JSON output!")
except Exception as e:
log_error("While reading from lvm shell we encountered an error %s" % str(e))
log_error("stdout= %s\nstderr= %s\n" % (stdout, stderr))
if self.lvm_shell.poll() is not None:
log_error("Underlying lvm shell process unexpectedly exited: %d" % self.lvm_shell.returncode)
else:
log_error("Underlying lvm shell process is still present!")
raise e
if keep_reading and cfg.run.value == 0: except IOError as ioe:
# We didn't complete as we are shutting down log_debug(str(ioe))
# Try to clean up lvm shell process pass
log_debug("exiting lvm shell as we are shutting down")
self.exit_shell()
raise SystemExit
return stdout, report_json, stderr return stdout, report_json, stderr
def _write_cmd(self, cmd): def _write_cmd(self, cmd):
self.parent_stdin.write(cmd) cmd_bytes = bytes(cmd, "utf-8")
self.parent_stdin.flush() num_written = self.lvm_shell.stdin.write(cmd_bytes)
assert (num_written == len(cmd_bytes))
self.lvm_shell.stdin.flush()
def __init__(self): def __init__(self):
# Create a temp directory # Create a temp directory
tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_") tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
tmp_file = "%s/lvmdbus_report" % (tmp_dir) tmp_file = "%s/lvmdbus_report" % (tmp_dir)
# Create a lock so that we don't step on each other when we are waiting for a command try:
# to finish and some other request comes in concurrently, like to exit the shell. # Lets create fifo for the report output
self.shell_lock = threading.RLock() os.mkfifo(tmp_file, 0o600)
except FileExistsError:
pass
# Create a fifo for the report output # We have to open non-blocking as the other side isn't open until
os.mkfifo(tmp_file, 0o600) # we actually fork the process.
# Open the fifo for use to read and for lvm child process to write to.
self.report_fd = os.open(tmp_file, os.O_NONBLOCK) self.report_fd = os.open(tmp_file, os.O_NONBLOCK)
self.report_stream = os.fdopen(self.report_fd, 'rb', 0) self.report_stream = os.fdopen(self.report_fd, 'rb', 0)
lvm_fd = os.open(tmp_file, os.O_WRONLY)
# Set up the environment for using our own socket for reporting and disable the abort # Setup the environment for using our own socket for reporting
# logic if lvm logs too much, which easily happens when utilizing the lvm shell. local_env = copy.deepcopy(os.environ)
local_env = {"LC_ALL": "C", "LVM_REPORT_FD": "%s" % lvm_fd, "LVM_COMMAND_PROFILE": "lvmdbusd", local_env["LVM_REPORT_FD"] = "32"
"LVM_LOG_FILE_MAX_LINES": "0"} local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd"
# If any env variables contain LVM we will propagate them too # Disable the abort logic if lvm logs too much, which easily happens
for k, v in os.environ.items(): # when utilizing the lvm shell.
if "PATH" in k: local_env["LVM_LOG_FILE_MAX_LINES"] = "0"
local_env[k] = v
if "LVM" in k:
local_env[k] = v
self.parent_stdin_fd, child_stdin_fd = pty.openpty()
self.parent_stdout_fd, child_stdout_fd = pty.openpty()
self.parent_stderr_fd, child_stderr_fd = pty.openpty()
self.parent_stdin = os.fdopen(self.parent_stdin_fd, "w")
self.parent_stdout = os.fdopen(self.parent_stdout_fd, "r")
self.parent_stderr = os.fdopen(self.parent_stderr_fd, "r")
# run the lvm shell # run the lvm shell
self.lvm_shell = subprocess.Popen( self.lvm_shell = subprocess.Popen(
[cfg.LVM_CMD], [LVM_CMD + " 32>%s" % tmp_file],
stdin=child_stdin_fd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env,
stdout=child_stdout_fd, env=local_env, stderr=subprocess.PIPE, close_fds=True, shell=True)
stderr=child_stderr_fd, close_fds=True,
pass_fds=(lvm_fd,), shell=False)
try: try:
make_non_block(self.parent_stdout_fd) make_non_block(self.lvm_shell.stdout)
make_non_block(self.parent_stderr_fd) make_non_block(self.lvm_shell.stderr)
# Close our copies of the child FDs there were created with the fork, we don't need them open.
os.close(lvm_fd)
os.close(child_stdin_fd)
os.close(child_stdout_fd)
os.close(child_stderr_fd)
# wait for the first prompt # wait for the first prompt
log_debug("waiting for first prompt...") errors = self._read_until_prompt(no_output=True)[2]
errors = self._read_response(no_output=True)[2]
if errors and len(errors): if errors and len(errors):
raise LvmBug(errors) raise RuntimeError(errors)
log_debug("lvm prompt read!!!")
except: except:
raise raise
finally: finally:
# These will get deleted when the FD count goes to zero, so we # These will get deleted when the FD count goes to zero so we
# can be sure to clean up correctly no matter how we finish # can be sure to clean up correctly no matter how we finish
os.unlink(tmp_file) os.unlink(tmp_file)
os.rmdir(tmp_dir) os.rmdir(tmp_dir)
def _get_last_log(self): def get_error_msg(self):
# Precondition, lock is held # We got an error, lets go fetch the error message
self._write_cmd('lastlog\n') self._write_cmd('lastlog\n')
report_json = self._read_response()[1]
return get_error_msg(report_json) # read everything from the STDOUT to the next prompt
stdout, report_json, stderr = self._read_until_prompt()
if 'log' in report_json:
error_msg = ""
# Walk the entire log array and build an error string
for log_entry in report_json['log']:
if log_entry['log_type'] == "error":
if error_msg:
error_msg += ', ' + log_entry['log_message']
else:
error_msg = log_entry['log_message']
return error_msg
return 'No error reason provided! (missing "log" section)'
def call_lvm(self, argv, debug=False): def call_lvm(self, argv, debug=False):
rc = 1 rc = 1
@ -220,94 +201,60 @@ class LVMShellProxy(object):
cmd += "\n" cmd += "\n"
# run the command by writing it to the shell's STDIN # run the command by writing it to the shell's STDIN
with self.shell_lock: self._write_cmd(cmd)
self._write_cmd(cmd)
# read everything from the STDOUT to the next prompt # read everything from the STDOUT to the next prompt
stdout, report_json, stderr = self._read_response() stdout, report_json, stderr = self._read_until_prompt()
# Parse the report to see what happened # Parse the report to see what happened
if 'log' in report_json: if 'log' in report_json:
ret_code = int(report_json['log'][-1:][0]['log_ret_code']) ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
# If we have an exported vg we get a log_ret_code == 5 when # If we have an exported vg we get a log_ret_code == 5 when
# we do a 'fullreport' # we do a 'fullreport'
# Note: 0 == error if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'): rc = 0
rc = 0 else:
else: error_msg = self.get_error_msg()
# Depending on where lvm fails the command, it may not have anything
# to report for "lastlog", so we need to check for a message in the
# report json too.
error_msg = self._get_last_log()
if error_msg is None:
error_msg = get_error_msg(report_json)
if error_msg is None:
error_msg = 'No error reason provided! (missing "log" section)'
if debug or rc != 0: if debug or rc != 0:
log_error(("CMD= %s" % cmd)) log_error(('CMD: %s' % cmd))
log_error(("EC= %d" % rc)) log_error(("EC = %d" % rc))
log_error(("ERROR_MSG=\n %s\n" % error_msg)) log_error(("ERROR_MSG=\n %s\n" % error_msg))
return rc, report_json, error_msg return rc, report_json, error_msg
def exit_shell(self): def exit_shell(self):
with self.shell_lock: try:
try: self._write_cmd('exit\n')
if self.lvm_shell is not None: except Exception as e:
self._write_cmd('exit\n') log_error(str(e))
self.lvm_shell.wait(1)
self.lvm_shell = None
except Exception as _e:
log_error("exit_shell: %s" % (str(_e)))
def __del__(self): def __del__(self):
# Note: When we are shutting down the daemon and the main process has already exited try:
# and this gets called we have a limited set of things we can do, like we cannot call self.lvm_shell.terminate()
# log_error as _common_log is None!!! except:
if self.lvm_shell is not None: pass
try:
self.lvm_shell.wait(1)
except subprocess.TimeoutExpired:
print("lvm shell child process did not exit as instructed, sending SIGTERM")
cfg.ignore_sigterm = True
self.lvm_shell.terminate()
child_exit_code = self.lvm_shell.wait(1)
print("lvm shell process exited with %d" % child_exit_code)
if __name__ == "__main__": if __name__ == "__main__":
print("USING LVM BINARY: %s " % cfg.LVM_CMD) shell = LVMShellProxy()
in_line = "start"
try: try:
if len(sys.argv) > 1 and sys.argv[1] == "bisect": while in_line:
shell = LVMShellProxy() in_line = input("lvm> ")
shell.exit_shell() if in_line:
else: start = time.time()
shell = LVMShellProxy() ret, out, err = shell.call_lvm(in_line.split())
in_line = "start" end = time.time()
try:
while in_line:
in_line = input("lvm> ")
if in_line:
if in_line == "exit":
shell.exit_shell()
sys.exit(0)
start = time.time()
ret, out, err = shell.call_lvm(in_line.split())
end = time.time()
print(("RC: %d" % ret)) print(("RC: %d" % ret))
print(("OUT:\n%s" % out)) print(("OUT:\n%s" % out))
print(("ERR:\n%s" % err)) print(("ERR:\n%s" % err))
print("Command = %f seconds" % (end - start)) print("Command = %f seconds" % (end - start))
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
except EOFError: except EOFError:
pass pass
except Exception as e: except Exception:
log_error("main process exiting on exception!\n%s" % extract_stack_trace(e)) traceback.print_exc(file=sys.stdout)
sys.exit(1)
sys.exit(0)

View File

@ -13,13 +13,14 @@ from collections import OrderedDict
import pprint as prettyprint import pprint as prettyprint
import os import os
import sys
from lvmdbusd import cmdhandler from lvmdbusd import cmdhandler
from lvmdbusd.utils import log_debug, log_error, lvm_column_key, LvmBug from lvmdbusd.utils import log_debug, log_error
class DataStore(object): class DataStore(object):
def __init__(self, vdo_support=False): def __init__(self, usejson=True, vdo_support=False):
self.pvs = {} self.pvs = {}
self.vgs = {} self.vgs = {}
self.lvs = {} self.lvs = {}
@ -34,9 +35,41 @@ class DataStore(object):
self.lvs_in_vgs = {} self.lvs_in_vgs = {}
self.pvs_in_vgs = {} self.pvs_in_vgs = {}
# self.refresh()
self.num_refreshes = 0 self.num_refreshes = 0
if usejson:
self.json = cmdhandler.supports_json()
else:
self.json = usejson
self.vdo_support = vdo_support self.vdo_support = vdo_support
@staticmethod
def _insert_record(table, key, record, allowed_multiple):
if key in table:
existing = table[key]
for rec_k, rec_v in record.items():
if rec_k in allowed_multiple:
# This column name allows us to store multiple value for
# each type
if not isinstance(existing[rec_k], list):
existing_value = existing[rec_k]
existing[rec_k] = [existing_value, rec_v]
else:
existing[rec_k].append(rec_v)
else:
# If something is not expected to have changing values
# lets ensure that
if existing[rec_k] != rec_v:
raise RuntimeError(
"existing[%s]=%s != %s" %
(rec_k, str(existing[rec_k]),
str(rec_v)))
else:
table[key] = record
@staticmethod @staticmethod
def _pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup): def _pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup):
for p in c_pvs.values(): for p in c_pvs.values():
@ -51,6 +84,22 @@ class DataStore(object):
# Lookup for translating between /dev/<name> and pv uuid # Lookup for translating between /dev/<name> and pv uuid
c_lookup[p['pv_name']] = p['pv_uuid'] c_lookup[p['pv_name']] = p['pv_uuid']
@staticmethod
def _parse_pvs(_pvs):
pvs = sorted(_pvs, key=lambda pk: pk['pv_name'])
c_pvs = OrderedDict()
c_lookup = {}
c_pvs_in_vgs = {}
for p in pvs:
DataStore._insert_record(
c_pvs, p['pv_uuid'], p,
['pvseg_start', 'pvseg_size', 'segtype'])
DataStore._pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup)
return c_pvs, c_lookup, c_pvs_in_vgs
@staticmethod @staticmethod
def _parse_pvs_json(_all): def _parse_pvs_json(_all):
@ -58,7 +107,7 @@ class DataStore(object):
c_lookup = {} c_lookup = {}
c_pvs_in_vgs = {} c_pvs_in_vgs = {}
# Each item in the report is a collection of information pertaining # Each item item in the report is a collection of information pertaining
# to the vg # to the vg
for r in _all['report']: for r in _all['report']:
tmp_pv = [] tmp_pv = []
@ -92,6 +141,28 @@ class DataStore(object):
return c_pvs, c_lookup, c_pvs_in_vgs return c_pvs, c_lookup, c_pvs_in_vgs
@staticmethod
def _parse_vgs(_vgs):
vgs = sorted(_vgs, key=lambda vk: vk['vg_uuid'])
c_vgs = OrderedDict()
c_lookup = {}
for i in vgs:
vg_name = i['vg_name']
# Lvm allows duplicate vg names. When this occurs, each subsequent
# matching VG name will be called vg_name:vg_uuid. Note: ':' is an
# invalid character for lvm VG names
if vg_name in c_lookup:
vg_name = "%s:%s" % (vg_name, i['vg_uuid'])
i['vg_name'] = vg_name
c_lookup[vg_name] = i['vg_uuid']
DataStore._insert_record(c_vgs, i['vg_uuid'], i, [])
return c_vgs, c_lookup
@staticmethod @staticmethod
def _parse_vgs_json(_all): def _parse_vgs_json(_all):
@ -156,12 +227,28 @@ class DataStore(object):
return c_lvs, c_lvs_in_vgs, c_lvs_hidden, c_lv_full_lookup return c_lvs, c_lvs_in_vgs, c_lvs_hidden, c_lv_full_lookup
@staticmethod
def _parse_lvs(_lvs):
lvs = sorted(_lvs, key=lambda vk: vk['lv_name'])
c_lvs = OrderedDict()
c_lv_full_lookup = OrderedDict()
for i in lvs:
full_name = "%s/%s" % (i['vg_name'], i['lv_name'])
c_lv_full_lookup[full_name] = i['lv_uuid']
DataStore._insert_record(
c_lvs, i['lv_uuid'], i,
['seg_pe_ranges', 'segtype'])
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
def _parse_lvs_json(self, _all): def _parse_lvs_json(self, _all):
c_lvs = OrderedDict() c_lvs = OrderedDict()
c_lv_full_lookup = {} c_lv_full_lookup = {}
# Each item in the report is a collection of information pertaining # Each item item in the report is a collection of information pertaining
# to the vg # to the vg
for r in _all['report']: for r in _all['report']:
# Get the lv data for this VG. # Get the lv data for this VG.
@ -309,12 +396,12 @@ class DataStore(object):
:param log Add debug log entry/exit messages :param log Add debug log entry/exit messages
:return: None :return: None
""" """
try: self.num_refreshes += 1
self.num_refreshes += 1 if log:
if log: log_debug("lvmdb - refresh entry")
log_debug("lvmdb - refresh entry")
# Grab everything first then parse it # Grab everything first then parse it
if self.json:
# Do a single lvm retrieve for everything in json # Do a single lvm retrieve for everything in json
a = cmdhandler.lvm_full_report_json() a = cmdhandler.lvm_full_report_json()
@ -322,25 +409,29 @@ class DataStore(object):
_vgs, _vgs_lookup = self._parse_vgs_json(a) _vgs, _vgs_lookup = self._parse_vgs_json(a)
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs_json(a) _lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs_json(a)
# Set all else:
self.pvs = _pvs _raw_pvs = cmdhandler.pv_retrieve_with_segs()
self.pv_path_to_uuid = _pvs_lookup _raw_vgs = cmdhandler.vg_retrieve(None)
self.vg_name_to_uuid = _vgs_lookup _raw_lvs = cmdhandler.lv_retrieve_with_segments()
self.lv_full_name_to_uuid = _lvs_lookup
self.vgs = _vgs _pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs(_raw_pvs)
self.lvs = _lvs _vgs, _vgs_lookup = self._parse_vgs(_raw_vgs)
self.lvs_in_vgs = _lvs_in_vgs _lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs(_raw_lvs)
self.pvs_in_vgs = _pvs_in_vgs
self.lvs_hidden = _lvs_hidden
# Create lookup table for which LV and segments are on each PV # Set all
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs() self.pvs = _pvs
except KeyError as ke: self.pv_path_to_uuid = _pvs_lookup
key = ke.args[0] self.vg_name_to_uuid = _vgs_lookup
if lvm_column_key(key): self.lv_full_name_to_uuid = _lvs_lookup
raise LvmBug("missing JSON key: '%s'" % key)
raise ke self.vgs = _vgs
self.lvs = _lvs
self.lvs_in_vgs = _lvs_in_vgs
self.pvs_in_vgs = _pvs_in_vgs
self.lvs_hidden = _lvs_hidden
# Create lookup table for which LV and segments are on each PV
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
if log: if log:
log_debug("lvmdb - refresh exit") log_debug("lvmdb - refresh exit")
@ -351,7 +442,7 @@ class DataStore(object):
else: else:
rc = [] rc = []
for s in pv_name: for s in pv_name:
# The user could be using a symlink instead of the actual # Ths user could be using a symlink instead of the actual
# block device, make sure we are using actual block device file # block device, make sure we are using actual block device file
# if the pv name isn't in the lookup # if the pv name isn't in the lookup
if s not in self.pv_path_to_uuid: if s not in self.pv_path_to_uuid:
@ -360,13 +451,10 @@ class DataStore(object):
return rc return rc
def pv_missing(self, pv_uuid): def pv_missing(self, pv_uuid):
# The uuid might not be a PV, default to false
if pv_uuid in self.pvs: if pv_uuid in self.pvs:
if self.pvs[pv_uuid]['pv_missing'] == '': if self.pvs[pv_uuid]['pv_missing'] == '':
return False return False
else: return True
return True
return False
def fetch_vgs(self, vg_name): def fetch_vgs(self, vg_name):
if not vg_name: if not vg_name:
@ -437,11 +525,15 @@ class DataStore(object):
if __name__ == "__main__": if __name__ == "__main__":
os.environ["LC_ALL"] = "C"
os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
pp = prettyprint.PrettyPrinter(indent=4) pp = prettyprint.PrettyPrinter(indent=4)
ds = DataStore() use_json = False
if len(sys.argv) != 1:
print(len(sys.argv))
use_json = True
ds = DataStore(use_json)
ds.refresh() ds.refresh()
print("PVS") print("PVS")

View File

@ -22,13 +22,14 @@ from . import lvmdb
from gi.repository import GLib from gi.repository import GLib
from .fetch import StateUpdate from .fetch import StateUpdate
from .manager import Manager from .manager import Manager
import traceback
import queue import queue
from . import udevwatch from . import udevwatch
from .utils import log_debug, log_error, log_msg, DebugMessages from .utils import log_debug, log_error
import argparse import argparse
import os import os
import sys import sys
from .cmdhandler import LvmFlightRecorder, supports_vdo, supports_json from .cmdhandler import LvmFlightRecorder, supports_vdo
from .request import RequestEntry from .request import RequestEntry
@ -41,7 +42,7 @@ def process_request():
while cfg.run.value != 0: while cfg.run.value != 0:
# noinspection PyBroadException # noinspection PyBroadException
try: try:
req = cfg.worker_q.get(True, cfg.G_LOOP_TMO) req = cfg.worker_q.get(True, 5)
log_debug( log_debug(
"Method start: %s with args %s (callback = %s)" % "Method start: %s with args %s (callback = %s)" %
(str(req.method), str(req.arguments), str(req.cb))) (str(req.method), str(req.arguments), str(req.cb)))
@ -49,15 +50,12 @@ def process_request():
log_debug("Method complete: %s" % str(req.method)) log_debug("Method complete: %s" % str(req.method))
except queue.Empty: except queue.Empty:
pass pass
except SystemExit: except Exception:
break st = traceback.format_exc()
except Exception as e:
st = utils.extract_stack_trace(e)
utils.log_error("process_request exception: \n%s" % st) utils.log_error("process_request exception: \n%s" % st)
log_debug("process_request thread exiting!")
def check_fr_size(value): def check_bb_size(value):
v = int(value) v = int(value)
if v < 0: if v < 0:
raise argparse.ArgumentTypeError( raise argparse.ArgumentTypeError(
@ -67,7 +65,7 @@ def check_fr_size(value):
def install_signal_handlers(): def install_signal_handlers():
# Because of the glib main loop stuff the python signal handler code is # Because of the glib main loop stuff the python signal handler code is
# apparently not usable, and we need to use the glib calls instead # apparently not usable and we need to use the glib calls instead
signal_add = None signal_add = None
if hasattr(GLib, 'unix_signal_add'): if hasattr(GLib, 'unix_signal_add'):
@ -79,13 +77,13 @@ def install_signal_handlers():
signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP, utils.handler, signal.SIGHUP) signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP, utils.handler, signal.SIGHUP)
signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, utils.handler, signal.SIGINT) signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, utils.handler, signal.SIGINT)
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR1, utils.handler, signal.SIGUSR1) signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR1, utils.handler, signal.SIGUSR1)
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR2, utils.handler, signal.SIGUSR2)
signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, utils.handler, signal.SIGTERM)
else: else:
log_error("GLib.unix_signal_[add|add_full] are NOT available!") log_error("GLib.unix_signal_[add|add_full] are NOT available!")
def process_args(): def main():
start = time.time()
# Add simple command line handling
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument( parser.add_argument(
"--udev", action='store_true', "--udev", action='store_true',
@ -106,137 +104,101 @@ def process_args():
default=False, default=False,
dest='use_lvm_shell') dest='use_lvm_shell')
parser.add_argument( parser.add_argument(
"--frsize", "--blackboxsize",
help="Size of the flight recorder (num. entries), 0 to disable (signal 12 to dump)", help="Size of the black box flight recorder, 0 to disable",
default=10, default=10,
type=check_fr_size, type=check_bb_size,
dest='fr_size') dest='bb_size')
args = parser.parse_args() use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
if not args.use_json: # Ensure that we get consistent output for parsing stdout/stderr
log_error("Daemon no longer supports lvm without JSON support, exiting!")
sys.exit(1)
else:
if not supports_json():
log_error("Un-supported version of LVM, daemon requires JSON output, exiting!")
sys.exit(1)
# Add udev watching
if args.use_udev:
# Make sure this msg ends up in the journal, so we know
log_msg('The --udev option is no longer supported,'
'the daemon always uses a combination of dbus notify from lvm tools and udev')
return args
def running_under_systemd():
""""
Checks to see if we are running under systemd, by checking daemon fd 0, 1
systemd sets stdin to /dev/null and 1 & 2 are a socket
"""
base = "/proc/self/fd"
stdout = os.readlink("%s/0" % base)
if stdout == "/dev/null":
stdout = os.readlink("%s/1" % base)
if "socket" in stdout:
return True
return False
def main():
start = time.time()
use_session = os.getenv('LVM_DBUSD_USE_SESSION', False)
# Ensure that we get consistent output for parsing stdout/stderr and that we
# are using the lvmdbusd profile.
os.environ["LC_ALL"] = "C" os.environ["LC_ALL"] = "C"
os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
# Indicator if we are running under systemd
cfg.systemd = running_under_systemd()
# Add simple command line handling
cfg.args = process_args()
cfg.args = parser.parse_args()
cfg.create_request_entry = RequestEntry cfg.create_request_entry = RequestEntry
# We create a flight recorder in cmdhandler too, but we replace it here # We create a flight recorder in cmdhandler too, but we replace it here
# as the user may be specifying a different size. The default one in # as the user may be specifying a different size. The default one in
# cmdhandler is for when we are running other code with a different main. # cmdhandler is for when we are running other code with a different main.
cfg.flightrecorder = LvmFlightRecorder(cfg.args.fr_size) cfg.blackbox = LvmFlightRecorder(cfg.args.bb_size)
# Create a circular buffer for debug logs if cfg.args.use_lvm_shell and not cfg.args.use_json:
cfg.debug = DebugMessages() log_error("You cannot specify --lvmshell and --nojson")
sys.exit(1)
log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
# We will dynamically add interfaces which support vdo if it # We will dynamically add interfaces which support vdo if it
# exists. # exists.
cfg.vdo_support = supports_vdo() cfg.vdo_support = supports_vdo()
if cfg.vdo_support and not cfg.args.use_json:
log_error("You cannot specify --nojson when lvm has VDO support")
sys.exit(1)
# List of threads that we start up # List of threads that we start up
thread_list = [] thread_list = []
install_signal_handlers() install_signal_handlers()
with utils.LockFile(cfg.LOCK_FILE): dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) dbus.mainloop.glib.threads_init()
dbus.mainloop.glib.threads_init()
cmdhandler.set_execution(cfg.args.use_lvm_shell) cmdhandler.set_execution(cfg.args.use_lvm_shell)
if use_session: if use_session:
cfg.bus = dbus.SessionBus() cfg.bus = dbus.SessionBus()
else: else:
cfg.bus = dbus.SystemBus() cfg.bus = dbus.SystemBus()
# The base name variable needs to exist for things to work. # The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
base_name = dbus.service.BusName(BUS_NAME, cfg.bus) base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
cfg.om = Lvm(BASE_OBJ_PATH) cfg.om = Lvm(BASE_OBJ_PATH)
cfg.om.register_object(Manager(MANAGER_OBJ_PATH)) cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
cfg.db = lvmdb.DataStore(vdo_support=cfg.vdo_support) cfg.db = lvmdb.DataStore(cfg.args.use_json, cfg.vdo_support)
# Using a thread to process requests, we cannot hang the dbus library # Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface # thread that is handling the dbus interface
thread_list.append( thread_list.append(
threading.Thread(target=process_request, name='process_request')) threading.Thread(target=process_request, name='process_request'))
# Have a single thread handling updating lvm and the dbus model, so we # Have a single thread handling updating lvm and the dbus model so we
# don't have multiple threads doing this as the same time # don't have multiple threads doing this as the same time
updater = StateUpdate() updater = StateUpdate()
thread_list.append(updater.thread) thread_list.append(updater.thread)
cfg.load = updater.load cfg.load = updater.load
cfg.loop = GLib.MainLoop() cfg.loop = GLib.MainLoop()
for thread in thread_list: for thread in thread_list:
thread.daemon = True thread.damon = True
thread.start() thread.start()
# In all cases we are going to monitor for udev until we get an # Add udev watching
# ExternalEvent. In the case where we get an external event and the user if cfg.args.use_udev:
# didn't specify --udev we will stop monitoring udev log_debug('Utilizing udev to trigger updates')
udevwatch.add()
end = time.time() # In all cases we are going to monitor for udev until we get an
log_debug( # ExternalEvent. In the case where we get an external event and the user
'Service ready! total time= %.4f, lvm time= %.4f count= %d' % # didn't specify --udev we will stop monitoring udev
(end - start, cmdhandler.total_time, cmdhandler.total_count), udevwatch.add()
'bg_black', 'fg_light_green')
try: end = time.time()
if cfg.run.value != 0: log_debug(
cfg.loop.run() 'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
udevwatch.remove() (end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
for thread in thread_list: try:
thread.join() if cfg.run.value != 0:
except KeyboardInterrupt: cfg.loop.run()
# If we are unable to register signal handler, we will end up here when udevwatch.remove()
# the service gets a ^C or a kill -2 <parent pid>
utils.handler(signal.SIGINT) for thread in thread_list:
thread.join()
except KeyboardInterrupt:
# If we are unable to register signal handler, we will end up here when
# the service gets a ^C or a kill -2 <parent pid>
utils.handler(signal.SIGINT)
return 0 return 0

View File

@ -137,8 +137,7 @@ class Manager(AutomatedProperties):
""" """
Dump the flight recorder to syslog Dump the flight recorder to syslog
""" """
cfg.debug.dump() cfg.blackbox.dump()
cfg.flightrecorder.dump()
@staticmethod @staticmethod
def _lookup_by_lvm_id(key): def _lookup_by_lvm_id(key):
@ -195,7 +194,6 @@ class Manager(AutomatedProperties):
def _external_event(command): def _external_event(command):
utils.log_debug("Processing _external_event= %s" % command, utils.log_debug("Processing _external_event= %s" % command,
'bg_black', 'fg_orange') 'bg_black', 'fg_orange')
cfg.got_external_event = True
cfg.load() cfg.load()
@dbus.service.method( @dbus.service.method(
@ -203,6 +201,14 @@ class Manager(AutomatedProperties):
in_signature='s', out_signature='i') in_signature='s', out_signature='i')
def ExternalEvent(self, command): def ExternalEvent(self, command):
utils.log_debug("ExternalEvent %s" % command) utils.log_debug("ExternalEvent %s" % command)
# If a user didn't explicitly specify udev, we will turn it off now.
if not cfg.args.use_udev:
if udevwatch.remove():
utils.log_debug("ExternalEvent received, disabling "
"udev monitoring")
# We are dependent on external events now to stay current!
cfg.got_external_event = True
r = RequestEntry( r = RequestEntry(
-1, Manager._external_event, (command,), None, None, False) -1, Manager._external_event, (command,), None, None, False)
cfg.worker_q.put(r) cfg.worker_q.put(r)

View File

@ -9,11 +9,12 @@
import sys import sys
import threading import threading
import traceback
import dbus import dbus
import os import os
import copy import copy
from . import cfg from . import cfg
from .utils import log_debug, log_error, extract_stack_trace from .utils import log_debug, pv_obj_path_generate, log_error
from .automatedproperties import AutomatedProperties from .automatedproperties import AutomatedProperties
@ -39,8 +40,8 @@ class ObjectManager(AutomatedProperties):
for k, v in list(obj._objects.items()): for k, v in list(obj._objects.items()):
path, props = v[0].emit_data() path, props = v[0].emit_data()
rc[path] = props rc[path] = props
except Exception as e: except Exception:
log_error("_get_managed_objects exception, bailing: \n%s" % extract_stack_trace(e)) traceback.print_exc(file=sys.stdout)
sys.exit(1) sys.exit(1)
return rc return rc
@ -52,6 +53,15 @@ class ObjectManager(AutomatedProperties):
(self, ), cb, cbe, False) (self, ), cb, cbe, False)
cfg.worker_q.put(r) cfg.worker_q.put(r)
def locked(self):
"""
If some external code need to run across a number of different
calls into ObjectManager while blocking others they can use this method
to lock others out.
:return:
"""
return ObjectManagerLock(self.rlock)
@dbus.service.signal( @dbus.service.signal(
dbus_interface="org.freedesktop.DBus.ObjectManager", dbus_interface="org.freedesktop.DBus.ObjectManager",
signature='oa{sa{sv}}') signature='oa{sa{sv}}')
@ -159,8 +169,8 @@ class ObjectManager(AutomatedProperties):
# print('Registering object path %s for %s' % # print('Registering object path %s for %s' %
# (path, dbus_object.lvm_id)) # (path, dbus_object.lvm_id))
# We want fast access to the object by a number of different ways, # We want fast access to the object by a number of different ways
# so we use multiple hashes with different keys # so we use multiple hashs with different keys
self._lookup_add(dbus_object, path, dbus_object.lvm_id, self._lookup_add(dbus_object, path, dbus_object.lvm_id,
dbus_object.Uuid) dbus_object.Uuid)
@ -209,7 +219,7 @@ class ObjectManager(AutomatedProperties):
def get_object_by_lvm_id(self, lvm_id): def get_object_by_lvm_id(self, lvm_id):
""" """
Given a lvm identifier, return the object registered for it Given an lvm identifier, return the object registered for it
:param lvm_id: The lvm identifier :param lvm_id: The lvm identifier
""" """
with self.rlock: with self.rlock:
@ -220,7 +230,7 @@ class ObjectManager(AutomatedProperties):
def get_object_path_by_lvm_id(self, lvm_id): def get_object_path_by_lvm_id(self, lvm_id):
""" """
Given a lvm identifier, return the object path for it Given an lvm identifier, return the object path for it
:param lvm_id: The lvm identifier :param lvm_id: The lvm identifier
:return: Object path or '/' if not found :return: Object path or '/' if not found
""" """
@ -272,12 +282,12 @@ class ObjectManager(AutomatedProperties):
For a given lvm asset return the dbus object path registered for it. For a given lvm asset return the dbus object path registered for it.
This method first looks up by uuid and then by lvm_id. You This method first looks up by uuid and then by lvm_id. You
can search by just one by setting uuid == lvm_id (uuid or lvm_id). can search by just one by setting uuid == lvm_id (uuid or lvm_id).
If the object is not found and path_create is not None, the If the object is not found and path_create is a not None, the
path_create function will be called to create a new object path and path_create function will be called to create a new object path and
register it with the object manager for the specified uuid & lvm_id. register it with the object manager for the specified uuid & lvm_id.
Note: If path create is not None, uuid and lvm_id cannot be equal Note: If path create is not None, uuid and lvm_id cannot be equal
:param uuid: The uuid for the lvm object we are searching for :param uuid: The uuid for the lvm object we are searching for
:param lvm_id: The lvm name (e.g. pv device path, vg name, lv full name) :param lvm_id: The lvm name (eg. pv device path, vg name, lv full name)
:param path_create: If not None, create the path using this function if :param path_create: If not None, create the path using this function if
we fail to find the object by uuid or lvm_id. we fail to find the object by uuid or lvm_id.
:returns None if lvm asset not found and path_create == None otherwise :returns None if lvm asset not found and path_create == None otherwise
@ -295,17 +305,18 @@ class ObjectManager(AutomatedProperties):
if uuid == lvm_id: if uuid == lvm_id:
path = self._id_lookup(lvm_id) path = self._id_lookup(lvm_id)
else: else:
# We have a uuid and an lvm_id we can do sanity checks to ensure # We have a uuid and a lvm_id we can do sanity checks to ensure
# that they are consistent # that they are consistent
# If a PV is missing its device path is '[unknown]' or some # If a PV is missing it's device path is '[unknown]' or some
# other text derivation of unknown. When we find that a PV is # other text derivation of unknown. When we find that a PV is
# missing we will clear out the lvm_id as it's not unique # missing we will clear out the lvm_id as it's likely not unique
# and thus not useful and harmful for lookups. # and thus not useful and potentially harmful for lookups.
if cfg.db.pv_missing(uuid): if path_create == pv_obj_path_generate and \
cfg.db.pv_missing(uuid):
lvm_id = None lvm_id = None
# Let's check for the uuid first # Lets check for the uuid first
path = self._id_lookup(uuid) path = self._id_lookup(uuid)
if path: if path:
# Ensure table lookups are correct # Ensure table lookups are correct
@ -326,3 +337,29 @@ class ObjectManager(AutomatedProperties):
# (uuid, lvm_id, str(path_create), path)) # (uuid, lvm_id, str(path_create), path))
return path return path
class ObjectManagerLock(object):
"""
The sole purpose of this class is to allow other code the ability to
lock the object manager using a `with` statement, eg.
with cfg.om.locked():
# Do stuff with object manager
This will ensure that the lock is always released (assuming this is done
correctly)
"""
def __init__(self, recursive_lock):
self._lock = recursive_lock
def __enter__(self):
# Acquire lock
self._lock.acquire()
# noinspection PyUnusedLocal
def __exit__(self, e_type, e_value, e_traceback):
# Release lock
self._lock.release()
self._lock = None

View File

@ -14,11 +14,11 @@ import dbus
from .cfg import PV_INTERFACE from .cfg import PV_INTERFACE
from . import cmdhandler from . import cmdhandler
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \ from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
lv_object_path_method, _handle_execute, lvm_column_key lv_object_path_method, _handle_execute
from .loader import common from .loader import common
from .request import RequestEntry from .request import RequestEntry
from .state import State from .state import State
from .utils import round_size, LvmBug from .utils import round_size
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
@ -28,23 +28,16 @@ def pvs_state_retrieve(selection, cache_refresh=True):
if cache_refresh: if cache_refresh:
cfg.db.refresh() cfg.db.refresh()
try: for p in cfg.db.fetch_pvs(selection):
for p in cfg.db.fetch_pvs(selection): rc.append(
rc.append( PvState(
PvState( p["pv_name"], p["pv_uuid"], p["pv_name"],
p["pv_name"], p["pv_uuid"], p["pv_name"], p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]),
p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]), n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]),
n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]), n(p["pv_mda_free"]), int(p["pv_ba_start"]),
n(p["pv_mda_free"]), int(p["pv_ba_start"]), n(p["pv_ba_size"]), n(p["pe_start"]),
n(p["pv_ba_size"]), n(p["pe_start"]), int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]), p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
except KeyError as ke:
# Sometimes lvm omits returning one of the keys we requested.
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
return rc return rc

View File

@ -7,13 +7,13 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import dbus
import threading import threading
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from gi.repository import GLib from gi.repository import GLib
from .job import Job from .job import Job
from . import cfg from . import cfg
from .utils import log_error, mt_async_call, extract_stack_trace import traceback
from .utils import log_error, mt_async_call
class RequestEntry(object): class RequestEntry(object):
@ -71,23 +71,13 @@ class RequestEntry(object):
try: try:
result = self.method(*self.arguments) result = self.method(*self.arguments)
self.register_result(result) self.register_result(result)
except SystemExit as se:
self.register_error(-1, str(se), se)
raise se
except dbus.exceptions.DBusException as dbe:
# This is an expected error path when something goes awry that
# we handled
self.register_error(-1, str(dbe), dbe)
except Exception as e: except Exception as e:
# Use the request entry to return the result as the client may # Use the request entry to return the result as the client may
# have gotten a job by the time we hit an error # have gotten a job by the time we hit an error
# Lets set the exception text as the error message and log the # Lets get the stacktrace and set that to the error message
# exception in the journal for figuring out what went wrong. st = traceback.format_exc()
cfg.debug.dump() cfg.blackbox.dump()
cfg.flightrecorder.dump() log_error("Exception returned to client: \n%s" % st)
tb = extract_stack_trace(e)
log_error("While processing %s: we encountered\n%s" % (str(self.method), tb))
log_error("Error returned to client: %s" % str(e))
self.register_error(-1, str(e), e) self.register_error(-1, str(e), e)
def is_done(self): def is_done(self):
@ -141,7 +131,7 @@ class RequestEntry(object):
mt_async_call(self.cb_error, error_exception) mt_async_call(self.cb_error, error_exception)
else: else:
# We have a job, and it's complete, indicate that it's done. # We have a job and it's complete, indicate that it's done.
self._job.Complete = True self._job.Complete = True
self._job = None self._job = None

View File

@ -52,30 +52,20 @@ def filter_event(action, device):
# when appropriate. # when appropriate.
refresh = False refresh = False
# Ignore everything but change
if action != 'change':
return
if 'ID_FS_TYPE' in device: if 'ID_FS_TYPE' in device:
fs_type_new = device['ID_FS_TYPE'] fs_type_new = device['ID_FS_TYPE']
if 'LVM' in fs_type_new: if 'LVM' in fs_type_new:
# If we get a lvm related udev event for a block device refresh = True
# we don't know about, it's either a pvcreate which we
# would handle with the dbus notification or something
# copied a pv signature onto a block device, this is
# required to catch the latter.
if not cfg.om.get_object_by_lvm_id(device['DEVNAME']):
refresh = True
elif fs_type_new == '': elif fs_type_new == '':
# Check to see if the device was one we knew about # Check to see if the device was one we knew about
if 'DEVNAME' in device: if 'DEVNAME' in device:
if cfg.om.get_object_by_lvm_id(device['DEVNAME']): found = cfg.om.get_object_by_lvm_id(device['DEVNAME'])
if found:
refresh = True refresh = True
else:
# This handles the wipefs -a path if 'DM_LV_NAME' in device:
if not refresh and 'DEVNAME' in device: refresh = True
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
refresh = True
if refresh: if refresh:
udev_add() udev_add()

View File

@ -10,14 +10,11 @@
import xml.etree.ElementTree as Et import xml.etree.ElementTree as Et
import sys import sys
import inspect import inspect
import collections import ctypes
import errno
import fcntl
import os import os
import stat
import string import string
import datetime import datetime
import tempfile from fcntl import fcntl, F_GETFL, F_SETFL
import dbus import dbus
from lvmdbusd import cfg from lvmdbusd import cfg
@ -89,7 +86,7 @@ def init_class_from_arguments(
nt = k nt = k
# If the current attribute has a value, but the incoming does # If the current attribute has a value, but the incoming does
# not, don't overwrite it. Otherwise, the default values on the # not, don't overwrite it. Otherwise the default values on the
# property decorator don't work as expected. # property decorator don't work as expected.
cur = getattr(obj_instance, nt, v) cur = getattr(obj_instance, nt, v)
@ -109,7 +106,7 @@ def init_class_from_arguments(
def get_properties(f): def get_properties(f):
""" """
Walks through an object instance, or it's parent class(es) and determines Walks through an object instance or it's parent class(es) and determines
which attributes are properties and if they were created to be used for which attributes are properties and if they were created to be used for
dbus. dbus.
:param f: Object to inspect :param f: Object to inspect
@ -193,7 +190,7 @@ def add_properties(xml, interface, props):
interface_element = c interface_element = c
break break
# Interface is not present, lets create it, so we have something to # Interface is not present, lets create it so we have something to
# attach the properties too # attach the properties too
if interface_element is None: if interface_element is None:
interface_element = Et.Element("interface", name=interface) interface_element = Et.Element("interface", name=interface)
@ -283,64 +280,25 @@ def parse_tags(tags):
return dbus.Array([], signature='s') return dbus.Array([], signature='s')
class DebugMessages(object): def _common_log(msg, *attributes):
cfg.stdout_lock.acquire()
tid = ctypes.CDLL('libc.so.6').syscall(186)
def __init__(self, size=5000): if STDOUT_TTY:
self.queue = collections.deque(maxlen=size)
self.lock = threading.RLock()
def add(self, message):
with self.lock:
self.queue.append(message)
def dump(self):
if cfg.args and not cfg.args.debug:
with self.lock:
if len(self.queue):
log_error("LVM dbus debug messages START last (%d max) messages" % self.queue.maxlen)
for m in self.queue:
print(m)
log_error("LVM dbus debug messages END")
self.queue.clear()
def _get_tid():
try:
# Only 3.8 and later have this
return threading.get_native_id()
except:
return -1
def _format_log_entry(msg):
tid = _get_tid()
if not cfg.systemd and STDOUT_TTY:
msg = "%s: %d:%d - %s" % \ msg = "%s: %d:%d - %s" % \
(datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"), (datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"),
os.getpid(), tid, msg) os.getpid(), tid, msg)
else: else:
if cfg.systemd: msg = "%d:%d - %s" % (os.getpid(), tid, msg)
# Systemd already puts the daemon pid in the log, we'll just add the tid
msg = "[%d]: %s" % (tid, msg)
else:
msg = "[%d:%d]: %s" % (os.getpid(), tid, msg)
return msg
def _common_log(msg, *attributes):
msg = _format_log_entry(msg)
cfg.stdout_lock.acquire()
if STDOUT_TTY and attributes: if STDOUT_TTY and attributes:
print(color(msg, *attributes)) print(color(msg, *attributes))
else: else:
print(msg) print(msg)
sys.stdout.flush()
cfg.stdout_lock.release() cfg.stdout_lock.release()
sys.stdout.flush()
# Serializes access to stdout to prevent interleaved output # Serializes access to stdout to prevent interleaved output
@ -349,19 +307,12 @@ def _common_log(msg, *attributes):
def log_debug(msg, *attributes): def log_debug(msg, *attributes):
if cfg.args and cfg.args.debug: if cfg.args and cfg.args.debug:
_common_log(msg, *attributes) _common_log(msg, *attributes)
else:
if cfg.debug:
cfg.debug.add(_format_log_entry(msg))
def log_error(msg, *attributes): def log_error(msg, *attributes):
_common_log(msg, *attributes) _common_log(msg, *attributes)
def log_msg(msg, *attributes):
_common_log(msg, *attributes)
def dump_threads_stackframe(): def dump_threads_stackframe():
ident_to_name = {} ident_to_name = {}
@ -389,32 +340,15 @@ def dump_threads_stackframe():
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
def handler(signum): def handler(signum):
try: try:
# signal 10
if signum == signal.SIGUSR1: if signum == signal.SIGUSR1:
cfg.debug.dump()
dump_threads_stackframe() dump_threads_stackframe()
# signal 12
elif signum == signal.SIGUSR2:
cfg.debug.dump()
cfg.flightrecorder.dump()
else: else:
# If we are getting a SIGTERM, and we sent one to the lvm shell we
# will ignore this and keep running.
if signum == signal.SIGTERM and cfg.ignore_sigterm:
# Clear the flag, so we will exit on SIGTERM if we didn't
# send it.
cfg.ignore_sigterm = False
return True
# If lvm shell is in use, tell it to exit
if cfg.SHELL_IN_USE is not None:
cfg.SHELL_IN_USE.exit_shell()
cfg.run.value = 0 cfg.run.value = 0
log_error('Exiting daemon with signal %d' % signum) log_debug('Exiting daemon with signal %d' % signum)
if cfg.loop is not None: if cfg.loop is not None:
cfg.loop.quit() cfg.loop.quit()
except BaseException as be: except:
st = extract_stack_trace(be) st = traceback.format_exc()
log_error("signal handler: exception (logged, not reported!) \n %s" % st) log_error("signal handler: exception (logged, not reported!) \n %s" % st)
# It's important we report that we handled the exception for the exception # It's important we report that we handled the exception for the exception
@ -543,7 +477,7 @@ def round_size(size_bytes):
return size_bytes + bs - remainder return size_bytes + bs - remainder
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_/%' _ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_\/%'
_ALLOWABLE_CH_SET = set(_ALLOWABLE_CH) _ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+' _ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
@ -638,23 +572,6 @@ def validate_tag(interface, tag):
% (tag, _ALLOWABLE_TAG_CH)) % (tag, _ALLOWABLE_TAG_CH))
def add_config_option(cmdline, key, value):
if 'help' in cmdline:
return cmdline
if key in cmdline:
for i, arg in enumerate(cmdline):
if arg == key:
if len(cmdline) <= i + 1:
raise dbus.exceptions.DBusException("Missing value for --config option.")
cmdline[i + 1] += " %s" % value
break
else:
cmdline.extend([key, value])
return cmdline
def add_no_notify(cmdline): def add_no_notify(cmdline):
""" """
Given a command line to execute we will see if `--config` is present, if it Given a command line to execute we will see if `--config` is present, if it
@ -666,18 +583,27 @@ def add_no_notify(cmdline):
:rtype: list :rtype: list
""" """
# Only after we have seen an external event will we disable lvm from sending # Only after we have seen an external event will be disable lvm from sending
# us one when we call lvm # us one when we call lvm
rv = cmdline
if cfg.got_external_event: if cfg.got_external_event:
rv = add_config_option(rv, "--config", "global/notify_dbus=0") if 'help' in cmdline:
return cmdline
return rv if '--config' in cmdline:
for i, arg in enumerate(cmdline):
if arg == '--config':
if len(cmdline) <= i+1:
raise dbus.exceptions.DBusException("Missing value for --config option.")
cmdline[i+1] += " global/notify_dbus=0"
break
else:
cmdline.extend(['--config', 'global/notify_dbus=0'])
return cmdline
# The methods below which start with mt_* are used to execute the desired code # The methods below which start with mt_* are used to execute the desired code
# on the main thread of execution to alleviate any issues the dbus-python # on the the main thread of execution to alleviate any issues the dbus-python
# library with regard to multithreaded access. Essentially, we are trying to # library with regards to multi-threaded access. Essentially, we are trying to
# ensure all dbus library interaction is done from the same thread! # ensure all dbus library interaction is done from the same thread!
@ -691,8 +617,9 @@ def _async_handler(call_back, parameters):
call_back(*parameters) call_back(*parameters)
else: else:
call_back() call_back()
except BaseException as be: except:
log_error("mt_async_call: exception (logged, not reported!) \n %s" % extract_stack_trace(be)) st = traceback.format_exc()
log_error("mt_async_call: exception (logged, not reported!) \n %s" % st)
# Execute the function on the main thread with the provided parameters, do # Execute the function on the main thread with the provided parameters, do
@ -742,6 +669,9 @@ class MThreadRunner(object):
self.rc = self.f() self.rc = self.f()
except BaseException as be: except BaseException as be:
self.exception = be self.exception = be
st = traceback.format_exc()
log_error("MThreadRunner: exception \n %s" % st)
log_error("Exception will be raised in calling thread!")
def _remove_objects(dbus_objects_rm): def _remove_objects(dbus_objects_rm):
@ -756,8 +686,8 @@ def mt_remove_dbus_objects(objs):
# Make stream non-blocking # Make stream non-blocking
def make_non_block(stream): def make_non_block(stream):
flags = fcntl.fcntl(stream, fcntl.F_GETFL) flags = fcntl(stream, F_GETFL)
fcntl.fcntl(stream, fcntl.F_SETFL, flags | os.O_NONBLOCK) fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
def read_decoded(stream): def read_decoded(stream):
@ -765,128 +695,3 @@ def read_decoded(stream):
if tmp: if tmp:
return tmp.decode("utf-8") return tmp.decode("utf-8")
return '' return ''
class LockFile(object):
"""
Simple lock file class
Based on Pg.1144 "The Linux Programming Interface" by Michael Kerrisk
"""
def __init__(self, lock_file):
self.fd = 0
self.lock_file = lock_file
def __enter__(self):
try:
os.makedirs(os.path.dirname(self.lock_file), exist_ok=True)
self.fd = os.open(self.lock_file, os.O_CREAT | os.O_RDWR, stat.S_IRUSR | stat.S_IWUSR)
# Get and set the close on exec and lock the file
flags = fcntl.fcntl(self.fd, fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(self.fd, fcntl.F_SETFL, flags)
fcntl.lockf(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except OSError as e:
if e.errno == errno.EAGAIN:
log_error("Daemon already running, exiting!")
else:
log_error("Error during creation of lock file(%s): errno(%d), exiting!" % (self.lock_file, e.errno))
sys.exit(114)
def __exit__(self, _type, _value, _traceback):
os.close(self.fd)
def extract_stack_trace(exception):
return ''.join(traceback.format_exception(None, exception, exception.__traceback__))
def lvm_column_key(key):
# Check LV
if key.startswith("lv_") or key.startswith("vg_") or key.startswith("pool_") or \
key.endswith("_percent") or key.startswith("move_") or key.startswith("vdo_") or \
key in ["origin_uuid", "segtype", "origin", "data_lv", "metadata_lv"]:
return True
# Check VG
if key.startswith("vg_") or key.startswith("lv_") or key.startswith("pv_") or \
key in ["max_lv", "max_pv", "snap_count"]:
return True
# Check PV
if key.startswith("pv") or key.startswith("vg") or (key in ['dev_size', 'pe_start']):
return True
return False
class LvmBug(RuntimeError):
"""
Things that are clearly a bug with lvm itself.
"""
def __init__(self, msg):
super().__init__(msg)
def __str__(self):
return "lvm bug encountered: %s" % ' '.join(self.args)
class LvmDebugData:
def __init__(self, do_collection):
self.fd = -1
self.fn = None
self.collect = do_collection
if self.collect:
log_msg("Collecting lvm debug data!")
def _remove_file(self):
if self.fn is not None:
os.unlink(self.fn)
self.fn = None
def _close_fd(self):
if self.fd != -1:
os.close(self.fd)
self.fd = -1
def setup(self):
# Create a secure filename
if self.collect:
self.fd, self.fn = tempfile.mkstemp(suffix=".log", prefix="lvmdbusd.lvm.debug.")
return self.fn
return None
def lvm_complete(self):
# Remove the file ASAP, so we decrease our odds of leaving it
# around if the daemon gets killed by a signal -9
self._remove_file()
def dump(self):
# Read the file and log it to log_err
if self.fd != -1:
# How big could the verbose debug get?
debug = os.read(self.fd, 1024*1024*5)
debug_txt = debug.decode("utf-8")
for line in debug_txt.split("\n"):
log_error("lvm debug >>> %s" % line)
self._close_fd()
# In case lvm_complete doesn't get called.
self._remove_file()
def complete(self):
self._close_fd()
# In case lvm_complete doesn't get called.
self._remove_file()
def get_error_msg(report_json):
# Get the error message from the returned JSON
if 'log' in report_json:
error_msg = ""
# Walk the entire log array and build an error string
for log_entry in report_json['log']:
if log_entry['log_type'] == "error":
if error_msg:
error_msg += ', ' + log_entry['log_message']
else:
error_msg = log_entry['log_message']
return error_msg
return None

View File

@ -20,7 +20,7 @@ from .request import RequestEntry
from .loader import common from .loader import common
from .state import State from .state import State
from . import background from . import background
from .utils import round_size, mt_remove_dbus_objects, LvmBug, lvm_column_key from .utils import round_size, mt_remove_dbus_objects
from .job import JobState from .job import JobState
@ -31,24 +31,17 @@ def vgs_state_retrieve(selection, cache_refresh=True):
if cache_refresh: if cache_refresh:
cfg.db.refresh() cfg.db.refresh()
try: for v in cfg.db.fetch_vgs(selection):
for v in cfg.db.fetch_vgs(selection): rc.append(
rc.append( VgState(
VgState( v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']), n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']), n(v['vg_extent_count']), n(v['vg_free_count']),
n(v['vg_extent_count']), n(v['vg_free_count']), v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
v['vg_profile'], n(v['max_lv']), n(v['max_pv']), n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
n(v['pv_count']), n(v['lv_count']), n(v['snap_count']), n(v['vg_seqno']), n(v['vg_mda_count']),
n(v['vg_seqno']), n(v['vg_mda_count']), n(v['vg_mda_free']), n(v['vg_mda_size']),
n(v['vg_mda_free']), n(v['vg_mda_size']), n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
except KeyError as ke:
# Sometimes lvm omits returning one of the keys we requested.
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
return rc return rc
@ -151,7 +144,6 @@ class Vg(AutomatedProperties):
_AllocNormal_meta = ('b', VG_INTERFACE) _AllocNormal_meta = ('b', VG_INTERFACE)
_AllocAnywhere_meta = ('b', VG_INTERFACE) _AllocAnywhere_meta = ('b', VG_INTERFACE)
_Clustered_meta = ('b', VG_INTERFACE) _Clustered_meta = ('b', VG_INTERFACE)
_Shared_meta = ('b', VG_INTERFACE)
_Name_meta = ('s', VG_INTERFACE) _Name_meta = ('s', VG_INTERFACE)
# noinspection PyUnusedLocal,PyPep8Naming # noinspection PyUnusedLocal,PyPep8Naming
@ -786,10 +778,6 @@ class Vg(AutomatedProperties):
def Clustered(self): def Clustered(self):
return self._attribute(5, 'c') return self._attribute(5, 'c')
@property
def Shared(self):
return self._attribute(5, 's')
class VgVdo(Vg): class VgVdo(Vg):

View File

@ -15,60 +15,61 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
top_builddir = @top_builddir@ top_builddir = @top_builddir@
USE_SD_NOTIFY=yes
SOURCES = lvmlockd-core.c SOURCES = lvmlockd-core.c
SOURCES2 = lvmlockctl.c
TARGETS = lvmlockd lvmlockctl
include $(top_builddir)/make.tmpl
ifeq ("@BUILD_LOCKDSANLOCK@", "yes") ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
SOURCES += lvmlockd-sanlock.c SOURCES += lvmlockd-sanlock.c
CFLAGS += $(LIBSANLOCKCLIENT_CFLAGS) LOCK_LIBS += -lsanlock_client
LOCK_LIBS += $(LIBSANLOCKCLIENT_LIBS)
endif endif
ifeq ("@BUILD_LOCKDDLM@", "yes") ifeq ("@BUILD_LOCKDDLM@", "yes")
SOURCES += lvmlockd-dlm.c SOURCES += lvmlockd-dlm.c
CFLAGS += $(LIBDLM) $(LIBDLMCONTROL_CFLAGS) LOCK_LIBS += -ldlm_lt
# LOCK_LIBS += $(LIBDLM_LIBS) $(LIBDLMCONTROL_LIBS) LOCK_LIBS += -ldlmcontrol
LOCK_LIBS += -ldlm_lt $(LIBDLMCONTROL_LIBS)
endif endif
ifeq ("@BUILD_LOCKDIDM@", "yes") ifeq ("@BUILD_LOCKDIDM@", "yes")
SOURCES += lvmlockd-idm.c SOURCES += lvmlockd-idm.c
LOCK_LIBS += $(LIBSEAGATEILM_LIBS) $(BLKID_LIBS) LOCK_LIBS += -lseagate_ilm -lblkid
endif endif
SOURCES2 = lvmlockctl.c
TARGETS = lvmlockd lvmlockctl
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
CFLOW_TARGET = lvmlockd CFLOW_TARGET = lvmlockd
.PHONY: install_lvmlockd install_lvmlockctl .PHONY: install_lvmlockd install_lvmlockctl
include $(top_builddir)/make.tmpl
CFLAGS += $(EXTRA_EXEC_CFLAGS) CFLAGS += $(EXTRA_EXEC_CFLAGS)
INCLUDES += -I$(top_srcdir)/libdaemon/server INCLUDES += -I$(top_srcdir)/libdaemon/server
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS) LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
ifeq ("@SD_NOTIFY_SUPPORT@", "yes") ifeq ($(USE_SD_NOTIFY),yes)
CFLAGS += $(LIBSYSTEMD_CFLAGS) CFLAGS += $(shell pkg-config --cflags libsystemd) -DUSE_SD_NOTIFY
LIBS += $(LIBSYSTEMD_LIBS) LIBS += $(shell pkg-config --libs libsystemd)
endif endif
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS) lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
$(SHOW) " [CC] $@" @echo " [CC] $@"
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LOCK_LIBS) $(LIBS) $(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LOCK_LIBS) $(LIBS)
lvmlockctl: lvmlockctl.o $(INTERNAL_LIBS) lvmlockctl: lvmlockctl.o $(INTERNAL_LIBS)
$(SHOW) " [CC] $@" @echo " [CC] $@"
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
install_lvmlockd: lvmlockd install_lvmlockd: lvmlockd
$(SHOW) " [INSTALL] $<" @echo " [INSTALL] $<"
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F) $(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
install_lvmlockctl: lvmlockctl install_lvmlockctl: lvmlockctl
$(SHOW) " [INSTALL] $<" @echo " [INSTALL] $<"
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F) $(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
install_lvm2: install_lvmlockd install_lvmlockctl install_lvm2: install_lvmlockd install_lvmlockctl

View File

@ -38,7 +38,7 @@ static int stop_lockspaces = 0;
static char *arg_vg_name = NULL; static char *arg_vg_name = NULL;
#define DUMP_SOCKET_NAME "lvmlockd-dump.sock" #define DUMP_SOCKET_NAME "lvmlockd-dump.sock"
#define DUMP_BUF_SIZE (4 * 1024 * 1024) #define DUMP_BUF_SIZE (1024 * 1024)
static char dump_buf[DUMP_BUF_SIZE+1]; static char dump_buf[DUMP_BUF_SIZE+1];
static int dump_len; static int dump_len;
static struct sockaddr_un dump_addr; static struct sockaddr_un dump_addr;
@ -67,160 +67,6 @@ do { \
syslog(LOG_WARNING, fmt, ##args); \ syslog(LOG_WARNING, fmt, ##args); \
} while (0) } while (0)
/*
* Like sscanf, but requires buffer size to be specified
* for storing scanned strings, e.g.
*
* szscanf("%s", sizeof(buf), buf);
*
* Up to size-1 input bytes will be copied into buf.
* A null byte will be written to buf following the
* last copied byte. When nothing is copied to buf,
* no terminating null byte is written.
*
* If an input string matching %s is too long for the
* specified buffer size, the characters that would have
* been copied are ignored.
*
* Only recognizes: %d, %u, %s.
*/
static int szscanf(const char *input, const char *format, ...)
{
va_list args;
const char *fm;
const char *in;
int matched = 0;
int n;
va_start(args, format);
fm = format;
in = input;
while (*fm != '\0') {
/*
* format is a string containing:
* 1. %d matching int from input
* %u matching unsigned int from input
* %s matching non-whitespace characters from input
* 2. whitespace chars matching zero or more whitespace
* characters from input
* 3. non-whitespace chars matching the same input chars
*/
if (*fm == '%') {
/*
* case 1: %u, %d, or %s
*/
/* advance past '%' character, to look for 'u', 'd' or 's' */
fm++;
if (*fm == 'd') {
/*
* read an int (%d)
*/
int *dest = va_arg(args, int *);
if (sscanf(in, "%d%n", dest, &n) == 1) {
in += n;
matched++;
} else {
/* matching failure: no input int */
break;
}
} else if (*fm == 'u') {
/*
* read an unsigned int (%u)
*/
unsigned int *dest = va_arg(args, unsigned int *);
if (sscanf(in, "%u%n", dest, &n) == 1) {
in += n;
matched++;
} else {
/* matching failure: no input unsigned int */
break;
}
} else if (*fm == 's') {
/*
* read a string (%s) into dest buffer with dest_size
* copy up to dest_size-1 characters into dest buffer
* write null byte into dest buffer following the last
* character copied. When dest_size-1 bytes are copied,
* the null byte is written into the final byte of the
* dest buffer. input bytes that would have been copied
* but did not fit in the dest buffer are skipped.
*/
size_t dest_size = va_arg(args, size_t);
char *dest = va_arg(args, char *);
char *out = dest;
/* don't copy leading input whitespace to dest */
while (isspace((unsigned char)*in))
in++;
/* copy non-whitespace characters from input to dest */
n = 0;
while (*in != '\0' && !isspace((unsigned char)*in) && (n < (int)dest_size-1)) {
*out = *in;
out++;
in++;
n++;
}
if (n) {
dest[n] = '\0';
matched++;
} else {
/* matching failure: no input string chars */
break;
}
/* ignore input bytes that would have been copied but didn't fit */
while (*in != '\0' && !isspace((unsigned char)*in))
in++;
} else {
/* unsupported format specifier */
matched = -1;
break;
}
/* advance past 'd', 'u', or 's' character */
fm++;
} else if (isspace((unsigned char)*fm)) {
/*
* case 2: format whitespace skips zero or more input
* whitespace characters
*/
while (isspace((unsigned char)*in))
in++;
/* advance past whitespace character */
fm++;
} else if (*fm == *in) {
/*
* case 3: literal character match between format and input
*/
fm++;
in++;
} else {
/*
* matching failure: format and input don't match
*/
break;
}
}
va_end(args);
return matched;
}
#define MAX_LINE 512 #define MAX_LINE 512
/* copied from lvmlockd-internal.h */ /* copied from lvmlockd-internal.h */
@ -251,11 +97,8 @@ static void save_client_info(char *line)
uint32_t client_id = 0; uint32_t client_id = 0;
char name[MAX_NAME+1] = { 0 }; char name[MAX_NAME+1] = { 0 };
/* info=client pid=%u fd=%d pi=%d id=%u name=%s */ (void) sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
&pid, &fd, &pi, &client_id, name);
if (szscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
&pid, &fd, &pi, &client_id, sizeof(name), name) < 0)
return;
clients[num_clients].client_id = client_id; clients[num_clients].client_id = client_id;
clients[num_clients].pid = pid; clients[num_clients].pid = pid;
@ -283,26 +126,20 @@ static void format_info_ls(char *line)
char ls_name[MAX_NAME+1] = { 0 }; char ls_name[MAX_NAME+1] = { 0 };
char vg_name[MAX_NAME+1] = { 0 }; char vg_name[MAX_NAME+1] = { 0 };
char vg_uuid[MAX_NAME+1] = { 0 }; char vg_uuid[MAX_NAME+1] = { 0 };
char vg_args[MAX_ARGS+1] = { 0 }; char vg_sysid[MAX_NAME+1] = { 0 };
char lm_type[MAX_NAME+1] = { 0 }; char lock_args[MAX_ARGS+1] = { 0 };
char lock_type[MAX_NAME+1] = { 0 };
/* info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_args=%s lm_type=%s */ (void) sscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_sysid=%s vg_args=%s lm_type=%s",
ls_name, vg_name, vg_uuid, vg_sysid, lock_args, lock_type);
if (szscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_args=%s lm_type=%s",
sizeof(ls_name), ls_name,
sizeof(vg_name), vg_name,
sizeof(vg_uuid), vg_uuid,
sizeof(vg_args), vg_args,
sizeof(lm_type), lm_type) < 0)
return;
if (!first_ls) if (!first_ls)
printf("\n"); printf("\n");
first_ls = 0; first_ls = 0;
printf("VG %s lock_type=%s %s\n", vg_name, lm_type, vg_uuid); printf("VG %s lock_type=%s %s\n", vg_name, lock_type, vg_uuid);
printf("LS %s %s\n", lm_type, ls_name); printf("LS %s %s\n", lock_type, ls_name);
} }
static void format_info_ls_action(char *line) static void format_info_ls_action(char *line)
@ -314,14 +151,8 @@ static void format_info_ls_action(char *line)
uint32_t pid = 0; uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 }; char cl_name[MAX_NAME+1] = { 0 };
/* info=ls_action client_id=%u flags=%s version=%u op=%s rt=%s mode=%s lm_type=%s result=%d lm_rv=%d */ (void) sscanf(line, "info=ls_action client_id=%u %s %s op=%s",
&client_id, flags, version, op);
if (szscanf(line, "info=ls_action client_id=%u flags=%s version=%s op=%s",
&client_id,
sizeof(flags), flags,
sizeof(version), version,
sizeof(op), op) < 0)
return;
find_client_info(client_id, &pid, cl_name); find_client_info(client_id, &pid, cl_name);
@ -333,18 +164,11 @@ static void format_info_r(char *line, char *r_name_out, char *r_type_out)
char r_name[MAX_NAME+1] = { 0 }; char r_name[MAX_NAME+1] = { 0 };
char r_type[4] = { 0 }; char r_type[4] = { 0 };
char mode[4] = { 0 }; char mode[4] = { 0 };
int sh_count = 0; char sh_count[MAX_NAME+1] = { 0 };
unsigned int ver = 0; uint32_t ver = 0;
/* info=r name=%s type=%s mode=%s sh_count=%d version=%s */ (void) sscanf(line, "info=r name=%s type=%s mode=%s %s version=%u",
r_name, r_type, mode, sh_count, &ver);
if (szscanf(line, "info=r name=%s type=%s mode=%s sh_count=%d version=%u",
sizeof(r_name), r_name,
sizeof(r_type), r_type,
sizeof(mode), mode,
&sh_count,
&ver) < 0)
return;
strcpy(r_name_out, r_name); strcpy(r_name_out, r_name);
strcpy(r_type_out, r_type); strcpy(r_type_out, r_type);
@ -369,8 +193,8 @@ static void format_info_r(char *line, char *r_name_out, char *r_type_out)
static void format_info_lk(char *line, char *r_name, char *r_type) static void format_info_lk(char *line, char *r_name, char *r_type)
{ {
char mode[4] = { 0 }; char mode[4] = { 0 };
char flags[MAX_NAME+1] = { 0 };
uint32_t ver = 0; uint32_t ver = 0;
char flags[MAX_NAME+1] = { 0 };
uint32_t client_id = 0; uint32_t client_id = 0;
uint32_t pid = 0; uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 }; char cl_name[MAX_NAME+1] = { 0 };
@ -381,14 +205,8 @@ static void format_info_lk(char *line, char *r_name, char *r_type)
return; return;
} }
/* info=lk mode=%s version=%s flags=%s client_id=%u */ (void) sscanf(line, "info=lk mode=%s version=%u %s client_id=%u",
mode, &ver, flags, &client_id);
if (szscanf(line, "info=lk mode=%s version=%u flags=%s client_id=%u",
sizeof(mode), mode,
&ver,
sizeof(flags), flags,
&client_id) < 0)
return;
find_client_info(client_id, &pid, cl_name); find_client_info(client_id, &pid, cl_name);
@ -411,9 +229,9 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
char op[MAX_NAME+1] = { 0 }; char op[MAX_NAME+1] = { 0 };
char rt[4] = { 0 }; char rt[4] = { 0 };
char mode[4] = { 0 }; char mode[4] = { 0 };
char lm_type[MAX_NAME+1] = { 0 }; char lm[MAX_NAME+1] = { 0 };
int result = 0; char result[MAX_NAME+1] = { 0 };
int lm_rv = 0; char lm_rv[MAX_NAME+1] = { 0 };
uint32_t pid = 0; uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 }; char cl_name[MAX_NAME+1] = { 0 };
@ -423,19 +241,8 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
return; return;
} }
/* info=r_action client_id=%u flags=%s version=%s op=%s rt=%s mode=%s lm_type=%s result=%d lm_rv=%d */ (void) sscanf(line, "info=r_action client_id=%u %s %s op=%s rt=%s mode=%s %s %s %s",
&client_id, flags, version, op, rt, mode, lm, result, lm_rv);
if (szscanf(line, "info=r_action client_id=%u flags=%s version=%s op=%s rt=%s mode=%s lm_type=%s result=%d lm_rv=%d",
&client_id,
sizeof(flags), flags,
sizeof(version), version,
sizeof(op), op,
sizeof(rt), rt,
sizeof(mode), mode,
sizeof(lm_type), lm_type,
&result,
&lm_rv) < 0)
return;
find_client_info(client_id, &pid, cl_name); find_client_info(client_id, &pid, cl_name);
@ -457,19 +264,19 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
static void format_info_line(char *line, char *r_name, char *r_type) static void format_info_line(char *line, char *r_name, char *r_type)
{ {
if (!strncmp(line, "info=structs ", sizeof("info=structs ") - 1)) { if (!strncmp(line, "info=structs ", strlen("info=structs "))) {
/* only print this in the raw info dump */ /* only print this in the raw info dump */
} else if (!strncmp(line, "info=client ", sizeof("info=client ") - 1)) { } else if (!strncmp(line, "info=client ", strlen("info=client "))) {
save_client_info(line); save_client_info(line);
} else if (!strncmp(line, "info=ls ", sizeof("info=ls ") - 1)) { } else if (!strncmp(line, "info=ls ", strlen("info=ls "))) {
format_info_ls(line); format_info_ls(line);
} else if (!strncmp(line, "info=ls_action ", sizeof("info=ls_action ") - 1)) { } else if (!strncmp(line, "info=ls_action ", strlen("info=ls_action "))) {
format_info_ls_action(line); format_info_ls_action(line);
} else if (!strncmp(line, "info=r ", sizeof("info=r ") - 1)) { } else if (!strncmp(line, "info=r ", strlen("info=r "))) {
/* /*
* r_name/r_type are reset when a new resource is found. * r_name/r_type are reset when a new resource is found.
* They are reused for the lock and action lines that * They are reused for the lock and action lines that
@ -479,11 +286,11 @@ static void format_info_line(char *line, char *r_name, char *r_type)
memset(r_type, 0, MAX_NAME+1); memset(r_type, 0, MAX_NAME+1);
format_info_r(line, r_name, r_type); format_info_r(line, r_name, r_type);
} else if (!strncmp(line, "info=lk ", sizeof("info=lk ") - 1)) { } else if (!strncmp(line, "info=lk ", strlen("info=lk "))) {
/* will use info from previous r */ /* will use info from previous r */
format_info_lk(line, r_name, r_type); format_info_lk(line, r_name, r_type);
} else if (!strncmp(line, "info=r_action ", sizeof("info=r_action ") - 1)) { } else if (!strncmp(line, "info=r_action ", strlen("info=r_action "))) {
/* will use info from previous r */ /* will use info from previous r */
format_info_r_action(line, r_name, r_type); format_info_r_action(line, r_name, r_type);
} else { } else {
@ -1133,7 +940,7 @@ static int read_options(int argc, char *argv[])
int option_index = 0; int option_index = 0;
int c; int c;
static const struct option _long_options[] = { static struct option long_options[] = {
{"help", no_argument, 0, 'h' }, {"help", no_argument, 0, 'h' },
{"quit", no_argument, 0, 'q' }, {"quit", no_argument, 0, 'q' },
{"info", no_argument, 0, 'i' }, {"info", no_argument, 0, 'i' },
@ -1155,7 +962,7 @@ static int read_options(int argc, char *argv[])
} }
while (1) { while (1) {
c = getopt_long(argc, argv, "hqidE:D:w:k:r:Se", _long_options, &option_index); c = getopt_long(argc, argv, "hqidE:D:w:k:r:Se", long_options, &option_index);
if (c == -1) if (c == -1)
break; break;

View File

@ -16,12 +16,9 @@
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket" #define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
#define LVMLOCKD_ADOPT_FILE DEFAULT_RUN_DIR "/lvmlockd.adopt" #define LVMLOCKD_ADOPT_FILE DEFAULT_RUN_DIR "/lvmlockd.adopt"
#define LVMLOCKD_USE_SANLOCK_LVB 0
/* Wrappers to open/close connection */ /* Wrappers to open/close connection */
static inline __attribute__((always_inline)) static inline daemon_handle lvmlockd_open(const char *sock)
daemon_handle lvmlockd_open(const char *sock)
{ {
daemon_info lvmlockd_info = { daemon_info lvmlockd_info = {
.path = "lvmlockd", .path = "lvmlockd",
@ -54,10 +51,5 @@ static inline void lvmlockd_close(daemon_handle h)
#define EREMOVED 219 #define EREMOVED 219
#define EDEVOPEN 220 /* sanlock failed to open lvmlock LV */ #define EDEVOPEN 220 /* sanlock failed to open lvmlock LV */
#define ELMERR 221 #define ELMERR 221
#define EORPHAN 222
#define EADOPT_NONE 223
#define EADOPT_RETRY 224
#define EIOTIMEOUT 225
#define ELOCKREPAIR 226
#endif /* _LVM_LVMLOCKD_CLIENT_H */ #endif /* _LVM_LVMLOCKD_CLIENT_H */

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@
#include "tools/tool.h" #include "tools/tool.h"
#include "libdaemon/server/daemon-server.h" #include "daemon-server.h"
#include "lib/mm/xlate.h" #include "lib/mm/xlate.h"
#include "lvmlockd-internal.h" #include "lvmlockd-internal.h"
@ -31,6 +31,7 @@
#include <errno.h> #include <errno.h>
#include <endian.h> #include <endian.h>
#include <fcntl.h> #include <fcntl.h>
#include <byteswap.h>
#include <syslog.h> #include <syslog.h>
#include <dirent.h> #include <dirent.h>
@ -95,6 +96,7 @@ static int check_args_version(char *vg_args)
static int read_cluster_name(char *clustername) static int read_cluster_name(char *clustername)
{ {
static const char close_error_msg[] = "read_cluster_name: close_error %d";
char *n; char *n;
int fd; int fd;
int rv; int rv;
@ -113,19 +115,18 @@ static int read_cluster_name(char *clustername)
rv = read(fd, clustername, MAX_ARGS); rv = read(fd, clustername, MAX_ARGS);
if (rv < 0) { if (rv < 0) {
log_error("read_cluster_name: cluster name read error %d, check dlm_controld", fd); log_error("read_cluster_name: cluster name read error %d, check dlm_controld", fd);
goto out; if (close(fd))
log_error(close_error_msg, fd);
return rv;
} }
clustername[rv] = 0; clustername[rv] = 0;
n = strstr(clustername, "\n"); n = strstr(clustername, "\n");
if (n) if (n)
*n = '\0'; *n = '\0';
rv = 0;
out:
if (close(fd)) if (close(fd))
log_error("read_cluster_name: close_error %d", fd); log_error(close_error_msg, fd);
return 0;
return rv;
} }
#define MAX_VERSION 16 #define MAX_VERSION 16
@ -168,10 +169,8 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
struct lm_dlm *lmd; struct lm_dlm *lmd;
int rv; int rv;
if (daemon_test) { if (daemon_test)
log_debug("lm_prepare_lockspace_dlm test");
goto skip_args; goto skip_args;
}
memset(sys_clustername, 0, sizeof(sys_clustername)); memset(sys_clustername, 0, sizeof(sys_clustername));
memset(arg_clustername, 0, sizeof(arg_clustername)); memset(arg_clustername, 0, sizeof(arg_clustername));
@ -221,112 +220,20 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
return 0; return 0;
} }
#define DLM_COMMS_PATH "/sys/kernel/config/dlm/cluster/comms" int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
#define LOCK_LINE_MAX 1024
static int get_local_nodeid(void)
{
struct dirent *de;
DIR *ls_dir;
char ls_comms_path[PATH_MAX] = { 0 };
char path[PATH_MAX] = { 0 };
FILE *file;
char line[LOCK_LINE_MAX];
char *str1, *str2;
int rv = -1, val;
snprintf(ls_comms_path, sizeof(ls_comms_path), "%s", DLM_COMMS_PATH);
if (!(ls_dir = opendir(ls_comms_path)))
return -ECONNREFUSED;
while ((de = readdir(ls_dir))) {
if (de->d_name[0] == '.')
continue;
snprintf(path, sizeof(path), "%s/%s/local",
DLM_COMMS_PATH, de->d_name);
if (!(file = fopen(ls_comms_path, "r")))
continue;
str1 = fgets(line, sizeof(line), file);
if (fclose(file))
log_sys_debug("fclose", path);
if (str1) {
rv = sscanf(line, "%d", &val);
if ((rv == 1) && (val == 1 )) {
snprintf(path, sizeof(path), "%s/%s/nodeid",
DLM_COMMS_PATH, de->d_name);
if (!(file = fopen(path, "r")))
continue;
str2 = fgets(line, sizeof(line), file);
if (fclose(file))
log_sys_debug("fclose", path);
if (str2) {
rv = sscanf(line, "%d", &val);
if (rv == 1) {
if (closedir(ls_dir))
log_sys_debug("closedir", ls_comms_path);
return val;
}
}
}
}
}
if (closedir(ls_dir))
log_sys_debug("closedir", ls_comms_path);
return rv;
}
int lm_purge_locks_dlm(struct lockspace *ls)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
int nodeid;
int rv = -1;
if (!lmd || !lmd->dh) {
log_error("purge_locks_dlm %s no dlm_handle_t error", ls->name);
goto fail;
}
nodeid = get_local_nodeid();
if (nodeid < 0) {
log_error("failed to get local nodeid");
goto fail;
}
if (dlm_ls_purge(lmd->dh, nodeid, 0)) {
log_error("purge_locks_dlm %s error", ls->name);
goto fail;
}
rv = 0;
fail:
return rv;
}
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok)
{ {
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data; struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
if (daemon_test) if (daemon_test)
return 0; return 0;
if (adopt_only || adopt_ok) { if (adopt)
lmd->dh = dlm_open_lockspace(ls->name); lmd->dh = dlm_open_lockspace(ls->name);
if (!lmd->dh && adopt_ok) else
lmd->dh = dlm_new_lockspace(ls->name, 0600, DLM_LSFL_NEWEXCL);
if (!lmd->dh)
log_error("add_lockspace_dlm adopt_only %d adopt_ok %d %s error",
adopt_only, adopt_ok, ls->name);
} else {
lmd->dh = dlm_new_lockspace(ls->name, 0600, DLM_LSFL_NEWEXCL); lmd->dh = dlm_new_lockspace(ls->name, 0600, DLM_LSFL_NEWEXCL);
if (!lmd->dh)
log_error("add_lockspace_dlm %s error", ls->name);
}
if (!lmd->dh) { if (!lmd->dh) {
log_error("add_lockspace_dlm %s adopt %d error", ls->name, adopt);
free(lmd); free(lmd);
ls->lm_data = NULL; ls->lm_data = NULL;
return -1; return -1;
@ -362,7 +269,7 @@ int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
return 0; return 0;
} }
int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl) static int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl)
{ {
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data; struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data; struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
@ -394,7 +301,7 @@ int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_
r->name, strlen(r->name), r->name, strlen(r->name),
0, NULL, NULL, NULL); 0, NULL, NULL, NULL);
if (rv < 0) { if (rv < 0) {
log_error("%s:%s add_resource_dlm lock error %d", ls->name, r->name, rv); log_error("S %s R %s add_resource_dlm lock error %d", ls->name, r->name, rv);
return rv; return rv;
} }
out: out:
@ -418,7 +325,7 @@ int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
rv = dlm_ls_unlock_wait(lmd->dh, lksb->sb_lkid, 0, lksb); rv = dlm_ls_unlock_wait(lmd->dh, lksb->sb_lkid, 0, lksb);
if (rv < 0) { if (rv < 0) {
log_error("%s:%s rem_resource_dlm unlock error %d", ls->name, r->name, rv); log_error("S %s R %s rem_resource_dlm unlock error %d", ls->name, r->name, rv);
} }
out: out:
free(rdd->vb); free(rdd->vb);
@ -473,7 +380,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
goto fail; goto fail;
} }
log_debug("%s:%s adopt_dlm", ls->name, r->name); log_debug("S %s R %s adopt_dlm", ls->name, r->name);
if (daemon_test) if (daemon_test)
return 0; return 0;
@ -482,29 +389,29 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
* dlm returns 0 for success, -EAGAIN if an orphan is * dlm returns 0 for success, -EAGAIN if an orphan is
* found with another mode, and -ENOENT if no orphan. * found with another mode, and -ENOENT if no orphan.
* *
* cast/bast/param are (void (*)(void*))1 because the kernel * cast/bast/param are (void *)1 because the kernel
* returns errors if some are null. * returns errors if some are null.
*/ */
rv = dlm_ls_lockx(lmd->dh, mode, lksb, flags, rv = dlm_ls_lockx(lmd->dh, mode, lksb, flags,
r->name, strlen(r->name), 0, r->name, strlen(r->name), 0,
(void (*)(void*))1, (void (*)(void*))1, (void (*)(void*))1, (void *)1, (void *)1, (void *)1,
NULL, NULL); NULL, NULL);
if (rv == -1 && (errno == EAGAIN)) { if (rv == -1 && (errno == EAGAIN)) {
log_debug("%s:%s adopt_dlm adopt mode %d try other mode", log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
ls->name, r->name, ld_mode); ls->name, r->name, ld_mode);
rv = -EADOPT_RETRY; rv = -EUCLEAN;
goto fail; goto fail;
} }
if (rv == -1 && (errno == ENOENT)) { if (rv == -1 && (errno == ENOENT)) {
log_debug("%s:%s adopt_dlm adopt mode %d no lock", log_debug("S %s R %s adopt_dlm adopt mode %d no lock",
ls->name, r->name, ld_mode); ls->name, r->name, ld_mode);
rv = -EADOPT_NONE; rv = -ENOENT;
goto fail; goto fail;
} }
if (rv < 0) { if (rv < 0) {
log_debug("%s:%s adopt_dlm mode %d flags %x error %d errno %d", log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
ls->name, r->name, mode, flags, rv, errno); ls->name, r->name, mode, flags, rv, errno);
goto fail; goto fail;
} }
@ -534,7 +441,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
*/ */
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode, int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int adopt_only, int adopt_ok) struct val_blk *vb_out, int adopt)
{ {
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data; struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data; struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
@ -544,13 +451,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
int mode; int mode;
int rv; int rv;
if (adopt_ok) { if (adopt) {
log_debug("%s:%s lock_dlm adopt_ok not supported", ls->name, r->name);
return -1;
}
if (adopt_only) {
log_debug("%s:%s lock_dlm adopt_only", ls->name, r->name);
/* When adopting, we don't follow the normal method /* When adopting, we don't follow the normal method
of acquiring a NL lock then converting it to the of acquiring a NL lock then converting it to the
desired mode. */ desired mode. */
@ -579,13 +480,13 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
return -EINVAL; return -EINVAL;
} }
log_debug("%s:%s lock_dlm", ls->name, r->name); log_debug("S %s R %s lock_dlm", ls->name, r->name);
if (daemon_test) { if (daemon_test) {
if (rdd->vb) { if (rdd->vb) {
vb_out->version = le16toh(rdd->vb->version); vb_out->version = le16_to_cpu(rdd->vb->version);
vb_out->flags = le16toh(rdd->vb->flags); vb_out->flags = le16_to_cpu(rdd->vb->flags);
vb_out->r_version = le32toh(rdd->vb->r_version); vb_out->r_version = le32_to_cpu(rdd->vb->r_version);
} }
return 0; return 0;
} }
@ -599,7 +500,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
r->name, strlen(r->name), r->name, strlen(r->name),
0, NULL, NULL, NULL); 0, NULL, NULL, NULL);
if (rv == -1) { if (rv == -1) {
log_debug("%s:%s lock_dlm acquire mode PR for %d rv %d", log_debug("S %s R %s lock_dlm acquire mode PR for %d rv %d",
ls->name, r->name, mode, rv); ls->name, r->name, mode, rv);
goto lockrv; goto lockrv;
} }
@ -612,17 +513,17 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
0, NULL, NULL, NULL); 0, NULL, NULL, NULL);
lockrv: lockrv:
if (rv == -1 && errno == EAGAIN) { if (rv == -1 && errno == EAGAIN) {
log_debug("%s:%s lock_dlm acquire mode %d rv EAGAIN", ls->name, r->name, mode); log_debug("S %s R %s lock_dlm acquire mode %d rv EAGAIN", ls->name, r->name, mode);
return -EAGAIN; return -EAGAIN;
} }
if (rv < 0) { if (rv < 0) {
log_error("%s:%s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno); log_error("S %s R %s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
return -ELMERR; return -ELMERR;
} }
if (rdd->vb) { if (rdd->vb) {
if (lksb->sb_flags & DLM_SBF_VALNOTVALID) { if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
log_debug("%s:%s lock_dlm VALNOTVALID", ls->name, r->name); log_debug("S %s R %s lock_dlm VALNOTVALID", ls->name, r->name);
memset(rdd->vb, 0, sizeof(struct val_blk)); memset(rdd->vb, 0, sizeof(struct val_blk));
memset(vb_out, 0, sizeof(struct val_blk)); memset(vb_out, 0, sizeof(struct val_blk));
goto out; goto out;
@ -637,9 +538,9 @@ lockrv:
memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk)); memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk));
memcpy(rdd->vb, &vb, sizeof(vb)); memcpy(rdd->vb, &vb, sizeof(vb));
vb_out->version = le16toh(vb.version); vb_out->version = le16_to_cpu(vb.version);
vb_out->flags = le16toh(vb.flags); vb_out->flags = le16_to_cpu(vb.flags);
vb_out->r_version = le32toh(vb.r_version); vb_out->r_version = le32_to_cpu(vb.r_version);
} }
out: out:
return 0; return 0;
@ -651,11 +552,11 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data; struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data; struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
struct dlm_lksb *lksb = &rdd->lksb; struct dlm_lksb *lksb = &rdd->lksb;
int mode; uint32_t mode;
uint32_t flags = 0; uint32_t flags = 0;
int rv; int rv;
log_debug("%s:%s convert_dlm", ls->name, r->name); log_debug("S %s R %s convert_dlm", ls->name, r->name);
flags |= LKF_CONVERT; flags |= LKF_CONVERT;
flags |= LKF_NOQUEUE; flags |= LKF_NOQUEUE;
@ -664,21 +565,19 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
if (rdd->vb && r_version && (r->mode == LD_LK_EX)) { if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
if (!rdd->vb->version) { if (!rdd->vb->version) {
/* first time vb has been written */ /* first time vb has been written */
rdd->vb->version = htole16(VAL_BLK_VERSION); rdd->vb->version = cpu_to_le16(VAL_BLK_VERSION);
} }
rdd->vb->r_version = htole32(r_version); rdd->vb->r_version = cpu_to_le32(r_version);
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk)); memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
log_debug("%s:%s convert_dlm set r_version %u", log_debug("S %s R %s convert_dlm set r_version %u",
ls->name, r->name, r_version); ls->name, r->name, r_version);
flags |= LKF_VALBLK; flags |= LKF_VALBLK;
} }
if ((mode = to_dlm_mode(ld_mode)) < 0) { mode = to_dlm_mode(ld_mode);
log_error("lm_convert_dlm invalid mode %d", ld_mode);
return -EINVAL;
}
if (daemon_test) if (daemon_test)
return 0; return 0;
@ -687,11 +586,11 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
0, NULL, NULL, NULL); 0, NULL, NULL, NULL);
if (rv == -1 && errno == EAGAIN) { if (rv == -1 && errno == EAGAIN) {
/* FIXME: When does this happen? Should something different be done? */ /* FIXME: When does this happen? Should something different be done? */
log_error("%s:%s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode); log_error("S %s R %s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
return -EAGAIN; return -EAGAIN;
} }
if (rv < 0) { if (rv < 0) {
log_error("%s:%s convert_dlm error %d", ls->name, r->name, rv); log_error("S %s R %s convert_dlm error %d", ls->name, r->name, rv);
rv = -ELMERR; rv = -ELMERR;
} }
return rv; return rv;
@ -723,17 +622,17 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
memcpy(&vb_next, rdd->vb, sizeof(struct val_blk)); memcpy(&vb_next, rdd->vb, sizeof(struct val_blk));
if (!vb_prev.version) { if (!vb_prev.version) {
vb_next.version = htole16(VAL_BLK_VERSION); vb_next.version = cpu_to_le16(VAL_BLK_VERSION);
new_vb = 1; new_vb = 1;
} }
if ((lmu_flags & LMUF_FREE_VG) && (r->type == LD_RT_VG)) { if ((lmu_flags & LMUF_FREE_VG) && (r->type == LD_RT_VG)) {
vb_next.flags = htole16(VBF_REMOVED); vb_next.flags = cpu_to_le16(VBF_REMOVED);
new_vb = 1; new_vb = 1;
} }
if (r_version) { if (r_version) {
vb_next.r_version = htole32(r_version); vb_next.r_version = cpu_to_le32(r_version);
new_vb = 1; new_vb = 1;
} }
@ -741,21 +640,21 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
memcpy(rdd->vb, &vb_next, sizeof(struct val_blk)); memcpy(rdd->vb, &vb_next, sizeof(struct val_blk));
memcpy(lksb->sb_lvbptr, &vb_next, sizeof(struct val_blk)); memcpy(lksb->sb_lvbptr, &vb_next, sizeof(struct val_blk));
log_debug("%s:%s unlock_dlm vb old %x %x %u new %x %x %u", log_debug("S %s R %s unlock_dlm vb old %x %x %u new %x %x %u",
ls->name, r->name, ls->name, r->name,
le16toh(vb_prev.version), le16_to_cpu(vb_prev.version),
le16toh(vb_prev.flags), le16_to_cpu(vb_prev.flags),
le32toh(vb_prev.r_version), le32_to_cpu(vb_prev.r_version),
le16toh(vb_next.version), le16_to_cpu(vb_next.version),
le16toh(vb_next.flags), le16_to_cpu(vb_next.flags),
le32toh(vb_next.r_version)); le32_to_cpu(vb_next.r_version));
} else { } else {
log_debug("%s:%s unlock_dlm vb unchanged", ls->name, r->name); log_debug("S %s R %s unlock_dlm vb unchanged", ls->name, r->name);
} }
flags |= LKF_VALBLK; flags |= LKF_VALBLK;
} else { } else {
log_debug("%s:%s unlock_dlm", ls->name, r->name); log_debug("S %s R %s unlock_dlm", ls->name, r->name);
} }
if (daemon_test) if (daemon_test)
@ -765,7 +664,7 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
r->name, strlen(r->name), r->name, strlen(r->name),
0, NULL, NULL, NULL); 0, NULL, NULL, NULL);
if (rv < 0) { if (rv < 0) {
log_error("%s:%s unlock_dlm error %d", ls->name, r->name, rv); log_error("S %s R %s unlock_dlm error %d", ls->name, r->name, rv);
rv = -ELMERR; rv = -ELMERR;
} }
@ -798,16 +697,9 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
* the stale lockspaces on the others eventually.) * the stale lockspaces on the others eventually.)
*/ */
/*
* On error, returns < 0
*
* On success:
* If other hosts are found, returns the number.
* If no other hosts are found (only ourself), returns 0.
*/
int lm_hosts_dlm(struct lockspace *ls, int notify) int lm_hosts_dlm(struct lockspace *ls, int notify)
{ {
static const char closedir_err_msg[] = "lm_hosts_dlm: closedir failed";
char ls_nodes_path[PATH_MAX]; char ls_nodes_path[PATH_MAX];
struct dirent *de; struct dirent *de;
DIR *ls_dir; DIR *ls_dir;
@ -830,7 +722,7 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
} }
if (closedir(ls_dir)) if (closedir(ls_dir))
log_error("lm_hosts_dlm: closedir failed"); log_error(closedir_err_msg);
if (!count) { if (!count) {
log_error("lm_hosts_dlm found no nodes in %s", ls_nodes_path); log_error("lm_hosts_dlm found no nodes in %s", ls_nodes_path);
@ -847,10 +739,10 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin) int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
{ {
static const char closedir_err_msg[] = "lm_get_lockspace_dlm: closedir failed";
struct lockspace *ls; struct lockspace *ls;
struct dirent *de; struct dirent *de;
DIR *ls_dir; DIR *ls_dir;
int ret = 0;
if (!(ls_dir = opendir(DLM_LOCKSPACES_PATH))) if (!(ls_dir = opendir(DLM_LOCKSPACES_PATH)))
return -ECONNREFUSED; return -ECONNREFUSED;
@ -863,20 +755,20 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
continue; continue;
if (!(ls = alloc_lockspace())) { if (!(ls = alloc_lockspace())) {
ret = -ENOMEM; if (closedir(ls_dir))
goto out; log_error(closedir_err_msg);
return -ENOMEM;
} }
ls->lm_type = LD_LM_DLM; ls->lm_type = LD_LM_DLM;
dm_strncpy(ls->name, de->d_name, sizeof(ls->name)); strncpy(ls->name, de->d_name, MAX_NAME);
dm_strncpy(ls->vg_name, ls->name + strlen(LVM_LS_PREFIX), sizeof(ls->vg_name)); strncpy(ls->vg_name, ls->name + strlen(LVM_LS_PREFIX), MAX_NAME);
list_add_tail(&ls->list, ls_rejoin); list_add_tail(&ls->list, ls_rejoin);
} }
out:
if (closedir(ls_dir))
log_error("lm_get_lockspace_dlm: closedir failed");
return ret; if (closedir(ls_dir))
log_error(closedir_err_msg);
return 0;
} }
int lm_is_running_dlm(void) int lm_is_running_dlm(void)
@ -906,7 +798,7 @@ int lm_refresh_lv_start_dlm(struct action *act)
int rv; int rv;
/* split /dev/vgname/lvname into vgname and lvname strings */ /* split /dev/vgname/lvname into vgname and lvname strings */
dm_strncpy(path, act->path, sizeof(path)); strncpy(path, act->path, PATH_MAX-1);
/* skip past dev */ /* skip past dev */
if (!(p = strchr(path + 1, '/'))) if (!(p = strchr(path + 1, '/')))

View File

@ -13,7 +13,7 @@
#include "tools/tool.h" #include "tools/tool.h"
#include "libdaemon/server/daemon-server.h" #include "daemon-server.h"
#include "lib/mm/xlate.h" #include "lib/mm/xlate.h"
#include "lvmlockd-internal.h" #include "lvmlockd-internal.h"
@ -136,7 +136,7 @@ static int lm_idm_scsi_directory_select(const struct dirent *s)
return 0; return 0;
} }
static int lm_idm_scsi_find_block_directory(const char *block_path) static int lm_idm_scsi_find_block_dirctory(const char *block_path)
{ {
struct stat stats; struct stat stats;
@ -252,7 +252,7 @@ static char *lm_idm_scsi_get_block_device_node(const char *scsi_path)
goto fail; goto fail;
} }
ret = lm_idm_scsi_find_block_directory(blk_path); ret = lm_idm_scsi_find_block_dirctory(blk_path);
if (ret < 0) { if (ret < 0) {
log_error("Fail to find block path %s", blk_path); log_error("Fail to find block path %s", blk_path);
goto fail; goto fail;
@ -364,7 +364,7 @@ static void lm_idm_update_vb_timestamp(uint64_t *vb_timestamp)
/* /*
* It's possible that the multiple nodes have no clock * It's possible that the multiple nodes have no clock
* synchronization with microsecond precision and the time * synchronization with microsecond prcision and the time
* is going backward. For this case, simply increment the * is going backward. For this case, simply increment the
* existing timestamp and write out to drive. * existing timestamp and write out to drive.
*/ */
@ -391,7 +391,7 @@ int lm_prepare_lockspace_idm(struct lockspace *ls)
return 0; return 0;
} }
int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok) int lm_add_lockspace_idm(struct lockspace *ls, int adopt)
{ {
char killpath[IDM_FAILURE_PATH_LEN]; char killpath[IDM_FAILURE_PATH_LEN];
char killargs[IDM_FAILURE_ARGS_LEN]; char killargs[IDM_FAILURE_ARGS_LEN];
@ -490,7 +490,7 @@ out:
return rv; return rv;
} }
int lm_add_resource_idm(struct lockspace *ls, struct resource *r) static int lm_add_resource_idm(struct lockspace *ls, struct resource *r)
{ {
struct rd_idm *rdi = (struct rd_idm *)r->lm_data; struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
@ -530,7 +530,7 @@ static int to_idm_mode(int ld_mode)
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode, int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs, struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
int adopt_only, int adopt_ok) int adopt)
{ {
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data; struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
struct rd_idm *rdi = (struct rd_idm *)r->lm_data; struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
@ -556,9 +556,9 @@ int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
if (daemon_test) { if (daemon_test) {
if (rdi->vb) { if (rdi->vb) {
vb_out->version = le16toh(rdi->vb->version); vb_out->version = le16_to_cpu(rdi->vb->version);
vb_out->flags = le16toh(rdi->vb->flags); vb_out->flags = le16_to_cpu(rdi->vb->flags);
vb_out->r_version = le32toh(rdi->vb->r_version); vb_out->r_version = le32_to_cpu(rdi->vb->r_version);
} }
return 0; return 0;
} }

View File

@ -13,9 +13,6 @@
#include "base/memory/container_of.h" #include "base/memory/container_of.h"
#include <stdint.h>
#include <pthread.h>
#define MAX_NAME 64 #define MAX_NAME 64
#define MAX_ARGS 64 #define MAX_ARGS 64
@ -62,7 +59,6 @@ enum {
LD_OP_BUSY, LD_OP_BUSY,
LD_OP_QUERY_LOCK, LD_OP_QUERY_LOCK,
LD_OP_REFRESH_LV, LD_OP_REFRESH_LV,
LD_OP_VG_STATUS,
}; };
/* resource types */ /* resource types */
@ -111,14 +107,11 @@ struct client {
#define LD_AF_SEARCH_LS 0x00000200 #define LD_AF_SEARCH_LS 0x00000200
#define LD_AF_WAIT_STARTING 0x00001000 #define LD_AF_WAIT_STARTING 0x00001000
#define LD_AF_DUP_GL_LS 0x00002000 #define LD_AF_DUP_GL_LS 0x00002000
#define LD_AF_ADOPT 0x00010000 /* adopt ok but not required */ #define LD_AF_ADOPT 0x00010000
#define LD_AF_WARN_GL_REMOVED 0x00020000 #define LD_AF_WARN_GL_REMOVED 0x00020000
#define LD_AF_LV_LOCK 0x00040000 #define LD_AF_LV_LOCK 0x00040000
#define LD_AF_LV_UNLOCK 0x00080000 #define LD_AF_LV_UNLOCK 0x00080000
#define LD_AF_SH_EXISTS 0x00100000 #define LD_AF_SH_EXISTS 0x00100000
#define LD_AF_ADOPT_ONLY 0x00200000 /* adopt orphan or fail */
#define LD_AF_NODELAY 0x00400000
#define LD_AF_REPAIR 0x00800000
/* /*
* Number of times to repeat a lock request after * Number of times to repeat a lock request after
@ -132,24 +125,12 @@ struct pvs {
int num; int num;
}; };
#define OWNER_NAME_SIZE 64
#define OWNER_STATE_SIZE 32
struct owner {
uint32_t host_id;
uint32_t generation;
uint32_t timestamp;
char state[OWNER_STATE_SIZE];
char name[OWNER_NAME_SIZE];
};
struct action { struct action {
struct list_head list; struct list_head list;
uint32_t client_id; uint32_t client_id;
uint32_t flags; /* LD_AF_ */ uint32_t flags; /* LD_AF_ */
uint32_t version; uint32_t version;
uint32_t host_id; uint64_t host_id;
uint64_t lv_size_bytes;
int8_t op; /* operation type LD_OP_ */ int8_t op; /* operation type LD_OP_ */
int8_t rt; /* resource type LD_RT_ */ int8_t rt; /* resource type LD_RT_ */
int8_t mode; /* lock mode LD_LK_ */ int8_t mode; /* lock mode LD_LK_ */
@ -158,7 +139,6 @@ struct action {
int max_retries; int max_retries;
int result; int result;
int lm_rv; /* return value from lm_ function */ int lm_rv; /* return value from lm_ function */
int align_mb;
char *path; char *path;
char vg_uuid[64]; char vg_uuid[64];
char vg_name[MAX_NAME+1]; char vg_name[MAX_NAME+1];
@ -166,8 +146,7 @@ struct action {
char lv_uuid[MAX_NAME+1]; char lv_uuid[MAX_NAME+1];
char vg_args[MAX_ARGS+1]; char vg_args[MAX_ARGS+1];
char lv_args[MAX_ARGS+1]; char lv_args[MAX_ARGS+1];
char prev_lv_args[MAX_ARGS+1]; char vg_sysid[MAX_NAME+1];
struct owner owner;
struct pvs pvs; /* PV list for idm */ struct pvs pvs; /* PV list for idm */
}; };
@ -180,7 +159,6 @@ struct resource {
unsigned int sh_count; /* number of sh locks on locks list */ unsigned int sh_count; /* number of sh locks on locks list */
uint32_t version; uint32_t version;
uint32_t last_client_id; /* last client_id to lock or unlock resource */ uint32_t last_client_id; /* last client_id to lock or unlock resource */
uint32_t dispose_client_id; /* client_id disposing of resource struct */
unsigned int lm_init : 1; /* lm_data is initialized */ unsigned int lm_init : 1; /* lm_data is initialized */
unsigned int adopt : 1; /* temp flag in remove_inactive_lvs */ unsigned int adopt : 1; /* temp flag in remove_inactive_lvs */
unsigned int version_zero_valid : 1; unsigned int version_zero_valid : 1;
@ -207,11 +185,13 @@ struct lockspace {
char vg_name[MAX_NAME+1]; char vg_name[MAX_NAME+1];
char vg_uuid[64]; char vg_uuid[64];
char vg_args[MAX_ARGS+1]; /* lock manager specific args */ char vg_args[MAX_ARGS+1]; /* lock manager specific args */
char vg_sysid[MAX_NAME+1];
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */ int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
void *lm_data; void *lm_data;
uint32_t host_id; uint64_t host_id;
uint64_t generation;
uint64_t free_lock_offset; /* for sanlock, start search for free lock here */ uint64_t free_lock_offset; /* for sanlock, start search for free lock here */
int free_lock_sector_size; /* for sanlock */
int free_lock_align_size; /* for sanlock */
struct pvs pvs; /* for idm: PV list */ struct pvs pvs; /* for idm: PV list */
uint32_t start_client_id; /* client_id that started the lockspace */ uint32_t start_client_id; /* client_id that started the lockspace */
@ -231,7 +211,6 @@ struct lockspace {
struct list_head actions; /* new client actions */ struct list_head actions; /* new client actions */
struct list_head resources; /* resource/lock state for gl/vg/lv */ struct list_head resources; /* resource/lock state for gl/vg/lv */
struct list_head dispose; /* resources to free */
}; };
/* val_blk version */ /* val_blk version */
@ -298,15 +277,15 @@ static inline int list_empty(const struct list_head *head)
list_entry((ptr)->next, type, member) list_entry((ptr)->next, type, member)
#define list_for_each_entry(pos, head, member) \ #define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, __typeof__(*pos), member); \ for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \ &pos->member != (head); \
pos = list_entry(pos->member.next, __typeof__(*pos), member)) pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \ #define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, __typeof__(*pos), member), \ for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, __typeof__(*pos), member); \ n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \ &pos->member != (head); \
pos = n, n = list_entry(n->member.next, __typeof__(*n), member)) pos = n, n = list_entry(n->member.next, typeof(*n), member))
/* to improve readability */ /* to improve readability */
@ -384,8 +363,6 @@ void log_level(int level, const char *fmt, ...) __attribute__((format(printf, 2
#define log_debug(fmt, args...) log_level(LOG_DEBUG, fmt, ##args) #define log_debug(fmt, args...) log_level(LOG_DEBUG, fmt, ##args)
#define log_error(fmt, args...) log_level(LOG_ERR, fmt, ##args) #define log_error(fmt, args...) log_level(LOG_ERR, fmt, ##args)
#define log_warn(fmt, args...) log_level(LOG_WARNING, fmt, ##args) #define log_warn(fmt, args...) log_level(LOG_WARNING, fmt, ##args)
#define log_sys_debug(x, y) \
log_debug("%s: %s failed: %s", y, x, strerror(errno))
struct lockspace *alloc_lockspace(void); struct lockspace *alloc_lockspace(void);
int lockspaces_empty(void); int lockspaces_empty(void);
@ -414,12 +391,10 @@ static inline const char *mode_str(int x)
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args); int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_prepare_lockspace_dlm(struct lockspace *ls); int lm_prepare_lockspace_dlm(struct lockspace *ls);
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok); int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
int lm_purge_locks_dlm(struct lockspace *ls);
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg); int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl);
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode, int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int adopt_only, int adopt_ok); struct val_blk *vb_out, int adopt);
int lm_convert_dlm(struct lockspace *ls, struct resource *r, int lm_convert_dlm(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version); int ld_mode, uint32_t r_version);
int lm_unlock_dlm(struct lockspace *ls, struct resource *r, int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
@ -441,102 +416,64 @@ static inline int lm_support_dlm(void)
static inline int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args) static inline int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
{ {
if (daemon_test)
return 0;
return -1; return -1;
} }
static inline int lm_prepare_lockspace_dlm(struct lockspace *ls) static inline int lm_prepare_lockspace_dlm(struct lockspace *ls)
{ {
if (daemon_test)
return 0;
return -1; return -1;
} }
static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok) static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
{ {
if (daemon_test)
return 0;
return -1;
}
static inline int lm_purge_locks_dlm(struct lockspace *ls)
{
if (daemon_test)
return 0;
return -1; return -1;
} }
static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg) static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
{ {
if (daemon_test)
return 0;
return -1;
}
static inline int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl)
{
if (daemon_test)
return 0;
return -1; return -1;
} }
static inline int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode, static inline int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int adopt_only, int adopt_ok) struct val_blk *vb_out, int adopt)
{ {
if (daemon_test)
return 0;
return -1; return -1;
} }
static inline int lm_convert_dlm(struct lockspace *ls, struct resource *r, static inline int lm_convert_dlm(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version) int ld_mode, uint32_t r_version)
{ {
if (daemon_test)
return 0;
return -1; return -1;
} }
static inline int lm_unlock_dlm(struct lockspace *ls, struct resource *r, static inline int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
uint32_t r_version, uint32_t lmu_flags) uint32_t r_version, uint32_t lmu_flags)
{ {
if (daemon_test)
return 0;
return -1; return -1;
} }
static inline int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r) static inline int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
{ {
if (daemon_test)
return 0;
return -1; return -1;
} }
static inline int lm_get_lockspaces_dlm(struct list_head *ls_rejoin) static inline int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
{ {
if (daemon_test)
return 0;
return -1; return -1;
} }
static inline int lm_data_size_dlm(void) static inline int lm_data_size_dlm(void)
{ {
if (daemon_test)
return 0;
return -1; return -1;
} }
static inline int lm_is_running_dlm(void) static inline int lm_is_running_dlm(void)
{ {
if (daemon_test)
return 1;
return 0; return 0;
} }
static inline int lm_support_dlm(void) static inline int lm_support_dlm(void)
{ {
if (daemon_test)
return 1;
return 0; return 0;
} }
@ -559,17 +496,15 @@ static inline int lm_refresh_lv_check_dlm(struct action *act)
#ifdef LOCKDSANLOCK_SUPPORT #ifdef LOCKDSANLOCK_SUPPORT
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb); int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args); int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, int sector_size, int align_size, uint64_t free_offset);
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r); int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args); int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation, int repair); int lm_prepare_lockspace_sanlock(struct lockspace *ls);
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok, int nodelay); int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt);
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg); int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r);
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode, int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int *retry, struct owner *owner, struct val_blk *vb_out, int *retry, int adopt);
int adopt_only, int adopt_ok, int repair);
int lm_convert_sanlock(struct lockspace *ls, struct resource *r, int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version); int ld_mode, uint32_t r_version);
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r, int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
@ -582,8 +517,7 @@ int lm_gl_is_enabled(struct lockspace *ls);
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin); int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
int lm_data_size_sanlock(void); int lm_data_size_sanlock(void);
int lm_is_running_sanlock(void); int lm_is_running_sanlock(void);
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes); int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size);
int lm_vg_status_sanlock(struct lockspace *ls, struct action *act);
static inline int lm_support_sanlock(void) static inline int lm_support_sanlock(void)
{ {
@ -592,12 +526,12 @@ static inline int lm_support_sanlock(void)
#else #else
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb) static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
{ {
return -1; return -1;
} }
static inline int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args) static inline int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, int sector_size, int align_size, uint64_t free_offset)
{ {
return -1; return -1;
} }
@ -612,12 +546,12 @@ static inline int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t fl
return -1; return -1;
} }
static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation, int repair) static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls)
{ {
return -1; return -1;
} }
static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok, int nodelay) static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt)
{ {
return -1; return -1;
} }
@ -627,14 +561,8 @@ static inline int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
return -1; return -1;
} }
static inline int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
{
return -1;
}
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode, static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int *retry, struct owner *owner, struct val_blk *vb_out, int *retry, int adopt)
int adopt_only, int adopt_ok, int repair)
{ {
return -1; return -1;
} }
@ -691,12 +619,7 @@ static inline int lm_is_running_sanlock(void)
return 0; return 0;
} }
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes) static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size)
{
return -1;
}
static inline int lm_vg_status_sanlock(struct lockspace *ls, struct action *act)
{ {
return -1; return -1;
} }
@ -713,12 +636,11 @@ static inline int lm_support_sanlock(void)
int lm_data_size_idm(void); int lm_data_size_idm(void);
int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args); int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_prepare_lockspace_idm(struct lockspace *ls); int lm_prepare_lockspace_idm(struct lockspace *ls);
int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok); int lm_add_lockspace_idm(struct lockspace *ls, int adopt);
int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg); int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg);
int lm_add_resource_idm(struct lockspace *ls, struct resource *r);
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode, int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs, struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
int adopt_only, int adopt_ok); int adopt);
int lm_convert_idm(struct lockspace *ls, struct resource *r, int lm_convert_idm(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version); int ld_mode, uint32_t r_version);
int lm_unlock_idm(struct lockspace *ls, struct resource *r, int lm_unlock_idm(struct lockspace *ls, struct resource *r,
@ -751,7 +673,7 @@ static inline int lm_prepare_lockspace_idm(struct lockspace *ls)
return -1; return -1;
} }
static inline int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok) static inline int lm_add_lockspace_idm(struct lockspace *ls, int adopt)
{ {
return -1; return -1;
} }
@ -761,14 +683,9 @@ static inline int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg)
return -1; return -1;
} }
static inline int lm_add_resource_idm(struct lockspace *ls, struct resource *r)
{
return -1;
}
static inline int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode, static inline int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs, struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
int adopt_only, int adopt_ok) int adopt)
{ {
return -1; return -1;
} }

File diff suppressed because it is too large Load Diff

View File

@ -32,11 +32,11 @@ LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS) LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS) lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
$(SHOW) " [CC] $@" @echo " [CC] $@"
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
install_lvmpolld: lvmpolld install_lvmpolld: lvmpolld
$(SHOW) " [INSTALL] $<" @echo " [INSTALL] $<"
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F) $(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
install_lvm2: install_lvmpolld install_lvm2: install_lvmpolld

View File

@ -19,7 +19,7 @@
#define MIN_ARGV_SIZE 8 #define MIN_ARGV_SIZE 8
static const char *const _polling_ops[] = { static const char *const polling_ops[] = {
[PVMOVE] = LVMPD_REQ_PVMOVE, [PVMOVE] = LVMPD_REQ_PVMOVE,
[CONVERT] = LVMPD_REQ_CONVERT, [CONVERT] = LVMPD_REQ_CONVERT,
[MERGE] = LVMPD_REQ_MERGE, [MERGE] = LVMPD_REQ_MERGE,
@ -28,7 +28,7 @@ static const char *const _polling_ops[] = {
const char *polling_op(enum poll_type type) const char *polling_op(enum poll_type type)
{ {
return type < POLL_TYPE_MAX ? _polling_ops[type] : "<undefined>"; return type < POLL_TYPE_MAX ? polling_ops[type] : "<undefined>";
} }
static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind) static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
@ -81,7 +81,7 @@ const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary,
/* one of: "convert", "pvmove", "merge", "merge_thin" */ /* one of: "convert", "pvmove", "merge", "merge_thin" */
if (!add_to_cmd_arr(&cmd_argv, "--polloperation", &i) || if (!add_to_cmd_arr(&cmd_argv, "--polloperation", &i) ||
!add_to_cmd_arr(&cmd_argv, _polling_ops[pdlv->type], &i)) !add_to_cmd_arr(&cmd_argv, polling_ops[pdlv->type], &i))
goto err; goto err;
/* vg/lv name */ /* vg/lv name */

View File

@ -15,8 +15,8 @@
#include "lvmpolld-common.h" #include "lvmpolld-common.h"
#include "lvm-version.h" #include "lvm-version.h"
#include "libdaemon/server/daemon-server.h" #include "daemon-server.h"
#include "libdaemon/server/daemon-log.h" #include "daemon-log.h"
#include <getopt.h> #include <getopt.h>
#include <poll.h> #include <poll.h>
@ -52,7 +52,7 @@ static pthread_key_t key;
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data) static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
{ {
#if defined(_GNU_SOURCE) && defined(STRERROR_R_CHAR_P) #ifdef _GNU_SOURCE
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */ return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) #elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf; return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
@ -75,7 +75,7 @@ static void _usage(const char *prog, FILE *file)
" -p|--pidfile Set path to the pidfile\n" " -p|--pidfile Set path to the pidfile\n"
" -s|--socket Set path to the communication socket\n" " -s|--socket Set path to the communication socket\n"
" -B|--binary Path to lvm2 binary\n" " -B|--binary Path to lvm2 binary\n"
" -t|--timeout Time to wait in seconds before shutdown on idle (missing or 0 = infinite)\n\n", prog, prog); " -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) static int _init(struct daemon_state *s)
@ -390,11 +390,6 @@ static void *fork_and_poll(void *args)
goto err; goto err;
} }
if (!pdlv->cmdargv || !*(pdlv->cmdargv)) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "Missing command");
goto err;
}
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd line arguments:"); DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd line arguments:");
debug_print(ls, pdlv->cmdargv); debug_print(ls, pdlv->cmdargv);
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---"); DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
@ -786,7 +781,7 @@ struct log_line_baton {
const char *prefix; const char *prefix;
}; };
static daemon_handle _lvmpolld = { .error = 0 }; daemon_handle _lvmpolld = { .error = 0 };
static daemon_handle _lvmpolld_open(const char *socket) static daemon_handle _lvmpolld_open(const char *socket)
{ {
@ -872,14 +867,14 @@ enum action_index {
ACTION_MAX /* keep at the end */ 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) static int _make_action(enum action_index idx, void *args)
{ {
static const action_fn_t _actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump }; return idx < ACTION_MAX ? actions[idx](args) : 0;
return idx < ACTION_MAX ? _actions[idx](args) : 0;
} }
static int _lvmpolld_client(const char *socket, enum action_index action) static int _lvmpolld_client(const char *socket, unsigned action)
{ {
int r; int r;
@ -897,9 +892,10 @@ static int _lvmpolld_client(const char *socket, enum action_index action)
return r ? EXIT_SUCCESS : EXIT_FAILURE; return r ? EXIT_SUCCESS : EXIT_FAILURE;
} }
static const struct option _long_options[] = { static int action_idx = ACTION_MAX;
static struct option long_options[] = {
/* Have actions always at the beginning of the array. */ /* Have actions always at the beginning of the array. */
{"dump", no_argument, 0, ACTION_DUMP }, /* or an option_index ? */ {"dump", no_argument, &action_idx, ACTION_DUMP }, /* or an option_index ? */
/* other options */ /* other options */
{"binary", required_argument, 0, 'B' }, {"binary", required_argument, 0, 'B' },
@ -918,7 +914,7 @@ int main(int argc, char *argv[])
int opt; int opt;
int option_index = 0; int option_index = 0;
int client = 0, server = 0; int client = 0, server = 0;
enum action_index action = ACTION_MAX; unsigned action = ACTION_MAX;
struct timespec timeout; struct timespec timeout;
daemon_idle di = { .ptimeout = &timeout }; daemon_idle di = { .ptimeout = &timeout };
struct lvmpolld_state ls = { .log_config = "" }; struct lvmpolld_state ls = { .log_config = "" };
@ -934,16 +930,16 @@ int main(int argc, char *argv[])
.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET, .socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
}; };
while ((opt = getopt_long(argc, argv, "fhVl:p:s:B:t:", _long_options, &option_index)) != -1) { while ((opt = getopt_long(argc, argv, "fhVl:p:s:B:t:", long_options, &option_index)) != -1) {
switch (opt) { switch (opt) {
case 0 : case 0 :
if (action != ACTION_MAX) { if (action < ACTION_MAX) {
fprintf(stderr, "Can't perform more actions. Action already requested: %s\n", fprintf(stderr, "Can't perform more actions. Action already requested: %s\n",
_long_options[action].name); long_options[action].name);
_usage(argv[0], stderr); _usage(argv[0], stderr);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
action = ACTION_DUMP; action = action_idx;
client = 1; client = 1;
break; break;
case '?': case '?':

View File

@ -46,7 +46,7 @@ static char *_construct_lvm_system_dir_env(const char *sysdir)
* - or - * - or -
* just single char to store NULL byte * just single char to store NULL byte
*/ */
size_t l = sysdir ? strlen(sysdir) + sizeof(LVM_SYSTEM_DIR): 1; size_t l = sysdir ? strlen(sysdir) + 16 : 1;
char *env = (char *) malloc(l * sizeof(char)); char *env = (char *) malloc(l * sizeof(char));
if (!env) if (!env)
@ -89,17 +89,6 @@ char *construct_id(const char *sysdir, const char *uuid)
return id; return id;
} }
static void _free_lvmpolld_lv(struct lvmpolld_lv *p)
{
free((void *)p->devicesfile);
free((void *)p->lvm_system_dir_env);
free((void *)p->lvmpolld_id);
free((void *)p->lvname);
free((void *)p->sinterval);
free((void *)p->cmdargv);
free((void *)p->cmdenvp);
}
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id, struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
const char *vgname, const char *lvname, const char *vgname, const char *lvname,
const char *sysdir, enum poll_type type, const char *sysdir, enum poll_type type,
@ -107,26 +96,30 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
struct lvmpolld_store *pdst, struct lvmpolld_store *pdst,
const char *devicesfile) const char *devicesfile)
{ {
char *lvmpolld_id = strdup(id), /* copy */
*full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
*lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
char *devicesfile_dup = devicesfile ? strdup(devicesfile) : NULL;
struct lvmpolld_lv tmp = { struct lvmpolld_lv tmp = {
.ls = ls, .ls = ls,
.type = type, .type = type,
.lvmpolld_id = strdup(id), .lvmpolld_id = lvmpolld_id,
.lvname = _construct_full_lvname(vgname, lvname), .lvid = _get_lvid(lvmpolld_id, sysdir),
.devicesfile = devicesfile ? strdup(devicesfile) : NULL, .lvname = full_lvname,
.lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir), .devicesfile = devicesfile_dup,
.sinterval = strdup(sinterval), .lvm_system_dir_env = lvm_system_dir_env,
.sinterval = strdup(sinterval), /* copy */
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout, .pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
.cmd_state = { .retcode = -1, .signal = 0 }, .cmd_state = { .retcode = -1, .signal = 0 },
.pdst = pdst, .pdst = pdst,
.init_rq_count = 1 .init_rq_count = 1
}, *pdlv = (struct lvmpolld_lv *) malloc(sizeof(struct lvmpolld_lv)); }, *pdlv = (struct lvmpolld_lv *) malloc(sizeof(struct lvmpolld_lv));
if (!pdlv || !tmp.lvmpolld_id || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval) if (!pdlv || !tmp.lvid || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
goto err; goto err;
tmp.lvid = _get_lvid(tmp.lvmpolld_id, sysdir), memcpy(pdlv, &tmp, sizeof(*pdlv));
*pdlv = tmp;
if (pthread_mutex_init(&pdlv->lock, NULL)) if (pthread_mutex_init(&pdlv->lock, NULL))
goto err; goto err;
@ -134,20 +127,29 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
return pdlv; return pdlv;
err: err:
_free_lvmpolld_lv(&tmp); free((void *)devicesfile_dup);
free((void *)full_lvname);
free(pdlv); free((void *)lvmpolld_id);
free((void *)lvm_system_dir_env);
free((void *)tmp.sinterval);
free((void *)pdlv);
return NULL; return NULL;
} }
void pdlv_destroy(struct lvmpolld_lv *pdlv) void pdlv_destroy(struct lvmpolld_lv *pdlv)
{ {
_free_lvmpolld_lv(pdlv); free((void *)pdlv->lvmpolld_id);
free((void *)pdlv->devicesfile);
free((void *)pdlv->lvname);
free((void *)pdlv->sinterval);
free((void *)pdlv->lvm_system_dir_env);
free((void *)pdlv->cmdargv);
free((void *)pdlv->cmdenvp);
pthread_mutex_destroy(&pdlv->lock); pthread_mutex_destroy(&pdlv->lock);
free(pdlv); free((void *)pdlv);
} }
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv) unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)
@ -271,12 +273,12 @@ static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdl
buffer_append(buff, tmp); buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tpolling_finished=%d\n", pdlv->polling_finished) > 0) if (dm_snprintf(tmp, sizeof(tmp), "\t\tpolling_finished=%d\n", pdlv->polling_finished) > 0)
buffer_append(buff, tmp); buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\terror_occurred=%d\n", pdlv->error) > 0) if (dm_snprintf(tmp, sizeof(tmp), "\t\terror_occured=%d\n", pdlv->error) > 0)
buffer_append(buff, tmp); buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tinit_requests_count=%d\n", pdlv->init_rq_count) > 0) if (dm_snprintf(tmp, sizeof(tmp), "\t\tinit_requests_count=%d\n", pdlv->init_rq_count) > 0)
buffer_append(buff, tmp); buffer_append(buff, tmp);
/* lvm_command-section { */ /* lvm_commmand-section { */
buffer_append(buff, "\t\tlvm_command {\n"); buffer_append(buff, "\t\tlvm_command {\n");
if (cmd_state->retcode == -1 && !cmd_state->signal) if (cmd_state->retcode == -1 && !cmd_state->signal)
buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_IN_PROGRESS "\"\n"); buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_IN_PROGRESS "\"\n");
@ -288,7 +290,7 @@ static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdl
buffer_append(buff, tmp); buffer_append(buff, tmp);
} }
buffer_append(buff, "\t\t}\n"); buffer_append(buff, "\t\t}\n");
/* } lvm_command-section */ /* } lvm_commmand-section */
buffer_append(buff, "\t}\n"); buffer_append(buff, "\t}\n");
/* } pdlv-section */ /* } pdlv-section */

View File

@ -15,10 +15,7 @@
#ifndef _LVM_LVMPOLLD_DATA_UTILS_H #ifndef _LVM_LVMPOLLD_DATA_UTILS_H
#define _LVM_LVMPOLLD_DATA_UTILS_H #define _LVM_LVMPOLLD_DATA_UTILS_H
#include "base/data-struct/hash.h"
#include <pthread.h> #include <pthread.h>
#include <stdio.h>
struct buffer; struct buffer;
struct lvmpolld_state; struct lvmpolld_state;
@ -48,18 +45,18 @@ struct lvmpolld_lv {
* accessing following vars doesn't * accessing following vars doesn't
* require struct lvmpolld_lv lock * require struct lvmpolld_lv lock
*/ */
struct lvmpolld_state *ls; struct lvmpolld_state *const ls;
enum poll_type type; const enum poll_type type;
const char *lvid; const char *const lvid;
const char *lvmpolld_id; const char *const lvmpolld_id;
const char *devicesfile; const char *const devicesfile;
const char *lvname; /* full vg/lv name */ const char *const lvname; /* full vg/lv name */
unsigned pdtimeout; /* in seconds */ const unsigned pdtimeout; /* in seconds */
const char *sinterval; const char *const sinterval;
const char *lvm_system_dir_env; const char *const lvm_system_dir_env;
struct lvmpolld_store *pdst; struct lvmpolld_store *const pdst;
const char **cmdargv; const char *const *cmdargv;
const char **cmdenvp; const char *const *cmdenvp;
/* only used by write */ /* only used by write */
pid_t cmd_pid; pid_t cmd_pid;
@ -69,9 +66,9 @@ struct lvmpolld_lv {
/* block of shared variables protected by lock */ /* block of shared variables protected by lock */
struct lvmpolld_cmd_stat cmd_state; struct lvmpolld_cmd_stat cmd_state;
unsigned init_rq_count; /* for debugging purposes only */ unsigned init_rq_count; /* for debuging purposes only */
unsigned polling_finished:1; /* no more updates */ unsigned polling_finished:1; /* no more updates */
unsigned error:1; /* unrecoverable error occurred in lvmpolld */ unsigned error:1; /* unrecoverable error occured in lvmpolld */
}; };
typedef void (*lvmpolld_parse_output_fn_t) (struct lvmpolld_lv *pdlv, const char *line); typedef void (*lvmpolld_parse_output_fn_t) (struct lvmpolld_lv *pdlv, const char *line);
@ -96,7 +93,7 @@ struct lvmpolld_thread_data {
struct lvmpolld_lv *pdlv; struct lvmpolld_lv *pdlv;
}; };
char *construct_id(const char *sysdir, const char *uuid); char *construct_id(const char *sysdir, const char *lvid);
/* LVMPOLLD_LV_T section */ /* LVMPOLLD_LV_T section */

View File

@ -45,7 +45,7 @@
#define LVMPD_RESP_OK "OK" #define LVMPD_RESP_OK "OK"
#define LVMPD_REAS_RETCODE "retcode" /* lvm cmd ret code */ #define LVMPD_REAS_RETCODE "retcode" /* lvm cmd ret code */
#define LVMPD_REAS_SIGNAL "signal" /* lvm cmd terminating signal */ #define LVMPD_REAS_SIGNAL "signal" /* lvm cmd terminating singal */
#define LVMPD_RET_DUP_FAILED 100 #define LVMPD_RET_DUP_FAILED 100
#define LVMPD_RET_EXC_FAILED 101 #define LVMPD_RET_EXC_FAILED 101

View File

@ -1,4 +1,4 @@
# Copyright (C) 2018 - 2022 Red Hat, Inc. All rights reserved. # Copyright (C) 2018 Red Hat, Inc. All rights reserved.
# #
# This file is part of the device-mapper userspace tools. # This file is part of the device-mapper userspace tools.
# #
@ -25,12 +25,10 @@ DEVICE_MAPPER_SOURCE=\
device_mapper/libdm-targets.c \ device_mapper/libdm-targets.c \
device_mapper/libdm-timestamp.c \ device_mapper/libdm-timestamp.c \
device_mapper/mm/pool.c \ device_mapper/mm/pool.c \
device_mapper/raid/raid_parser.c \
device_mapper/regex/matcher.c \ device_mapper/regex/matcher.c \
device_mapper/regex/parse_rx.c \ device_mapper/regex/parse_rx.c \
device_mapper/regex/ttree.c \ device_mapper/regex/ttree.c \
device_mapper/vdo/status.c \ device_mapper/vdo/status.c \
device_mapper/vdo/vdo_reader.c \
device_mapper/vdo/vdo_target.c device_mapper/vdo/vdo_target.c
DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a
@ -45,10 +43,10 @@ CLEAN_TARGETS += $(DEVICE_MAPPER_DEPENDS) $(DEVICE_MAPPER_OBJECTS) \
#$(DEVICE_MAPPER_OBJECTS): INCLUDES+=$(VDO_INCLUDES) #$(DEVICE_MAPPER_OBJECTS): INCLUDES+=$(VDO_INCLUDES)
$(DEVICE_MAPPER_TARGET): $(DEVICE_MAPPER_OBJECTS) $(DEVICE_MAPPER_TARGET): $(DEVICE_MAPPER_OBJECTS)
$(SHOW) " [AR] $@" @echo " [AR] $@"
$(Q) $(RM) $@ $(Q) $(RM) $@
$(Q) $(AR) rsv $@ $(DEVICE_MAPPER_OBJECTS) > /dev/null $(Q) $(AR) rsv $@ $(DEVICE_MAPPER_OBJECTS) > /dev/null
ifeq ("$(USE_TRACKING)","yes") ifeq ("$(DEPENDS)","yes")
-include $(DEVICE_MAPPER_DEPENDS) -include $(DEVICE_MAPPER_DEPENDS)
endif endif

View File

@ -19,7 +19,6 @@
#include "base/data-struct/list.h" #include "base/data-struct/list.h"
#include "base/data-struct/hash.h" #include "base/data-struct/hash.h"
#include "raid/target.h"
#include "vdo/target.h" #include "vdo/target.h"
#include <inttypes.h> #include <inttypes.h>
@ -176,11 +175,12 @@ struct dm_names {
struct dm_active_device { struct dm_active_device {
struct dm_list list; struct dm_list list;
dev_t devno; int major;
const char *name; /* device name */ int minor;
char *name; /* device name */
uint32_t event_nr; /* valid when DM_DEVICE_LIST_HAS_EVENT_NR is set */ uint32_t event_nr; /* valid when DM_DEVICE_LIST_HAS_EVENT_NR is set */
const char *uuid; /* valid uuid when DM_DEVICE_LIST_HAS_UUID is set */ char *uuid; /* valid uuid when DM_DEVICE_LIST_HAS_UUID is set */
}; };
struct dm_versions { struct dm_versions {
@ -192,7 +192,7 @@ struct dm_versions {
int dm_get_library_version(char *version, size_t size); int dm_get_library_version(char *version, size_t size);
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size); int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
int dm_task_get_info(struct dm_task *dmt, struct dm_info *info); int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi);
/* /*
* This function returns dm device's UUID based on the value * This function returns dm device's UUID based on the value
@ -230,6 +230,13 @@ struct dm_names *dm_task_get_names(struct dm_task *dmt);
#define DM_DEVICE_LIST_HAS_UUID 2 #define DM_DEVICE_LIST_HAS_UUID 2
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list, int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
unsigned *devs_features); unsigned *devs_features);
/*
* -1: no idea about uuid (not provided by DM_DEVICE_LIST ioctl)
* 0: uuid not present
* 1: listed and dm_active_device will be set for not NULL pointer
*/
int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
const struct dm_active_device **dev);
/* Release all associated memory with list of active DM devices */ /* Release all associated memory with list of active DM devices */
void dm_device_list_destroy(struct dm_list **devs_list); void dm_device_list_destroy(struct dm_list **devs_list);
@ -305,15 +312,15 @@ int dm_task_add_target(struct dm_task *dmt,
#define DM_FORMAT_DEV_BUFSIZE 13 /* Minimum bufsize to handle worst case. */ #define DM_FORMAT_DEV_BUFSIZE 13 /* Minimum bufsize to handle worst case. */
int dm_format_dev(char *buf, int bufsize, uint32_t dev_major, uint32_t dev_minor); int dm_format_dev(char *buf, int bufsize, uint32_t dev_major, uint32_t dev_minor);
/* Use this to retrieve target information returned from a STATUS call */ /* Use this to retrive target information returned from a STATUS call */
void *dm_get_next_target(struct dm_task *dmt, void *dm_get_next_target(struct dm_task *dmt,
void *next, uint64_t *start, uint64_t *length, void *next, uint64_t *start, uint64_t *length,
char **target_type, char **params); char **target_type, char **params);
/* /*
* Following dm_get_status_* functions will allocate appropriate status structure * Following dm_get_status_* functions will allocate approriate status structure
* from passed mempool together with the necessary character arrays. * from passed mempool together with the necessary character arrays.
* Destroying the mempool will release all associated allocation. * Destroying the mempool will release all asociated allocation.
*/ */
/* Parse params from STATUS call for mirror target */ /* Parse params from STATUS call for mirror target */
@ -542,7 +549,7 @@ const char *dm_sysfs_dir(void);
/* /*
* Configure default UUID prefix string. * Configure default UUID prefix string.
* Conventionally this is a short capitalized prefix indicating the subsystem * Conventionally this is a short capitalised prefix indicating the subsystem
* that is managing the devices, e.g. "LVM-" or "MPATH-". * that is managing the devices, e.g. "LVM-" or "MPATH-".
* To support stacks of devices from different subsystems, recursive functions * To support stacks of devices from different subsystems, recursive functions
* stop recursing if they reach a device with a different prefix. * stop recursing if they reach a device with a different prefix.
@ -585,7 +592,7 @@ int dm_device_has_mounted_fs(uint32_t major, uint32_t minor);
/* /*
* Callback is invoked for individual mountinfo lines, * Callback is invoked for individal mountinfo lines,
* minor, major and mount target are parsed and unmangled. * minor, major and mount target are parsed and unmangled.
*/ */
typedef int (*dm_mountinfo_line_callback_fn) (char *line, unsigned maj, unsigned min, typedef int (*dm_mountinfo_line_callback_fn) (char *line, unsigned maj, unsigned min,
@ -699,7 +706,7 @@ void *dm_tree_node_get_context(const struct dm_tree_node *node);
/* /*
* Returns 0 when node size and its children is unchanged. * Returns 0 when node size and its children is unchanged.
* Returns 1 when node or any of its children has increased size. * Returns 1 when node or any of its children has increased size.
* Returns -1 when node or any of its children has reduced size. * Rerurns -1 when node or any of its children has reduced size.
*/ */
int dm_tree_node_size_changed(const struct dm_tree_node *dnode); int dm_tree_node_size_changed(const struct dm_tree_node *dnode);
@ -886,7 +893,7 @@ struct dm_tree_node_raid_params {
}; };
/* /*
* Version 2 of above node raid params struct to keep API compatibility. * Version 2 of above node raid params struct to keeep API compatibility.
* *
* Extended for more than 64 legs (max 253 in the MD kernel runtime!), * Extended for more than 64 legs (max 253 in the MD kernel runtime!),
* delta_disks for disk add/remove reshaping, * delta_disks for disk add/remove reshaping,
@ -909,7 +916,7 @@ struct dm_tree_node_raid_params_v2 {
* 'rebuilds' and 'writemostly' are bitfields that signify * 'rebuilds' and 'writemostly' are bitfields that signify
* which devices in the array are to be rebuilt or marked * which devices in the array are to be rebuilt or marked
* writemostly. The kernel supports up to 253 legs. * writemostly. The kernel supports up to 253 legs.
* We limit ourselves by choosing a lower value * We limit ourselvs by choosing a lower value
* for DEFAULT_RAID_MAX_IMAGES. * for DEFAULT_RAID_MAX_IMAGES.
*/ */
uint64_t rebuilds[RAID_BITMAP_SIZE]; uint64_t rebuilds[RAID_BITMAP_SIZE];
@ -946,7 +953,7 @@ struct dm_config_node;
* *
* policy_settings { * policy_settings {
* migration_threshold=2048 * migration_threshold=2048
* sequential_threshold=100 * sequention_threashold=100
* ... * ...
* } * }
* *
@ -975,9 +982,7 @@ struct writecache_settings {
uint32_t fua; uint32_t fua;
uint32_t nofua; uint32_t nofua;
uint32_t cleaner; uint32_t cleaner;
uint32_t max_age; /* in milliseconds */ uint32_t max_age;
uint32_t metadata_only;
uint32_t pause_writeback; /* in milliseconds */
/* /*
* Allow an unrecognized key and its val to be passed to the kernel for * Allow an unrecognized key and its val to be passed to the kernel for
@ -999,8 +1004,6 @@ struct writecache_settings {
unsigned nofua_set:1; unsigned nofua_set:1;
unsigned cleaner_set:1; unsigned cleaner_set:1;
unsigned max_age_set:1; unsigned max_age_set:1;
unsigned metadata_only_set:1;
unsigned pause_writeback_set:1;
}; };
int dm_tree_node_add_writecache_target(struct dm_tree_node *node, int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
@ -1024,7 +1027,6 @@ struct integrity_settings {
uint32_t commit_time; uint32_t commit_time;
uint32_t bitmap_flush_interval; uint32_t bitmap_flush_interval;
uint64_t sectors_per_bit; uint64_t sectors_per_bit;
uint32_t allow_discards;
unsigned journal_sectors_set:1; unsigned journal_sectors_set:1;
unsigned interleave_sectors_set:1; unsigned interleave_sectors_set:1;
@ -1033,7 +1035,6 @@ struct integrity_settings {
unsigned commit_time_set:1; unsigned commit_time_set:1;
unsigned bitmap_flush_interval_set:1; unsigned bitmap_flush_interval_set:1;
unsigned sectors_per_bit_set:1; unsigned sectors_per_bit_set:1;
unsigned allow_discards_set:1;
}; };
int dm_tree_node_add_integrity_target(struct dm_tree_node *node, int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
@ -1048,11 +1049,10 @@ int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
*/ */
int dm_tree_node_add_vdo_target(struct dm_tree_node *node, int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
uint64_t size, uint64_t size,
uint32_t vdo_version,
const char *vdo_pool_name, const char *vdo_pool_name,
const char *data_uuid, const char *data_uuid,
uint64_t data_size, uint64_t data_size,
const struct dm_vdo_target_params *vtp); const struct dm_vdo_target_params *param);
/* /*
* FIXME Add individual cache policy pairs <key> = value, like: * FIXME Add individual cache policy pairs <key> = value, like:
@ -1095,7 +1095,7 @@ int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
/* End of Replicator API */ /* End of Replicator API */
/* /*
* FIXME: Defines below are based on kernel's dm-thin.c defines * FIXME: Defines bellow are based on kernel's dm-thin.c defines
* DATA_DEV_BLOCK_SIZE_MIN_SECTORS (64 * 1024 >> SECTOR_SHIFT) * DATA_DEV_BLOCK_SIZE_MIN_SECTORS (64 * 1024 >> SECTOR_SHIFT)
* DATA_DEV_BLOCK_SIZE_MAX_SECTORS (1024 * 1024 * 1024 >> SECTOR_SHIFT) * DATA_DEV_BLOCK_SIZE_MAX_SECTORS (1024 * 1024 * 1024 >> SECTOR_SHIFT)
*/ */
@ -1161,7 +1161,7 @@ int dm_tree_node_set_thin_pool_error_if_no_space(struct dm_tree_node *node,
int dm_tree_node_set_thin_pool_read_only(struct dm_tree_node *node, int dm_tree_node_set_thin_pool_read_only(struct dm_tree_node *node,
unsigned read_only); unsigned read_only);
/* /*
* FIXME: Defines below are based on kernel's dm-thin.c defines * FIXME: Defines bellow are based on kernel's dm-thin.c defines
* MAX_DEV_ID ((1 << 24) - 1) * MAX_DEV_ID ((1 << 24) - 1)
*/ */
#define DM_THIN_MAX_DEVICE_ID (UINT32_C((1 << 24) - 1)) #define DM_THIN_MAX_DEVICE_ID (UINT32_C((1 << 24) - 1))
@ -1179,9 +1179,9 @@ void dm_tree_node_set_presuspend_node(struct dm_tree_node *node,
struct dm_tree_node *presuspend_node); struct dm_tree_node *presuspend_node);
int dm_tree_node_add_target_area(struct dm_tree_node *node, int dm_tree_node_add_target_area(struct dm_tree_node *node,
const char *dev_name, const char *dev_name,
const char *uuid, const char *dlid,
uint64_t offset); uint64_t offset);
/* /*
* Only for temporarily-missing raid devices where changes are tracked. * Only for temporarily-missing raid devices where changes are tracked.
@ -1591,9 +1591,9 @@ int dm_fclose(FILE *stream);
* Pointer to the buffer is stored in *buf. * Pointer to the buffer is stored in *buf.
* Returns -1 on failure leaving buf undefined. * Returns -1 on failure leaving buf undefined.
*/ */
int dm_asprintf(char **result, const char *format, ...) int dm_asprintf(char **buf, const char *format, ...)
__attribute__ ((format(printf, 2, 3))); __attribute__ ((format(printf, 2, 3)));
int dm_vasprintf(char **result, const char *format, va_list aq) int dm_vasprintf(char **buf, const char *format, va_list ap)
__attribute__ ((format(printf, 2, 0))); __attribute__ ((format(printf, 2, 0)));
/* /*
@ -1870,7 +1870,6 @@ const void *dm_report_value_cache_get(struct dm_report *rh, const char *name);
#define DM_REPORT_OUTPUT_FIELD_UNQUOTED 0x00000010 #define DM_REPORT_OUTPUT_FIELD_UNQUOTED 0x00000010
#define DM_REPORT_OUTPUT_COLUMNS_AS_ROWS 0x00000020 #define DM_REPORT_OUTPUT_COLUMNS_AS_ROWS 0x00000020
#define DM_REPORT_OUTPUT_MULTIPLE_TIMES 0x00000040 #define DM_REPORT_OUTPUT_MULTIPLE_TIMES 0x00000040
#define DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS 0x00000080
struct dm_report *dm_report_init(uint32_t *report_types, struct dm_report *dm_report_init(uint32_t *report_types,
const struct dm_report_object_type *types, const struct dm_report_object_type *types,
@ -1942,7 +1941,7 @@ void dm_report_free(struct dm_report *rh);
* Prefix added to each field name with DM_REPORT_OUTPUT_FIELD_NAME_PREFIX * Prefix added to each field name with DM_REPORT_OUTPUT_FIELD_NAME_PREFIX
*/ */
int dm_report_set_output_field_name_prefix(struct dm_report *rh, int dm_report_set_output_field_name_prefix(struct dm_report *rh,
const char *output_field_name_prefix); const char *report_prefix);
int dm_report_set_selection(struct dm_report *rh, const char *selection); int dm_report_set_selection(struct dm_report *rh, const char *selection);
@ -1983,8 +1982,7 @@ struct dm_report_group;
typedef enum { typedef enum {
DM_REPORT_GROUP_SINGLE, DM_REPORT_GROUP_SINGLE,
DM_REPORT_GROUP_BASIC, DM_REPORT_GROUP_BASIC,
DM_REPORT_GROUP_JSON, DM_REPORT_GROUP_JSON
DM_REPORT_GROUP_JSON_STD
} dm_report_group_type_t; } dm_report_group_type_t;
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data); struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data);
@ -2035,7 +2033,6 @@ struct dm_config_tree *dm_config_create(void);
struct dm_config_tree *dm_config_from_string(const char *config_settings); struct dm_config_tree *dm_config_from_string(const char *config_settings);
int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end); int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end);
int dm_config_parse_without_dup_node_check(struct dm_config_tree *cft, const char *start, const char *end); int dm_config_parse_without_dup_node_check(struct dm_config_tree *cft, const char *start, const char *end);
int dm_config_parse_only_section(struct dm_config_tree *cft, const char *start, const char *end, const char *section);
void *dm_config_get_custom(struct dm_config_tree *cft); void *dm_config_get_custom(struct dm_config_tree *cft);
void dm_config_set_custom(struct dm_config_tree *cft, void *custom); void dm_config_set_custom(struct dm_config_tree *cft, void *custom);
@ -2060,7 +2057,7 @@ void dm_config_destroy(struct dm_config_tree *cft);
/* Simple output line by line. */ /* Simple output line by line. */
typedef int (*dm_putline_fn)(const char *line, void *baton); typedef int (*dm_putline_fn)(const char *line, void *baton);
/* More advanced output with config node reference. */ /* More advaced output with config node reference. */
typedef int (*dm_config_node_out_fn)(const struct dm_config_node *cn, const char *line, void *baton); typedef int (*dm_config_node_out_fn)(const struct dm_config_node *cn, const char *line, void *baton);
/* /*
@ -2082,7 +2079,7 @@ int dm_config_write_one_node_out(const struct dm_config_node *cn, const struct d
struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn, const char *path); struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn, const char *path);
int dm_config_has_node(const struct dm_config_node *cn, const char *path); int dm_config_has_node(const struct dm_config_node *cn, const char *path);
int dm_config_remove_node(struct dm_config_node *parent, struct dm_config_node *rem_node); int dm_config_remove_node(struct dm_config_node *parent, struct dm_config_node *remove);
const char *dm_config_find_str(const struct dm_config_node *cn, const char *path, const char *fail); const char *dm_config_find_str(const struct dm_config_node *cn, const char *path, const char *fail);
const char *dm_config_find_str_allow_empty(const struct dm_config_node *cn, const char *path, const char *fail); const char *dm_config_find_str_allow_empty(const struct dm_config_node *cn, const char *path, const char *fail);
int dm_config_find_int(const struct dm_config_node *cn, const char *path, int fail); int dm_config_find_int(const struct dm_config_node *cn, const char *path, int fail);
@ -2114,7 +2111,7 @@ unsigned dm_config_maybe_section(const char *str, unsigned len);
const char *dm_config_parent_name(const struct dm_config_node *n); const char *dm_config_parent_name(const struct dm_config_node *n);
struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *cn, int siblings); struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *node, int siblings);
struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key); struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key);
struct dm_config_value *dm_config_create_value(struct dm_config_tree *cft); struct dm_config_value *dm_config_create_value(struct dm_config_tree *cft);
struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *cn, int siblings); struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *cn, int siblings);
@ -2123,7 +2120,7 @@ struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const st
* Common formatting flags applicable to all config node types (lower 16 bits). * Common formatting flags applicable to all config node types (lower 16 bits).
*/ */
#define DM_CONFIG_VALUE_FMT_COMMON_ARRAY 0x00000001 /* value is array */ #define DM_CONFIG_VALUE_FMT_COMMON_ARRAY 0x00000001 /* value is array */
#define DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES 0x00000002 /* add spaces in "key = value" pairs in contrast to "key=value" for better readability */ #define DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES 0x00000002 /* add spaces in "key = value" pairs in constrast to "key=value" for better readability */
/* /*
* Type-related config node formatting flags (higher 16 bits). * Type-related config node formatting flags (higher 16 bits).
@ -2169,7 +2166,7 @@ struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
*/ */
#define DM_UDEV_DISABLE_DM_RULES_FLAG 0x0001 #define DM_UDEV_DISABLE_DM_RULES_FLAG 0x0001
/* /*
* DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG is set in case we need to disable * DM_UDEV_DISABLE_SUBSYTEM_RULES_FLAG is set in case we need to disable
* subsystem udev rules, but still we need the general DM udev rules to * subsystem udev rules, but still we need the general DM udev rules to
* be applied (to create the nodes and symlinks under /dev and /dev/disk). * be applied (to create the nodes and symlinks under /dev and /dev/disk).
*/ */
@ -2240,7 +2237,7 @@ struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
int dm_cookie_supported(void); int dm_cookie_supported(void);
/* /*
* Udev synchronization functions. * Udev synchronisation functions.
*/ */
void dm_udev_set_sync_support(int sync_with_udev); void dm_udev_set_sync_support(int sync_with_udev);
int dm_udev_get_sync_support(void); int dm_udev_get_sync_support(void);

View File

@ -70,7 +70,6 @@ static unsigned _dm_version_minor = 0;
static unsigned _dm_version_patchlevel = 0; static unsigned _dm_version_patchlevel = 0;
static int _log_suppress = 0; static int _log_suppress = 0;
static struct dm_timestamp *_dm_ioctl_timestamp = NULL; static struct dm_timestamp *_dm_ioctl_timestamp = NULL;
static int _dm_warn_inactive_suppress = 0;
/* /*
* If the kernel dm driver only supports one major number * If the kernel dm driver only supports one major number
@ -88,8 +87,10 @@ static int _version_checked = 0;
static int _version_ok = 1; static int _version_ok = 1;
static unsigned _ioctl_buffer_double_factor = 0; static unsigned _ioctl_buffer_double_factor = 0;
const int _dm_compat = 0;
/* *INDENT-OFF* */ /* *INDENT-OFF* */
static const struct cmd_data _cmd_data_v4[] = { static struct cmd_data _cmd_data_v4[] = {
{"create", DM_DEV_CREATE, {4, 0, 0}}, {"create", DM_DEV_CREATE, {4, 0, 0}},
{"reload", DM_TABLE_LOAD, {4, 0, 0}}, {"reload", DM_TABLE_LOAD, {4, 0, 0}},
{"remove", DM_DEV_REMOVE, {4, 0, 0}}, {"remove", DM_DEV_REMOVE, {4, 0, 0}},
@ -138,6 +139,7 @@ static char *_align(char *ptr, unsigned int a)
return (char *) (((unsigned long) ptr + agn) & ~agn); return (char *) (((unsigned long) ptr + agn) & ~agn);
} }
#ifdef DM_IOCTLS
static unsigned _kernel_major = 0; static unsigned _kernel_major = 0;
static unsigned _kernel_minor = 0; static unsigned _kernel_minor = 0;
static unsigned _kernel_release = 0; static unsigned _kernel_release = 0;
@ -180,9 +182,6 @@ int get_uname_version(unsigned *major, unsigned *minor, unsigned *release)
return 1; return 1;
} }
#ifdef DM_IOCTLS
/* /*
* Set number to NULL to populate _dm_bitset - otherwise first * Set number to NULL to populate _dm_bitset - otherwise first
* match is returned. * match is returned.
@ -199,7 +198,6 @@ static int _get_proc_number(const char *file, const char *name,
char *line = NULL; char *line = NULL;
size_t len; size_t len;
uint32_t num; uint32_t num;
unsigned blocksection = (strcmp(file, PROC_DEVICES) == 0) ? 0 : 1;
if (!(fl = fopen(file, "r"))) { if (!(fl = fopen(file, "r"))) {
log_sys_error("fopen", file); log_sys_error("fopen", file);
@ -207,9 +205,7 @@ static int _get_proc_number(const char *file, const char *name,
} }
while (getline(&line, &len, fl) != -1) { while (getline(&line, &len, fl) != -1) {
if (!blocksection && (line[0] == 'B')) if (sscanf(line, "%u %255s\n", &num, &nm[0]) == 2) {
blocksection = 1;
else if (sscanf(line, "%u %255s\n", &num, &nm[0]) == 2) {
if (!strcmp(name, nm)) { if (!strcmp(name, nm)) {
if (number) { if (number) {
*number = num; *number = num;
@ -249,16 +245,6 @@ static int _control_device_number(uint32_t *major, uint32_t *minor)
return 1; return 1;
} }
static int _control_unlink(const char *control)
{
if (unlink(control) && (errno != ENOENT)) {
log_sys_error("unlink", control);
return -1;
}
return 0;
}
/* /*
* Returns 1 if it exists on returning; 0 if it doesn't; -1 if it's wrong. * Returns 1 if it exists on returning; 0 if it doesn't; -1 if it's wrong.
*/ */
@ -274,7 +260,10 @@ static int _control_exists(const char *control, uint32_t major, uint32_t minor)
if (!S_ISCHR(buf.st_mode)) { if (!S_ISCHR(buf.st_mode)) {
log_verbose("%s: Wrong inode type", control); log_verbose("%s: Wrong inode type", control);
return _control_unlink(control); if (!unlink(control))
return 0;
log_sys_error("unlink", control);
return -1;
} }
if (major && buf.st_rdev != MKDEV(major, minor)) { if (major && buf.st_rdev != MKDEV(major, minor)) {
@ -282,7 +271,10 @@ static int _control_exists(const char *control, uint32_t major, uint32_t minor)
"(%u, %u)", control, "(%u, %u)", control,
MAJOR(buf.st_mode), MINOR(buf.st_mode), MAJOR(buf.st_mode), MINOR(buf.st_mode),
major, minor); major, minor);
return _control_unlink(control); if (!unlink(control))
return 0;
log_sys_error("unlink", control);
return -1;
} }
return 1; return 1;
@ -318,13 +310,8 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
old_umask = umask(DM_CONTROL_NODE_UMASK); old_umask = umask(DM_CONTROL_NODE_UMASK);
if (mknod(control, S_IFCHR | S_IRUSR | S_IWUSR, if (mknod(control, S_IFCHR | S_IRUSR | S_IWUSR,
MKDEV(major, minor)) < 0) { MKDEV(major, minor)) < 0) {
if (errno != EEXIST) { log_sys_error("mknod", control);
log_sys_error("mknod", control); ret = 0;
ret = 0;
} else if (_control_exists(control, major, minor) != 1) {
stack; /* Invalid control node created by parallel command ? */
ret = 0;
}
} }
umask(old_umask); umask(old_umask);
(void) dm_prepare_selinux_context(NULL, 0); (void) dm_prepare_selinux_context(NULL, 0);
@ -410,7 +397,7 @@ static void _close_control_fd(void)
{ {
if (_control_fd != -1) { if (_control_fd != -1) {
if (close(_control_fd) < 0) if (close(_control_fd) < 0)
log_sys_debug("close", "_control_fd"); log_sys_error("close", "_control_fd");
_control_fd = -1; _control_fd = -1;
} }
} }
@ -486,7 +473,7 @@ static void _dm_zfree_string(char *string)
{ {
if (string) { if (string) {
memset(string, 0, strlen(string)); memset(string, 0, strlen(string));
__asm__ volatile ("" ::: "memory"); /* Compiler barrier. */ asm volatile ("" ::: "memory"); /* Compiler barrier. */
free(string); free(string);
} }
} }
@ -495,7 +482,7 @@ static void _dm_zfree_dmi(struct dm_ioctl *dmi)
{ {
if (dmi) { if (dmi) {
memset(dmi, 0, dmi->data_size); memset(dmi, 0, dmi->data_size);
__asm__ volatile ("" ::: "memory"); /* Compiler barrier. */ asm volatile ("" ::: "memory"); /* Compiler barrier. */
free(dmi); free(dmi);
} }
} }
@ -599,9 +586,23 @@ int dm_check_version(void)
_version_checked = 1; _version_checked = 1;
if (_check_version(dmversion, sizeof(dmversion), 0)) if (_check_version(dmversion, sizeof(dmversion), _dm_compat))
return 1; return 1;
if (!_dm_compat)
goto_bad;
log_verbose("device-mapper ioctl protocol version %u failed. "
"Trying protocol version 1.", _dm_version);
_dm_version = 1;
if (_check_version(dmversion, sizeof(dmversion), 0)) {
log_verbose("Using device-mapper ioctl protocol version 1");
return 1;
}
compat = "(compat)";
bad:
dm_get_library_version(libversion, sizeof(libversion)); dm_get_library_version(libversion, sizeof(libversion));
log_error("Incompatible libdevmapper %s%s and kernel driver %s.", log_error("Incompatible libdevmapper %s%s and kernel driver %s.",
@ -660,7 +661,7 @@ void *dm_get_next_target(struct dm_task *dmt, void *next,
return t->next; return t->next;
} }
/* Unmarshal the target info returned from a status call */ /* Unmarshall the target info returned from a status call */
static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi) static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi)
{ {
char *outbuf = (char *) dmi + dmi->data_start; char *outbuf = (char *) dmi + dmi->data_start;
@ -749,11 +750,6 @@ uint32_t dm_task_get_read_ahead(const struct dm_task *dmt, uint32_t *read_ahead)
struct dm_deps *dm_task_get_deps(struct dm_task *dmt) struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
{ {
if (!dmt) {
log_error(INTERNAL_ERROR "Missing dm_task.");
return NULL;
}
return (struct dm_deps *) (((char *) dmt->dmi.v4) + return (struct dm_deps *) (((char *) dmt->dmi.v4) +
dmt->dmi.v4->data_start); dmt->dmi.v4->data_start);
} }
@ -770,7 +766,7 @@ static size_t _align_val(size_t val)
} }
static void *_align_ptr(void *ptr) static void *_align_ptr(void *ptr)
{ {
return (void *)(uintptr_t)_align_val((size_t)ptr); return (void *)_align_val((size_t)ptr);
} }
static int _check_has_event_nr(void) { static int _check_has_event_nr(void) {
@ -783,12 +779,19 @@ static int _check_has_event_nr(void) {
return _has_event_nr; return _has_event_nr;
} }
struct dm_device_list {
struct dm_list list;
unsigned count;
unsigned features;
struct dm_hash_table *uuids;
};
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list, int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
unsigned *devs_features) unsigned *devs_features)
{ {
struct dm_names *names, *names1; struct dm_names *names, *names1;
struct dm_active_device *dm_dev, *dm_new_dev; struct dm_active_device *dm_dev, *dm_new_dev;
struct dm_list *devs; struct dm_device_list *devs;
unsigned next = 0; unsigned next = 0;
uint32_t *event_nr; uint32_t *event_nr;
char *uuid_ptr; char *uuid_ptr;
@ -809,12 +812,12 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
} while (next); } while (next);
} }
/* buffer for devs + sorted ptrs + dm_devs + aligned strings */ if (!(devs = malloc(sizeof(*devs) + (cnt ? cnt * sizeof(*dm_dev) + (char*)names1 - (char*)names + 256 : 0))))
if (!(devs = malloc(sizeof(*devs) + cnt * (2 * sizeof(void*) + sizeof(*dm_dev)) +
(cnt ? (char*)names1 - (char*)names + 256 : 0))))
return_0; return_0;
dm_list_init(devs); dm_list_init(&devs->list);
devs->count = cnt;
devs->uuids = NULL;
if (!cnt) { if (!cnt) {
/* nothing in the list -> mark all features present */ /* nothing in the list -> mark all features present */
@ -822,22 +825,27 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
goto out; /* nothing else to do */ goto out; /* nothing else to do */
} }
/* Shift position where to store individual dm_devs */ dm_dev = (struct dm_active_device *) (devs + 1);
dm_dev = (struct dm_active_device *) ((long*) (devs + 1) + cnt);
do { do {
names = (struct dm_names *)((char *) names + next); names = (struct dm_names *)((char *) names + next);
dm_dev->devno = (dev_t) names->dev; dm_dev->major = MAJOR(names->dev);
dm_dev->name = (const char *)(dm_dev + 1); dm_dev->minor = MINOR(names->dev);
dm_dev->name = (char*)(dm_dev + 1);
dm_dev->event_nr = 0; dm_dev->event_nr = 0;
dm_dev->uuid = ""; dm_dev->uuid = NULL;
strcpy(dm_dev->name, names->name);
len = strlen(names->name) + 1; len = strlen(names->name) + 1;
memcpy((char*)dm_dev->name, names->name, len);
dm_new_dev = _align_ptr((char*)(dm_dev + 1) + len); dm_new_dev = _align_ptr((char*)(dm_dev + 1) + len);
if (_check_has_event_nr()) { if (_check_has_event_nr()) {
/* Hash for UUIDs with some more bits to reduce colision count */
if (!devs->uuids && !(devs->uuids = dm_hash_create(cnt * 8))) {
free(devs);
return_0;
}
*devs_features |= DM_DEVICE_LIST_HAS_EVENT_NR; *devs_features |= DM_DEVICE_LIST_HAS_EVENT_NR;
event_nr = _align_ptr(names->name + len); event_nr = _align_ptr(names->name + len);
@ -846,29 +854,54 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
if ((event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) { if ((event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
*devs_features |= DM_DEVICE_LIST_HAS_UUID; *devs_features |= DM_DEVICE_LIST_HAS_UUID;
uuid_ptr = _align_ptr(event_nr + 2); uuid_ptr = _align_ptr(event_nr + 2);
len = strlen(uuid_ptr) + 1; dm_dev->uuid = (char*) dm_new_dev;
memcpy(dm_new_dev, uuid_ptr, len); dm_new_dev = _align_ptr((char*)dm_new_dev + strlen(uuid_ptr) + 1);
dm_dev->uuid = (const char *) dm_new_dev; strcpy(dm_dev->uuid, uuid_ptr);
dm_new_dev = _align_ptr((char*)dm_new_dev + len); if (!dm_hash_insert(devs->uuids, dm_dev->uuid, dm_dev))
return_0; // FIXME
#if 0
log_debug("Active %s (%s) %d:%d event:%u",
dm_dev->name, dm_dev->uuid,
dm_dev->major, dm_dev->minor, dm_dev->event_nr);
#endif
} }
} }
dm_list_add(devs, &dm_dev->list); dm_list_add(&devs->list, &dm_dev->list);
dm_dev = dm_new_dev; dm_dev = dm_new_dev;
next = names->next; next = names->next;
} while (next); } while (next);
out: out:
*devs_list = devs; *devs_list = (struct dm_list *)devs;
return 1; return 1;
} }
int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
const struct dm_active_device **dev)
{
struct dm_device_list *devs = (struct dm_device_list *) devs_list;
struct dm_active_device *dm_dev;
if (devs->uuids &&
(dm_dev = dm_hash_lookup(devs->uuids, uuid))) {
if (dev)
*dev = dm_dev;
return 1;
}
return 0;
}
void dm_device_list_destroy(struct dm_list **devs_list) void dm_device_list_destroy(struct dm_list **devs_list)
{ {
struct dm_device_list *devs = (struct dm_device_list *) *devs_list; struct dm_device_list *devs = (struct dm_device_list *) *devs_list;
if (devs) { if (devs) {
if (devs->uuids)
dm_hash_destroy(devs->uuids);
free(devs); free(devs);
*devs_list = NULL; *devs_list = NULL;
} }
@ -1161,10 +1194,9 @@ static char *_add_target(struct target *t, char *out, char *end)
while (*pt) while (*pt)
if (*pt++ == '\\') if (*pt++ == '\\')
backslash_count++; backslash_count++;
len = strlen(t->params) + backslash_count;
len = strlen(t->params) + 1; if ((out >= end) || (out + len + 1) >= end) {
if ((out >= end) || (out + len + backslash_count) >= end) {
log_error("Ran out of memory building ioctl parameter"); log_error("Ran out of memory building ioctl parameter");
return NULL; return NULL;
} }
@ -1180,8 +1212,8 @@ static char *_add_target(struct target *t, char *out, char *end)
*out++ = '\0'; *out++ = '\0';
} }
else { else {
memcpy(out, t->params, len); strcpy(out, t->params);
out += len + backslash_count; out += len + 1;
} }
/* align next block */ /* align next block */
@ -1215,7 +1247,7 @@ static int _lookup_dev_name(uint64_t dev, char *buf, size_t len)
do { do {
names = (struct dm_names *)((char *) names + next); names = (struct dm_names *)((char *) names + next);
if (names->dev == dev) { if (names->dev == dev) {
memccpy(buf, names->name, 0, len); strncpy(buf, names->name, len);
r = 1; r = 1;
break; break;
} }
@ -1252,7 +1284,6 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
struct target *t; struct target *t;
struct dm_target_msg *tmsg; struct dm_target_msg *tmsg;
size_t len = sizeof(struct dm_ioctl); size_t len = sizeof(struct dm_ioctl);
size_t message_len = 0, newname_len = 0, geometry_len = 0;
char *b, *e; char *b, *e;
int count = 0; int count = 0;
@ -1313,20 +1344,14 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
return NULL; return NULL;
} }
if (dmt->newname) { if (dmt->newname)
newname_len = strlen(dmt->newname) + 1; len += strlen(dmt->newname) + 1;
len += newname_len;
}
if (dmt->message) { if (dmt->message)
message_len = strlen(dmt->message) + 1; len += sizeof(struct dm_target_msg) + strlen(dmt->message) + 1;
len += sizeof(struct dm_target_msg) + message_len;
}
if (dmt->geometry) { if (dmt->geometry)
geometry_len = strlen(dmt->geometry) + 1; len += strlen(dmt->geometry) + 1;
len += geometry_len;
}
/* /*
* Give len a minimum size so that we have space to store * Give len a minimum size so that we have space to store
@ -1384,10 +1409,12 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
/* FIXME Until resume ioctl supplies name, use dev_name for readahead */ /* FIXME Until resume ioctl supplies name, use dev_name for readahead */
if (DEV_NAME(dmt) && (dmt->type != DM_DEVICE_RESUME || dmt->minor < 0 || if (DEV_NAME(dmt) && (dmt->type != DM_DEVICE_RESUME || dmt->minor < 0 ||
dmt->major < 0)) dmt->major < 0))
memccpy(dmi->name, DEV_NAME(dmt), 0, sizeof(dmi->name)); /* coverity[buffer_size_warning] */
strncpy(dmi->name, DEV_NAME(dmt), sizeof(dmi->name));
if (DEV_UUID(dmt)) if (DEV_UUID(dmt))
memccpy(dmi->uuid, DEV_UUID(dmt), 0, sizeof(dmi->uuid)); /* coverity[buffer_size_warning] */
strncpy(dmi->uuid, DEV_UUID(dmt), sizeof(dmi->uuid));
if (dmt->type == DM_DEVICE_SUSPEND) if (dmt->type == DM_DEVICE_SUSPEND)
dmi->flags |= DM_SUSPEND_FLAG; dmi->flags |= DM_SUSPEND_FLAG;
@ -1413,23 +1440,22 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
} }
if (dmt->query_inactive_table) { if (dmt->query_inactive_table) {
if (!_dm_inactive_supported()) if (!_dm_inactive_supported())
log_warn_suppress(_dm_warn_inactive_suppress++, log_warn("WARNING: Inactive table query unsupported "
"WARNING: Inactive table query unsupported by kernel. " "by kernel. It will use live table.");
"It will use live table.");
dmi->flags |= DM_QUERY_INACTIVE_TABLE_FLAG; dmi->flags |= DM_QUERY_INACTIVE_TABLE_FLAG;
} }
if (dmt->new_uuid) { if (dmt->new_uuid) {
if (_dm_version_minor < 19) { if (_dm_version_minor < 19) {
log_error("Setting UUID unsupported by kernel. " log_error("WARNING: Setting UUID unsupported by "
"Aborting operation."); "kernel. Aborting operation.");
goto bad; goto bad;
} }
dmi->flags |= DM_UUID_FLAG; dmi->flags |= DM_UUID_FLAG;
} }
if (dmt->ima_measurement) { if (dmt->ima_measurement) {
if (_dm_version_minor < 45) { if (_dm_version_minor < 45) {
log_error("IMA measurement unsupported by kernel. " log_error("WARNING: IMA measurement unsupported by "
"Aborting operation."); "kernel. Aborting operation.");
goto bad; goto bad;
} }
dmi->flags |= DM_IMA_MEASUREMENT_FLAG; dmi->flags |= DM_IMA_MEASUREMENT_FLAG;
@ -1447,16 +1473,16 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
goto_bad; goto_bad;
if (dmt->newname) if (dmt->newname)
memcpy(b, dmt->newname, newname_len); strcpy(b, dmt->newname);
if (dmt->message) { if (dmt->message) {
tmsg = (struct dm_target_msg *) b; tmsg = (struct dm_target_msg *) b;
tmsg->sector = dmt->sector; tmsg->sector = dmt->sector;
memcpy(tmsg->message, dmt->message, message_len); strcpy(tmsg->message, dmt->message);
} }
if (dmt->geometry) if (dmt->geometry)
memcpy(b, dmt->geometry, geometry_len); strcpy(b, dmt->geometry);
return dmi; return dmi;
@ -1578,7 +1604,7 @@ static int _check_uevent_generated(struct dm_ioctl *dmi)
static int _create_and_load_v4(struct dm_task *dmt) static int _create_and_load_v4(struct dm_task *dmt)
{ {
struct dm_task *task; struct dm_task *task;
int r, ioctl_errno = 0; int r;
uint32_t cookie; uint32_t cookie;
/* Use new task struct to create the device */ /* Use new task struct to create the device */
@ -1604,10 +1630,8 @@ static int _create_and_load_v4(struct dm_task *dmt)
task->cookie_set = dmt->cookie_set; task->cookie_set = dmt->cookie_set;
task->add_node = dmt->add_node; task->add_node = dmt->add_node;
if (!dm_task_run(task)) { if (!dm_task_run(task))
ioctl_errno = task->ioctl_errno;
goto_bad; goto_bad;
}
dm_task_destroy(task); dm_task_destroy(task);
@ -1633,8 +1657,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
task->ima_measurement = dmt->ima_measurement; task->ima_measurement = dmt->ima_measurement;
r = dm_task_run(task); r = dm_task_run(task);
if (!r)
ioctl_errno = task->ioctl_errno;
task->head = NULL; task->head = NULL;
task->tail = NULL; task->tail = NULL;
@ -1652,7 +1674,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
dmt->uuid = NULL; dmt->uuid = NULL;
free(dmt->mangled_uuid); free(dmt->mangled_uuid);
dmt->mangled_uuid = NULL; dmt->mangled_uuid = NULL;
/* coverity[double_free] recursive function call */
_dm_task_free_targets(dmt); _dm_task_free_targets(dmt);
if (dm_task_run(dmt)) if (dm_task_run(dmt))
@ -1664,7 +1685,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
dmt->uuid = NULL; dmt->uuid = NULL;
free(dmt->mangled_uuid); free(dmt->mangled_uuid);
dmt->mangled_uuid = NULL; dmt->mangled_uuid = NULL;
/* coverity[double_free] recursive function call */
_dm_task_free_targets(dmt); _dm_task_free_targets(dmt);
/* /*
@ -1683,18 +1703,12 @@ static int _create_and_load_v4(struct dm_task *dmt)
if (!dm_task_run(dmt)) if (!dm_task_run(dmt))
log_error("Failed to revert device creation."); log_error("Failed to revert device creation.");
if (ioctl_errno != 0)
dmt->ioctl_errno = ioctl_errno;
return 0; return 0;
bad: bad:
dm_task_destroy(task); dm_task_destroy(task);
_udev_complete(dmt); _udev_complete(dmt);
if (ioctl_errno != 0)
dmt->ioctl_errno = ioctl_errno;
return 0; return 0;
} }
@ -2036,7 +2050,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
/* /*
* Prevent udev vs. libdevmapper race when processing nodes * Prevent udev vs. libdevmapper race when processing nodes
* and symlinks. This can happen when the udev rules are * and symlinks. This can happen when the udev rules are
* installed and udev synchronization code is enabled in * installed and udev synchronisation code is enabled in
* libdevmapper but the software using libdevmapper does not * libdevmapper but the software using libdevmapper does not
* make use of it (by not calling dm_task_set_cookie before). * make use of it (by not calling dm_task_set_cookie before).
* We need to instruct the udev rules not to be applied at * We need to instruct the udev rules not to be applied at
@ -2046,7 +2060,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
if (!dmt->cookie_set && dm_udev_get_sync_support()) { if (!dmt->cookie_set && dm_udev_get_sync_support()) {
log_debug_activation("Cookie value is not set while trying to call %s " log_debug_activation("Cookie value is not set while trying to call %s "
"ioctl. Please, consider using libdevmapper's udev " "ioctl. Please, consider using libdevmapper's udev "
"synchronization interface or disable it explicitly " "synchronisation interface or disable it explicitly "
"by calling dm_udev_set_sync_support(0).", "by calling dm_udev_set_sync_support(0).",
dmt->type == DM_DEVICE_RESUME ? "DM_DEVICE_RESUME" : dmt->type == DM_DEVICE_RESUME ? "DM_DEVICE_RESUME" :
dmt->type == DM_DEVICE_REMOVE ? "DM_DEVICE_REMOVE" : dmt->type == DM_DEVICE_REMOVE ? "DM_DEVICE_REMOVE" :

View File

@ -16,8 +16,6 @@
#ifndef LIB_DMTARGETS_H #ifndef LIB_DMTARGETS_H
#define LIB_DMTARGETS_H #define LIB_DMTARGETS_H
#include "device_mapper/all.h"
#include <inttypes.h> #include <inttypes.h>
#include <sys/types.h> #include <sys/types.h>
@ -81,7 +79,7 @@ struct dm_task {
}; };
struct cmd_data { struct cmd_data {
const char name[16]; const char *name;
const unsigned cmd; const unsigned cmd;
const int version[3]; const int version[3];
}; };

View File

@ -511,7 +511,7 @@ int unmangle_string(const char *str, const char *str_name, size_t len,
char *buf, size_t buf_len, dm_string_mangling_t mode) char *buf, size_t buf_len, dm_string_mangling_t mode)
{ {
int strict = mode != DM_STRING_MANGLING_NONE; int strict = mode != DM_STRING_MANGLING_NONE;
char str_rest[DM_NAME_LEN + 1]; char str_rest[DM_NAME_LEN];
size_t i, j; size_t i, j;
unsigned int code; unsigned int code;
int r = 0; int r = 0;
@ -537,8 +537,7 @@ int unmangle_string(const char *str, const char *str_name, size_t len,
} }
if (str[i] == '\\' && str[i+1] == 'x') { if (str[i] == '\\' && str[i+1] == 'x') {
if (!sscanf(&str[i+2], "%2x%" DM_TO_STRING(DM_NAME_LEN) "s", if (!sscanf(&str[i+2], "%2x%s", &code, str_rest)) {
&code, str_rest)) {
log_debug_activation("Hex encoding mismatch detected in %s \"%s\" " log_debug_activation("Hex encoding mismatch detected in %s \"%s\" "
"while trying to unmangle it.", str_name, str); "while trying to unmangle it.", str_name, str);
goto out; goto out;
@ -1061,8 +1060,9 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
if (info.st_rdev == dev) if (info.st_rdev == dev)
return 1; return 1;
if (unlink(path) && (errno != ENOENT)) { if (unlink(path) < 0) {
log_sys_error("unlink", path); log_error("Unable to unlink device node for '%s'",
dev_name);
return 0; return 0;
} }
} else if (_warn_if_op_needed(warn_if_udev_failed)) } else if (_warn_if_op_needed(warn_if_udev_failed))
@ -1106,8 +1106,8 @@ static int _rm_dev_node(const char *dev_name, int warn_if_udev_failed)
"Falling back to direct node removal.", path); "Falling back to direct node removal.", path);
/* udev may already have deleted the node. Ignore ENOENT. */ /* udev may already have deleted the node. Ignore ENOENT. */
if (unlink(path) && (errno != ENOENT)) { if (unlink(path) < 0 && errno != ENOENT) {
log_sys_error("unlink", path); log_error("Unable to unlink device node for '%s'", dev_name);
return 0; return 0;
} }
@ -1451,10 +1451,9 @@ struct node_op_parms {
static void _store_str(char **pos, char **ptr, const char *str) static void _store_str(char **pos, char **ptr, const char *str)
{ {
size_t len = strlen(str) + 1; strcpy(*pos, str);
memcpy(*pos, str, len);
*ptr = *pos; *ptr = *pos;
*pos += len; *pos += strlen(*ptr) + 1;
} }
static void _del_node_op(struct node_op_parms *nop) static void _del_node_op(struct node_op_parms *nop)
@ -1704,17 +1703,15 @@ const char *dm_sysfs_dir(void)
*/ */
int dm_set_uuid_prefix(const char *uuid_prefix) int dm_set_uuid_prefix(const char *uuid_prefix)
{ {
size_t len;
if (!uuid_prefix) if (!uuid_prefix)
return_0; return_0;
if ((len = strlen(uuid_prefix)) > DM_MAX_UUID_PREFIX_LEN) { if (strlen(uuid_prefix) > DM_MAX_UUID_PREFIX_LEN) {
log_error("New uuid prefix %s too long.", uuid_prefix); log_error("New uuid prefix %s too long.", uuid_prefix);
return 0; return 0;
} }
memcpy(_default_uuid_prefix, uuid_prefix, len + 1); strcpy(_default_uuid_prefix, uuid_prefix);
return 1; return 1;
} }
@ -1743,9 +1740,6 @@ static void _unmangle_mountinfo_string(const char *src, char *buf)
*buf = '\0'; *buf = '\0';
} }
/* coverity[+tainted_string_sanitize_content:arg-0] */
static int _sanitize_line(const char *line) { return 1; }
/* Parse one line of mountinfo and unmangled target line */ /* Parse one line of mountinfo and unmangled target line */
static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min, char *buf) static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min, char *buf)
{ {
@ -1796,7 +1790,7 @@ static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min,
} }
/* /*
* Function to operate on individual mountinfo line, * Function to operate on individal mountinfo line,
* minor, major and mount target are parsed and unmangled * minor, major and mount target are parsed and unmangled
*/ */
int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data) int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data)
@ -1816,8 +1810,7 @@ int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data)
} }
while (!feof(minfo) && fgets(buffer, sizeof(buffer), minfo)) while (!feof(minfo) && fgets(buffer, sizeof(buffer), minfo))
if (!_sanitize_line(buffer) || if (!_mountinfo_parse_line(buffer, &maj, &min, target) ||
!_mountinfo_parse_line(buffer, &maj, &min, target) ||
!read_fn(buffer, maj, min, target, cb_data)) { !read_fn(buffer, maj, min, target, cb_data)) {
stack; stack;
r = 0; r = 0;
@ -1832,27 +1825,32 @@ int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data)
static int _sysfs_get_dm_name(uint32_t major, uint32_t minor, char *buf, size_t buf_size) static int _sysfs_get_dm_name(uint32_t major, uint32_t minor, char *buf, size_t buf_size)
{ {
char sysfs_path[PATH_MAX], temp_buf[2 * DM_NAME_LEN]; char *sysfs_path, *temp_buf = NULL;
FILE *fp = NULL; FILE *fp = NULL;
int r = 0; int r = 0;
size_t len; size_t len;
if (dm_snprintf(sysfs_path, sizeof(sysfs_path), if (!(sysfs_path = malloc(PATH_MAX)) ||
"%sdev/block/%" PRIu32 ":%" PRIu32 !(temp_buf = malloc(PATH_MAX))) {
log_error("_sysfs_get_dm_name: failed to allocate temporary buffers");
goto bad;
}
if (dm_snprintf(sysfs_path, PATH_MAX, "%sdev/block/%" PRIu32 ":%" PRIu32
"/dm/name", _sysfs_dir, major, minor) < 0) { "/dm/name", _sysfs_dir, major, minor) < 0) {
log_error("_sysfs_get_dm_name: dm_snprintf failed."); log_error("_sysfs_get_dm_name: dm_snprintf failed");
goto bad; goto bad;
} }
if (!(fp = fopen(sysfs_path, "r"))) { if (!(fp = fopen(sysfs_path, "r"))) {
if (errno == ENOENT) if (errno != ENOENT)
log_sys_debug("fopen", sysfs_path);
else
log_sys_error("fopen", sysfs_path); log_sys_error("fopen", sysfs_path);
else
log_sys_debug("fopen", sysfs_path);
goto bad; goto bad;
} }
if (!fgets(temp_buf, sizeof(temp_buf), fp)) { if (!fgets(temp_buf, PATH_MAX, fp)) {
log_sys_error("fgets", sysfs_path); log_sys_error("fgets", sysfs_path);
goto bad; goto bad;
} }
@ -1860,21 +1858,20 @@ static int _sysfs_get_dm_name(uint32_t major, uint32_t minor, char *buf, size_t
len = strlen(temp_buf); len = strlen(temp_buf);
if (len > buf_size) { if (len > buf_size) {
log_error("_sysfs_get_dm_name: supplied buffer too small."); log_error("_sysfs_get_dm_name: supplied buffer too small");
goto bad; goto bad;
} }
if (len) temp_buf[len ? len - 1 : 0] = '\0'; /* \n */
--len; /* strip \n */ strcpy(buf, temp_buf);
memcpy(buf, temp_buf, len);
buf[len] = '\0';
r = 1; r = 1;
bad: bad:
if (fp && fclose(fp)) if (fp && fclose(fp))
log_sys_error("fclose", sysfs_path); log_sys_error("fclose", sysfs_path);
free(temp_buf);
free(sysfs_path);
return r; return r;
} }
@ -1957,7 +1954,7 @@ static int _sysfs_find_kernel_name(uint32_t major, uint32_t minor, char *buf, si
!strcmp(name_dev, "holders") || !strcmp(name_dev, "holders") ||
!strcmp(name_dev, "integrity") || !strcmp(name_dev, "integrity") ||
!strcmp(name_dev, "loop") || !strcmp(name_dev, "loop") ||
!strcmp(name_dev, "queue") || !strcmp(name_dev, "queueu") ||
!strcmp(name_dev, "md") || !strcmp(name_dev, "md") ||
!strcmp(name_dev, "mq") || !strcmp(name_dev, "mq") ||
!strcmp(name_dev, "power") || !strcmp(name_dev, "power") ||
@ -2314,7 +2311,7 @@ static int _check_semaphore_is_supported(void)
if (maxid < 0) { if (maxid < 0) {
log_warn("Kernel not configured for semaphores (System V IPC). " log_warn("Kernel not configured for semaphores (System V IPC). "
"Not using udev synchronization code."); "Not using udev synchronisation code.");
return 0; return 0;
} }
@ -2337,7 +2334,7 @@ static int _check_udev_is_running(void)
if (!(r = udev_queue_get_udev_is_active(udev_queue))) if (!(r = udev_queue_get_udev_is_active(udev_queue)))
log_debug_activation("Udev is not running. " log_debug_activation("Udev is not running. "
"Not using udev synchronization code."); "Not using udev synchronisation code.");
udev_queue_unref(udev_queue); udev_queue_unref(udev_queue);
udev_unref(udev); udev_unref(udev);
@ -2412,7 +2409,7 @@ static int _get_cookie_sem(uint32_t cookie, int *semid)
break; break;
case EACCES: case EACCES:
log_error("No permission to access " log_error("No permission to access "
"notification semaphore identified " "notificaton semaphore identified "
"by cookie value %" PRIu32 " (0x%x)", "by cookie value %" PRIu32 " (0x%x)",
cookie, cookie); cookie, cookie);
break; break;
@ -2433,20 +2430,20 @@ static int _udev_notify_sem_inc(uint32_t cookie, int semid)
int val; int val;
if (semop(semid, &sb, 1) < 0) { if (semop(semid, &sb, 1) < 0) {
log_error("cookie inc: semid %d: semop failed for cookie 0x%" PRIx32 ": %s", log_error("semid %d: semop failed for cookie 0x%" PRIx32 ": %s",
semid, cookie, strerror(errno)); semid, cookie, strerror(errno));
return 0; return 0;
} }
if ((val = semctl(semid, 0, GETVAL)) < 0) { if ((val = semctl(semid, 0, GETVAL)) < 0) {
log_warn("cookie inc: semid %d: sem_ctl GETVAL failed for " log_error("semid %d: sem_ctl GETVAL failed for "
"cookie 0x%" PRIx32 ": %s", "cookie 0x%" PRIx32 ": %s",
semid, cookie, strerror(errno)); semid, cookie, strerror(errno));
log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) incremented.", return 0;
cookie, semid); }
} else
log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) incremented to %d", log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) incremented to %d",
cookie, semid, val); cookie, semid, val);
return 1; return 1;
} }
@ -2456,21 +2453,23 @@ static int _udev_notify_sem_dec(uint32_t cookie, int semid)
struct sembuf sb = {0, -1, IPC_NOWAIT}; struct sembuf sb = {0, -1, IPC_NOWAIT};
int val; int val;
if ((val = semctl(semid, 0, GETVAL)) < 0) if ((val = semctl(semid, 0, GETVAL)) < 0) {
log_warn("cookie dec: semid %d: sem_ctl GETVAL failed for " log_error("semid %d: sem_ctl GETVAL failed for "
"cookie 0x%" PRIx32 ": %s", "cookie 0x%" PRIx32 ": %s",
semid, cookie, strerror(errno)); semid, cookie, strerror(errno));
return 0;
}
if (semop(semid, &sb, 1) < 0) { if (semop(semid, &sb, 1) < 0) {
switch (errno) { switch (errno) {
case EAGAIN: case EAGAIN:
log_error("cookie dec: semid %d: semop failed for cookie " log_error("semid %d: semop failed for cookie "
"0x%" PRIx32 ": " "0x%" PRIx32 ": "
"incorrect semaphore state", "incorrect semaphore state",
semid, cookie); semid, cookie);
break; break;
default: default:
log_error("cookie dec: semid %d: semop failed for cookie " log_error("semid %d: semop failed for cookie "
"0x%" PRIx32 ": %s", "0x%" PRIx32 ": %s",
semid, cookie, strerror(errno)); semid, cookie, strerror(errno));
break; break;
@ -2478,12 +2477,9 @@ static int _udev_notify_sem_dec(uint32_t cookie, int semid)
return 0; return 0;
} }
if (val < 0) log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) decremented to %d",
log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) decremented.", cookie, semid, val - 1);
cookie, semid);
else
log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) decremented to %d",
cookie, semid, val - 1);
return 1; return 1;
} }
@ -2560,7 +2556,7 @@ static int _udev_notify_sem_create(uint32_t *cookie, int *semid)
sem_arg.val = 1; sem_arg.val = 1;
if (semctl(gen_semid, 0, SETVAL, sem_arg) < 0) { if (semctl(gen_semid, 0, SETVAL, sem_arg) < 0) {
log_error("cookie create: semid %d: semctl failed: %s", gen_semid, strerror(errno)); log_error("semid %d: semctl failed: %s", gen_semid, strerror(errno));
/* We have to destroy just created semaphore /* We have to destroy just created semaphore
* so it won't stay in the system. */ * so it won't stay in the system. */
(void) _udev_notify_sem_destroy(gen_cookie, gen_semid); (void) _udev_notify_sem_destroy(gen_cookie, gen_semid);
@ -2568,10 +2564,9 @@ static int _udev_notify_sem_create(uint32_t *cookie, int *semid)
} }
if ((val = semctl(gen_semid, 0, GETVAL)) < 0) { if ((val = semctl(gen_semid, 0, GETVAL)) < 0) {
log_error("cookie create: semid %d: sem_ctl GETVAL failed for " log_error("semid %d: sem_ctl GETVAL failed for "
"cookie 0x%" PRIx32 ": %s", "cookie 0x%" PRIx32 ": %s",
gen_semid, gen_cookie, strerror(errno)); gen_semid, gen_cookie, strerror(errno));
(void) _udev_notify_sem_destroy(gen_cookie, gen_semid);
goto bad; goto bad;
} }

View File

@ -36,7 +36,7 @@ struct target *create_target(uint64_t start,
uint64_t len, uint64_t len,
const char *type, const char *params); const char *type, const char *params);
int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor, int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major,
uid_t uid, gid_t gid, mode_t mode, int check_udev, unsigned rely_on_udev); uid_t uid, gid_t gid, mode_t mode, int check_udev, unsigned rely_on_udev);
int rm_dev_node(const char *dev_name, int check_udev, unsigned rely_on_udev); int rm_dev_node(const char *dev_name, int check_udev, unsigned rely_on_udev);
int rename_dev_node(const char *old_name, const char *new_name, int rename_dev_node(const char *old_name, const char *new_name,

View File

@ -53,8 +53,6 @@ struct parser {
int no_dup_node_check; /* whether to disable dup node checking */ int no_dup_node_check; /* whether to disable dup node checking */
const char *key; /* last obtained key */ const char *key; /* last obtained key */
unsigned ignored_creation_time; unsigned ignored_creation_time;
unsigned section_indent;
const char *stop_after_section;
}; };
struct config_output { struct config_output {
@ -72,11 +70,12 @@ static struct dm_config_value *_value(struct parser *p);
static struct dm_config_value *_type(struct parser *p); static struct dm_config_value *_type(struct parser *p);
static int _match_aux(struct parser *p, int t); static int _match_aux(struct parser *p, int t);
static struct dm_config_value *_create_value(struct dm_pool *mem); static struct dm_config_value *_create_value(struct dm_pool *mem);
static struct dm_config_value *_create_str_value(struct dm_pool *mem, const char *str, size_t str_len); static struct dm_config_node *_create_node(struct dm_pool *mem);
static struct dm_config_node *_create_node(struct dm_pool *mem, const char *key, size_t key_len);
static char *_dup_tok(struct parser *p); static char *_dup_tok(struct parser *p);
static char *_dup_token(struct dm_pool *mem, const char *b, const char *e); static char *_dup_token(struct dm_pool *mem, const char *b, const char *e);
static const int _sep = '/';
#define MAX_INDENT 32 #define MAX_INDENT 32
#define match(t) do {\ #define match(t) do {\
@ -87,24 +86,20 @@ static char *_dup_token(struct dm_pool *mem, const char *b, const char *e);
} \ } \
} while(0) } while(0)
/* match token */
static int _tok_match(const char *str, const char *b, const char *e) static int _tok_match(const char *str, const char *b, const char *e)
{ {
while (b < e) { while (*str && (b != e)) {
if (!*str || if (*str++ != *b++)
(*str != *b))
return 0; return 0;
++str;
++b;
} }
return !*str; /* token is matching for \0 end */ return !(*str || (b != e));
} }
struct dm_config_tree *dm_config_create(void) struct dm_config_tree *dm_config_create(void)
{ {
struct dm_config_tree *cft; struct dm_config_tree *cft;
struct dm_pool *mem = dm_pool_create("config", 63 * 1024); struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
if (!mem) { if (!mem) {
log_error("Failed to allocate config pool."); log_error("Failed to allocate config pool.");
@ -178,24 +173,23 @@ static struct dm_config_node *_config_reverse(struct dm_config_node *head)
return middle; return middle;
} }
static int _do_dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end, static int _do_dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end, int no_dup_node_check)
int no_dup_node_check, const char *section)
{ {
/* TODO? if (start == end) return 1; */ /* TODO? if (start == end) return 1; */
struct parser p = { struct parser *p;
.mem = cft->mem, if (!(p = dm_pool_zalloc(cft->mem, sizeof(*p))))
.tb = start, return_0;
.te = start,
.fb = start,
.fe = end,
.line = 1,
.stop_after_section = section,
.no_dup_node_check = no_dup_node_check
};
_get_token(&p, TOK_SECTION_E); p->mem = cft->mem;
if (!(cft->root = _file(&p))) p->fb = start;
p->fe = end;
p->tb = p->te = p->fb;
p->line = 1;
p->no_dup_node_check = no_dup_node_check;
_get_token(p, TOK_SECTION_E);
if (!(cft->root = _file(p)))
return_0; return_0;
cft->root = _config_reverse(cft->root); cft->root = _config_reverse(cft->root);
@ -205,23 +199,12 @@ static int _do_dm_config_parse(struct dm_config_tree *cft, const char *start, co
int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end) int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end)
{ {
return _do_dm_config_parse(cft, start, end, 0, NULL); return _do_dm_config_parse(cft, start, end, 0);
} }
int dm_config_parse_without_dup_node_check(struct dm_config_tree *cft, const char *start, const char *end) int dm_config_parse_without_dup_node_check(struct dm_config_tree *cft, const char *start, const char *end)
{ {
return _do_dm_config_parse(cft, start, end, 1, NULL); return _do_dm_config_parse(cft, start, end, 1);
}
/*
* Stop parsing more sections after given section is parsed.
* Only non-section config nodes are then still parsed.
* It can be useful, when parsing i.e. lvm2 metadata and only physical_volumes config node is needed.
* This function is automatically running without_dup_node_check.
*/
int dm_config_parse_only_section(struct dm_config_tree *cft, const char *start, const char *end, const char *section)
{
return _do_dm_config_parse(cft, start, end, 1, section);
} }
struct dm_config_tree *dm_config_from_string(const char *config_settings) struct dm_config_tree *dm_config_from_string(const char *config_settings)
@ -487,33 +470,23 @@ int dm_config_write_node_out(const struct dm_config_node *cn,
/* /*
* parser * parser
*/ */
static const char *_string_tok(struct parser *p, size_t *len) static char *_dup_string_tok(struct parser *p)
{ {
ptrdiff_t d = p->te - p->tb; char *str;
if (d < 2) { p->tb++, p->te--; /* strip "'s */
if (p->te < p->tb) {
log_error("Parse error at byte %" PRIptrdiff_t " (line %d): " log_error("Parse error at byte %" PRIptrdiff_t " (line %d): "
"expected a string token.", "expected a string token.",
p->tb - p->fb + 1, p->line); p->tb - p->fb + 1, p->line);
return NULL; return NULL;
} }
*len = (size_t)(d - 2); /* strip "'s */ if (!(str = _dup_tok(p)))
return p->tb + 1;
}
static char *_dup_string_tok(struct parser *p)
{
const char *tok;
size_t len;
char *str;
if (!(tok = _string_tok(p, &len)))
return_NULL; return_NULL;
if (!(str = _dup_token(p->mem, tok, tok + len))) p->te++;
return_NULL;
return str; return str;
} }
@ -535,9 +508,10 @@ static struct dm_config_node *_make_node(struct dm_pool *mem,
{ {
struct dm_config_node *n; struct dm_config_node *n;
if (!(n = _create_node(mem, key_b, key_e - key_b))) if (!(n = _create_node(mem)))
return_NULL; return_NULL;
n->key = _dup_token(mem, key_b, key_e);
if (parent) { if (parent) {
n->parent = parent; n->parent = parent;
n->sib = parent->child; n->sib = parent->child;
@ -552,18 +526,17 @@ static struct dm_config_node *_find_or_make_node(struct dm_pool *mem,
const char *path, const char *path,
int no_dup_node_check) int no_dup_node_check)
{ {
const int sep = '/';
const char *e; const char *e;
struct dm_config_node *cn = parent ? parent->child : NULL; struct dm_config_node *cn = parent ? parent->child : NULL;
struct dm_config_node *cn_found = NULL; struct dm_config_node *cn_found = NULL;
while (cn || mem) { while (cn || mem) {
/* trim any leading slashes */ /* trim any leading slashes */
while (*path && (*path == sep)) while (*path && (*path == _sep))
path++; path++;
/* find the end of this segment */ /* find the end of this segment */
for (e = path; *e && (*e != sep); e++) ; for (e = path; *e && (*e != _sep); e++) ;
/* hunt for the node */ /* hunt for the node */
cn_found = NULL; cn_found = NULL;
@ -607,8 +580,6 @@ static struct dm_config_node *_section(struct parser *p, struct dm_config_node *
struct dm_config_node *root; struct dm_config_node *root;
struct dm_config_value *value; struct dm_config_value *value;
char *str; char *str;
size_t len;
char buf[8192];
if (p->t == TOK_STRING_ESCAPED) { if (p->t == TOK_STRING_ESCAPED) {
if (!(str = _dup_string_tok(p))) if (!(str = _dup_string_tok(p)))
@ -622,16 +593,9 @@ static struct dm_config_node *_section(struct parser *p, struct dm_config_node *
match(TOK_STRING); match(TOK_STRING);
} else { } else {
len = p->te - p->tb; if (!(str = _dup_tok(p)))
if (len < (sizeof(buf) - 1)) { return_NULL;
/* Use stack for smaller string */
str = buf;
memcpy(str, p->tb, len);
str[len] = '\0';
} else {
if (!(str = _dup_tok(p)))
return_NULL;
}
match(TOK_IDENTIFIER); match(TOK_IDENTIFIER);
} }
@ -645,28 +609,12 @@ static struct dm_config_node *_section(struct parser *p, struct dm_config_node *
return_NULL; return_NULL;
if (p->t == TOK_SECTION_B) { if (p->t == TOK_SECTION_B) {
if (p->stop_after_section)
++p->section_indent;
match(TOK_SECTION_B); match(TOK_SECTION_B);
while (p->t != TOK_SECTION_E) { while (p->t != TOK_SECTION_E) {
if (!(_section(p, root))) if (!(_section(p, root)))
return_NULL; return_NULL;
} }
match(TOK_SECTION_E); match(TOK_SECTION_E);
if (p->stop_after_section && (--p->section_indent == 1)) {
if (!strcmp(str, p->stop_after_section)) {
/* Found stopping section name -> parsing is finished.
* Now try to find the sequence "\n}\n" from end of b
* parsed buffer to continue filling remaining nodes */
for (p->te = p->fe - 1; p->te > p->tb; --p->te)
if ((p->te[-2] == '\n') &&
(p->te[-1] == '}') &&
(p->te[ 0] == '\n')) {
p->t = TOK_SECTION_E;
break;
}
}
}
} else { } else {
match(TOK_EQ); match(TOK_EQ);
p->key = root->key; p->key = root->key;
@ -723,14 +671,16 @@ static struct dm_config_value *_value(struct parser *p)
static struct dm_config_value *_type(struct parser *p) static struct dm_config_value *_type(struct parser *p)
{ {
/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */ /* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
struct dm_config_value *v; struct dm_config_value *v = _create_value(p->mem);
const char *str; char *str;
size_t len;
if (!v) {
log_error("Failed to allocate type value");
return NULL;
}
switch (p->t) { switch (p->t) {
case TOK_INT: case TOK_INT:
if (!(v = _create_value(p->mem)))
break;
v->type = DM_CFG_INT; v->type = DM_CFG_INT;
errno = 0; errno = 0;
v->v.i = strtoll(p->tb, NULL, 0); /* FIXME: check error */ v->v.i = strtoll(p->tb, NULL, 0); /* FIXME: check error */
@ -751,8 +701,6 @@ static struct dm_config_value *_type(struct parser *p)
break; break;
case TOK_FLOAT: case TOK_FLOAT:
if (!(v = _create_value(p->mem)))
break;
v->type = DM_CFG_FLOAT; v->type = DM_CFG_FLOAT;
errno = 0; errno = 0;
v->v.f = strtod(p->tb, NULL); /* FIXME: check error */ v->v.f = strtod(p->tb, NULL); /* FIXME: check error */
@ -764,31 +712,31 @@ static struct dm_config_value *_type(struct parser *p)
break; break;
case TOK_STRING: case TOK_STRING:
if (!(str = _string_tok(p, &len))) v->type = DM_CFG_STRING;
if (!(v->v.str = _dup_string_tok(p)))
return_NULL; return_NULL;
if ((v = _create_str_value(p->mem, str, len))) { match(TOK_STRING);
v->type = DM_CFG_STRING;
match(TOK_STRING);
}
break; break;
case TOK_STRING_BARE: case TOK_STRING_BARE:
if ((v = _create_str_value(p->mem, p->tb, p->te - p->tb))) { v->type = DM_CFG_STRING;
v->type = DM_CFG_STRING;
match(TOK_STRING_BARE); if (!(v->v.str = _dup_tok(p)))
} return_NULL;
match(TOK_STRING_BARE);
break; break;
case TOK_STRING_ESCAPED: case TOK_STRING_ESCAPED:
if (!(str = _string_tok(p, &len))) v->type = DM_CFG_STRING;
return_NULL;
if ((v = _create_str_value(p->mem, str, len))) { if (!(str = _dup_string_tok(p)))
v->type = DM_CFG_STRING; return_NULL;
dm_unescape_double_quotes((char*)v->v.str); dm_unescape_double_quotes(str);
match(TOK_STRING_ESCAPED); v->v.str = str;
} match(TOK_STRING_ESCAPED);
break; break;
default: default:
@ -796,12 +744,6 @@ static struct dm_config_value *_type(struct parser *p)
p->tb - p->fb + 1, p->line); p->tb - p->fb + 1, p->line);
return NULL; return NULL;
} }
if (!v) {
log_error("Failed to allocate type value.");
return NULL;
}
return v; return v;
} }
@ -819,52 +761,60 @@ static int _match_aux(struct parser *p, int t)
*/ */
static void _get_token(struct parser *p, int tok_prev) static void _get_token(struct parser *p, int tok_prev)
{ {
/* Should next token be interpreted as value instead of identifier? */ int values_allowed = 0;
const int values_allowed = (tok_prev == TOK_EQ ||
tok_prev == TOK_ARRAY_B ||
tok_prev == TOK_COMMA);
const char *te; const char *te;
char c;
p->tb = p->te; p->tb = p->te;
_eat_space(p); _eat_space(p);
if (p->tb == p->fe || if (p->tb == p->fe || !*p->tb) {
!((c = *p->tb))) {
p->t = TOK_EOF; p->t = TOK_EOF;
return; return;
} }
/* Should next token be interpreted as value instead of identifier? */
if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
tok_prev == TOK_COMMA)
values_allowed = 1;
p->t = TOK_INT; /* fudge so the fall through for p->t = TOK_INT; /* fudge so the fall through for
floats works */ floats works */
te = p->te + 1; /* next character */
switch (c) { te = p->te;
switch (*te) {
case SECTION_B_CHAR: case SECTION_B_CHAR:
p->t = TOK_SECTION_B; p->t = TOK_SECTION_B;
te++;
break; break;
case SECTION_E_CHAR: case SECTION_E_CHAR:
p->t = TOK_SECTION_E; p->t = TOK_SECTION_E;
te++;
break; break;
case '[': case '[':
p->t = TOK_ARRAY_B; p->t = TOK_ARRAY_B;
te++;
break; break;
case ']': case ']':
p->t = TOK_ARRAY_E; p->t = TOK_ARRAY_E;
te++;
break; break;
case ',': case ',':
p->t = TOK_COMMA; p->t = TOK_COMMA;
te++;
break; break;
case '=': case '=':
p->t = TOK_EQ; p->t = TOK_EQ;
te++;
break; break;
case '"': case '"':
p->t = TOK_STRING_ESCAPED; p->t = TOK_STRING_ESCAPED;
te++;
while ((te != p->fe) && (*te) && (*te != '"')) { while ((te != p->fe) && (*te) && (*te != '"')) {
if ((*te == '\\') && (te + 1 != p->fe) && if ((*te == '\\') && (te + 1 != p->fe) &&
*(te + 1)) *(te + 1))
@ -878,6 +828,7 @@ static void _get_token(struct parser *p, int tok_prev)
case '\'': case '\'':
p->t = TOK_STRING; p->t = TOK_STRING;
te++;
while ((te != p->fe) && (*te) && (*te != '\'')) while ((te != p->fe) && (*te) && (*te != '\''))
te++; te++;
@ -901,7 +852,7 @@ static void _get_token(struct parser *p, int tok_prev)
case '+': case '+':
case '-': case '-':
if (values_allowed) { if (values_allowed) {
for (; te != p->fe; ++te) { while (++te != p->fe) {
if (!isdigit((int) *te)) { if (!isdigit((int) *te)) {
if (*te == '.') { if (*te == '.') {
if (p->t != TOK_FLOAT) { if (p->t != TOK_FLOAT) {
@ -918,10 +869,10 @@ static void _get_token(struct parser *p, int tok_prev)
default: default:
p->t = TOK_IDENTIFIER; p->t = TOK_IDENTIFIER;
while ((te != p->fe) && ((c = *te)) && !isspace(c) && while ((te != p->fe) && (*te) && !isspace(*te) &&
(c != '#') && (c != '=') && (*te != '#') && (*te != '=') &&
(c != SECTION_B_CHAR) && (*te != SECTION_B_CHAR) &&
(c != SECTION_E_CHAR)) (*te != SECTION_E_CHAR))
te++; te++;
if (values_allowed) if (values_allowed)
p->t = TOK_STRING_BARE; p->t = TOK_STRING_BARE;
@ -934,19 +885,16 @@ static void _get_token(struct parser *p, int tok_prev)
static void _eat_space(struct parser *p) static void _eat_space(struct parser *p)
{ {
while (p->tb != p->fe) { while (p->tb != p->fe) {
if (!isspace(*p->te)) { if (*p->te == '#')
if (*p->te != '#')
break;
while ((p->te != p->fe) && (*p->te != '\n') && (*p->te)) while ((p->te != p->fe) && (*p->te != '\n') && (*p->te))
++p->te; ++p->te;
}
while (p->te != p->fe) { else if (!isspace(*p->te))
break;
while ((p->te != p->fe) && isspace(*p->te)) {
if (*p->te == '\n') if (*p->te == '\n')
++p->line; ++p->line;
else if (!isspace(*p->te))
break;
++p->te; ++p->te;
} }
@ -962,44 +910,9 @@ static struct dm_config_value *_create_value(struct dm_pool *mem)
return dm_pool_zalloc(mem, sizeof(struct dm_config_value)); return dm_pool_zalloc(mem, sizeof(struct dm_config_value));
} }
static struct dm_config_value *_create_str_value(struct dm_pool *mem, const char *str, size_t str_len) static struct dm_config_node *_create_node(struct dm_pool *mem)
{ {
struct dm_config_value *cv; return dm_pool_zalloc(mem, sizeof(struct dm_config_node));
char *str_buf;
if (!(cv = dm_pool_alloc(mem, sizeof(struct dm_config_value) + str_len + 1)))
return_NULL;
memset(cv, 0, sizeof(*cv));
if (str) {
str_buf = (char *)(cv + 1);
memcpy(str_buf, str, str_len);
str_buf[str_len] = '\0';
cv->v.str = str_buf;
}
return cv;
}
static struct dm_config_node *_create_node(struct dm_pool *mem, const char *key, size_t key_len)
{
struct dm_config_node *cn;
char *key_buf;
if (!(cn = dm_pool_alloc(mem, sizeof(struct dm_config_node) + key_len + 1)))
return_NULL;
memset(cn, 0, sizeof(*cn));
if (key) {
key_buf = (char *)(cn + 1);
memcpy(key_buf, key, key_len);
key_buf[key_len] = '\0';
cn->key = key_buf;
}
return cn;
} }
static char *_dup_token(struct dm_pool *mem, const char *b, const char *e) static char *_dup_token(struct dm_pool *mem, const char *b, const char *e)
@ -1416,20 +1329,19 @@ static struct dm_config_value *_clone_config_value(struct dm_pool *mem,
{ {
struct dm_config_value *new_cv; struct dm_config_value *new_cv;
if (v->type == DM_CFG_STRING) { if (!(new_cv = _create_value(mem))) {
if (!(new_cv = _create_str_value(mem, v->v.str, strlen(v->v.str)))) { log_error("Failed to clone config value.");
log_error("Failed to clone string config value."); return NULL;
return NULL;
}
} else {
if (!(new_cv = _create_value(mem))) {
log_error("Failed to clone config value.");
return NULL;
}
new_cv->v = v->v;
} }
new_cv->type = v->type; new_cv->type = v->type;
if (v->type == DM_CFG_STRING) {
if (!(new_cv->v.str = dm_pool_strdup(mem, v->v.str))) {
log_error("Failed to clone config string value.");
return NULL;
}
} else
new_cv->v = v->v;
if (v->next && !(new_cv->next = _clone_config_value(mem, v->next))) if (v->next && !(new_cv->next = _clone_config_value(mem, v->next)))
return_NULL; return_NULL;
@ -1446,11 +1358,16 @@ struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const
return NULL; return NULL;
} }
if (!(new_cn = _create_node(mem, cn->key, cn->key ? strlen(cn->key) : 0))) { if (!(new_cn = _create_node(mem))) {
log_error("Failed to clone config node."); log_error("Failed to clone config node.");
return NULL; return NULL;
} }
if ((cn->key && !(new_cn->key = dm_pool_strdup(mem, cn->key)))) {
log_error("Failed to clone config node key.");
return NULL;
}
new_cn->id = cn->id; new_cn->id = cn->id;
if ((cn->v && !(new_cn->v = _clone_config_value(mem, cn->v))) || if ((cn->v && !(new_cn->v = _clone_config_value(mem, cn->v))) ||
@ -1461,20 +1378,23 @@ struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const
return new_cn; return new_cn;
} }
struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *cn, int sib) struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *node, int sib)
{ {
return dm_config_clone_node_with_mem(cft->mem, cn, sib); return dm_config_clone_node_with_mem(cft->mem, node, sib);
} }
struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key) struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key)
{ {
struct dm_config_node *cn; struct dm_config_node *cn;
if (!(cn = _create_node(cft->mem, key, strlen(key)))) { if (!(cn = _create_node(cft->mem))) {
log_error("Failed to create config node."); log_error("Failed to create config node.");
return NULL; return NULL;
} }
if (!(cn->key = dm_pool_strdup(cft->mem, key))) {
log_error("Failed to create config node's key.");
return NULL;
}
cn->parent = NULL; cn->parent = NULL;
cn->v = NULL; cn->v = NULL;

View File

@ -19,6 +19,7 @@
#include "misc/dm-ioctl.h" #include "misc/dm-ioctl.h"
#include "vdo/target.h" #include "vdo/target.h"
#include <stdarg.h>
#include <string.h> #include <string.h>
#include <sys/utsname.h> #include <sys/utsname.h>
@ -151,17 +152,15 @@ struct thin_message {
struct load_segment { struct load_segment {
struct dm_list list; struct dm_list list;
uint64_t size;
unsigned type; unsigned type;
uint64_t size;
unsigned area_count; /* Linear + Striped + Mirrored + Crypt */ unsigned area_count; /* Linear + Striped + Mirrored + Crypt */
struct dm_list areas; /* Linear + Striped + Mirrored + Crypt */ struct dm_list areas; /* Linear + Striped + Mirrored + Crypt */
uint32_t stripe_size; /* Striped + raid */ uint32_t stripe_size; /* Striped + raid */
uint32_t region_size; /* Mirror + raid */
int persistent; /* Snapshot */ int persistent; /* Snapshot */
uint32_t chunk_size; /* Snapshot */ uint32_t chunk_size; /* Snapshot */
struct dm_tree_node *cow; /* Snapshot */ struct dm_tree_node *cow; /* Snapshot */
@ -169,9 +168,10 @@ struct load_segment {
struct dm_tree_node *merge; /* Snapshot */ struct dm_tree_node *merge; /* Snapshot */
struct dm_tree_node *log; /* Mirror */ struct dm_tree_node *log; /* Mirror */
uint32_t region_size; /* Mirror + raid */
unsigned clustered; /* Mirror */ unsigned clustered; /* Mirror */
unsigned mirror_area_count; /* Mirror */ unsigned mirror_area_count; /* Mirror */
uint64_t flags; /* Mirror + Raid + Cache */ uint32_t flags; /* Mirror + raid + Cache */
char *uuid; /* Clustered mirror log */ char *uuid; /* Clustered mirror log */
const char *policy_name; /* Cache */ const char *policy_name; /* Cache */
@ -214,7 +214,6 @@ struct load_segment {
uint32_t device_id; /* Thin */ uint32_t device_id; /* Thin */
// VDO params // VDO params
uint32_t vdo_version; /* VDO - version of target table line */
struct dm_tree_node *vdo_data; /* VDO */ struct dm_tree_node *vdo_data; /* VDO */
struct dm_vdo_target_params vdo_params; /* VDO */ struct dm_vdo_target_params vdo_params; /* VDO */
const char *vdo_name; /* VDO - device name is ALSO passed as table arg */ const char *vdo_name; /* VDO - device name is ALSO passed as table arg */
@ -265,7 +264,7 @@ struct load_properties {
/* /*
* Preload tree normally only loads and not resume, but there is * Preload tree normally only loads and not resume, but there is
* automatic resume when target is extended, as it's believed * automatic resume when target is extended, as it's believed
* there can be no i/o flying to this 'new' extended space * there can be no i/o flying to this 'new' extedend space
* from any device above. Reason is that preloaded target above * from any device above. Reason is that preloaded target above
* may actually need to see its bigger subdevice before it * may actually need to see its bigger subdevice before it
* gets suspended. As long as devices are simple linears * gets suspended. As long as devices are simple linears
@ -277,7 +276,7 @@ struct load_properties {
/* /*
* When comparing table lines to decide if a reload is * When comparing table lines to decide if a reload is
* needed, ignore any differences between the lvm device * needed, ignore any differences betwen the lvm device
* params and the kernel-reported device params. * params and the kernel-reported device params.
* dm-integrity reports many internal parameters on the * dm-integrity reports many internal parameters on the
* table line when lvm does not explicitly set them, * table line when lvm does not explicitly set them,
@ -288,16 +287,12 @@ struct load_properties {
/* /*
* Call node_send_messages(), set to 2 if there are messages * Call node_send_messages(), set to 2 if there are messages
* When != 0, it validates matching transaction id, thus thin-pools * When != 0, it validates matching transaction id, thus thin-pools
* where transaction_id is passed as 0 are never validated, this * where transation_id is passed as 0 are never validated, this
* allows external management of thin-pool TID. * allows external managment of thin-pool TID.
*/ */
unsigned send_messages; unsigned send_messages;
/* Skip suspending node's children, used when sending messages to thin-pool */ /* Skip suspending node's children, used when sending messages to thin-pool */
int skip_suspend; int skip_suspend;
/* Suspend and Resume siblings after node activation with udev flags*/
unsigned reactivate_siblings;
uint16_t reactivate_udev_flags;
}; };
/* Two of these used to join two nodes with uses and used_by. */ /* Two of these used to join two nodes with uses and used_by. */
@ -348,7 +343,7 @@ struct dm_tree {
int retry_remove; /* 1 retries remove if not successful */ int retry_remove; /* 1 retries remove if not successful */
uint32_t cookie; uint32_t cookie;
char buf[DM_NAME_LEN + 32]; /* print buffer for device_name (major:minor) */ char buf[DM_NAME_LEN + 32]; /* print buffer for device_name (major:minor) */
const char * const *optional_uuid_suffixes; /* uuid suffixes ignored when matching */ const char **optional_uuid_suffixes; /* uuid suffixes ignored when matching */
}; };
/* /*
@ -540,8 +535,7 @@ static struct dm_tree_node *_create_dm_tree_node(struct dm_tree *dtree,
struct dm_tree_node *node; struct dm_tree_node *node;
dev_t dev; dev_t dev;
if (!dtree || !dtree->mem || if (!(node = dm_pool_zalloc(dtree->mem, sizeof(*node))) ||
!(node = dm_pool_zalloc(dtree->mem, sizeof(*node))) ||
!(node->name = dm_pool_strdup(dtree->mem, name)) || !(node->name = dm_pool_strdup(dtree->mem, name)) ||
!(node->uuid = dm_pool_strdup(dtree->mem, uuid))) { !(node->uuid = dm_pool_strdup(dtree->mem, uuid))) {
log_error("_create_dm_tree_node alloc failed."); log_error("_create_dm_tree_node alloc failed.");
@ -591,7 +585,6 @@ void dm_tree_set_optional_uuid_suffixes(struct dm_tree *dtree, const char **opti
dtree->optional_uuid_suffixes = optional_uuid_suffixes; dtree->optional_uuid_suffixes = optional_uuid_suffixes;
} }
static const char *_node_name(struct dm_tree_node *dnode);
static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree, static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
const char *uuid) const char *uuid)
{ {
@ -599,26 +592,28 @@ static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
const char *default_uuid_prefix; const char *default_uuid_prefix;
size_t default_uuid_prefix_len; size_t default_uuid_prefix_len;
const char *suffix, *suffix_position; const char *suffix, *suffix_position;
char uuid_without_suffix[DM_UUID_LEN + 1]; char uuid_without_suffix[DM_UUID_LEN];
unsigned i = 0; unsigned i = 0;
const char * const *suffix_list = dtree->optional_uuid_suffixes; const char **suffix_list = dtree->optional_uuid_suffixes;
if ((node = dm_hash_lookup(dtree->uuids, uuid))) { if ((node = dm_hash_lookup(dtree->uuids, uuid))) {
log_debug_activation("Matched uuid %s %s in deptree.", uuid, _node_name(node)); log_debug("Matched uuid %s in deptree.", uuid);
return node; return node;
} }
default_uuid_prefix = dm_uuid_prefix();
default_uuid_prefix_len = strlen(default_uuid_prefix);
if (suffix_list && (suffix_position = strrchr(uuid, '-'))) { if (suffix_list && (suffix_position = strrchr(uuid, '-'))) {
while ((suffix = suffix_list[i++])) { while ((suffix = suffix_list[i++])) {
if (strcmp(suffix_position + 1, suffix)) if (strcmp(suffix_position + 1, suffix))
continue; continue;
dm_strncpy(uuid_without_suffix, uuid, sizeof(uuid_without_suffix)); (void) strncpy(uuid_without_suffix, uuid, sizeof(uuid_without_suffix));
uuid_without_suffix[suffix_position - uuid] = '\0'; uuid_without_suffix[suffix_position - uuid] = '\0';
if ((node = dm_hash_lookup(dtree->uuids, uuid_without_suffix))) { if ((node = dm_hash_lookup(dtree->uuids, uuid_without_suffix))) {
log_debug_activation("Matched uuid %s %s (missing suffix -%s) in deptree.", log_debug("Matched uuid %s (missing suffix -%s) in deptree.", uuid_without_suffix, suffix);
uuid_without_suffix, _node_name(node), suffix);
return node; return node;
} }
@ -626,17 +621,15 @@ static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
}; };
} }
default_uuid_prefix = dm_uuid_prefix(); if (strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len))
default_uuid_prefix_len = strlen(default_uuid_prefix); return NULL;
if ((strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len) == 0) && if ((node = dm_hash_lookup(dtree->uuids, uuid + default_uuid_prefix_len))) {
(node = dm_hash_lookup(dtree->uuids, uuid + default_uuid_prefix_len))) { log_debug("Matched uuid %s (missing prefix) in deptree.", uuid + default_uuid_prefix_len);
log_debug_activation("Matched uuid %s %s (missing prefix) in deptree.",
uuid + default_uuid_prefix_len, _node_name(node));
return node; return node;
} }
log_debug_activation("Not matched uuid %s in deptree.", uuid); log_debug("Not matched uuid %s in deptree.", uuid);
return NULL; return NULL;
} }
@ -969,7 +962,7 @@ static int _check_device_not_in_use(const char *name, struct dm_info *info)
} else if (dm_device_has_holders(info->major, info->minor)) } else if (dm_device_has_holders(info->major, info->minor))
reason = "is used by another device"; reason = "is used by another device";
else if (dm_device_has_mounted_fs(info->major, info->minor)) else if (dm_device_has_mounted_fs(info->major, info->minor))
reason = "contains a filesystem in use"; reason = "constains a filesystem in use";
else else
return 1; return 1;
@ -1817,7 +1810,7 @@ static int _dm_tree_deactivate_children(struct dm_tree_node *dnode,
if (info.open_count) { if (info.open_count) {
/* Skip internal non-toplevel opened nodes */ /* Skip internal non-toplevel opened nodes */
/* On some old udev systems without correct udev rules /* On some old udev systems without corrrect udev rules
* this hack avoids 'leaking' active _mimageX legs after * this hack avoids 'leaking' active _mimageX legs after
* deactivation of mirror LV. Other suffixes are not added * deactivation of mirror LV. Other suffixes are not added
* since it's expected newer systems with wider range of * since it's expected newer systems with wider range of
@ -2036,68 +2029,6 @@ static int _rename_conflict_exists(struct dm_tree_node *parent,
return 0; return 0;
} }
/*
* Reactivation of sibling nodes
*
* Function is used when activating origin and its thick snapshots
* to ensure udev is processing first the origin LV and all the
* snapshot LVs are processed afterwards.
*/
static int _reactivate_siblings(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len)
{
struct dm_tree_node *child;
const char *uuid;
void *handle = NULL;
int r = 1;
/* Wait for udev before reactivating siblings */
if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
stack;
dm_tree_set_cookie(dnode, 0);
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
if (child->props.reactivate_siblings) {
/* Skip 'leading' device in this group, marked with flag */
child->props.reactivate_siblings = 0;
continue;
}
if (!(uuid = dm_tree_node_get_uuid(child))) {
stack;
continue;
}
if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
continue;
if (!_suspend_node(child->name, child->info.major, child->info.minor,
child->dtree->skip_lockfs,
child->dtree->no_flush, &child->info)) {
log_error("Unable to suspend %s (" FMTu32
":" FMTu32 ")", child->name,
child->info.major, child->info.minor);
r = 0;
continue;
}
if (!_resume_node(child->name, child->info.major, child->info.minor,
child->props.read_ahead, child->props.read_ahead_flags,
&child->info, &child->dtree->cookie,
child->props.reactivate_udev_flags, // use these flags
child->info.suspended)) {
log_error("Failed to suspend %s (" FMTu32
":" FMTu32 ")", child->name,
child->info.major, child->info.minor);
r = 0;
continue;
}
}
return r;
}
int dm_tree_activate_children(struct dm_tree_node *dnode, int dm_tree_activate_children(struct dm_tree_node *dnode,
const char *uuid_prefix, const char *uuid_prefix,
size_t uuid_prefix_len) size_t uuid_prefix_len)
@ -2108,7 +2039,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
struct dm_tree_node *child = dnode; struct dm_tree_node *child = dnode;
const char *name; const char *name;
const char *uuid; const char *uuid;
int priority, next_priority; int priority;
/* Activate children first */ /* Activate children first */
while ((child = dm_tree_next_child(&handle, dnode, 0))) { while ((child = dm_tree_next_child(&handle, dnode, 0))) {
@ -2126,16 +2057,12 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
} }
handle = NULL; handle = NULL;
for (priority = 0; priority < 3; priority++) { for (priority = 0; priority < 3; priority++) {
awaiting_peer_rename = 0; awaiting_peer_rename = 0;
next_priority = 0;
while ((child = dm_tree_next_child(&handle, dnode, 0))) { while ((child = dm_tree_next_child(&handle, dnode, 0))) {
if (priority != child->activation_priority) { if (priority != child->activation_priority)
if ((next_priority < child->activation_priority) &&
(child->activation_priority > priority))
next_priority = child->activation_priority;
continue; continue;
}
if (!(uuid = dm_tree_node_get_uuid(child))) { if (!(uuid = dm_tree_node_get_uuid(child))) {
stack; stack;
@ -2183,23 +2110,16 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
/* /*
* FIXME: Implement delayed error reporting * FIXME: Implement delayed error reporting
* activation should be stopped only in the case, * activation should be stopped only in the case,
* the submission of transaction_id message fails, * the submission of transation_id message fails,
* resume should continue further, just whole command * resume should continue further, just whole command
* has to report failure. * has to report failure.
*/ */
if (r && (child->props.send_messages > 1) && if (r && (child->props.send_messages > 1) &&
!(r = _node_send_messages(child, uuid_prefix, uuid_prefix_len, 1))) !(r = _node_send_messages(child, uuid_prefix, uuid_prefix_len, 1)))
stack; stack;
/* Reactivate only for fresh activated origin */
if (r && child->props.reactivate_siblings &&
(!(r = _reactivate_siblings(dnode, uuid_prefix, uuid_prefix_len))))
stack;
} }
if (awaiting_peer_rename) if (awaiting_peer_rename)
priority--; /* redo priority level */ priority--; /* redo priority level */
else if (!next_priority)
break; /* no more work, higher priority was not found in the chain */
} }
return r; return r;
@ -2275,7 +2195,7 @@ static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *
return 1; return 1;
} }
/* simplify string emitting code */ /* simplify string emiting code */
#define EMIT_PARAMS(p, str...)\ #define EMIT_PARAMS(p, str...)\
do {\ do {\
int w;\ int w;\
@ -2758,10 +2678,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
count += 1; count += 1;
if (seg->writecache_settings.max_age_set) if (seg->writecache_settings.max_age_set)
count += 2; count += 2;
if (seg->writecache_settings.metadata_only_set)
count += 1;
if (seg->writecache_settings.pause_writeback_set)
count += 2;
if (seg->writecache_settings.new_key) if (seg->writecache_settings.new_key)
count += 2; count += 2;
@ -2813,14 +2729,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age); EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age);
} }
if (seg->writecache_settings.metadata_only_set) {
EMIT_PARAMS(pos, " metadata_only");
}
if (seg->writecache_settings.pause_writeback_set) {
EMIT_PARAMS(pos, " pause_writeback %u", seg->writecache_settings.pause_writeback);
}
if (seg->writecache_settings.new_key) { if (seg->writecache_settings.new_key) {
EMIT_PARAMS(pos, " %s %s", EMIT_PARAMS(pos, " %s %s",
seg->writecache_settings.new_key, seg->writecache_settings.new_key,
@ -2869,8 +2777,6 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
count++; count++;
if (set->sectors_per_bit_set) if (set->sectors_per_bit_set)
count++; count++;
if (set->allow_discards_set && set->allow_discards)
count++;
EMIT_PARAMS(pos, "%s 0 %u %s %d fix_padding block_size:%u internal_hash:%s", EMIT_PARAMS(pos, "%s 0 %u %s %d fix_padding block_size:%u internal_hash:%s",
origin_dev, origin_dev,
@ -2890,7 +2796,7 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
EMIT_PARAMS(pos, " journal_sectors:%u", set->journal_sectors); EMIT_PARAMS(pos, " journal_sectors:%u", set->journal_sectors);
if (set->interleave_sectors_set) if (set->interleave_sectors_set)
EMIT_PARAMS(pos, " interleave_sectors:%u", set->interleave_sectors); EMIT_PARAMS(pos, " ineterleave_sectors:%u", set->interleave_sectors);
if (set->buffer_sectors_set) if (set->buffer_sectors_set)
EMIT_PARAMS(pos, " buffer_sectors:%u", set->buffer_sectors); EMIT_PARAMS(pos, " buffer_sectors:%u", set->buffer_sectors);
@ -2907,9 +2813,6 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
if (set->sectors_per_bit_set) if (set->sectors_per_bit_set)
EMIT_PARAMS(pos, " sectors_per_bit:%llu", (unsigned long long)set->sectors_per_bit); EMIT_PARAMS(pos, " sectors_per_bit:%llu", (unsigned long long)set->sectors_per_bit);
if (set->allow_discards_set && set->allow_discards)
EMIT_PARAMS(pos, " allow_discards");
if (!dm_task_secure_data(dmt)) if (!dm_task_secure_data(dmt))
stack; stack;
@ -2946,18 +2849,13 @@ static int _thin_pool_emit_segment_line(struct dm_task *dmt,
return 1; return 1;
} }
static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t minor, static int _vdo_emit_segment_line(struct dm_task *dmt,
struct load_segment *seg, struct load_segment *seg,
char *params, size_t paramsize) char *params, size_t paramsize)
{ {
int pos = 0; int pos = 0;
char data[DM_FORMAT_DEV_BUFSIZE]; char data[DM_FORMAT_DEV_BUFSIZE];
char data_dev[128]; // for /dev/dm-XXXX char data_dev[128]; // for /dev/dm-XXXX
uint64_t logical_blocks;
struct dm_task *vdo_dmt;
uint64_t start, length = 0;
char *type = NULL;
char *vdo_params = NULL;
if (!_build_dev_string(data, sizeof(data), seg->vdo_data)) if (!_build_dev_string(data, sizeof(data), seg->vdo_data))
return_0; return_0;
@ -2967,59 +2865,18 @@ static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t
return 0; return 0;
} }
/* EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s "
* If there is already running VDO target, read 'existing' virtual size out of table line "maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
* and avoid reading it them from VDO metadata device data_dev,
* seg->vdo_data_size / 8, // this parameter is in 4K units
* NOTE: ATM VDO virtual size can be ONLY extended thus it's simple to recognize 'right' size. seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
* However if there would be supported also reduction, this check would need to check range. seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
*/ seg->vdo_params.block_map_era_length,
if ((vdo_dmt = dm_task_create(DM_DEVICE_TABLE))) { seg->vdo_params.use_metadata_hints ? "on" : "off" ,
if (dm_task_set_major(vdo_dmt, major) && (seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_SYNC) ? "sync" :
dm_task_set_minor(vdo_dmt, minor) && (seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC) ? "async" :
dm_task_run(vdo_dmt)) { (seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
(void) dm_get_next_target(vdo_dmt, NULL, &start, &length, &type, &vdo_params); seg->vdo_name,
if (!type || strcmp(type, "vdo"))
length = 0;
}
dm_task_destroy(vdo_dmt);
}
if (!length && dm_vdo_parse_logical_size(data_dev, &logical_blocks))
length = logical_blocks * 8;
if (seg->size < length) {
log_debug_activation("Correcting VDO virtual volume size from " FMTu64 " to " FMTu64 ".",
seg->size, length);
seg->size = length;
}
if (seg->vdo_version < 4) {
EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s ",
data_dev,
seg->vdo_data_size / 8, // this parameter is in 4K units
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
seg->vdo_params.block_map_era_length,
seg->vdo_params.use_metadata_hints ? "on" : "off" ,
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_SYNC) ? "sync" :
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC) ? "async" :
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
seg->vdo_name);
} else {
EMIT_PARAMS(pos, "V4 %s " FMTu64 " %u " FMTu64 " %u "
"deduplication %s compression %s ",
data_dev,
seg->vdo_data_size / 8, // this parameter is in 4K units
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
seg->vdo_params.block_map_era_length,
seg->vdo_params.use_deduplication ? "on" : "off",
seg->vdo_params.use_compression ? "on" : "off");
}
EMIT_PARAMS(pos, "maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
seg->vdo_params.max_discard, seg->vdo_params.max_discard,
seg->vdo_params.ack_threads, seg->vdo_params.ack_threads,
seg->vdo_params.bio_threads, seg->vdo_params.bio_threads,
@ -3094,7 +2951,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size); EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size);
break; break;
case SEG_VDO: case SEG_VDO:
if (!_vdo_emit_segment_line(dmt, major, minor, seg, params, paramsize)) if (!_vdo_emit_segment_line(dmt, seg, params, paramsize))
return_0; return_0;
break; break;
case SEG_CRYPT: case SEG_CRYPT:
@ -3383,7 +3240,7 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
if (!child->info.exists && !(node_created = _create_node(child, dnode))) if (!child->info.exists && !(node_created = _create_node(child, dnode)))
return_0; return_0;
/* Propagate delayed resume from extended child node */ /* Propagate delayed resume from exteded child node */
if (child->props.delay_resume_if_extended) if (child->props.delay_resume_if_extended)
dnode->props.delay_resume_if_extended = 1; dnode->props.delay_resume_if_extended = 1;
@ -3533,10 +3390,6 @@ int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
/* Resume snapshot origins after new snapshots */ /* Resume snapshot origins after new snapshots */
dnode->activation_priority = 1; dnode->activation_priority = 1;
if (!dnode->info.exists)
/* Reactivate siblings for this origin after being resumed */
dnode->props.reactivate_siblings = 1;
/* /*
* Don't resume the origin immediately in case it is a non-trivial * Don't resume the origin immediately in case it is a non-trivial
* target that must not be active more than once concurrently! * target that must not be active more than once concurrently!
@ -3599,20 +3452,6 @@ static int _add_snapshot_target(struct dm_tree_node *node,
/* Resume merging snapshot after snapshot-merge */ /* Resume merging snapshot after snapshot-merge */
seg->merge->activation_priority = 2; seg->merge->activation_priority = 2;
} }
} else if (!origin_node->info.exists) {
/* Keep original udev_flags for reactivation. */
node->props.reactivate_udev_flags = node->udev_flags;
/* Reactivation is needed if the origin's -real device is not in DM table.
* For this case after the resume of its origin LV we resume its snapshots
* with updated udev_flags to completely avoid udev scanning for the first resume.
* Reactivation then resumes snapshots with original udev_flags.
*/
node->udev_flags |= DM_SUBSYSTEM_UDEV_FLAG0 |
DM_UDEV_DISABLE_DISK_RULES_FLAG |
DM_UDEV_DISABLE_OTHER_RULES_FLAG;
log_debug_activation("Using udev_flags 0x%x for activation of %s.",
node->udev_flags, node->name);
} }
return 1; return 1;
@ -3819,7 +3658,7 @@ int dm_tree_node_add_raid_target(struct dm_tree_node *node,
* - maximum 253 legs in a raid set (MD kernel limitation) * - maximum 253 legs in a raid set (MD kernel limitation)
* - delta_disks for disk add/remove reshaping * - delta_disks for disk add/remove reshaping
* - data_offset for out-of-place reshaping * - data_offset for out-of-place reshaping
* - data_copies to cope with odd numbers of raid10 disks * - data_copies to cope witth odd numbers of raid10 disks
*/ */
int dm_tree_node_add_raid_target_with_params_v2(struct dm_tree_node *node, int dm_tree_node_add_raid_target_with_params_v2(struct dm_tree_node *node,
uint64_t size, uint64_t size,
@ -3870,7 +3709,7 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
{ {
struct dm_config_node *cn; struct dm_config_node *cn;
struct load_segment *seg; struct load_segment *seg;
const uint64_t modemask = static const uint64_t _modemask =
DM_CACHE_FEATURE_PASSTHROUGH | DM_CACHE_FEATURE_PASSTHROUGH |
DM_CACHE_FEATURE_WRITETHROUGH | DM_CACHE_FEATURE_WRITETHROUGH |
DM_CACHE_FEATURE_WRITEBACK; DM_CACHE_FEATURE_WRITEBACK;
@ -3882,12 +3721,12 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
return 0; return 0;
} }
switch (feature_flags & modemask) { switch (feature_flags & _modemask) {
case DM_CACHE_FEATURE_PASSTHROUGH: case DM_CACHE_FEATURE_PASSTHROUGH:
case DM_CACHE_FEATURE_WRITEBACK: case DM_CACHE_FEATURE_WRITEBACK:
if (strcmp(policy_name, "cleaner") == 0) { if (strcmp(policy_name, "cleaner") == 0) {
/* Enforce writethrough mode for cleaner policy */ /* Enforce writethrough mode for cleaner policy */
feature_flags = ~modemask; feature_flags = ~_modemask;
feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH; feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
} }
/* Fall through */ /* Fall through */
@ -4083,7 +3922,7 @@ int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
uint32_t slog_flags, uint32_t slog_flags,
uint32_t slog_region_size) uint32_t slog_region_size)
{ {
log_error("Replicator target is unsupported."); log_error("Replicator targer is unsupported.");
return 0; return 0;
} }
@ -4370,12 +4209,6 @@ int dm_tree_node_set_thin_external_origin(struct dm_tree_node *node,
seg->external = external; seg->external = external;
if (!external->info.minor) {
log_debug_activation("Delaying resume for new external origin %s.",
external->name);
external->props.delay_resume_if_new = 1;
}
return 1; return 1;
} }
@ -4490,7 +4323,6 @@ void dm_tree_node_set_callback(struct dm_tree_node *dnode,
int dm_tree_node_add_vdo_target(struct dm_tree_node *node, int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
uint64_t size, uint64_t size,
uint32_t vdo_version,
const char *vdo_pool_name, const char *vdo_pool_name,
const char *data_uuid, const char *data_uuid,
uint64_t data_size, uint64_t data_size,
@ -4512,13 +4344,11 @@ int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
if (!_link_tree_nodes(node, seg->vdo_data)) if (!_link_tree_nodes(node, seg->vdo_data))
return_0; return_0;
seg->vdo_version = vdo_version;
seg->vdo_params = *vtp; seg->vdo_params = *vtp;
seg->vdo_name = vdo_pool_name; seg->vdo_name = vdo_pool_name;
seg->vdo_data_size = data_size; seg->vdo_data_size = data_size;
if (seg->vdo_version < 4) node->props.send_messages = 2;
node->props.send_messages = 2;
return 1; return 1;
} }

View File

@ -223,6 +223,7 @@ retry_fcntl:
} }
/* coverity[leaked_handle] intentional leak of fd handle here */ /* coverity[leaked_handle] intentional leak of fd handle here */
return 1; return 1;
fail_close_unlink: fail_close_unlink:

File diff suppressed because it is too large Load Diff

View File

@ -169,7 +169,7 @@ int dm_vasprintf(char **result, const char *format, va_list aq)
} }
if (i > 1) { if (i > 1) {
/* Reallocating more than once? */ /* Reallocating more then once? */
if (!(*result = strdup(buf))) { if (!(*result = strdup(buf))) {
free(buf); free(buf);
return -1; return -1;
@ -192,7 +192,7 @@ int dm_asprintf(char **result, const char *format, ...)
} }
/* /*
* Count occurrences of 'c' in 'str' until we reach a null char. * Count occurences of 'c' in 'str' until we reach a null char.
* *
* Returns: * Returns:
* len - incremented for each char we encounter. * len - incremented for each char we encounter.
@ -385,7 +385,7 @@ char *dm_build_dm_uuid(struct dm_pool *mem, const char *uuid_prefix, const char
return NULL; return NULL;
} }
snprintf(dmuuid, len, "%s%s%s%s", uuid_prefix, lvid, (*layer) ? "-" : "", layer); sprintf(dmuuid, "%s%s%s%s", uuid_prefix, lvid, (*layer) ? "-" : "", layer);
return dmuuid; return dmuuid;
} }
@ -471,10 +471,10 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
double d; double d;
uint64_t byte = UINT64_C(0); uint64_t byte = UINT64_C(0);
uint64_t units = UINT64_C(1024); uint64_t units = UINT64_C(1024);
char *size_buf; char *size_buf = NULL;
char new_unit_type = '\0', unit_type_buf[2]; char new_unit_type = '\0', unit_type_buf[2];
const char *prefix = ""; const char *prefix = "";
static const char _size_str[][3][12] = { const char * const size_str[][3] = {
/* BASE_UNKNOWN */ /* BASE_UNKNOWN */
{" ", " ", " "}, /* [0] */ {" ", " ", " "}, /* [0] */
@ -519,14 +519,14 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
/* Case-independent match */ /* Case-independent match */
for (s = 0; s < NUM_UNIT_PREFIXES; s++) for (s = 0; s < NUM_UNIT_PREFIXES; s++)
if (toupper((int) unit_type) == if (toupper((int) unit_type) ==
*_size_str[BASE_SHARED + s][2]) { *size_str[BASE_SHARED + s][2]) {
base = BASE_SHARED; base = BASE_SHARED;
break; break;
} }
} else { } else {
/* Case-dependent match for powers of 1000 */ /* Case-dependent match for powers of 1000 */
for (s = 0; s < NUM_UNIT_PREFIXES; s++) for (s = 0; s < NUM_UNIT_PREFIXES; s++)
if (unit_type == *_size_str[BASE_1000 + s][2]) { if (unit_type == *size_str[BASE_1000 + s][2]) {
base = BASE_1000; base = BASE_1000;
break; break;
} }
@ -534,7 +534,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
/* Case-dependent match for powers of 1024 */ /* Case-dependent match for powers of 1024 */
if (base == BASE_UNKNOWN) if (base == BASE_UNKNOWN)
for (s = 0; s < NUM_UNIT_PREFIXES; s++) for (s = 0; s < NUM_UNIT_PREFIXES; s++)
if (unit_type == *_size_str[BASE_1024 + s][2]) { if (unit_type == *size_str[BASE_1024 + s][2]) {
base = BASE_1024; base = BASE_1024;
break; break;
} }
@ -544,7 +544,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
/* Check for special units - s, b or u */ /* Check for special units - s, b or u */
for (s = 0; s < NUM_SPECIAL; s++) for (s = 0; s < NUM_SPECIAL; s++)
if (toupper((int) unit_type) == if (toupper((int) unit_type) ==
*_size_str[BASE_SPECIAL + s][2]) { *size_str[BASE_SPECIAL + s][2]) {
base = BASE_SPECIAL; base = BASE_SPECIAL;
break; break;
} }
@ -552,7 +552,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
if (size == UINT64_C(0)) { if (size == UINT64_C(0)) {
if (base == BASE_UNKNOWN) if (base == BASE_UNKNOWN)
s = 0; s = 0;
snprintf(size_buf, SIZE_BUF, "0%s", include_suffix ? _size_str[base + s][suffix_type] : ""); sprintf(size_buf, "0%s", include_suffix ? size_str[base + s][suffix_type] : "");
return size_buf; return size_buf;
} }
@ -591,7 +591,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
if ((s < NUM_UNIT_PREFIXES) && if ((s < NUM_UNIT_PREFIXES) &&
((unit_type == 'R') || (unit_type == 'r'))) { ((unit_type == 'R') || (unit_type == 'r'))) {
/* When the rounding would cause difference, add '<' prefix /* When the rounding would cause difference, add '<' prefix
* i.e. 2043M is more than 1.9949G prints <2.00G * i.e. 2043M is more then 1.9949G prints <2.00G
* This version is for 2 digits fixed precision */ * This version is for 2 digits fixed precision */
d = 100. * (double) size / byte; d = 100. * (double) size / byte;
if (!_close_enough(floorl(d), nearbyintl(d))) if (!_close_enough(floorl(d), nearbyintl(d)))
@ -602,7 +602,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
} }
/* FIXME Make precision configurable */ /* FIXME Make precision configurable */
switch (toupper(*_size_str[base + s][DM_SIZE_UNIT])) { switch (toupper(*size_str[base + s][DM_SIZE_UNIT])) {
case 'B': case 'B':
case 'S': case 'S':
precision = 0; precision = 0;
@ -612,7 +612,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
} }
snprintf(size_buf, SIZE_BUF, "%s%.*f%s", prefix, precision, snprintf(size_buf, SIZE_BUF, "%s%.*f%s", prefix, precision,
(double) size / byte, include_suffix ? _size_str[base + s][suffix_type] : ""); (double) size / byte, include_suffix ? size_str[base + s][suffix_type] : "");
return size_buf; return size_buf;
} }

View File

@ -106,31 +106,26 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
/* Second field holds the device count */ /* Second field holds the device count */
msg_fields = "<#devs> "; msg_fields = "<#devs> ";
if (!(pp = _skip_fields(params, 1)) || (sscanf(pp, "%d", &i) != 1) || !(p = _skip_fields(pp, 1))) if (!(p = _skip_fields(params, 1)) || (sscanf(p, "%d", &i) != 1))
goto_bad; goto_bad;
msg_fields = ""; msg_fields = "";
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid)))) if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid))))
goto_bad; goto_bad;
msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> "; if (!(s->raid_type = dm_pool_zalloc(mem, p - params)))
if (!(s->raid_type = dm_pool_strndup(mem, params, pp - params - 1)))
goto_bad; /* memory is freed when pool is destroyed */ goto_bad; /* memory is freed when pool is destroyed */
if (!(pp = _skip_fields(p, 1))) if (!(s->dev_health = dm_pool_zalloc(mem, i + 1))) /* Space for health chars */
goto_bad; goto_bad;
/* Raid target can actually report more than real number of legs in a case msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> ";
* raid legs have been removed during initial raid array resynchronization */ if (sscanf(params, "%s %u %s " FMTu64 "/" FMTu64,
if (i > (pp - p - 1)) s->raid_type,
i = pp - p - 1; &s->dev_count,
s->dev_health,
if (!(s->dev_health = dm_pool_strndup(mem, p, i))) /* health chars */ &s->insync_regions,
goto_bad; &s->total_regions) != 5)
p = pp;
s->dev_count = i;
if (sscanf(p, FMTu64 "/" FMTu64, &s->insync_regions, &s->total_regions) != 2)
goto_bad; goto_bad;
/* /*
@ -146,13 +141,13 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
msg_fields = "<sync_action> and <mismatch_cnt> "; msg_fields = "<sync_action> and <mismatch_cnt> ";
/* Skip pre-1.5.0 params */ /* Skip pre-1.5.0 params */
if (!(pp = _skip_fields(params, 4)) || !(p = _skip_fields(pp, 1))) if (!(p = _skip_fields(params, 4)) || !(pp = _skip_fields(p, 1)))
goto_bad; goto_bad;
if (!(s->sync_action = dm_pool_strndup(mem, pp, p - pp - 1))) if (!(s->sync_action = dm_pool_zalloc(mem, pp - p)))
goto_bad; goto_bad;
if (sscanf(p, FMTu64, &s->mismatch_count) != 1) if (sscanf(p, "%s " FMTu64, s->sync_action, &s->mismatch_count) != 2)
goto_bad; goto_bad;
if (num_fields < 7) if (num_fields < 7)
@ -171,35 +166,23 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
if (sscanf(p, FMTu64, &s->data_offset) != 1) if (sscanf(p, FMTu64, &s->data_offset) != 1)
goto bad; goto bad;
/* <journal_char> - 'A' - active write-through journal device.
* - 'a' - active write-back journal device.
* - 'D' - dead journal device.
* - '-' - no journal device.
*/
out: out:
*status = s; *status = s;
while (i-- > 0) if (s->insync_regions == s->total_regions) {
if (s->dev_health[i] == 'a') /* FIXME: kernel gives misleading info here
a++; /* Count number of 'a' */ * Trying to recognize a true state */
while (i-- > 0)
if (s->dev_health[i] == 'a')
a++; /* Count number of 'a' */
if (a) { if (a && a < s->dev_count) {
if ((a < s->dev_count) && /* SOME legs are in 'a' */ /* SOME legs are in 'a' */
/* FIXME: kernel gives misleading info here if (!strcasecmp(s->sync_action, "recover")
* Trying to recognize a true state */ || !strcasecmp(s->sync_action, "idle"))
(s->insync_regions == s->total_regions) && /* Kernel may possibly start some action
(!strcasecmp(s->sync_action, "recover") || * in near-by future, do not report 100% */
!strcasecmp(s->sync_action, "idle"))) { s->insync_regions--;
/* Kernel may possibly start some action
* in near-by future, do not report 100% */
s->insync_regions--;
}
if ((a == s->dev_count) && /* all legs are in 'a' */
(!strcasecmp(s->sync_action, "resync") ||
!strcasecmp(s->sync_action, "idle"))) {
/* Mark 1st. leg in sync */
s->dev_health[0] = 'A';
} }
} }
@ -335,19 +318,11 @@ int dm_get_status_cache(struct dm_pool *mem, const char *params,
/* Read in policy args */ /* Read in policy args */
pp = p; pp = p;
if (!(p = _skip_fields(p, 1))) if (!(p = _skip_fields(p, 1)) ||
goto_bad; !(s->policy_name = dm_pool_zalloc(mem, (p - pp))))
goto bad;
i = p - pp; if (sscanf(pp, "%s %d", s->policy_name, &s->policy_argc) != 2)
if ((i < 1) ||
!(s->policy_name = dm_pool_zalloc(mem, i)))
goto_bad;
dm_strncpy(s->policy_name, pp, i);
if (sscanf(p, "%d", &s->policy_argc) != 1)
goto bad; goto bad;
if (s->policy_argc && if (s->policy_argc &&
(!(s->policy_argv = dm_pool_zalloc(mem, sizeof(char *) * s->policy_argc)) || (!(s->policy_argv = dm_pool_zalloc(mem, sizeof(char *) * s->policy_argc)) ||
!(p = _skip_fields(p, 1)) || !(p = _skip_fields(p, 1)) ||
@ -409,12 +384,12 @@ int dm_get_status_integrity(struct dm_pool *mem, const char *params,
struct dm_status_integrity **status) struct dm_status_integrity **status)
{ {
struct dm_status_integrity *s; struct dm_status_integrity *s;
char recalc_str[16] = { 0 }; char recalc_str[16] = "\0";
if (!(s = dm_pool_zalloc(mem, sizeof(*s)))) if (!(s = dm_pool_zalloc(mem, sizeof(*s))))
return_0; return_0;
if (sscanf(params, "%llu %llu %15s", if (sscanf(params, "%llu %llu %s",
(unsigned long long *)&s->number_of_mismatches, (unsigned long long *)&s->number_of_mismatches,
(unsigned long long *)&s->provided_data_sectors, (unsigned long long *)&s->provided_data_sectors,
recalc_str) != 3) { recalc_str) != 3) {
@ -536,21 +511,6 @@ int dm_get_status_thin(struct dm_pool *mem, const char *params,
return 1; return 1;
} }
static dm_status_mirror_health_t _get_health(char c)
{
switch (c) {
case 'A': return DM_STATUS_MIRROR_ALIVE;
case 'F': return DM_STATUS_MIRROR_FLUSH_FAILED;
case 'D': return DM_STATUS_MIRROR_WRITE_FAILED;
case 'S': return DM_STATUS_MIRROR_SYNC_FAILED;
case 'R': return DM_STATUS_MIRROR_READ_FAILED;
default:
log_warn("WARNING: Unknown mirror health status char: %c", c);
/* fall through */
case 'U': return DM_STATUS_MIRROR_UNCLASSIFIED;
}
}
/* /*
* dm core parms: 0 409600 mirror * dm core parms: 0 409600 mirror
* Mirror core parms: 2 253:4 253:5 400/400 * Mirror core parms: 2 253:4 253:5 400/400
@ -579,7 +539,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
pos += used; pos += used;
if (num_devs > DM_MIRROR_MAX_IMAGES) { if (num_devs > DM_MIRROR_MAX_IMAGES) {
log_error(INTERNAL_ERROR "More than " DM_TO_STRING(DM_MIRROR_MAX_IMAGES) log_error(INTERNAL_ERROR "More then " DM_TO_STRING(DM_MIRROR_MAX_IMAGES)
" reported in mirror status."); " reported in mirror status.");
goto out; goto out;
} }
@ -604,7 +564,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
pos += used; pos += used;
for (i = 0; i < num_devs ; ++i) for (i = 0; i < num_devs ; ++i)
s->devs[i].health = _get_health(pos[i]); s->devs[i].health = pos[i];
if (!(pos = _skip_fields(pos, argc))) if (!(pos = _skip_fields(pos, argc)))
goto_out; goto_out;
@ -649,7 +609,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
goto_out; goto_out;
for (i = 0; i < s->log_count; ++i) for (i = 0; i < s->log_count; ++i)
s->logs[i].health = _get_health(pos[i]); s->logs[i].health = pos[i];
} }
} }

View File

@ -13,8 +13,6 @@
# include <linux/types.h> # include <linux/types.h>
#endif #endif
#include <stdint.h>
#define DM_DIR "mapper" /* Slashes not supported */ #define DM_DIR "mapper" /* Slashes not supported */
#define DM_CONTROL_NODE "control" #define DM_CONTROL_NODE "control"
#define DM_MAX_TYPE_NAME 16 #define DM_MAX_TYPE_NAME 16
@ -211,7 +209,7 @@ struct dm_name_list {
}; };
#define DM_NAME_LIST_FLAG_HAS_UUID 1 #define DM_NAME_LIST_FLAG_HAS_UUID 1
#define DM_NAME_LIST_FLAG_DOES_NOT_HAVE_UUID 2 #define DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID 2
/* /*
* Used to retrieve the target versions * Used to retrieve the target versions

View File

@ -62,7 +62,7 @@
* *
* The UUID contained in the dm_ulog_request structure is the reference that * The UUID contained in the dm_ulog_request structure is the reference that
* will be used by all request types to a specific log. The constructor must * will be used by all request types to a specific log. The constructor must
* record this association with the instance created. * record this assotiation with the instance created.
* *
* When the request has been processed, user-space must return the * When the request has been processed, user-space must return the
* dm_ulog_request to the kernel - setting the 'error' field, filling the * dm_ulog_request to the kernel - setting the 'error' field, filling the

View File

@ -13,8 +13,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "base/memory/zalloc.h" #include "dmlib.h"
#include "device_mapper/misc/dmlib.h"
#include <assert.h> #include <assert.h>
struct block { struct block {

View File

@ -14,7 +14,7 @@
*/ */
#ifdef VALGRIND_POOL #ifdef VALGRIND_POOL
#include <memcheck.h> #include "memcheck.h"
#endif #endif
#include "base/memory/zalloc.h" #include "base/memory/zalloc.h"

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