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

Compare commits

..

4 Commits

Author SHA1 Message Date
5e48b04561 pvscan: only add device args to dev cache
Optimize the common pvscan --cache command by only adding
the necessary devs to dev-cache.
2021-10-18 16:24:24 -05:00
3e893b9b09 hints: new pvs_online type
Use a new form of hints to reduce device scanning in
vgchange -aay run by the udev rule for event based
autoactivation.

Standard hints allow a command with a named VG arg to scan
only the PVs in the named VG, rather than scanning all
available PVs.  Standard hints are useful with a stable set
of system devices.  When new devices are arriving, as occurs
during system startup, the hints are repeatedly invalidated,
which makes standard hints unhelpful while devices are
regularly appearing.  This is the situation in which
vgchange -aay is used, so standard hints are not generally
helpful for autoactivation.

In the context of system startup, pvscan --cache is keeping
track of available PVs using the pvs_online files, similar
to what the hints file does for a running system.  Given this,
a new hint mode, hints = "pvs_online", is added which derives
an equivalent to standard hints, based on pvs_online files
that are being created by udev-run pvscans.  This hint mode
is useful while devices are appearing, e.g. during system
startup, and vgchange -aay can benefit from it.

pvscan --cache -aay autoactivation already has a similar
optimization (the "quick" activation case) that is based
on the pvs_online file, but it is not implemented as a
form of hints.

This new form of hints is mainly useful in the context of
event based autoactivation, during which standard hints are
not useful.  Once the system is in a steady state after startup
(devices are not regularly appearing), the standard hints are
most useful.  The pvs_online hint method could be used on a
running system, but would be no better than standard hints,
and may be inferior because pvs_online files are not rigidly
updated after system startup.
2021-10-15 16:27:04 -05:00
c06d5fe28e add fixed event activation services
Add two new fixed activation services for startup:
lvm-activate-vgs-main and lvm-activate-vgs-last.

The -main service runs early, without service dependencies.
The -last service runs later, after other services have
started (other services that may set up devices for PVs,
like mulitpathd.)

The lvm-activate-vgs services both run "vgchange -aay"
to activate all VGs that are preset and complete at the
time of system startup.  When there are many VGs, these
two vgchange commands will replace many per-VG vgchange
commands.

The last service enables event activation by creating
the file /run/lvm/event-activation-on.  After that,
new devices that appear will be processed by event based
autoactivation commands.  Prior to the existence of the
event-activation-on file, event-based commands do nothing.

lvm.conf event_activation_options can be used to
configure service-based activation only, or event-based
activation only, or the approach described above which
begins with service based activation and then switches
to event-based.

service_only: only the -main and -last services will
activate VGs.  VGs on devices that appear later will
not be autoactivated.

event_only: the -main and -last services will not
activate any VGs, and all VGs will be activated
from per-VG event-based activation commands.

service_to_event: the -main and -last services will
activate VGs that are complete at the time the
services run, and VGs that appear later will be
activated from per-VG event-based activation
commands.
2021-10-15 16:25:01 -05:00
4f1957ee50 vgchange: add vgonline option
Using --vgonline with vgchange -aay makes vgchange use
/run/lvm/vgs_online/ files in the same way as pvscan.
If the online file for the vg does not exist and the
command is able to exclusively create it, then it will
activate the VG.  If the online file exists or the create
fails, then the VG will not be activated.
2021-10-15 12:59:03 -05:00
631 changed files with 27085 additions and 54256 deletions

32
.gitignore vendored
View File

@ -14,14 +14,8 @@
*.so
*.so.*
*.sw*
*.su
*.patch
*~
# gcov files:
*.gcda
*.gcno
.export.sym
.exported_symbols_generated
.gdb_history
@ -45,19 +39,12 @@ make.tmpl
coverity/coverity_model.xml
/.cache/
/compile_commands.json
/doc/.ikiwiki
/public
/libdm/.symver_check
daemons/clvmd
daemons/dmfilemapd
daemons/lvmetad/
# gcov files:
*.gcda
*.gcno
tools/man-generator
tools/man-generator.c
test/.lib-dir-stamp
test/.tests-stamp
@ -115,8 +102,6 @@ test/api/thin_percent.t
test/api/vglist.t
test/api/vgtest.t
test/lib/aux
test/lib/cache-mq.profile
test/lib/cache-smq.profile
test/lib/check
test/lib/clvmd
test/lib/dm-version-expected
@ -126,7 +111,6 @@ test/lib/dmstats
test/lib/fail
test/lib/flavour-ndev-cluster
test/lib/flavour-ndev-cluster-lvmpolld
test/lib/flavour-ndev-devicesfile
test/lib/flavour-ndev-lvmetad
test/lib/flavour-ndev-lvmetad-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-lvmpolld
test/lib/flavour-udev-lvmlockd-dlm
test/lib/flavour-udev-lvmlockd-idm
test/lib/flavour-udev-lvmlockd-sanlock
test/lib/flavour-udev-lvmlockd-test
test/lib/flavour-udev-lvmpolld
@ -149,13 +132,8 @@ test/lib/lvm
test/lib/lvm-wrapper
test/lib/lvmchange
test/lib/lvmdbusd.profile
test/lib/lvmdevices
test/lib/lvmetad
test/lib/lvmlockctl
test/lib/lvmlockd
test/lib/lvmpolld
test/lib/lvm_import_vdo
test/lib/lvm_vdo_wrapper
test/lib/not
test/lib/paths
test/lib/paths-common
@ -165,7 +143,5 @@ test/lib/test
test/lib/thin-performance.profile
test/lib/utils
test/lib/version-expected
test/lib/vgimportdevices
test/unit/dmraid_t.c
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
tools.distclean: test.distclean
endif
DISTCLEAN_DIRS += lcov_reports* autom4te.cache
DISTCLEAN_DIRS += lcov_reports*
DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
include make.tmpl
@ -47,7 +47,7 @@ include $(top_srcdir)/base/Makefile
include $(top_srcdir)/device_mapper/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
scripts: lib
tools: lib libdaemon
@ -55,7 +55,7 @@ po: tools daemons
man: tools
all_man: tools
test: tools daemons
unit-test run-unit-test: test libdm
unit-test run-unit-test: test
daemons.device-mapper: libdm.device-mapper
tools.device-mapper: libdm.device-mapper
@ -127,7 +127,6 @@ all_man:
install_system_dirs:
$(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_BACKUP_DIR)
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_CACHE_DIR)
@ -172,7 +171,6 @@ help:
@echo " lcov-dated Generate lcov with timedate suffix."
@echo " lcov-reset Reset lcov counters"
@echo " man Build man pages."
@echo " print-VARIABLE Resolve make variable."
@echo " rpm Build rpm."
@echo " run-unit-test Run unit tests."
@echo " tags Generate c/etags."

29
README
View File

@ -1,5 +1,7 @@
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.
Installation instructions are in INSTALL.
@ -10,30 +12,20 @@ Tarballs are available from:
https://github.com/lvmteam/lvm2/releases
The source code is stored in git:
https://gitlab.com/lvmteam/lvm2
Clone:
git clone git@gitlab.com:lvmteam/lvm2.git
Anonymous access:
git clone https://gitlab.com/lvmteam/lvm2.git
Mirrored to:
* https://github.com/lvmteam/lvm2
https://sourceware.org/git/?p=lvm2.git
git clone git://sourceware.org/git/lvm2.git
mirrored to:
https://github.com/lvmteam/lvm2
git clone https://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:
linux-lvm@lists.linux.dev
Subscribe via email to: linux-lvm+subscribe@lists.linux.dev
Archive https://lore.kernel.org/linux-lvm/
Older archive https://listman.redhat.com/archives/linux-lvm/
linux-lvm@redhat.com
Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm
Mailing lists for LVM2 development, patches and commits:
lvm-devel@lists.linux.dev
Subscribe via email to: lvm-devel+subscribe@lists.linux.dev
Archive https://lore.kernel.org/lvm-devel/
Older archive https://listman.redhat.com/archives/lvm-devel/
lvm-devel@redhat.com
Subscribe from https://www.redhat.com/mailman/listinfo/lvm-devel
lvm2-commits@lists.fedorahosted.org (Read-only archive of commits)
Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits
@ -49,7 +41,6 @@ Website:
Report upstream bugs at:
https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper
or open issues at:
https://gitlab.com/groups/lvmteam/-/issues
https://github.com/lvmteam/lvm2/issues
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
- 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
`--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.
To run D-Bus daemon tests, existing D-Bus session is required.

View File

@ -1 +1 @@
2.03.26(2) (2024-08-23)
2.03.14(2)-git (2021-08-11)

View File

@ -1 +1 @@
1.02.200 (2024-08-23)
1.02.181-git (2021-08-11)

185
WHATS_NEW
View File

@ -1,178 +1,5 @@
Version 2.03.26 - 23rd August 2024
Version 2.03.14 -
==================================
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 manipuilate 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.
Bettter 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 desriptors 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.
Recognize 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.
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 lossing of delete message on thin-pool extension.
Version 2.03.15 - 07th February 2022
====================================
Remove service based autoactivation. global/event_activation = 0 is NOOP.
Improve support for metadata profiles for --type writecache.
Use cache or active DM device when available with new kernels.
Introduce function to utilize UUIDs from DM_DEVICE_LIST.
Increase some hash table size to better support large device sets.
Version 2.03.14 - 20th October 2021
===================================
Device scanning is skipping directories on different filesystems.
Print info message with too many or too large archived files.
Reduce metadata readings during scanning phase.
Optimize computation of crc32 check sum with multiple PVs.
@ -180,7 +7,7 @@ Version 2.03.14 - 20th October 2021
Filter out unsupported MQ/SMQ cache policy setting.
Fix memleak in mpath filter.
Support newer location for VDO statistics.
Add support for VDO async-unsafe write policy.
Add support for VDO async-unsage write policy.
Improve lvm_import_vdo script.
Support VDO LV with lvcreate -ky.
Fix lvconvert for VDO LV bigger then 2T.
@ -248,7 +75,7 @@ Version 2.03.12 - 07th May 2021
Fix IMSM MD RAID detection on 4k devices.
Check for presence of VDO target before starting any conversion.
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.
Fix crashing lvdisplay when thin volume was waiting for merge.
Support option --errorwhenfull when converting volume to thin-pool.
@ -321,7 +148,7 @@ Version 2.03.10 - 09th August 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.
Version 2.03.08 - 11th February 2020
@ -3334,7 +3161,7 @@ Version 2.02.68 - 23rd June 2010
Add device name and offset to raw_read_mda_header error messages.
Honour log argument when down-converting stacked mirror.
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.
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.
@ -5468,5 +5295,3 @@ Display output. Some metadata information cannot yet be displayed.
Recovery tools to salvage "lost" metadata directly from the disks:
but we hope the new format will mean such tools are hardly ever needed!

View File

@ -1,69 +1,5 @@
Version 1.02.200 - 23rd August 2024
Version 1.02.181 -
===================================
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
=====================================
Unmangle UUIDs for DM_DEVICE_LIST ioctl.
Version 1.02.181 - 20th October 2021
====================================
Add IMA support with 'dmsetup measure' command.
Add defines DM_NAME_LIST_FLAG_HAS_UUID, DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID.
Enhance tracking of activated devices when preloading dm tree.
@ -1156,7 +1092,7 @@ Version 1.02.37 - 15th September 2009
Version 1.02.36 - 6th August 2009
=================================
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
================================
@ -1559,5 +1495,3 @@ Version 1.00.08 - 27 Feb 2004
Fixed DESTDIR for make install/install_static_lib.
Updated README/INSTALL to reflect move to sources.redhat.com.
Updated autoconf files to 2003-06-17.

View File

@ -62,24 +62,6 @@ AC_DEFUN([AC_TRY_LDFLAGS],
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
# ===========================================================================

306
aclocal.m4 vendored
View File

@ -1,6 +1,6 @@
# generated automatically by aclocal 1.16.5 -*- Autoconf -*-
# generated automatically by aclocal 1.16.2 -*- Autoconf -*-
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
# Copyright (C) 1996-2020 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -69,8 +69,8 @@ AC_DEFUN([AX_PYTHON_MODULE],[
fi
])
# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*-
# serial 12 (pkg-config-0.29.2)
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 11 (pkg-config-0.29.1)
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
@ -112,7 +112,7 @@ dnl
dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require.
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_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ
@ -157,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
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 have to call PKG_CHECK_EXISTS manually
AC_DEFUN([PKG_CHECK_EXISTS],
@ -213,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
pkg_failed=no
AC_MSG_CHECKING([for $2])
AC_MSG_CHECKING([for $1])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
@ -223,17 +223,17 @@ and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
AC_MSG_RESULT([no])
AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
# Put the nasty error message in config.log where it belongs
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:
$$1_PKG_ERRORS
@ -244,8 +244,8 @@ installed software in a non-standard prefix.
_PKG_TEXT])[]dnl
])
elif test $pkg_failed = untried; then
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
[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
path to pkg-config.
@ -255,10 +255,10 @@ _PKG_TEXT
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
])
else
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
AC_MSG_RESULT([yes])
$3
$3
fi[]dnl
])dnl PKG_CHECK_MODULES
@ -413,7 +413,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
])dnl PKG_HAVE_DEFINE_WITH_MODULES
# Copyright (C) 1999-2021 Free Software Foundation, Inc.
# Copyright (C) 1999-2020 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -492,7 +492,7 @@ AC_DEFUN([AM_PATH_PYTHON],
])
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])])
else
@ -501,132 +501,27 @@ AC_DEFUN([AM_PATH_PYTHON],
dnl trailing zero was eliminated. So now we output just the major
dnl and minor version numbers, as numbers. Apparently the tertiary
dnl version is not of interest.
dnl
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])
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
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)"`])
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
dnl emacs-page
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.
# Just factor out some code duplication.
am_python_setup_sysconfig="\
import sys
# Prefer sysconfig over distutils.sysconfig, for better compatibility
@ -646,95 +541,96 @@ try:
except ImportError:
pass"
dnl emacs-page Set up 4 directories:
dnl Set up 4 directories:
dnl 1. pythondir: where to install python scripts. This is the
dnl site-packages directory, not the python standard library
dnl directory like in previous automake betas. This behavior
dnl is more consistent with lispdir.m4 for example.
dnl pythondir -- where to install python scripts. This is the
dnl site-packages directory, not the python standard library
dnl directory like in previous automake betas. This behavior
dnl is more consistent with lispdir.m4 for example.
dnl Query distutils for this directory.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON script directory (pythondir)],
[am_cv_python_pythondir],
[if test "x$am_cv_python_prefix" = x; then
am_py_prefix=$am__usable_prefix
else
am_py_prefix=$am_cv_python_prefix
fi
am_cv_python_pythondir=`$PYTHON -c "
AC_CACHE_CHECK([for $am_display_PYTHON script directory],
[am_cv_python_pythondir],
[if test "x$prefix" = xNONE
then
am_py_prefix=$ac_default_prefix
else
am_py_prefix=$prefix
fi
am_cv_python_pythondir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
else:
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"`
#
case $am_cv_python_pythondir in
$am_py_prefix*)
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},"`
;;
*)
case $am_py_prefix in
/usr|/System*) ;;
*) am_cv_python_pythondir="\${PYTHON_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
;;
case $am_cv_python_pythondir in
$am_py_prefix*)
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,"`
;;
*)
case $am_py_prefix in
/usr|/System*) ;;
*)
am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
;;
esac
;;
esac
;;
esac
])
])
AC_SUBST([pythondir], [$am_cv_python_pythondir])
dnl 2. pkgpythondir: $PACKAGE directory under pythondir. Was
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
dnl more consistent with the rest of automake.
dnl
dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
dnl more consistent with the rest of automake.
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
dnl 3. pyexecdir: directory for installing python extension modules
dnl (shared libraries).
dnl pyexecdir -- directory for installing python extension modules
dnl (shared libraries)
dnl Query distutils for this directory.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory (pyexecdir)],
[am_cv_python_pyexecdir],
[if test "x$am_cv_python_exec_prefix" = x; then
am_py_exec_prefix=$am__usable_exec_prefix
else
am_py_exec_prefix=$am_cv_python_exec_prefix
fi
am_cv_python_pyexecdir=`$PYTHON -c "
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
[am_cv_python_pyexecdir],
[if test "x$exec_prefix" = xNONE
then
am_py_exec_prefix=$am_py_prefix
else
am_py_exec_prefix=$exec_prefix
fi
am_cv_python_pyexecdir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_exec_prefix'})
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
else:
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix')
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"`
#
case $am_cv_python_pyexecdir in
$am_py_exec_prefix*)
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},"`
;;
*)
case $am_py_exec_prefix in
/usr|/System*) ;;
*) am_cv_python_pyexecdir="\${PYTHON_EXEC_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
;;
case $am_cv_python_pyexecdir in
$am_py_exec_prefix*)
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,"`
;;
*)
case $am_py_exec_prefix in
/usr|/System*) ;;
*)
am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
;;
esac
;;
esac
;;
esac
])
])
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
dnl 4. pkgpyexecdir: $(pyexecdir)/$(PACKAGE)
dnl
dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
dnl Run any user-specified action.
$2
fi
])
@ -757,7 +653,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
sys.exit(sys.hexversion < minverhex)"
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
# Copyright (C) 2001-2020 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# 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
scriptversion=2020-11-14.01; # UTC
scriptversion=2006-10-14.15
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# 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.
#
# 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.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
IFS=" "" $nl"
# Set DOITPROG to "echo" to test this script.
# set DOITPROG to echo to test this script
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Don't use :- since 4.3BSD and earlier shells don't like it.
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;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
posix_glob=
posix_mkdir=
# Desired mode of installed file.
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
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
chgrpcmd=
stripcmd=
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=
dst=
dir_arg=
dst_arg=
dstarg=
no_target_directory=
copy_on_change=false
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
@ -100,116 +95,91 @@ In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-p pass -p to $cpprog.
-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.
-c (ignored)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
--help display this help and exit.
--version display version info and exit.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
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/
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-c) shift
continue;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-d) dir_arg=true
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
shift
shift
continue;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
shift
shift
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
continue;;
-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"
shift;;
-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;;
-T) no_target_directory=true
shift
continue;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# 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
if test $# -ne 0 && test -z "$dir_arg$dstarg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
if test -n "$dstarg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
set fnord "$@" "$dstarg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
dstarg=$arg
done
fi
@ -218,26 +188,13 @@ if test $# -eq 0; then
echo "$0: no input file specified." >&2
exit 1
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.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
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
trap '(exit $?); exit' 1 2 13 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
@ -248,16 +205,16 @@ if test -z "$dir_arg"; then
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
u_plus_rw=
else
u_plus_rw='% 200'
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
u_plus_rw=
else
u_plus_rw=,u+rw
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
@ -265,9 +222,9 @@ fi
for src
do
# Protect names problematic for 'test' and other utilities.
# Protect names starting with `-'.
case $src in
-* | [=\(\)!]) src=./$src;;
-*) src=./$src ;;
esac
if test -n "$dir_arg"; then
@ -275,10 +232,6 @@ do
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
# Don't chown directories that already exist.
if test $dstdir_status = 0; then
chowncmd=""
fi
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
@ -289,154 +242,196 @@ do
exit 1
fi
if test -z "$dst_arg"; then
if test -z "$dstarg"; then
echo "$0: no destination specified." >&2
exit 1
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 "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
if test -n "$no_target_directory"; then
echo "$0: $dstarg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dstbase=`basename "$src"`
case $dst in
*/) dst=$dst$dstbase;;
*) dst=$dst/$dstbase;;
esac
dst=$dstdir/`basename "$src"`
dstdir_status=0
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"
dstdir_status=$?
fi
fi
case $dstdir in
*/) dstdirslash=$dstdir;;
*) dstdirslash=$dstdir/;;
esac
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
posix_mkdir=false
# The $RANDOM variable is not portable (e.g., dash). Use it
# here however when possible just to lower collision chance.
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
trap '
ret=$?
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
exit $ret
' 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"
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
mkdir_mode=
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
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
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
# directory the slow way, step by step, checking for races as we go.
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
oIFS=$IFS
IFS=/
set -f
$posix_glob && set -f
set fnord $dstdir
shift
set +f
$posix_glob && set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
test -z "$d" && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
@ -449,25 +444,14 @@ do
else
# Make a couple of temp file names in the proper directory.
dsttmp=${dstdirslash}_inst.$$_
rmtmp=${dstdirslash}_rm.$$_
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask &&
{ 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") &&
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# 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
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
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
# Now rename the file to the real destination.
{ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
|| {
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# 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.
{
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
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# 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
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
} || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp)
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# time-stamp-end: "$"
# End:

View File

@ -1,9 +1,9 @@
#!/bin/sh
# 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
# 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.
# 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
# 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
# <automake-patches@gnu.org>.
if test -z "$PYTHON"; then
if [ -z "$PYTHON" ]; then
PYTHON=python
fi
@ -62,19 +62,13 @@ while test $# -ne 0; do
;;
-h|--help)
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
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
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:
py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py
@ -100,143 +94,77 @@ EOF
shift
done
if test $# -eq 0; then
usage_error "no files given"
files=$*
if test -z "$files"; then
usage_error "no files given"
fi
# if basedir was given, then it should be prepended to filenames before
# byte compilation.
if test -z "$basedir"; then
pathtrans="path = file"
if [ -z "$basedir" ]; then
pathtrans="path = file"
else
pathtrans="path = os.path.join('$basedir', file)"
pathtrans="path = os.path.join('$basedir', file)"
fi
# if destdir was given, then it needs to be prepended to the filename to
# byte compile but not go into the compiled file.
if test -z "$destdir"; then
filetrans="filepath = path"
if [ -z "$destdir" ]; then
filetrans="filepath = path"
else
filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
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 "
import sys, os, py_compile
import sys, os, py_compile, imp
try:
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'
files = '''$files'''
sys.stdout.write('Byte-compiling python modules...\n')
for file in sys.argv[1:]:
for file in files.split():
$pathtrans
$filetrans
if (
not os.path.exists(filepath)
or not (len(filepath) >= 3 and filepath[-3:] == '.py')
):
continue
sys.stdout.write(file + ' ')
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, destpath(filepath), path)
sys.stdout.write('\n')" "$@" || exit $?
if hasattr(imp, 'get_tag'):
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 "
import sys, os, py_compile
import sys, os, py_compile, imp
try:
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 + 'o'
# pypy2 does not use .pyo optimization
if sys.version_info.major <= 2 and hasattr(sys, 'pypy_translation_info'):
# pypy does not use .pyo optimization
if hasattr(sys, 'pypy_translation_info'):
sys.exit(0)
files = '''$files'''
sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n')
for file in sys.argv[1:]:
for file in files.split():
$pathtrans
$filetrans
if (
not os.path.exists(filepath)
or not (len(filepath) >= 3 and filepath[-3:] == '.py')
):
continue
sys.stdout.write(file + ' ')
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, destpath(filepath), path)
sys.stdout.write('\n')" "$@" 2>/dev/null || exit $?
# Then byte compile w/more optimization.
# Only do this for Python 3.5+, see https://bugs.gnu.org/38043 for background.
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
if hasattr(imp, 'get_tag'):
py_compile.compile(filepath, imp.cache_from_source(filepath, False), path)
else:
py_compile.compile(filepath, filepath + 'o', path)
sys.stdout.write('\n')" 2>/dev/null || :
# Local Variables:
# mode: shell-script
# 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-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

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

View File

@ -41,7 +41,7 @@ struct dm_hash_table {
static unsigned _hash(const void *key, unsigned len)
{
/* 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,
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,

View File

@ -19,7 +19,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//----------------------------------------------------------------
@ -70,7 +69,7 @@ struct node48 {
};
struct node256 {
uint32_t nr_entries;
uint32_t nr_entries;
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)
{
if (rt->dtr)
rt->dtr(rt->dtr_context, v);
rt->dtr(rt->dtr_context, v);
}
// Returns the number of values removed
@ -119,8 +118,8 @@ static unsigned _free_node(struct radix_tree *rt, struct value v)
break;
case VALUE:
_dtr(rt, v.value);
nr = 1;
_dtr(rt, v.value);
nr = 1;
break;
case VALUE_CHAIN:
@ -179,9 +178,9 @@ unsigned radix_tree_size(struct radix_tree *rt)
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;
@ -208,7 +207,7 @@ static bool _insert_unset(struct radix_tree *rt, struct value *v, const uint8_t
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;
@ -235,7 +234,7 @@ static bool _insert_value(struct radix_tree *rt, struct value *v, const uint8_t
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;
return _insert(rt, &vc->child, kb, ke, rv);
@ -249,7 +248,7 @@ static unsigned min(unsigned lhs, unsigned 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;
@ -314,7 +313,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
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;
if (n4->nr_entries == 4) {
@ -344,7 +343,7 @@ static bool _insert_node4(struct radix_tree *rt, struct value *v, const uint8_t
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;
@ -383,7 +382,7 @@ static bool _insert_node16(struct radix_tree *rt, struct value *v, const uint8_t
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;
if (n48->nr_entries == 48) {
@ -418,20 +417,20 @@ static bool _insert_node48(struct radix_tree *rt, struct value *v, const uint8_t
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;
bool r, was_unset = n256->values[*kb].type == UNSET;
r = _insert(rt, n256->values + *kb, kb + 1, ke, rv);
if (r && was_unset)
n256->nr_entries++;
n256->nr_entries++;
return r;
}
// 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 (v->type == UNSET) {
@ -488,10 +487,10 @@ static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, c
struct lookup_result {
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;
struct value_chain *vc;
@ -501,7 +500,7 @@ static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, c
struct node48 *n48;
struct node256 *n256;
if (kb == ke || !kb) /* extra check for !kb for coverity */
if (kb == ke)
return (struct lookup_result) {.v = v, .kb = kb};
switch (v->type) {
@ -556,10 +555,8 @@ static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, c
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);
return _insert(rt, lr.v, lr.kb, ke, rv);
}
@ -567,14 +564,14 @@ bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen, un
// Note the degrade functions also free the original node.
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);
n4->nr_entries = n16->nr_entries;
memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys));
memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values));
free(n16);
n4->nr_entries = n16->nr_entries;
memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys));
memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values));
free(n16);
result->type = NODE4;
result->value.ptr = n4;
@ -583,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)
{
unsigned i, count = 0;
struct node16 *n16 = zalloc(sizeof(*n16));
struct node16 *n16 = zalloc(sizeof(*n16));
assert(n16 != NULL);
n16->nr_entries = n48->nr_entries;
for (i = 0; i < 256; i++) {
if (n48->keys[i] < 48) {
n16->keys[count] = i;
n16->values[count] = n48->values[n48->keys[i]];
count++;
}
}
n16->nr_entries = n48->nr_entries;
for (i = 0; i < 256; i++) {
if (n48->keys[i] < 48) {
n16->keys[count] = i;
n16->values[count] = n48->values[n48->keys[i]];
count++;
}
}
free(n48);
free(n48);
result->type = NODE16;
result->value.ptr = n16;
@ -604,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)
{
unsigned i, count = 0;
struct node48 *n48 = zalloc(sizeof(*n48));
unsigned i, count = 0;
struct node48 *n48 = zalloc(sizeof(*n48));
assert(n48 != NULL);
n48->nr_entries = n256->nr_entries;
for (i = 0; i < 256; i++) {
n48->nr_entries = n256->nr_entries;
for (i = 0; i < 256; i++) {
if (n256->values[i].type == UNSET)
n48->keys[i] = 48;
@ -619,9 +616,9 @@ static void _degrade_to_n48(struct node256 *n256, struct value *result)
n48->values[count] = n256->values[i];
count++;
}
}
}
free(n256);
free(n256);
result->type = NODE48;
result->value.ptr = n48;
@ -635,14 +632,14 @@ static void _erase_elt(void *array, size_t obj_size, unsigned count, unsigned id
return;
memmove(((uint8_t *) array) + (obj_size * idx),
((uint8_t *) array) + (obj_size * (idx + 1)),
obj_size * (count - idx - 1));
((uint8_t *) array) + (obj_size * (idx + 1)),
obj_size * (count - idx - 1));
// Zero the now unused last elt (set's v.type to UNSET)
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;
unsigned i, j;
@ -654,27 +651,27 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
struct node256 *n256;
if (kb == ke) {
if (root->type == VALUE) {
root->type = UNSET;
_dtr(rt, root->value);
return true;
if (root->type == VALUE) {
root->type = UNSET;
_dtr(rt, root->value);
return true;
} else if (root->type == VALUE_CHAIN) {
} else if (root->type == VALUE_CHAIN) {
vc = root->value.ptr;
_dtr(rt, vc->value);
memcpy(root, &vc->child, sizeof(*root));
free(vc);
return true;
} else
} else
return false;
}
switch (root->type) {
case UNSET:
case VALUE:
// this is a value for a prefix of the key
return false;
// this is a value for a prefix of the key
return false;
case VALUE_CHAIN:
vc = root->value.ptr;
@ -689,11 +686,11 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
case PREFIX_CHAIN:
pc = root->value.ptr;
if (ke - kb < pc->len)
return false;
return false;
for (i = 0; i < pc->len; i++)
if (kb[i] != pc->prefix[i])
return false;
return false;
r = _remove(rt, &pc->child, kb + pc->len, ke);
if (r && pc->child.type == UNSET) {
@ -708,12 +705,12 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
if (n4->keys[i] == *kb) {
r = _remove(rt, n4->values + i, kb + 1, ke);
if (r && n4->values[i].type == UNSET) {
if (i < n4->nr_entries) {
_erase_elt(n4->keys, sizeof(*n4->keys), n4->nr_entries, i);
_erase_elt(n4->values, sizeof(*n4->values), n4->nr_entries, i);
}
if (i < n4->nr_entries) {
_erase_elt(n4->keys, sizeof(*n4->keys), 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) {
free(n4);
root->type = UNSET;
@ -725,19 +722,19 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
return false;
case NODE16:
n16 = root->value.ptr;
n16 = root->value.ptr;
for (i = 0; i < n16->nr_entries; i++) {
if (n16->keys[i] == *kb) {
r = _remove(rt, n16->values + i, kb + 1, ke);
if (r && n16->values[i].type == UNSET) {
if (i < n16->nr_entries) {
_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i);
_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i);
}
if (i < n16->nr_entries) {
_erase_elt(n16->keys, sizeof(*n16->keys), 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) {
_degrade_to_n4(n16, root);
_degrade_to_n4(n16, root);
}
}
return r;
@ -749,18 +746,18 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
n48 = root->value.ptr;
i = n48->keys[*kb];
if (i < 48) {
r = _remove(rt, n48->values + i, kb + 1, ke);
if (r && n48->values[i].type == UNSET) {
n48->keys[*kb] = 48;
for (j = 0; j < 256; j++)
if (n48->keys[j] < 48 && n48->keys[j] > i)
n48->keys[j]--;
r = _remove(rt, n48->values + i, kb + 1, ke);
if (r && n48->values[i].type == UNSET) {
n48->keys[*kb] = 48;
for (j = 0; j < 256; j++)
if (n48->keys[j] < 48 && n48->keys[j] > i)
n48->keys[j]--;
_erase_elt(n48->values, sizeof(*n48->values), n48->nr_entries, i);
n48->nr_entries--;
if (n48->nr_entries <= 16)
_degrade_to_n16(n48, root);
}
return r;
_degrade_to_n16(n48, root);
}
return r;
}
return false;
@ -770,7 +767,7 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
if (r && n256->values[*kb].type == UNSET) {
n256->nr_entries--;
if (n256->nr_entries <= 48)
_degrade_to_n48(n256, root);
_degrade_to_n48(n256, root);
}
return r;
}
@ -778,14 +775,11 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
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;
const uint8_t *ke = kb + keylen;
if (_remove(rt, &rt->root, kb, ke)) {
rt->nr_entries--;
return true;
if (_remove(rt, &rt->root, key_begin, key_end)) {
rt->nr_entries--;
return true;
}
return false;
@ -793,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
// the remaining key matches part of it.
if (lr->v->type == PREFIX_CHAIN) {
unsigned i, rlen = ke - lr->kb;
const struct prefix_chain *pc = lr->v->value.ptr;
if (rlen < pc->len) {
for (i = 0; i < rlen; i++)
if (pc->prefix[i] != lr->kb[i])
return false;
return true;
// It's possible the top node is a prefix chain, and
// the remaining key matches part of it.
if (lr->v->type == PREFIX_CHAIN) {
unsigned i, rlen = ke - lr->kb;
struct prefix_chain *pc = lr->v->value.ptr;
if (rlen < pc->len) {
for (i = 0; i < rlen; i++)
if (pc->prefix[i] != lr->kb[i])
return false;
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;
unsigned i, j, len;
@ -832,7 +826,7 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
case UNSET:
case VALUE:
// No entries with the given prefix
return true;
return true;
case VALUE_CHAIN:
vc = root->value.ptr;
@ -849,7 +843,7 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
len = min(pc->len, ke - kb);
for (i = 0; i < len; 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);
if (r && pc->child.type == UNSET) {
@ -864,12 +858,12 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
if (n4->keys[i] == *kb) {
r = _remove_subtree(rt, n4->values + i, kb + 1, ke, count);
if (r && n4->values[i].type == UNSET) {
if (i < n4->nr_entries) {
_erase_elt(n4->keys, sizeof(*n4->keys), n4->nr_entries, i);
_erase_elt(n4->values, sizeof(*n4->values), n4->nr_entries, i);
}
if (i < n4->nr_entries) {
_erase_elt(n4->keys, sizeof(*n4->keys), 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) {
free(n4);
root->type = UNSET;
@ -881,19 +875,19 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
return true;
case NODE16:
n16 = root->value.ptr;
n16 = root->value.ptr;
for (i = 0; i < n16->nr_entries; i++) {
if (n16->keys[i] == *kb) {
r = _remove_subtree(rt, n16->values + i, kb + 1, ke, count);
if (r && n16->values[i].type == UNSET) {
if (i < n16->nr_entries) {
_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i);
_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i);
}
if (i < n16->nr_entries) {
_erase_elt(n16->keys, sizeof(*n16->keys), 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)
_degrade_to_n4(n16, root);
_degrade_to_n4(n16, root);
}
return r;
}
@ -904,18 +898,18 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
n48 = root->value.ptr;
i = n48->keys[*kb];
if (i < 48) {
r = _remove_subtree(rt, n48->values + i, kb + 1, ke, count);
if (r && n48->values[i].type == UNSET) {
n48->keys[*kb] = 48;
for (j = 0; j < 256; j++)
if (n48->keys[j] < 48 && n48->keys[j] > i)
n48->keys[j]--;
r = _remove_subtree(rt, n48->values + i, kb + 1, ke, count);
if (r && n48->values[i].type == UNSET) {
n48->keys[*kb] = 48;
for (j = 0; j < 256; j++)
if (n48->keys[j] < 48 && n48->keys[j] > i)
n48->keys[j]--;
_erase_elt(n48->values, sizeof(*n48->values), n48->nr_entries, i);
n48->nr_entries--;
if (n48->nr_entries <= 16)
_degrade_to_n16(n48, root);
}
return r;
_degrade_to_n16(n48, root);
}
return r;
}
return true;
@ -928,7 +922,7 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
if (r && n256->values[*kb].type == UNSET) {
n256->nr_entries--;
if (n256->nr_entries <= 48)
_degrade_to_n48(n256, root);
_degrade_to_n48(n256, root);
}
return r;
}
@ -937,13 +931,11 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
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;
const uint8_t *ke = kb + prefix_len;
unsigned count = 0;
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;
return count;
@ -951,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,
union radix_value *result)
bool 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 value_chain *vc;
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
if (lr.kb == ke) {
@ -978,58 +968,58 @@ bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
}
// 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;
const struct value_chain *vc;
const struct prefix_chain *pc;
const struct node4 *n4;
const struct node16 *n16;
const struct node48 *n48;
const struct node256 *n256;
struct value_chain *vc;
struct prefix_chain *pc;
struct node4 *n4;
struct node16 *n16;
struct node48 *n48;
struct node256 *n256;
switch (v->type) {
case UNSET:
// can't happen
// can't happen
break;
case VALUE:
return it->visit(it, NULL, 0, v->value);
return it->visit(it, NULL, NULL, v->value);
case VALUE_CHAIN:
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:
pc = v->value.ptr;
return _iterate(it, &pc->child);
return _iterate(&pc->child, it);
case NODE4:
n4 = (const struct node4 *) v->value.ptr;
n4 = (struct node4 *) v->value.ptr;
for (i = 0; i < n4->nr_entries; i++)
if (!_iterate(it, n4->values + i))
return false;
return true;
if (!_iterate(n4->values + i, it))
return false;
return true;
case NODE16:
n16 = (const struct node16 *) v->value.ptr;
n16 = (struct node16 *) v->value.ptr;
for (i = 0; i < n16->nr_entries; i++)
if (!_iterate(it, n16->values + i))
return false;
if (!_iterate(n16->values + i, it))
return false;
return true;
case NODE48:
n48 = (const struct node48 *) v->value.ptr;
n48 = (struct node48 *) v->value.ptr;
for (i = 0; i < n48->nr_entries; i++)
if (!_iterate(it, n48->values + i))
return false;
if (!_iterate(n48->values + i, it))
return false;
return true;
case NODE256:
n256 = (const struct node256 *) v->value.ptr;
n256 = (struct node256 *) v->value.ptr;
for (i = 0; i < 256; i++)
if (n256->values[i].type != UNSET && !_iterate(it, n256->values + i))
return false;
if (n256->values[i].type != UNSET && !_iterate(n256->values + i, it))
return false;
return true;
}
@ -1037,14 +1027,12 @@ static bool _iterate(struct radix_tree_iterator *it, const struct value *v)
return false;
}
void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
struct radix_tree_iterator *it)
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
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);
if (lr.kb == ke || _prefix_chain_matches(&lr, ke))
(void) _iterate(it, lr.v);
(void) _iterate(lr.v, it);
}
//----------------------------------------------------------------
@ -1142,7 +1130,7 @@ static bool _check_nodes(struct value *v, unsigned *count)
if (ncount != n48->nr_entries) {
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;
}
@ -1178,7 +1166,7 @@ static bool _check_nodes(struct value *v, unsigned *count)
if (ncount != n256->nr_entries) {
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;
}
@ -1201,7 +1189,7 @@ bool radix_tree_is_well_formed(struct radix_tree *rt)
if (rt->nr_entries != count) {
fprintf(stderr, "incorrect entry count: rt->nr_entries = %u, actual = %u\n",
rt->nr_entries, count);
rt->nr_entries, count);
return false;
}
@ -1219,7 +1207,6 @@ static void _dump(FILE *out, struct value v, unsigned indent)
struct node16 *n16;
struct node48 *n48;
struct node256 *n256;
unsigned printable;
if (v.type == UNSET)
return;
@ -1244,22 +1231,9 @@ static void _dump(FILE *out, struct value v, unsigned indent)
case PREFIX_CHAIN:
pc = v.value.ptr;
fprintf(out, "<prefix(%u): ", pc->len);
printable = 1;
fprintf(out, "<prefix: ");
for (i = 0; i < pc->len; i++)
if (!isprint(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, "%x.", (unsigned) *(pc->prefix + i));
fprintf(out, ">\n");
_dump(out, pc->child, indent + 1);
break;
@ -1268,7 +1242,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
n4 = v.value.ptr;
fprintf(out, "<n4: ");
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");
for (i = 0; i < n4->nr_entries; i++)
@ -1279,7 +1253,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
n16 = v.value.ptr;
fprintf(out, "<n16: ");
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");
for (i = 0; i < n16->nr_entries; i++)
@ -1291,7 +1265,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
fprintf(out, "<n48: ");
for (i = 0; i < 256; i++)
if (n48->keys[i] < 48)
fprintf(out, "%02x ", i);
fprintf(out, "%x ", i);
fprintf(out, ">\n");
for (i = 0; i < n48->nr_entries; i++) {
@ -1305,7 +1279,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
fprintf(out, "<n256: ");
for (i = 0; i < 256; i++)
if (n256->values[i].type != UNSET)
fprintf(out, "%02x ", i);
fprintf(out, "%x ", i);
fprintf(out, ">\n");
for (i = 0; i < 256; i++)

View File

@ -1,5 +1,5 @@
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
//
//
// This file is part of LVM2.
//
// This copyrighted material is made available to anyone wishing to use,
@ -18,7 +18,6 @@
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
//----------------------------------------------------------------
// This implementation is based around nested binary trees. Very
@ -38,12 +37,12 @@ struct node {
struct radix_tree {
radix_value_dtr dtr;
void *dtr_context;
unsigned nr_entries;
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));
@ -106,7 +105,7 @@ unsigned radix_tree_size(struct radix_tree *rt)
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;
@ -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);
}
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;
@ -152,51 +151,39 @@ static bool _insert(struct node **pn, const uint8_t *kb, const uint8_t *ke, unio
return _insert(&n->center, kb + 1, ke, v);
}
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)
{
const uint8_t *kb = key;
const uint8_t *ke = kb + keylen;
if (!_insert(&rt->root, kb, ke, v))
return false;
rt->nr_entries++;
return true;
return _insert(&rt->root, kb, ke, 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)
{
const uint8_t *kb = key;
const uint8_t *ke = kb + keylen;
struct node **pn = _lookup(&rt->root, kb, ke);
struct node *n = *pn;
if (!n || !n->has_value)
return false;
rt->nr_entries--;
else {
if (rt->dtr)
rt->dtr(rt->dtr_context, n->value);
if (rt->dtr)
rt->dtr(rt->dtr_context, n->value);
if (n->left || n->center || n->right) {
n->has_value = false;
return true;
if (n->left || n->center || n->right) {
n->has_value = false;
return true;
} else {
// FIXME: delete parent if this was the last entry
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 *key, size_t keylen)
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
{
const uint8_t *kb = key;
const uint8_t *ke = kb + keylen;
struct node **pn;
unsigned count;
@ -210,20 +197,17 @@ unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *key, size_t
return count;
}
bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
union radix_value *result)
bool
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 *n = *pn;
if (n && n->has_value) {
*result = n->value;
return true;
}
return false;
} else
return false;
}
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)
// 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->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)
{
const uint8_t *kb = key;
const uint8_t *ke = kb + keylen;
if (kb == ke)
_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->has_value)
it->visit(it, NULL, 0, n->value);
it->visit(it, NULL, NULL, n->value);
_iterate(n->center, it);
}
}
@ -267,32 +248,8 @@ bool radix_tree_is_well_formed(struct radix_tree *rt)
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: %llu\n", 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)
{
_dump(out, rt->root, 0);
}
//----------------------------------------------------------------

View File

@ -19,45 +19,3 @@
#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,51 +33,32 @@ struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context);
void radix_tree_destroy(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_remove(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);
bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke);
// 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,
union radix_value *result);
bool radix_tree_lookup(struct radix_tree *rt,
uint8_t *kb, uint8_t *ke, union radix_value *result);
// The radix tree stores entries in lexicographical order. Which means
// we can iterate entries, in order. Or iterate entries with a particular
// prefix.
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,
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,
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);
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
struct radix_tree_iterator *it);
// Checks that some constraints on the shape of the tree are
// being held. For debug only.
bool radix_tree_is_well_formed(struct radix_tree *rt);
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);
}
//----------------------------------------------------------------
#endif

View File

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

View File

@ -126,7 +126,7 @@ devices {
# be used, regardless of this setting, when the --devicesfile
# option is set to a specific file name.
# This configuration option has an automatic default value.
# use_devicesfile = @DEFAULT_USE_DEVICES_FILE@
# use_devicesfile = 0
# Configuration option devices/devicesfile.
# The name of the system devices file, listing devices that LVM should use.
@ -135,16 +135,6 @@ devices {
# This configuration option has an automatic default value.
# 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.
# Look outside of the devices file for missing devname entries.
# A devname entry is used for a device that does not have a stable
@ -159,27 +149,7 @@ devices {
# at other devices, but only those that are likely to have the PV.
# If "all", lvm will look at all devices on the system.
# This configuration option has an automatic default value.
# search_for_devnames = "all"
# 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" ]
# search_for_devnames = "auto"
# Configuration option devices/filter.
# Limit the block devices that are used by LVM commands.
@ -241,12 +211,17 @@ devices {
# sysfs_scan = 1
# Configuration option devices/scan_lvs.
# Allow LVM LVs to be used as PVs. When enabled, LVM commands will
# scan active LVs to look for other PVs. Caution is required to
# avoid using PVs that belong to guest images stored on LVs.
# When enabled, the LVs scanned should be restricted using the
# devices file or the filter. This option does not enable autoactivation
# of layered VGs, which requires editing LVM udev rules (see LVM_PVSCAN_ON_LVS.)
# Scan LVM LVs for layered PVs, allowing LVs to be used as PVs.
# When 1, LVM will detect PVs layered on LVs, and caution must be
# taken to avoid a host accessing a layered VG that may not belong
# to it, e.g. from a guest image. This generally requires excluding
# the LVs with device filters. Also, when this setting is enabled,
# 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.
# scan_lvs = 0
@ -650,12 +625,13 @@ allocation {
# 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.
# 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.
# vdo_minimum_io_size = 4096
@ -675,6 +651,11 @@ allocation {
# This configuration option has an automatic default value.
# 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.
# Enables sparse indexing for VDO volume.
# This configuration option has an automatic default value.
@ -703,7 +684,7 @@ allocation {
# Configuration option allocation/vdo_bio_threads.
# Specifies the number of threads to use for submitting I/O
# 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,
# plus 1.12 MiB of RAM per megabyte of configured read cache size.
# This configuration option has an automatic default value.
@ -717,7 +698,7 @@ allocation {
# Configuration option allocation/vdo_cpu_threads.
# 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.
# vdo_cpu_threads = 2
@ -735,7 +716,7 @@ allocation {
# processing based on the hash value computed from the block data.
# A logical thread count of 9 or more will require explicitly specifying
# 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
# either all zero or all non-zero.
# This configuration option has an automatic default value.
@ -777,7 +758,7 @@ allocation {
# vdo_max_discard = 1
# 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.
# vdo_pool_header_size = 512
}
@ -801,9 +782,6 @@ log {
# to define fields to display and sort fields for the log report.
# You can also use log/command_log_selection to define selection
# criteria used each time the log is reported.
# Note that if report/output_format (or --reporformat 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.
# report_command_log = 0
@ -959,7 +937,7 @@ backup {
# archive = 1
# Configuration option backup/archive_dir.
# Location of the metadata archive files.
# Location of the metdata archive files.
# Remember to back up this directory regularly!
# This configuration option has an automatic default value.
# archive_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@"
@ -1035,7 +1013,7 @@ global {
# Location of proc filesystem.
# This configuration option is advanced.
# This configuration option has an automatic default value.
# proc = "@DEFAULT_PROC_DIR@"
# proc = "/proc"
# Configuration option global/etc.
# Location of /etc system configuration directory.
@ -1173,13 +1151,18 @@ global {
# lvdisplay_shows_full_device_path = 0
# Configuration option global/event_activation.
# Disable event based autoactivation commands.
# WARNING: setting this to zero may cause machine startup to fail.
# Previously, setting this to zero would enable static autoactivation
# services (via the lvm2-activation-generator), but the autoactivation
# services and generator have been removed.
# Activate LVs based on system-generated device events.
# When a PV appears on the system, a system-generated uevent triggers
# the lvm2-pvscan service which runs the pvscan --cache -aay command.
# If the new PV completes a VG, pvscan autoactivates LVs in the VG.
# When event_activation is disabled, the lvm2-activation services are
# generated and run at fixed points during system startup. These
# services run vgchange -aay to autoactivate LVs in VGs that happen
# to be present at that point in time.
# See the --setautoactivation option or the auto_activation_volume_list
# setting to configure autoactivation for specific VGs or LVs.
# This configuration option has an automatic default value.
# event_activation = @DEFAULT_EVENT_ACTIVATION@
# event_activation = 1
# Configuration option global/use_aio.
# Use async I/O when reading and writing devices.
@ -1224,7 +1207,7 @@ global {
# Configuration option global/thin_check_executable.
# 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
# deactivated, this command is run. Activation will only proceed if
# the command has an exit status of 0. Set to "" to skip this check.
@ -1248,14 +1231,6 @@ global {
# This configuration option has an automatic default value.
# 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.
# List of options passed to the thin_check command.
# With thin_check version 2.1 or newer you can add the option
@ -1270,11 +1245,6 @@ global {
# This configuration option has an automatic default value.
# 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.
# Features to not use in the thin driver.
# This can be helpful for testing, or to avoid using a feature that is
@ -1323,14 +1293,6 @@ global {
# This configuration option has an automatic default value.
# 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.
# List of options passed to the cache_check command.
# With cache_check version 5.0 or newer you should include the option
@ -1343,11 +1305,6 @@ global {
# This configuration option has an automatic default value.
# 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.
# The full path to the vdoformat command.
# LVM uses this command to initial data volume for VDO type logical volume
@ -1362,10 +1319,10 @@ global {
# Configuration option global/vdo_disabled_features.
# Features to not use in the vdo driver.
# 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
# vdo_disabled_features = [ "online_rename", "version4" ]
# vdo_disabled_features = [ "online_rename" ]
#
# This configuration option does not have a default value defined.
@ -1395,9 +1352,8 @@ global {
# Use an LVM-specific derivation of the local machine-id as the
# system ID. See 'man machine-id'.
# machineid
# Use the contents of the machine-id file to set the system ID.
# (appmachineid is recommended to avoid exposing the confidential
# machine-id.)
# Use the contents of the machine-id file to set the system ID
# (appmachineid is recommended.)
# file
# Use the contents of another file (system_id_file) to set the
# system ID.
@ -1513,13 +1469,13 @@ activation {
# Configuration option activation/reserved_stack.
# 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.
# This configuration option has an automatic default value.
# reserved_stack = 64
# Configuration option activation/reserved_memory.
# 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.
# This configuration option has an automatic default value.
# reserved_memory = 8192
@ -1654,7 +1610,7 @@ activation {
# This includes LVs that have the following segment types:
# raid1, raid4, raid5*, and raid6*.
# 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.
# Automatic handling requires dmeventd to be monitoring the LV.
#
@ -1678,7 +1634,7 @@ activation {
# (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
# 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.
# Automatic handling requires dmeventd to be monitoring the LV.
#
@ -1840,7 +1796,7 @@ activation {
# Configuration option activation/polling_interval.
# Check pvmove or lvconvert progress at this interval (seconds).
# 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
# is only one thing to wait for, there are no progress reports, but
# the process is awoken immediately once the operation is complete.
@ -1985,14 +1941,15 @@ activation {
# Configuration section report.
# LVM report command output formatting.
report {
# This configuration section has an automatic default value.
# report {
# Configuration option report/output_format.
# Format of LVM command's report output.
# If there is more than one report per command, then the format
# is applied for all reports. You can also change output format
# directly on command line using --reportformat option which
# has precedence over report/output_format setting.
# has precedence over log/output_format setting.
# Accepted values:
# basic
# Original format with columns and rows. If there is more than
@ -2000,13 +1957,6 @@ report {
# name for identification.
# json
# 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.
# output_format = "basic"
@ -2046,11 +1996,7 @@ report {
# buffered = 1
# Configuration option report/headings.
# Format of LVM command's report output headings.
# Accepted values:
# 0 no headings,
# 1 headings with column abbreviations,
# 2 headings with full column names.
# Show headings for columns on report.
# This configuration option has an automatic default value.
# headings = 1
@ -2400,7 +2346,7 @@ report {
# This is displayed when the device for a PV is not known.
# This configuration option has an automatic default value.
# two_word_unknown_device = 0
}
# }
# Configuration section dmeventd.
# Settings for the LVM event daemon.

View File

@ -8,6 +8,7 @@ allocation {
vdo_minimum_io_size=4096
vdo_block_map_cache_size_mb=128
vdo_block_map_period=16380
vdo_check_point_frequency=0
vdo_use_sparse_index=0
vdo_index_memory_size_mb=256
vdo_slab_size_mb=2048

14423
configure vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -43,14 +43,14 @@ static void usage (FILE *dest)
int main(int argc, char *argv[])
{
int foreground_mode = 0;
static const struct option _long_options[] = {
struct option longopts[] = {
{ "foreground", no_argument, NULL, 'f' },
{ "help" , no_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
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) {
case 'f':
foreground_mode = 1;

View File

@ -108,7 +108,7 @@ static SaVersionT version = { 'B', 1, 1 };
#endif
#define DEBUGGING_HISTORY 100
#define DEBUGGING_BUFLEN 270
#define DEBUGGING_BUFLEN 128
#define LOG_SPRINT(cc, f, arg...) do { \
cc->idx++; \
cc->idx = cc->idx % DEBUGGING_HISTORY; \
@ -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_CLEAR_REGION) &&
(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);
if (!tmp_rq) {
/*
@ -1341,7 +1340,6 @@ static void cpg_join_callback(struct clog_cpg *match,
goto out;
}
/* coverity[suspicious_sizeof] allocation is using varargs data @end */
rq = malloc(DM_ULOG_REQUEST_SIZE);
if (!rq) {
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) ?
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->luid = luid;

View File

@ -34,7 +34,7 @@
#define LOG_OFFSET 2
#define RESYNC_HISTORY 50
#define RESYNC_BUFLEN 270
#define RESYNC_BUFLEN 128
//static char resync_history[RESYNC_HISTORY][128];
//static int idx = 0;
#define LOG_SPRINT(_lc, f, arg...) do { \
@ -67,7 +67,7 @@ struct log_c {
uint32_t recoverer;
uint64_t recovering_region; /* -1 means not recovering */
uint64_t skip_bit_warning; /* used to warn if region skipped */
unsigned sync_search;
int sync_search;
int resume_override;
@ -220,7 +220,7 @@ static int rw_log(struct log_c *lc, int do_write)
if (r < 0)
LOG_ERROR("[%s] rw_log: read failure: %s",
SHORT_UUID(lc->uuid), strerror(errno));
if ((unsigned) r != lc->disk_size)
if (r != lc->disk_size)
return -EIO; /* Failed disk read */
return 0;
}
@ -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! */
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;
DIR *dp;
struct dirent *dep;
struct stat statbuf;
unsigned major, minor;
int major, minor;
if (!strstr(major_minor_str, ":")) {
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;
if (!S_ISBLK(statbuf.st_mode))
return -EINVAL;
dm_strncpy(path_rtn, major_minor_str, sz);
sprintf(path_rtn, "%s", major_minor_str);
return 0;
}
@ -329,7 +329,7 @@ static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int
* 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) {
LOG_DBG("Unable to stat %s", path_rtn);
continue;
@ -394,7 +394,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
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) {
LOG_ERROR("Unable to find path to device %s", argv[0]);
goto fail;
@ -452,7 +452,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
lc->skip_bit_warning = region_count;
lc->disk_fd = -1;
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);
r = -EINVAL;
goto fail;

View File

@ -13,7 +13,6 @@
#define _LVM_CLOG_FUNCTIONS_H
#include "libdm/libdevmapper.h"
#include "libdm/dm-tools/util.h"
#include "libdm/misc/dm-log-userspace.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));
break;
}
/* ELSE */ /* fall through */
/* ELSE, fall through */
case DM_ULOG_IS_CLEAN:
case DM_ULOG_FLUSH:
case DM_ULOG_MARK_REGION:

View File

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

View File

@ -20,7 +20,7 @@
/* SHORT_UUID - print last 8 chars of a string */
#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]
extern int log_tabbing;

View File

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

View File

@ -23,12 +23,12 @@
#include "libdm/misc/dm-logging.h"
#include "base/memory/zalloc.h"
#include "libdaemon/server/daemon-stray.h"
#include <dlfcn.h>
#include <pthread.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#include <arpa/inet.h> /* for htonl, ntohl */
@ -92,10 +92,12 @@ static const size_t THREAD_STACK_SIZE = 300 * 1024;
/* Default idle exit timeout 1 hour (in seconds) */
static const time_t DMEVENTD_IDLE_EXIT_TIMEOUT = 60 * 60;
static int _debug_level = 0;
static int _use_syslog = 1;
static int _systemd_activation = 0;
static int _foreground = 0;
static int _restart = 0;
static time_t _idle_since = 0;
static const char *_exit_on = DEFAULT_DMEVENTD_EXIT_ON_PATH;
static char **_initial_registrations = 0;
/* FIXME Make configurable at runtime */
@ -200,9 +202,9 @@ struct message_data {
char *dso_name; /* Name of DSO. */
char *device_uuid; /* Mapped device path. */
char *events_str; /* Events string as fetched from message. */
unsigned events_field; /* Events bitfield. */
uint32_t timeout_secs;
enum dm_event_mask events_field; /* Events bitfield. */
char *timeout_str;
uint32_t timeout_secs;
struct dm_event_daemon_message *msg; /* Pointer to message buffer. */
};
@ -721,18 +723,12 @@ static int _get_status(struct message_data *message_data)
static int _get_parameters(struct message_data *message_data) {
struct dm_event_daemon_message *msg = message_data->msg;
int size;
char idle_buf[32] = "";
if (_idle_since)
(void)dm_snprintf(idle_buf, sizeof(idle_buf), " idle=%lu", (long unsigned) (time(NULL) - _idle_since));
free(msg->data);
if ((size = dm_asprintf(&msg->data, "%s pid=%d daemon=%s exec_method=%s exit_on=\"%s\"%s",
if ((size = dm_asprintf(&msg->data, "%s pid=%d daemon=%s exec_method=%s",
message_data->id, getpid(),
_foreground ? "no" : "yes",
_systemd_activation ? "systemd" : "direct",
_exit_on,
idle_buf)) < 0) {
_systemd_activation ? "systemd" : "direct")) < 0) {
stack;
return -ENOMEM;
}
@ -991,7 +987,6 @@ static void _monitor_unregister(void *arg)
DEBUGLOG("Unregistering monitor for %s.", thread->device.name);
_unregister_for_timeout(thread);
/* coverity[missing_lock] no missing lock here */
if ((thread->status != DM_THREAD_REGISTERING) &&
!_do_unregister_device(thread))
log_error("%s: %s unregister failed.", __func__,
@ -1002,8 +997,6 @@ static void _monitor_unregister(void *arg)
_lock_mutex();
thread->status = DM_THREAD_DONE; /* Last access to thread memory! */
_unlock_mutex();
if (_exit_now) /* Exit is already in-progress, wake-up sleeping select() */
kill(getpid(), SIGINT);
}
/* Device monitoring thread. */
@ -1050,9 +1043,9 @@ static void *_monitor_thread(void *arg)
_unlock_mutex();
_do_process_event(thread);
thread->current_events = 0; /* Current events processed */
_lock_mutex();
thread->current_events = 0; /* Current events processed */
thread->processing = 0;
/*
@ -1168,36 +1161,6 @@ static int _unregister_for_event(struct message_data *message_data)
return ret;
}
static void _unregister_all_threads(void)
{
struct thread_status *thread, *tmp;
_lock_mutex();
dm_list_iterate_items_safe(thread, tmp, &_thread_registry)
_update_events(thread, 0);
_unlock_mutex();
}
static void _wait_for_new_pid(void)
{
unsigned long st_ino = 0;
struct stat st;
int i;
for (i = 0; i < 400000; ++i) {
if (lstat(DMEVENTD_PIDFILE, &st) == 0) {
if (!st_ino)
st_ino = st.st_ino;
else if (st_ino != st.st_ino)
break; /* different pidfile */
} else if (errno == ENOENT)
break; /* pidfile is removed */
usleep(100);
}
}
/*
* Register for an event.
*
@ -1441,8 +1404,7 @@ static int _open_fifo(const char *path)
} else if (!S_ISFIFO(st.st_mode) || st.st_uid ||
(st.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO))) {
log_warn("WARNING: %s has wrong attributes: Replacing.", path);
/* coverity[toctou] don't care, path is going to be recreated */
if (unlink(path) && (errno != ENOENT)) {
if (unlink(path)) {
log_sys_error("unlink", path);
return -1;
}
@ -1450,7 +1412,6 @@ static int _open_fifo(const char *path)
/* Create fifo. */
(void) dm_prepare_selinux_context(path, S_IFIFO);
/* coverity[toctou] revalidating things again */
if ((mkfifo(path, 0600) == -1) && errno != EEXIST) {
log_sys_error("mkfifo", path);
(void) dm_prepare_selinux_context(NULL, 0);
@ -1679,7 +1640,7 @@ static int _do_process_request(struct dm_event_daemon_message *msg)
} else
ret = _handle_request(msg, &message_data);
msg->cmd = (uint32_t)ret;
msg->cmd = ret;
if (!msg->data)
msg->size = dm_asprintf(&(msg->data), "%s %s", message_data.id, strerror(-ret));
@ -1716,9 +1677,9 @@ static void _process_request(struct dm_event_fifos *fifos)
free(msg.data);
if (cmd == DM_EVENT_CMD_DIE) {
_unregister_all_threads();
_exit_now = DM_SCHEDULED_EXIT;
log_info("dmeventd exiting for restart.");
if (unlink(DMEVENTD_PIDFILE))
log_sys_error("unlink", DMEVENTD_PIDFILE);
_exit(0);
}
}
@ -1765,7 +1726,7 @@ static void _cleanup_unused_threads(void)
DEBUGLOG("Destroying Thr %x.", (int)thread->thread);
if (pthread_join(thread->thread, NULL))
log_sys_debug("pthread_join", "");
log_sys_error("pthread_join", "");
_free_thread_status(thread);
_lock_mutex();
@ -1796,7 +1757,7 @@ static void _init_thread_signals(void)
sigdelset(&my_sigset, SIGQUIT);
if (pthread_sigmask(SIG_BLOCK, &my_sigset, NULL))
log_sys_debug("pthread_sigmask", "SIG_BLOCK");
log_sys_error("pthread_sigmask", "SIG_BLOCK");
}
/*
@ -1808,8 +1769,7 @@ static void _init_thread_signals(void)
*/
static void _exit_handler(int sig __attribute__((unused)))
{
if (!_exit_now)
_exit_now = DM_SIGNALED_EXIT;
_exit_now = DM_SIGNALED_EXIT;
}
#ifdef __linux__
@ -1825,7 +1785,7 @@ static int _set_oom_adj(const char *oom_adj_path, int val)
fprintf(fp, "%i", val);
if (dm_fclose(fp))
log_sys_debug("fclose", oom_adj_path);
log_sys_error("fclose", oom_adj_path);
return 1;
}
@ -1839,11 +1799,11 @@ static int _protect_against_oom_killer(void)
if (stat(OOM_ADJ_FILE, &st) == -1) {
if (errno != ENOENT)
log_sys_debug("stat", OOM_ADJ_FILE);
log_sys_error("stat", OOM_ADJ_FILE);
/* Try old oom_adj interface as a fallback */
if (stat(OOM_ADJ_FILE_OLD, &st) == -1) {
log_sys_debug("stat", OOM_ADJ_FILE_OLD);
log_sys_error("stat", OOM_ADJ_FILE_OLD);
return 1;
}
@ -1931,30 +1891,26 @@ out:
static void _remove_files_on_exit(void)
{
if (unlink(DMEVENTD_PIDFILE) && (errno != ENOENT))
log_sys_debug("unlink", DMEVENTD_PIDFILE);
if (unlink(DMEVENTD_PIDFILE))
log_sys_error("unlink", DMEVENTD_PIDFILE);
if (!_systemd_activation) {
if (unlink(DM_EVENT_FIFO_CLIENT) && (errno != ENOENT))
log_sys_debug("unlink", DM_EVENT_FIFO_CLIENT);
if (unlink(DM_EVENT_FIFO_CLIENT))
log_sys_error("unlink", DM_EVENT_FIFO_CLIENT);
if (unlink(DM_EVENT_FIFO_SERVER) && (errno != ENOENT))
log_sys_debug("unlink", DM_EVENT_FIFO_SERVER);
if (unlink(DM_EVENT_FIFO_SERVER))
log_sys_error("unlink", DM_EVENT_FIFO_SERVER);
}
}
static void _daemonize(void)
{
int child_status, null_fd;
int child_status;
int fd;
pid_t pid;
struct rlimit rlim;
struct timeval tval;
sigset_t my_sigset;
struct custom_fds custom_fds = {
/* Do not close fds preloaded by systemd! */
.out = (_systemd_activation) ? SD_FD_FIFO_SERVER : -1,
.err = -1,
.report = (_systemd_activation) ? SD_FD_FIFO_CLIENT : -1,
};
sigemptyset(&my_sigset);
if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) {
@ -1998,28 +1954,33 @@ static void _daemonize(void)
if (chdir("/"))
exit(EXIT_CHDIR_FAILURE);
daemon_close_stray_fds("dmeventd", 0, -1, &custom_fds);
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
fd = 256; /* just have to guess */
else
fd = rlim.rlim_cur;
if ((null_fd = open("/dev/null", O_RDWR)) < 0)
for (--fd; fd >= 0; fd--) {
#ifdef __linux__
/* Do not close fds preloaded by systemd! */
if (_systemd_activation &&
(fd == SD_FD_FIFO_SERVER || fd == SD_FD_FIFO_CLIENT))
continue;
#endif
(void) close(fd);
}
if ((open("/dev/null", O_RDONLY) < 0) ||
(open("/dev/null", O_WRONLY) < 0) ||
(open("/dev/null", O_WRONLY) < 0))
exit(EXIT_DESC_OPEN_FAILURE);
if ((dup2(null_fd, STDIN_FILENO) == -1) ||
(dup2(null_fd, STDOUT_FILENO) == -1) ||
(dup2(null_fd, STDERR_FILENO) == -1))
exit(EXIT_DESC_OPEN_FAILURE);
if ((null_fd > STDERR_FILENO) && close(null_fd))
exit(EXIT_DESC_CLOSE_FAILURE);
setsid();
/* coverity[leaked_handle] 'null_fd' handle is not leaking */
}
static int _reinstate_registrations(struct dm_event_fifos *fifos)
{
static const char _failed_parsing_msg[] = "Failed to parse existing event registration.\n";
static const char _delim[] = " ";
static const char *_delim = " ";
struct dm_event_daemon_message msg = { 0 };
char *endp, *dso_name, *dev_name, *mask, *timeout;
unsigned long mask_value, timeout_value;
@ -2069,94 +2030,28 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
return 1;
}
static int _info_dmeventd(const char *name, struct dm_event_fifos *fifos)
{
struct dm_event_daemon_message msg = { 0 };
int i, count = 0;
char *line;
int version;
int ret = 0;
if (!dm_daemon_is_running(DMEVENTD_PIDFILE)) {
fprintf(stderr, "No running dmeventd instance for status query.\n");
return 0;
}
/* Get the list of registrations from the running daemon. */
if (!init_fifos(fifos)) {
fprintf(stderr, "Could not initiate communication with existing dmeventd.\n");
return 0;
}
if (!dm_event_get_version(fifos, &version)) {
fprintf(stderr, "Could not communicate with existing dmeventd.\n");
goto out;
}
if (version < 1) {
fprintf(stderr, "The running dmeventd instance is too old.\n"
"Protocol version %d (required: 1). Action cancelled.\n", version);
goto out;
}
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_STATUS, "-", "-", 0, 0)) {
fprintf(stderr, "Failed to acquire status from existing dmeventd.\n");
goto out;
}
line = strchr(msg.data, ' ') + 1;
for (i = 0; msg.data[i]; ++i)
if (msg.data[i] == ';') {
msg.data[i] = 0;
if (!count)
printf("%s is monitoring:\n", name);
printf("%s\n", line);
line = msg.data + i + 1;
++count;
}
free(msg.data);
if (!count)
printf("%s does not monitor any device.\n", name);
if (version >= 2) {
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
fprintf(stderr, "Failed to acquire parameters from existing dmeventd.\n");
goto out;
}
printf("%s internal status: %s\n", name, msg.data);
free(msg.data);
}
ret = 1;
out:
fini_fifos(fifos);
return ret;
}
/* Return 0 - fail, 1 - success, 2 - continue */
static int _restart_dmeventd(struct dm_event_fifos *fifos)
static void _restart_dmeventd(void)
{
struct dm_event_fifos fifos = {
.client = -1,
.server = -1,
/* FIXME Make these either configurable or depend directly on dmeventd_path */
.client_path = DM_EVENT_FIFO_CLIENT,
.server_path = DM_EVENT_FIFO_SERVER
};
struct dm_event_daemon_message msg = { 0 };
int i, count = 0;
char *message;
int version;
const char *e;
if (!dm_daemon_is_running(DMEVENTD_PIDFILE)) {
fprintf(stderr, "WARNING: Could not find running dmeventd associated with pid file %s.\n", DMEVENTD_PIDFILE);
return 0;
}
/* Get the list of registrations from the running daemon. */
if (!init_fifos(fifos)) {
if (!init_fifos(&fifos)) {
fprintf(stderr, "WARNING: Could not initiate communication with existing dmeventd.\n");
return 0;
exit(EXIT_FAILURE);
}
if (!dm_event_get_version(fifos, &version)) {
if (!dm_event_get_version(&fifos, &version)) {
fprintf(stderr, "WARNING: Could not communicate with existing dmeventd.\n");
goto bad;
}
@ -2168,7 +2063,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
goto bad;
}
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_STATUS, "-", "-", 0, 0))
if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_GET_STATUS, "-", "-", 0, 0))
goto bad;
message = strchr(msg.data, ' ') + 1;
@ -2192,7 +2087,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
}
if (version >= 2) {
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
fprintf(stderr, "Failed to acquire parameters from old dmeventd.\n");
goto bad;
}
@ -2212,7 +2107,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
}
#endif
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_DIE, "-", "-", 0, 0)) {
if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_DIE, "-", "-", 0, 0)) {
fprintf(stderr, "Old dmeventd refused to die.\n");
goto bad;
}
@ -2221,41 +2116,43 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
((e = getenv(SD_ACTIVATION_ENV_VAR_NAME)) && strcmp(e, "1")))
_systemd_activation = 1;
fini_fifos(fifos);
/* Give a few seconds dmeventd to finish */
_wait_for_new_pid();
if (!_systemd_activation)
return 2; // continue with dmeventd start up
/* Reopen fifos. */
if (!init_fifos(fifos)) {
fprintf(stderr, "Could not initiate communication with new instance of dmeventd.\n");
return 0;
for (i = 0; i < 10; ++i) {
if ((access(DMEVENTD_PIDFILE, F_OK) == -1) && (errno == ENOENT))
break;
usleep(10);
}
if (!_reinstate_registrations(fifos)) {
if (!_systemd_activation) {
fini_fifos(&fifos);
return;
}
/* Reopen fifos. */
fini_fifos(&fifos);
if (!init_fifos(&fifos)) {
fprintf(stderr, "Could not initiate communication with new instance of dmeventd.\n");
exit(EXIT_FAILURE);
}
if (!_reinstate_registrations(&fifos)) {
fprintf(stderr, "Failed to reinstate monitoring with new instance of dmeventd.\n");
goto bad;
}
fini_fifos(fifos);
return 1;
fini_fifos(&fifos);
exit(EXIT_SUCCESS);
bad:
fini_fifos(fifos);
return 0;
fini_fifos(&fifos);
exit(EXIT_FAILURE);
}
static void _usage(char *prog, FILE *file)
{
fprintf(file, "Usage:\n"
"%s [-d [-d [-d]]] [-e path] [-f] [-h] [i] [-l] [-R] [-V] [-?]\n\n"
"%s [-d [-d [-d]]] [-f] [-h] [-l] [-R] [-V] [-?]\n\n"
" -d Log debug messages to syslog (-d, -dd, -ddd)\n"
" -e Select a file path checked on exit\n"
" -f Don't fork, run in the foreground\n"
" -h Show this help information\n"
" -i Query running instance of dmeventd for info\n"
" -l Log to stdout,stderr instead of syslog\n"
" -? Show this help information on stderr\n"
" -R Restart dmeventd\n"
@ -2265,10 +2162,6 @@ static void _usage(char *prog, FILE *file)
int main(int argc, char *argv[])
{
signed char opt;
int debug_level = 0;
int info = 0;
int restart = 0;
int use_syslog = 1;
struct dm_event_fifos fifos = {
.client = -1,
.server = -1,
@ -2276,58 +2169,39 @@ int main(int argc, char *argv[])
.server_path = DM_EVENT_FIFO_SERVER
};
time_t now, idle_exit_timeout = DMEVENTD_IDLE_EXIT_TIMEOUT;
opterr = 0;
optind = 0;
optopt = optind = opterr = 0;
optarg = (char*) "";
while ((opt = getopt(argc, argv, ":?e:fhiVdlR")) != EOF) {
while ((opt = getopt(argc, argv, "?fhVdlR")) != EOF) {
switch (opt) {
case 'h':
_usage(argv[0], stdout);
return EXIT_SUCCESS;
exit(EXIT_SUCCESS);
case '?':
_usage(argv[0], stderr);
return EXIT_SUCCESS;
case 'i':
info++;
break;
exit(EXIT_SUCCESS);
case 'R':
restart++;
break;
case 'e':
if (strchr(optarg, '"')) {
fprintf(stderr, "dmeventd: option -e does not accept path \"%s\" with '\"' character.\n", optarg);
return EXIT_FAILURE;
}
_exit_on=optarg;
_restart++;
break;
case 'f':
_foreground++;
break;
case 'd':
debug_level++;
_debug_level++;
break;
case 'l':
use_syslog = 0;
_use_syslog = 0;
break;
case 'V':
printf("dmeventd version: %s\n", DM_LIB_VERSION);
return EXIT_SUCCESS;
case ':':
fprintf(stderr, "dmeventd: option -%c requires an argument.\n", optopt);
return EXIT_FAILURE;
exit(EXIT_SUCCESS);
}
}
if (info) {
_foreground = 1;
use_syslog = 0;
}
if (!_foreground && !use_syslog) {
if (!_foreground && !_use_syslog) {
printf("WARNING: Ignoring logging to stdout, needs options -f\n");
use_syslog = 1;
_use_syslog = 1;
}
/*
* Switch to C locale to avoid reading large locale-archive file
* used by some glibc (on some distributions it takes over 100MB).
@ -2336,29 +2210,21 @@ int main(int argc, char *argv[])
if (setenv("LC_ALL", "C", 1))
perror("Cannot set LC_ALL to C");
if (info)
return _info_dmeventd(argv[0], &fifos) ? EXIT_SUCCESS : EXIT_FAILURE;
if (_restart)
_restart_dmeventd();
#ifdef __linux__
_systemd_activation = _systemd_handover(&fifos);
#endif
dm_log_with_errno_init(_libdm_log);
if (restart) {
dm_event_log_set(debug_level, 0);
if ((restart = _restart_dmeventd(&fifos)) < 2)
return restart ? EXIT_SUCCESS : EXIT_FAILURE;
}
if (!_foreground)
_daemonize();
if (use_syslog)
if (_use_syslog)
openlog("dmeventd", LOG_PID, LOG_DAEMON);
dm_event_log_set(debug_level, use_syslog);
dm_event_log_set(_debug_level, _use_syslog);
dm_log_with_errno_init(_libdm_log);
(void) dm_prepare_selinux_context(DMEVENTD_PIDFILE, S_IFREG);
if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0)
@ -2419,28 +2285,15 @@ int main(int argc, char *argv[])
break;
}
}
} else
switch (_exit_now) {
case DM_SIGNALED_EXIT:
_exit_now = DM_SCHEDULED_EXIT;
/*
* When '_exit_now' is set, signal has been received,
* but can not simply exit unless all
* threads are done processing.
*/
log_info("dmeventd received break, scheduling exit.");
/* fall through */
case DM_SCHEDULED_EXIT:
/* While exit is scheduled, check for exit_on file */
DEBUGLOG("Checking exit on file \"%s\".", _exit_on);
if (_exit_on[0] && (access(_exit_on, F_OK) == 0)) {
log_info("dmeventd detected exit on file %s, unregistering all monitored devices.",
_exit_on);
_unregister_all_threads();
}
break;
}
} else if (_exit_now == DM_SIGNALED_EXIT) {
_exit_now = DM_SCHEDULED_EXIT;
/*
* When '_exit_now' is set, signal has been received,
* but can not simply exit unless all
* threads are done processing.
*/
log_info("dmeventd received break, scheduling exit.");
}
_process_request(&fifos);
_cleanup_unused_threads();
}
@ -2450,11 +2303,11 @@ int main(int argc, char *argv[])
log_notice("dmeventd shutting down.");
if (fifos.client >= 0 && close(fifos.client))
log_sys_debug("client close", fifos.client_path);
log_sys_error("client close", fifos.client_path);
if (fifos.server >= 0 && close(fifos.server))
log_sys_debug("server close", fifos.server_path);
log_sys_error("server close", fifos.server_path);
if (use_syslog)
if (_use_syslog)
closelog();
_exit_dm_lib();

View File

@ -68,7 +68,7 @@ struct dm_event_fifos {
int daemon_talk(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg, int cmd,
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);
void fini_fifos(struct dm_event_fifos *fifos);
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,
struct dm_event_daemon_message *msg, int cmd,
const char *dso_name, const char *dev_name,
unsigned evmask, uint32_t timeout)
enum dm_event_mask evmask, uint32_t timeout)
{
int msg_size;
memset(msg, 0, sizeof(*msg));
@ -400,16 +400,25 @@ int daemon_talk(struct dm_event_fifos *fifos,
return (int32_t) msg->cmd;
}
/*
* Check for usable client fifo file
* start_daemon
*
* Returns: 2 cliant path does not exists, dmeventd should be restarted
* 1 on success, 0 otherwise
* 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 _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;
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:
@ -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 (errno == ENOENT)
/* Jump ahead if fifo does not already exist. */
return 2;
goto start_server;
else {
log_sys_error("stat", fifos->client_path);
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);
if (close(fifos->client))
log_sys_debug("close", fifos->client_path);
fifos->client = -1;
return 0;
}
/* server is running and listening */
if (close(fifos->client))
log_sys_debug("close", fifos->client_path);
fifos->client = -1;
return 1;
}
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 2;
}
/*
* 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 */
}
start_server:
/* server is not running */
if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
log_sys_error("stat", args[0]);
return 0;
@ -512,17 +492,8 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
strerror(errno));
else if (WEXITSTATUS(status))
log_error("Unable to start dmeventd.");
else {
/* Loop here till forked dmeventd is serving fifos */
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.");
}
else
ret = 1;
}
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. */
if (flock(fifos->server, LOCK_EX) < 0) {
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) {*/
@ -553,9 +524,6 @@ int init_fifos(struct dm_event_fifos *fifos)
return 1;
bad:
if (flock(fifos->server, LOCK_UN))
log_sys_debug("flock unlock", fifos->server_path);
bad_no_unlock:
if (close(fifos->server))
log_sys_debug("close", fifos->server_path);
fifos->server = -1;
@ -584,8 +552,6 @@ void fini_fifos(struct dm_event_fifos *fifos)
if (close(fifos->server))
log_sys_debug("close", fifos->server_path);
}
fifos->client = fifos->server = -1;
}
/* 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. */
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 *p = msg->data;
@ -779,7 +745,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
int ret = 0;
const char *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_event_daemon_message msg = { 0 };
struct dm_info info;
@ -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) {
char *p;
struct dm_event_daemon_message msg = { 0 };
int ret = 0;
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0))
return 0;
@ -886,17 +851,13 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
*version = 0;
if (!p || !(p = strchr(p, ' '))) /* Message ID */
goto out;
return 0;
if (!(p = strchr(p + 1, ' '))) /* HELLO */
goto out;
return 0;
if ((p = strchr(p + 1, ' '))) /* HELLO, once more */
*version = atoi(p);
ret = 1;
out:
free(msg.data);
return ret;
return 1;
}
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 pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
static long long _start = 0;
static time_t start = 0;
const char *indent = "";
FILE *stream = log_stderr(level) ? stderr : stdout;
int prio;
long long now, now_nsec;
time_t now;
int log_with_debug = 0;
if (subsys[0] == '#') {
@ -962,28 +923,17 @@ void dm_event_log(const char *subsys, int level, const char *file,
if (_use_syslog) {
vsyslog(prio, format, ap);
} else {
if (_debug_level) {
#define _NSEC_PER_SEC (1000000000LL)
#ifdef HAVE_REALTIME
struct timespec mono_time = { 0 };
if (clock_gettime(CLOCK_MONOTONIC, &mono_time) == 0)
now = mono_time.tv_sec * _NSEC_PER_SEC + mono_time.tv_nsec;
else
#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,
now = time(NULL);
if (!start)
start = now;
now -= start;
if (_debug_level)
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
(int)now / 60, (int)now % 60,
// TODO: Maybe use shorter ID
// ((int)(pthread_self()) >> 6) & 0xffff,
(int)pthread_self(), subsys,
(_debug_level > 3) ? "" : indent);
}
if (_debug_level > 3)
fprintf(stream, "%28s:%4d %s", file, line, indent);
vfprintf(stream, _(format), ap);

View File

@ -123,7 +123,6 @@ struct dm_pool *dmeventd_lvm2_pool(void)
int dmeventd_lvm2_run(const char *cmdline)
{
/* coverity[missing_lock] no locking for run part */
return (lvm2_run(_lvm_handle, cmdline) == LVM2_COMMAND_SUCCEEDED);
}

View File

@ -51,14 +51,18 @@ include $(top_builddir)/make.tmpl
.PHONY: install_lvmdbusd
all:
$(Q) test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
install_lvmdbusd: $(LVMDBUSD)
$(SHOW) " [INSTALL] $<"
@echo " [INSTALL] $<"
$(Q) $(INSTALL_DIR) $(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) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir)
$(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]
install_lvm2: install_lvmdbusd

View File

@ -44,10 +44,10 @@ class AutomatedProperties(dbus.service.Object):
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
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
:return:
"""
@ -88,6 +88,7 @@ class AutomatedProperties(dbus.service.Object):
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _get_all_prop(obj, interface_name):
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
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import subprocess
from . import cfg
from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm
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
import threading
import time
import traceback
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):
# We need to execute these command stand alone by forking & exec'ing
# the command always as we will be getting periodic output from them on
# the status of the long-running operation.
# the status of the long running operation.
meta = LvmExecutionMeta(time.time(), 0, command)
cfg.flightrecorder.add(meta)
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
cfg.blackbox.add(meta)
ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
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:
job_state.Percent = 100

View File

@ -11,18 +11,11 @@ import os
import multiprocessing
import queue
import itertools
from lvmdbusd.utils import LvmDebugData
from lvmdbusd import path
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
om = None
@ -32,13 +25,13 @@ bus = None
# Command line args
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
# Shared state variable across all processes
run = multiprocessing.Value('i', 1)
# If this is set to true, the current setup support lvm shell, and we are
# If this is set to true, the current setup support lvm shell and we are
# running in that mode of operation
SHELL_IN_USE = None
@ -50,11 +43,6 @@ worker_q = queue.Queue()
# Main event loop
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')
BASE_INTERFACE = 'com.redhat.lvmdbus1'
PV_INTERFACE = BASE_INTERFACE + '.Pv'
@ -102,14 +90,11 @@ vdo_support = False
db = None
# lvm flight recorder
flightrecorder = None
blackbox = None
# RequestEntry ctor
create_request_entry = None
# Circular debug log
debug = None
def exit_daemon():
"""
@ -119,6 +104,3 @@ def exit_daemon():
if run and loop:
run.value = 0
loop.quit()
systemd = False

View File

@ -6,18 +6,19 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import errno
from subprocess import Popen, PIPE
import select
import time
import threading
from itertools import chain
import collections
import traceback
import os
from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
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
try:
@ -25,6 +26,7 @@ try:
except ImportError:
import json
SEP = '{|}'
total_time = 0.0
total_count = 0
@ -36,7 +38,7 @@ cmd_lock = threading.RLock()
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.start = start
self.ended = ended
@ -47,49 +49,32 @@ class LvmExecutionMeta(object):
def __str__(self):
with self.lock:
if self.ended == 0:
ended_txt = "still running"
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" \
return "EC= %d for %s\n" \
"STARTED: %f, ENDED: %f\n" \
"STDOUT=%s\n" \
"STDERR=%s\n" % \
(self.ec, " ".join(self.cmd), time.ctime(self.start), ended_txt, float(self.ended) - self.start,
self.stdout_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
(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
self.stderr_txt)
class LvmFlightRecorder(object):
def __init__(self, size=16):
self.queue = collections.deque(maxlen=size)
self.lock = threading.RLock()
def add(self, lvm_exec_meta):
with self.lock:
self.queue.append(lvm_exec_meta)
self.queue.append(lvm_exec_meta)
def dump(self):
with self.lock:
with cmd_lock:
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):
log_error(str(c))
log_error("LVM dbus flight recorder END")
self.queue.clear()
cfg.flightrecorder = LvmFlightRecorder()
cfg.blackbox = LvmFlightRecorder()
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*
otherwise call_lvm function will fail to read
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
# Callback signature
@ -121,9 +106,6 @@ def call_lvm(command, debug=False, line_cb=None,
command.insert(0, cfg.LVM_CMD)
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,
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.stderr)
while True and cfg.run.value != 0:
while True:
try:
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]:
if r == process.stdout.fileno():
@ -151,8 +133,8 @@ def call_lvm(command, debug=False, line_cb=None,
if i != -1:
try:
line_cb(cb_data, stdout_text[stdout_index:i])
except BaseException as be:
st = extract_stack_trace(be)
except:
st = traceback.format_exc()
log_error("call_lvm: line_cb exception: \n %s" % st)
stdout_index = i + 1
else:
@ -163,31 +145,12 @@ def call_lvm(command, debug=False, line_cb=None,
break
except IOError as ioe:
log_debug("call_lvm:" + str(ioe))
break
pass
if process.returncode is not None:
cfg.lvmdebug.lvm_complete()
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"
if debug or process.returncode != 0:
_debug_c(command, process.returncode, (stdout_text, stderr_text))
return process.returncode, stdout_text, stderr_text
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
@ -202,18 +165,18 @@ def _shell_cfg():
_t_call = lvm_shell.call_lvm
cfg.SHELL_IN_USE = lvm_shell
return True
except Exception as e:
except Exception:
_t_call = call_lvm
cfg.SHELL_IN_USE = None
log_error("Unable to utilize lvm shell, dropping "
"back to fork & exec\n%s" % extract_stack_trace(e))
log_error(traceback.format_exc())
log_error("Unable to utilize lvm shell, dropping back to fork & exec")
return False
def set_execution(shell):
global _t_call
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
if cfg.SHELL_IN_USE and shell:
return True
@ -237,15 +200,11 @@ def time_wrapper(command, debug=False):
with cmd_lock:
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)
ended = time.time()
total_time += (ended - start)
total_count += 1
meta.completed(ended, *results)
cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
return results
@ -255,11 +214,44 @@ call = time_wrapper
# Default cmd
# Place default arguments for every command here.
def _dc(cmd, args):
c = [cmd, '--nosuffix', '--unbuffered', '--units', 'b']
c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
'--unbuffered', '--units', 'b']
c.extend(args)
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):
rc = []
for k, v in list(dict(options).items()):
@ -324,12 +316,10 @@ def vg_rename(vg_uuid, new_name, rename_options):
return call(cmd)
def vg_remove(vg_id, remove_options):
def vg_remove(vg_name, remove_options):
cmd = ['vgremove']
cmd.extend(options_to_cli_args(remove_options))
cmd.extend(['-f', vg_id])
# 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])
cmd.extend(['-f', vg_name])
return call(cmd)
@ -623,25 +613,68 @@ def lvm_full_report_json():
'--configreport', 'vg', '-o', ','.join(vg_columns),
'--configreport', 'lv', '-o', ','.join(lv_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)
# When we have an exported vg the exit code of lvs or fullreport will be 5
if rc == 0 or rc == 5:
if type(out) != dict:
raise LvmBug("lvm likely returned invalid JSON, lvm exit code = %d, output = %s, err= %s" %
(rc, str(out), str(err)))
return out
raise LvmBug("'fullreport' exited with code '%d'" % rc)
# With the current implementation, if we are using the shell then we
# are using JSON and JSON is returned back to us as it was parsed to
# figure out if we completed OK or not
if cfg.SHELL_IN_USE:
assert(type(out) == dict)
return out
else:
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):
@ -787,10 +820,6 @@ def activate_deactivate(op, name, activate, control_flags, options):
if (1 << 5) & control_flags:
cmd.append('--ignoreactivationskip')
# Shared locking (Cluster)
if (1 << 6) & control_flags:
op += 's'
if activate:
op += 'y'
else:
@ -802,6 +831,53 @@ def activate_deactivate(op, name, activate, control_flags, options):
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__':
# Leave this for future debug as needed
pass
pv_data = pv_retrieve_with_segs()
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
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import errno
from .pv import load_pvs
from .vg import load_vgs
from .lv import load_lvs
from . import cfg
from .utils import MThreadRunner, log_debug, log_error, LvmBug, extract_stack_trace
from .utils import MThreadRunner, log_debug, log_error
import threading
import queue
import time
import traceback
def _main_thread_load(refresh=True, emit_signal=True):
@ -120,125 +120,89 @@ class StateUpdate(object):
@staticmethod
def update_thread(obj):
exception_count = 0
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:
# noinspection PyBroadException
try:
refresh = True
emit_signal = True
cache_refresh = True
log = True
need_main_thread = True
with obj.lock:
wait = not obj.deferred
obj.deferred = False
if len(queued_requests) == 0 and wait:
# Note: If we don't have anything for N seconds we will
# get a queue.Empty exception raised here
queued_requests.append(obj.queue.get(block=True, timeout=cfg.G_LOOP_TMO))
queued_requests.append(obj.queue.get(True, 2))
# Ok we have one or the deferred queue has some,
# check if any others and grab them too
_drain_queue(queued_requests, obj.queue)
# check if any others
try:
while True:
queued_requests.append(obj.queue.get(False))
except queue.Empty:
pass
if len(queued_requests) > 1:
log_debug("Processing %d updates!" % len(queued_requests),
'bg_black', 'fg_light_green')
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!
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
exception_count = 0
except queue.Empty:
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:
log_error("update_thread: \n%s" % extract_stack_trace(e))
_handle_error()
finally:
cfg.lvmdebug.complete()
st = traceback.format_exc()
log_error("update_thread exception: \n%s" % st)
cfg.blackbox.dump()
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
# otherwise they hang forever ...
bailing(Exception("update thread exiting"))
log_debug("update thread exiting!")
log_error("Too many errors in update_thread, exiting daemon")
cfg.exit_daemon()
else:
# Slow things down when encountering errors
time.sleep(1)
def __init__(self):
self.lock = threading.RLock()
self.queue = queue.Queue()
self.deferred = False
# Do initial load, with retries. During error injection testing we can and do fail here.
count = 0
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))
# Do initial load
load(refresh=False, emit_signal=False, need_main_thread=False)
self.thread = threading.Thread(target=StateUpdate.update_thread,
args=(self,),

View File

@ -44,7 +44,7 @@ class WaitingClient(object):
self.timer_id = GLib.timeout_add_seconds(
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
def notify(self):
with self.rlock:
@ -71,7 +71,7 @@ class JobState(object):
self._stderr = ''
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
if self._request:
# 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
# the client to remove themselves from the list. As we have a lock
# here and a lock in the waiting client too, and they can be obtained
# in different orders, a deadlock can occur.
# in different orders, a dead lock can occur.
# As this remove is really optional, we will try to acquire the lock
# and remove. If we are unsuccessful it's not fatal, we just delay
# the time when the objects can be garbage collected by python
@ -226,21 +226,3 @@ class Job(AutomatedProperties):
def Uuid(self):
import uuid
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)
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
return_object = True

View File

@ -10,7 +10,7 @@
from .automatedproperties import AutomatedProperties
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
from . import cmdhandler
from . import cfg
@ -21,12 +21,14 @@ from .utils import n, n32, d
from .loader import common
from .state import State
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
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.
def get_key(i):
@ -65,80 +67,73 @@ def lvs_state_retrieve(selection, cache_refresh=True):
if cache_refresh:
cfg.db.refresh()
try:
# 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
# we are trying to gather information we could be in a position where we
# don't have information available yet.
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
# 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
# we are trying to gather information we could be in a position where we
# don't have information available yet.
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
for l in lvs:
if cfg.vdo_support:
rc.append(LvStateVdo(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid'],
l['vdo_operating_mode'],
l['vdo_compression_state'],
l['vdo_index_state'],
n(l['vdo_used_size']),
d(l['vdo_saving_percent']),
l['vdo_compression'],
l['vdo_deduplication'],
l['vdo_use_metadata_hints'],
n32(l['vdo_minimum_io_size']),
n(l['vdo_block_map_cache_size']),
n32(l['vdo_block_map_era_length']),
l['vdo_use_sparse_index'],
n(l['vdo_index_memory_size']),
n(l['vdo_slab_size']),
n32(l['vdo_ack_threads']),
n32(l['vdo_bio_threads']),
n32(l['vdo_bio_rotation']),
n32(l['vdo_cpu_threads']),
n32(l['vdo_hash_zone_threads']),
n32(l['vdo_logical_threads']),
n32(l['vdo_physical_threads']),
n32(l['vdo_max_discard']),
l['vdo_write_policy'],
n32(l['vdo_header_size'])))
else:
rc.append(LvState(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid']))
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
for l in lvs:
if cfg.vdo_support:
rc.append(LvStateVdo(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid'],
l['vdo_operating_mode'],
l['vdo_compression_state'],
l['vdo_index_state'],
n(l['vdo_used_size']),
d(l['vdo_saving_percent']),
l['vdo_compression'],
l['vdo_deduplication'],
l['vdo_use_metadata_hints'],
n32(l['vdo_minimum_io_size']),
n(l['vdo_block_map_cache_size']),
n32(l['vdo_block_map_era_length']),
l['vdo_use_sparse_index'],
n(l['vdo_index_memory_size']),
n(l['vdo_slab_size']),
n32(l['vdo_ack_threads']),
n32(l['vdo_bio_threads']),
n32(l['vdo_bio_rotation']),
n32(l['vdo_cpu_threads']),
n32(l['vdo_hash_zone_threads']),
n32(l['vdo_logical_threads']),
n32(l['vdo_physical_threads']),
n32(l['vdo_max_discard']),
l['vdo_write_policy'],
n32(l['vdo_header_size'])))
else:
rc.append(LvState(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid']))
return rc
@ -279,15 +274,15 @@ class LvStateVdo(LvState):
MetaDataPercent, CopyPercent, SyncPercent,
MetaDataSizeBytes, move_pv, move_pv_uuid,
vdo_operating_mode, vdo_compression_state, vdo_index_state,
vdo_used_size, vdo_saving_percent, vdo_compression,
vdo_deduplication, vdo_use_metadata_hints,
vdo_minimum_io_size, vdo_block_map_cache_size,
vdo_block_map_era_length, vdo_use_sparse_index,
vdo_index_memory_size, vdo_slab_size, vdo_ack_threads,
vdo_bio_threads, vdo_bio_rotation, vdo_cpu_threads,
vdo_hash_zone_threads, vdo_logical_threads,
vdo_physical_threads, vdo_max_discard,
vdo_write_policy, vdo_header_size):
vdo_used_size,vdo_saving_percent,vdo_compression,
vdo_deduplication,vdo_use_metadata_hints,
vdo_minimum_io_size,vdo_block_map_cache_size,
vdo_block_map_era_length,vdo_use_sparse_index,
vdo_index_memory_size,vdo_slab_size,vdo_ack_threads,
vdo_bio_threads,vdo_bio_rotation,vdo_cpu_threads,
vdo_hash_zone_threads,vdo_logical_threads,
vdo_physical_threads,vdo_max_discard,
vdo_write_policy,vdo_header_size):
super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
@ -376,8 +371,8 @@ class LvCommon(AutomatedProperties):
return dbus.Struct((self.state.Attr[index],
type_map.get(self.state.Attr[index], default)),
signature="(ss)")
except BaseException as b:
st = utils.extract_stack_trace(b)
except BaseException:
st = traceback.format_exc()
log_error("attr_struct: \n%s" % st)
return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
@ -600,7 +595,7 @@ class Lv(LvCommon):
optional_size = space + 512 - remainder
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)
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
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 "/"
@dbus.service.method(
@ -749,7 +744,7 @@ class Lv(LvCommon):
cfg.worker_q.put(r)
@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
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
@ -758,7 +753,7 @@ class Lv(LvCommon):
if lv_to_cache:
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)
if rc == 0:
# When we cache an LV, the cache pool and the lv that is getting
@ -775,14 +770,9 @@ class Lv(LvCommon):
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE, 'LV to cache with object path %s not present!' %
lv_object_path)
lv_object_path)
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_interface=LV_INTERFACE,
in_signature='oia{sv}',
@ -855,10 +845,10 @@ class LvVdoPool(Lv):
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def DisableCompression(self, tmo, comp_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_compression,
@ -888,10 +878,10 @@ class LvVdoPool(Lv):
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_deduplication,
@ -962,8 +952,33 @@ class LvCachePool(Lv):
@staticmethod
def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
return Lv._caching_common(cmdhandler.lv_cache_lv, lv_uuid, lv_name,
lv_object_path, cache_options)
# Make sure we have a dbus object representing cache pool
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
# 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_interface=CACHE_POOL_INTERFACE,

View File

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

View File

@ -13,13 +13,14 @@ from collections import OrderedDict
import pprint as prettyprint
import os
import sys
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):
def __init__(self, vdo_support=False):
def __init__(self, usejson=True, vdo_support=False):
self.pvs = {}
self.vgs = {}
self.lvs = {}
@ -34,9 +35,41 @@ class DataStore(object):
self.lvs_in_vgs = {}
self.pvs_in_vgs = {}
# self.refresh()
self.num_refreshes = 0
if usejson:
self.json = cmdhandler.supports_json()
else:
self.json = usejson
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
def _pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup):
for p in c_pvs.values():
@ -51,6 +84,22 @@ class DataStore(object):
# Lookup for translating between /dev/<name> and pv uuid
c_lookup[p['pv_name']] = p['pv_uuid']
@staticmethod
def _parse_pvs(_pvs):
pvs = sorted(_pvs, key=lambda pk: pk['pv_name'])
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
def _parse_pvs_json(_all):
@ -58,7 +107,7 @@ class DataStore(object):
c_lookup = {}
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
for r in _all['report']:
tmp_pv = []
@ -92,6 +141,28 @@ class DataStore(object):
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
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
@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):
c_lvs = OrderedDict()
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
for r in _all['report']:
# Get the lv data for this VG.
@ -309,12 +396,12 @@ class DataStore(object):
:param log Add debug log entry/exit messages
:return: None
"""
try:
self.num_refreshes += 1
if log:
log_debug("lvmdb - refresh entry")
self.num_refreshes += 1
if log:
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
a = cmdhandler.lvm_full_report_json()
@ -322,25 +409,29 @@ class DataStore(object):
_vgs, _vgs_lookup = self._parse_vgs_json(a)
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs_json(a)
# Set all
self.pvs = _pvs
self.pv_path_to_uuid = _pvs_lookup
self.vg_name_to_uuid = _vgs_lookup
self.lv_full_name_to_uuid = _lvs_lookup
else:
_raw_pvs = cmdhandler.pv_retrieve_with_segs()
_raw_vgs = cmdhandler.vg_retrieve(None)
_raw_lvs = cmdhandler.lv_retrieve_with_segments()
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
_pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs(_raw_pvs)
_vgs, _vgs_lookup = self._parse_vgs(_raw_vgs)
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs(_raw_lvs)
# Create lookup table for which LV and segments are on each PV
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
except KeyError as ke:
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
# Set all
self.pvs = _pvs
self.pv_path_to_uuid = _pvs_lookup
self.vg_name_to_uuid = _vgs_lookup
self.lv_full_name_to_uuid = _lvs_lookup
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:
log_debug("lvmdb - refresh exit")
@ -360,13 +451,10 @@ class DataStore(object):
return rc
def pv_missing(self, pv_uuid):
# The uuid might not be a PV, default to false
if pv_uuid in self.pvs:
if self.pvs[pv_uuid]['pv_missing'] == '':
return False
else:
return True
return False
return True
def fetch_vgs(self, vg_name):
if not vg_name:
@ -437,11 +525,15 @@ class DataStore(object):
if __name__ == "__main__":
os.environ["LC_ALL"] = "C"
os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
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()
print("PVS")

View File

@ -22,13 +22,14 @@ from . import lvmdb
from gi.repository import GLib
from .fetch import StateUpdate
from .manager import Manager
import traceback
import queue
from . import udevwatch
from .utils import log_debug, log_error, log_msg, DebugMessages
from .utils import log_debug, log_error
import argparse
import os
import sys
from .cmdhandler import LvmFlightRecorder, supports_vdo, supports_json
from .cmdhandler import LvmFlightRecorder, supports_vdo
from .request import RequestEntry
@ -41,7 +42,7 @@ def process_request():
while cfg.run.value != 0:
# noinspection PyBroadException
try:
req = cfg.worker_q.get(True, cfg.G_LOOP_TMO)
req = cfg.worker_q.get(True, 5)
log_debug(
"Method start: %s with args %s (callback = %s)" %
(str(req.method), str(req.arguments), str(req.cb)))
@ -49,15 +50,12 @@ def process_request():
log_debug("Method complete: %s" % str(req.method))
except queue.Empty:
pass
except SystemExit:
break
except Exception as e:
st = utils.extract_stack_trace(e)
except Exception:
st = traceback.format_exc()
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)
if v < 0:
raise argparse.ArgumentTypeError(
@ -67,7 +65,7 @@ def check_fr_size(value):
def install_signal_handlers():
# 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
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.SIGINT, utils.handler, signal.SIGINT)
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:
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.add_argument(
"--udev", action='store_true',
@ -106,137 +104,101 @@ def process_args():
default=False,
dest='use_lvm_shell')
parser.add_argument(
"--frsize",
help="Size of the flight recorder (num. entries), 0 to disable (signal 12 to dump)",
"--blackboxsize",
help="Size of the black box flight recorder, 0 to disable",
default=10,
type=check_fr_size,
dest='fr_size')
type=check_bb_size,
dest='bb_size')
args = parser.parse_args()
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
if not args.use_json:
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 damon 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.
# Ensure that we get consistent output for parsing stdout/stderr
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
# We create a flight recorder in cmdhandler too, but we replace it here
# as the user may be specifying a different size. The default one in
# cmdhandler is for when we are running other code with a different main.
cfg.flightrecorder = LvmFlightRecorder(cfg.args.fr_size)
cfg.blackbox = LvmFlightRecorder(cfg.args.bb_size)
# Create a circular buffer for debug logs
cfg.debug = DebugMessages()
log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
if cfg.args.use_lvm_shell and not cfg.args.use_json:
log_error("You cannot specify --lvmshell and --nojson")
sys.exit(1)
# We will dynamically add interfaces which support vdo if it
# exists.
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
thread_list = []
install_signal_handlers()
with utils.LockFile(cfg.LOCK_FILE):
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
dbus.mainloop.glib.threads_init()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
dbus.mainloop.glib.threads_init()
cmdhandler.set_execution(cfg.args.use_lvm_shell)
cmdhandler.set_execution(cfg.args.use_lvm_shell)
if use_session:
cfg.bus = dbus.SessionBus()
else:
cfg.bus = dbus.SystemBus()
# The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal
base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
cfg.om = Lvm(BASE_OBJ_PATH)
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
if use_session:
cfg.bus = dbus.SessionBus()
else:
cfg.bus = dbus.SystemBus()
# The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal
base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
cfg.om = Lvm(BASE_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
# thread that is handling the dbus interface
thread_list.append(
threading.Thread(target=process_request, name='process_request'))
# Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface
thread_list.append(
threading.Thread(target=process_request, name='process_request'))
# Have a single thread handling updating lvm and the dbus model, so we
# don't have multiple threads doing this as the same time
updater = StateUpdate()
thread_list.append(updater.thread)
# Have a single thread handling updating lvm and the dbus model so we
# don't have multiple threads doing this as the same time
updater = StateUpdate()
thread_list.append(updater.thread)
cfg.load = updater.load
cfg.load = updater.load
cfg.loop = GLib.MainLoop()
cfg.loop = GLib.MainLoop()
for thread in thread_list:
thread.damon = True
thread.start()
for thread in thread_list:
thread.damon = True
thread.start()
# In all cases we are going to monitor for udev until we get an
# ExternalEvent. In the case where we get an external event and the user
# didn't specify --udev we will stop monitoring udev
udevwatch.add()
# Add udev watching
if cfg.args.use_udev:
log_debug('Utilizing udev to trigger updates')
end = time.time()
log_debug(
'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
# In all cases we are going to monitor for udev until we get an
# ExternalEvent. In the case where we get an external event and the user
# didn't specify --udev we will stop monitoring udev
udevwatch.add()
try:
if cfg.run.value != 0:
cfg.loop.run()
udevwatch.remove()
end = time.time()
log_debug(
'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
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)
try:
if cfg.run.value != 0:
cfg.loop.run()
udevwatch.remove()
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

View File

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

View File

@ -9,11 +9,12 @@
import sys
import threading
import traceback
import dbus
import os
import copy
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
@ -39,8 +40,8 @@ class ObjectManager(AutomatedProperties):
for k, v in list(obj._objects.items()):
path, props = v[0].emit_data()
rc[path] = props
except Exception as e:
log_error("_get_managed_objects exception, bailing: \n%s" % extract_stack_trace(e))
except Exception:
traceback.print_exc(file=sys.stdout)
sys.exit(1)
return rc
@ -52,6 +53,15 @@ class ObjectManager(AutomatedProperties):
(self, ), cb, cbe, False)
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_interface="org.freedesktop.DBus.ObjectManager",
signature='oa{sa{sv}}')
@ -159,7 +169,7 @@ class ObjectManager(AutomatedProperties):
# print('Registering object path %s for %s' %
# (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 hashs with different keys
self._lookup_add(dbus_object, path, dbus_object.lvm_id,
dbus_object.Uuid)
@ -209,7 +219,7 @@ class ObjectManager(AutomatedProperties):
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
"""
with self.rlock:
@ -220,7 +230,7 @@ class ObjectManager(AutomatedProperties):
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
:return: Object path or '/' if not found
"""
@ -277,7 +287,7 @@ class ObjectManager(AutomatedProperties):
register it with the object manager for the specified uuid & lvm_id.
Note: If path create is not None, uuid and lvm_id cannot be equal
:param uuid: The uuid for the lvm object we are searching for
:param lvm_id: The lvm name (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
we fail to find the object by uuid or lvm_id.
:returns None if lvm asset not found and path_create == None otherwise
@ -295,17 +305,18 @@ class ObjectManager(AutomatedProperties):
if uuid == lvm_id:
path = self._id_lookup(lvm_id)
else:
# We have an uuid and a 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
# 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
# missing we will clear out the lvm_id as it's not unique
# and thus not useful and harmful for lookups.
if cfg.db.pv_missing(uuid):
# missing we will clear out the lvm_id as it's likely not unique
# and thus not useful and potentially harmful for lookups.
if path_create == pv_obj_path_generate and \
cfg.db.pv_missing(uuid):
lvm_id = None
# Let's check for the uuid first
# Lets check for the uuid first
path = self._id_lookup(uuid)
if path:
# Ensure table lookups are correct
@ -326,3 +337,29 @@ class ObjectManager(AutomatedProperties):
# (uuid, lvm_id, str(path_create), 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 . import cmdhandler
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 .request import RequestEntry
from .state import State
from .utils import round_size, LvmBug
from .utils import round_size
# noinspection PyUnusedLocal
@ -28,23 +28,16 @@ def pvs_state_retrieve(selection, cache_refresh=True):
if cache_refresh:
cfg.db.refresh()
try:
for p in cfg.db.fetch_pvs(selection):
rc.append(
PvState(
p["pv_name"], p["pv_uuid"], p["pv_name"],
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_mda_free"]), int(p["pv_ba_start"]),
n(p["pv_ba_size"]), n(p["pe_start"]),
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
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
for p in cfg.db.fetch_pvs(selection):
rc.append(
PvState(
p["pv_name"], p["pv_uuid"], p["pv_name"],
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_mda_free"]), int(p["pv_ba_start"]),
n(p["pv_ba_size"]), n(p["pe_start"]),
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
return rc

View File

@ -7,13 +7,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import dbus
import threading
# noinspection PyUnresolvedReferences
from gi.repository import GLib
from .job import Job
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):
@ -71,23 +71,13 @@ class RequestEntry(object):
try:
result = self.method(*self.arguments)
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:
# Use the request entry to return the result as the client may
# have gotten a job by the time we hit an error
# Lets set the exception text as the error message and log the
# exception in the journal for figuring out what went wrong.
cfg.debug.dump()
cfg.flightrecorder.dump()
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))
# Lets get the stacktrace and set that to the error message
st = traceback.format_exc()
cfg.blackbox.dump()
log_error("Exception returned to client: \n%s" % st)
self.register_error(-1, str(e), e)
def is_done(self):
@ -141,7 +131,7 @@ class RequestEntry(object):
mt_async_call(self.cb_error, error_exception)
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 = None

View File

@ -52,30 +52,20 @@ def filter_event(action, device):
# when appropriate.
refresh = False
# Ignore everything but change
if action != 'change':
return
if 'ID_FS_TYPE' in device:
fs_type_new = device['ID_FS_TYPE']
if 'LVM' in fs_type_new:
# If we get a lvm related udev event for a block device
# 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
refresh = True
elif fs_type_new == '':
# Check to see if the device was one we knew about
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
else:
# This handles the wipefs -a path
if not refresh and 'DEVNAME' in device:
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
refresh = True
if 'DM_LV_NAME' in device:
refresh = True
if refresh:
udev_add()

View File

@ -10,14 +10,11 @@
import xml.etree.ElementTree as Et
import sys
import inspect
import collections
import errno
import fcntl
import ctypes
import os
import stat
import string
import datetime
import tempfile
from fcntl import fcntl, F_GETFL, F_SETFL
import dbus
from lvmdbusd import cfg
@ -89,7 +86,7 @@ def init_class_from_arguments(
nt = k
# 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.
cur = getattr(obj_instance, nt, v)
@ -109,7 +106,7 @@ def init_class_from_arguments(
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
dbus.
:param f: Object to inspect
@ -193,7 +190,7 @@ def add_properties(xml, interface, props):
interface_element = c
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
if interface_element is None:
interface_element = Et.Element("interface", name=interface)
@ -283,64 +280,25 @@ def parse_tags(tags):
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):
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:
if STDOUT_TTY:
msg = "%s: %d:%d - %s" % \
(datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"),
os.getpid(), tid, msg)
else:
if cfg.systemd:
# 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()
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
if STDOUT_TTY and attributes:
print(color(msg, *attributes))
else:
print(msg)
sys.stdout.flush()
cfg.stdout_lock.release()
sys.stdout.flush()
# Serializes access to stdout to prevent interleaved output
@ -349,19 +307,12 @@ def _common_log(msg, *attributes):
def log_debug(msg, *attributes):
if cfg.args and cfg.args.debug:
_common_log(msg, *attributes)
else:
if cfg.debug:
cfg.debug.add(_format_log_entry(msg))
def log_error(msg, *attributes):
_common_log(msg, *attributes)
def log_msg(msg, *attributes):
_common_log(msg, *attributes)
def dump_threads_stackframe():
ident_to_name = {}
@ -389,32 +340,15 @@ def dump_threads_stackframe():
# noinspection PyUnusedLocal
def handler(signum):
try:
# signal 10
if signum == signal.SIGUSR1:
cfg.debug.dump()
dump_threads_stackframe()
# signal 12
elif signum == signal.SIGUSR2:
cfg.debug.dump()
cfg.flightrecorder.dump()
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
log_error('Exiting daemon with signal %d' % signum)
log_debug('Exiting daemon with signal %d' % signum)
if cfg.loop is not None:
cfg.loop.quit()
except BaseException as be:
st = extract_stack_trace(be)
except:
st = traceback.format_exc()
log_error("signal handler: exception (logged, not reported!) \n %s" % st)
# 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
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_/%'
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_\/%'
_ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
@ -638,23 +572,6 @@ def validate_tag(interface, tag):
% (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):
"""
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
"""
# 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
rv = cmdline
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
# on the main thread of execution to alleviate any issues the dbus-python
# library with regard to multithreaded access. Essentially, we are trying to
# on the the main thread of execution to alleviate any issues the dbus-python
# library with regards to multi-threaded access. Essentially, we are trying to
# ensure all dbus library interaction is done from the same thread!
@ -691,8 +617,9 @@ def _async_handler(call_back, parameters):
call_back(*parameters)
else:
call_back()
except BaseException as be:
log_error("mt_async_call: exception (logged, not reported!) \n %s" % extract_stack_trace(be))
except:
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
@ -742,6 +669,9 @@ class MThreadRunner(object):
self.rc = self.f()
except BaseException as 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):
@ -756,8 +686,8 @@ def mt_remove_dbus_objects(objs):
# Make stream non-blocking
def make_non_block(stream):
flags = fcntl.fcntl(stream, fcntl.F_GETFL)
fcntl.fcntl(stream, fcntl.F_SETFL, flags | os.O_NONBLOCK)
flags = fcntl(stream, F_GETFL)
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
def read_decoded(stream):
@ -765,128 +695,3 @@ def read_decoded(stream):
if tmp:
return tmp.decode("utf-8")
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 .state import State
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
@ -31,24 +31,17 @@ def vgs_state_retrieve(selection, cache_refresh=True):
if cache_refresh:
cfg.db.refresh()
try:
for v in cfg.db.fetch_vgs(selection):
rc.append(
VgState(
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_extent_count']), n(v['vg_free_count']),
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['vg_seqno']), n(v['vg_mda_count']),
n(v['vg_mda_free']), n(v['vg_mda_size']),
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
for v in cfg.db.fetch_vgs(selection):
rc.append(
VgState(
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_extent_count']), n(v['vg_free_count']),
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['vg_seqno']), n(v['vg_mda_count']),
n(v['vg_mda_free']), n(v['vg_mda_size']),
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
return rc
@ -151,7 +144,6 @@ class Vg(AutomatedProperties):
_AllocNormal_meta = ('b', VG_INTERFACE)
_AllocAnywhere_meta = ('b', VG_INTERFACE)
_Clustered_meta = ('b', VG_INTERFACE)
_Shared_meta = ('b', VG_INTERFACE)
_Name_meta = ('s', VG_INTERFACE)
# noinspection PyUnusedLocal,PyPep8Naming
@ -786,10 +778,6 @@ class Vg(AutomatedProperties):
def Clustered(self):
return self._attribute(5, 'c')
@property
def Shared(self):
return self._attribute(5, 's')
class VgVdo(Vg):

View File

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

View File

@ -38,7 +38,7 @@ static int stop_lockspaces = 0;
static char *arg_vg_name = NULL;
#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 int dump_len;
static struct sockaddr_un dump_addr;
@ -264,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)
{
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 */
} else if (!strncmp(line, "info=client ", sizeof("info=client ") - 1)) {
} else if (!strncmp(line, "info=client ", strlen("info=client "))) {
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);
} 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);
} 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.
* They are reused for the lock and action lines that
@ -286,11 +286,11 @@ static void format_info_line(char *line, char *r_name, char *r_type)
memset(r_type, 0, MAX_NAME+1);
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 */
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 */
format_info_r_action(line, r_name, r_type);
} else {
@ -940,7 +940,7 @@ static int read_options(int argc, char *argv[])
int option_index = 0;
int c;
static const struct option _long_options[] = {
static struct option long_options[] = {
{"help", no_argument, 0, 'h' },
{"quit", no_argument, 0, 'q' },
{"info", no_argument, 0, 'i' },
@ -962,7 +962,7 @@ static int read_options(int argc, char *argv[])
}
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)
break;

View File

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

View File

@ -140,7 +140,7 @@ static int str_to_mode(const char *str);
* the act is passed back to the client_thread to be returned to the client.
*/
static const char lvmlockd_protocol[] = "lvmlockd";
static const char *lvmlockd_protocol = "lvmlockd";
static const int lvmlockd_protocol_version = 1;
static int daemon_quit;
static int adopt_opt;
@ -155,7 +155,7 @@ static const char *adopt_file;
* 1MB should fit all the info we need to dump.
*/
#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];
static struct sockaddr_un dump_addr;
static socklen_t dump_addrlen;
@ -810,27 +810,6 @@ static const char *op_str(int x)
};
}
static const char *op_mode_str(int op, int mode)
{
if (op != LD_OP_LOCK)
return op_str(op);
switch (mode) {
case LD_LK_IV:
return "lock_iv";
case LD_LK_UN:
return "unlock";
case LD_LK_NL:
return "lock_nl";
case LD_LK_SH:
return "lock_sh";
case LD_LK_EX:
return "lock_ex";
default:
return "lock_bad";
}
}
int last_string_from_args(char *args_in, char *last)
{
const char *args = args_in;
@ -1062,16 +1041,16 @@ static int lm_prepare_lockspace(struct lockspace *ls, struct action *act)
return rv;
}
static int lm_add_lockspace(struct lockspace *ls, struct action *act, int adopt_only, int adopt_ok)
static int lm_add_lockspace(struct lockspace *ls, struct action *act, int adopt)
{
int rv;
if (ls->lm_type == LD_LM_DLM)
rv = lm_add_lockspace_dlm(ls, adopt_only, adopt_ok);
rv = lm_add_lockspace_dlm(ls, adopt);
else if (ls->lm_type == LD_LM_SANLOCK)
rv = lm_add_lockspace_sanlock(ls, adopt_only, adopt_ok);
rv = lm_add_lockspace_sanlock(ls, adopt);
else if (ls->lm_type == LD_LM_IDM)
rv = lm_add_lockspace_idm(ls, adopt_only, adopt_ok);
rv = lm_add_lockspace_idm(ls, adopt);
else
return -1;
@ -1099,17 +1078,17 @@ static int lm_rem_lockspace(struct lockspace *ls, struct action *act, int free_v
}
static int lm_lock(struct lockspace *ls, struct resource *r, int mode, struct action *act,
struct val_blk *vb_out, int *retry, int adopt_only, int adopt_ok)
struct val_blk *vb_out, int *retry, int adopt)
{
int rv;
if (ls->lm_type == LD_LM_DLM)
rv = lm_lock_dlm(ls, r, mode, vb_out, adopt_only, adopt_ok);
rv = lm_lock_dlm(ls, r, mode, vb_out, adopt);
else if (ls->lm_type == LD_LM_SANLOCK)
rv = lm_lock_sanlock(ls, r, mode, vb_out, retry, adopt_only, adopt_ok);
rv = lm_lock_sanlock(ls, r, mode, vb_out, retry, adopt);
else if (ls->lm_type == LD_LM_IDM)
rv = lm_lock_idm(ls, r, mode, vb_out, act->lv_uuid,
&act->pvs, adopt_only, adopt_ok);
&act->pvs, adopt);
else
return -1;
@ -1190,13 +1169,10 @@ static int lm_find_free_lock(struct lockspace *ls, uint64_t *free_offset, int *s
/*
* While adopting locks, actions originate from the adopt_locks()
* function, not from a client. So, these actions (flagged ADOPT_ONLY),
* function, not from a client. So, these actions (flagged ADOPT),
* should be passed back to the adopt_locks() function through the
* adopt_results list, and not be sent back to a client via the
* client_list/client_thread. INTERNAL_CLIENT_ID indicates the
* act was generated internally and not from a client, and
* distinguishes internal adopt request from those received from
* a client.
* client_list/client_thread.
*/
static void add_client_result(struct action *act)
@ -1209,7 +1185,7 @@ static void add_client_result(struct action *act)
}
pthread_mutex_lock(&client_mutex);
if ((act->flags & LD_AF_ADOPT_ONLY) && (act->client_id == INTERNAL_CLIENT_ID))
if (act->flags & LD_AF_ADOPT)
list_add_tail(&act->list, &adopt_results);
else
list_add_tail(&act->list, &client_results);
@ -1274,11 +1250,9 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
r->last_client_id = act->client_id;
if (r->type == LD_RT_LV)
log_debug("%s:%s res_lock %s cl %u (%s)", ls->name, r->name,
mode_str(act->mode), act->client_id, act->lv_name);
log_debug("S %s R %s res_lock cl %u mode %s (%s)", ls->name, r->name, act->client_id, mode_str(act->mode), act->lv_name);
else
log_debug("%s:%s res_lock %s cl %u", ls->name, r->name,
mode_str(act->mode), act->client_id);
log_debug("S %s R %s res_lock cl %u mode %s", ls->name, r->name, act->client_id, mode_str(act->mode));
if (r->mode == LD_LK_SH && act->mode == LD_LK_SH)
goto add_lk;
@ -1286,15 +1260,13 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
if (r->type == LD_RT_LV && act->lv_args[0])
memcpy(r->lv_args, act->lv_args, MAX_ARGS);
rv = lm_lock(ls, r, act->mode, act, &vb, retry,
act->flags & LD_AF_ADOPT_ONLY ? 1 : 0,
act->flags & LD_AF_ADOPT ? 1 : 0);
rv = lm_lock(ls, r, act->mode, act, &vb, retry, act->flags & LD_AF_ADOPT);
if (rv && r->use_vb)
log_debug("%s:%s res_lock rv %d read vb %x %x %u",
if (r->use_vb)
log_debug("S %s R %s res_lock rv %d read vb %x %x %u",
ls->name, r->name, rv, vb.version, vb.flags, vb.r_version);
else if (rv)
log_debug("%s:%s res_lock rv %d", ls->name, r->name, rv);
else
log_debug("S %s R %s res_lock rv %d", ls->name, r->name, rv);
if (rv < 0)
return rv;
@ -1307,7 +1279,7 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
* be invalidated. When we need to invalidate the lvmetad
* cache, but don't have a usable r_version from the lvb,
* send lvmetad new_version 0 which causes it to invalidate
* the VG metadata without comparing against the currently
* the VG metdata without comparing against the currently
* cached VG seqno.
*/
@ -1317,7 +1289,7 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
/* LV locks don't use an lvb. */
} else if (vb.version && ((vb.version & 0xFF00) > (VAL_BLK_VERSION & 0xFF00))) {
log_error("%s:%s res_lock invalid val_blk version %x flags %x r_version %u",
log_error("S %s R %s res_lock invalid val_blk version %x flags %x r_version %u",
ls->name, r->name, vb.version, vb.flags, vb.r_version);
inval_meta = 1;
new_version = 0;
@ -1335,7 +1307,7 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
* acquired it, and increased r_version so we know that our
* cache is invalid.
*/
log_debug("%s:%s res_lock got version %u our %u",
log_debug("S %s R %s res_lock got version %u our %u",
ls->name, r->name, vb.r_version, r->version);
r->version = vb.r_version;
new_version = vb.r_version;
@ -1348,9 +1320,7 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
* once someone uses the lock and writes a new lvb value.
* Do nothing.
*/
/*
log_debug("%s:%s res_lock version_zero_valid still zero", ls->name, r->name);
*/
log_debug("S %s R %s res_lock version_zero_valid still zero", ls->name, r->name);
} else if (r->version_zero_valid && vb.r_version) {
/*
@ -1373,11 +1343,11 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
* larger version?)
*/
if (r->version && (r->version >= vb.r_version)) {
log_debug("%s:%s res_lock version_zero_valid got version %u less than our %u",
log_debug("S %s R %s res_lock version_zero_valid got version %u less than our %u",
ls->name, r->name, vb.r_version, r->version);
new_version = 0;
} else {
log_debug("%s:%s res_lock version_zero_valid got version %u our %u",
log_debug("S %s R %s res_lock version_zero_valid got version %u our %u",
ls->name, r->name, vb.r_version, r->version);
new_version = vb.r_version;
}
@ -1389,7 +1359,7 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
/*
* The first time we've acquired the lock and seen the lvb.
*/
log_debug("%s:%s res_lock initial version %u", ls->name, r->name, vb.r_version);
log_debug("S %s R %s res_lock initial version %u", ls->name, r->name, vb.r_version);
r->version = vb.r_version;
inval_meta = 1;
new_version = vb.r_version;
@ -1400,7 +1370,7 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
* The lock may have never been used to change something.
* (e.g. a new sanlock GL?)
*/
log_debug("%s:%s res_lock all versions zero", ls->name, r->name);
log_debug("S %s R %s res_lock all versions zero", ls->name, r->name);
if (!r->version_zero_valid) {
inval_meta = 1;
new_version = 0;
@ -1424,9 +1394,9 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
* is unchanged and we don't need to invalidate metadata.
*/
if ((ls->lm_type == LD_LM_DLM) && !vb.version && !vb.flags)
log_debug("%s:%s res_lock all lvb content is blank",
log_debug("S %s R %s res_lock all lvb content is blank",
ls->name, r->name);
log_debug("%s:%s res_lock our version %u got vb %x %x %u",
log_debug("S %s R %s res_lock our version %u got vb %x %x %u",
ls->name, r->name, r->version, vb.version, vb.flags, vb.r_version);
r->version_zero_valid = 1;
inval_meta = 1;
@ -1443,21 +1413,21 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
* FIXME: how does the cache validation and replacement in lvmetad
* work in this case?
*/
log_debug("%s:%s res_lock got version %u less than our version %u",
log_debug("S %s R %s res_lock got version %u less than our version %u",
ls->name, r->name, vb.r_version, r->version);
r->version = vb.r_version;
inval_meta = 1;
new_version = 0;
r->version_zero_valid = 0;
} else {
log_debug("%s:%s res_lock undefined vb condition vzv %d our version %u vb %x %x %u",
log_debug("S %s R %s res_lock undefined vb condition vzv %d our version %u vb %x %x %u",
ls->name, r->name, r->version_zero_valid, r->version,
vb.version, vb.flags, vb.r_version);
}
if (vb.version && vb.r_version && (vb.flags & VBF_REMOVED)) {
/* Should we set ls->thread_stop = 1 ? */
log_debug("%s:%s res_lock vb flag REMOVED",
log_debug("S %s R %s res_lock vb flag REMOVED",
ls->name, r->name);
rv = -EREMOVED;
}
@ -1499,12 +1469,12 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
*/
if (inval_meta && (r->type == LD_RT_VG)) {
log_debug("%s:%s res_lock invalidate vg state version %u",
log_debug("S %s R %s res_lock invalidate vg state version %u",
ls->name, r->name, new_version);
}
if (inval_meta && (r->type == LD_RT_GL)) {
log_debug("%s:%s res_lock invalidate global state", ls->name, r->name);
log_debug("S %s R %s res_lock invalidate global state", ls->name, r->name);
}
/*
@ -1561,8 +1531,7 @@ static int res_convert(struct lockspace *ls, struct resource *r,
r->last_client_id = act->client_id;
log_debug("%s:%s res_convert %s cl %u", ls->name, r->name,
mode_str(act->mode), act->client_id);
log_debug("S %s R %s res_convert cl %u mode %s", ls->name, r->name, act->client_id, mode_str(act->mode));
if (act->mode == LD_LK_EX && lk->mode == LD_LK_SH && r->sh_count > 1)
return -EAGAIN;
@ -1578,7 +1547,7 @@ static int res_convert(struct lockspace *ls, struct resource *r,
r_version = r->version;
r->version_zero_valid = 0;
log_debug("%s:%s res_convert r_version inc %u",
log_debug("S %s R %s res_convert r_version inc %u",
ls->name, r->name, r_version);
} else if ((r->type == LD_RT_VG) && (r->mode == LD_LK_EX) && (lk->version > r->version)) {
@ -1586,14 +1555,14 @@ static int res_convert(struct lockspace *ls, struct resource *r,
r_version = r->version;
r->version_zero_valid = 0;
log_debug("%s:%s res_convert r_version new %u", ls->name, r->name, r_version);
log_debug("S %s R %s res_convert r_version new %u", ls->name, r->name, r_version);
} else {
r_version = 0;
}
rv = lm_convert(ls, r, act->mode, act, r_version);
log_debug("%s:%s res_convert rv %d", ls->name, r->name, rv);
log_debug("S %s R %s res_convert rv %d", ls->name, r->name, rv);
if (rv < 0)
return rv;
@ -1604,7 +1573,7 @@ static int res_convert(struct lockspace *ls, struct resource *r,
r->sh_count = 0;
} else {
/* should not be possible */
log_error("%s:%s res_convert invalid modes %d %d",
log_error("S %s R %s res_convert invalid modes %d %d",
ls->name, r->name, lk->mode, act->mode);
return -1;
}
@ -1643,7 +1612,7 @@ static int res_cancel(struct lockspace *ls, struct resource *r,
return -ENOENT;
do_cancel:
log_debug("%s:%s res_cancel cl %u", ls->name, r->name, cact->client_id);
log_debug("S %s R %s res_cancel cl %u", ls->name, r->name, cact->client_id);
cact->result = -ECANCELED;
list_del(&cact->list);
add_client_result(cact);
@ -1691,12 +1660,12 @@ static int res_unlock(struct lockspace *ls, struct resource *r,
}
if (act->op != LD_OP_CLOSE)
log_debug("%s:%s res_unlock cl %u no locks", ls->name, r->name, act->client_id);
log_debug("S %s R %s res_unlock cl %u no locks", ls->name, r->name, act->client_id);
return -ENOENT;
do_unlock:
if ((act->flags & LD_AF_LV_UNLOCK) && (r->last_client_id != act->client_id)) {
log_debug("%s:%s res_unlock cl %u for failed client ignored, last client %u",
log_debug("S %s R %s res_unlock cl %u for failed client ignored, last client %u",
ls->name, r->name, act->client_id, r->last_client_id);
return -ENOENT;
}
@ -1704,17 +1673,17 @@ do_unlock:
r->last_client_id = act->client_id;
if (act->op == LD_OP_CLOSE)
log_debug("%s:%s res_unlock cl %u from close", ls->name, r->name, act->client_id);
log_debug("S %s R %s res_unlock cl %u from close", ls->name, r->name, act->client_id);
else if (r->type == LD_RT_LV)
log_debug("%s:%s res_unlock cl %u (%s)", ls->name, r->name, act->client_id, act->lv_name);
log_debug("S %s R %s res_unlock cl %u (%s)", ls->name, r->name, act->client_id, act->lv_name);
else
log_debug("%s:%s res_unlock cl %u", ls->name, r->name, act->client_id);
log_debug("S %s R %s res_unlock cl %u", ls->name, r->name, act->client_id);
/* send unlock to lm when last sh lock is unlocked */
if (lk->mode == LD_LK_SH) {
r->sh_count--;
if (r->sh_count > 0) {
log_debug("%s:%s res_unlock sh_count %u", ls->name, r->name, r->sh_count);
log_debug("S %s R %s res_unlock sh_count %u", ls->name, r->name, r->sh_count);
goto rem_lk;
}
}
@ -1725,14 +1694,14 @@ do_unlock:
r_version = r->version;
r->version_zero_valid = 0;
log_debug("%s:%s res_unlock r_version inc %u", ls->name, r->name, r_version);
log_debug("S %s R %s res_unlock r_version inc %u", ls->name, r->name, r_version);
} else if ((r->type == LD_RT_VG) && (r->mode == LD_LK_EX) && (lk->version > r->version)) {
r->version = lk->version;
r_version = r->version;
r->version_zero_valid = 0;
log_debug("%s:%s res_unlock r_version new %u",
log_debug("S %s R %s res_unlock r_version new %u",
ls->name, r->name, r_version);
} else {
r_version = 0;
@ -1741,11 +1710,11 @@ do_unlock:
rv = lm_unlock(ls, r, act, r_version, 0);
if (rv < 0) {
/* should never happen, retry? */
log_error("%s:%s res_unlock lm error %d", ls->name, r->name, rv);
log_error("S %s R %s res_unlock lm error %d", ls->name, r->name, rv);
return rv;
}
/* log_debug("%s:%s res_unlock lm done", ls->name, r->name); */
log_debug("S %s R %s res_unlock lm done", ls->name, r->name);
rem_lk:
list_del(&lk->list);
@ -1764,13 +1733,13 @@ static int res_update(struct lockspace *ls, struct resource *r,
lk = find_lock_client(r, act->client_id);
if (!lk) {
log_error("%s:%s res_update cl %u lock not found",
log_error("S %s R %s res_update cl %u lock not found",
ls->name, r->name, act->client_id);
return -ENOENT;
}
if (r->mode != LD_LK_EX) {
log_error("%s:%s res_update cl %u version on non-ex lock",
log_error("S %s R %s res_update cl %u version on non-ex lock",
ls->name, r->name, act->client_id);
return -EINVAL;
}
@ -1791,13 +1760,13 @@ static int res_update(struct lockspace *ls, struct resource *r,
* force an invalidation on other hosts. The next change
* will return to using the seqno again.
*/
log_error("%s:%s res_update cl %u old version %u new version %u too small",
log_error("S %s R %s res_update cl %u old version %u new version %u too small",
ls->name, r->name, act->client_id, r->version, act->version);
}
lk->version = act->version;
}
log_debug("%s:%s res_update cl %u lk version to %u", ls->name, r->name, act->client_id, lk->version);
log_debug("S %s R %s res_update cl %u lk version to %u", ls->name, r->name, act->client_id, lk->version);
return 0;
}
@ -1950,7 +1919,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
list_for_each_entry_safe(act, safe, &r->actions, list) {
if (act->op == LD_OP_FREE && act->rt == LD_RT_LV) {
log_debug("%s:%s free_lv", ls->name, r->name);
log_debug("S %s R %s free_lv", ls->name, r->name);
rv = free_lv(ls, r);
act->result = rv;
list_del(&act->list);
@ -1972,7 +1941,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
add_client_result(act);
if (!rv && act->op == LD_OP_DISABLE) {
log_debug("%s:%s free disabled", ls->name, r->name);
log_debug("S %s R %s free disabled", ls->name, r->name);
goto r_free;
}
}
@ -2190,7 +2159,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
(act->retries <= act->max_retries) &&
(lm_retry || (r->type != LD_RT_LV))) {
/* leave act on list */
log_debug("%s:%s res_lock EAGAIN retry", ls->name, r->name);
log_debug("S %s R %s res_lock EAGAIN retry", ls->name, r->name);
act->retries++;
*retry_out = 1;
} else {
@ -2223,7 +2192,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
(act->retries <= act->max_retries) &&
(lm_retry || (r->type != LD_RT_LV))) {
/* leave act on list */
log_debug("%s:%s res_lock EAGAIN retry", ls->name, r->name);
log_debug("S %s R %s res_lock EAGAIN retry", ls->name, r->name);
act->retries++;
*retry_out = 1;
} else {
@ -2242,13 +2211,13 @@ static void res_process(struct lockspace *ls, struct resource *r,
r_free:
/* For the EUNATCH case it may be possible there are queued actions? */
list_for_each_entry_safe(act, safe, &r->actions, list) {
log_error("%s:%s res_process r_free cancel %s client %d",
log_error("S %s R %s res_process r_free cancel %s client %d",
ls->name, r->name, op_str(act->op), act->client_id);
act->result = -ECANCELED;
list_del(&act->list);
add_client_result(act);
}
log_debug("%s:%s res_process free", ls->name, r->name);
log_debug("S %s R %s res_process free", ls->name, r->name);
lm_rem_resource(ls, r);
list_del(&r->list);
free_resource(r);
@ -2306,9 +2275,9 @@ static int clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
*/
if (lk->flags & LD_LF_PERSISTENT && !drop_vg)
log_error("%s:%s clear lock persistent", ls->name, r->name);
log_error("S %s R %s clear lock persistent", ls->name, r->name);
else
log_debug("%s:%s clear lock mode %s client %d", ls->name, r->name, mode_str(lk->mode), lk->client_id);
log_debug("S %s R %s clear lock mode %s client %d", ls->name, r->name, mode_str(lk->mode), lk->client_id);
if (lk->version > lk_version)
lk_version = lk->version;
@ -2323,13 +2292,13 @@ static int clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
if ((r->type == LD_RT_GL) && (r->mode == LD_LK_EX)) {
r->version++;
r_version = r->version;
log_debug("%s:%s clear_locks r_version inc %u",
log_debug("S %s R %s clear_locks r_version inc %u",
ls->name, r->name, r_version);
} else if ((r->type == LD_RT_VG) && (r->mode == LD_LK_EX) && (lk_version > r->version)) {
r->version = lk_version;
r_version = r->version;
log_debug("%s:%s clear_locks r_version new %u",
log_debug("S %s R %s clear_locks r_version new %u",
ls->name, r->name, r_version);
} else {
@ -2339,19 +2308,19 @@ static int clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
rv = lm_unlock(ls, r, NULL, r_version, free_vg ? LMUF_FREE_VG : 0);
if (rv < 0) {
/* should never happen */
log_error("%s:%s clear_locks free %d drop %d lm unlock error %d",
log_error("S %s R %s clear_locks free %d drop %d lm unlock error %d",
ls->name, r->name, free_vg, drop_vg, rv);
}
list_for_each_entry_safe(act, act_safe, &r->actions, list) {
log_error("%s:%s clear_locks cancel %s client %d",
log_error("S %s R %s clear_locks cancel %s client %d",
ls->name, r->name, op_str(act->op), act->client_id);
act->result = -ECANCELED;
list_del(&act->list);
add_client_result(act);
}
r_free:
log_debug("%s:%s free", ls->name, r->name);
log_debug("S %s R %s free", ls->name, r->name);
lm_rem_resource(ls, r);
list_del(&r->list);
free_resource(r);
@ -2398,13 +2367,13 @@ static struct resource *find_resource_act(struct lockspace *ls,
r->mode = LD_LK_UN;
if (r->type == LD_RT_GL) {
dm_strncpy(r->name, R_NAME_GL, sizeof(r->name));
strncpy(r->name, R_NAME_GL, MAX_NAME);
r->use_vb = 1;
} else if (r->type == LD_RT_VG) {
dm_strncpy(r->name, R_NAME_VG, sizeof(r->name));
strncpy(r->name, R_NAME_VG, MAX_NAME);
r->use_vb = 1;
} else if (r->type == LD_RT_LV) {
dm_strncpy(r->name, act->lv_uuid, sizeof(r->name));
strncpy(r->name, act->lv_uuid, MAX_NAME);
r->use_vb = 0;
}
@ -2488,18 +2457,15 @@ static void *lockspace_thread_main(void *arg_in)
struct list_head tmp_act;
struct list_head act_close;
char tmp_name[MAX_NAME+5];
int fail_stop_busy;
int free_vg = 0;
int drop_vg = 0;
int error = 0;
int adopt_only = 0;
int adopt_ok = 0;
int adopt_flag = 0;
int wait_flag = 0;
int retry;
int rv;
INIT_LIST_HEAD(&act_close);
INIT_LIST_HEAD(&tmp_act);
/* first action may be client add */
pthread_mutex_lock(&ls->mutex);
@ -2513,21 +2479,14 @@ static void *lockspace_thread_main(void *arg_in)
if (add_act->flags & LD_AF_WAIT)
wait_flag = 1;
if (add_act->flags & LD_AF_ADOPT_ONLY)
adopt_only = 1;
if (add_act->flags & LD_AF_ADOPT)
adopt_ok = 1;
adopt_flag = 1;
}
}
pthread_mutex_unlock(&ls->mutex);
if (ls->lm_type == LD_LM_DLM && !strcmp(gl_lsname_dlm, ls->name)) {
log_debug("dlm global lockspace adopt_ok");
adopt_ok = 1;
}
log_debug("S %s lm_add_lockspace %s wait %d adopt_only %d adopt_ok %d",
ls->name, lm_str(ls->lm_type), wait_flag, adopt_only, adopt_ok);
log_debug("S %s lm_add_lockspace %s wait %d adopt %d",
ls->name, lm_str(ls->lm_type), wait_flag, adopt_flag);
/*
* The prepare step does not wait for anything and is quick;
@ -2546,7 +2505,7 @@ static void *lockspace_thread_main(void *arg_in)
* The actual lockspace join can take a while.
*/
if (!error) {
error = lm_add_lockspace(ls, add_act, adopt_only, adopt_ok);
error = lm_add_lockspace(ls, add_act, adopt_flag);
log_debug("S %s lm_add_lockspace done %d", ls->name, error);
@ -2573,8 +2532,6 @@ static void *lockspace_thread_main(void *arg_in)
if (error)
goto out_act;
restart:
while (1) {
pthread_mutex_lock(&ls->mutex);
while (!ls->thread_work) {
@ -2755,7 +2712,7 @@ static void *lockspace_thread_main(void *arg_in)
list_add_tail(&act->list, &r->actions);
log_debug("%s:%s action %s %s", ls->name, r->name,
log_debug("S %s R %s action %s %s", ls->name, r->name,
op_str(act->op), mode_str(act->mode));
}
pthread_mutex_unlock(&ls->mutex);
@ -2827,48 +2784,17 @@ out_rem:
* Leave the lockspace.
*/
fail_stop_busy = 0;
rv = lm_rem_lockspace(ls, NULL, free_vg);
if (rv < 0) {
pthread_mutex_lock(&ls->mutex);
list_for_each_entry_safe(act, safe, &ls->actions, list) {
/*
* If there's a stop action then there's a path to return an error,
* and in the case of EBUSY presumably there's a chance to redo it.
*/
if ((act->op == LD_OP_STOP) && (rv == -EBUSY)) {
log_debug("S %s rem_lockspace for stop error %d", ls->name, rv);
act->result = -EBUSY;
list_del(&act->list);
list_add_tail(&act->list, &tmp_act);
ls->thread_stop = 0;
fail_stop_busy = 1;
break;
}
}
pthread_mutex_unlock(&ls->mutex);
if (fail_stop_busy) {
pthread_mutex_lock(&client_mutex);
list_del(&act->list);
list_add_tail(&act->list, &client_results);
pthread_cond_signal(&client_cond);
pthread_mutex_unlock(&client_mutex);
goto restart;
}
}
if (rv < 0)
log_debug("S %s rem_lockspace error %d", ls->name, rv);
else
log_debug("S %s rem_lockspace done", ls->name);
log_debug("S %s rem_lockspace done %d", ls->name, rv);
out_act:
/*
* Move remaining actions to results; this will usually (always?)
* be only the stop action.
*/
INIT_LIST_HEAD(&tmp_act);
pthread_mutex_lock(&ls->mutex);
list_for_each_entry_safe(act, safe, &ls->actions, list) {
if (act->op == LD_OP_FREE) {
@ -2992,11 +2918,12 @@ static struct lockspace *find_lockspace_name(char *ls_name)
static int vg_ls_name(const char *vg_name, char *ls_name)
{
if (snprintf(ls_name, MAX_NAME, "%s%s", LVM_LS_PREFIX, vg_name) >= MAX_NAME) {
if (strlen(vg_name) + 4 > MAX_NAME) {
log_error("vg name too long %s", vg_name);
return -1;
}
snprintf(ls_name, MAX_NAME, "%s%s", LVM_LS_PREFIX, vg_name);
return 0;
}
@ -3054,13 +2981,13 @@ static int add_lockspace_thread(const char *ls_name,
if (vg_uuid)
/* coverity[buffer_size_warning] */
memccpy(ls->vg_uuid, vg_uuid, 0, 64);
strncpy(ls->vg_uuid, vg_uuid, 64);
if (vg_name)
dm_strncpy(ls->vg_name, vg_name, sizeof(ls->vg_name));
strncpy(ls->vg_name, vg_name, MAX_NAME);
if (vg_args)
dm_strncpy(ls->vg_args, vg_args, sizeof(ls->vg_args));
strncpy(ls->vg_args, vg_args, MAX_ARGS);
if (act)
ls->host_id = act->host_id;
@ -3089,7 +3016,9 @@ static int add_lockspace_thread(const char *ls_name,
!alloc_and_copy_pvs_path(&ls2->pvs, &ls->pvs)) {
log_debug("add_lockspace_thread %s fails to allocate pvs", ls->name);
rv = -ENOMEM;
} else if (ls2->thread_stop) {
}
if (ls2->thread_stop) {
log_debug("add_lockspace_thread %s exists and stopping", ls->name);
rv = -EAGAIN;
} else if (!ls2->create_fail && !ls2->create_done) {
@ -3602,7 +3531,7 @@ static void work_test_gl(void)
is_enabled = lm_gl_is_enabled(ls);
if (is_enabled) {
log_debug("S %s worker found gl_is_enabled", ls->name);
dm_strncpy(gl_lsname_sanlock, ls->name, sizeof(gl_lsname_sanlock));
strncpy(gl_lsname_sanlock, ls->name, MAX_NAME);
}
}
pthread_mutex_unlock(&ls->mutex);
@ -4144,7 +4073,7 @@ static int client_send_result(struct client *cl, struct action *act)
log_debug("send %s[%d] cl %u %s %s rv %d %s %s",
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
op_mode_str(act->op, act->mode), rt_str(act->rt),
op_str(act->op), rt_str(act->rt),
act->result, (act->result == -ENOLS) ? "ENOLS" : "", result_flags);
res = daemon_reply_simple("OK",
@ -4228,26 +4157,12 @@ static int add_lock_action(struct action *act)
vg_ls_name(act->vg_name, ls_name);
} else {
if (!gl_use_dlm && !gl_use_sanlock && !gl_use_idm) {
int run_sanlock = lm_is_running_sanlock();
int run_dlm = lm_is_running_dlm();
int run_idm = lm_is_running_idm();
if (run_sanlock + run_dlm + run_idm >= 2) {
log_error("global lock op %s mode %s: multiple lock managers running sanlock=%d dlm=%d idm=%d",
op_str(act->op), mode_str(act->mode), run_sanlock, run_dlm, run_idm);
} else if (!run_sanlock && !run_dlm && !run_idm) {
log_debug("global lock op %s mode %s: no lock manager running",
op_str(act->op), mode_str(act->mode));
} else {
if (run_dlm)
gl_use_dlm = 1;
else if (run_sanlock)
gl_use_sanlock = 1;
else if (run_idm)
gl_use_idm = 1;
log_debug("global lock op %s mode %s: gl_use_sanlock %d gl_use_dlm %d gl_use_idm %d",
op_str(act->op), mode_str(act->mode), gl_use_sanlock, gl_use_dlm, gl_use_idm);
}
if (lm_is_running_dlm())
gl_use_dlm = 1;
else if (lm_is_running_sanlock())
gl_use_sanlock = 1;
else if (lm_is_running_idm())
gl_use_idm = 1;
}
gl_ls_name(ls_name);
}
@ -4553,12 +4468,6 @@ static uint32_t str_to_opts(const char *str)
flags |= LD_AF_ENABLE;
if (strstr(str, "disable"))
flags |= LD_AF_DISABLE;
/* FIXME: parse the flag values properly */
if (strstr(str, "adopt_only"))
flags |= LD_AF_ADOPT_ONLY;
else if (strstr(str, "adopt"))
flags |= LD_AF_ADOPT;
out:
return flags;
}
@ -4783,12 +4692,9 @@ static int dump_info(int *dump_len)
/*
* clients
* Proper lock order is client_mutex then cl->mutex,
* but cl->mutex is already held so skip client info
* if it would block.
*/
if (pthread_mutex_trylock(&client_mutex))
goto print_ls;
pthread_mutex_lock(&client_mutex);
list_for_each_entry(cl, &client_list, list) {
ret = print_client(cl, "client", pos, len);
if (ret >= len - pos) {
@ -4802,7 +4708,6 @@ static int dump_info(int *dump_len)
if (rv < 0)
return rv;
print_ls:
/*
* lockspaces with their action/resource/lock info
*/
@ -4874,7 +4779,7 @@ static void client_recv_action(struct client *cl)
const char *path;
const char *str;
struct pvs pvs;
char buf[18]; /* "path[%d]\0", %d outputs signed integer so max to 10 bytes */
char buf[17]; /* "path[%d]\0", %d outputs signed integer so max to 10 bytes */
int64_t val;
uint32_t opts = 0;
int result = 0;
@ -4999,13 +4904,13 @@ static void client_recv_action(struct client *cl)
act->path = strdup(path);
if (vg_name && strcmp(vg_name, "none"))
dm_strncpy(act->vg_name, vg_name, sizeof(act->vg_name));
strncpy(act->vg_name, vg_name, MAX_NAME);
if (vg_uuid && strcmp(vg_uuid, "none"))
memccpy(act->vg_uuid, vg_uuid, 0, 64);
strncpy(act->vg_uuid, vg_uuid, 64);
if (vg_sysid && strcmp(vg_sysid, "none"))
dm_strncpy(act->vg_sysid, vg_sysid, sizeof(act->vg_sysid));
strncpy(act->vg_sysid, vg_sysid, MAX_NAME);
str = daemon_request_str(req, "lv_name", NULL);
if (str && strcmp(str, "none"))
@ -5071,9 +4976,9 @@ skip_pvs_path:
dm_config_destroy(req.cft);
buffer_destroy(&req.buffer);
log_debug("recv %s[%d] cl %u %s %s \"%s\" flags %x",
log_debug("recv %s[%d] cl %u %s %s \"%s\" mode %s flags %x",
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
op_mode_str(act->op, act->mode), rt_str(act->rt), act->vg_name, opts);
op_str(act->op), rt_str(act->rt), act->vg_name, mode_str(act->mode), opts);
if (lm == LD_LM_DLM && !lm_support_dlm()) {
log_debug("dlm not supported");
@ -5377,7 +5282,7 @@ static int match_dm_uuid(char *dm_uuid, char *lv_lock_uuid)
{
char buf1[64];
char buf2[64];
unsigned i, j;
int i, j;
memset(buf1, 0, sizeof(buf1));
memset(buf2, 0, sizeof(buf2));
@ -5461,7 +5366,7 @@ static int remove_inactive_lvs(struct list_head *vg_lockd)
goto next_dmname;
}
log_debug("adopt found active dm %s %s lv %s/%s",
log_debug("adopt remove_inactive dm name %s dm uuid %s vgname %s lvname %s",
names->name, dm_uuid, vgname, lvname);
if (!vgname || !lvname) {
@ -5482,7 +5387,8 @@ static int remove_inactive_lvs(struct list_head *vg_lockd)
continue;
/* Found an active LV in a lockd VG. */
log_debug("adopting %s", names->name);
log_debug("dm device %s adopt in vg %s lv %s",
names->name, ls->vg_name, r->name);
r->adopt = 1;
goto next_dmname;
}
@ -5719,7 +5625,7 @@ static void adopt_locks(void)
act->rt = LD_RT_VG;
act->lm_type = ls->lm_type;
act->client_id = INTERNAL_CLIENT_ID;
dm_strncpy(act->vg_name, ls->vg_name, sizeof(act->vg_name));
strncpy(act->vg_name, ls->vg_name, MAX_NAME);
memcpy(act->vg_uuid, ls->vg_uuid, 64);
memcpy(act->vg_args, ls->vg_args, MAX_ARGS);
act->host_id = ls->host_id;
@ -5754,6 +5660,7 @@ static void adopt_locks(void)
*/
while (count_start_done < count_start) {
sleep(1);
act = NULL;
pthread_mutex_lock(&client_mutex);
@ -5763,10 +5670,8 @@ static void adopt_locks(void)
}
pthread_mutex_unlock(&client_mutex);
if (!act) {
usleep(500000);
if (!act)
continue;
}
if (act->result < 0) {
log_error("adopt add lockspace failed vg %s %d", act->vg_name, act->result);
@ -5809,12 +5714,12 @@ static void adopt_locks(void)
act->op = LD_OP_LOCK;
act->rt = LD_RT_LV;
act->mode = r->adopt_mode;
act->flags = (LD_AF_ADOPT_ONLY | LD_AF_PERSISTENT);
act->flags = (LD_AF_ADOPT | LD_AF_PERSISTENT);
act->client_id = INTERNAL_CLIENT_ID;
act->lm_type = ls->lm_type;
dm_strncpy(act->vg_name, ls->vg_name, sizeof(act->vg_name));
dm_strncpy(act->lv_uuid, r->name, sizeof(act->lv_uuid));
dm_strncpy(act->lv_args, r->lv_args, sizeof(act->lv_args));
strncpy(act->vg_name, ls->vg_name, MAX_NAME);
strncpy(act->lv_uuid, r->name, MAX_NAME);
strncpy(act->lv_args, r->lv_args, MAX_ARGS);
log_debug("adopt lock for lv %s %s", act->vg_name, act->lv_uuid);
@ -5837,10 +5742,10 @@ static void adopt_locks(void)
act->op = LD_OP_LOCK;
act->rt = LD_RT_VG;
act->mode = LD_LK_SH;
act->flags = LD_AF_ADOPT_ONLY;
act->flags = LD_AF_ADOPT;
act->client_id = INTERNAL_CLIENT_ID;
act->lm_type = ls->lm_type;
dm_strncpy(act->vg_name, ls->vg_name, sizeof(act->vg_name));
strncpy(act->vg_name, ls->vg_name, MAX_NAME);
log_debug("adopt lock for vg %s", act->vg_name);
@ -5863,7 +5768,7 @@ static void adopt_locks(void)
act->op = LD_OP_LOCK;
act->rt = LD_RT_GL;
act->mode = LD_LK_SH;
act->flags = LD_AF_ADOPT_ONLY;
act->flags = LD_AF_ADOPT;
act->client_id = INTERNAL_CLIENT_ID;
act->lm_type = (gl_use_sanlock ? LD_LM_SANLOCK : LD_LM_DLM);
@ -5884,6 +5789,7 @@ static void adopt_locks(void)
*/
while (count_adopt_done < count_adopt) {
sleep(1);
act = NULL;
pthread_mutex_lock(&client_mutex);
@ -5893,16 +5799,14 @@ static void adopt_locks(void)
}
pthread_mutex_unlock(&client_mutex);
if (!act) {
usleep(200000);
if (!act)
continue;
}
/*
* lock adopt results
*/
if (act->result == -EADOPT_RETRY) {
if (act->result == -EUCLEAN) {
/*
* Adopt failed because the orphan has a different mode
* than initially requested. Repeat the lock-adopt operation
@ -5941,7 +5845,7 @@ static void adopt_locks(void)
free_action(act);
}
} else if (act->result == -EADOPT_NONE) {
} else if (act->result == -ENOENT) {
/*
* No orphan lock exists. This is common for GL/VG locks
* because they may not have been held when lvmlockd exited.
@ -6031,6 +5935,7 @@ static void adopt_locks(void)
/* Wait for the unlocks to complete. */
while (count_adopt_done < count_adopt) {
sleep(1);
act = NULL;
pthread_mutex_lock(&client_mutex);
@ -6040,10 +5945,8 @@ static void adopt_locks(void)
}
pthread_mutex_unlock(&client_mutex);
if (!act) {
usleep(200000);
if (!act)
continue;
}
if (act->result < 0)
log_error("adopt unlock error %d", act->result);
@ -6053,18 +5956,7 @@ static void adopt_locks(void)
}
/* Try to purge the orphan locks when lock manager is dlm */
if (lm_support_dlm() && lm_is_running_dlm()) {
list_for_each_entry(ls, &ls_found, list) {
pthread_mutex_lock(&lockspaces_mutex);
ls1 = find_lockspace_name(ls->name);
if (ls1) {
log_debug("ls: %s purge locks", ls->name);
lm_purge_locks_dlm(ls1);
}
pthread_mutex_unlock(&lockspaces_mutex);
}
}
/* FIXME: purge any remaining orphan locks in each rejoined ls? */
if (count_start_fail || count_adopt_fail)
goto fail;
@ -6102,7 +5994,7 @@ static void process_listener(int poll_fd)
return;
if (!(cl = alloc_client())) {
if (close(fd))
if (!close(fd))
log_error("failed to close lockd poll fd");
return;
}
@ -6379,8 +6271,9 @@ int main(int argc, char *argv[])
.daemon_fini = NULL,
.daemon_main = main_loop,
};
daemon_host_id_file = NULL;
static const struct option long_options[] = {
static struct option long_options[] = {
{"help", no_argument, 0, 'h' },
{"version", no_argument, 0, 'V' },
{"test", no_argument, 0, 'T' },
@ -6398,8 +6291,6 @@ int main(int argc, char *argv[])
{0, 0, 0, 0 }
};
daemon_host_id_file = NULL;
while (1) {
int c;
int lm;

View File

@ -96,6 +96,7 @@ static int check_args_version(char *vg_args)
static int read_cluster_name(char *clustername)
{
static const char close_error_msg[] = "read_cluster_name: close_error %d";
char *n;
int fd;
int rv;
@ -114,19 +115,18 @@ static int read_cluster_name(char *clustername)
rv = read(fd, clustername, MAX_ARGS);
if (rv < 0) {
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;
n = strstr(clustername, "\n");
if (n)
*n = '\0';
rv = 0;
out:
if (close(fd))
log_error("read_cluster_name: close_error %d", fd);
return rv;
log_error(close_error_msg, fd);
return 0;
}
#define MAX_VERSION 16
@ -220,112 +220,20 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
return 0;
}
#define DLM_COMMS_PATH "/sys/kernel/config/dlm/cluster/comms"
#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)
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
if (daemon_test)
return 0;
if (adopt_only || adopt_ok) {
if (adopt)
lmd->dh = dlm_open_lockspace(ls->name);
if (!lmd->dh && adopt_ok)
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 {
else
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) {
log_error("add_lockspace_dlm %s adopt %d error", ls->name, adopt);
free(lmd);
ls->lm_data = NULL;
return -1;
@ -393,7 +301,7 @@ static int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int wit
r->name, strlen(r->name),
0, NULL, NULL, NULL);
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;
}
out:
@ -417,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);
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:
free(rdd->vb);
@ -472,7 +380,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
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)
return 0;
@ -481,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
* 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.
*/
rv = dlm_ls_lockx(lmd->dh, mode, lksb, flags,
r->name, strlen(r->name), 0,
(void (*)(void*))1, (void (*)(void*))1, (void (*)(void*))1,
(void *)1, (void *)1, (void *)1,
NULL, NULL);
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);
rv = -EADOPT_RETRY;
rv = -EUCLEAN;
goto fail;
}
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);
rv = -EADOPT_NONE;
rv = -ENOENT;
goto fail;
}
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);
goto fail;
}
@ -533,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,
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 rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
@ -543,13 +451,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
int mode;
int rv;
if (adopt_ok) {
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);
if (adopt) {
/* When adopting, we don't follow the normal method
of acquiring a NL lock then converting it to the
desired mode. */
@ -578,7 +480,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
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 (rdd->vb) {
@ -598,7 +500,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
r->name, strlen(r->name),
0, NULL, NULL, NULL);
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);
goto lockrv;
}
@ -611,17 +513,17 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
0, NULL, NULL, NULL);
lockrv:
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;
}
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;
}
if (rdd->vb) {
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(vb_out, 0, sizeof(struct val_blk));
goto out;
@ -650,11 +552,11 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
struct dlm_lksb *lksb = &rdd->lksb;
int mode;
uint32_t mode;
uint32_t flags = 0;
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_NOQUEUE;
@ -668,16 +570,14 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
rdd->vb->r_version = cpu_to_le32(r_version);
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);
flags |= LKF_VALBLK;
}
if ((mode = to_dlm_mode(ld_mode)) < 0) {
log_error("lm_convert_dlm invalid mode %d", ld_mode);
return -EINVAL;
}
mode = to_dlm_mode(ld_mode);
if (daemon_test)
return 0;
@ -686,11 +586,11 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
0, NULL, NULL, NULL);
if (rv == -1 && errno == EAGAIN) {
/* 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;
}
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;
}
return rv;
@ -740,7 +640,7 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
memcpy(rdd->vb, &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,
le16_to_cpu(vb_prev.version),
le16_to_cpu(vb_prev.flags),
@ -749,12 +649,12 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
le16_to_cpu(vb_next.flags),
le32_to_cpu(vb_next.r_version));
} 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;
} 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)
@ -764,7 +664,7 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
r->name, strlen(r->name),
0, NULL, NULL, NULL);
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;
}
@ -799,6 +699,7 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
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];
struct dirent *de;
DIR *ls_dir;
@ -821,7 +722,7 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
}
if (closedir(ls_dir))
log_error("lm_hosts_dlm: closedir failed");
log_error(closedir_err_msg);
if (!count) {
log_error("lm_hosts_dlm found no nodes in %s", ls_nodes_path);
@ -838,10 +739,10 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
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 dirent *de;
DIR *ls_dir;
int ret = 0;
if (!(ls_dir = opendir(DLM_LOCKSPACES_PATH)))
return -ECONNREFUSED;
@ -854,20 +755,20 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
continue;
if (!(ls = alloc_lockspace())) {
ret = -ENOMEM;
goto out;
if (closedir(ls_dir))
log_error(closedir_err_msg);
return -ENOMEM;
}
ls->lm_type = LD_LM_DLM;
dm_strncpy(ls->name, de->d_name, sizeof(ls->name));
dm_strncpy(ls->vg_name, ls->name + strlen(LVM_LS_PREFIX), sizeof(ls->vg_name));
strncpy(ls->name, de->d_name, MAX_NAME);
strncpy(ls->vg_name, ls->name + strlen(LVM_LS_PREFIX), MAX_NAME);
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)
@ -897,7 +798,7 @@ int lm_refresh_lv_start_dlm(struct action *act)
int rv;
/* 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 */
if (!(p = strchr(path + 1, '/')))

View File

@ -391,7 +391,7 @@ int lm_prepare_lockspace_idm(struct lockspace *ls)
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 killargs[IDM_FAILURE_ARGS_LEN];
@ -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,
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 rd_idm *rdi = (struct rd_idm *)r->lm_data;

View File

@ -107,12 +107,11 @@ struct client {
#define LD_AF_SEARCH_LS 0x00000200
#define LD_AF_WAIT_STARTING 0x00001000
#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_LV_LOCK 0x00040000
#define LD_AF_LV_UNLOCK 0x00080000
#define LD_AF_SH_EXISTS 0x00100000
#define LD_AF_ADOPT_ONLY 0x00200000 /* adopt orphan or fail */
/*
* Number of times to repeat a lock request after
@ -364,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_error(fmt, args...) log_level(LOG_ERR, 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);
int lockspaces_empty(void);
@ -394,11 +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_prepare_lockspace_dlm(struct lockspace *ls);
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok);
int lm_purge_locks_dlm(struct lockspace *ls);
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
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 ld_mode, uint32_t r_version);
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
@ -428,12 +424,7 @@ static inline int lm_prepare_lockspace_dlm(struct lockspace *ls)
return -1;
}
static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok)
{
return -1;
}
static inline int lm_purge_locks_dlm(struct lockspace *ls)
static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
{
return -1;
}
@ -444,7 +435,7 @@ static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
}
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)
{
return -1;
}
@ -510,11 +501,10 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_arg
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_prepare_lockspace_sanlock(struct lockspace *ls);
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok);
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt);
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int *retry,
int adopt_only, int adopt_ok);
struct val_blk *vb_out, int *retry, int adopt);
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version);
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
@ -561,7 +551,7 @@ static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls)
return -1;
}
static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok)
static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt)
{
return -1;
}
@ -572,8 +562,7 @@ static inline int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
}
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int *retry,
int adopt_only, int adopt_ok)
struct val_blk *vb_out, int *retry, int adopt)
{
return -1;
}
@ -647,11 +636,11 @@ static inline int lm_support_sanlock(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_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_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
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 ld_mode, uint32_t r_version);
int lm_unlock_idm(struct lockspace *ls, struct resource *r,
@ -684,7 +673,7 @@ static inline int lm_prepare_lockspace_idm(struct lockspace *ls)
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;
}
@ -696,7 +685,7 @@ static inline int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg)
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,
int adopt_only, int adopt_ok)
int adopt)
{
return -1;
}

View File

@ -24,10 +24,26 @@
#include "sanlock_admin.h"
#include "sanlock_resource.h"
/* FIXME: these are copied from sanlock.h only until
an updated version of sanlock is available with them. */
#define SANLK_RES_ALIGN1M 0x00000010
#define SANLK_RES_ALIGN2M 0x00000020
#define SANLK_RES_ALIGN4M 0x00000040
#define SANLK_RES_ALIGN8M 0x00000080
#define SANLK_RES_SECTOR512 0x00000100
#define SANLK_RES_SECTOR4K 0x00000200
#define SANLK_LSF_ALIGN1M 0x00000010
#define SANLK_LSF_ALIGN2M 0x00000020
#define SANLK_LSF_ALIGN4M 0x00000040
#define SANLK_LSF_ALIGN8M 0x00000080
#define SANLK_LSF_SECTOR512 0x00000100
#define SANLK_LSF_SECTOR4K 0x00000200
#include <stddef.h>
#include <poll.h>
#include <errno.h>
#include <syslog.h>
#include <blkid/blkid.h>
#include <sys/sysmacros.h>
#define ONE_MB 1048576
@ -213,13 +229,13 @@ static uint64_t daemon_test_lv_count;
/*
* Copy a null-terminated string "str" into a fixed
* size struct field "buf" which is not null terminated.
* (ATM SANLK_NAME_LEN is only 48 bytes.
* Use memccpy() instead of strncpy().
* size (SANLK_NAME_LEN) struct field "buf" which is
* not null terminated.
*/
static void strcpy_name_len(char *buf, const char *str, size_t len)
static void strcpy_name_len(char *buf, char *str, int len)
{
memccpy(buf, str, 0, len);
/* coverity[buffer_size_warning] */
strncpy(buf, str, SANLK_NAME_LEN);
}
static int lock_lv_name_from_args(char *vg_args, char *lock_lv_name)
@ -515,6 +531,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
memset(&ss, 0, sizeof(ss));
memset(&rd, 0, sizeof(rd));
memset(&disk, 0, sizeof(disk));
memset(lock_lv_name, 0, sizeof(lock_lv_name));
memset(lock_args_version, 0, sizeof(lock_args_version));
if (!vg_args || !vg_args[0] || !strcmp(vg_args, "none")) {
@ -526,7 +543,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
/* see comment above about input vg_args being only lock_lv_name */
dm_strncpy(lock_lv_name, vg_args, sizeof(lock_lv_name));
snprintf(lock_lv_name, MAX_ARGS, "%s", vg_args);
if (strlen(lock_lv_name) + strlen(lock_args_version) + 2 > MAX_ARGS)
return -EARGS;
@ -601,7 +618,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
gl_name = R_NAME_GL;
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
strcpy_name_len(rd.rs.name, gl_name, SANLK_NAME_LEN);
strcpy_name_len(rd.rs.name, (char *)gl_name, SANLK_NAME_LEN);
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
rd.rs.disks[0].offset = align_size * GL_LOCK_BEGIN;
rd.rs.num_disks = 1;
@ -616,7 +633,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
}
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
strcpy_name_len(rd.rs.name, R_NAME_VG, SANLK_NAME_LEN);
strcpy_name_len(rd.rs.name, (char *)R_NAME_VG, SANLK_NAME_LEN);
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
rd.rs.disks[0].offset = align_size * VG_LOCK_BEGIN;
rd.rs.num_disks = 1;
@ -631,7 +648,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
}
if (!strcmp(gl_name, R_NAME_GL))
dm_strncpy(gl_lsname_sanlock, ls_name, sizeof(gl_lsname_sanlock));
strncpy(gl_lsname_sanlock, ls_name, MAX_NAME);
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
if (rv >= MAX_ARGS)
@ -651,7 +668,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
strcpy_name_len(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
strcpy_name_len(rd.rs.name, "#unused", SANLK_NAME_LEN);
strcpy_name_len(rd.rs.name, (char *)"#unused", SANLK_NAME_LEN);
offset = align_size * LV_LOCK_BEGIN;
@ -667,10 +684,10 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
break;
}
if (rv < 0) {
if (rv) {
log_error("clear lv resource area %llu error %d",
(unsigned long long)offset, rv);
return rv;
break;
}
offset += align_size;
}
@ -998,16 +1015,16 @@ int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r)
struct sanlk_resource *rs = &rds->rs;
int rv;
log_debug("%s:%s free_lv_san", ls->name, r->name);
log_debug("S %s R %s free_lv_san", ls->name, r->name);
if (daemon_test)
return 0;
strcpy_name_len(rs->name, "#unused", SANLK_NAME_LEN);
strcpy_name_len(rs->name, (char *)"#unused", SANLK_NAME_LEN);
rv = sanlock_write_resource(rs, 0, 0, 0);
if (rv < 0) {
log_error("%s:%s free_lv_san write error %d",
log_error("S %s R %s free_lv_san write error %d",
ls->name, r->name, rv);
}
@ -1038,10 +1055,10 @@ int lm_ex_disable_gl_sanlock(struct lockspace *ls)
memset(&rd2, 0, sizeof(rd2));
strcpy_name_len(rd1.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
strcpy_name_len(rd1.rs.name, R_NAME_GL, SANLK_NAME_LEN);
strcpy_name_len(rd1.rs.name, (char *)R_NAME_GL, SANLK_NAME_LEN);
strcpy_name_len(rd2.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
strcpy_name_len(rd2.rs.name, R_NAME_GL_DISABLED, SANLK_NAME_LEN);
strcpy_name_len(rd2.rs.name, (char *)R_NAME_GL_DISABLED, SANLK_NAME_LEN);
rd1.rs.num_disks = 1;
memcpy(rd1.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
@ -1107,7 +1124,7 @@ int lm_able_gl_sanlock(struct lockspace *ls, int enable)
memset(&rd, 0, sizeof(rd));
strcpy_name_len(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
strcpy_name_len(rd.rs.name, gl_name, SANLK_NAME_LEN);
strcpy_name_len(rd.rs.name, (char *)gl_name, SANLK_NAME_LEN);
rd.rs.num_disks = 1;
memcpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
@ -1127,7 +1144,7 @@ out:
ls->sanlock_gl_enabled = enable;
if (enable)
dm_strncpy(gl_lsname_sanlock, ls->name, sizeof(gl_lsname_sanlock));
strncpy(gl_lsname_sanlock, ls->name, MAX_NAME);
if (!enable && !strcmp(gl_lsname_sanlock, ls->name))
memset(gl_lsname_sanlock, 0, sizeof(gl_lsname_sanlock));
@ -1318,7 +1335,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
struct stat st;
struct lm_sanlock *lms = NULL;
char lock_lv_name[MAX_ARGS+1];
char lsname[SANLK_NAME_LEN + 1] = { 0 };
char lsname[SANLK_NAME_LEN + 1];
char disk_path[SANLK_PATH_LEN];
char killpath[SANLK_PATH_LEN];
char killargs[SANLK_PATH_LEN];
@ -1399,7 +1416,8 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
goto fail;
}
dm_strncpy(lsname, ls->name, sizeof(lsname));
memset(lsname, 0, sizeof(lsname));
strncpy(lsname, ls->name, SANLK_NAME_LEN);
memcpy(lms->ss.name, lsname, SANLK_NAME_LEN);
lms->ss.host_id_disk.offset = 0;
@ -1500,7 +1518,7 @@ fail:
return ret;
}
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok)
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt)
{
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
int rv;
@ -1511,15 +1529,11 @@ int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok)
}
rv = sanlock_add_lockspace_timeout(&lms->ss, 0, sanlock_io_timeout);
if (rv == -EEXIST && (adopt_ok || adopt_only)) {
if (rv == -EEXIST && adopt) {
/* We could alternatively just skip the sanlock call for adopt. */
log_debug("S %s add_lockspace_san adopt found ls", ls->name);
goto out;
}
if ((rv != -EEXIST) && adopt_only) {
log_error("S %s add_lockspace_san add_lockspace adopt_only not found", ls->name);
goto fail;
}
if (rv < 0) {
/* retry for some errors? */
log_error("S %s add_lockspace_san add_lockspace error %d", ls->name, rv);
@ -1574,7 +1588,7 @@ int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
* This shouldn't be generally necessary, but there may some races
* between nodes starting and removing a vg which this could help.
*/
strcpy_name_len(lms->ss.name, "#unused", SANLK_NAME_LEN);
strcpy_name_len(lms->ss.name, (char *)"#unused", SANLK_NAME_LEN);
rv = sanlock_write_lockspace(&lms->ss, 0, 0, sanlock_io_timeout);
if (rv < 0) {
@ -1615,17 +1629,12 @@ static int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
/* LD_RT_LV offset is set in each lm_lock call from lv_args. */
/*
* Disable sanlock lvb since lock versions are not currently used for
* anything, and it's nice to avoid the extra i/o used for lvb's.
*/
#if LVMLOCKD_USE_SANLOCK_LVB
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
rds->vb = zalloc(sizeof(struct val_blk));
if (!rds->vb)
return -ENOMEM;
}
#endif
return 0;
}
@ -1634,16 +1643,16 @@ int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r)
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
/* FIXME: assert r->mode == UN or unlock if it's not? */
#ifdef LVMLOCKD_USE_SANLOCK_LVB
free(rds->vb);
#endif
memset(rds, 0, sizeof(struct rd_sanlock));
r->lm_init = 0;
return 0;
}
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int *retry, int adopt_only, int adopt_ok)
struct val_blk *vb_out, int *retry, int adopt)
{
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
@ -1683,20 +1692,20 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
rv = check_args_version(r->lv_args, LV_LOCK_ARGS_MAJOR);
if (rv < 0) {
log_error("%s:%s lock_san wrong lv_args version %s",
log_error("S %s R %s lock_san wrong lv_args version %s",
ls->name, r->name, r->lv_args);
return rv;
}
rv = lock_lv_offset_from_args(r->lv_args, &lock_lv_offset);
if (rv < 0) {
log_error("%s:%s lock_san lv_offset_from_args error %d %s",
log_error("S %s R %s lock_san lv_offset_from_args error %d %s",
ls->name, r->name, rv, r->lv_args);
return rv;
}
if (!added && (rds->rs.disks[0].offset != lock_lv_offset)) {
log_debug("%s:%s lock_san offset old %llu new %llu",
log_debug("S %s R %s lock_san offset old %llu new %llu",
ls->name, r->name,
(unsigned long long)rds->rs.disks[0].offset,
(unsigned long long)lock_lv_offset);
@ -1722,7 +1731,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
rs->flags |= SANLK_RES_PERSISTENT;
log_debug("%s:%s lock_san %s at %s:%llu",
log_debug("S %s R %s lock_san %s at %s:%llu",
ls->name, r->name, mode_str(ld_mode), rs->disks[0].path,
(unsigned long long)rs->disks[0].offset);
@ -1737,10 +1746,8 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
if (rds->vb)
flags |= SANLK_ACQUIRE_LVB;
if (adopt_only)
if (adopt)
flags |= SANLK_ACQUIRE_ORPHAN_ONLY;
if (adopt_ok)
flags |= SANLK_ACQUIRE_ORPHAN;
/*
* Don't block waiting for a failed lease to expire since it causes
@ -1766,7 +1773,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
* a shared lock but the lock is held ex by another host.
* There's no point in retrying this case, just return an error.
*/
log_debug("%s:%s lock_san acquire mode %d rv EAGAIN", ls->name, r->name, ld_mode);
log_debug("S %s R %s lock_san acquire mode %d rv EAGAIN", ls->name, r->name, ld_mode);
*retry = 0;
return -EAGAIN;
}
@ -1780,31 +1787,31 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
* The lvm command will see this error, refresh the lvmlock
* lv, and try again.
*/
log_debug("%s:%s lock_san acquire offset %llu rv EMSGSIZE",
log_debug("S %s R %s lock_san acquire offset %llu rv EMSGSIZE",
ls->name, r->name, (unsigned long long)rs->disks[0].offset);
*retry = 0;
return -EMSGSIZE;
}
if ((adopt_only || adopt_ok) && (rv == -EUCLEAN)) {
if (adopt && (rv == -EUCLEAN)) {
/*
* The orphan lock exists but in a different mode than we asked
* for, so the caller should try again with the other mode.
*/
log_debug("%s:%s lock_san adopt mode %d try other mode",
log_debug("S %s R %s lock_san adopt mode %d try other mode",
ls->name, r->name, ld_mode);
*retry = 0;
return -EADOPT_RETRY;
return -EUCLEAN;
}
if (adopt_only && (rv == -ENOENT)) {
if (adopt && (rv == -ENOENT)) {
/*
* No orphan lock exists.
*/
log_debug("%s:%s lock_san adopt_only mode %d no orphan found",
log_debug("S %s R %s lock_san adopt mode %d no orphan found",
ls->name, r->name, ld_mode);
*retry = 0;
return -EADOPT_NONE;
return -ENOENT;
}
if (rv == SANLK_ACQUIRE_IDLIVE || rv == SANLK_ACQUIRE_OWNED || rv == SANLK_ACQUIRE_OTHER) {
@ -1823,7 +1830,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
* so if requesting a sh lock, retry a couple times,
* otherwise don't.
*/
log_debug("%s:%s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
log_debug("S %s R %s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
*retry = (ld_mode == LD_LK_SH) ? 1 : 0;
return -EAGAIN;
}
@ -1833,7 +1840,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
* sanlock got an i/o timeout when trying to acquire the
* lease on disk.
*/
log_debug("%s:%s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
log_debug("S %s R %s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
*retry = 0;
return -EAGAIN;
}
@ -1843,7 +1850,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
* There was contention with another host for the lease,
* and we lost.
*/
log_debug("%s:%s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
log_debug("S %s R %s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
*retry = 0;
return -EAGAIN;
}
@ -1862,19 +1869,19 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
* command can print an different error indicating that the
* owner of the lease is in the process of expiring?
*/
log_debug("%s:%s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
log_debug("S %s R %s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
*retry = 0;
return -EAGAIN;
}
if (rv < 0) {
log_error("%s:%s lock_san acquire error %d",
log_error("S %s R %s lock_san acquire error %d",
ls->name, r->name, rv);
/* if the gl has been disabled, remove and free the gl resource */
if ((rv == SANLK_LEADER_RESOURCE) && (r->type == LD_RT_GL)) {
if (!lm_gl_is_enabled(ls)) {
log_error("%s:%s lock_san gl has been disabled",
log_error("S %s R %s lock_san gl has been disabled",
ls->name, r->name);
if (!strcmp(gl_lsname_sanlock, ls->name))
memset(gl_lsname_sanlock, 0, sizeof(gl_lsname_sanlock));
@ -1887,7 +1894,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
/* sanlock gets i/o errors trying to read/write the leases. */
if (rv == -EIO)
return -ELOCKIO;
rv = -ELOCKIO;
/*
* The sanlock lockspace can disappear if the lease storage fails,
@ -1896,11 +1903,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
* stop and free the lockspace.
*/
if (rv == -ENOSPC)
return -ELOCKIO;
/* The request conflicted with an orphan lock. */
if (rv == -EUCLEAN)
return -EORPHAN;
rv = -ELOCKIO;
/*
* generic error number for sanlock errors that we are not
@ -1916,7 +1919,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
if (rds->vb) {
rv = sanlock_get_lvb(0, rs, (char *)&vb, sizeof(vb));
if (rv < 0) {
log_error("%s:%s lock_san get_lvb error %d", ls->name, r->name, rv);
log_error("S %s R %s lock_san get_lvb error %d", ls->name, r->name, rv);
memset(rds->vb, 0, sizeof(struct val_blk));
memset(vb_out, 0, sizeof(struct val_blk));
/* the lock is still acquired, the vb values considered invalid */
@ -1951,7 +1954,7 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
uint32_t flags = 0;
int rv;
log_debug("%s:%s convert_san %s to %s",
log_debug("S %s R %s convert_san %s to %s",
ls->name, r->name, mode_str(r->mode), mode_str(ld_mode));
if (daemon_test)
@ -1966,12 +1969,12 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
rds->vb->r_version = cpu_to_le32(r_version);
memcpy(&vb, rds->vb, sizeof(vb));
log_debug("%s:%s convert_san set r_version %u",
log_debug("S %s R %s convert_san set r_version %u",
ls->name, r->name, r_version);
rv = sanlock_set_lvb(0, rs, (char *)&vb, sizeof(vb));
if (rv < 0) {
log_error("%s:%s convert_san set_lvb error %d",
log_error("S %s R %s convert_san set_lvb error %d",
ls->name, r->name, rv);
return -ELMERR;
}
@ -2010,10 +2013,10 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
case SANLK_DBLOCK_LVER:
case SANLK_DBLOCK_MBAL:
/* expected errors from known/normal cases like lock contention or io timeouts */
log_debug("%s:%s convert_san error %d", ls->name, r->name, rv);
log_debug("S %s R %s convert_san error %d", ls->name, r->name, rv);
return -EAGAIN;
default:
log_error("%s:%s convert_san convert error %d", ls->name, r->name, rv);
log_error("S %s R %s convert_san convert error %d", ls->name, r->name, rv);
rv = -ELMERR;
}
@ -2031,7 +2034,7 @@ static int release_rename(struct lockspace *ls, struct resource *r)
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
int rv;
log_debug("%s:%s release rename", ls->name, r->name);
log_debug("S %s R %s release rename", ls->name, r->name);
res_args = malloc(2 * sizeof(struct sanlk_resource *));
if (!res_args)
@ -2043,14 +2046,14 @@ static int release_rename(struct lockspace *ls, struct resource *r)
res1 = (struct sanlk_resource *)&rd1;
res2 = (struct sanlk_resource *)&rd2;
strcpy_name_len(res2->name, "invalid_removed", SANLK_NAME_LEN);
strcpy_name_len(res2->name, (char *)"invalid_removed", SANLK_NAME_LEN);
res_args[0] = res1;
res_args[1] = res2;
rv = sanlock_release(lms->sock, -1, SANLK_REL_RENAME, 2, res_args);
if (rv < 0) {
log_error("%s:%s unlock_san release rename error %d", ls->name, r->name, rv);
log_error("S %s R %s unlock_san release rename error %d", ls->name, r->name, rv);
rv = -ELMERR;
}
@ -2079,7 +2082,7 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
struct val_blk vb;
int rv;
log_debug("%s:%s unlock_san %s r_version %u flags %x",
log_debug("S %s R %s unlock_san %s r_version %u flags %x",
ls->name, r->name, mode_str(r->mode), r_version, lmu_flags);
if (daemon_test) {
@ -2101,12 +2104,12 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
rds->vb->r_version = cpu_to_le32(r_version);
memcpy(&vb, rds->vb, sizeof(vb));
log_debug("%s:%s unlock_san set r_version %u",
log_debug("S %s R %s unlock_san set r_version %u",
ls->name, r->name, r_version);
rv = sanlock_set_lvb(0, rs, (char *)&vb, sizeof(vb));
if (rv < 0) {
log_error("%s:%s unlock_san set_lvb error %d",
log_error("S %s R %s unlock_san set_lvb error %d",
ls->name, r->name, rv);
return -ELMERR;
}
@ -2123,7 +2126,7 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
rv = sanlock_release(lms->sock, -1, 0, 1, &rs);
if (rv < 0)
log_error("%s:%s unlock_san release error %d", ls->name, r->name, rv);
log_error("S %s R %s unlock_san release error %d", ls->name, r->name, rv);
/*
* sanlock may return an error here if it fails to release the lease on

View File

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

View File

@ -19,7 +19,7 @@
#define MIN_ARGV_SIZE 8
static const char *const _polling_ops[] = {
static const char *const polling_ops[] = {
[PVMOVE] = LVMPD_REQ_PVMOVE,
[CONVERT] = LVMPD_REQ_CONVERT,
[MERGE] = LVMPD_REQ_MERGE,
@ -28,7 +28,7 @@ static const char *const _polling_ops[] = {
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)
@ -81,7 +81,7 @@ const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary,
/* one of: "convert", "pvmove", "merge", "merge_thin" */
if (!add_to_cmd_arr(&cmd_argv, "--polloperation", &i) ||
!add_to_cmd_arr(&cmd_argv, _polling_ops[pdlv->type], &i))
!add_to_cmd_arr(&cmd_argv, polling_ops[pdlv->type], &i))
goto err;
/* vg/lv name */

View File

@ -52,7 +52,7 @@ static pthread_key_t key;
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 */
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
@ -781,7 +781,7 @@ struct log_line_baton {
const char *prefix;
};
static daemon_handle _lvmpolld = { .error = 0 };
daemon_handle _lvmpolld = { .error = 0 };
static daemon_handle _lvmpolld_open(const char *socket)
{
@ -867,14 +867,14 @@ enum action_index {
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 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;
@ -892,9 +892,10 @@ static int _lvmpolld_client(const char *socket, enum action_index action)
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. */
{"dump", no_argument, 0, ACTION_DUMP }, /* or an option_index ? */
{"dump", no_argument, &action_idx, ACTION_DUMP }, /* or an option_index ? */
/* other options */
{"binary", required_argument, 0, 'B' },
@ -913,7 +914,7 @@ int main(int argc, char *argv[])
int opt;
int option_index = 0;
int client = 0, server = 0;
enum action_index action = ACTION_MAX;
unsigned action = ACTION_MAX;
struct timespec timeout;
daemon_idle di = { .ptimeout = &timeout };
struct lvmpolld_state ls = { .log_config = "" };
@ -929,16 +930,16 @@ int main(int argc, char *argv[])
.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) {
case 0 :
if (action != ACTION_MAX) {
if (action < ACTION_MAX) {
fprintf(stderr, "Can't perform more actions. Action already requested: %s\n",
_long_options[action].name);
long_options[action].name);
_usage(argv[0], stderr);
exit(EXIT_FAILURE);
}
action = ACTION_DUMP;
action = action_idx;
client = 1;
break;
case '?':

View File

@ -45,18 +45,18 @@ struct lvmpolld_lv {
* accessing following vars doesn't
* require struct lvmpolld_lv lock
*/
struct lvmpolld_state *ls;
enum poll_type type;
const char *lvid;
const char *lvmpolld_id;
const char *devicesfile;
const char *lvname; /* full vg/lv name */
unsigned pdtimeout; /* in seconds */
const char *sinterval;
const char *lvm_system_dir_env;
struct lvmpolld_store *pdst;
const char **cmdargv;
const char **cmdenvp;
struct lvmpolld_state *const ls;
const enum poll_type type;
const char *const lvid;
const char *const lvmpolld_id;
const char *const devicesfile;
const char *const lvname; /* full vg/lv name */
const unsigned pdtimeout; /* in seconds */
const char *const sinterval;
const char *const lvm_system_dir_env;
struct lvmpolld_store *const pdst;
const char *const *cmdargv;
const char *const *cmdenvp;
/* only used by write */
pid_t cmd_pid;
@ -66,7 +66,7 @@ struct lvmpolld_lv {
/* block of shared variables protected by lock */
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 error:1; /* unrecoverable error occured in lvmpolld */
};

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.
#
@ -29,7 +29,6 @@ DEVICE_MAPPER_SOURCE=\
device_mapper/regex/parse_rx.c \
device_mapper/regex/ttree.c \
device_mapper/vdo/status.c \
device_mapper/vdo/vdo_reader.c \
device_mapper/vdo/vdo_target.c
DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a
@ -44,10 +43,10 @@ CLEAN_TARGETS += $(DEVICE_MAPPER_DEPENDS) $(DEVICE_MAPPER_OBJECTS) \
#$(DEVICE_MAPPER_OBJECTS): INCLUDES+=$(VDO_INCLUDES)
$(DEVICE_MAPPER_TARGET): $(DEVICE_MAPPER_OBJECTS)
$(SHOW) " [AR] $@"
@echo " [AR] $@"
$(Q) $(RM) $@
$(Q) $(AR) rsv $@ $(DEVICE_MAPPER_OBJECTS) > /dev/null
ifeq ("$(USE_TRACKING)","yes")
ifeq ("$(DEPENDS)","yes")
-include $(DEVICE_MAPPER_DEPENDS)
endif

View File

@ -173,15 +173,6 @@ struct dm_names {
char name[];
};
struct dm_active_device {
struct dm_list list;
dev_t devno;
const char *name; /* device name */
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 */
};
struct dm_versions {
uint32_t next; /* Offset to next struct from start of this struct */
uint32_t version[3];
@ -219,18 +210,6 @@ const char *dm_task_get_message_response(struct dm_task *dmt);
*/
const char *dm_task_get_name(const struct dm_task *dmt);
struct dm_names *dm_task_get_names(struct dm_task *dmt);
/*
* Retrieve the list of devices and put them into easily accessible
* struct dm_active_device list elements.
* devs_features provides flag-set with used features so it's easy to check
* whether the kernel provides i.e. UUID info together with DM names
*/
#define DM_DEVICE_LIST_HAS_EVENT_NR 1
#define DM_DEVICE_LIST_HAS_UUID 2
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
unsigned *devs_features);
/* Release all associated memory with list of active DM devices */
void dm_device_list_destroy(struct dm_list **devs_list);
int dm_task_set_ro(struct dm_task *dmt);
int dm_task_set_newname(struct dm_task *dmt, const char *newname);
@ -974,9 +953,7 @@ struct writecache_settings {
uint32_t fua;
uint32_t nofua;
uint32_t cleaner;
uint32_t max_age; /* in milliseconds */
uint32_t metadata_only;
uint32_t pause_writeback; /* in milliseconds */
uint32_t max_age;
/*
* Allow an unrecognized key and its val to be passed to the kernel for
@ -998,8 +975,6 @@ struct writecache_settings {
unsigned nofua_set:1;
unsigned cleaner_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,
@ -1023,7 +998,6 @@ struct integrity_settings {
uint32_t commit_time;
uint32_t bitmap_flush_interval;
uint64_t sectors_per_bit;
uint32_t allow_discards;
unsigned journal_sectors_set:1;
unsigned interleave_sectors_set:1;
@ -1032,7 +1006,6 @@ struct integrity_settings {
unsigned commit_time_set:1;
unsigned bitmap_flush_interval_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,
@ -1047,7 +1020,6 @@ int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
*/
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
uint64_t size,
uint32_t vdo_version,
const char *vdo_pool_name,
const char *data_uuid,
uint64_t data_size,
@ -1869,7 +1841,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_COLUMNS_AS_ROWS 0x00000020
#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,
const struct dm_report_object_type *types,
@ -1982,8 +1953,7 @@ struct dm_report_group;
typedef enum {
DM_REPORT_GROUP_SINGLE,
DM_REPORT_GROUP_BASIC,
DM_REPORT_GROUP_JSON,
DM_REPORT_GROUP_JSON_STD
DM_REPORT_GROUP_JSON
} dm_report_group_type_t;
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data);
@ -2238,7 +2208,7 @@ struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
int dm_cookie_supported(void);
/*
* Udev synchronization functions.
* Udev synchronisation functions.
*/
void dm_udev_set_sync_support(int sync_with_udev);
int dm_udev_get_sync_support(void);

View File

@ -87,8 +87,10 @@ static int _version_checked = 0;
static int _version_ok = 1;
static unsigned _ioctl_buffer_double_factor = 0;
const int _dm_compat = 0;
/* *INDENT-OFF* */
static const struct cmd_data _cmd_data_v4[] = {
static struct cmd_data _cmd_data_v4[] = {
{"create", DM_DEV_CREATE, {4, 0, 0}},
{"reload", DM_TABLE_LOAD, {4, 0, 0}},
{"remove", DM_DEV_REMOVE, {4, 0, 0}},
@ -137,6 +139,7 @@ static char *_align(char *ptr, unsigned int a)
return (char *) (((unsigned long) ptr + agn) & ~agn);
}
#ifdef DM_IOCTLS
static unsigned _kernel_major = 0;
static unsigned _kernel_minor = 0;
static unsigned _kernel_release = 0;
@ -179,9 +182,6 @@ int get_uname_version(unsigned *major, unsigned *minor, unsigned *release)
return 1;
}
#ifdef DM_IOCTLS
/*
* Set number to NULL to populate _dm_bitset - otherwise first
* match is returned.
@ -198,7 +198,6 @@ static int _get_proc_number(const char *file, const char *name,
char *line = NULL;
size_t len;
uint32_t num;
unsigned blocksection = (strcmp(file, PROC_DEVICES) == 0) ? 0 : 1;
if (!(fl = fopen(file, "r"))) {
log_sys_error("fopen", file);
@ -206,9 +205,7 @@ static int _get_proc_number(const char *file, const char *name,
}
while (getline(&line, &len, fl) != -1) {
if (!blocksection && (line[0] == 'B'))
blocksection = 1;
else if (sscanf(line, "%u %255s\n", &num, &nm[0]) == 2) {
if (sscanf(line, "%u %255s\n", &num, &nm[0]) == 2) {
if (!strcmp(name, nm)) {
if (number) {
*number = num;
@ -248,16 +245,6 @@ static int _control_device_number(uint32_t *major, uint32_t *minor)
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.
*/
@ -273,7 +260,10 @@ static int _control_exists(const char *control, uint32_t major, uint32_t minor)
if (!S_ISCHR(buf.st_mode)) {
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)) {
@ -281,7 +271,10 @@ static int _control_exists(const char *control, uint32_t major, uint32_t minor)
"(%u, %u)", control,
MAJOR(buf.st_mode), MINOR(buf.st_mode),
major, minor);
return _control_unlink(control);
if (!unlink(control))
return 0;
log_sys_error("unlink", control);
return -1;
}
return 1;
@ -317,13 +310,8 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
old_umask = umask(DM_CONTROL_NODE_UMASK);
if (mknod(control, S_IFCHR | S_IRUSR | S_IWUSR,
MKDEV(major, minor)) < 0) {
if (errno != EEXIST) {
log_sys_error("mknod", control);
ret = 0;
} else if (_control_exists(control, major, minor) != 1) {
stack; /* Invalid control node created by parallel command ? */
ret = 0;
}
log_sys_error("mknod", control);
ret = 0;
}
umask(old_umask);
(void) dm_prepare_selinux_context(NULL, 0);
@ -409,7 +397,7 @@ static void _close_control_fd(void)
{
if (_control_fd != -1) {
if (close(_control_fd) < 0)
log_sys_debug("close", "_control_fd");
log_sys_error("close", "_control_fd");
_control_fd = -1;
}
}
@ -598,9 +586,23 @@ int dm_check_version(void)
_version_checked = 1;
if (_check_version(dmversion, sizeof(dmversion), 0))
if (_check_version(dmversion, sizeof(dmversion), _dm_compat))
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));
log_error("Incompatible libdevmapper %s%s and kernel driver %s.",
@ -614,7 +616,8 @@ int dm_check_version(void)
int dm_cookie_supported(void)
{
return (dm_check_version() &&
((_dm_version == 4) ? _dm_version_minor >= 15 : _dm_version > 4));
_dm_version >= 4 &&
_dm_version_minor >= 15);
}
static int _dm_inactive_supported(void)
@ -748,131 +751,10 @@ 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)
{
if (!dmt) {
log_error(INTERNAL_ERROR "Missing dm_task.");
return NULL;
}
return (struct dm_deps *) (((char *) dmt->dmi.v4) +
dmt->dmi.v4->data_start);
}
/*
* Round up the ptr to an 8-byte boundary.
* Follow kernel pattern.
*/
#define ALIGN_MASK 7
static size_t _align_val(size_t val)
{
return (val + ALIGN_MASK) & ~ALIGN_MASK;
}
static void *_align_ptr(void *ptr)
{
return (void *)_align_val((size_t)ptr);
}
static int _check_has_event_nr(void) {
static int _has_event_nr = -1;
if (_has_event_nr < 0)
_has_event_nr = dm_check_version() &&
((_dm_version == 4) ? _dm_version_minor >= 38 : _dm_version > 4);
return _has_event_nr;
}
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
unsigned *devs_features)
{
struct dm_names *names, *names1;
struct dm_active_device *dm_dev, *dm_new_dev;
struct dm_list *devs;
unsigned next = 0;
uint32_t *event_nr;
char *uuid_ptr;
size_t len;
int cnt = 0;
*devs_list = 0;
*devs_features = 0;
if ((names = dm_task_get_names(dmt)) && names->dev) {
names1 = names;
if (!names->name[0])
cnt = -1; /* -> cnt == 0 when no device is really present */
do {
names1 = (struct dm_names *)((char *) names1 + next);
next = names1->next;
++cnt;
} while (next);
}
/* buffer for devs + sorted ptrs + dm_devs + aligned strings */
if (!(devs = malloc(sizeof(*devs) + cnt * (2 * sizeof(void*) + sizeof(*dm_dev)) +
(cnt ? (char*)names1 - (char*)names + 256 : 0))))
return_0;
dm_list_init(devs);
if (!cnt) {
/* nothing in the list -> mark all features present */
*devs_features |= (DM_DEVICE_LIST_HAS_EVENT_NR | DM_DEVICE_LIST_HAS_UUID);
goto out; /* nothing else to do */
}
/* Shift position where to store individual dm_devs */
dm_dev = (struct dm_active_device *) ((long*) (devs + 1) + cnt);
do {
names = (struct dm_names *)((char *) names + next);
dm_dev->devno = (dev_t) names->dev;
dm_dev->name = (const char *)(dm_dev + 1);
dm_dev->event_nr = 0;
dm_dev->uuid = "";
len = strlen(names->name) + 1;
memcpy((char*)dm_dev->name, names->name, len);
dm_new_dev = _align_ptr((char*)(dm_dev + 1) + len);
if (_check_has_event_nr()) {
*devs_features |= DM_DEVICE_LIST_HAS_EVENT_NR;
event_nr = _align_ptr(names->name + len);
dm_dev->event_nr = event_nr[0];
if ((event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
*devs_features |= DM_DEVICE_LIST_HAS_UUID;
uuid_ptr = _align_ptr(event_nr + 2);
len = strlen(uuid_ptr) + 1;
memcpy(dm_new_dev, uuid_ptr, len);
dm_dev->uuid = (const char *) dm_new_dev;
dm_new_dev = _align_ptr((char*)dm_new_dev + len);
}
}
dm_list_add(devs, &dm_dev->list);
dm_dev = dm_new_dev;
next = names->next;
} while (next);
out:
*devs_list = devs;
return 1;
}
void dm_device_list_destroy(struct dm_list **devs_list)
{
struct dm_device_list *devs = (struct dm_device_list *) *devs_list;
if (devs) {
free(devs);
*devs_list = NULL;
}
}
struct dm_names *dm_task_get_names(struct dm_task *dmt)
{
return (struct dm_names *) (((char *) dmt->dmi.v4) +
@ -1160,10 +1042,9 @@ static char *_add_target(struct target *t, char *out, char *end)
while (*pt)
if (*pt++ == '\\')
backslash_count++;
len = strlen(t->params) + backslash_count;
len = strlen(t->params) + 1;
if ((out >= end) || (out + len + backslash_count) >= end) {
if ((out >= end) || (out + len + 1) >= end) {
log_error("Ran out of memory building ioctl parameter");
return NULL;
}
@ -1179,8 +1060,8 @@ static char *_add_target(struct target *t, char *out, char *end)
*out++ = '\0';
}
else {
memcpy(out, t->params, len);
out += len + backslash_count;
strcpy(out, t->params);
out += len + 1;
}
/* align next block */
@ -1214,7 +1095,7 @@ static int _lookup_dev_name(uint64_t dev, char *buf, size_t len)
do {
names = (struct dm_names *)((char *) names + next);
if (names->dev == dev) {
memccpy(buf, names->name, 0, len);
strncpy(buf, names->name, len);
r = 1;
break;
}
@ -1251,7 +1132,6 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
struct target *t;
struct dm_target_msg *tmsg;
size_t len = sizeof(struct dm_ioctl);
size_t message_len = 0, newname_len = 0, geometry_len = 0;
char *b, *e;
int count = 0;
@ -1312,20 +1192,14 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
return NULL;
}
if (dmt->newname) {
newname_len = strlen(dmt->newname) + 1;
len += newname_len;
}
if (dmt->newname)
len += strlen(dmt->newname) + 1;
if (dmt->message) {
message_len = strlen(dmt->message) + 1;
len += sizeof(struct dm_target_msg) + message_len;
}
if (dmt->message)
len += sizeof(struct dm_target_msg) + strlen(dmt->message) + 1;
if (dmt->geometry) {
geometry_len = strlen(dmt->geometry) + 1;
len += geometry_len;
}
if (dmt->geometry)
len += strlen(dmt->geometry) + 1;
/*
* Give len a minimum size so that we have space to store
@ -1383,10 +1257,12 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
/* FIXME Until resume ioctl supplies name, use dev_name for readahead */
if (DEV_NAME(dmt) && (dmt->type != DM_DEVICE_RESUME || dmt->minor < 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))
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)
dmi->flags |= DM_SUSPEND_FLAG;
@ -1445,16 +1321,16 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
goto_bad;
if (dmt->newname)
memcpy(b, dmt->newname, newname_len);
strcpy(b, dmt->newname);
if (dmt->message) {
tmsg = (struct dm_target_msg *) b;
tmsg->sector = dmt->sector;
memcpy(tmsg->message, dmt->message, message_len);
strcpy(tmsg->message, dmt->message);
}
if (dmt->geometry)
memcpy(b, dmt->geometry, geometry_len);
strcpy(b, dmt->geometry);
return dmi;
@ -1565,7 +1441,8 @@ static int _udev_complete(struct dm_task *dmt)
static int _check_uevent_generated(struct dm_ioctl *dmi)
{
if (!dm_check_version() ||
((_dm_version == 4) ? _dm_version_minor < 17 : _dm_version < 4))
_dm_version < 4 ||
_dm_version_minor < 17)
/* can't check, assume uevent is generated */
return 1;
@ -1576,7 +1453,7 @@ static int _check_uevent_generated(struct dm_ioctl *dmi)
static int _create_and_load_v4(struct dm_task *dmt)
{
struct dm_task *task;
int r, ioctl_errno = 0;
int r;
uint32_t cookie;
/* Use new task struct to create the device */
@ -1602,10 +1479,8 @@ static int _create_and_load_v4(struct dm_task *dmt)
task->cookie_set = dmt->cookie_set;
task->add_node = dmt->add_node;
if (!dm_task_run(task)) {
ioctl_errno = task->ioctl_errno;
if (!dm_task_run(task))
goto_bad;
}
dm_task_destroy(task);
@ -1631,8 +1506,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
task->ima_measurement = dmt->ima_measurement;
r = dm_task_run(task);
if (!r)
ioctl_errno = task->ioctl_errno;
task->head = NULL;
task->tail = NULL;
@ -1650,7 +1523,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
dmt->uuid = NULL;
free(dmt->mangled_uuid);
dmt->mangled_uuid = NULL;
/* coverity[double_free] recursive function call */
_dm_task_free_targets(dmt);
if (dm_task_run(dmt))
@ -1662,7 +1534,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
dmt->uuid = NULL;
free(dmt->mangled_uuid);
dmt->mangled_uuid = NULL;
/* coverity[double_free] recursive function call */
_dm_task_free_targets(dmt);
/*
@ -1681,18 +1552,12 @@ static int _create_and_load_v4(struct dm_task *dmt)
if (!dm_task_run(dmt))
log_error("Failed to revert device creation.");
if (ioctl_errno != 0)
dmt->ioctl_errno = ioctl_errno;
return 0;
bad:
dm_task_destroy(task);
_udev_complete(dmt);
if (ioctl_errno != 0)
dmt->ioctl_errno = ioctl_errno;
return 0;
}
@ -1943,34 +1808,23 @@ static int _do_dm_ioctl_unmangle_string(char *str, const char *str_name,
static int _dm_ioctl_unmangle_names(int type, struct dm_ioctl *dmi)
{
char buf[DM_NAME_LEN];
char buf_uuid[DM_UUID_LEN];
struct dm_name_list *names;
struct dm_names *names;
unsigned next = 0;
char *name;
int r = 1;
uint32_t *event_nr;
char *uuid_ptr;
dm_string_mangling_t mangling_mode = dm_get_name_mangling_mode();
if ((name = dmi->name))
r &= _do_dm_ioctl_unmangle_string(name, "name", buf, sizeof(buf),
mangling_mode);
r = _do_dm_ioctl_unmangle_string(name, "name", buf, sizeof(buf),
dm_get_name_mangling_mode());
if (type == DM_DEVICE_LIST &&
((names = ((struct dm_name_list *) ((char *)dmi + dmi->data_start)))) &&
((names = ((struct dm_names *) ((char *)dmi + dmi->data_start)))) &&
names->dev) {
do {
names = (struct dm_name_list *)((char *) names + next);
event_nr = _align_ptr(names->name + strlen(names->name) + 1);
r &= _do_dm_ioctl_unmangle_string(names->name, "name",
buf, sizeof(buf), mangling_mode);
/* Unmangle also UUID within same loop */
if (_check_has_event_nr() &&
(event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
uuid_ptr = _align_ptr(event_nr + 2);
r &= _do_dm_ioctl_unmangle_string(uuid_ptr, "UUID", buf_uuid,
sizeof(buf_uuid), mangling_mode);
}
names = (struct dm_names *)((char *) names + next);
r = _do_dm_ioctl_unmangle_string(names->name, "name",
buf, sizeof(buf),
dm_get_name_mangling_mode());
next = names->next;
} while (next);
}
@ -2034,7 +1888,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
/*
* Prevent udev vs. libdevmapper race when processing nodes
* 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
* make use of it (by not calling dm_task_set_cookie before).
* We need to instruct the udev rules not to be applied at
@ -2044,7 +1898,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
if (!dmt->cookie_set && dm_udev_get_sync_support()) {
log_debug_activation("Cookie value is not set while trying to call %s "
"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).",
dmt->type == DM_DEVICE_RESUME ? "DM_DEVICE_RESUME" :
dmt->type == DM_DEVICE_REMOVE ? "DM_DEVICE_REMOVE" :

View File

@ -79,7 +79,7 @@ struct dm_task {
};
struct cmd_data {
const char name[16];
const char *name;
const unsigned cmd;
const int version[3];
};

View File

@ -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 (!sscanf(&str[i+2], "%2x%" DM_TO_STRING(DM_NAME_LEN) "s",
&code, str_rest)) {
if (!sscanf(&str[i+2], "%2x%s", &code, str_rest)) {
log_debug_activation("Hex encoding mismatch detected in %s \"%s\" "
"while trying to unmangle it.", str_name, str);
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)
return 1;
if (unlink(path) && (errno != ENOENT)) {
log_sys_error("unlink", path);
if (unlink(path) < 0) {
log_error("Unable to unlink device node for '%s'",
dev_name);
return 0;
}
} 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);
/* udev may already have deleted the node. Ignore ENOENT. */
if (unlink(path) && (errno != ENOENT)) {
log_sys_error("unlink", path);
if (unlink(path) < 0 && errno != ENOENT) {
log_error("Unable to unlink device node for '%s'", dev_name);
return 0;
}
@ -1451,10 +1451,9 @@ struct node_op_parms {
static void _store_str(char **pos, char **ptr, const char *str)
{
size_t len = strlen(str) + 1;
memcpy(*pos, str, len);
strcpy(*pos, str);
*ptr = *pos;
*pos += len;
*pos += strlen(*ptr) + 1;
}
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)
{
size_t len;
if (!uuid_prefix)
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);
return 0;
}
memcpy(_default_uuid_prefix, uuid_prefix, len + 1);
strcpy(_default_uuid_prefix, uuid_prefix);
return 1;
}
@ -1743,9 +1740,6 @@ static void _unmangle_mountinfo_string(const char *src, char *buf)
*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 */
static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min, char *buf)
{
@ -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))
if (!_sanitize_line(buffer) ||
!_mountinfo_parse_line(buffer, &maj, &min, target) ||
if (!_mountinfo_parse_line(buffer, &maj, &min, target) ||
!read_fn(buffer, maj, min, target, cb_data)) {
stack;
r = 0;
@ -2318,7 +2311,7 @@ static int _check_semaphore_is_supported(void)
if (maxid < 0) {
log_warn("Kernel not configured for semaphores (System V IPC). "
"Not using udev synchronization code.");
"Not using udev synchronisation code.");
return 0;
}
@ -2341,7 +2334,7 @@ static int _check_udev_is_running(void)
if (!(r = udev_queue_get_udev_is_active(udev_queue)))
log_debug_activation("Udev is not running. "
"Not using udev synchronization code.");
"Not using udev synchronisation code.");
udev_queue_unref(udev_queue);
udev_unref(udev);

View File

@ -74,6 +74,8 @@ static struct dm_config_node *_create_node(struct dm_pool *mem);
static char *_dup_tok(struct parser *p);
static char *_dup_token(struct dm_pool *mem, const char *b, const char *e);
static const int _sep = '/';
#define MAX_INDENT 32
#define match(t) do {\
@ -175,18 +177,19 @@ static int _do_dm_config_parse(struct dm_config_tree *cft, const char *start, co
{
/* TODO? if (start == end) return 1; */
struct parser p = {
.mem = cft->mem,
.tb = start,
.te = start,
.fb = start,
.fe = end,
.line = 1,
.no_dup_node_check = no_dup_node_check
};
struct parser *p;
if (!(p = dm_pool_zalloc(cft->mem, sizeof(*p))))
return_0;
_get_token(&p, TOK_SECTION_E);
if (!(cft->root = _file(&p)))
p->mem = cft->mem;
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;
cft->root = _config_reverse(cft->root);
@ -523,18 +526,17 @@ static struct dm_config_node *_find_or_make_node(struct dm_pool *mem,
const char *path,
int no_dup_node_check)
{
const int sep = '/';
const char *e;
struct dm_config_node *cn = parent ? parent->child : NULL;
struct dm_config_node *cn_found = NULL;
while (cn || mem) {
/* trim any leading slashes */
while (*path && (*path == sep))
while (*path && (*path == _sep))
path++;
/* find the end of this segment */
for (e = path; *e && (*e != sep); e++) ;
for (e = path; *e && (*e != _sep); e++) ;
/* hunt for the node */
cn_found = NULL;

View File

@ -171,7 +171,7 @@ struct load_segment {
uint32_t region_size; /* Mirror + raid */
unsigned clustered; /* Mirror */
unsigned mirror_area_count; /* Mirror */
uint64_t flags; /* Mirror + Raid + Cache */
uint32_t flags; /* Mirror + raid + Cache */
char *uuid; /* Clustered mirror log */
const char *policy_name; /* Cache */
@ -214,7 +214,6 @@ struct load_segment {
uint32_t device_id; /* Thin */
// VDO params
uint32_t vdo_version; /* VDO - version of target table line */
struct dm_tree_node *vdo_data; /* VDO */
struct dm_vdo_target_params vdo_params; /* VDO */
const char *vdo_name; /* VDO - device name is ALSO passed as table arg */
@ -294,10 +293,6 @@ struct load_properties {
unsigned send_messages;
/* Skip suspending node's children, used when sending messages to thin-pool */
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. */
@ -348,7 +343,7 @@ struct dm_tree {
int retry_remove; /* 1 retries remove if not successful */
uint32_t cookie;
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 */
};
/*
@ -590,7 +585,6 @@ void dm_tree_set_optional_uuid_suffixes(struct dm_tree *dtree, const char **opti
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,
const char *uuid)
{
@ -598,26 +592,28 @@ static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
const char *default_uuid_prefix;
size_t default_uuid_prefix_len;
const char *suffix, *suffix_position;
char uuid_without_suffix[DM_UUID_LEN + 1];
char uuid_without_suffix[DM_UUID_LEN];
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))) {
log_debug_activation("Matched uuid %s %s in deptree.", uuid, _node_name(node));
log_debug("Matched uuid %s in deptree.", uuid);
return node;
}
default_uuid_prefix = dm_uuid_prefix();
default_uuid_prefix_len = strlen(default_uuid_prefix);
if (suffix_list && (suffix_position = strrchr(uuid, '-'))) {
while ((suffix = suffix_list[i++])) {
if (strcmp(suffix_position + 1, suffix))
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';
if ((node = dm_hash_lookup(dtree->uuids, uuid_without_suffix))) {
log_debug_activation("Matched uuid %s %s (missing suffix -%s) in deptree.",
uuid_without_suffix, _node_name(node), suffix);
log_debug("Matched uuid %s (missing suffix -%s) in deptree.", uuid_without_suffix, suffix);
return node;
}
@ -625,17 +621,15 @@ static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
};
}
default_uuid_prefix = dm_uuid_prefix();
default_uuid_prefix_len = strlen(default_uuid_prefix);
if (strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len))
return NULL;
if ((strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len) == 0) &&
(node = dm_hash_lookup(dtree->uuids, uuid + default_uuid_prefix_len))) {
log_debug_activation("Matched uuid %s %s (missing prefix) in deptree.",
uuid + default_uuid_prefix_len, _node_name(node));
if ((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);
return node;
}
log_debug_activation("Not matched uuid %s in deptree.", uuid);
log_debug("Not matched uuid %s in deptree.", uuid);
return NULL;
}
@ -2035,68 +2029,6 @@ static int _rename_conflict_exists(struct dm_tree_node *parent,
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,
const char *uuid_prefix,
size_t uuid_prefix_len)
@ -2107,7 +2039,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
struct dm_tree_node *child = dnode;
const char *name;
const char *uuid;
int priority, next_priority;
int priority;
/* Activate children first */
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
@ -2125,16 +2057,12 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
}
handle = NULL;
for (priority = 0; priority < 3; priority++) {
awaiting_peer_rename = 0;
next_priority = 0;
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
if (priority != child->activation_priority) {
if ((next_priority < child->activation_priority) &&
(child->activation_priority > priority))
next_priority = child->activation_priority;
if (priority != child->activation_priority)
continue;
}
if (!(uuid = dm_tree_node_get_uuid(child))) {
stack;
@ -2189,16 +2117,9 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
if (r && (child->props.send_messages > 1) &&
!(r = _node_send_messages(child, uuid_prefix, uuid_prefix_len, 1)))
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)
priority--; /* redo priority level */
else if (!next_priority)
break; /* no more work, higher priority was not found in the chain */
}
return r;
@ -2757,10 +2678,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
count += 1;
if (seg->writecache_settings.max_age_set)
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)
count += 2;
@ -2812,14 +2729,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
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) {
EMIT_PARAMS(pos, " %s %s",
seg->writecache_settings.new_key,
@ -2868,8 +2777,6 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
count++;
if (set->sectors_per_bit_set)
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",
origin_dev,
@ -2906,9 +2813,6 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
if (set->sectors_per_bit_set)
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))
stack;
@ -2945,18 +2849,13 @@ static int _thin_pool_emit_segment_line(struct dm_task *dmt,
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,
char *params, size_t paramsize)
{
int pos = 0;
char data[DM_FORMAT_DEV_BUFSIZE];
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))
return_0;
@ -2966,59 +2865,18 @@ static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t
return 0;
}
/*
* If there is already running VDO target, read 'existing' virtual size out of table line
* and avoid reading it them from VDO metadata device
*
* NOTE: ATM VDO virtual size can be ONLY extended thus it's simple to recongnize 'right' size.
* However if there would be supported also reduction, this check would need to check range.
*/
if ((vdo_dmt = dm_task_create(DM_DEVICE_TABLE))) {
if (dm_task_set_major(vdo_dmt, major) &&
dm_task_set_minor(vdo_dmt, minor) &&
dm_task_run(vdo_dmt)) {
(void) dm_get_next_target(vdo_dmt, NULL, &start, &length, &type, &vdo_params);
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",
EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s "
"maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
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,
seg->vdo_params.max_discard,
seg->vdo_params.ack_threads,
seg->vdo_params.bio_threads,
@ -3093,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);
break;
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;
break;
case SEG_CRYPT:
@ -3532,10 +3390,6 @@ int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
/* Resume snapshot origins after new snapshots */
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
* target that must not be active more than once concurrently!
@ -3598,20 +3452,6 @@ static int _add_snapshot_target(struct dm_tree_node *node,
/* Resume merging snapshot after snapshot-merge */
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;
@ -3869,7 +3709,7 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
{
struct dm_config_node *cn;
struct load_segment *seg;
const uint64_t modemask =
static const uint64_t _modemask =
DM_CACHE_FEATURE_PASSTHROUGH |
DM_CACHE_FEATURE_WRITETHROUGH |
DM_CACHE_FEATURE_WRITEBACK;
@ -3881,12 +3721,12 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
return 0;
}
switch (feature_flags & modemask) {
switch (feature_flags & _modemask) {
case DM_CACHE_FEATURE_PASSTHROUGH:
case DM_CACHE_FEATURE_WRITEBACK:
if (strcmp(policy_name, "cleaner") == 0) {
/* Enforce writethrough mode for cleaner policy */
feature_flags = ~modemask;
feature_flags = ~_modemask;
feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
}
/* Fall through */
@ -4369,12 +4209,6 @@ int dm_tree_node_set_thin_external_origin(struct dm_tree_node *node,
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;
}
@ -4489,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,
uint64_t size,
uint32_t vdo_version,
const char *vdo_pool_name,
const char *data_uuid,
uint64_t data_size,
@ -4511,13 +4344,11 @@ int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
if (!_link_tree_nodes(node, seg->vdo_data))
return_0;
seg->vdo_version = vdo_version;
seg->vdo_params = *vtp;
seg->vdo_name = vdo_pool_name;
seg->vdo_data_size = data_size;
if (seg->vdo_version < 4)
node->props.send_messages = 2;
node->props.send_messages = 2;
return 1;
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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:
* 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;
}
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;
}
@ -552,7 +552,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
if (size == UINT64_C(0)) {
if (base == BASE_UNKNOWN)
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;
}

View File

@ -106,31 +106,26 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
/* Second field holds the device count */
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;
msg_fields = "";
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid))))
goto_bad;
msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> ";
if (!(s->raid_type = dm_pool_strndup(mem, params, pp - params - 1)))
if (!(s->raid_type = dm_pool_zalloc(mem, p - params)))
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;
/* Raid target can actually report more then real number of legs in a case
* raid legs have been removed during initial raid array resynchronization */
if (i > (pp - p - 1))
i = pp - p - 1;
if (!(s->dev_health = dm_pool_strndup(mem, p, i))) /* health chars */
goto_bad;
p = pp;
s->dev_count = i;
if (sscanf(p, FMTu64 "/" FMTu64, &s->insync_regions, &s->total_regions) != 2)
msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> ";
if (sscanf(params, "%s %u %s " FMTu64 "/" FMTu64,
s->raid_type,
&s->dev_count,
s->dev_health,
&s->insync_regions,
&s->total_regions) != 5)
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> ";
/* 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;
if (!(s->sync_action = dm_pool_strndup(mem, pp, p - pp - 1)))
if (!(s->sync_action = dm_pool_zalloc(mem, pp - p)))
goto_bad;
if (sscanf(p, FMTu64, &s->mismatch_count) != 1)
if (sscanf(p, "%s " FMTu64, s->sync_action, &s->mismatch_count) != 2)
goto_bad;
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)
goto bad;
/* <journal_char> - 'A' - active write-through journal device.
* - 'a' - active write-back journal device.
* - 'D' - dead journal device.
* - '-' - no journal device.
*/
out:
*status = s;
while (i-- > 0)
if (s->dev_health[i] == 'a')
a++; /* Count number of 'a' */
if (s->insync_regions == s->total_regions) {
/* FIXME: kernel gives misleading info here
* Trying to recognize a true state */
while (i-- > 0)
if (s->dev_health[i] == 'a')
a++; /* Count number of 'a' */
if (a) {
if ((a < s->dev_count) && /* SOME legs are in 'a' */
/* FIXME: kernel gives misleading info here
* Trying to recognize a true state */
(s->insync_regions == s->total_regions) &&
(!strcasecmp(s->sync_action, "recover") ||
!strcasecmp(s->sync_action, "idle"))) {
/* 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';
if (a && a < s->dev_count) {
/* SOME legs are in 'a' */
if (!strcasecmp(s->sync_action, "recover")
|| !strcasecmp(s->sync_action, "idle"))
/* Kernel may possibly start some action
* in near-by future, do not report 100% */
s->insync_regions--;
}
}
@ -528,21 +511,6 @@ int dm_get_status_thin(struct dm_pool *mem, const char *params,
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
* Mirror core parms: 2 253:4 253:5 400/400
@ -596,7 +564,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
pos += used;
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)))
goto_out;
@ -641,7 +609,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
goto_out;
for (i = 0; i < s->log_count; ++i)
s->logs[i].health = _get_health(pos[i]);
s->logs[i].health = pos[i];
}
}

View File

@ -77,10 +77,9 @@ enum dm_vdo_write_policy {
struct dm_vdo_target_params {
uint32_t minimum_io_size; // in sectors
uint32_t block_map_cache_size_mb;
union {
uint32_t block_map_era_length; // format period
uint32_t block_map_period; // supported alias
};
uint32_t block_map_era_length; // format period
uint32_t check_point_frequency;
uint32_t index_memory_size_mb; // format
uint32_t slab_size_mb; // format
@ -107,8 +106,6 @@ struct dm_vdo_target_params {
bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
uint64_t vdo_size);
bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks);
//----------------------------------------------------------------
#endif

View File

@ -1,5 +1,5 @@
/*
* 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.
*
@ -15,52 +15,49 @@
#ifndef DEVICE_MAPPER_VDO_LIMITS_H
#define DEVICE_MAPPER_VDO_LIMITS_H
#ifndef SECTOR_SHIFT
#define SECTOR_SHIFT 9L
#endif
#define DM_VDO_BLOCK_SIZE UINT64_C(8) // 4KiB in sectors
#define DM_VDO_BLOCK_SIZE_KB (DM_VDO_BLOCK_SIZE << SECTOR_SHIFT)
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB (128) // 128MiB
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB (16 * 1024 * 1024 - 1) // 16TiB - 1
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_PER_LOGICAL_THREAD (4096 * DM_VDO_BLOCK_SIZE_KB)
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM 1
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM 16380
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM (1)
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM (16380)
#define DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB 256 // 0.25 GiB
#define DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB (256) // 0.25 GiB
#define DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB (1024 * 1024 * 1024) // 1TiB
#define DM_VDO_SLAB_SIZE_MINIMUM_MB 128 // 128MiB
//#define DM_VDO_READ_CACHE_SIZE_MINIMUM_MB (0)
#define DM_VDO_READ_CACHE_SIZE_MAXIMUM_MB (16 * 1024 * 1024 - 1) // 16TiB - 1
#define DM_VDO_SLAB_SIZE_MINIMUM_MB (128) // 128MiB
#define DM_VDO_SLAB_SIZE_MAXIMUM_MB (32 * 1024) // 32GiB
#define DM_VDO_SLABS_MAXIMUM 8192
#define DM_VDO_LOGICAL_SIZE_MAXIMUM (UINT64_C(4) * 1024 * 1024 * 1024 * 1024 * 1024 >> SECTOR_SHIFT) // 4PiB
#define DM_VDO_PHYSICAL_SIZE_MAXIMUM (UINT64_C(64) * DM_VDO_BLOCK_SIZE_KB * 1024 * 1024 * 1024 >> SECTOR_SHIFT) // 256TiB
//#define DM_VDO_LOGICAL_SIZE_MINIMUM_MB (0)
#define DM_VDO_LOGICAL_SIZE_MAXIMUM_MB (UINT64_C(4) * 1024 * 1024 * 1024) // 4PiB
#define DM_VDO_ACK_THREADS_MINIMUM 0
#define DM_VDO_ACK_THREADS_MAXIMUM 100
//#define DM_VDO_ACK_THREADS_MINIMUM (0)
#define DM_VDO_ACK_THREADS_MAXIMUM (100)
#define DM_VDO_BIO_THREADS_MINIMUM 1
#define DM_VDO_BIO_THREADS_MAXIMUM 100
#define DM_VDO_BIO_THREADS_MINIMUM (1)
#define DM_VDO_BIO_THREADS_MAXIMUM (100)
#define DM_VDO_BIO_ROTATION_MINIMUM 1
#define DM_VDO_BIO_ROTATION_MAXIMUM 1024
#define DM_VDO_BIO_ROTATION_MINIMUM (1)
#define DM_VDO_BIO_ROTATION_MAXIMUM (1024)
#define DM_VDO_CPU_THREADS_MINIMUM 1
#define DM_VDO_CPU_THREADS_MAXIMUM 100
#define DM_VDO_CPU_THREADS_MINIMUM (1)
#define DM_VDO_CPU_THREADS_MAXIMUM (100)
#define DM_VDO_HASH_ZONE_THREADS_MINIMUM 0
#define DM_VDO_HASH_ZONE_THREADS_MAXIMUM 100
//#define DM_VDO_HASH_ZONE_THREADS_MINIMUM (0)
#define DM_VDO_HASH_ZONE_THREADS_MAXIMUM (100)
#define DM_VDO_LOGICAL_THREADS_MINIMUM 0
#define DM_VDO_LOGICAL_THREADS_MAXIMUM 60
//#define DM_VDO_LOGICAL_THREADS_MINIMUM (0)
#define DM_VDO_LOGICAL_THREADS_MAXIMUM (100)
#define DM_VDO_PHYSICAL_THREADS_MINIMUM 0
#define DM_VDO_PHYSICAL_THREADS_MAXIMUM 16
//#define DM_VDO_PHYSICAL_THREADS_MINIMUM (0)
#define DM_VDO_PHYSICAL_THREADS_MAXIMUM (16)
#define DM_VDO_MAX_DISCARD_MINIMUM 1
#define DM_VDO_MAX_DISCARD_MAXIMUM (UINT32_MAX / (uint32_t)(DM_VDO_BLOCK_SIZE_KB))
#define DM_VDO_MAX_DISCARD_MINIMUM (1)
#define DM_VDO_MAX_DISCARD_MAXIMUM (UINT32_MAX / 4096)
#endif // DEVICE_MAPPER_VDO_LIMITS_H

View File

@ -1,308 +0,0 @@
/*
* Copyright (C) 2022 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Based on VDO sources: https://github.com/dm-vdo/vdo
*
* Simplified parser of VDO superblock to obtain basic VDO parameteers
*
* TODO: maybe switch to some library in the future
*/
//#define _GNU_SOURCE 1
//#define _LARGEFILE64_SOURCE 1
#include "device_mapper/misc/dmlib.h"
#include "target.h"
#include "lib/mm/xlate.h"
//#include "linux/byteorder/big_endian.h"
//#include "linux/byteorder/little_endian.h"
//#define le32_to_cpu __le32_to_cpu
//#define le64_to_cpu __le64_to_cpu
#include <errno.h>
#include <fcntl.h>
#include <linux/fs.h> /* For block ioctl definitions */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
typedef unsigned char uuid_t[16];
#define __packed __attribute__((packed))
static const char _MAGIC_NUMBER[] = "dmvdo001";
#define MAGIC_NUMBER_SIZE (sizeof(_MAGIC_NUMBER) - 1)
struct vdo_version_number {
uint32_t major_version;
uint32_t minor_version;
} __packed;
/*
* The registry of component ids for use in headers
*/
enum {
SUPER_BLOCK = 0,
FIXED_LAYOUT = 1,
RECOVERY_JOURNAL = 2,
SLAB_DEPOT = 3,
BLOCK_MAP = 4,
GEOMETRY_BLOCK = 5,
}; /* ComponentID */
struct vdo_header {
uint32_t id; /* The component this is a header for */
struct vdo_version_number version; /* The version of the data format */
size_t size; /* The size of the data following this header */
} __packed;
struct vdo_geometry_block {
char magic_number[MAGIC_NUMBER_SIZE];
struct vdo_header header;
uint32_t checksum;
} __packed;
struct vdo_config {
uint64_t logical_blocks; /* number of logical blocks */
uint64_t physical_blocks; /* number of physical blocks */
uint64_t slab_size; /* number of blocks in a slab */
uint64_t recovery_journal_size; /* number of recovery journal blocks */
uint64_t slab_journal_blocks; /* number of slab journal blocks */
} __packed;
struct vdo_component_41_0 {
uint32_t state;
uint64_t complete_recoveries;
uint64_t read_only_recoveries;
struct vdo_config config; /* packed */
uint64_t nonce;
} __packed;
enum vdo_volume_region_id {
VDO_INDEX_REGION = 0,
VDO_DATA_REGION = 1,
VDO_VOLUME_REGION_COUNT,
};
struct vdo_volume_region {
/* The ID of the region */
enum vdo_volume_region_id id;
/*
* The absolute starting offset on the device. The region continues
* until the next region begins.
*/
uint64_t start_block;
} __packed;
struct vdo_index_config {
uint32_t mem;
uint32_t unused;
uint8_t sparse;
} __packed;
struct vdo_volume_geometry {
uint32_t release_version;
uint64_t nonce;
uuid_t uuid;
uint64_t bio_offset;
struct vdo_volume_region regions[VDO_VOLUME_REGION_COUNT];
struct vdo_index_config index_config;
} __packed;
struct vdo_volume_geometry_4 {
uint32_t release_version;
uint64_t nonce;
uuid_t uuid;
struct vdo_volume_region regions[VDO_VOLUME_REGION_COUNT];
struct vdo_index_config index_config;
} __packed;
/* Decoding mostly only some used stucture members */
static void _vdo_decode_version(struct vdo_version_number *v)
{
v->major_version = le32_to_cpu(v->major_version);
v->minor_version = le32_to_cpu(v->minor_version);
}
static void _vdo_decode_header(struct vdo_header *h)
{
h->id = le32_to_cpu(h->id);
_vdo_decode_version(&h->version);
h->size = le64_to_cpu(h->size);
}
static void _vdo_decode_geometry_region(struct vdo_volume_region *vr)
{
vr->id = le32_to_cpu(vr->id);
vr->start_block = le64_to_cpu(vr->start_block);
}
static void _vdo_decode_volume_geometry(struct vdo_volume_geometry *vg)
{
vg->release_version = le32_to_cpu(vg->release_version);
vg->nonce = le64_to_cpu(vg->nonce);
vg->bio_offset = le64_to_cpu(vg->bio_offset);
_vdo_decode_geometry_region(&vg->regions[VDO_DATA_REGION]);
}
static void _vdo_decode_volume_geometry_4(struct vdo_volume_geometry *vg,
struct vdo_volume_geometry_4 *vg_4)
{
vg->release_version = le32_to_cpu(vg_4->release_version);
vg->nonce = le64_to_cpu(vg_4->nonce);
vg->bio_offset = 0;
vg->regions[VDO_DATA_REGION] = vg_4->regions[VDO_DATA_REGION];
_vdo_decode_geometry_region(&vg->regions[VDO_DATA_REGION]);
}
static void _vdo_decode_config(struct vdo_config *vc)
{
vc->logical_blocks = le64_to_cpu(vc->logical_blocks);
vc->physical_blocks = le64_to_cpu(vc->physical_blocks);
vc->slab_size = le64_to_cpu(vc->slab_size);
vc->recovery_journal_size = le64_to_cpu(vc->recovery_journal_size);
vc->slab_journal_blocks = le64_to_cpu(vc->slab_journal_blocks);
}
static void _vdo_decode_pvc(struct vdo_component_41_0 *pvc)
{
_vdo_decode_config(&pvc->config);
pvc->nonce = le64_to_cpu(pvc->nonce);
}
bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)
{
char buffer[4096];
int fh;
bool r = false;
struct stat st;
uint64_t size;
uint64_t regpos;
struct vdo_header h;
struct vdo_version_number vn;
struct vdo_volume_geometry vg;
struct vdo_volume_geometry_4 vg_4;
struct vdo_component_41_0 pvc;
*logical_blocks = 0;
if ((fh = open(vdo_path, O_RDONLY)) == -1) {
log_sys_debug("Failed to open VDO backend %s.", vdo_path);
return false;
}
if (ioctl(fh, BLKGETSIZE64, &size) == -1) {
if (errno != ENOTTY) {
log_sys_debug("ioctl", vdo_path);
goto err;
}
/* lets retry for file sizes */
if (fstat(fh, &st) < 0) {
log_sys_debug("fstat", vdo_path);
goto err;
}
size = st.st_size;
}
if (read(fh, buffer, sizeof(buffer)) < 0) {
log_sys_debug("read", vdo_path);
goto err;
}
if (strncmp(buffer, _MAGIC_NUMBER, MAGIC_NUMBER_SIZE)) {
log_debug_activation("Found mismatching VDO magic header in %s.", vdo_path);
goto err;
}
memcpy(&h, buffer + MAGIC_NUMBER_SIZE, sizeof(h));
_vdo_decode_header(&h);
if (h.id != 5) {
log_debug_activation("Expected geometry VDO block instead of block %u.", h.id);
goto err;
}
switch (h.version.major_version) {
case 4:
memcpy(&vg_4, buffer + MAGIC_NUMBER_SIZE + sizeof(h), sizeof(vg_4));
_vdo_decode_volume_geometry_4(&vg, &vg_4);
break;
case 5:
memcpy(&vg, buffer + MAGIC_NUMBER_SIZE + sizeof(h), sizeof(vg));
_vdo_decode_volume_geometry(&vg);
break;
default:
log_debug_activation("Unsupported VDO version %u.%u.", h.version.major_version, h.version.minor_version);
goto err;
}
regpos = (vg.regions[VDO_DATA_REGION].start_block - vg.bio_offset) * 4096;
if ((regpos + sizeof(buffer)) > size) {
log_debug_activation("File/Device is shorter and can't provide requested VDO volume region at " FMTu64 " > " FMTu64 ".", regpos, size);
goto err;
}
if (lseek(fh, regpos, SEEK_SET) < 0) {
log_sys_debug("lseek", vdo_path);
goto err;
}
if (read(fh, buffer, sizeof(buffer)) < 0) {
log_sys_debug("read", vdo_path);
goto err;
}
memcpy(&vn, buffer + sizeof(struct vdo_geometry_block), sizeof(vn));
_vdo_decode_version(&vn);
if (vn.major_version > 41) {
log_debug_activation("Unknown VDO component version %u.", vn.major_version); // should be 41!
goto err;
}
memcpy(&pvc, buffer + sizeof(struct vdo_geometry_block) + sizeof(vn), sizeof(pvc));
_vdo_decode_pvc(&pvc);
if (pvc.nonce != vg.nonce) {
log_debug_activation("VDO metadata has mismatching VDO nonces " FMTu64 " != " FMTu64 ".", pvc.nonce, vg.nonce);
goto err;
}
#if 0
log_debug_activation("LogBlocks " FMTu64 ".", pvc.config.logical_blocks);
log_debug_activation("PhyBlocks " FMTu64 ".", pvc.config.physical_blocks);
log_debug_activation("SlabSize " FMTu64 ".", pvc.config.slab_size);
log_debug_activation("RecJourSize " FMTu64 ".", pvc.config.recovery_journal_size);
log_debug_activation("SlabJouSize " FMTu64 ".", pvc.config.slab_journal_blocks);
#endif
*logical_blocks = pvc.config.logical_blocks;
r = true;
err:
(void) close(fh);
return r;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@ -18,117 +18,82 @@
#include "vdo_limits.h"
#include "target.h"
/* validate vdo target parameters and 'vdo_size' in sectors */
bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
uint64_t vdo_size)
{
bool valid = true;
/* 512 or 4096 bytes only ATM */
if ((vtp->minimum_io_size != (512 >> SECTOR_SHIFT)) &&
(vtp->minimum_io_size != (4096 >> SECTOR_SHIFT))) {
log_error("VDO minimum io size %u is unsupported [512, 4096].",
if ((vtp->minimum_io_size != 1) &&
(vtp->minimum_io_size != 8)) {
log_error("VDO minimum io size %u is unsupported.",
vtp->minimum_io_size);
valid = false;
}
if ((vtp->block_map_cache_size_mb < DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB) ||
(vtp->block_map_cache_size_mb > DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB)) {
log_error("VDO block map cache size %u MiB is out of range [%u..%u].",
vtp->block_map_cache_size_mb,
DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB,
DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB);
valid = false;
}
if ((vtp->block_map_era_length < DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM) ||
(vtp->block_map_era_length > DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM)) {
log_error("VDO block map era length %u is out of range [%u..%u].",
vtp->block_map_era_length,
DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM,
DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM);
log_error("VDO block map cache size %u out of range.",
vtp->block_map_cache_size_mb);
valid = false;
}
if ((vtp->index_memory_size_mb < DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB) ||
(vtp->index_memory_size_mb > DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB)) {
log_error("VDO index memory size %u MiB is out of range [%u..%u].",
vtp->index_memory_size_mb,
DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB,
DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB);
log_error("VDO index memory size %u out of range.",
vtp->index_memory_size_mb);
valid = false;
}
if ((vtp->slab_size_mb < DM_VDO_SLAB_SIZE_MINIMUM_MB) ||
(vtp->slab_size_mb > DM_VDO_SLAB_SIZE_MAXIMUM_MB)) {
log_error("VDO slab size %u MiB is out of range [%u..%u].",
vtp->slab_size_mb,
DM_VDO_SLAB_SIZE_MINIMUM_MB,
DM_VDO_SLAB_SIZE_MAXIMUM_MB);
log_error("VDO slab size %u out of range.",
vtp->slab_size_mb);
valid = false;
}
if ((vtp->max_discard < DM_VDO_MAX_DISCARD_MINIMUM) ||
(vtp->max_discard > DM_VDO_MAX_DISCARD_MAXIMUM)) {
log_error("VDO max discard %u is out of range [%u..%u].",
vtp->max_discard,
DM_VDO_MAX_DISCARD_MINIMUM,
DM_VDO_MAX_DISCARD_MAXIMUM);
log_error("VDO max discard %u out of range.",
vtp->max_discard);
valid = false;
}
if (vtp->ack_threads > DM_VDO_ACK_THREADS_MAXIMUM) {
log_error("VDO ack threads %u is out of range [0..%u].",
vtp->ack_threads,
DM_VDO_ACK_THREADS_MAXIMUM);
log_error("VDO ack threads %u out of range.", vtp->ack_threads);
valid = false;
}
if ((vtp->bio_threads < DM_VDO_BIO_THREADS_MINIMUM) ||
(vtp->bio_threads > DM_VDO_BIO_THREADS_MAXIMUM)) {
log_error("VDO bio threads %u is out of range [%u..%u].",
vtp->bio_threads,
DM_VDO_BIO_THREADS_MINIMUM,
DM_VDO_BIO_THREADS_MAXIMUM);
log_error("VDO bio threads %u out of range.", vtp->bio_threads);
valid = false;
}
if ((vtp->bio_rotation < DM_VDO_BIO_ROTATION_MINIMUM) ||
(vtp->bio_rotation > DM_VDO_BIO_ROTATION_MAXIMUM)) {
log_error("VDO bio rotation %u is out of range [%u..%u].",
vtp->bio_rotation,
DM_VDO_BIO_ROTATION_MINIMUM,
DM_VDO_BIO_ROTATION_MAXIMUM);
log_error("VDO bio rotation %u out of range.", vtp->bio_rotation);
valid = false;
}
if ((vtp->cpu_threads < DM_VDO_CPU_THREADS_MINIMUM) ||
(vtp->cpu_threads > DM_VDO_CPU_THREADS_MAXIMUM)) {
log_error("VDO cpu threads %u is out of range [%u..%u].",
vtp->cpu_threads,
DM_VDO_CPU_THREADS_MINIMUM,
DM_VDO_CPU_THREADS_MAXIMUM);
log_error("VDO cpu threads %u out of range.", vtp->cpu_threads);
valid = false;
}
if (vtp->hash_zone_threads > DM_VDO_HASH_ZONE_THREADS_MAXIMUM) {
log_error("VDO hash zone threads %u is out of range [0..%u].",
vtp->hash_zone_threads,
DM_VDO_HASH_ZONE_THREADS_MAXIMUM);
log_error("VDO hash zone threads %u out of range.", vtp->hash_zone_threads);
valid = false;
}
if (vtp->logical_threads > DM_VDO_LOGICAL_THREADS_MAXIMUM) {
log_error("VDO logical threads %u is out of range [0..%u].",
vtp->logical_threads,
DM_VDO_LOGICAL_THREADS_MAXIMUM);
log_error("VDO logical threads %u out of range.", vtp->logical_threads);
valid = false;
}
if (vtp->physical_threads > DM_VDO_PHYSICAL_THREADS_MAXIMUM) {
log_error("VDO physical threads %u is out of range [0..%u].",
vtp->physical_threads,
DM_VDO_PHYSICAL_THREADS_MAXIMUM);
log_error("VDO physical threads %u out of range.", vtp->physical_threads);
valid = false;
}
@ -155,10 +120,10 @@ bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
valid = false;
}
if (vdo_size > DM_VDO_LOGICAL_SIZE_MAXIMUM) {
log_error("VDO logical size is larger than limit " FMTu64 " TiB by " FMTu64 " KiB.",
DM_VDO_LOGICAL_SIZE_MAXIMUM / (UINT64_C(1024) * 1024 * 1024 * 1024 >> SECTOR_SHIFT),
(vdo_size - DM_VDO_LOGICAL_SIZE_MAXIMUM) / 2);
if (vdo_size >= (DM_VDO_LOGICAL_SIZE_MAXIMUM_MB * UINT64_C(1024 * 2))) {
log_error("VDO logical size is by " FMTu64 "KiB bigger then limit " FMTu64 "TiB.",
(vdo_size - (DM_VDO_LOGICAL_SIZE_MAXIMUM_MB * UINT64_C(1024 * 2))) / 2,
DM_VDO_LOGICAL_SIZE_MAXIMUM_MB / UINT64_C(1024) / UINT64_C(1024));
valid = false;
}

View File

@ -1,24 +0,0 @@
# Common problems
## Duplicate PVs in the system
LVM tries to detect the common sources of duplicates, mdadm RAID and multipath,
there are cases where duplicate PV appears on the system.
There are two solutions to this problem:
* Setting a *global_filter* configuration option.
* Using of *devices_file* (See [lvmdevices(8)](https://man7.org/linux/man-pages/man8/lvmdevices.8.html))
## Device Filtering
*filter* and *global_filter* are meant to be used in two ways:
* as an allow list, listing patterns for devices which will be accepted
* `a|/dev/sdX|`, and rejecting the rest `r|.*|`,
* as a reject list, listing only patterns for devices which will be rejected
* `r|/dev/sdX|`,
Even though there are situations where it works, mixing reject and accept
patterns is not recommended.

View File

@ -1,34 +0,0 @@
LVM2 Wiki Documentation
=======================
If you are looking for information about LVM2 visit the [[Index]] page,
There are only some notes about writing stuff under *./doc* here:
* If possible use [[MarkDown]] for formatting, use *.md* (or *.mdwn*) suffix.
* For linking between files, use [[IkiWiki]] syntax `[[FileName]]` or
`[[FileName#Anchor]]`, or `[[link text|FileName]]`
Markdown
--------
* Use `<!-- comment -->` to keep notes, which will not be rendered.
* Use `[[TODO]]` for anything what needs attention. This will be accessible
through the linked [[TODO]] page.
IkiWiki
-------
* Install ikiwiki:
yum install ikiwiki
* To generate the content, run following in the LVM2 top directory:
ikiwiki --setup ikiwiki.setup
Internal Stuff:
---------------
* [[TODO]] Can we have a section which is hidden by default? Like this one?
* [[TODO]] Add basic IkiWiki and MarkDown How To.

View File

@ -1,152 +0,0 @@
# LVM - Logical Volume Manager for Linux
<!--
* TODO: Add banner for Important News: Critical Bugs, Important Announcements,...
-->
<!--
* TODO: Add a feed for latest articles/release-notes on the right
-->
<!--
## About LVM2
-->
LVM aka LVM2 refers to the userspace toolset that provide logical volume
management facilities on linux.
<!--
It is reasonably backwards-compatible with the
original LVM1 toolset.
* TODO: Add information about LVM1 metadata format conversion!
-->
LVM offers more flexibility than using partitions, allowing one to
* grow and, where supported by filesystem, shrink volumes,
* create snapshots of existing volumes,
* mirror data on multiple disks including RAID levels 5 or 6,
* striping data on multiple disks,
* create a read or write cache.
To use LVM2 you need 3 things:
* [device-mapper](https://sourceware.org/dm/) in your kernel (upstream since long ago)
* the userspace device-mapper support library (*libdevmapper*) (part of lvm2)
* and the userspace LVM2 tools.
## Getting LVM
Most of linux distribution offer packaged LVM tools.
Depending on your distribution use
# RPM based distributions (Fedora):
yum install lvm2
# DEB based distributions (Debian, Ubuntu):
apt-get install lvm2
Tarballs of the userspace LVM2 source code releases are available from [sourceware.org](https://sourceware.org/pub/lvm2/) [ftp](ftp://sourceware.org/pub/lvm2/).
List of official [mirror sites](https://sourceware.org/mirrors.html) (including http and rsync protocols).
### LVM Releases
[[!inline pages="release-notes/2.03.* and !*/template and !*/Discussion and !tagged(draft) and !tagged(pending)" limit=2 rootpage="release-notes"]]
[[More releases|release-notes/index]]
## Getting Started
<!--
TODO: We are missing a lvm(7) man page explaining this, I think it would be a nic addition!
And perhaps so would be a lvmtroubleshooting(7) guide.
-->
Word of warning first! Even though LVM errs on the side of data safety it is a
tool with low level access and one may seriously harm their data when used
incorrectly!
* Physical Volume (PV) is underlying disk, local or remote, encrypted or even
a mdadm RAID volume. PV is divided into so called Physical Extents (PE) which
are a basic allocation unit.
List PVs using [pvs(8)](https://man7.org/linux/man-pages/man8/pvs.8.html) or
[pvdisplay(8)](https://man7.org/linux/man-pages/man8/pvdisplay.8.html).
Make one by running `pvcreate /dev/sdX`.
See [pvcreate(8)](https://man7.org/linux/man-pages/man8/pvcreate.8.html). This step is optional.
* Volume Group (VG) consisting of one or more PVs is used as a pool from which LVs are allocated.
List VGs using [vgs(8)](https://man7.org/linux/man-pages/man8/vgs.8.html) or
[vgdisplay(8)](https://man7.org/linux/man-pages/man8/vgdisplay.8.html).
Make one by running `vgcreate VGNAME /dev/sdX...`, add PVs to existing one by `vgextend VGNAME /dev/sdX`.
To use LVM at least one Volume Group must be present on the system.
See [vgcreate(8)](https://man7.org/linux/man-pages/man8/vgcreate.8.html), and
[vgextend(8)](https://man7.org/linux/man-pages/man8/vgextend.8.html).
* Logical Volume (LV) is the block device usually visible to user to be used for file system.
List PVs using [lvs(8)](https://man7.org/linux/man-pages/man8/lvs.8.html) or
[lvdisplay(8)](https://man7.org/linux/man-pages/man8/lvdisplay.8.html).
Make one by running `lvcreate [-n LVNAME] -L SIZE VGNAME`, and you are done!
See [vgcreate(8)](https://man7.org/linux/man-pages/man8/vgcreate.8.html).
## Avoiding Problems
Good start is to avoid using `{--force|-f}` and `{--yes|-y}` options which are
often seen on internet discussions.
there is a possibility of data loss, LVM tools usually ask, so read the prompts
carefully! Using `--yes` removes these safety.
Also in some cases where it is too dangerous to proceed, e.g. device is used,
LVM refuses to do so, which can be overridden by `--force`.
Second, when resizing and especially when shrinking LVs it is always a good
idea to use `--resizefs` option which ensures the devices are resized in
correct order.
Third, if you still make a mess, never ever run fsck on damaged LV/FS, this is
usually the final blow to your data. It is always better to ask first!
## Documentation
## Resolving Problems
* Backup if possible!
* Search the problem first, check the list of [[common problems|Problems]]
* Never run `fsck` on damaged LV, LV must be recovered first!
* When asking for help describe exactly how the system got corrupted. It really
does not help trying to cover one's mistakes in such situation, it takes
longer to get help and also you are likely to get wrong answer making repair
impossible.
## Reporting Bugs
* When you find a problem there is often something specific about your system.
If the problem is reproducible run the failing command(s) with verbose flag
`-vvvv` which gives developers clue where the problem might be.
There is a [lvmdump(8)](https://man7.org/linux/man-pages/man8/lvmdump.8.html)
tool to help collect data about your system, block devices and LVM setup.
* Please report upstream bugs or request features in [Red Hat Bugzilla](https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper)
<!--
TODO:
* Add links to other documentation
* Add links to git
* Add links to mailing lists
* Resolving problems
* Backup if possible!
* Newer run fsck! Do the research first!
* List of Common issues
* Resizing in wrong order
* Thin pool running out of space
* Configuration - duplicates
* Mailing list
* IRC?
* Reporting Bugs
* sosreport/lvmdump
* BZ
* Contributing
* gitlab MR
* Add latest articles
-->

View File

@ -67,7 +67,7 @@ the entries (each hotspot block covers a larger area than a single
cache block).
All this means smq uses ~25bytes per cache block. Still a lot of
memory, but a substantial improvement nonetheless.
memory, but a substantial improvement nontheless.
Level balancing:
mq placed entries in different levels of the multiqueue structures

View File

@ -35,7 +35,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
capi:authenc(hmac(sha256),xts(aes))-random
capi:rfc7539(chacha20,poly1305)-random
The /proc/crypto contains a list of currently loaded crypto modes.
The /proc/crypto contains a list of curently loaded crypto modes.
<key>
Key used for encryption. It is encoded either as a hexadecimal number
@ -81,7 +81,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
<#opt_params>
Number of optional parameters. If there are no optional parameters,
the optional parameters section can be skipped or #opt_params can be zero.
the optional paramaters section can be skipped or #opt_params can be zero.
Otherwise #opt_params is the number of following arguments.
Example of optional parameters section:

View File

@ -120,7 +120,7 @@ journal_crypt:algorithm(:key) (the key is optional)
"salsa20", "ctr(aes)" or "ecb(arc4)").
The journal contains history of last writes to the block device,
an attacker reading the journal could see the last sector numbers
an attacker reading the journal could see the last sector nubmers
that were written. From the sector numbers, the attacker can infer
the size of files that were written. To protect against this
situation, you can encrypt the journal.

View File

@ -65,7 +65,7 @@ Construction Parameters
<#opt_params>
Number of optional parameters. If there are no optional parameters,
the optional parameters section can be skipped or #opt_params can be zero.
the optional paramaters section can be skipped or #opt_params can be zero.
Otherwise #opt_params is the number of following arguments.
Example of optional parameters section:

View File

@ -1,4 +0,0 @@
.page {
max-width: 1280px;
margin: auto;
}

View File

@ -37,7 +37,7 @@ segment type. The available RAID types are:
"raid6_nr" - RAID6 Rotating parity N with data restart
"raid6_nc" - RAID6 Rotating parity N with data continuation
The exception to 'no shorthand options' will be where the RAID implementations
can displace traditional targets. This is the case with 'mirror' and 'raid1'.
can displace traditional tagets. This is the case with 'mirror' and 'raid1'.
In this case, "mirror_segtype_default" - found under the "global" section in
lvm.conf - can be set to "mirror" or "raid1". The segment type inferred when
the '-m' option is used will be taken from this setting. The default segment
@ -104,7 +104,7 @@ and 4 devices for RAID 6/10.
lvconvert should work exactly as it does now when dealing with mirrors -
even if(when) we switch to MD RAID1. Of course, there are no plans to
allow the presence of the metadata area to be configurable (e.g. --corelog).
allow the presense of the metadata area to be configurable (e.g. --corelog).
It will be simple enough to detect if the LV being up/down-converted is
new or old-style mirroring.
@ -120,7 +120,7 @@ RAID4 to RAID5 or RAID5 to RAID6.
Line 02/03/04:
These are familiar options - all of which would now be available as options
for change. (However, it'd be nice if we didn't have regionsize in there.
It's simple on the kernel side, but is just an extra - often unnecessary -
It's simple on the kernel side, but is just an extra - often unecessary -
parameter to many functions in the LVM codebase.)
Line 05:
@ -375,8 +375,8 @@ the slot. Even the names of the images will be renamed to properly reflect
their index in the array. Unlike the "mirror" segment type, you will never have
an image named "*_rimage_1" occupying the index position 0.
As with adding images, removing images holds off on committing LVM metadata
until all possible changes have been made. This reduces the likelihood of bad
As with adding images, removing images holds off on commiting LVM metadata
until all possible changes have been made. This reduces the likelyhood of bad
intermediate stages being left due to a failure of operation or machine crash.
RAID1 '--splitmirrors', '--trackchanges', and '--merge' operations

View File

@ -87,7 +87,7 @@ are as follows:
/etc/lvm/lvm.conf. Once this operation is complete, the logical volumes
will be consistent. However, the volume group will still be inconsistent -
due to the refernced-but-missing device/PV - and operations will still be
restricted to the aforementioned actions until either the device is
restricted to the aformentioned actions until either the device is
restored or 'vgreduce --removemissing' is run.
Device Revival (transient failures):
@ -135,9 +135,9 @@ If a mirror is not 'in-sync', a read failure will produce an I/O error.
This error will propagate all the way up to the applications above the
logical volume (e.g. the file system). No automatic intervention will
take place in this case either. It is up to the user to decide what
can be done/salvaged in this scenario. If the user is confident that the
can be done/salvaged in this senario. If the user is confident that the
images of the mirror are the same (or they are willing to simply attempt
to retrieve whatever data they can), 'lvconvert' can be used to eliminate
to retreive whatever data they can), 'lvconvert' can be used to eliminate
the failed image and proceed.
Mirror resynchronization errors:
@ -191,11 +191,11 @@ command are set in the LVM configuration file. They are:
3-way mirror fails, the mirror will be converted to a 2-way mirror.
The "allocate" policy takes the further action of trying to replace
the failed image using space that is available in the volume group.
Replacing a failed mirror image will incur the cost of
Replacing a failed mirror image will incure the cost of
resynchronizing - degrading the performance of the mirror. The
default policy for handling an image failure is "remove". This
allows the mirror to still function, but gives the administrator the
choice of when to incur the extra performance costs of replacing
choice of when to incure the extra performance costs of replacing
the failed image.
RAID logical volume device failures are handled differently from the "mirror"

View File

@ -63,7 +63,7 @@ classical snapshot merge, thin snapshot merge.
The second store is suited only for pvmove --abort operations in-progress. Both
stores are independent and identical LVs (pvmove /dev/sda3 and pvmove --abort /dev/sda3)
can be run concurrently from lvmpolld point of view (on lvm2 side the consistency is
can be run concurently from lvmpolld point of view (on lvm2 side the consistency is
guaranteed by lvm2 locking mechanism).
Locking order

View File

@ -51,5 +51,3 @@ In future optional target flags will be given in two situations:
This decision could well be contentious, so could distro maintainers feel
free to comment.
[[!tag legacy]]

View File

@ -1,76 +0,0 @@
<!-- Page title -->
[[!meta title="Version 2.03.24 - Feature and Bug Fix Release"]]
Version 2.03.24
===============
* **Changes in udev rules, new version of systemd is recommended (256).**
* **When using LVs as PVs these are no longer auto activated!**
* Allow creating VDO device for thin data when creating thin pool.
* More devices can be used as external origin for thin snapshot.
* And [[!toggle text="more"]]
[[!toggleable text="""
Features
-----------------------
* Swap properties like hostname, date and time when swapping LVs.
* Allow thin snapshot taken of thin volume from another pool as external origin.
* Allow chaining of external origins.
### Changes to device handling
* **IMPORTANT:** When `devices/scan_lvs` is enabled found LVs are no longer auto
activated, must enable `LVM_PVSCAN_ON_LVS` in udev rules (*69-dm-lvm.rules*.)
* NOTE: It is not recommended to use LVs for PVs. If you have an use case for
this talk to us, please.
* Changes to devices file are now backed up in */etc/lvm/devices/backup/*.
Controlled by `devices/devicesfile_backup_limit` configuration option.
* When `devices/use_devicesfile` is set to `0` existing file is renamed to
*system.devices-unused.YYYYMMDD.HHMMSS* to prevent outdated file to be used
on reenabling.
### Use VDO device for thin pool's data
New option `--pooldatavdo` during lvcreate or lvconvert allows using VDO as backing device.
More options (`--compression {y|n}`, `--deduplication {y|n}`,
`--vdosettings STRING`) to control the options are supported by these commands.
Example of converting a *lvol1* to a thin pool with enabled compression and deduplication:
lvconvert --type thin-pool --pooldatavdo y vg/lvol1
Changes in command line
-----------------------
* Add *--wipesignature* option controlling signature wiping when converting volume to thin-pool.
* Allow *lvcreate --snapshot* without *{-T|--thin}* option when creating snapshot of a thin volume.
* Allow *--raidintegrity{,mode,blocksize}* options with implicit RAID1 (i.e. when *-m1* is used on command line)
./configure options
-------------------
These changes are for packagers:
* Add `--with-default-event-activation` option controlling default for
`global/event_activation`. Default value is unchanged. Useful when creating
builds for testing.
* Add `--with-modulesdir` option.
Changes in udev rules
---------------------
**IMPORTANT:** Rework of udev rules in cooperation with systemd is included in this release.
* `DM_SUSPENDED` and `DM_NOSCAN` are now entirely internal for DM and cannot be used outside of DM rules.
* Upper level rules should consume `DM_UDEV_DISABLE_OTHER_RULES_FLAG` rather than `DM_NOSCAN` and `DM_SUSPENDED`.
Also few more minor improvements:
* Better handling of `DISK_RO` events and suspended devices
"""]]
[[!tag]]
[[!meta date="Thu May 16 12:12:06 2024 +0200"]]

View File

@ -1,19 +0,0 @@
<!-- Page title -->
[[!meta title="Version 2.03.25 - Feature and Bug Fix Release"]]
Version 2.03.25
===============
* Add `vgimportdevices --rootvg [--auto]` adding devices from root VG to devices file.
* Add `lvm-devices-import.{path,service}` service using the above to initialize devices file.
* Handle pruning ids from devices file when lvremove is called and a PV is on top of the LV.
* Change device cache data structures and caching to speed up operations with many LVs.
* Fix infinite loop in lvm shell completion causing out of memory issue (2.03.24).
* Allow forced change of locktype from none.
* Handle OPTIONS defined in /etc/sysconfig/lvmlockd.
* And as usually some clean up, static analysis fixes, etc.
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
[[!tag]]
[[!meta date="Fri Jul 12 12:49:07 2024 +0200"]]

View File

@ -1,18 +0,0 @@
<!-- Page title -->
[[!meta title="Version 2.03.26 - Feature and Bug Fix Release"]]
Version 2.03.26
===============
* Add `--integritysettings` option to manipulate dm-integrity settings.
* Add `--refresh` with `vgscan --mknodes`.
* Improve documentation for `--refresh` option.
* Use `log/report_command_log=1` config setting by default for JSON output format.
* Fix `vgmknodes --refresh` to wait for udev before checking `/dev` content.
* Fix internal error reported by pvmove on a VG with single PV.
* Fix unreleased memory pools on RAID lvextend.
* And as usually some clean up, static analysis fixes, etc.
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
[[!tag]]
[[!meta date="Fri Aug 23 16:02:00 2024 +0200"]]

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