mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-11 20:24:07 +03:00
Compare commits
3 Commits
dev-dct-de
...
dev-dct-lv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e1e61bfd6 | ||
|
|
c2b31ee8d5 | ||
|
|
7bcd93321d |
26
.gitignore
vendored
26
.gitignore
vendored
@@ -14,14 +14,8 @@
|
|||||||
*.so
|
*.so
|
||||||
*.so.*
|
*.so.*
|
||||||
*.sw*
|
*.sw*
|
||||||
*.su
|
|
||||||
*.patch
|
|
||||||
*~
|
*~
|
||||||
|
|
||||||
# gcov files:
|
|
||||||
*.gcda
|
|
||||||
*.gcno
|
|
||||||
|
|
||||||
.export.sym
|
.export.sym
|
||||||
.exported_symbols_generated
|
.exported_symbols_generated
|
||||||
.gdb_history
|
.gdb_history
|
||||||
@@ -45,13 +39,12 @@ make.tmpl
|
|||||||
|
|
||||||
coverity/coverity_model.xml
|
coverity/coverity_model.xml
|
||||||
|
|
||||||
/libdm/.symver_check
|
# gcov files:
|
||||||
|
*.gcda
|
||||||
daemons/clvmd
|
*.gcno
|
||||||
daemons/dmfilemapd
|
|
||||||
daemons/lvmetad/
|
|
||||||
|
|
||||||
tools/man-generator
|
tools/man-generator
|
||||||
|
tools/man-generator.c
|
||||||
|
|
||||||
test/.lib-dir-stamp
|
test/.lib-dir-stamp
|
||||||
test/.tests-stamp
|
test/.tests-stamp
|
||||||
@@ -109,8 +102,6 @@ test/api/thin_percent.t
|
|||||||
test/api/vglist.t
|
test/api/vglist.t
|
||||||
test/api/vgtest.t
|
test/api/vgtest.t
|
||||||
test/lib/aux
|
test/lib/aux
|
||||||
test/lib/cache-mq.profile
|
|
||||||
test/lib/cache-smq.profile
|
|
||||||
test/lib/check
|
test/lib/check
|
||||||
test/lib/clvmd
|
test/lib/clvmd
|
||||||
test/lib/dm-version-expected
|
test/lib/dm-version-expected
|
||||||
@@ -120,7 +111,6 @@ test/lib/dmstats
|
|||||||
test/lib/fail
|
test/lib/fail
|
||||||
test/lib/flavour-ndev-cluster
|
test/lib/flavour-ndev-cluster
|
||||||
test/lib/flavour-ndev-cluster-lvmpolld
|
test/lib/flavour-ndev-cluster-lvmpolld
|
||||||
test/lib/flavour-ndev-devicesfile
|
|
||||||
test/lib/flavour-ndev-lvmetad
|
test/lib/flavour-ndev-lvmetad
|
||||||
test/lib/flavour-ndev-lvmetad-lvmpolld
|
test/lib/flavour-ndev-lvmetad-lvmpolld
|
||||||
test/lib/flavour-ndev-lvmpolld
|
test/lib/flavour-ndev-lvmpolld
|
||||||
@@ -130,7 +120,6 @@ test/lib/flavour-udev-cluster-lvmpolld
|
|||||||
test/lib/flavour-udev-lvmetad
|
test/lib/flavour-udev-lvmetad
|
||||||
test/lib/flavour-udev-lvmetad-lvmpolld
|
test/lib/flavour-udev-lvmetad-lvmpolld
|
||||||
test/lib/flavour-udev-lvmlockd-dlm
|
test/lib/flavour-udev-lvmlockd-dlm
|
||||||
test/lib/flavour-udev-lvmlockd-idm
|
|
||||||
test/lib/flavour-udev-lvmlockd-sanlock
|
test/lib/flavour-udev-lvmlockd-sanlock
|
||||||
test/lib/flavour-udev-lvmlockd-test
|
test/lib/flavour-udev-lvmlockd-test
|
||||||
test/lib/flavour-udev-lvmpolld
|
test/lib/flavour-udev-lvmpolld
|
||||||
@@ -143,13 +132,8 @@ test/lib/lvm
|
|||||||
test/lib/lvm-wrapper
|
test/lib/lvm-wrapper
|
||||||
test/lib/lvmchange
|
test/lib/lvmchange
|
||||||
test/lib/lvmdbusd.profile
|
test/lib/lvmdbusd.profile
|
||||||
test/lib/lvmdevices
|
|
||||||
test/lib/lvmetad
|
test/lib/lvmetad
|
||||||
test/lib/lvmlockctl
|
|
||||||
test/lib/lvmlockd
|
|
||||||
test/lib/lvmpolld
|
test/lib/lvmpolld
|
||||||
test/lib/lvm_import_vdo
|
|
||||||
test/lib/lvm_vdo_wrapper
|
|
||||||
test/lib/not
|
test/lib/not
|
||||||
test/lib/paths
|
test/lib/paths
|
||||||
test/lib/paths-common
|
test/lib/paths-common
|
||||||
@@ -159,7 +143,5 @@ test/lib/test
|
|||||||
test/lib/thin-performance.profile
|
test/lib/thin-performance.profile
|
||||||
test/lib/utils
|
test/lib/utils
|
||||||
test/lib/version-expected
|
test/lib/version-expected
|
||||||
test/lib/vgimportdevices
|
|
||||||
|
|
||||||
test/unit/dmraid_t.c
|
test/unit/dmraid_t.c
|
||||||
test/unit/unit-test
|
test/unit/unit-test
|
||||||
|
|||||||
104
.gitlab-ci.yml
104
.gitlab-ci.yml
@@ -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
|
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ ifeq ($(MAKECMDGOALS),distclean)
|
|||||||
udev po
|
udev po
|
||||||
tools.distclean: test.distclean
|
tools.distclean: test.distclean
|
||||||
endif
|
endif
|
||||||
DISTCLEAN_DIRS += lcov_reports* autom4te.cache
|
DISTCLEAN_DIRS += lcov_reports*
|
||||||
DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
|
DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
|
||||||
|
|
||||||
include make.tmpl
|
include make.tmpl
|
||||||
@@ -47,7 +47,7 @@ include $(top_srcdir)/base/Makefile
|
|||||||
include $(top_srcdir)/device_mapper/Makefile
|
include $(top_srcdir)/device_mapper/Makefile
|
||||||
include $(top_srcdir)/test/unit/Makefile
|
include $(top_srcdir)/test/unit/Makefile
|
||||||
|
|
||||||
lib: include libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
|
lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
|
||||||
daemons: lib libdaemon tools
|
daemons: lib libdaemon tools
|
||||||
scripts: lib
|
scripts: lib
|
||||||
tools: lib libdaemon
|
tools: lib libdaemon
|
||||||
@@ -55,7 +55,7 @@ po: tools daemons
|
|||||||
man: tools
|
man: tools
|
||||||
all_man: tools
|
all_man: tools
|
||||||
test: tools daemons
|
test: tools daemons
|
||||||
unit-test run-unit-test: test libdm
|
unit-test run-unit-test: test
|
||||||
|
|
||||||
daemons.device-mapper: libdm.device-mapper
|
daemons.device-mapper: libdm.device-mapper
|
||||||
tools.device-mapper: libdm.device-mapper
|
tools.device-mapper: libdm.device-mapper
|
||||||
@@ -127,7 +127,6 @@ all_man:
|
|||||||
|
|
||||||
install_system_dirs:
|
install_system_dirs:
|
||||||
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
|
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
|
||||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)/devices
|
|
||||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
|
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
|
||||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_BACKUP_DIR)
|
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_BACKUP_DIR)
|
||||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_CACHE_DIR)
|
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_CACHE_DIR)
|
||||||
@@ -172,7 +171,6 @@ help:
|
|||||||
@echo " lcov-dated Generate lcov with timedate suffix."
|
@echo " lcov-dated Generate lcov with timedate suffix."
|
||||||
@echo " lcov-reset Reset lcov counters"
|
@echo " lcov-reset Reset lcov counters"
|
||||||
@echo " man Build man pages."
|
@echo " man Build man pages."
|
||||||
@echo " print-VARIABLE Resolve make variable."
|
|
||||||
@echo " rpm Build rpm."
|
@echo " rpm Build rpm."
|
||||||
@echo " run-unit-test Run unit tests."
|
@echo " run-unit-test Run unit tests."
|
||||||
@echo " tags Generate c/etags."
|
@echo " tags Generate c/etags."
|
||||||
|
|||||||
29
README
29
README
@@ -1,5 +1,7 @@
|
|||||||
This tree contains the LVM2 and device-mapper tools and libraries.
|
This tree contains the LVM2 and device-mapper tools and libraries.
|
||||||
|
|
||||||
|
This is development branch, for stable 2.02 release see stable-2.02 branch.
|
||||||
|
|
||||||
For more information about LVM2 read the changelog in the WHATS_NEW file.
|
For more information about LVM2 read the changelog in the WHATS_NEW file.
|
||||||
Installation instructions are in INSTALL.
|
Installation instructions are in INSTALL.
|
||||||
|
|
||||||
@@ -10,30 +12,20 @@ Tarballs are available from:
|
|||||||
https://github.com/lvmteam/lvm2/releases
|
https://github.com/lvmteam/lvm2/releases
|
||||||
|
|
||||||
The source code is stored in git:
|
The source code is stored in git:
|
||||||
https://gitlab.com/lvmteam/lvm2
|
https://sourceware.org/git/?p=lvm2.git
|
||||||
Clone:
|
git clone git://sourceware.org/git/lvm2.git
|
||||||
git clone git@gitlab.com:lvmteam/lvm2.git
|
mirrored to:
|
||||||
Anonymous access:
|
https://github.com/lvmteam/lvm2
|
||||||
git clone https://gitlab.com/lvmteam/lvm2.git
|
|
||||||
Mirrored to:
|
|
||||||
* https://github.com/lvmteam/lvm2
|
|
||||||
git clone https://github.com/lvmteam/lvm2.git
|
git clone https://github.com/lvmteam/lvm2.git
|
||||||
git clone git@github.com:lvmteam/lvm2.git
|
git clone git@github.com:lvmteam/lvm2.git
|
||||||
* https://sourceware.org/git/?p=lvm2.git
|
|
||||||
git clone https://sourceware.org/git/lvm2.git
|
|
||||||
git clone git://sourceware.org/git/lvm2.git
|
|
||||||
|
|
||||||
Mailing list for general discussion related to LVM2:
|
Mailing list for general discussion related to LVM2:
|
||||||
linux-lvm@lists.linux.dev
|
linux-lvm@redhat.com
|
||||||
Subscribe via email to: linux-lvm+subscribe@lists.linux.dev
|
Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm
|
||||||
Archive https://lore.kernel.org/linux-lvm/
|
|
||||||
Older archive https://listman.redhat.com/archives/linux-lvm/
|
|
||||||
|
|
||||||
Mailing lists for LVM2 development, patches and commits:
|
Mailing lists for LVM2 development, patches and commits:
|
||||||
lvm-devel@lists.linux.dev
|
lvm-devel@redhat.com
|
||||||
Subscribe via email to: lvm-devel+subscribe@lists.linux.dev
|
Subscribe from https://www.redhat.com/mailman/listinfo/lvm-devel
|
||||||
Archive https://lore.kernel.org/lvm-devel/
|
|
||||||
Older archive https://listman.redhat.com/archives/lvm-devel/
|
|
||||||
|
|
||||||
lvm2-commits@lists.fedorahosted.org (Read-only archive of commits)
|
lvm2-commits@lists.fedorahosted.org (Read-only archive of commits)
|
||||||
Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits
|
Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits
|
||||||
@@ -49,7 +41,6 @@ Website:
|
|||||||
Report upstream bugs at:
|
Report upstream bugs at:
|
||||||
https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper
|
https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper
|
||||||
or open issues at:
|
or open issues at:
|
||||||
https://gitlab.com/groups/lvmteam/-/issues
|
|
||||||
https://github.com/lvmteam/lvm2/issues
|
https://github.com/lvmteam/lvm2/issues
|
||||||
|
|
||||||
The source code repository used until 7th June 2012 is accessible using CVS:
|
The source code repository used until 7th June 2012 is accessible using CVS:
|
||||||
|
|||||||
7
TESTING
7
TESTING
@@ -21,15 +21,10 @@ You MUST disable (or mask) any LVM daemons:
|
|||||||
- clvmd
|
- clvmd
|
||||||
- cmirrord
|
- cmirrord
|
||||||
|
|
||||||
Some lvm.conf options should be set:
|
|
||||||
|
|
||||||
- global/event_activation = 0
|
|
||||||
- activation/monitoring = 0
|
|
||||||
|
|
||||||
For running cluster tests, we are using singlenode locking. Pass
|
For running cluster tests, we are using singlenode locking. Pass
|
||||||
`--with-clvmd=singlenode` to configure.
|
`--with-clvmd=singlenode` to configure.
|
||||||
|
|
||||||
NOTE: This is useful only for testing, and should not be used in production
|
NOTE: This is useful only for testing, and should not be used in produciton
|
||||||
code.
|
code.
|
||||||
|
|
||||||
To run D-Bus daemon tests, existing D-Bus session is required.
|
To run D-Bus daemon tests, existing D-Bus session is required.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.02.199-git (2024-05-16)
|
1.02.187-git (2022-05-18)
|
||||||
|
|||||||
144
WHATS_NEW
144
WHATS_NEW
@@ -1,145 +1,11 @@
|
|||||||
Version 2.03.25 -
|
Version 2.03.17 -
|
||||||
==================
|
|
||||||
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.
|
Extend VDO and VDOPOOL without flushing and locking fs.
|
||||||
Add --valuesonly option to lvmconfig to print only values without keys.
|
Add --valuesonly option to lvmconfig to print only values without keys.
|
||||||
Updates configure with recent autoconf tooling.
|
Updates configure with recent autoconf tooling.
|
||||||
Fix lvconvert --test --type vdo-pool execution.
|
Fix lvconvert --test --type vdo-pool execution.
|
||||||
Add json_std output format for more JSON standard compliant version of output.
|
Add json_std output format for more JSON standard compliant version of output.
|
||||||
Fix vdo_slab_size_mb value for converted VDO volume.
|
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
|
Version 2.03.16 - 18th May 2022
|
||||||
===============================
|
===============================
|
||||||
@@ -239,7 +105,7 @@ Version 2.03.12 - 07th May 2021
|
|||||||
Fix IMSM MD RAID detection on 4k devices.
|
Fix IMSM MD RAID detection on 4k devices.
|
||||||
Check for presence of VDO target before starting any conversion.
|
Check for presence of VDO target before starting any conversion.
|
||||||
Support metatadata profiles with volume VDO pool conversions.
|
Support metatadata profiles with volume VDO pool conversions.
|
||||||
Support -Zn for conversion of already formatted VDO pools.
|
Support -Zn for conversion of already formated VDO pools.
|
||||||
Avoid removing LVs on error path of lvconvert during creation volumes.
|
Avoid removing LVs on error path of lvconvert during creation volumes.
|
||||||
Fix crashing lvdisplay when thin volume was waiting for merge.
|
Fix crashing lvdisplay when thin volume was waiting for merge.
|
||||||
Support option --errorwhenfull when converting volume to thin-pool.
|
Support option --errorwhenfull when converting volume to thin-pool.
|
||||||
@@ -312,7 +178,7 @@ Version 2.03.10 - 09th August 2020
|
|||||||
|
|
||||||
Version 2.03.09 - 26th March 2020
|
Version 2.03.09 - 26th March 2020
|
||||||
=================================
|
=================================
|
||||||
Fix formatting of vdopool (vdo_slab_size_mb was smaller by 2 bits).
|
Fix formating of vdopool (vdo_slab_size_mb was smaller by 2 bits).
|
||||||
Fix showing of a dm kernel error when uncaching a volume with cachevol.
|
Fix showing of a dm kernel error when uncaching a volume with cachevol.
|
||||||
|
|
||||||
Version 2.03.08 - 11th February 2020
|
Version 2.03.08 - 11th February 2020
|
||||||
@@ -3325,7 +3191,7 @@ Version 2.02.68 - 23rd June 2010
|
|||||||
Add device name and offset to raw_read_mda_header error messages.
|
Add device name and offset to raw_read_mda_header error messages.
|
||||||
Honour log argument when down-converting stacked mirror.
|
Honour log argument when down-converting stacked mirror.
|
||||||
Sleep to workaround clvmd -S race: socket closed early and server drops cmd.
|
Sleep to workaround clvmd -S race: socket closed early and server drops cmd.
|
||||||
Use early udev synchronization and update of dev nodes for clustered mirrors.
|
Use early udev synchronisation and update of dev nodes for clustered mirrors.
|
||||||
Remove incorrect inclusion of kdev_t.h from cmirrord/functions.h.
|
Remove incorrect inclusion of kdev_t.h from cmirrord/functions.h.
|
||||||
Add man pages for lvmconf and non-existent lvmsadc and lvmsar tools.
|
Add man pages for lvmconf and non-existent lvmsadc and lvmsar tools.
|
||||||
Exit successfully when using -o help (but not -o +help) with LVM reports.
|
Exit successfully when using -o help (but not -o +help) with LVM reports.
|
||||||
@@ -5459,5 +5325,3 @@ Display output. Some metadata information cannot yet be displayed.
|
|||||||
|
|
||||||
Recovery tools to salvage "lost" metadata directly from the disks:
|
Recovery tools to salvage "lost" metadata directly from the disks:
|
||||||
but we hope the new format will mean such tools are hardly ever needed!
|
but we hope the new format will mean such tools are hardly ever needed!
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
56
WHATS_NEW_DM
56
WHATS_NEW_DM
@@ -1,55 +1,5 @@
|
|||||||
Version 1.02.199 -
|
Version 1.02.187 -
|
||||||
===================
|
|
||||||
|
|
||||||
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.
|
Add DM_REPORT_GROUP_JSON_STD for more JSON standard compliant output format.
|
||||||
|
|
||||||
Version 1.02.185 - 18th May 2022
|
Version 1.02.185 - 18th May 2022
|
||||||
@@ -1153,7 +1103,7 @@ Version 1.02.37 - 15th September 2009
|
|||||||
Version 1.02.36 - 6th August 2009
|
Version 1.02.36 - 6th August 2009
|
||||||
=================================
|
=================================
|
||||||
Add udevcookies, udevcomplete, udevcomplete_all and --noudevwait to dmsetup.
|
Add udevcookies, udevcomplete, udevcomplete_all and --noudevwait to dmsetup.
|
||||||
Add libdevmapper functions to support synchronization with udev.
|
Add libdevmapper functions to support synchronisation with udev.
|
||||||
|
|
||||||
Version 1.02.35 - 28th July 2009
|
Version 1.02.35 - 28th July 2009
|
||||||
================================
|
================================
|
||||||
@@ -1556,5 +1506,3 @@ Version 1.00.08 - 27 Feb 2004
|
|||||||
Fixed DESTDIR for make install/install_static_lib.
|
Fixed DESTDIR for make install/install_static_lib.
|
||||||
Updated README/INSTALL to reflect move to sources.redhat.com.
|
Updated README/INSTALL to reflect move to sources.redhat.com.
|
||||||
Updated autoconf files to 2003-06-17.
|
Updated autoconf files to 2003-06-17.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
18
acinclude.m4
18
acinclude.m4
@@ -62,24 +62,6 @@ AC_DEFUN([AC_TRY_LDFLAGS],
|
|||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
|
||||||
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
|
||||||
dnl -------------------------------------------
|
|
||||||
dnl Since: 0.28
|
|
||||||
dnl
|
|
||||||
dnl Retrieves the value of the pkg-config variable for the given module.
|
|
||||||
AC_DEFUN([PKG_CHECK_VAR],
|
|
||||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
|
||||||
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
|
|
||||||
|
|
||||||
_PKG_CONFIG([$1], [variable="][$3]["], [$2])
|
|
||||||
AS_VAR_COPY([$1], [pkg_cv_][$1])
|
|
||||||
|
|
||||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
|
||||||
])dnl PKG_CHECK_VAR
|
|
||||||
|
|
||||||
|
|
||||||
# ===========================================================================
|
# ===========================================================================
|
||||||
# http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html
|
# http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html
|
||||||
# ===========================================================================
|
# ===========================================================================
|
||||||
|
|||||||
10
aclocal.m4
vendored
10
aclocal.m4
vendored
@@ -69,8 +69,8 @@ AC_DEFUN([AX_PYTHON_MODULE],[
|
|||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*-
|
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||||
# serial 12 (pkg-config-0.29.2)
|
# serial 11 (pkg-config-0.29.1)
|
||||||
|
|
||||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
||||||
@@ -112,7 +112,7 @@ dnl
|
|||||||
dnl See the "Since" comment for each macro you use to see what version
|
dnl See the "Since" comment for each macro you use to see what version
|
||||||
dnl of the macros you require.
|
dnl of the macros you require.
|
||||||
m4_defun([PKG_PREREQ],
|
m4_defun([PKG_PREREQ],
|
||||||
[m4_define([PKG_MACROS_VERSION], [0.29.2])
|
[m4_define([PKG_MACROS_VERSION], [0.29.1])
|
||||||
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
|
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
|
||||||
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
|
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
|
||||||
])dnl PKG_PREREQ
|
])dnl PKG_PREREQ
|
||||||
@@ -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 PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||||
dnl
|
dnl
|
||||||
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||||
dnl only at the first occurrence in configure.ac, so if the first place
|
dnl only at the first occurence in configure.ac, so if the first place
|
||||||
dnl it's called might be skipped (such as if it is within an "if", you
|
dnl it's called might be skipped (such as if it is within an "if", you
|
||||||
dnl have to call PKG_CHECK_EXISTS manually
|
dnl have to call PKG_CHECK_EXISTS manually
|
||||||
AC_DEFUN([PKG_CHECK_EXISTS],
|
AC_DEFUN([PKG_CHECK_EXISTS],
|
||||||
@@ -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
|
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
|
||||||
|
|
||||||
pkg_failed=no
|
pkg_failed=no
|
||||||
AC_MSG_CHECKING([for $2])
|
AC_MSG_CHECKING([for $1])
|
||||||
|
|
||||||
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
||||||
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# py-compile - Compile a Python program
|
# py-compile - Compile a Python program
|
||||||
|
|
||||||
scriptversion=2023-03-30.00; # UTC
|
scriptversion=2011-06-08.12; # UTC
|
||||||
|
|
||||||
# Copyright (C) 2000-2023 Free Software Foundation, Inc.
|
# Copyright (C) 2000-2014 Free Software Foundation, Inc.
|
||||||
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,7 +16,7 @@ scriptversion=2023-03-30.00; # UTC
|
|||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
|
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# As a special exception to the GNU General Public License, if you
|
# As a special exception to the GNU General Public License, if you
|
||||||
# distribute this file as part of a program that contains a
|
# distribute this file as part of a program that contains a
|
||||||
@@ -27,7 +27,7 @@ scriptversion=2023-03-30.00; # UTC
|
|||||||
# bugs to <bug-automake@gnu.org> or send patches to
|
# bugs to <bug-automake@gnu.org> or send patches to
|
||||||
# <automake-patches@gnu.org>.
|
# <automake-patches@gnu.org>.
|
||||||
|
|
||||||
if test -z "$PYTHON"; then
|
if [ -z "$PYTHON" ]; then
|
||||||
PYTHON=python
|
PYTHON=python
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -62,19 +62,13 @@ while test $# -ne 0; do
|
|||||||
;;
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
cat <<\EOF
|
cat <<\EOF
|
||||||
Usage: py-compile [options] FILES...
|
Usage: py-compile [--help] [--version] [--basedir DIR] [--destdir DIR] FILES..."
|
||||||
|
|
||||||
Byte compile some python scripts FILES. Use --destdir to specify any
|
Byte compile some python scripts FILES. Use --destdir to specify any
|
||||||
leading directory path to the FILES that you don't want to include in the
|
leading directory path to the FILES that you don't want to include in the
|
||||||
byte compiled file. Specify --basedir for any additional path information you
|
byte compiled file. Specify --basedir for any additional path information you
|
||||||
do want to be shown in the byte compiled file.
|
do want to be shown in the byte compiled file.
|
||||||
|
|
||||||
Options:
|
|
||||||
--basedir DIR Prefix all FILES with DIR, and include in error messages.
|
|
||||||
--destdir DIR Prefix all FILES with DIR before compiling.
|
|
||||||
-v, --version Display version information.
|
|
||||||
-h, --help This help screen.
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py
|
py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py
|
||||||
|
|
||||||
@@ -100,13 +94,14 @@ EOF
|
|||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
if test $# -eq 0; then
|
files=$*
|
||||||
|
if test -z "$files"; then
|
||||||
usage_error "no files given"
|
usage_error "no files given"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# if basedir was given, then it should be prepended to filenames before
|
# if basedir was given, then it should be prepended to filenames before
|
||||||
# byte compilation.
|
# byte compilation.
|
||||||
if test -z "$basedir"; then
|
if [ -z "$basedir" ]; then
|
||||||
pathtrans="path = file"
|
pathtrans="path = file"
|
||||||
else
|
else
|
||||||
pathtrans="path = os.path.join('$basedir', file)"
|
pathtrans="path = os.path.join('$basedir', file)"
|
||||||
@@ -114,129 +109,62 @@ fi
|
|||||||
|
|
||||||
# if destdir was given, then it needs to be prepended to the filename to
|
# if destdir was given, then it needs to be prepended to the filename to
|
||||||
# byte compile but not go into the compiled file.
|
# byte compile but not go into the compiled file.
|
||||||
if test -z "$destdir"; then
|
if [ -z "$destdir" ]; then
|
||||||
filetrans="filepath = path"
|
filetrans="filepath = path"
|
||||||
else
|
else
|
||||||
filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
|
filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
python_major=`$PYTHON -c 'import sys; print(sys.version_info[0])'`
|
|
||||||
if test -z "$python_major"; then
|
|
||||||
usage_error "could not determine $PYTHON major version"
|
|
||||||
fi
|
|
||||||
|
|
||||||
case $python_major in
|
|
||||||
[01])
|
|
||||||
usage_error "python version 0.x and 1.x not supported"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
python_minor=`$PYTHON -c 'import sys; print(sys.version_info[1])'`
|
|
||||||
|
|
||||||
# NB: When adding support for newer versions, prefer copying & adding new cases
|
|
||||||
# rather than try to keep things merged with shell variables.
|
|
||||||
|
|
||||||
# First byte compile (no optimization) all the modules.
|
|
||||||
# This works for all currently known Python versions.
|
|
||||||
$PYTHON -c "
|
$PYTHON -c "
|
||||||
import sys, os, py_compile
|
import sys, os, py_compile, imp
|
||||||
|
|
||||||
try:
|
files = '''$files'''
|
||||||
import importlib
|
|
||||||
except ImportError:
|
|
||||||
importlib = None
|
|
||||||
|
|
||||||
# importlib.util.cache_from_source was added in 3.4
|
|
||||||
if (
|
|
||||||
hasattr(importlib, 'util')
|
|
||||||
and hasattr(importlib.util, 'cache_from_source')
|
|
||||||
):
|
|
||||||
destpath = importlib.util.cache_from_source
|
|
||||||
else:
|
|
||||||
destpath = lambda filepath: filepath + 'c'
|
|
||||||
|
|
||||||
sys.stdout.write('Byte-compiling python modules...\n')
|
sys.stdout.write('Byte-compiling python modules...\n')
|
||||||
for file in sys.argv[1:]:
|
for file in files.split():
|
||||||
$pathtrans
|
$pathtrans
|
||||||
$filetrans
|
$filetrans
|
||||||
if (
|
if not os.path.exists(filepath) or not (len(filepath) >= 3
|
||||||
not os.path.exists(filepath)
|
and filepath[-3:] == '.py'):
|
||||||
or not (len(filepath) >= 3 and filepath[-3:] == '.py')
|
|
||||||
):
|
|
||||||
continue
|
continue
|
||||||
sys.stdout.write(file + ' ')
|
sys.stdout.write(file)
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
py_compile.compile(filepath, destpath(filepath), path)
|
if hasattr(imp, 'get_tag'):
|
||||||
sys.stdout.write('\n')" "$@" || exit $?
|
py_compile.compile(filepath, imp.cache_from_source(filepath), path)
|
||||||
|
else:
|
||||||
|
py_compile.compile(filepath, filepath + 'c', path)
|
||||||
|
sys.stdout.write('\n')" || exit $?
|
||||||
|
|
||||||
# Then byte compile w/optimization all the modules.
|
# this will fail for python < 1.5, but that doesn't matter ...
|
||||||
$PYTHON -O -c "
|
$PYTHON -O -c "
|
||||||
import sys, os, py_compile
|
import sys, os, py_compile, imp
|
||||||
|
|
||||||
try:
|
# pypy does not use .pyo optimization
|
||||||
import importlib
|
if hasattr(sys, 'pypy_translation_info'):
|
||||||
except ImportError:
|
|
||||||
importlib = None
|
|
||||||
|
|
||||||
# importlib.util.cache_from_source was added in 3.4
|
|
||||||
if (
|
|
||||||
hasattr(importlib, 'util')
|
|
||||||
and hasattr(importlib.util, 'cache_from_source')
|
|
||||||
):
|
|
||||||
destpath = importlib.util.cache_from_source
|
|
||||||
else:
|
|
||||||
destpath = lambda filepath: filepath + 'o'
|
|
||||||
|
|
||||||
# pypy2 does not use .pyo optimization
|
|
||||||
if sys.version_info.major <= 2 and hasattr(sys, 'pypy_translation_info'):
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
files = '''$files'''
|
||||||
sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n')
|
sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n')
|
||||||
for file in sys.argv[1:]:
|
for file in files.split():
|
||||||
$pathtrans
|
$pathtrans
|
||||||
$filetrans
|
$filetrans
|
||||||
if (
|
if not os.path.exists(filepath) or not (len(filepath) >= 3
|
||||||
not os.path.exists(filepath)
|
and filepath[-3:] == '.py'):
|
||||||
or not (len(filepath) >= 3 and filepath[-3:] == '.py')
|
|
||||||
):
|
|
||||||
continue
|
continue
|
||||||
sys.stdout.write(file + ' ')
|
sys.stdout.write(file)
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
py_compile.compile(filepath, destpath(filepath), path)
|
if hasattr(imp, 'get_tag'):
|
||||||
sys.stdout.write('\n')" "$@" 2>/dev/null || exit $?
|
py_compile.compile(filepath, imp.cache_from_source(filepath, False), path)
|
||||||
|
else:
|
||||||
# Then byte compile w/more optimization.
|
py_compile.compile(filepath, filepath + 'o', path)
|
||||||
# Only do this for Python 3.5+, see https://bugs.gnu.org/38043 for background.
|
sys.stdout.write('\n')" 2>/dev/null || :
|
||||||
case $python_major.$python_minor in
|
|
||||||
2.*|3.[0-4])
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
$PYTHON -OO -c "
|
|
||||||
import sys, os, py_compile, importlib
|
|
||||||
|
|
||||||
sys.stdout.write('Byte-compiling python modules (more optimized versions)'
|
|
||||||
' ...\n')
|
|
||||||
for file in sys.argv[1:]:
|
|
||||||
$pathtrans
|
|
||||||
$filetrans
|
|
||||||
if (
|
|
||||||
not os.path.exists(filepath)
|
|
||||||
or not (len(filepath) >= 3 and filepath[-3:] == '.py')
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
sys.stdout.write(file + ' ')
|
|
||||||
sys.stdout.flush()
|
|
||||||
py_compile.compile(filepath, importlib.util.cache_from_source(filepath), path)
|
|
||||||
sys.stdout.write('\n')" "$@" 2>/dev/null || exit $?
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
# mode: shell-script
|
# mode: shell-script
|
||||||
# sh-indentation: 2
|
# sh-indentation: 2
|
||||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||||
# time-stamp-start: "scriptversion="
|
# time-stamp-start: "scriptversion="
|
||||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||||
# time-stamp-time-zone: "UTC0"
|
# time-stamp-time-zone: "UTC"
|
||||||
# time-stamp-end: "; # UTC"
|
# time-stamp-end: "; # UTC"
|
||||||
# End:
|
# End:
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ CLEAN_TARGETS += $(BASE_DEPENDS) $(BASE_OBJECTS) \
|
|||||||
$(BASE_TARGET)
|
$(BASE_TARGET)
|
||||||
|
|
||||||
$(BASE_TARGET): $(BASE_OBJECTS)
|
$(BASE_TARGET): $(BASE_OBJECTS)
|
||||||
$(SHOW) " [AR] $@"
|
@echo " [AR] $@"
|
||||||
$(Q) $(RM) $@
|
$(Q) $(RM) $@
|
||||||
$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null
|
$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null
|
||||||
|
|
||||||
ifeq ("$(USE_TRACKING)","yes")
|
ifeq ("$(DEPENDS)","yes")
|
||||||
-include $(BASE_DEPENDS)
|
-include $(BASE_DEPENDS)
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ struct dm_hash_table {
|
|||||||
static unsigned _hash(const void *key, unsigned len)
|
static unsigned _hash(const void *key, unsigned len)
|
||||||
{
|
{
|
||||||
/* Permutation of the Integers 0 through 255 */
|
/* Permutation of the Integers 0 through 255 */
|
||||||
static const unsigned char _nums[] = {
|
static unsigned char _nums[] = {
|
||||||
1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
|
1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
|
||||||
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
|
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
|
||||||
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
|
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
@@ -179,9 +178,9 @@ unsigned radix_tree_size(struct radix_tree *rt)
|
|||||||
return rt->nr_entries;
|
return rt->nr_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv);
|
static bool _insert(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv);
|
||||||
|
|
||||||
static bool _insert_unset(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
|
static bool _insert_unset(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||||
{
|
{
|
||||||
unsigned len = ke - kb;
|
unsigned len = ke - kb;
|
||||||
|
|
||||||
@@ -208,7 +207,7 @@ static bool _insert_unset(struct radix_tree *rt, struct value *v, const uint8_t
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _insert_value(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
|
static bool _insert_value(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||||
{
|
{
|
||||||
unsigned len = ke - kb;
|
unsigned len = ke - kb;
|
||||||
|
|
||||||
@@ -235,7 +234,7 @@ static bool _insert_value(struct radix_tree *rt, struct value *v, const uint8_t
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _insert_value_chain(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
|
static bool _insert_value_chain(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||||
{
|
{
|
||||||
struct value_chain *vc = v->value.ptr;
|
struct value_chain *vc = v->value.ptr;
|
||||||
return _insert(rt, &vc->child, kb, ke, rv);
|
return _insert(rt, &vc->child, kb, ke, rv);
|
||||||
@@ -249,7 +248,7 @@ static unsigned min(unsigned lhs, unsigned rhs)
|
|||||||
return rhs;
|
return rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
|
static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||||
{
|
{
|
||||||
struct prefix_chain *pc = v->value.ptr;
|
struct prefix_chain *pc = v->value.ptr;
|
||||||
|
|
||||||
@@ -314,7 +313,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _insert_node4(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
|
static bool _insert_node4(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||||
{
|
{
|
||||||
struct node4 *n4 = v->value.ptr;
|
struct node4 *n4 = v->value.ptr;
|
||||||
if (n4->nr_entries == 4) {
|
if (n4->nr_entries == 4) {
|
||||||
@@ -344,7 +343,7 @@ static bool _insert_node4(struct radix_tree *rt, struct value *v, const uint8_t
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _insert_node16(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
|
static bool _insert_node16(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||||
{
|
{
|
||||||
struct node16 *n16 = v->value.ptr;
|
struct node16 *n16 = v->value.ptr;
|
||||||
|
|
||||||
@@ -383,7 +382,7 @@ static bool _insert_node16(struct radix_tree *rt, struct value *v, const uint8_t
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _insert_node48(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
|
static bool _insert_node48(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||||
{
|
{
|
||||||
struct node48 *n48 = v->value.ptr;
|
struct node48 *n48 = v->value.ptr;
|
||||||
if (n48->nr_entries == 48) {
|
if (n48->nr_entries == 48) {
|
||||||
@@ -418,7 +417,7 @@ static bool _insert_node48(struct radix_tree *rt, struct value *v, const uint8_t
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _insert_node256(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
|
static bool _insert_node256(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||||
{
|
{
|
||||||
struct node256 *n256 = v->value.ptr;
|
struct node256 *n256 = v->value.ptr;
|
||||||
bool r, was_unset = n256->values[*kb].type == UNSET;
|
bool r, was_unset = n256->values[*kb].type == UNSET;
|
||||||
@@ -431,7 +430,7 @@ static bool _insert_node256(struct radix_tree *rt, struct value *v, const uint8_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: the tree should not be touched if insert fails (eg, OOM)
|
// FIXME: the tree should not be touched if insert fails (eg, OOM)
|
||||||
static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
|
static bool _insert(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||||
{
|
{
|
||||||
if (kb == ke) {
|
if (kb == ke) {
|
||||||
if (v->type == UNSET) {
|
if (v->type == UNSET) {
|
||||||
@@ -488,10 +487,10 @@ static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, c
|
|||||||
|
|
||||||
struct lookup_result {
|
struct lookup_result {
|
||||||
struct value *v;
|
struct value *v;
|
||||||
const uint8_t *kb;
|
uint8_t *kb;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, const uint8_t *ke)
|
static struct lookup_result _lookup_prefix(struct value *v, uint8_t *kb, uint8_t *ke)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
struct value_chain *vc;
|
struct value_chain *vc;
|
||||||
@@ -501,7 +500,7 @@ static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, c
|
|||||||
struct node48 *n48;
|
struct node48 *n48;
|
||||||
struct node256 *n256;
|
struct node256 *n256;
|
||||||
|
|
||||||
if (kb == ke || !kb) /* extra check for !kb for coverity */
|
if (kb == ke)
|
||||||
return (struct lookup_result) {.v = v, .kb = kb};
|
return (struct lookup_result) {.v = v, .kb = kb};
|
||||||
|
|
||||||
switch (v->type) {
|
switch (v->type) {
|
||||||
@@ -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};
|
return (struct lookup_result) {.v = v, .kb = kb};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value rv)
|
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = key;
|
|
||||||
const uint8_t *ke = kb + keylen;
|
|
||||||
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
||||||
return _insert(rt, lr.v, lr.kb, ke, rv);
|
return _insert(rt, lr.v, lr.kb, ke, rv);
|
||||||
}
|
}
|
||||||
@@ -642,7 +639,7 @@ static void _erase_elt(void *array, size_t obj_size, unsigned count, unsigned id
|
|||||||
memset(((uint8_t *) array) + (count - 1) * obj_size, 0, obj_size);
|
memset(((uint8_t *) array) + (count - 1) * obj_size, 0, obj_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb, const uint8_t *ke)
|
static bool _remove(struct radix_tree *rt, struct value *root, uint8_t *kb, uint8_t *ke)
|
||||||
{
|
{
|
||||||
bool r;
|
bool r;
|
||||||
unsigned i, j;
|
unsigned i, j;
|
||||||
@@ -778,12 +775,9 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen)
|
bool radix_tree_remove(struct radix_tree *rt, uint8_t *key_begin, uint8_t *key_end)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = key;
|
if (_remove(rt, &rt->root, key_begin, key_end)) {
|
||||||
const uint8_t *ke = kb + keylen;
|
|
||||||
|
|
||||||
if (_remove(rt, &rt->root, kb, ke)) {
|
|
||||||
rt->nr_entries--;
|
rt->nr_entries--;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -793,13 +787,13 @@ bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen)
|
|||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
static bool _prefix_chain_matches(const struct lookup_result *lr, const uint8_t *ke)
|
static bool _prefix_chain_matches(struct lookup_result *lr, uint8_t *ke)
|
||||||
{
|
{
|
||||||
// It's possible the top node is a prefix chain, and
|
// It's possible the top node is a prefix chain, and
|
||||||
// the remaining key matches part of it.
|
// the remaining key matches part of it.
|
||||||
if (lr->v->type == PREFIX_CHAIN) {
|
if (lr->v->type == PREFIX_CHAIN) {
|
||||||
unsigned i, rlen = ke - lr->kb;
|
unsigned i, rlen = ke - lr->kb;
|
||||||
const struct prefix_chain *pc = lr->v->value.ptr;
|
struct prefix_chain *pc = lr->v->value.ptr;
|
||||||
if (rlen < pc->len) {
|
if (rlen < pc->len) {
|
||||||
for (i = 0; i < rlen; i++)
|
for (i = 0; i < rlen; i++)
|
||||||
if (pc->prefix[i] != lr->kb[i])
|
if (pc->prefix[i] != lr->kb[i])
|
||||||
@@ -811,7 +805,7 @@ static bool _prefix_chain_matches(const struct lookup_result *lr, const uint8_t
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uint8_t *kb, const uint8_t *ke, unsigned *count)
|
static bool _remove_subtree(struct radix_tree *rt, struct value *root, uint8_t *kb, uint8_t *ke, unsigned *count)
|
||||||
{
|
{
|
||||||
bool r;
|
bool r;
|
||||||
unsigned i, j, len;
|
unsigned i, j, len;
|
||||||
@@ -937,10 +931,8 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, size_t prefix_len)
|
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = prefix;
|
|
||||||
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))
|
||||||
@@ -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,
|
bool radix_tree_lookup(struct radix_tree *rt,
|
||||||
union radix_value *result)
|
uint8_t *kb, uint8_t *ke, union radix_value *result)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = key;
|
|
||||||
const uint8_t *ke = kb + keylen;
|
|
||||||
struct value_chain *vc;
|
struct value_chain *vc;
|
||||||
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
||||||
if (lr.kb == ke) {
|
if (lr.kb == ke) {
|
||||||
@@ -978,15 +968,15 @@ bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: build up the keys too
|
// FIXME: build up the keys too
|
||||||
static bool _iterate(struct radix_tree_iterator *it, const struct value *v)
|
static bool _iterate(struct value *v, struct radix_tree_iterator *it)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
const struct value_chain *vc;
|
struct value_chain *vc;
|
||||||
const struct prefix_chain *pc;
|
struct prefix_chain *pc;
|
||||||
const struct node4 *n4;
|
struct node4 *n4;
|
||||||
const struct node16 *n16;
|
struct node16 *n16;
|
||||||
const struct node48 *n48;
|
struct node48 *n48;
|
||||||
const struct node256 *n256;
|
struct node256 *n256;
|
||||||
|
|
||||||
switch (v->type) {
|
switch (v->type) {
|
||||||
case UNSET:
|
case UNSET:
|
||||||
@@ -994,41 +984,41 @@ static bool _iterate(struct radix_tree_iterator *it, const struct value *v)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VALUE:
|
case VALUE:
|
||||||
return it->visit(it, NULL, 0, v->value);
|
return it->visit(it, NULL, NULL, v->value);
|
||||||
|
|
||||||
case VALUE_CHAIN:
|
case VALUE_CHAIN:
|
||||||
vc = v->value.ptr;
|
vc = v->value.ptr;
|
||||||
return it->visit(it, NULL, 0, vc->value) && _iterate(it, &vc->child);
|
return it->visit(it, NULL, NULL, vc->value) && _iterate(&vc->child, it);
|
||||||
|
|
||||||
case PREFIX_CHAIN:
|
case PREFIX_CHAIN:
|
||||||
pc = v->value.ptr;
|
pc = v->value.ptr;
|
||||||
return _iterate(it, &pc->child);
|
return _iterate(&pc->child, it);
|
||||||
|
|
||||||
case NODE4:
|
case NODE4:
|
||||||
n4 = (const struct node4 *) v->value.ptr;
|
n4 = (struct node4 *) v->value.ptr;
|
||||||
for (i = 0; i < n4->nr_entries; i++)
|
for (i = 0; i < n4->nr_entries; i++)
|
||||||
if (!_iterate(it, n4->values + i))
|
if (!_iterate(n4->values + i, it))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case NODE16:
|
case NODE16:
|
||||||
n16 = (const struct node16 *) v->value.ptr;
|
n16 = (struct node16 *) v->value.ptr;
|
||||||
for (i = 0; i < n16->nr_entries; i++)
|
for (i = 0; i < n16->nr_entries; i++)
|
||||||
if (!_iterate(it, n16->values + i))
|
if (!_iterate(n16->values + i, it))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case NODE48:
|
case NODE48:
|
||||||
n48 = (const struct node48 *) v->value.ptr;
|
n48 = (struct node48 *) v->value.ptr;
|
||||||
for (i = 0; i < n48->nr_entries; i++)
|
for (i = 0; i < n48->nr_entries; i++)
|
||||||
if (!_iterate(it, n48->values + i))
|
if (!_iterate(n48->values + i, it))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case NODE256:
|
case NODE256:
|
||||||
n256 = (const struct node256 *) v->value.ptr;
|
n256 = (struct node256 *) v->value.ptr;
|
||||||
for (i = 0; i < 256; i++)
|
for (i = 0; i < 256; i++)
|
||||||
if (n256->values[i].type != UNSET && !_iterate(it, n256->values + i))
|
if (n256->values[i].type != UNSET && !_iterate(n256->values + i, it))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1037,14 +1027,12 @@ static bool _iterate(struct radix_tree_iterator *it, const struct value *v)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
|
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
|
||||||
struct radix_tree_iterator *it)
|
struct radix_tree_iterator *it)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = key;
|
|
||||||
const uint8_t *ke = kb + keylen;
|
|
||||||
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
||||||
if (lr.kb == ke || _prefix_chain_matches(&lr, ke))
|
if (lr.kb == ke || _prefix_chain_matches(&lr, ke))
|
||||||
(void) _iterate(it, lr.v);
|
(void) _iterate(lr.v, it);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
@@ -1219,7 +1207,6 @@ static void _dump(FILE *out, struct value v, unsigned indent)
|
|||||||
struct node16 *n16;
|
struct node16 *n16;
|
||||||
struct node48 *n48;
|
struct node48 *n48;
|
||||||
struct node256 *n256;
|
struct node256 *n256;
|
||||||
unsigned printable;
|
|
||||||
|
|
||||||
if (v.type == UNSET)
|
if (v.type == UNSET)
|
||||||
return;
|
return;
|
||||||
@@ -1244,22 +1231,9 @@ static void _dump(FILE *out, struct value v, unsigned indent)
|
|||||||
|
|
||||||
case PREFIX_CHAIN:
|
case PREFIX_CHAIN:
|
||||||
pc = v.value.ptr;
|
pc = v.value.ptr;
|
||||||
fprintf(out, "<prefix(%u): ", pc->len);
|
fprintf(out, "<prefix: ");
|
||||||
printable = 1;
|
|
||||||
for (i = 0; i < pc->len; i++)
|
for (i = 0; i < pc->len; i++)
|
||||||
if (!isprint(pc->prefix[i])) {
|
fprintf(out, "%x.", (unsigned) *(pc->prefix + i));
|
||||||
printable = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (printable)
|
|
||||||
fputc('"', out);
|
|
||||||
for (i = 0; i < pc->len; i++)
|
|
||||||
if (printable)
|
|
||||||
fprintf(out, "%c", pc->prefix[i]);
|
|
||||||
else
|
|
||||||
fprintf(out, "%02x.", (unsigned) *(pc->prefix + i));
|
|
||||||
if (printable)
|
|
||||||
fputc('"', out);
|
|
||||||
fprintf(out, ">\n");
|
fprintf(out, ">\n");
|
||||||
_dump(out, pc->child, indent + 1);
|
_dump(out, pc->child, indent + 1);
|
||||||
break;
|
break;
|
||||||
@@ -1268,7 +1242,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
|
|||||||
n4 = v.value.ptr;
|
n4 = v.value.ptr;
|
||||||
fprintf(out, "<n4: ");
|
fprintf(out, "<n4: ");
|
||||||
for (i = 0; i < n4->nr_entries; i++)
|
for (i = 0; i < n4->nr_entries; i++)
|
||||||
fprintf(out, "%02x ", (unsigned) n4->keys[i]);
|
fprintf(out, "%x ", (unsigned) n4->keys[i]);
|
||||||
fprintf(out, ">\n");
|
fprintf(out, ">\n");
|
||||||
|
|
||||||
for (i = 0; i < n4->nr_entries; i++)
|
for (i = 0; i < n4->nr_entries; i++)
|
||||||
@@ -1279,7 +1253,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
|
|||||||
n16 = v.value.ptr;
|
n16 = v.value.ptr;
|
||||||
fprintf(out, "<n16: ");
|
fprintf(out, "<n16: ");
|
||||||
for (i = 0; i < n16->nr_entries; i++)
|
for (i = 0; i < n16->nr_entries; i++)
|
||||||
fprintf(out, "%02x ", (unsigned) n16->keys[i]);
|
fprintf(out, "%x ", (unsigned) n16->keys[i]);
|
||||||
fprintf(out, ">\n");
|
fprintf(out, ">\n");
|
||||||
|
|
||||||
for (i = 0; i < n16->nr_entries; i++)
|
for (i = 0; i < n16->nr_entries; i++)
|
||||||
@@ -1291,7 +1265,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
|
|||||||
fprintf(out, "<n48: ");
|
fprintf(out, "<n48: ");
|
||||||
for (i = 0; i < 256; i++)
|
for (i = 0; i < 256; i++)
|
||||||
if (n48->keys[i] < 48)
|
if (n48->keys[i] < 48)
|
||||||
fprintf(out, "%02x ", i);
|
fprintf(out, "%x ", i);
|
||||||
fprintf(out, ">\n");
|
fprintf(out, ">\n");
|
||||||
|
|
||||||
for (i = 0; i < n48->nr_entries; i++) {
|
for (i = 0; i < n48->nr_entries; i++) {
|
||||||
@@ -1305,7 +1279,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
|
|||||||
fprintf(out, "<n256: ");
|
fprintf(out, "<n256: ");
|
||||||
for (i = 0; i < 256; i++)
|
for (i = 0; i < 256; i++)
|
||||||
if (n256->values[i].type != UNSET)
|
if (n256->values[i].type != UNSET)
|
||||||
fprintf(out, "%02x ", i);
|
fprintf(out, "%x ", i);
|
||||||
fprintf(out, ">\n");
|
fprintf(out, ">\n");
|
||||||
|
|
||||||
for (i = 0; i < 256; i++)
|
for (i = 0; i < 256; i++)
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// This implementation is based around nested binary trees. Very
|
// This implementation is based around nested binary trees. Very
|
||||||
@@ -38,12 +37,12 @@ struct node {
|
|||||||
struct radix_tree {
|
struct radix_tree {
|
||||||
radix_value_dtr dtr;
|
radix_value_dtr dtr;
|
||||||
void *dtr_context;
|
void *dtr_context;
|
||||||
unsigned nr_entries;
|
|
||||||
|
|
||||||
struct node *root;
|
struct node *root;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context)
|
struct radix_tree *
|
||||||
|
radix_tree_create(radix_value_dtr dtr, void *dtr_context)
|
||||||
{
|
{
|
||||||
struct radix_tree *rt = zalloc(sizeof(*rt));
|
struct radix_tree *rt = zalloc(sizeof(*rt));
|
||||||
|
|
||||||
@@ -106,7 +105,7 @@ unsigned radix_tree_size(struct radix_tree *rt)
|
|||||||
return _count(rt->root);
|
return _count(rt->root);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct node **_lookup(struct node **pn, const uint8_t *kb, const uint8_t *ke)
|
static struct node **_lookup(struct node **pn, uint8_t *kb, uint8_t *ke)
|
||||||
{
|
{
|
||||||
struct node *n = *pn;
|
struct node *n = *pn;
|
||||||
|
|
||||||
@@ -123,7 +122,7 @@ static struct node **_lookup(struct node **pn, const uint8_t *kb, const uint8_t
|
|||||||
return _lookup(&n->center, kb + 1, ke);
|
return _lookup(&n->center, kb + 1, ke);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _insert(struct node **pn, const uint8_t *kb, const uint8_t *ke, union radix_value v)
|
static bool _insert(struct node **pn, uint8_t *kb, uint8_t *ke, union radix_value v)
|
||||||
{
|
{
|
||||||
struct node *n = *pn;
|
struct node *n = *pn;
|
||||||
|
|
||||||
@@ -152,31 +151,20 @@ static bool _insert(struct node **pn, const uint8_t *kb, const uint8_t *ke, unio
|
|||||||
return _insert(&n->center, kb + 1, ke, v);
|
return _insert(&n->center, kb + 1, ke, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen,
|
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v)
|
||||||
union radix_value v)
|
|
||||||
{
|
{
|
||||||
const uint8_t *kb = key;
|
return _insert(&rt->root, kb, ke, v);
|
||||||
const uint8_t *ke = kb + keylen;
|
|
||||||
|
|
||||||
if (!_insert(&rt->root, kb, ke, v))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
rt->nr_entries++;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen)
|
bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = key;
|
|
||||||
const uint8_t *ke = kb + keylen;
|
|
||||||
struct node **pn = _lookup(&rt->root, kb, ke);
|
struct node **pn = _lookup(&rt->root, kb, ke);
|
||||||
struct node *n = *pn;
|
struct node *n = *pn;
|
||||||
|
|
||||||
if (!n || !n->has_value)
|
if (!n || !n->has_value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
rt->nr_entries--;
|
else {
|
||||||
|
|
||||||
if (rt->dtr)
|
if (rt->dtr)
|
||||||
rt->dtr(rt->dtr_context, n->value);
|
rt->dtr(rt->dtr_context, n->value);
|
||||||
|
|
||||||
@@ -184,19 +172,18 @@ bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen)
|
|||||||
n->has_value = false;
|
n->has_value = false;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
} else {
|
||||||
|
|
||||||
// FIXME: delete parent if this was the last entry
|
// FIXME: delete parent if this was the last entry
|
||||||
free(n);
|
free(n);
|
||||||
*pn = NULL;
|
*pn = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
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;
|
struct node **pn;
|
||||||
unsigned count;
|
unsigned count;
|
||||||
|
|
||||||
@@ -210,19 +197,16 @@ unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *key, size_t
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
|
bool
|
||||||
union radix_value *result)
|
radix_tree_lookup(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value *result)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = key;
|
|
||||||
const uint8_t *ke = kb + keylen;
|
|
||||||
struct node **pn = _lookup(&rt->root, kb, ke);
|
struct node **pn = _lookup(&rt->root, kb, ke);
|
||||||
struct node *n = *pn;
|
struct node *n = *pn;
|
||||||
|
|
||||||
if (n && n->has_value) {
|
if (n && n->has_value) {
|
||||||
*result = n->value;
|
*result = n->value;
|
||||||
return true;
|
return true;
|
||||||
}
|
} else
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,18 +219,15 @@ static void _iterate(struct node *n, struct radix_tree_iterator *it)
|
|||||||
|
|
||||||
if (n->has_value)
|
if (n->has_value)
|
||||||
// FIXME: fill out the key
|
// FIXME: fill out the key
|
||||||
it->visit(it, NULL, 0, n->value);
|
it->visit(it, NULL, NULL, n->value);
|
||||||
|
|
||||||
_iterate(n->center, it);
|
_iterate(n->center, it);
|
||||||
_iterate(n->right, it);
|
_iterate(n->right, it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
|
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
|
||||||
struct radix_tree_iterator *it)
|
struct radix_tree_iterator *it)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = key;
|
|
||||||
const uint8_t *ke = kb + keylen;
|
|
||||||
|
|
||||||
if (kb == ke)
|
if (kb == ke)
|
||||||
_iterate(rt->root, it);
|
_iterate(rt->root, it);
|
||||||
|
|
||||||
@@ -256,7 +237,7 @@ void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
|
|||||||
|
|
||||||
if (n) {
|
if (n) {
|
||||||
if (n->has_value)
|
if (n->has_value)
|
||||||
it->visit(it, NULL, 0, n->value);
|
it->visit(it, NULL, NULL, n->value);
|
||||||
_iterate(n->center, it);
|
_iterate(n->center, it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,32 +248,8 @@ bool radix_tree_is_well_formed(struct radix_tree *rt)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dump(FILE *out, struct node *n, unsigned indent)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
if (!n)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_dump(out, n->left, indent + 1);
|
|
||||||
|
|
||||||
for (i = 0; i < 2 * indent; i++)
|
|
||||||
fprintf(out, " ");
|
|
||||||
|
|
||||||
if (n->has_value) {
|
|
||||||
fprintf(out, "value: %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)
|
void radix_tree_dump(struct radix_tree *rt, FILE *out)
|
||||||
{
|
{
|
||||||
_dump(out, rt->root, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|||||||
@@ -19,45 +19,3 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
struct visitor {
|
|
||||||
struct radix_tree_iterator it;
|
|
||||||
unsigned pos, nr_entries;
|
|
||||||
union radix_value *values;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool _visitor(struct radix_tree_iterator *it,
|
|
||||||
const void *key, size_t keylen,
|
|
||||||
union radix_value v)
|
|
||||||
{
|
|
||||||
struct visitor *vt = container_of(it, struct visitor, it);
|
|
||||||
|
|
||||||
if (vt->pos >= vt->nr_entries)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
vt->values[vt->pos++] = v;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool radix_tree_values(struct radix_tree *rt, const void *key, size_t keylen,
|
|
||||||
union radix_value **values, unsigned *nr_values)
|
|
||||||
{
|
|
||||||
struct visitor vt = {
|
|
||||||
.it.visit = _visitor,
|
|
||||||
.nr_entries = rt->nr_entries,
|
|
||||||
.values = calloc(rt->nr_entries + 1, sizeof(union radix_value)),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (vt.values) {
|
|
||||||
// build set of all values in current radix tree
|
|
||||||
radix_tree_iterate(rt, key, keylen, &vt.it);
|
|
||||||
*nr_values = vt.pos;
|
|
||||||
*values = vt.values;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
|
|||||||
@@ -33,14 +33,14 @@ struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context);
|
|||||||
void radix_tree_destroy(struct radix_tree *rt);
|
void radix_tree_destroy(struct radix_tree *rt);
|
||||||
|
|
||||||
unsigned radix_tree_size(struct radix_tree *rt);
|
unsigned radix_tree_size(struct radix_tree *rt);
|
||||||
bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value v);
|
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v);
|
||||||
bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen);
|
bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke);
|
||||||
|
|
||||||
// Returns the number of values removed
|
// Returns the number of values removed
|
||||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, size_t prefix_len);
|
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *prefix_b, uint8_t *prefix_e);
|
||||||
|
|
||||||
bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
|
bool radix_tree_lookup(struct radix_tree *rt,
|
||||||
union radix_value *result);
|
uint8_t *kb, uint8_t *ke, union radix_value *result);
|
||||||
|
|
||||||
// The radix tree stores entries in lexicographical order. Which means
|
// The radix tree stores entries in lexicographical order. Which means
|
||||||
// we can iterate entries, in order. Or iterate entries with a particular
|
// we can iterate entries, in order. Or iterate entries with a particular
|
||||||
@@ -48,36 +48,17 @@ bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
|
|||||||
struct radix_tree_iterator {
|
struct radix_tree_iterator {
|
||||||
// Returns false if the iteration should end.
|
// Returns false if the iteration should end.
|
||||||
bool (*visit)(struct radix_tree_iterator *it,
|
bool (*visit)(struct radix_tree_iterator *it,
|
||||||
const void *key, size_t keylen, union radix_value v);
|
uint8_t *kb, uint8_t *ke, union radix_value v);
|
||||||
};
|
};
|
||||||
|
|
||||||
void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
|
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
|
||||||
struct radix_tree_iterator *it);
|
struct radix_tree_iterator *it);
|
||||||
|
|
||||||
// Alternative traversing radix_tree.
|
|
||||||
// Builds whole set all radix_tree nr_values values.
|
|
||||||
// After use, free(values).
|
|
||||||
bool radix_tree_values(struct radix_tree *rt, const void *key, size_t keylen,
|
|
||||||
union radix_value **values, unsigned *nr_values);
|
|
||||||
|
|
||||||
// Checks that some constraints on the shape of the tree are
|
// Checks that some constraints on the shape of the tree are
|
||||||
// being held. For debug only.
|
// being held. For debug only.
|
||||||
bool radix_tree_is_well_formed(struct radix_tree *rt);
|
bool radix_tree_is_well_formed(struct radix_tree *rt);
|
||||||
void radix_tree_dump(struct radix_tree *rt, FILE *out);
|
void radix_tree_dump(struct radix_tree *rt, FILE *out);
|
||||||
|
|
||||||
// Shortcut for ptr value return
|
|
||||||
// Note: if value would be NULL, it's same result for not/found case.
|
|
||||||
static inline void *radix_tree_lookup_ptr(struct radix_tree *rt, const void *key, size_t keylen)
|
|
||||||
{
|
|
||||||
union radix_value v;
|
|
||||||
return radix_tree_lookup(rt, key, keylen, &v) ? v.ptr : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool radix_tree_insert_ptr(struct radix_tree *rt, const void *key, size_t keylen, void *ptr)
|
|
||||||
{
|
|
||||||
union radix_value v = { .ptr = ptr };
|
|
||||||
return radix_tree_insert(rt, key, keylen, v);
|
|
||||||
}
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ install_localconf: $(CONFLOCAL)
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
install_profiles: $(PROFILES)
|
install_profiles: $(PROFILES)
|
||||||
$(SHOW) " [INSTALL] $<"
|
@echo " [INSTALL] $<"
|
||||||
$(Q) $(INSTALL_DIR) $(profiledir)
|
$(Q) $(INSTALL_DIR) $(profiledir)
|
||||||
$(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/
|
$(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/
|
||||||
|
|
||||||
|
|||||||
@@ -135,16 +135,6 @@ devices {
|
|||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# devicesfile = "system.devices"
|
# devicesfile = "system.devices"
|
||||||
|
|
||||||
# Configuration option devices/devicesfile_backup_limit.
|
|
||||||
# The max number of backup files to keep in /etc/lvm/devices/backup.
|
|
||||||
# LVM creates a backup of the devices file each time a new
|
|
||||||
# version is created, or each time a modification is detected.
|
|
||||||
# When the max number of backups is reached, the oldest are
|
|
||||||
# removed to remain at the limit. Set to 0 to disable backups.
|
|
||||||
# Only the system devices file is backed up.
|
|
||||||
# This configuration option has an automatic default value.
|
|
||||||
# devicesfile_backup_limit = 50
|
|
||||||
|
|
||||||
# Configuration option devices/search_for_devnames.
|
# Configuration option devices/search_for_devnames.
|
||||||
# Look outside of the devices file for missing devname entries.
|
# Look outside of the devices file for missing devname entries.
|
||||||
# A devname entry is used for a device that does not have a stable
|
# A devname entry is used for a device that does not have a stable
|
||||||
@@ -159,27 +149,7 @@ devices {
|
|||||||
# at other devices, but only those that are likely to have the PV.
|
# at other devices, but only those that are likely to have the PV.
|
||||||
# If "all", lvm will look at all devices on the system.
|
# If "all", lvm will look at all devices on the system.
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# search_for_devnames = "all"
|
# search_for_devnames = "auto"
|
||||||
|
|
||||||
# Configuration option devices/device_ids_refresh.
|
|
||||||
# Find PVs on new devices and update the device IDs in the devices file.
|
|
||||||
# If PVs are restored or moved to a new system with new devices, but
|
|
||||||
# an old system.devices remains with old device IDs, then search for
|
|
||||||
# the PVIDs on new devices and update the device IDs in system.devices.
|
|
||||||
# The original device IDs must also not be found on the new system.
|
|
||||||
# See device_ids_refresh_check for conditions that trigger the refresh.
|
|
||||||
# This configuration option has an automatic default value.
|
|
||||||
# device_ids_refresh = 1
|
|
||||||
|
|
||||||
# Configuration option devices/device_ids_refresh_checks.
|
|
||||||
# Conditions that trigger device_ids_refresh to locate PVIDs on new devices.
|
|
||||||
# product_uuid: refresh if /sys/devices/virtual/dmi/id/product_uuid does not
|
|
||||||
# match the value saved in system.devices.
|
|
||||||
# hostname: refresh if hostname does not match the value saved in system.devices.
|
|
||||||
# (hostname is used if product_uuid is not available.)
|
|
||||||
# Remove values from this list to prevent lvm from using them.
|
|
||||||
# This configuration option has an automatic default value.
|
|
||||||
# device_ids_refresh_checks = [ "product_uuid", "hostname" ]
|
|
||||||
|
|
||||||
# Configuration option devices/filter.
|
# Configuration option devices/filter.
|
||||||
# Limit the block devices that are used by LVM commands.
|
# Limit the block devices that are used by LVM commands.
|
||||||
@@ -241,12 +211,17 @@ devices {
|
|||||||
# sysfs_scan = 1
|
# sysfs_scan = 1
|
||||||
|
|
||||||
# Configuration option devices/scan_lvs.
|
# Configuration option devices/scan_lvs.
|
||||||
# Allow LVM LVs to be used as PVs. When enabled, LVM commands will
|
# Scan LVM LVs for layered PVs, allowing LVs to be used as PVs.
|
||||||
# scan active LVs to look for other PVs. Caution is required to
|
# When 1, LVM will detect PVs layered on LVs, and caution must be
|
||||||
# avoid using PVs that belong to guest images stored on LVs.
|
# taken to avoid a host accessing a layered VG that may not belong
|
||||||
# When enabled, the LVs scanned should be restricted using the
|
# to it, e.g. from a guest image. This generally requires excluding
|
||||||
# devices file or the filter. This option does not enable autoactivation
|
# the LVs with device filters. Also, when this setting is enabled,
|
||||||
# of layered VGs, which requires editing LVM udev rules (see LVM_PVSCAN_ON_LVS.)
|
# every LVM command will scan every active LV on the system (unless
|
||||||
|
# filtered), which can cause performance problems on systems with
|
||||||
|
# many active LVs. When this setting is 0, LVM will not detect or
|
||||||
|
# use PVs that exist on LVs, and will not allow a PV to be created on
|
||||||
|
# an LV. The LVs are ignored using a built in device filter that
|
||||||
|
# identifies and excludes LVs.
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# scan_lvs = 0
|
# scan_lvs = 0
|
||||||
|
|
||||||
@@ -675,6 +650,11 @@ allocation {
|
|||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# vdo_block_map_period = 16380
|
# vdo_block_map_period = 16380
|
||||||
|
|
||||||
|
# Configuration option allocation/vdo_check_point_frequency.
|
||||||
|
# The default check point frequency for VDO volume.
|
||||||
|
# This configuration option has an automatic default value.
|
||||||
|
# vdo_check_point_frequency = 0
|
||||||
|
|
||||||
# Configuration option allocation/vdo_use_sparse_index.
|
# Configuration option allocation/vdo_use_sparse_index.
|
||||||
# Enables sparse indexing for VDO volume.
|
# Enables sparse indexing for VDO volume.
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
@@ -777,7 +757,7 @@ allocation {
|
|||||||
# vdo_max_discard = 1
|
# vdo_max_discard = 1
|
||||||
|
|
||||||
# Configuration option allocation/vdo_pool_header_size.
|
# Configuration option allocation/vdo_pool_header_size.
|
||||||
# Specified the empty header size in KiB at the front and end of vdo pool device.
|
# Specified the emptry header size in KiB at the front and end of vdo pool device.
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# vdo_pool_header_size = 512
|
# vdo_pool_header_size = 512
|
||||||
}
|
}
|
||||||
@@ -956,7 +936,7 @@ backup {
|
|||||||
# archive = 1
|
# archive = 1
|
||||||
|
|
||||||
# Configuration option backup/archive_dir.
|
# Configuration option backup/archive_dir.
|
||||||
# Location of the metadata archive files.
|
# Location of the metdata archive files.
|
||||||
# Remember to back up this directory regularly!
|
# Remember to back up this directory regularly!
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# archive_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@"
|
# archive_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@"
|
||||||
@@ -1032,7 +1012,7 @@ global {
|
|||||||
# Location of proc filesystem.
|
# Location of proc filesystem.
|
||||||
# This configuration option is advanced.
|
# This configuration option is advanced.
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# proc = "@DEFAULT_PROC_DIR@"
|
# proc = "/proc"
|
||||||
|
|
||||||
# Configuration option global/etc.
|
# Configuration option global/etc.
|
||||||
# Location of /etc system configuration directory.
|
# Location of /etc system configuration directory.
|
||||||
@@ -1176,7 +1156,7 @@ global {
|
|||||||
# services (via the lvm2-activation-generator), but the autoactivation
|
# services (via the lvm2-activation-generator), but the autoactivation
|
||||||
# services and generator have been removed.
|
# services and generator have been removed.
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# event_activation = @DEFAULT_EVENT_ACTIVATION@
|
# event_activation = 1
|
||||||
|
|
||||||
# Configuration option global/use_aio.
|
# Configuration option global/use_aio.
|
||||||
# Use async I/O when reading and writing devices.
|
# Use async I/O when reading and writing devices.
|
||||||
@@ -1221,7 +1201,7 @@ global {
|
|||||||
|
|
||||||
# Configuration option global/thin_check_executable.
|
# Configuration option global/thin_check_executable.
|
||||||
# The full path to the thin_check command.
|
# The full path to the thin_check command.
|
||||||
# LVM uses this command to check that a thin pool metadata device is in a
|
# LVM uses this command to check that a thin metadata device is in a
|
||||||
# usable state. When a thin pool is activated and after it is
|
# usable state. When a thin pool is activated and after it is
|
||||||
# deactivated, this command is run. Activation will only proceed if
|
# deactivated, this command is run. Activation will only proceed if
|
||||||
# the command has an exit status of 0. Set to "" to skip this check.
|
# the command has an exit status of 0. Set to "" to skip this check.
|
||||||
@@ -1245,14 +1225,6 @@ global {
|
|||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# thin_repair_executable = "@THIN_REPAIR_CMD@"
|
# thin_repair_executable = "@THIN_REPAIR_CMD@"
|
||||||
|
|
||||||
# Configuration option global/thin_restore_executable.
|
|
||||||
# The full path to the thin_restore command.
|
|
||||||
# LVM uses this command to restore generated data for a thin pool metadata device.
|
|
||||||
# Also see thin_restore_options.
|
|
||||||
# (See package device-mapper-persistent-data or thin-provisioning-tools)
|
|
||||||
# This configuration option has an automatic default value.
|
|
||||||
# thin_restore_executable = "@THIN_RESTORE_CMD@"
|
|
||||||
|
|
||||||
# Configuration option global/thin_check_options.
|
# Configuration option global/thin_check_options.
|
||||||
# List of options passed to the thin_check command.
|
# List of options passed to the thin_check command.
|
||||||
# With thin_check version 2.1 or newer you can add the option
|
# With thin_check version 2.1 or newer you can add the option
|
||||||
@@ -1267,11 +1239,6 @@ global {
|
|||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# thin_repair_options = [ "" ]
|
# thin_repair_options = [ "" ]
|
||||||
|
|
||||||
# Configuration option global/thin_restore_options.
|
|
||||||
# List of options passed to the thin_restore command.
|
|
||||||
# This configuration option has an automatic default value.
|
|
||||||
# thin_restore_options = [ "" ]
|
|
||||||
|
|
||||||
# Configuration option global/thin_disabled_features.
|
# Configuration option global/thin_disabled_features.
|
||||||
# Features to not use in the thin driver.
|
# Features to not use in the thin driver.
|
||||||
# This can be helpful for testing, or to avoid using a feature that is
|
# This can be helpful for testing, or to avoid using a feature that is
|
||||||
@@ -1320,14 +1287,6 @@ global {
|
|||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# cache_repair_executable = "@CACHE_REPAIR_CMD@"
|
# cache_repair_executable = "@CACHE_REPAIR_CMD@"
|
||||||
|
|
||||||
# Configuration option global/cache_restore_executable.
|
|
||||||
# The full path to the cache_restore command.
|
|
||||||
# LVM uses this command to restore generated data for a cache metadata device.
|
|
||||||
# Also see cache_restore_options.
|
|
||||||
# (See package device-mapper-persistent-data or thin-provisioning-tools)
|
|
||||||
# This configuration option has an automatic default value.
|
|
||||||
# cache_restore_executable = "@CACHE_RESTORE_CMD@"
|
|
||||||
|
|
||||||
# Configuration option global/cache_check_options.
|
# Configuration option global/cache_check_options.
|
||||||
# List of options passed to the cache_check command.
|
# List of options passed to the cache_check command.
|
||||||
# With cache_check version 5.0 or newer you should include the option
|
# With cache_check version 5.0 or newer you should include the option
|
||||||
@@ -1340,11 +1299,6 @@ global {
|
|||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# cache_repair_options = [ "" ]
|
# cache_repair_options = [ "" ]
|
||||||
|
|
||||||
# Configuration option global/cache_restore_options.
|
|
||||||
# List of options passed to the cache_restore command.
|
|
||||||
# This configuration option has an automatic default value.
|
|
||||||
# cache_restore_options = [ "" ]
|
|
||||||
|
|
||||||
# Configuration option global/vdo_format_executable.
|
# Configuration option global/vdo_format_executable.
|
||||||
# The full path to the vdoformat command.
|
# The full path to the vdoformat command.
|
||||||
# LVM uses this command to initial data volume for VDO type logical volume
|
# LVM uses this command to initial data volume for VDO type logical volume
|
||||||
@@ -1359,10 +1313,10 @@ global {
|
|||||||
# Configuration option global/vdo_disabled_features.
|
# Configuration option global/vdo_disabled_features.
|
||||||
# Features to not use in the vdo driver.
|
# Features to not use in the vdo driver.
|
||||||
# This can be helpful for testing, or to avoid using a feature that is
|
# This can be helpful for testing, or to avoid using a feature that is
|
||||||
# causing problems. Features include: online_rename, version4
|
# causing problems. Features include: online_rename
|
||||||
#
|
#
|
||||||
# Example
|
# Example
|
||||||
# vdo_disabled_features = [ "online_rename", "version4" ]
|
# vdo_disabled_features = [ "online_rename" ]
|
||||||
#
|
#
|
||||||
# This configuration option does not have a default value defined.
|
# This configuration option does not have a default value defined.
|
||||||
|
|
||||||
@@ -1392,9 +1346,8 @@ global {
|
|||||||
# Use an LVM-specific derivation of the local machine-id as the
|
# Use an LVM-specific derivation of the local machine-id as the
|
||||||
# system ID. See 'man machine-id'.
|
# system ID. See 'man machine-id'.
|
||||||
# machineid
|
# machineid
|
||||||
# Use the contents of the machine-id file to set the system ID.
|
# Use the contents of the machine-id file to set the system ID
|
||||||
# (appmachineid is recommended to avoid exposing the confidential
|
# (appmachineid is recommended.)
|
||||||
# machine-id.)
|
|
||||||
# file
|
# file
|
||||||
# Use the contents of another file (system_id_file) to set the
|
# Use the contents of another file (system_id_file) to set the
|
||||||
# system ID.
|
# system ID.
|
||||||
@@ -1510,13 +1463,13 @@ activation {
|
|||||||
|
|
||||||
# Configuration option activation/reserved_stack.
|
# Configuration option activation/reserved_stack.
|
||||||
# Stack size in KiB to reserve for use while devices are suspended.
|
# Stack size in KiB to reserve for use while devices are suspended.
|
||||||
# Insufficient reserve risks I/O deadlock during device suspension.
|
# Insufficent reserve risks I/O deadlock during device suspension.
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# reserved_stack = 64
|
# reserved_stack = 64
|
||||||
|
|
||||||
# Configuration option activation/reserved_memory.
|
# Configuration option activation/reserved_memory.
|
||||||
# Memory size in KiB to reserve for use while devices are suspended.
|
# Memory size in KiB to reserve for use while devices are suspended.
|
||||||
# Insufficient reserve risks I/O deadlock during device suspension.
|
# Insufficent reserve risks I/O deadlock during device suspension.
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# reserved_memory = 8192
|
# reserved_memory = 8192
|
||||||
|
|
||||||
@@ -1651,7 +1604,7 @@ activation {
|
|||||||
# This includes LVs that have the following segment types:
|
# This includes LVs that have the following segment types:
|
||||||
# raid1, raid4, raid5*, and raid6*.
|
# raid1, raid4, raid5*, and raid6*.
|
||||||
# If a device in the LV fails, the policy determines the steps
|
# If a device in the LV fails, the policy determines the steps
|
||||||
# performed by dmeventd automatically, and the steps performed by the
|
# performed by dmeventd automatically, and the steps perfomed by the
|
||||||
# manual command lvconvert --repair --use-policies.
|
# manual command lvconvert --repair --use-policies.
|
||||||
# Automatic handling requires dmeventd to be monitoring the LV.
|
# Automatic handling requires dmeventd to be monitoring the LV.
|
||||||
#
|
#
|
||||||
@@ -1675,7 +1628,7 @@ activation {
|
|||||||
# (copies) and a mirror log. A disk log ensures that a mirror LV does
|
# (copies) and a mirror log. A disk log ensures that a mirror LV does
|
||||||
# not need to be re-synced (all copies made the same) every time a
|
# not need to be re-synced (all copies made the same) every time a
|
||||||
# machine reboots or crashes. If a device in the LV fails, this policy
|
# machine reboots or crashes. If a device in the LV fails, this policy
|
||||||
# determines the steps performed by dmeventd automatically, and the steps
|
# determines the steps perfomed by dmeventd automatically, and the steps
|
||||||
# performed by the manual command lvconvert --repair --use-policies.
|
# performed by the manual command lvconvert --repair --use-policies.
|
||||||
# Automatic handling requires dmeventd to be monitoring the LV.
|
# Automatic handling requires dmeventd to be monitoring the LV.
|
||||||
#
|
#
|
||||||
@@ -1837,7 +1790,7 @@ activation {
|
|||||||
# Configuration option activation/polling_interval.
|
# Configuration option activation/polling_interval.
|
||||||
# Check pvmove or lvconvert progress at this interval (seconds).
|
# Check pvmove or lvconvert progress at this interval (seconds).
|
||||||
# When pvmove or lvconvert must wait for the kernel to finish
|
# When pvmove or lvconvert must wait for the kernel to finish
|
||||||
# synchronizing or merging data, they check and report progress at
|
# synchronising or merging data, they check and report progress at
|
||||||
# intervals of this number of seconds. If this is set to 0 and there
|
# intervals of this number of seconds. If this is set to 0 and there
|
||||||
# is only one thing to wait for, there are no progress reports, but
|
# is only one thing to wait for, there are no progress reports, but
|
||||||
# the process is awoken immediately once the operation is complete.
|
# the process is awoken immediately once the operation is complete.
|
||||||
@@ -1982,7 +1935,8 @@ activation {
|
|||||||
|
|
||||||
# Configuration section report.
|
# Configuration section report.
|
||||||
# LVM report command output formatting.
|
# LVM report command output formatting.
|
||||||
report {
|
# This configuration section has an automatic default value.
|
||||||
|
# report {
|
||||||
|
|
||||||
# Configuration option report/output_format.
|
# Configuration option report/output_format.
|
||||||
# Format of LVM command's report output.
|
# Format of LVM command's report output.
|
||||||
@@ -2042,11 +1996,7 @@ report {
|
|||||||
# buffered = 1
|
# buffered = 1
|
||||||
|
|
||||||
# Configuration option report/headings.
|
# Configuration option report/headings.
|
||||||
# Format of LVM command's report output headings.
|
# Show headings for columns on report.
|
||||||
# Accepted values:
|
|
||||||
# 0 no headings,
|
|
||||||
# 1 headings with column abbreviations,
|
|
||||||
# 2 headings with full column names.
|
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# headings = 1
|
# headings = 1
|
||||||
|
|
||||||
@@ -2396,7 +2346,7 @@ report {
|
|||||||
# This is displayed when the device for a PV is not known.
|
# This is displayed when the device for a PV is not known.
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# two_word_unknown_device = 0
|
# two_word_unknown_device = 0
|
||||||
}
|
# }
|
||||||
|
|
||||||
# Configuration section dmeventd.
|
# Configuration section dmeventd.
|
||||||
# Settings for the LVM event daemon.
|
# Settings for the LVM event daemon.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ allocation {
|
|||||||
vdo_minimum_io_size=4096
|
vdo_minimum_io_size=4096
|
||||||
vdo_block_map_cache_size_mb=128
|
vdo_block_map_cache_size_mb=128
|
||||||
vdo_block_map_period=16380
|
vdo_block_map_period=16380
|
||||||
|
vdo_check_point_frequency=0
|
||||||
vdo_use_sparse_index=0
|
vdo_use_sparse_index=0
|
||||||
vdo_index_memory_size_mb=256
|
vdo_index_memory_size_mb=256
|
||||||
vdo_slab_size_mb=2048
|
vdo_slab_size_mb=2048
|
||||||
|
|||||||
1533
configure.ac
1533
configure.ac
File diff suppressed because it is too large
Load Diff
@@ -32,12 +32,12 @@ CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
|||||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||||
|
|
||||||
cmirrord: $(OBJECTS)
|
cmirrord: $(OBJECTS)
|
||||||
$(SHOW) " [CC] $@"
|
@echo " [CC] $@"
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
||||||
$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS)
|
$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS)
|
||||||
|
|
||||||
install_cluster: $(TARGETS)
|
install_cluster: $(TARGETS)
|
||||||
$(SHOW) " [INSTALL] $<"
|
@echo " [INSTALL] $<"
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(usrsbindir)/$(<F)
|
$(Q) $(INSTALL_PROGRAM) -D $< $(usrsbindir)/$(<F)
|
||||||
|
|
||||||
install: install_cluster
|
install: install_cluster
|
||||||
|
|||||||
@@ -43,14 +43,14 @@ static void usage (FILE *dest)
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int foreground_mode = 0;
|
int foreground_mode = 0;
|
||||||
static const struct option _long_options[] = {
|
struct option longopts[] = {
|
||||||
{ "foreground", no_argument, NULL, 'f' },
|
{ "foreground", no_argument, NULL, 'f' },
|
||||||
{ "help" , no_argument, NULL, 'h' },
|
{ "help" , no_argument, NULL, 'h' },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
while ((opt = getopt_long (argc, argv, "fh", _long_options, NULL)) != -1) {
|
while ((opt = getopt_long (argc, argv, "fh", longopts, NULL)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'f':
|
case 'f':
|
||||||
foreground_mode = 1;
|
foreground_mode = 1;
|
||||||
|
|||||||
@@ -1091,7 +1091,6 @@ static void cpg_message_callback(cpg_handle_t handle, const struct cpg_name *gna
|
|||||||
(rq->u_rq.request_type != DM_ULOG_RESUME) &&
|
(rq->u_rq.request_type != DM_ULOG_RESUME) &&
|
||||||
(rq->u_rq.request_type != DM_ULOG_CLEAR_REGION) &&
|
(rq->u_rq.request_type != DM_ULOG_CLEAR_REGION) &&
|
||||||
(rq->u_rq.request_type != DM_ULOG_CHECKPOINT_READY)) {
|
(rq->u_rq.request_type != DM_ULOG_CHECKPOINT_READY)) {
|
||||||
/* coverity[suspicious_sizeof] allocation is using varargs data @end */
|
|
||||||
tmp_rq = malloc(DM_ULOG_REQUEST_SIZE);
|
tmp_rq = malloc(DM_ULOG_REQUEST_SIZE);
|
||||||
if (!tmp_rq) {
|
if (!tmp_rq) {
|
||||||
/*
|
/*
|
||||||
@@ -1341,7 +1340,6 @@ static void cpg_join_callback(struct clog_cpg *match,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* coverity[suspicious_sizeof] allocation is using varargs data @end */
|
|
||||||
rq = malloc(DM_ULOG_REQUEST_SIZE);
|
rq = malloc(DM_ULOG_REQUEST_SIZE);
|
||||||
if (!rq) {
|
if (!rq) {
|
||||||
LOG_ERROR("cpg_config_callback: "
|
LOG_ERROR("cpg_config_callback: "
|
||||||
@@ -1634,7 +1632,7 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
|
|||||||
|
|
||||||
size = ((strlen(uuid) + 1) > CPG_MAX_NAME_LENGTH) ?
|
size = ((strlen(uuid) + 1) > CPG_MAX_NAME_LENGTH) ?
|
||||||
CPG_MAX_NAME_LENGTH : (strlen(uuid) + 1);
|
CPG_MAX_NAME_LENGTH : (strlen(uuid) + 1);
|
||||||
dm_strncpy(new->name.value, uuid, size);
|
(void) dm_strncpy(new->name.value, uuid, size);
|
||||||
new->name.length = (uint32_t)size;
|
new->name.length = (uint32_t)size;
|
||||||
new->luid = luid;
|
new->luid = luid;
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ struct log_c {
|
|||||||
uint32_t recoverer;
|
uint32_t recoverer;
|
||||||
uint64_t recovering_region; /* -1 means not recovering */
|
uint64_t recovering_region; /* -1 means not recovering */
|
||||||
uint64_t skip_bit_warning; /* used to warn if region skipped */
|
uint64_t skip_bit_warning; /* used to warn if region skipped */
|
||||||
unsigned sync_search;
|
int sync_search;
|
||||||
|
|
||||||
int resume_override;
|
int resume_override;
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ static int rw_log(struct log_c *lc, int do_write)
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
LOG_ERROR("[%s] rw_log: read failure: %s",
|
LOG_ERROR("[%s] rw_log: read failure: %s",
|
||||||
SHORT_UUID(lc->uuid), strerror(errno));
|
SHORT_UUID(lc->uuid), strerror(errno));
|
||||||
if ((unsigned) r != lc->disk_size)
|
if (r != lc->disk_size)
|
||||||
return -EIO; /* Failed disk read */
|
return -EIO; /* Failed disk read */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -292,13 +292,13 @@ static int write_log(struct log_c *lc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME Rewrite this function taking advantage of the udev changes (where in use) to improve its efficiency! */
|
/* FIXME Rewrite this function taking advantage of the udev changes (where in use) to improve its efficiency! */
|
||||||
static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int *unlink_path __attribute__((unused)))
|
static int find_disk_path(char *major_minor_str, char *path_rtn, int *unlink_path __attribute__((unused)))
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
struct dirent *dep;
|
struct dirent *dep;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
unsigned major, minor;
|
int major, minor;
|
||||||
|
|
||||||
if (!strstr(major_minor_str, ":")) {
|
if (!strstr(major_minor_str, ":")) {
|
||||||
r = stat(major_minor_str, &statbuf);
|
r = stat(major_minor_str, &statbuf);
|
||||||
@@ -306,7 +306,7 @@ static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int
|
|||||||
return -errno;
|
return -errno;
|
||||||
if (!S_ISBLK(statbuf.st_mode))
|
if (!S_ISBLK(statbuf.st_mode))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
dm_strncpy(path_rtn, major_minor_str, sz);
|
sprintf(path_rtn, "%s", major_minor_str);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,7 +329,7 @@ static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int
|
|||||||
* wanted.
|
* wanted.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
snprintf(path_rtn, sz, "/dev/mapper/%s", dep->d_name);
|
sprintf(path_rtn, "/dev/mapper/%s", dep->d_name);
|
||||||
if (stat(path_rtn, &statbuf) < 0) {
|
if (stat(path_rtn, &statbuf) < 0) {
|
||||||
LOG_DBG("Unable to stat %s", path_rtn);
|
LOG_DBG("Unable to stat %s", path_rtn);
|
||||||
continue;
|
continue;
|
||||||
@@ -394,7 +394,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = find_disk_path(argv[0], disk_path, sizeof(disk_path), &unlink_path);
|
r = find_disk_path(argv[0], disk_path, &unlink_path);
|
||||||
if (r) {
|
if (r) {
|
||||||
LOG_ERROR("Unable to find path to device %s", argv[0]);
|
LOG_ERROR("Unable to find path to device %s", argv[0]);
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -452,7 +452,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
|||||||
lc->skip_bit_warning = region_count;
|
lc->skip_bit_warning = region_count;
|
||||||
lc->disk_fd = -1;
|
lc->disk_fd = -1;
|
||||||
lc->log_dev_failed = 0;
|
lc->log_dev_failed = 0;
|
||||||
if (!_dm_strncpy(lc->uuid, uuid, DM_UUID_LEN)) {
|
if (!dm_strncpy(lc->uuid, uuid, DM_UUID_LEN)) {
|
||||||
LOG_ERROR("Cannot use too long UUID %s.", uuid);
|
LOG_ERROR("Cannot use too long UUID %s.", uuid);
|
||||||
r = -EINVAL;
|
r = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
#define _LVM_CLOG_FUNCTIONS_H
|
#define _LVM_CLOG_FUNCTIONS_H
|
||||||
|
|
||||||
#include "libdm/libdevmapper.h"
|
#include "libdm/libdevmapper.h"
|
||||||
#include "libdm/dm-tools/util.h"
|
|
||||||
#include "libdm/misc/dm-log-userspace.h"
|
#include "libdm/misc/dm-log-userspace.h"
|
||||||
#include "cluster.h"
|
#include "cluster.h"
|
||||||
|
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ static int do_local_work(void *data __attribute__((unused)))
|
|||||||
RQ_TYPE(u_rq->request_type));
|
RQ_TYPE(u_rq->request_type));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* ELSE */ /* fall through */
|
/* ELSE, fall through */
|
||||||
case DM_ULOG_IS_CLEAN:
|
case DM_ULOG_IS_CLEAN:
|
||||||
case DM_ULOG_FLUSH:
|
case DM_ULOG_FLUSH:
|
||||||
case DM_ULOG_MARK_REGION:
|
case DM_ULOG_MARK_REGION:
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
|
||||||
const char * const __rq_types_off_by_one[] = {
|
const char *__rq_types_off_by_one[] = {
|
||||||
"DM_ULOG_CTR",
|
"DM_ULOG_CTR",
|
||||||
"DM_ULOG_DTR",
|
"DM_ULOG_DTR",
|
||||||
"DM_ULOG_PRESUSPEND",
|
"DM_ULOG_PRESUSPEND",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
/* SHORT_UUID - print last 8 chars of a string */
|
/* SHORT_UUID - print last 8 chars of a string */
|
||||||
#define SHORT_UUID(x) (strlen(x) > 8) ? ((x) + (strlen(x) - 8)) : (x)
|
#define SHORT_UUID(x) (strlen(x) > 8) ? ((x) + (strlen(x) - 8)) : (x)
|
||||||
|
|
||||||
extern const char * const __rq_types_off_by_one[];
|
extern const char *__rq_types_off_by_one[];
|
||||||
#define RQ_TYPE(x) __rq_types_off_by_one[(x) - 1]
|
#define RQ_TYPE(x) __rq_types_off_by_one[(x) - 1]
|
||||||
|
|
||||||
extern int log_tabbing;
|
extern int log_tabbing;
|
||||||
|
|||||||
@@ -70,13 +70,13 @@ plugins.device-mapper: $(LIB_SHARED)
|
|||||||
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
|
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
|
||||||
|
|
||||||
dmeventd: $(LIB_SHARED) dmeventd.o
|
dmeventd: $(LIB_SHARED) dmeventd.o
|
||||||
$(SHOW) " [CC] $@"
|
@echo " [CC] $@"
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
||||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
|
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
|
||||||
|
|
||||||
dmeventd.static: $(LIB_STATIC) dmeventd.o
|
dmeventd.static: $(LIB_STATIC) dmeventd.o
|
||||||
$(SHOW) " [CC] $@"
|
@echo " [CC] $@"
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(STATIC_LDFLAGS) -static dmeventd.o \
|
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static dmeventd.o \
|
||||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
|
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
|
||||||
|
|
||||||
ifeq ("@PKGCONFIG@", "yes")
|
ifeq ("@PKGCONFIG@", "yes")
|
||||||
@@ -84,27 +84,27 @@ ifeq ("@PKGCONFIG@", "yes")
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
install_include: $(srcdir)/libdevmapper-event.h
|
install_include: $(srcdir)/libdevmapper-event.h
|
||||||
$(SHOW) " [INSTALL] $(<F)"
|
@echo " [INSTALL] $(<F)"
|
||||||
$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F)
|
$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F)
|
||||||
|
|
||||||
install_pkgconfig: libdevmapper-event.pc
|
install_pkgconfig: libdevmapper-event.pc
|
||||||
$(SHOW) " [INSTALL] $<"
|
@echo " [INSTALL] $<"
|
||||||
$(Q) $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
|
$(Q) $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
|
||||||
|
|
||||||
install_lib_dynamic: install_lib_shared
|
install_lib_dynamic: install_lib_shared
|
||||||
|
|
||||||
install_lib_static: $(LIB_STATIC)
|
install_lib_static: $(LIB_STATIC)
|
||||||
$(SHOW) " [INSTALL] $<"
|
@echo " [INSTALL] $<"
|
||||||
$(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
|
$(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
|
||||||
|
|
||||||
install_lib: $(INSTALL_LIB_TARGETS)
|
install_lib: $(INSTALL_LIB_TARGETS)
|
||||||
|
|
||||||
install_dmeventd_dynamic: dmeventd
|
install_dmeventd_dynamic: dmeventd
|
||||||
$(SHOW) " [INSTALL] $<"
|
@echo " [INSTALL] $<"
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
|
|
||||||
install_dmeventd_static: dmeventd.static
|
install_dmeventd_static: dmeventd.static
|
||||||
$(SHOW) " [INSTALL] $<"
|
@echo " [INSTALL] $<"
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
|
$(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
|
||||||
|
|
||||||
install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
|
install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
|
||||||
|
|||||||
@@ -23,12 +23,12 @@
|
|||||||
#include "libdm/misc/dm-logging.h"
|
#include "libdm/misc/dm-logging.h"
|
||||||
#include "base/memory/zalloc.h"
|
#include "base/memory/zalloc.h"
|
||||||
|
|
||||||
#include "libdaemon/server/daemon-stray.h"
|
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <sys/file.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
#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) */
|
/* Default idle exit timeout 1 hour (in seconds) */
|
||||||
static const time_t DMEVENTD_IDLE_EXIT_TIMEOUT = 60 * 60;
|
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 _systemd_activation = 0;
|
||||||
static int _foreground = 0;
|
static int _foreground = 0;
|
||||||
|
static int _restart = 0;
|
||||||
static time_t _idle_since = 0;
|
static time_t _idle_since = 0;
|
||||||
static const char *_exit_on = DEFAULT_DMEVENTD_EXIT_ON_PATH;
|
|
||||||
static char **_initial_registrations = 0;
|
static char **_initial_registrations = 0;
|
||||||
|
|
||||||
/* FIXME Make configurable at runtime */
|
/* FIXME Make configurable at runtime */
|
||||||
@@ -200,9 +202,9 @@ struct message_data {
|
|||||||
char *dso_name; /* Name of DSO. */
|
char *dso_name; /* Name of DSO. */
|
||||||
char *device_uuid; /* Mapped device path. */
|
char *device_uuid; /* Mapped device path. */
|
||||||
char *events_str; /* Events string as fetched from message. */
|
char *events_str; /* Events string as fetched from message. */
|
||||||
unsigned events_field; /* Events bitfield. */
|
enum dm_event_mask events_field; /* Events bitfield. */
|
||||||
uint32_t timeout_secs;
|
|
||||||
char *timeout_str;
|
char *timeout_str;
|
||||||
|
uint32_t timeout_secs;
|
||||||
struct dm_event_daemon_message *msg; /* Pointer to message buffer. */
|
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) {
|
static int _get_parameters(struct message_data *message_data) {
|
||||||
struct dm_event_daemon_message *msg = message_data->msg;
|
struct dm_event_daemon_message *msg = message_data->msg;
|
||||||
int size;
|
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);
|
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(),
|
message_data->id, getpid(),
|
||||||
_foreground ? "no" : "yes",
|
_foreground ? "no" : "yes",
|
||||||
_systemd_activation ? "systemd" : "direct",
|
_systemd_activation ? "systemd" : "direct")) < 0) {
|
||||||
_exit_on,
|
|
||||||
idle_buf)) < 0) {
|
|
||||||
stack;
|
stack;
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
@@ -991,7 +987,6 @@ static void _monitor_unregister(void *arg)
|
|||||||
DEBUGLOG("Unregistering monitor for %s.", thread->device.name);
|
DEBUGLOG("Unregistering monitor for %s.", thread->device.name);
|
||||||
_unregister_for_timeout(thread);
|
_unregister_for_timeout(thread);
|
||||||
|
|
||||||
/* coverity[missing_lock] no missing lock here */
|
|
||||||
if ((thread->status != DM_THREAD_REGISTERING) &&
|
if ((thread->status != DM_THREAD_REGISTERING) &&
|
||||||
!_do_unregister_device(thread))
|
!_do_unregister_device(thread))
|
||||||
log_error("%s: %s unregister failed.", __func__,
|
log_error("%s: %s unregister failed.", __func__,
|
||||||
@@ -1002,8 +997,6 @@ static void _monitor_unregister(void *arg)
|
|||||||
_lock_mutex();
|
_lock_mutex();
|
||||||
thread->status = DM_THREAD_DONE; /* Last access to thread memory! */
|
thread->status = DM_THREAD_DONE; /* Last access to thread memory! */
|
||||||
_unlock_mutex();
|
_unlock_mutex();
|
||||||
if (_exit_now) /* Exit is already in-progress, wake-up sleeping select() */
|
|
||||||
kill(getpid(), SIGINT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Device monitoring thread. */
|
/* Device monitoring thread. */
|
||||||
@@ -1050,9 +1043,9 @@ static void *_monitor_thread(void *arg)
|
|||||||
_unlock_mutex();
|
_unlock_mutex();
|
||||||
|
|
||||||
_do_process_event(thread);
|
_do_process_event(thread);
|
||||||
|
thread->current_events = 0; /* Current events processed */
|
||||||
|
|
||||||
_lock_mutex();
|
_lock_mutex();
|
||||||
thread->current_events = 0; /* Current events processed */
|
|
||||||
thread->processing = 0;
|
thread->processing = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1168,36 +1161,6 @@ static int _unregister_for_event(struct message_data *message_data)
|
|||||||
return ret;
|
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.
|
* 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 ||
|
} else if (!S_ISFIFO(st.st_mode) || st.st_uid ||
|
||||||
(st.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO))) {
|
(st.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO))) {
|
||||||
log_warn("WARNING: %s has wrong attributes: Replacing.", path);
|
log_warn("WARNING: %s has wrong attributes: Replacing.", path);
|
||||||
/* coverity[toctou] don't care, path is going to be recreated */
|
if (unlink(path)) {
|
||||||
if (unlink(path) && (errno != ENOENT)) {
|
|
||||||
log_sys_error("unlink", path);
|
log_sys_error("unlink", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1450,7 +1412,6 @@ static int _open_fifo(const char *path)
|
|||||||
|
|
||||||
/* Create fifo. */
|
/* Create fifo. */
|
||||||
(void) dm_prepare_selinux_context(path, S_IFIFO);
|
(void) dm_prepare_selinux_context(path, S_IFIFO);
|
||||||
/* coverity[toctou] revalidating things again */
|
|
||||||
if ((mkfifo(path, 0600) == -1) && errno != EEXIST) {
|
if ((mkfifo(path, 0600) == -1) && errno != EEXIST) {
|
||||||
log_sys_error("mkfifo", path);
|
log_sys_error("mkfifo", path);
|
||||||
(void) dm_prepare_selinux_context(NULL, 0);
|
(void) dm_prepare_selinux_context(NULL, 0);
|
||||||
@@ -1679,7 +1640,7 @@ static int _do_process_request(struct dm_event_daemon_message *msg)
|
|||||||
} else
|
} else
|
||||||
ret = _handle_request(msg, &message_data);
|
ret = _handle_request(msg, &message_data);
|
||||||
|
|
||||||
msg->cmd = (uint32_t)ret;
|
msg->cmd = ret;
|
||||||
if (!msg->data)
|
if (!msg->data)
|
||||||
msg->size = dm_asprintf(&(msg->data), "%s %s", message_data.id, strerror(-ret));
|
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);
|
free(msg.data);
|
||||||
|
|
||||||
if (cmd == DM_EVENT_CMD_DIE) {
|
if (cmd == DM_EVENT_CMD_DIE) {
|
||||||
_unregister_all_threads();
|
if (unlink(DMEVENTD_PIDFILE))
|
||||||
_exit_now = DM_SCHEDULED_EXIT;
|
log_sys_error("unlink", DMEVENTD_PIDFILE);
|
||||||
log_info("dmeventd exiting for restart.");
|
_exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1765,7 +1726,7 @@ static void _cleanup_unused_threads(void)
|
|||||||
DEBUGLOG("Destroying Thr %x.", (int)thread->thread);
|
DEBUGLOG("Destroying Thr %x.", (int)thread->thread);
|
||||||
|
|
||||||
if (pthread_join(thread->thread, NULL))
|
if (pthread_join(thread->thread, NULL))
|
||||||
log_sys_debug("pthread_join", "");
|
log_sys_error("pthread_join", "");
|
||||||
|
|
||||||
_free_thread_status(thread);
|
_free_thread_status(thread);
|
||||||
_lock_mutex();
|
_lock_mutex();
|
||||||
@@ -1796,7 +1757,7 @@ static void _init_thread_signals(void)
|
|||||||
sigdelset(&my_sigset, SIGQUIT);
|
sigdelset(&my_sigset, SIGQUIT);
|
||||||
|
|
||||||
if (pthread_sigmask(SIG_BLOCK, &my_sigset, NULL))
|
if (pthread_sigmask(SIG_BLOCK, &my_sigset, NULL))
|
||||||
log_sys_debug("pthread_sigmask", "SIG_BLOCK");
|
log_sys_error("pthread_sigmask", "SIG_BLOCK");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1808,7 +1769,6 @@ static void _init_thread_signals(void)
|
|||||||
*/
|
*/
|
||||||
static void _exit_handler(int sig __attribute__((unused)))
|
static void _exit_handler(int sig __attribute__((unused)))
|
||||||
{
|
{
|
||||||
if (!_exit_now)
|
|
||||||
_exit_now = DM_SIGNALED_EXIT;
|
_exit_now = DM_SIGNALED_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1825,7 +1785,7 @@ static int _set_oom_adj(const char *oom_adj_path, int val)
|
|||||||
fprintf(fp, "%i", val);
|
fprintf(fp, "%i", val);
|
||||||
|
|
||||||
if (dm_fclose(fp))
|
if (dm_fclose(fp))
|
||||||
log_sys_debug("fclose", oom_adj_path);
|
log_sys_error("fclose", oom_adj_path);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1839,11 +1799,11 @@ static int _protect_against_oom_killer(void)
|
|||||||
|
|
||||||
if (stat(OOM_ADJ_FILE, &st) == -1) {
|
if (stat(OOM_ADJ_FILE, &st) == -1) {
|
||||||
if (errno != ENOENT)
|
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 */
|
/* Try old oom_adj interface as a fallback */
|
||||||
if (stat(OOM_ADJ_FILE_OLD, &st) == -1) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1931,30 +1891,26 @@ out:
|
|||||||
|
|
||||||
static void _remove_files_on_exit(void)
|
static void _remove_files_on_exit(void)
|
||||||
{
|
{
|
||||||
if (unlink(DMEVENTD_PIDFILE) && (errno != ENOENT))
|
if (unlink(DMEVENTD_PIDFILE))
|
||||||
log_sys_debug("unlink", DMEVENTD_PIDFILE);
|
log_sys_error("unlink", DMEVENTD_PIDFILE);
|
||||||
|
|
||||||
if (!_systemd_activation) {
|
if (!_systemd_activation) {
|
||||||
if (unlink(DM_EVENT_FIFO_CLIENT) && (errno != ENOENT))
|
if (unlink(DM_EVENT_FIFO_CLIENT))
|
||||||
log_sys_debug("unlink", DM_EVENT_FIFO_CLIENT);
|
log_sys_error("unlink", DM_EVENT_FIFO_CLIENT);
|
||||||
|
|
||||||
if (unlink(DM_EVENT_FIFO_SERVER) && (errno != ENOENT))
|
if (unlink(DM_EVENT_FIFO_SERVER))
|
||||||
log_sys_debug("unlink", DM_EVENT_FIFO_SERVER);
|
log_sys_error("unlink", DM_EVENT_FIFO_SERVER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _daemonize(void)
|
static void _daemonize(void)
|
||||||
{
|
{
|
||||||
int child_status, null_fd;
|
int child_status;
|
||||||
|
int fd;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
struct rlimit rlim;
|
||||||
struct timeval tval;
|
struct timeval tval;
|
||||||
sigset_t my_sigset;
|
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);
|
sigemptyset(&my_sigset);
|
||||||
if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) {
|
if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) {
|
||||||
@@ -1998,28 +1954,33 @@ static void _daemonize(void)
|
|||||||
if (chdir("/"))
|
if (chdir("/"))
|
||||||
exit(EXIT_CHDIR_FAILURE);
|
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);
|
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();
|
setsid();
|
||||||
|
|
||||||
/* coverity[leaked_handle] 'null_fd' handle is not leaking */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _reinstate_registrations(struct dm_event_fifos *fifos)
|
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 _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 };
|
struct dm_event_daemon_message msg = { 0 };
|
||||||
char *endp, *dso_name, *dev_name, *mask, *timeout;
|
char *endp, *dso_name, *dev_name, *mask, *timeout;
|
||||||
unsigned long mask_value, timeout_value;
|
unsigned long mask_value, timeout_value;
|
||||||
@@ -2069,94 +2030,28 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _info_dmeventd(const char *name, struct dm_event_fifos *fifos)
|
static void _restart_dmeventd(void)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
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 };
|
struct dm_event_daemon_message msg = { 0 };
|
||||||
int i, count = 0;
|
int i, count = 0;
|
||||||
char *message;
|
char *message;
|
||||||
int version;
|
int version;
|
||||||
const char *e;
|
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. */
|
/* 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");
|
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");
|
fprintf(stderr, "WARNING: Could not communicate with existing dmeventd.\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@@ -2168,7 +2063,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
|
|||||||
goto bad;
|
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;
|
goto bad;
|
||||||
|
|
||||||
message = strchr(msg.data, ' ') + 1;
|
message = strchr(msg.data, ' ') + 1;
|
||||||
@@ -2192,7 +2087,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (version >= 2) {
|
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");
|
fprintf(stderr, "Failed to acquire parameters from old dmeventd.\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@@ -2212,7 +2107,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
|
|||||||
}
|
}
|
||||||
#endif
|
#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");
|
fprintf(stderr, "Old dmeventd refused to die.\n");
|
||||||
goto bad;
|
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")))
|
((e = getenv(SD_ACTIVATION_ENV_VAR_NAME)) && strcmp(e, "1")))
|
||||||
_systemd_activation = 1;
|
_systemd_activation = 1;
|
||||||
|
|
||||||
fini_fifos(fifos);
|
for (i = 0; i < 10; ++i) {
|
||||||
|
if ((access(DMEVENTD_PIDFILE, F_OK) == -1) && (errno == ENOENT))
|
||||||
/* Give a few seconds dmeventd to finish */
|
break;
|
||||||
_wait_for_new_pid();
|
usleep(10);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
fprintf(stderr, "Failed to reinstate monitoring with new instance of dmeventd.\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
fini_fifos(fifos);
|
fini_fifos(&fifos);
|
||||||
return 1;
|
exit(EXIT_SUCCESS);
|
||||||
bad:
|
bad:
|
||||||
fini_fifos(fifos);
|
fini_fifos(&fifos);
|
||||||
return 0;
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _usage(char *prog, FILE *file)
|
static void _usage(char *prog, FILE *file)
|
||||||
{
|
{
|
||||||
fprintf(file, "Usage:\n"
|
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"
|
" -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"
|
" -f Don't fork, run in the foreground\n"
|
||||||
" -h Show this help information\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"
|
" -l Log to stdout,stderr instead of syslog\n"
|
||||||
" -? Show this help information on stderr\n"
|
" -? Show this help information on stderr\n"
|
||||||
" -R Restart dmeventd\n"
|
" -R Restart dmeventd\n"
|
||||||
@@ -2265,10 +2162,6 @@ static void _usage(char *prog, FILE *file)
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
signed char opt;
|
signed char opt;
|
||||||
int debug_level = 0;
|
|
||||||
int info = 0;
|
|
||||||
int restart = 0;
|
|
||||||
int use_syslog = 1;
|
|
||||||
struct dm_event_fifos fifos = {
|
struct dm_event_fifos fifos = {
|
||||||
.client = -1,
|
.client = -1,
|
||||||
.server = -1,
|
.server = -1,
|
||||||
@@ -2276,58 +2169,39 @@ int main(int argc, char *argv[])
|
|||||||
.server_path = DM_EVENT_FIFO_SERVER
|
.server_path = DM_EVENT_FIFO_SERVER
|
||||||
};
|
};
|
||||||
time_t now, idle_exit_timeout = DMEVENTD_IDLE_EXIT_TIMEOUT;
|
time_t now, idle_exit_timeout = DMEVENTD_IDLE_EXIT_TIMEOUT;
|
||||||
|
opterr = 0;
|
||||||
|
optind = 0;
|
||||||
|
|
||||||
optopt = optind = opterr = 0;
|
while ((opt = getopt(argc, argv, "?fhVdlR")) != EOF) {
|
||||||
optarg = (char*) "";
|
|
||||||
while ((opt = getopt(argc, argv, ":?e:fhiVdlR")) != EOF) {
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
_usage(argv[0], stdout);
|
_usage(argv[0], stdout);
|
||||||
return EXIT_SUCCESS;
|
exit(EXIT_SUCCESS);
|
||||||
case '?':
|
case '?':
|
||||||
_usage(argv[0], stderr);
|
_usage(argv[0], stderr);
|
||||||
return EXIT_SUCCESS;
|
exit(EXIT_SUCCESS);
|
||||||
case 'i':
|
|
||||||
info++;
|
|
||||||
break;
|
|
||||||
case 'R':
|
case 'R':
|
||||||
restart++;
|
_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;
|
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
_foreground++;
|
_foreground++;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
debug_level++;
|
_debug_level++;
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
use_syslog = 0;
|
_use_syslog = 0;
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
printf("dmeventd version: %s\n", DM_LIB_VERSION);
|
printf("dmeventd version: %s\n", DM_LIB_VERSION);
|
||||||
return EXIT_SUCCESS;
|
exit(EXIT_SUCCESS);
|
||||||
case ':':
|
|
||||||
fprintf(stderr, "dmeventd: option -%c requires an argument.\n", optopt);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info) {
|
if (!_foreground && !_use_syslog) {
|
||||||
_foreground = 1;
|
|
||||||
use_syslog = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_foreground && !use_syslog) {
|
|
||||||
printf("WARNING: Ignoring logging to stdout, needs options -f\n");
|
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
|
* Switch to C locale to avoid reading large locale-archive file
|
||||||
* used by some glibc (on some distributions it takes over 100MB).
|
* 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))
|
if (setenv("LC_ALL", "C", 1))
|
||||||
perror("Cannot set LC_ALL to C");
|
perror("Cannot set LC_ALL to C");
|
||||||
|
|
||||||
if (info)
|
if (_restart)
|
||||||
return _info_dmeventd(argv[0], &fifos) ? EXIT_SUCCESS : EXIT_FAILURE;
|
_restart_dmeventd();
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
_systemd_activation = _systemd_handover(&fifos);
|
_systemd_activation = _systemd_handover(&fifos);
|
||||||
#endif
|
#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)
|
if (!_foreground)
|
||||||
_daemonize();
|
_daemonize();
|
||||||
|
|
||||||
if (use_syslog)
|
if (_use_syslog)
|
||||||
openlog("dmeventd", LOG_PID, LOG_DAEMON);
|
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);
|
(void) dm_prepare_selinux_context(DMEVENTD_PIDFILE, S_IFREG);
|
||||||
if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0)
|
if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0)
|
||||||
@@ -2419,9 +2285,7 @@ int main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else if (_exit_now == DM_SIGNALED_EXIT) {
|
||||||
switch (_exit_now) {
|
|
||||||
case DM_SIGNALED_EXIT:
|
|
||||||
_exit_now = DM_SCHEDULED_EXIT;
|
_exit_now = DM_SCHEDULED_EXIT;
|
||||||
/*
|
/*
|
||||||
* When '_exit_now' is set, signal has been received,
|
* When '_exit_now' is set, signal has been received,
|
||||||
@@ -2429,18 +2293,7 @@ int main(int argc, char *argv[])
|
|||||||
* threads are done processing.
|
* threads are done processing.
|
||||||
*/
|
*/
|
||||||
log_info("dmeventd received break, scheduling exit.");
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
_process_request(&fifos);
|
_process_request(&fifos);
|
||||||
_cleanup_unused_threads();
|
_cleanup_unused_threads();
|
||||||
}
|
}
|
||||||
@@ -2450,11 +2303,11 @@ int main(int argc, char *argv[])
|
|||||||
log_notice("dmeventd shutting down.");
|
log_notice("dmeventd shutting down.");
|
||||||
|
|
||||||
if (fifos.client >= 0 && close(fifos.client))
|
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))
|
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();
|
closelog();
|
||||||
|
|
||||||
_exit_dm_lib();
|
_exit_dm_lib();
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ struct dm_event_fifos {
|
|||||||
int daemon_talk(struct dm_event_fifos *fifos,
|
int daemon_talk(struct dm_event_fifos *fifos,
|
||||||
struct dm_event_daemon_message *msg, int cmd,
|
struct dm_event_daemon_message *msg, int cmd,
|
||||||
const char *dso_name, const char *dev_name,
|
const char *dso_name, const char *dev_name,
|
||||||
unsigned evmask, uint32_t timeout);
|
enum dm_event_mask evmask, uint32_t timeout);
|
||||||
int init_fifos(struct dm_event_fifos *fifos);
|
int init_fifos(struct dm_event_fifos *fifos);
|
||||||
void fini_fifos(struct dm_event_fifos *fifos);
|
void fini_fifos(struct dm_event_fifos *fifos);
|
||||||
int dm_event_get_version(struct dm_event_fifos *fifos, int *version);
|
int dm_event_get_version(struct dm_event_fifos *fifos, int *version);
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
|||||||
int daemon_talk(struct dm_event_fifos *fifos,
|
int daemon_talk(struct dm_event_fifos *fifos,
|
||||||
struct dm_event_daemon_message *msg, int cmd,
|
struct dm_event_daemon_message *msg, int cmd,
|
||||||
const char *dso_name, const char *dev_name,
|
const char *dso_name, const char *dev_name,
|
||||||
unsigned evmask, uint32_t timeout)
|
enum dm_event_mask evmask, uint32_t timeout)
|
||||||
{
|
{
|
||||||
int msg_size;
|
int msg_size;
|
||||||
memset(msg, 0, sizeof(*msg));
|
memset(msg, 0, sizeof(*msg));
|
||||||
@@ -400,16 +400,25 @@ int daemon_talk(struct dm_event_fifos *fifos,
|
|||||||
return (int32_t) msg->cmd;
|
return (int32_t) msg->cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for usable client fifo file
|
* start_daemon
|
||||||
*
|
*
|
||||||
* Returns: 2 cliant path does not exists, dmeventd should be restarted
|
* This function forks off a process (dmeventd) that will handle
|
||||||
* 1 on success, 0 otherwise
|
* the events. I am currently test opening one of the fifos to
|
||||||
|
* ensure that the daemon is running and listening... I thought
|
||||||
|
* this would be less expensive than fork/exec'ing every time.
|
||||||
|
* Perhaps there is an even quicker/better way (no, checking the
|
||||||
|
* lock file is _not_ a better way).
|
||||||
|
*
|
||||||
|
* Returns: 1 on success, 0 otherwise
|
||||||
*/
|
*/
|
||||||
static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *fifos)
|
static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
|
||||||
{
|
{
|
||||||
|
int pid, ret = 0;
|
||||||
|
int status;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
char default_dmeventd_path[] = DMEVENTD_PATH;
|
||||||
|
char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME Explicitly verify the code's requirement that client_path is secure:
|
* FIXME Explicitly verify the code's requirement that client_path is secure:
|
||||||
@@ -420,7 +429,7 @@ static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *f
|
|||||||
if ((lstat(fifos->client_path, &statbuf) < 0)) {
|
if ((lstat(fifos->client_path, &statbuf) < 0)) {
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
/* Jump ahead if fifo does not already exist. */
|
/* Jump ahead if fifo does not already exist. */
|
||||||
return 2;
|
goto start_server;
|
||||||
else {
|
else {
|
||||||
log_sys_error("stat", fifos->client_path);
|
log_sys_error("stat", fifos->client_path);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -446,14 +455,12 @@ static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *f
|
|||||||
log_error("%s is no longer a secure root-owned fifo with mode 0600.", fifos->client_path);
|
log_error("%s is no longer a secure root-owned fifo with mode 0600.", fifos->client_path);
|
||||||
if (close(fifos->client))
|
if (close(fifos->client))
|
||||||
log_sys_debug("close", fifos->client_path);
|
log_sys_debug("close", fifos->client_path);
|
||||||
fifos->client = -1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* server is running and listening */
|
/* server is running and listening */
|
||||||
if (close(fifos->client))
|
if (close(fifos->client))
|
||||||
log_sys_debug("close", fifos->client_path);
|
log_sys_debug("close", fifos->client_path);
|
||||||
fifos->client = -1;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (errno != ENXIO && errno != ENOENT) {
|
if (errno != ENXIO && errno != ENOENT) {
|
||||||
@@ -462,36 +469,9 @@ static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *f
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 2;
|
start_server:
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* start_daemon
|
|
||||||
*
|
|
||||||
* This function forks off a process (dmeventd) that will handle
|
|
||||||
* the events. I am currently test opening one of the fifos to
|
|
||||||
* ensure that the daemon is running and listening... I thought
|
|
||||||
* this would be less expensive than fork/exec'ing every time.
|
|
||||||
* Perhaps there is an even quicker/better way (no, checking the
|
|
||||||
* lock file is _not_ a better way).
|
|
||||||
*
|
|
||||||
* Returns: 1 on success, 0 otherwise
|
|
||||||
*/
|
|
||||||
static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
|
|
||||||
{
|
|
||||||
struct stat statbuf;
|
|
||||||
char default_dmeventd_path[] = DMEVENTD_PATH;
|
|
||||||
char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
|
|
||||||
int pid, ret = 0;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
switch (_check_for_usable_fifos(dmeventd_path, fifos)) {
|
|
||||||
case 0: return_0;
|
|
||||||
case 1: return 1; /* Already running dmeventd */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* server is not running */
|
/* server is not running */
|
||||||
|
|
||||||
if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
|
if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
|
||||||
log_sys_error("stat", args[0]);
|
log_sys_error("stat", args[0]);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -512,17 +492,8 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
|
|||||||
strerror(errno));
|
strerror(errno));
|
||||||
else if (WEXITSTATUS(status))
|
else if (WEXITSTATUS(status))
|
||||||
log_error("Unable to start dmeventd.");
|
log_error("Unable to start dmeventd.");
|
||||||
else {
|
else
|
||||||
/* Loop here till forked dmeventd is serving fifos */
|
ret = 1;
|
||||||
for (ret = 100; ret > 0; --ret)
|
|
||||||
switch (_check_for_usable_fifos(dmeventd_path, fifos)) {
|
|
||||||
case 0: return_0;
|
|
||||||
case 1: return 1;
|
|
||||||
case 2: usleep(1000); break;
|
|
||||||
}
|
|
||||||
/* ret == 0 */
|
|
||||||
log_error("Dmeventd is not serving fifos.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -542,7 +513,7 @@ int init_fifos(struct dm_event_fifos *fifos)
|
|||||||
/* Lock out anyone else trying to do communication with the daemon. */
|
/* Lock out anyone else trying to do communication with the daemon. */
|
||||||
if (flock(fifos->server, LOCK_EX) < 0) {
|
if (flock(fifos->server, LOCK_EX) < 0) {
|
||||||
log_sys_error("flock", fifos->server_path);
|
log_sys_error("flock", fifos->server_path);
|
||||||
goto bad_no_unlock;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/
|
/* if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/
|
||||||
@@ -553,9 +524,6 @@ int init_fifos(struct dm_event_fifos *fifos)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
bad:
|
bad:
|
||||||
if (flock(fifos->server, LOCK_UN))
|
|
||||||
log_sys_debug("flock unlock", fifos->server_path);
|
|
||||||
bad_no_unlock:
|
|
||||||
if (close(fifos->server))
|
if (close(fifos->server))
|
||||||
log_sys_debug("close", fifos->server_path);
|
log_sys_debug("close", fifos->server_path);
|
||||||
fifos->server = -1;
|
fifos->server = -1;
|
||||||
@@ -584,8 +552,6 @@ void fini_fifos(struct dm_event_fifos *fifos)
|
|||||||
if (close(fifos->server))
|
if (close(fifos->server))
|
||||||
log_sys_debug("close", fifos->server_path);
|
log_sys_debug("close", fifos->server_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
fifos->client = fifos->server = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get uuid of a device */
|
/* Get uuid of a device */
|
||||||
@@ -754,7 +720,7 @@ static char *_fetch_string(char **src, const int delimiter)
|
|||||||
|
|
||||||
/* Parse a device message from the daemon. */
|
/* Parse a device message from the daemon. */
|
||||||
static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||||
char **uuid, unsigned *evmask)
|
char **uuid, enum dm_event_mask *evmask)
|
||||||
{
|
{
|
||||||
char *id;
|
char *id;
|
||||||
char *p = msg->data;
|
char *p = msg->data;
|
||||||
@@ -779,7 +745,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
const char *uuid = NULL;
|
const char *uuid = NULL;
|
||||||
char *reply_dso = NULL, *reply_uuid = NULL;
|
char *reply_dso = NULL, *reply_uuid = NULL;
|
||||||
unsigned reply_mask = 0;
|
enum dm_event_mask reply_mask = 0;
|
||||||
struct dm_task *dmt = NULL;
|
struct dm_task *dmt = NULL;
|
||||||
struct dm_event_daemon_message msg = { 0 };
|
struct dm_event_daemon_message msg = { 0 };
|
||||||
struct dm_info info;
|
struct dm_info info;
|
||||||
@@ -878,7 +844,6 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
|||||||
int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
|
int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
|
||||||
char *p;
|
char *p;
|
||||||
struct dm_event_daemon_message msg = { 0 };
|
struct dm_event_daemon_message msg = { 0 };
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0))
|
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -886,17 +851,13 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
|
|||||||
*version = 0;
|
*version = 0;
|
||||||
|
|
||||||
if (!p || !(p = strchr(p, ' '))) /* Message ID */
|
if (!p || !(p = strchr(p, ' '))) /* Message ID */
|
||||||
goto out;
|
return 0;
|
||||||
if (!(p = strchr(p + 1, ' '))) /* HELLO */
|
if (!(p = strchr(p + 1, ' '))) /* HELLO */
|
||||||
goto out;
|
return 0;
|
||||||
if ((p = strchr(p + 1, ' '))) /* HELLO, once more */
|
if ((p = strchr(p + 1, ' '))) /* HELLO, once more */
|
||||||
*version = atoi(p);
|
*version = atoi(p);
|
||||||
|
|
||||||
ret = 1;
|
return 1;
|
||||||
out:
|
|
||||||
free(msg.data);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dm_event_log_set(int debug_log_level, int use_syslog)
|
void dm_event_log_set(int debug_log_level, int use_syslog)
|
||||||
@@ -911,11 +872,11 @@ void dm_event_log(const char *subsys, int level, const char *file,
|
|||||||
{
|
{
|
||||||
static int _abort_on_internal_errors = -1;
|
static int _abort_on_internal_errors = -1;
|
||||||
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static long long _start = 0;
|
static time_t start = 0;
|
||||||
const char *indent = "";
|
const char *indent = "";
|
||||||
FILE *stream = log_stderr(level) ? stderr : stdout;
|
FILE *stream = log_stderr(level) ? stderr : stdout;
|
||||||
int prio;
|
int prio;
|
||||||
long long now, now_nsec;
|
time_t now;
|
||||||
int log_with_debug = 0;
|
int log_with_debug = 0;
|
||||||
|
|
||||||
if (subsys[0] == '#') {
|
if (subsys[0] == '#') {
|
||||||
@@ -962,28 +923,17 @@ void dm_event_log(const char *subsys, int level, const char *file,
|
|||||||
if (_use_syslog) {
|
if (_use_syslog) {
|
||||||
vsyslog(prio, format, ap);
|
vsyslog(prio, format, ap);
|
||||||
} else {
|
} else {
|
||||||
if (_debug_level) {
|
now = time(NULL);
|
||||||
#define _NSEC_PER_SEC (1000000000LL)
|
if (!start)
|
||||||
#ifdef HAVE_REALTIME
|
start = now;
|
||||||
struct timespec mono_time = { 0 };
|
now -= start;
|
||||||
if (clock_gettime(CLOCK_MONOTONIC, &mono_time) == 0)
|
if (_debug_level)
|
||||||
now = mono_time.tv_sec * _NSEC_PER_SEC + mono_time.tv_nsec;
|
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
|
||||||
else
|
(int)now / 60, (int)now % 60,
|
||||||
#endif
|
|
||||||
now = time(NULL) * _NSEC_PER_SEC;
|
|
||||||
|
|
||||||
if (!_start)
|
|
||||||
_start = now;
|
|
||||||
now -= _start;
|
|
||||||
now_nsec = now %_NSEC_PER_SEC;
|
|
||||||
now /= _NSEC_PER_SEC;
|
|
||||||
fprintf(stream, "[%2lld:%02lld.%06lld] %8x:%-6s%s",
|
|
||||||
now / 60, now % 60, now_nsec / 1000,
|
|
||||||
// TODO: Maybe use shorter ID
|
// TODO: Maybe use shorter ID
|
||||||
// ((int)(pthread_self()) >> 6) & 0xffff,
|
// ((int)(pthread_self()) >> 6) & 0xffff,
|
||||||
(int)pthread_self(), subsys,
|
(int)pthread_self(), subsys,
|
||||||
(_debug_level > 3) ? "" : indent);
|
(_debug_level > 3) ? "" : indent);
|
||||||
}
|
|
||||||
if (_debug_level > 3)
|
if (_debug_level > 3)
|
||||||
fprintf(stream, "%28s:%4d %s", file, line, indent);
|
fprintf(stream, "%28s:%4d %s", file, line, indent);
|
||||||
vfprintf(stream, _(format), ap);
|
vfprintf(stream, _(format), ap);
|
||||||
|
|||||||
@@ -123,7 +123,6 @@ struct dm_pool *dmeventd_lvm2_pool(void)
|
|||||||
|
|
||||||
int dmeventd_lvm2_run(const char *cmdline)
|
int dmeventd_lvm2_run(const char *cmdline)
|
||||||
{
|
{
|
||||||
/* coverity[missing_lock] no locking for run part */
|
|
||||||
return (lvm2_run(_lvm_handle, cmdline) == LVM2_COMMAND_SUCCEEDED);
|
return (lvm2_run(_lvm_handle, cmdline) == LVM2_COMMAND_SUCCEEDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,14 +51,18 @@ include $(top_builddir)/make.tmpl
|
|||||||
|
|
||||||
.PHONY: install_lvmdbusd
|
.PHONY: install_lvmdbusd
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(Q) test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
|
||||||
|
|
||||||
install_lvmdbusd: $(LVMDBUSD)
|
install_lvmdbusd: $(LVMDBUSD)
|
||||||
$(SHOW) " [INSTALL] $<"
|
@echo " [INSTALL] $<"
|
||||||
$(Q) $(INSTALL_DIR) $(sbindir)
|
$(Q) $(INSTALL_DIR) $(sbindir)
|
||||||
$(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
$(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
||||||
$(Q) $(INSTALL_DIR) $(lvmdbusdir) $(lvmdbusdir)/__pycache__
|
$(Q) $(INSTALL_DIR) $(lvmdbusdir)
|
||||||
$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(lvmdbusdir))
|
$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(lvmdbusdir))
|
||||||
$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir)
|
$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir)
|
||||||
$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbuspydir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
|
$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbuspydir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
|
||||||
|
$(Q) $(CHMOD) 755 $(lvmdbusdir)/__pycache__
|
||||||
$(Q) $(CHMOD) 444 $(lvmdbusdir)/__pycache__/*.py[co]
|
$(Q) $(CHMOD) 444 $(lvmdbusdir)/__pycache__/*.py[co]
|
||||||
|
|
||||||
install_lvm2: install_lvmdbusd
|
install_lvm2: install_lvmdbusd
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ class AutomatedProperties(dbus.service.Object):
|
|||||||
|
|
||||||
def set_interface(self, interface):
|
def set_interface(self, interface):
|
||||||
"""
|
"""
|
||||||
With inheritance, we can't easily tell what interfaces a class provides,
|
With inheritance we can't easily tell what interfaces a class provides
|
||||||
so we will have each class that implements an interface tell the
|
so we will have each class that implements an interface tell the
|
||||||
base AutomatedProperties what it is they do provide. This is kind of
|
base AutomatedProperties what it is they do provide. This is kind of
|
||||||
clunky, and perhaps we can figure out a better way to do this later.
|
clunky and perhaps we can figure out a better way to do this later.
|
||||||
:param interface: An interface the object supports
|
:param interface: An interface the object supports
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
@@ -88,6 +88,7 @@ class AutomatedProperties(dbus.service.Object):
|
|||||||
cb, cbe, False)
|
cb, cbe, False)
|
||||||
cfg.worker_q.put(r)
|
cfg.worker_q.put(r)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_all_prop(obj, interface_name):
|
def _get_all_prop(obj, interface_name):
|
||||||
if interface_name in obj.interface(True):
|
if interface_name in obj.interface(True):
|
||||||
|
|||||||
@@ -7,13 +7,16 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import subprocess
|
||||||
from . import cfg
|
from . import cfg
|
||||||
from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm
|
from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm
|
||||||
import dbus
|
import dbus
|
||||||
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
|
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
|
||||||
|
mt_async_call
|
||||||
from .request import RequestEntry
|
from .request import RequestEntry
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
def pv_move_lv_cmd(move_options, lv_full_name,
|
def pv_move_lv_cmd(move_options, lv_full_name,
|
||||||
@@ -62,15 +65,18 @@ def _move_callback(job_state, line_str):
|
|||||||
def _move_merge(interface_name, command, job_state):
|
def _move_merge(interface_name, command, job_state):
|
||||||
# We need to execute these command stand alone by forking & exec'ing
|
# We need to execute these command stand alone by forking & exec'ing
|
||||||
# the command always as we will be getting periodic output from them on
|
# the command always as we will be getting periodic output from them on
|
||||||
# the status of the long-running operation.
|
# the status of the long running operation.
|
||||||
|
|
||||||
meta = LvmExecutionMeta(time.time(), 0, command)
|
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
|
||||||
cfg.flightrecorder.add(meta)
|
cfg.blackbox.add(meta)
|
||||||
|
|
||||||
ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
|
ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
|
||||||
cb_data=job_state)
|
cb_data=job_state)
|
||||||
ended = time.time()
|
|
||||||
meta.completed(ended, ec, stdout, stderr)
|
with meta.lock:
|
||||||
|
meta.ended = time.time()
|
||||||
|
meta.ec = ec
|
||||||
|
meta.stderr_txt = stderr
|
||||||
|
|
||||||
if ec == 0:
|
if ec == 0:
|
||||||
job_state.Percent = 100
|
job_state.Percent = 100
|
||||||
|
|||||||
@@ -11,18 +11,11 @@ import os
|
|||||||
import multiprocessing
|
import multiprocessing
|
||||||
import queue
|
import queue
|
||||||
import itertools
|
import itertools
|
||||||
from lvmdbusd.utils import LvmDebugData
|
|
||||||
|
|
||||||
from lvmdbusd import path
|
from lvmdbusd import path
|
||||||
|
|
||||||
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
|
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
|
||||||
|
|
||||||
LOCK_FILE = os.getenv("LVM_DBUSD_LOCKFILE", "/var/lock/lvm/lvmdbusd")
|
|
||||||
|
|
||||||
# Save off the debug data needed for lvm team to debug issues
|
|
||||||
# only used for 'fullreport' at this time.
|
|
||||||
lvmdebug = LvmDebugData(os.getenv('LVM_DBUSD_COLLECT_LVM_DEBUG', False))
|
|
||||||
|
|
||||||
# This is the global object manager
|
# This is the global object manager
|
||||||
om = None
|
om = None
|
||||||
|
|
||||||
@@ -32,13 +25,13 @@ bus = None
|
|||||||
# Command line args
|
# Command line args
|
||||||
args = None
|
args = None
|
||||||
|
|
||||||
# Set to true if we depend on external events for updates
|
# Set to true if we are depending on external events for updates
|
||||||
got_external_event = False
|
got_external_event = False
|
||||||
|
|
||||||
# Shared state variable across all processes
|
# Shared state variable across all processes
|
||||||
run = multiprocessing.Value('i', 1)
|
run = multiprocessing.Value('i', 1)
|
||||||
|
|
||||||
# If this is set to true, the current setup support lvm shell, and we are
|
# If this is set to true, the current setup support lvm shell and we are
|
||||||
# running in that mode of operation
|
# running in that mode of operation
|
||||||
SHELL_IN_USE = None
|
SHELL_IN_USE = None
|
||||||
|
|
||||||
@@ -50,11 +43,6 @@ worker_q = queue.Queue()
|
|||||||
# Main event loop
|
# Main event loop
|
||||||
loop = None
|
loop = None
|
||||||
|
|
||||||
G_LOOP_TMO = 0.5
|
|
||||||
|
|
||||||
# Used to instruct the daemon if we should ignore SIGTERM
|
|
||||||
ignore_sigterm = False
|
|
||||||
|
|
||||||
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
|
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
|
||||||
BASE_INTERFACE = 'com.redhat.lvmdbus1'
|
BASE_INTERFACE = 'com.redhat.lvmdbus1'
|
||||||
PV_INTERFACE = BASE_INTERFACE + '.Pv'
|
PV_INTERFACE = BASE_INTERFACE + '.Pv'
|
||||||
@@ -102,14 +90,11 @@ vdo_support = False
|
|||||||
db = None
|
db = None
|
||||||
|
|
||||||
# lvm flight recorder
|
# lvm flight recorder
|
||||||
flightrecorder = None
|
blackbox = None
|
||||||
|
|
||||||
# RequestEntry ctor
|
# RequestEntry ctor
|
||||||
create_request_entry = None
|
create_request_entry = None
|
||||||
|
|
||||||
# Circular debug log
|
|
||||||
debug = None
|
|
||||||
|
|
||||||
|
|
||||||
def exit_daemon():
|
def exit_daemon():
|
||||||
"""
|
"""
|
||||||
@@ -119,6 +104,3 @@ def exit_daemon():
|
|||||||
if run and loop:
|
if run and loop:
|
||||||
run.value = 0
|
run.value = 0
|
||||||
loop.quit()
|
loop.quit()
|
||||||
|
|
||||||
|
|
||||||
systemd = False
|
|
||||||
|
|||||||
@@ -6,18 +6,19 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
import errno
|
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
import select
|
import select
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
import collections
|
import collections
|
||||||
|
import traceback
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from lvmdbusd import cfg
|
from lvmdbusd import cfg
|
||||||
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
|
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
|
||||||
make_non_block, read_decoded, extract_stack_trace, LvmBug, add_config_option, get_error_msg
|
make_non_block, read_decoded
|
||||||
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
|
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -25,6 +26,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
SEP = '{|}'
|
||||||
|
|
||||||
total_time = 0.0
|
total_time = 0.0
|
||||||
total_count = 0
|
total_count = 0
|
||||||
@@ -36,7 +38,7 @@ cmd_lock = threading.RLock()
|
|||||||
|
|
||||||
class LvmExecutionMeta(object):
|
class LvmExecutionMeta(object):
|
||||||
|
|
||||||
def __init__(self, start, ended, cmd, ec=-1000, stdout_txt=None, stderr_txt=None):
|
def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
|
||||||
self.lock = threading.RLock()
|
self.lock = threading.RLock()
|
||||||
self.start = start
|
self.start = start
|
||||||
self.ended = ended
|
self.ended = ended
|
||||||
@@ -47,49 +49,32 @@ class LvmExecutionMeta(object):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if self.ended == 0:
|
return "EC= %d for %s\n" \
|
||||||
ended_txt = "still running"
|
"STARTED: %f, ENDED: %f\n" \
|
||||||
self.ended = time.time()
|
|
||||||
else:
|
|
||||||
ended_txt = str(time.ctime(self.ended))
|
|
||||||
|
|
||||||
return 'EC= %d for "%s"\n' \
|
|
||||||
"STARTED: %s, ENDED: %s, DURATION: %f\n" \
|
|
||||||
"STDOUT=%s\n" \
|
"STDOUT=%s\n" \
|
||||||
"STDERR=%s\n" % \
|
"STDERR=%s\n" % \
|
||||||
(self.ec, " ".join(self.cmd), time.ctime(self.start), ended_txt, float(self.ended) - self.start,
|
(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
|
||||||
self.stdout_txt,
|
|
||||||
self.stderr_txt)
|
self.stderr_txt)
|
||||||
|
|
||||||
def completed(self, end_time, ec, stdout_txt, stderr_txt):
|
|
||||||
with self.lock:
|
|
||||||
self.ended = end_time
|
|
||||||
self.ec = ec
|
|
||||||
self.stdout_txt = stdout_txt
|
|
||||||
self.stderr_txt = stderr_txt
|
|
||||||
|
|
||||||
|
|
||||||
class LvmFlightRecorder(object):
|
class LvmFlightRecorder(object):
|
||||||
|
|
||||||
def __init__(self, size=16):
|
def __init__(self, size=16):
|
||||||
self.queue = collections.deque(maxlen=size)
|
self.queue = collections.deque(maxlen=size)
|
||||||
self.lock = threading.RLock()
|
|
||||||
|
|
||||||
def add(self, lvm_exec_meta):
|
def add(self, lvm_exec_meta):
|
||||||
with self.lock:
|
|
||||||
self.queue.append(lvm_exec_meta)
|
self.queue.append(lvm_exec_meta)
|
||||||
|
|
||||||
def dump(self):
|
def dump(self):
|
||||||
with self.lock:
|
with cmd_lock:
|
||||||
if len(self.queue):
|
if len(self.queue):
|
||||||
log_error("LVM dbus flight recorder START (in order of newest to oldest)")
|
log_error("LVM dbus flight recorder START")
|
||||||
for c in reversed(self.queue):
|
for c in reversed(self.queue):
|
||||||
log_error(str(c))
|
log_error(str(c))
|
||||||
log_error("LVM dbus flight recorder END")
|
log_error("LVM dbus flight recorder END")
|
||||||
self.queue.clear()
|
|
||||||
|
|
||||||
|
|
||||||
cfg.flightrecorder = LvmFlightRecorder()
|
cfg.blackbox = LvmFlightRecorder()
|
||||||
|
|
||||||
|
|
||||||
def _debug_c(cmd, exit_code, out):
|
def _debug_c(cmd, exit_code, out):
|
||||||
@@ -109,7 +94,7 @@ def call_lvm(command, debug=False, line_cb=None,
|
|||||||
stdin, CALL MUST EXECUTE QUICKLY and not *block*
|
stdin, CALL MUST EXECUTE QUICKLY and not *block*
|
||||||
otherwise call_lvm function will fail to read
|
otherwise call_lvm function will fail to read
|
||||||
stdin/stdout. Return value of call back is ignored
|
stdin/stdout. Return value of call back is ignored
|
||||||
:param cb_data: Supplied to call back to allow caller access to
|
:param cb_data: Supplied to callback to allow caller access to
|
||||||
its own data
|
its own data
|
||||||
|
|
||||||
# Callback signature
|
# Callback signature
|
||||||
@@ -121,9 +106,6 @@ def call_lvm(command, debug=False, line_cb=None,
|
|||||||
command.insert(0, cfg.LVM_CMD)
|
command.insert(0, cfg.LVM_CMD)
|
||||||
command = add_no_notify(command)
|
command = add_no_notify(command)
|
||||||
|
|
||||||
# Ensure we get an error message when we fork & exec the lvm command line
|
|
||||||
command = add_config_option(command, "--config", 'log/command_log_selection="log_context!=''"')
|
|
||||||
|
|
||||||
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
|
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
|
||||||
env=os.environ)
|
env=os.environ)
|
||||||
|
|
||||||
@@ -133,10 +115,10 @@ def call_lvm(command, debug=False, line_cb=None,
|
|||||||
make_non_block(process.stdout)
|
make_non_block(process.stdout)
|
||||||
make_non_block(process.stderr)
|
make_non_block(process.stderr)
|
||||||
|
|
||||||
while True and cfg.run.value != 0:
|
while True:
|
||||||
try:
|
try:
|
||||||
rd_fd = [process.stdout.fileno(), process.stderr.fileno()]
|
rd_fd = [process.stdout.fileno(), process.stderr.fileno()]
|
||||||
ready = select.select(rd_fd, [], [], cfg.G_LOOP_TMO)
|
ready = select.select(rd_fd, [], [], 2)
|
||||||
|
|
||||||
for r in ready[0]:
|
for r in ready[0]:
|
||||||
if r == process.stdout.fileno():
|
if r == process.stdout.fileno():
|
||||||
@@ -151,8 +133,8 @@ def call_lvm(command, debug=False, line_cb=None,
|
|||||||
if i != -1:
|
if i != -1:
|
||||||
try:
|
try:
|
||||||
line_cb(cb_data, stdout_text[stdout_index:i])
|
line_cb(cb_data, stdout_text[stdout_index:i])
|
||||||
except BaseException as be:
|
except:
|
||||||
st = extract_stack_trace(be)
|
st = traceback.format_exc()
|
||||||
log_error("call_lvm: line_cb exception: \n %s" % st)
|
log_error("call_lvm: line_cb exception: \n %s" % st)
|
||||||
stdout_index = i + 1
|
stdout_index = i + 1
|
||||||
else:
|
else:
|
||||||
@@ -163,32 +145,13 @@ def call_lvm(command, debug=False, line_cb=None,
|
|||||||
break
|
break
|
||||||
except IOError as ioe:
|
except IOError as ioe:
|
||||||
log_debug("call_lvm:" + str(ioe))
|
log_debug("call_lvm:" + str(ioe))
|
||||||
break
|
pass
|
||||||
|
|
||||||
if process.returncode is not None:
|
if debug or process.returncode != 0:
|
||||||
cfg.lvmdebug.lvm_complete()
|
|
||||||
if debug or (process.returncode != 0 and (process.returncode != 5 and "fullreport" in command)):
|
|
||||||
_debug_c(command, process.returncode, (stdout_text, stderr_text))
|
_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
|
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"
|
|
||||||
|
|
||||||
|
|
||||||
# The actual method which gets called to invoke the lvm command, can vary
|
# The actual method which gets called to invoke the lvm command, can vary
|
||||||
# from forking a new process to using lvm shell
|
# from forking a new process to using lvm shell
|
||||||
_t_call = call_lvm
|
_t_call = call_lvm
|
||||||
@@ -202,18 +165,18 @@ def _shell_cfg():
|
|||||||
_t_call = lvm_shell.call_lvm
|
_t_call = lvm_shell.call_lvm
|
||||||
cfg.SHELL_IN_USE = lvm_shell
|
cfg.SHELL_IN_USE = lvm_shell
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception:
|
||||||
_t_call = call_lvm
|
_t_call = call_lvm
|
||||||
cfg.SHELL_IN_USE = None
|
cfg.SHELL_IN_USE = None
|
||||||
log_error("Unable to utilize lvm shell, dropping "
|
log_error(traceback.format_exc())
|
||||||
"back to fork & exec\n%s" % extract_stack_trace(e))
|
log_error("Unable to utilize lvm shell, dropping back to fork & exec")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def set_execution(shell):
|
def set_execution(shell):
|
||||||
global _t_call
|
global _t_call
|
||||||
with cmd_lock:
|
with cmd_lock:
|
||||||
# If the user requested lvm shell, and we are currently setup that
|
# If the user requested lvm shell and we are currently setup that
|
||||||
# way, just return
|
# way, just return
|
||||||
if cfg.SHELL_IN_USE and shell:
|
if cfg.SHELL_IN_USE and shell:
|
||||||
return True
|
return True
|
||||||
@@ -237,15 +200,11 @@ def time_wrapper(command, debug=False):
|
|||||||
|
|
||||||
with cmd_lock:
|
with cmd_lock:
|
||||||
start = time.time()
|
start = time.time()
|
||||||
meta = LvmExecutionMeta(start, 0, command)
|
|
||||||
# Add the partial metadata to flight recorder, so if the command hangs
|
|
||||||
# we will see what it was.
|
|
||||||
cfg.flightrecorder.add(meta)
|
|
||||||
results = _t_call(command, debug)
|
results = _t_call(command, debug)
|
||||||
ended = time.time()
|
ended = time.time()
|
||||||
total_time += (ended - start)
|
total_time += (ended - start)
|
||||||
total_count += 1
|
total_count += 1
|
||||||
meta.completed(ended, *results)
|
cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
@@ -255,7 +214,8 @@ call = time_wrapper
|
|||||||
# Default cmd
|
# Default cmd
|
||||||
# Place default arguments for every command here.
|
# Place default arguments for every command here.
|
||||||
def _dc(cmd, args):
|
def _dc(cmd, args):
|
||||||
c = [cmd, '--nosuffix', '--unbuffered', '--units', 'b']
|
c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
|
||||||
|
'--unbuffered', '--units', 'b']
|
||||||
c.extend(args)
|
c.extend(args)
|
||||||
return c
|
return c
|
||||||
|
|
||||||
@@ -324,12 +284,10 @@ def vg_rename(vg_uuid, new_name, rename_options):
|
|||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
|
|
||||||
def vg_remove(vg_id, remove_options):
|
def vg_remove(vg_name, remove_options):
|
||||||
cmd = ['vgremove']
|
cmd = ['vgremove']
|
||||||
cmd.extend(options_to_cli_args(remove_options))
|
cmd.extend(options_to_cli_args(remove_options))
|
||||||
cmd.extend(['-f', vg_id])
|
cmd.extend(['-f', vg_name])
|
||||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2175220 is preventing us from doing the following
|
|
||||||
# cmd.extend(['-f', "--select", "vg_uuid=%s" % vg_id])
|
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
|
|
||||||
@@ -623,25 +581,28 @@ def lvm_full_report_json():
|
|||||||
'--configreport', 'vg', '-o', ','.join(vg_columns),
|
'--configreport', 'vg', '-o', ','.join(vg_columns),
|
||||||
'--configreport', 'lv', '-o', ','.join(lv_columns),
|
'--configreport', 'lv', '-o', ','.join(lv_columns),
|
||||||
'--configreport', 'seg', '-o', ','.join(lv_seg_columns),
|
'--configreport', 'seg', '-o', ','.join(lv_seg_columns),
|
||||||
'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns)
|
'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns),
|
||||||
|
'--reportformat', 'json'
|
||||||
])
|
])
|
||||||
|
|
||||||
# We are running the fullreport command, we will ask lvm to output the debug
|
|
||||||
# data, so we can have the required information for lvm to debug the fullreport failures.
|
|
||||||
# Note: this is disabled by default and can be enabled with env. var.
|
|
||||||
# LVM_DBUSD_COLLECT_LVM_DEBUG=True
|
|
||||||
fn = cfg.lvmdebug.setup()
|
|
||||||
if fn is not None:
|
|
||||||
add_config_option(cmd, "--config", "log {level=7 file=%s syslog=0}" % fn)
|
|
||||||
|
|
||||||
rc, out, err = call(cmd)
|
rc, out, err = call(cmd)
|
||||||
# When we have an exported vg the exit code of lvs or fullreport will be 5
|
# When we have an exported vg the exit code of lvs or fullreport will be 5
|
||||||
if rc == 0 or rc == 5:
|
if rc == 0 or rc == 5:
|
||||||
if type(out) != dict:
|
# With the current implementation, if we are using the shell then we
|
||||||
raise LvmBug("lvm likely returned invalid JSON, lvm exit code = %d, output = %s, err= %s" %
|
# are using JSON and JSON is returned back to us as it was parsed to
|
||||||
(rc, str(out), str(err)))
|
# figure out if we completed OK or not
|
||||||
|
if cfg.SHELL_IN_USE:
|
||||||
|
assert(type(out) == dict)
|
||||||
return out
|
return out
|
||||||
raise LvmBug("'fullreport' exited with code '%d'" % rc)
|
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_resize(device, size_bytes, create_options):
|
def pv_resize(device, size_bytes, create_options):
|
||||||
@@ -787,10 +748,6 @@ def activate_deactivate(op, name, activate, control_flags, options):
|
|||||||
if (1 << 5) & control_flags:
|
if (1 << 5) & control_flags:
|
||||||
cmd.append('--ignoreactivationskip')
|
cmd.append('--ignoreactivationskip')
|
||||||
|
|
||||||
# Shared locking (Cluster)
|
|
||||||
if (1 << 6) & control_flags:
|
|
||||||
op += 's'
|
|
||||||
|
|
||||||
if activate:
|
if activate:
|
||||||
op += 'y'
|
op += 'y'
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
import errno
|
|
||||||
|
|
||||||
from .pv import load_pvs
|
from .pv import load_pvs
|
||||||
from .vg import load_vgs
|
from .vg import load_vgs
|
||||||
from .lv import load_lvs
|
from .lv import load_lvs
|
||||||
from . import cfg
|
from . import cfg
|
||||||
from .utils import MThreadRunner, log_debug, log_error, LvmBug, extract_stack_trace
|
from .utils import MThreadRunner, log_debug, log_error
|
||||||
import threading
|
import threading
|
||||||
import queue
|
import queue
|
||||||
import time
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
def _main_thread_load(refresh=True, emit_signal=True):
|
def _main_thread_load(refresh=True, emit_signal=True):
|
||||||
@@ -120,125 +120,89 @@ class StateUpdate(object):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def update_thread(obj):
|
def update_thread(obj):
|
||||||
exception_count = 0
|
exception_count = 0
|
||||||
|
|
||||||
queued_requests = []
|
queued_requests = []
|
||||||
|
|
||||||
def set_results(val):
|
|
||||||
nonlocal queued_requests
|
|
||||||
for idx in queued_requests:
|
|
||||||
idx.set_result(val)
|
|
||||||
# Only clear out the requests after we have given them a result
|
|
||||||
# otherwise we can orphan the waiting threads, and they never
|
|
||||||
# wake up if we get an exception
|
|
||||||
queued_requests = []
|
|
||||||
|
|
||||||
def bailing(rv):
|
|
||||||
set_results(rv)
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
item = obj.queue.get(False)
|
|
||||||
item.set_result(rv)
|
|
||||||
except queue.Empty:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _load_args(requests):
|
|
||||||
"""
|
|
||||||
If we have multiple requests in the queue, they might not all have the same options. If any of the requests
|
|
||||||
have an option set we need to honor it.
|
|
||||||
"""
|
|
||||||
refresh = any([r.refresh for r in requests])
|
|
||||||
emit_signal = any([r.emit_signal for r in requests])
|
|
||||||
cache_refresh = any([r.cache_refresh for r in requests])
|
|
||||||
log = any([r.log for r in requests])
|
|
||||||
need_main_thread = any([r.need_main_thread for r in requests])
|
|
||||||
|
|
||||||
return refresh, emit_signal, cache_refresh, log, need_main_thread
|
|
||||||
|
|
||||||
def _drain_queue(queued, incoming):
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
queued.append(incoming.get(block=False))
|
|
||||||
except queue.Empty:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _handle_error():
|
|
||||||
nonlocal exception_count
|
|
||||||
exception_count += 1
|
|
||||||
|
|
||||||
if exception_count >= 5:
|
|
||||||
log_error("Too many errors in update_thread, exiting daemon")
|
|
||||||
cfg.debug.dump()
|
|
||||||
cfg.flightrecorder.dump()
|
|
||||||
bailing(errno.EFAULT)
|
|
||||||
cfg.exit_daemon()
|
|
||||||
else:
|
|
||||||
# Slow things down when encountering errors
|
|
||||||
cfg.lvmdebug.complete()
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
while cfg.run.value != 0:
|
while cfg.run.value != 0:
|
||||||
# noinspection PyBroadException
|
# noinspection PyBroadException
|
||||||
try:
|
try:
|
||||||
|
refresh = True
|
||||||
|
emit_signal = True
|
||||||
|
cache_refresh = True
|
||||||
|
log = True
|
||||||
|
need_main_thread = True
|
||||||
|
|
||||||
with obj.lock:
|
with obj.lock:
|
||||||
wait = not obj.deferred
|
wait = not obj.deferred
|
||||||
obj.deferred = False
|
obj.deferred = False
|
||||||
|
|
||||||
if len(queued_requests) == 0 and wait:
|
if len(queued_requests) == 0 and wait:
|
||||||
# Note: If we don't have anything for N seconds we will
|
queued_requests.append(obj.queue.get(True, 2))
|
||||||
# get a queue.Empty exception raised here
|
|
||||||
queued_requests.append(obj.queue.get(block=True, timeout=cfg.G_LOOP_TMO))
|
|
||||||
|
|
||||||
# Ok we have one or the deferred queue has some,
|
# Ok we have one or the deferred queue has some,
|
||||||
# check if any others and grab them too
|
# check if any others
|
||||||
_drain_queue(queued_requests, obj.queue)
|
try:
|
||||||
|
while True:
|
||||||
|
queued_requests.append(obj.queue.get(False))
|
||||||
|
|
||||||
|
except queue.Empty:
|
||||||
|
pass
|
||||||
|
|
||||||
if len(queued_requests) > 1:
|
if len(queued_requests) > 1:
|
||||||
log_debug("Processing %d updates!" % len(queued_requests),
|
log_debug("Processing %d updates!" % len(queued_requests),
|
||||||
'bg_black', 'fg_light_green')
|
'bg_black', 'fg_light_green')
|
||||||
|
|
||||||
num_changes = load(*_load_args(queued_requests))
|
# We have what we can, run the update with the needed options
|
||||||
|
for i in queued_requests:
|
||||||
|
if not i.refresh:
|
||||||
|
refresh = False
|
||||||
|
if not i.emit_signal:
|
||||||
|
emit_signal = False
|
||||||
|
if not i.cache_refresh:
|
||||||
|
cache_refresh = False
|
||||||
|
if not i.log:
|
||||||
|
log = False
|
||||||
|
if not i.need_main_thread:
|
||||||
|
need_main_thread = False
|
||||||
|
|
||||||
|
num_changes = load(refresh, emit_signal, cache_refresh, log,
|
||||||
|
need_main_thread)
|
||||||
# Update is done, let everyone know!
|
# Update is done, let everyone know!
|
||||||
set_results(num_changes)
|
for i in queued_requests:
|
||||||
|
i.set_result(num_changes)
|
||||||
|
|
||||||
|
# Only clear out the requests after we have given them a result
|
||||||
|
# otherwise we can orphan the waiting threads and they never
|
||||||
|
# wake up if we get an exception
|
||||||
|
queued_requests = []
|
||||||
|
|
||||||
# We retrieved OK, clear exception count
|
# We retrieved OK, clear exception count
|
||||||
exception_count = 0
|
exception_count = 0
|
||||||
|
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
except SystemExit:
|
|
||||||
break
|
|
||||||
except LvmBug as bug:
|
|
||||||
# If a lvm bug occurred, we will dump the lvm debug data if
|
|
||||||
# we have it.
|
|
||||||
cfg.lvmdebug.dump()
|
|
||||||
log_error(str(bug))
|
|
||||||
_handle_error()
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_error("update_thread: \n%s" % extract_stack_trace(e))
|
st = traceback.format_exc()
|
||||||
_handle_error()
|
log_error("update_thread exception: \n%s" % st)
|
||||||
finally:
|
cfg.blackbox.dump()
|
||||||
cfg.lvmdebug.complete()
|
exception_count += 1
|
||||||
|
if exception_count >= 5:
|
||||||
|
for i in queued_requests:
|
||||||
|
i.set_result(e)
|
||||||
|
|
||||||
# Make sure to unblock any that may be waiting before we exit this thread
|
log_error("Too many errors in update_thread, exiting daemon")
|
||||||
# otherwise they hang forever ...
|
cfg.exit_daemon()
|
||||||
bailing(Exception("update thread exiting"))
|
|
||||||
log_debug("update thread exiting!")
|
else:
|
||||||
|
# Slow things down when encountering errors
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.lock = threading.RLock()
|
self.lock = threading.RLock()
|
||||||
self.queue = queue.Queue()
|
self.queue = queue.Queue()
|
||||||
self.deferred = False
|
self.deferred = False
|
||||||
|
|
||||||
# Do initial load, with retries. During error injection testing we can and do fail here.
|
# Do initial load
|
||||||
count = 0
|
load(refresh=False, emit_signal=False, need_main_thread=False)
|
||||||
need_refresh = False # First attempt we are building from new, any subsequent will be true
|
|
||||||
while count < 5:
|
|
||||||
try:
|
|
||||||
load(refresh=need_refresh, emit_signal=False, need_main_thread=False)
|
|
||||||
break
|
|
||||||
except LvmBug as bug:
|
|
||||||
count += 1
|
|
||||||
need_refresh = True
|
|
||||||
log_error("We encountered an lvm bug on initial load, trying again %s" % str(bug))
|
|
||||||
|
|
||||||
self.thread = threading.Thread(target=StateUpdate.update_thread,
|
self.thread = threading.Thread(target=StateUpdate.update_thread,
|
||||||
args=(self,),
|
args=(self,),
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class WaitingClient(object):
|
|||||||
self.timer_id = GLib.timeout_add_seconds(
|
self.timer_id = GLib.timeout_add_seconds(
|
||||||
tmo, WaitingClient._timeout, self)
|
tmo, WaitingClient._timeout, self)
|
||||||
|
|
||||||
# The job finished before the timer popped, and we are being notified that
|
# The job finished before the timer popped and we are being notified that
|
||||||
# it's done
|
# it's done
|
||||||
def notify(self):
|
def notify(self):
|
||||||
with self.rlock:
|
with self.rlock:
|
||||||
@@ -71,7 +71,7 @@ class JobState(object):
|
|||||||
self._stderr = ''
|
self._stderr = ''
|
||||||
self._waiting_clients = []
|
self._waiting_clients = []
|
||||||
|
|
||||||
# This is a lvm command that is just taking too long and doesn't
|
# This is an lvm command that is just taking too long and doesn't
|
||||||
# support background operation
|
# support background operation
|
||||||
if self._request:
|
if self._request:
|
||||||
# Faking the percentage when we don't have one
|
# Faking the percentage when we don't have one
|
||||||
@@ -138,7 +138,7 @@ class JobState(object):
|
|||||||
# If a waiting client timer pops before the job is done we will allow
|
# If a waiting client timer pops before the job is done we will allow
|
||||||
# the client to remove themselves from the list. As we have a lock
|
# the client to remove themselves from the list. As we have a lock
|
||||||
# here and a lock in the waiting client too, and they can be obtained
|
# here and a lock in the waiting client too, and they can be obtained
|
||||||
# in different orders, a deadlock can occur.
|
# in different orders, a dead lock can occur.
|
||||||
# As this remove is really optional, we will try to acquire the lock
|
# As this remove is really optional, we will try to acquire the lock
|
||||||
# and remove. If we are unsuccessful it's not fatal, we just delay
|
# and remove. If we are unsuccessful it's not fatal, we just delay
|
||||||
# the time when the objects can be garbage collected by python
|
# the time when the objects can be garbage collected by python
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ def common(retrieve, o_type, search_keys,
|
|||||||
existing_paths = cfg.om.object_paths_by_type(o_type)
|
existing_paths = cfg.om.object_paths_by_type(o_type)
|
||||||
|
|
||||||
for o in objects:
|
for o in objects:
|
||||||
# Assume we need to add this one to dbus, unless we are refreshing,
|
# Assume we need to add this one to dbus, unless we are refreshing
|
||||||
# and it's already present
|
# and it's already present
|
||||||
return_object = True
|
return_object = True
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
from .automatedproperties import AutomatedProperties
|
from .automatedproperties import AutomatedProperties
|
||||||
|
|
||||||
from . import utils
|
from . import utils
|
||||||
from .utils import vg_obj_path_generate, log_error, _handle_execute, LvmBug
|
from .utils import vg_obj_path_generate, log_error, _handle_execute
|
||||||
import dbus
|
import dbus
|
||||||
from . import cmdhandler
|
from . import cmdhandler
|
||||||
from . import cfg
|
from . import cfg
|
||||||
@@ -21,12 +21,14 @@ from .utils import n, n32, d
|
|||||||
from .loader import common
|
from .loader import common
|
||||||
from .state import State
|
from .state import State
|
||||||
from . import background
|
from . import background
|
||||||
from .utils import round_size, mt_remove_dbus_objects, lvm_column_key
|
from .utils import round_size, mt_remove_dbus_objects
|
||||||
from .job import JobState
|
from .job import JobState
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
# Try and build a key for a LV, so that we sort the LVs with the least dependencies
|
|
||||||
# first. This may be error-prone because of the flexibility LVM
|
# Try and build a key for a LV, so that we sort the LVs with least dependencies
|
||||||
|
# first. This may be error prone because of the flexibility LVM
|
||||||
# provides and what you can stack.
|
# provides and what you can stack.
|
||||||
def get_key(i):
|
def get_key(i):
|
||||||
|
|
||||||
@@ -65,7 +67,6 @@ def lvs_state_retrieve(selection, cache_refresh=True):
|
|||||||
if cache_refresh:
|
if cache_refresh:
|
||||||
cfg.db.refresh()
|
cfg.db.refresh()
|
||||||
|
|
||||||
try:
|
|
||||||
# When building up the model, it's best to process LVs with the least
|
# When building up the model, it's best to process LVs with the least
|
||||||
# dependencies to those that are dependant upon other LVs. Otherwise, when
|
# dependencies to those that are dependant upon other LVs. Otherwise, when
|
||||||
# we are trying to gather information we could be in a position where we
|
# we are trying to gather information we could be in a position where we
|
||||||
@@ -133,12 +134,6 @@ def lvs_state_retrieve(selection, cache_refresh=True):
|
|||||||
n(l['lv_metadata_size']),
|
n(l['lv_metadata_size']),
|
||||||
l['move_pv'],
|
l['move_pv'],
|
||||||
l['move_pv_uuid']))
|
l['move_pv_uuid']))
|
||||||
except KeyError as ke:
|
|
||||||
# Sometimes lvm omits returning one of the keys we requested.
|
|
||||||
key = ke.args[0]
|
|
||||||
if lvm_column_key(key):
|
|
||||||
raise LvmBug("missing JSON key: '%s'" % key)
|
|
||||||
raise ke
|
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
|
|
||||||
@@ -279,15 +274,15 @@ class LvStateVdo(LvState):
|
|||||||
MetaDataPercent, CopyPercent, SyncPercent,
|
MetaDataPercent, CopyPercent, SyncPercent,
|
||||||
MetaDataSizeBytes, move_pv, move_pv_uuid,
|
MetaDataSizeBytes, move_pv, move_pv_uuid,
|
||||||
vdo_operating_mode, vdo_compression_state, vdo_index_state,
|
vdo_operating_mode, vdo_compression_state, vdo_index_state,
|
||||||
vdo_used_size, vdo_saving_percent, vdo_compression,
|
vdo_used_size,vdo_saving_percent,vdo_compression,
|
||||||
vdo_deduplication, vdo_use_metadata_hints,
|
vdo_deduplication,vdo_use_metadata_hints,
|
||||||
vdo_minimum_io_size, vdo_block_map_cache_size,
|
vdo_minimum_io_size,vdo_block_map_cache_size,
|
||||||
vdo_block_map_era_length, vdo_use_sparse_index,
|
vdo_block_map_era_length,vdo_use_sparse_index,
|
||||||
vdo_index_memory_size, vdo_slab_size, vdo_ack_threads,
|
vdo_index_memory_size,vdo_slab_size,vdo_ack_threads,
|
||||||
vdo_bio_threads, vdo_bio_rotation, vdo_cpu_threads,
|
vdo_bio_threads,vdo_bio_rotation,vdo_cpu_threads,
|
||||||
vdo_hash_zone_threads, vdo_logical_threads,
|
vdo_hash_zone_threads,vdo_logical_threads,
|
||||||
vdo_physical_threads, vdo_max_discard,
|
vdo_physical_threads,vdo_max_discard,
|
||||||
vdo_write_policy, vdo_header_size):
|
vdo_write_policy,vdo_header_size):
|
||||||
super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
|
super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
|
||||||
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
|
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
|
||||||
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
|
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
|
||||||
@@ -376,8 +371,8 @@ class LvCommon(AutomatedProperties):
|
|||||||
return dbus.Struct((self.state.Attr[index],
|
return dbus.Struct((self.state.Attr[index],
|
||||||
type_map.get(self.state.Attr[index], default)),
|
type_map.get(self.state.Attr[index], default)),
|
||||||
signature="(ss)")
|
signature="(ss)")
|
||||||
except BaseException as b:
|
except BaseException:
|
||||||
st = utils.extract_stack_trace(b)
|
st = traceback.format_exc()
|
||||||
log_error("attr_struct: \n%s" % st)
|
log_error("attr_struct: \n%s" % st)
|
||||||
return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
|
return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
|
||||||
|
|
||||||
@@ -600,7 +595,7 @@ class Lv(LvCommon):
|
|||||||
optional_size = space + 512 - remainder
|
optional_size = space + 512 - remainder
|
||||||
|
|
||||||
LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
|
LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
|
||||||
lv_name, snapshot_options, name, optional_size))
|
lv_name, snapshot_options,name, optional_size))
|
||||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||||
return cfg.om.get_object_path_by_lvm_id(full_name)
|
return cfg.om.get_object_path_by_lvm_id(full_name)
|
||||||
|
|
||||||
@@ -640,7 +635,7 @@ class Lv(LvCommon):
|
|||||||
|
|
||||||
size_change = new_size_bytes - dbo.SizeBytes
|
size_change = new_size_bytes - dbo.SizeBytes
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_resize(
|
LvCommon.handle_execute(*cmdhandler.lv_resize(
|
||||||
dbo.lvm_id, size_change, pv_dests, resize_options))
|
dbo.lvm_id, size_change,pv_dests, resize_options))
|
||||||
return "/"
|
return "/"
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -749,7 +744,7 @@ class Lv(LvCommon):
|
|||||||
cfg.worker_q.put(r)
|
cfg.worker_q.put(r)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _caching_common(method, lv_uuid, lv_name, lv_object_path, cache_options):
|
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||||
|
|
||||||
@@ -758,7 +753,7 @@ class Lv(LvCommon):
|
|||||||
|
|
||||||
if lv_to_cache:
|
if lv_to_cache:
|
||||||
fcn = lv_to_cache.lv_full_name()
|
fcn = lv_to_cache.lv_full_name()
|
||||||
rc, out, err = method(
|
rc, out, err = cmdhandler.lv_writecache_lv(
|
||||||
dbo.lv_full_name(), fcn, cache_options)
|
dbo.lv_full_name(), fcn, cache_options)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
# When we cache an LV, the cache pool and the lv that is getting
|
# When we cache an LV, the cache pool and the lv that is getting
|
||||||
@@ -778,11 +773,6 @@ class Lv(LvCommon):
|
|||||||
lv_object_path)
|
lv_object_path)
|
||||||
return lv_converted
|
return lv_converted
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
|
|
||||||
return Lv._caching_common(cmdhandler.lv_writecache_lv, lv_uuid,
|
|
||||||
lv_name, lv_object_path, cache_options)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
dbus_interface=LV_INTERFACE,
|
dbus_interface=LV_INTERFACE,
|
||||||
in_signature='oia{sv}',
|
in_signature='oia{sv}',
|
||||||
@@ -962,8 +952,33 @@ class LvCachePool(Lv):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
|
def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
|
||||||
return Lv._caching_common(cmdhandler.lv_cache_lv, lv_uuid, lv_name,
|
# Make sure we have a dbus object representing cache pool
|
||||||
lv_object_path, cache_options)
|
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||||
|
|
||||||
|
# Make sure we have dbus object representing lv to cache
|
||||||
|
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
|
||||||
|
|
||||||
|
if lv_to_cache:
|
||||||
|
fcn = lv_to_cache.lv_full_name()
|
||||||
|
rc, out, err = cmdhandler.lv_cache_lv(
|
||||||
|
dbo.lv_full_name(), fcn, cache_options)
|
||||||
|
if rc == 0:
|
||||||
|
# When we cache an LV, the cache pool and the lv that is getting
|
||||||
|
# cached need to be removed from the object manager and
|
||||||
|
# re-created as their interfaces have changed!
|
||||||
|
mt_remove_dbus_objects((dbo, lv_to_cache))
|
||||||
|
cfg.load()
|
||||||
|
|
||||||
|
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
|
||||||
|
else:
|
||||||
|
raise dbus.exceptions.DBusException(
|
||||||
|
LV_INTERFACE,
|
||||||
|
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||||
|
else:
|
||||||
|
raise dbus.exceptions.DBusException(
|
||||||
|
LV_INTERFACE, 'LV to cache with object path %s not present!' %
|
||||||
|
lv_object_path)
|
||||||
|
return lv_converted
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
dbus_interface=CACHE_POOL_INTERFACE,
|
dbus_interface=CACHE_POOL_INTERFACE,
|
||||||
|
|||||||
@@ -14,11 +14,10 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
import shlex
|
import shlex
|
||||||
import os
|
import os
|
||||||
import pty
|
import traceback
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import threading
|
|
||||||
import select
|
import select
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -27,11 +26,9 @@ except ImportError:
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
import lvmdbusd.cfg as cfg
|
from lvmdbusd.cfg import LVM_CMD
|
||||||
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
|
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
|
||||||
read_decoded, extract_stack_trace, LvmBug, get_error_msg
|
read_decoded
|
||||||
|
|
||||||
SHELL_PROMPT = "lvm> "
|
|
||||||
|
|
||||||
|
|
||||||
def _quote_arg(arg):
|
def _quote_arg(arg):
|
||||||
@@ -47,7 +44,7 @@ class LVMShellProxy(object):
|
|||||||
# up trying to get one.
|
# up trying to get one.
|
||||||
#
|
#
|
||||||
# Returns stdout, report (JSON), stderr
|
# Returns stdout, report (JSON), stderr
|
||||||
def _read_response(self, no_output=False):
|
def _read_response(self):
|
||||||
stdout = ""
|
stdout = ""
|
||||||
report = ""
|
report = ""
|
||||||
stderr = ""
|
stderr = ""
|
||||||
@@ -60,37 +57,33 @@ class LVMShellProxy(object):
|
|||||||
# a hang. Keep reading until we get the prompt back and the report
|
# a hang. Keep reading until we get the prompt back and the report
|
||||||
# FD does not contain valid JSON
|
# FD does not contain valid JSON
|
||||||
|
|
||||||
while keep_reading and cfg.run.value != 0:
|
while keep_reading:
|
||||||
try:
|
try:
|
||||||
rd_fd = [
|
rd_fd = [
|
||||||
self.parent_stdout_fd,
|
self.lvm_shell.stdout.fileno(),
|
||||||
self.report_stream.fileno(),
|
self.report_stream.fileno(),
|
||||||
self.parent_stderr_fd]
|
self.lvm_shell.stderr.fileno()]
|
||||||
ready = select.select(rd_fd, [], [], cfg.G_LOOP_TMO)
|
ready = select.select(rd_fd, [], [], 2)
|
||||||
|
|
||||||
for r in ready[0]:
|
for r in ready[0]:
|
||||||
if r == self.parent_stdout_fd:
|
if r == self.lvm_shell.stdout.fileno():
|
||||||
for line in self.parent_stdout.readlines():
|
stdout += read_decoded(self.lvm_shell.stdout)
|
||||||
stdout += line
|
|
||||||
elif r == self.report_stream.fileno():
|
elif r == self.report_stream.fileno():
|
||||||
report += read_decoded(self.report_stream)
|
report += read_decoded(self.report_stream)
|
||||||
elif r == self.parent_stderr_fd:
|
elif r == self.lvm_shell.stderr.fileno():
|
||||||
for line in self.parent_stderr.readlines():
|
stderr += read_decoded(self.lvm_shell.stderr)
|
||||||
stderr += line
|
|
||||||
|
|
||||||
# Check to see if the lvm process died on us
|
# Check to see if the lvm process died on us
|
||||||
if self.lvm_shell.poll() is not None:
|
if self.lvm_shell.poll() is not None:
|
||||||
raise Exception(self.lvm_shell.returncode, "%s" % stderr)
|
raise Exception(self.lvm_shell.returncode, "%s" % stderr)
|
||||||
|
|
||||||
if stdout.endswith(SHELL_PROMPT):
|
|
||||||
if no_output:
|
|
||||||
keep_reading = False
|
|
||||||
else:
|
|
||||||
cur_report_len = len(report)
|
cur_report_len = len(report)
|
||||||
if cur_report_len != 0:
|
if cur_report_len != 0:
|
||||||
# Only bother to parse if we have more data
|
# Only bother to parse if we have more data and the last 2 characters match expected
|
||||||
if prev_report_len != cur_report_len:
|
# complete JSON, prevents excessive JSON parsing attempts
|
||||||
|
if prev_report_len != cur_report_len and report[-2:] == "}\n":
|
||||||
prev_report_len = cur_report_len
|
prev_report_len = cur_report_len
|
||||||
|
|
||||||
# Parse the JSON if it's good we are done,
|
# Parse the JSON if it's good we are done,
|
||||||
# if not we will try to read some more.
|
# if not we will try to read some more.
|
||||||
try:
|
try:
|
||||||
@@ -99,46 +92,36 @@ class LVMShellProxy(object):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if keep_reading:
|
# As long as lvm is spewing something on one of the FDs we will
|
||||||
|
# keep trying. If we get a few timeouts with no activity, and
|
||||||
|
# we don't have valid JSON, we will raise an error.
|
||||||
|
if len(ready) == 0 and keep_reading:
|
||||||
extra_passes -= 1
|
extra_passes -= 1
|
||||||
if extra_passes <= 0:
|
if extra_passes <= 0:
|
||||||
if len(report):
|
if len(report):
|
||||||
raise LvmBug("Invalid json: %s" %
|
raise ValueError("Invalid json: %s" %
|
||||||
report)
|
report)
|
||||||
else:
|
else:
|
||||||
raise LvmBug(
|
raise ValueError(
|
||||||
"lvm returned no JSON output!")
|
"lvm returned no JSON output!")
|
||||||
except Exception as e:
|
|
||||||
log_error("While reading from lvm shell we encountered an error %s" % str(e))
|
|
||||||
log_error("stdout= %s\nstderr= %s\n" % (stdout, stderr))
|
|
||||||
if self.lvm_shell.poll() is not None:
|
|
||||||
log_error("Underlying lvm shell process unexpectedly exited: %d" % self.lvm_shell.returncode)
|
|
||||||
else:
|
|
||||||
log_error("Underlying lvm shell process is still present!")
|
|
||||||
raise e
|
|
||||||
|
|
||||||
if keep_reading and cfg.run.value == 0:
|
except IOError as ioe:
|
||||||
# We didn't complete as we are shutting down
|
log_debug(str(ioe))
|
||||||
# Try to clean up lvm shell process
|
pass
|
||||||
log_debug("exiting lvm shell as we are shutting down")
|
|
||||||
self.exit_shell()
|
|
||||||
raise SystemExit
|
|
||||||
|
|
||||||
return stdout, report_json, stderr
|
return stdout, report_json, stderr
|
||||||
|
|
||||||
def _write_cmd(self, cmd):
|
def _write_cmd(self, cmd):
|
||||||
self.parent_stdin.write(cmd)
|
cmd_bytes = bytes(cmd, "utf-8")
|
||||||
self.parent_stdin.flush()
|
num_written = self.lvm_shell.stdin.write(cmd_bytes)
|
||||||
|
assert (num_written == len(cmd_bytes))
|
||||||
|
self.lvm_shell.stdin.flush()
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Create a temp directory
|
# Create a temp directory
|
||||||
tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
|
tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
|
||||||
tmp_file = "%s/lvmdbus_report" % (tmp_dir)
|
tmp_file = "%s/lvmdbus_report" % (tmp_dir)
|
||||||
|
|
||||||
# Create a lock so that we don't step on each other when we are waiting for a command
|
|
||||||
# to finish and some other request comes in concurrently, like to exit the shell.
|
|
||||||
self.shell_lock = threading.RLock()
|
|
||||||
|
|
||||||
# Create a fifo for the report output
|
# Create a fifo for the report output
|
||||||
os.mkfifo(tmp_file, 0o600)
|
os.mkfifo(tmp_file, 0o600)
|
||||||
|
|
||||||
@@ -154,42 +137,25 @@ class LVMShellProxy(object):
|
|||||||
|
|
||||||
# If any env variables contain LVM we will propagate them too
|
# If any env variables contain LVM we will propagate them too
|
||||||
for k, v in os.environ.items():
|
for k, v in os.environ.items():
|
||||||
if "PATH" in k:
|
|
||||||
local_env[k] = v
|
|
||||||
if "LVM" in k:
|
if "LVM" in k:
|
||||||
local_env[k] = v
|
local_env[k] = v
|
||||||
|
|
||||||
self.parent_stdin_fd, child_stdin_fd = pty.openpty()
|
|
||||||
self.parent_stdout_fd, child_stdout_fd = pty.openpty()
|
|
||||||
self.parent_stderr_fd, child_stderr_fd = pty.openpty()
|
|
||||||
self.parent_stdin = os.fdopen(self.parent_stdin_fd, "w")
|
|
||||||
self.parent_stdout = os.fdopen(self.parent_stdout_fd, "r")
|
|
||||||
self.parent_stderr = os.fdopen(self.parent_stderr_fd, "r")
|
|
||||||
|
|
||||||
# run the lvm shell
|
# run the lvm shell
|
||||||
self.lvm_shell = subprocess.Popen(
|
self.lvm_shell = subprocess.Popen(
|
||||||
[cfg.LVM_CMD],
|
[LVM_CMD],
|
||||||
stdin=child_stdin_fd,
|
stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env,
|
||||||
stdout=child_stdout_fd, env=local_env,
|
stderr=subprocess.PIPE, close_fds=True, pass_fds=(lvm_fd,), shell=False)
|
||||||
stderr=child_stderr_fd, close_fds=True,
|
|
||||||
pass_fds=(lvm_fd,), shell=False)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
make_non_block(self.parent_stdout_fd)
|
make_non_block(self.lvm_shell.stdout)
|
||||||
make_non_block(self.parent_stderr_fd)
|
make_non_block(self.lvm_shell.stderr)
|
||||||
|
|
||||||
# Close our copies of the child FDs there were created with the fork, we don't need them open.
|
# Close our copy of the lvm_fd, child process is open in its process space
|
||||||
os.close(lvm_fd)
|
os.close(lvm_fd)
|
||||||
os.close(child_stdin_fd)
|
|
||||||
os.close(child_stdout_fd)
|
|
||||||
os.close(child_stderr_fd)
|
|
||||||
|
|
||||||
# wait for the first prompt
|
# Assume we are ready as we may not get the lvm prompt message depending on
|
||||||
log_debug("waiting for first prompt...")
|
# if we are using readline or editline.
|
||||||
errors = self._read_response(no_output=True)[2]
|
|
||||||
if errors and len(errors):
|
|
||||||
raise LvmBug(errors)
|
|
||||||
log_debug("lvm prompt read!!!")
|
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
@@ -198,11 +164,25 @@ class LVMShellProxy(object):
|
|||||||
os.unlink(tmp_file)
|
os.unlink(tmp_file)
|
||||||
os.rmdir(tmp_dir)
|
os.rmdir(tmp_dir)
|
||||||
|
|
||||||
def _get_last_log(self):
|
def get_error_msg(self):
|
||||||
# Precondition, lock is held
|
# We got an error, lets go fetch the error message
|
||||||
self._write_cmd('lastlog\n')
|
self._write_cmd('lastlog\n')
|
||||||
report_json = self._read_response()[1]
|
|
||||||
return get_error_msg(report_json)
|
# read everything from the STDOUT to the next prompt
|
||||||
|
stdout, report_json, stderr = self._read_response()
|
||||||
|
if 'log' in report_json:
|
||||||
|
error_msg = ""
|
||||||
|
# Walk the entire log array and build an error string
|
||||||
|
for log_entry in report_json['log']:
|
||||||
|
if log_entry['log_type'] == "error":
|
||||||
|
if error_msg:
|
||||||
|
error_msg += ', ' + log_entry['log_message']
|
||||||
|
else:
|
||||||
|
error_msg = log_entry['log_message']
|
||||||
|
|
||||||
|
return error_msg
|
||||||
|
|
||||||
|
return 'No error reason provided! (missing "log" section)'
|
||||||
|
|
||||||
def call_lvm(self, argv, debug=False):
|
def call_lvm(self, argv, debug=False):
|
||||||
rc = 1
|
rc = 1
|
||||||
@@ -220,7 +200,6 @@ class LVMShellProxy(object):
|
|||||||
cmd += "\n"
|
cmd += "\n"
|
||||||
|
|
||||||
# run the command by writing it to the shell's STDIN
|
# run the command by writing it to the shell's STDIN
|
||||||
with self.shell_lock:
|
|
||||||
self._write_cmd(cmd)
|
self._write_cmd(cmd)
|
||||||
|
|
||||||
# read everything from the STDOUT to the next prompt
|
# read everything from the STDOUT to the next prompt
|
||||||
@@ -231,53 +210,33 @@ class LVMShellProxy(object):
|
|||||||
ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
|
ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
|
||||||
# If we have an exported vg we get a log_ret_code == 5 when
|
# If we have an exported vg we get a log_ret_code == 5 when
|
||||||
# we do a 'fullreport'
|
# we do a 'fullreport'
|
||||||
# Note: 0 == error
|
|
||||||
if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
|
if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
|
||||||
rc = 0
|
rc = 0
|
||||||
else:
|
else:
|
||||||
# Depending on where lvm fails the command, it may not have anything
|
error_msg = self.get_error_msg()
|
||||||
# to report for "lastlog", so we need to check for a message in the
|
|
||||||
# report json too.
|
|
||||||
error_msg = self._get_last_log()
|
|
||||||
if error_msg is None:
|
|
||||||
error_msg = get_error_msg(report_json)
|
|
||||||
if error_msg is None:
|
|
||||||
error_msg = 'No error reason provided! (missing "log" section)'
|
|
||||||
|
|
||||||
if debug or rc != 0:
|
if debug or rc != 0:
|
||||||
log_error(("CMD= %s" % cmd))
|
log_error(('CMD: %s' % cmd))
|
||||||
log_error(("EC= %d" % rc))
|
log_error(("EC = %d" % rc))
|
||||||
log_error(("ERROR_MSG=\n %s\n" % error_msg))
|
log_error(("ERROR_MSG=\n %s\n" % error_msg))
|
||||||
|
|
||||||
return rc, report_json, error_msg
|
return rc, report_json, error_msg
|
||||||
|
|
||||||
def exit_shell(self):
|
def exit_shell(self):
|
||||||
with self.shell_lock:
|
|
||||||
try:
|
try:
|
||||||
if self.lvm_shell is not None:
|
|
||||||
self._write_cmd('exit\n')
|
self._write_cmd('exit\n')
|
||||||
self.lvm_shell.wait(1)
|
except Exception as e:
|
||||||
self.lvm_shell = None
|
log_error(str(e))
|
||||||
except Exception as _e:
|
|
||||||
log_error("exit_shell: %s" % (str(_e)))
|
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
# Note: When we are shutting down the daemon and the main process has already exited
|
|
||||||
# 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:
|
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()
|
self.lvm_shell.terminate()
|
||||||
child_exit_code = self.lvm_shell.wait(1)
|
except:
|
||||||
print("lvm shell process exited with %d" % child_exit_code)
|
pass
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("USING LVM BINARY: %s " % cfg.LVM_CMD)
|
print("USING LVM BINARY: %s " % LVM_CMD)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if len(sys.argv) > 1 and sys.argv[1] == "bisect":
|
if len(sys.argv) > 1 and sys.argv[1] == "bisect":
|
||||||
@@ -290,9 +249,6 @@ if __name__ == "__main__":
|
|||||||
while in_line:
|
while in_line:
|
||||||
in_line = input("lvm> ")
|
in_line = input("lvm> ")
|
||||||
if in_line:
|
if in_line:
|
||||||
if in_line == "exit":
|
|
||||||
shell.exit_shell()
|
|
||||||
sys.exit(0)
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
ret, out, err = shell.call_lvm(in_line.split())
|
ret, out, err = shell.call_lvm(in_line.split())
|
||||||
end = time.time()
|
end = time.time()
|
||||||
@@ -306,8 +262,8 @@ if __name__ == "__main__":
|
|||||||
pass
|
pass
|
||||||
except EOFError:
|
except EOFError:
|
||||||
pass
|
pass
|
||||||
except Exception as e:
|
except Exception:
|
||||||
log_error("main process exiting on exception!\n%s" % extract_stack_trace(e))
|
traceback.print_exc(file=sys.stdout)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import pprint as prettyprint
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from lvmdbusd import cmdhandler
|
from lvmdbusd import cmdhandler
|
||||||
from lvmdbusd.utils import log_debug, log_error, lvm_column_key, LvmBug
|
from lvmdbusd.utils import log_debug, log_error
|
||||||
|
|
||||||
|
|
||||||
class DataStore(object):
|
class DataStore(object):
|
||||||
@@ -58,7 +58,7 @@ class DataStore(object):
|
|||||||
c_lookup = {}
|
c_lookup = {}
|
||||||
c_pvs_in_vgs = {}
|
c_pvs_in_vgs = {}
|
||||||
|
|
||||||
# Each item in the report is a collection of information pertaining
|
# Each item item in the report is a collection of information pertaining
|
||||||
# to the vg
|
# to the vg
|
||||||
for r in _all['report']:
|
for r in _all['report']:
|
||||||
tmp_pv = []
|
tmp_pv = []
|
||||||
@@ -161,7 +161,7 @@ class DataStore(object):
|
|||||||
c_lvs = OrderedDict()
|
c_lvs = OrderedDict()
|
||||||
c_lv_full_lookup = {}
|
c_lv_full_lookup = {}
|
||||||
|
|
||||||
# Each item in the report is a collection of information pertaining
|
# Each item item in the report is a collection of information pertaining
|
||||||
# to the vg
|
# to the vg
|
||||||
for r in _all['report']:
|
for r in _all['report']:
|
||||||
# Get the lv data for this VG.
|
# Get the lv data for this VG.
|
||||||
@@ -309,7 +309,6 @@ class DataStore(object):
|
|||||||
:param log Add debug log entry/exit messages
|
:param log Add debug log entry/exit messages
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
self.num_refreshes += 1
|
self.num_refreshes += 1
|
||||||
if log:
|
if log:
|
||||||
log_debug("lvmdb - refresh entry")
|
log_debug("lvmdb - refresh entry")
|
||||||
@@ -336,11 +335,6 @@ class DataStore(object):
|
|||||||
|
|
||||||
# Create lookup table for which LV and segments are on each PV
|
# Create lookup table for which LV and segments are on each PV
|
||||||
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
|
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
|
|
||||||
|
|
||||||
if log:
|
if log:
|
||||||
log_debug("lvmdb - refresh exit")
|
log_debug("lvmdb - refresh exit")
|
||||||
@@ -360,13 +354,10 @@ class DataStore(object):
|
|||||||
return rc
|
return rc
|
||||||
|
|
||||||
def pv_missing(self, pv_uuid):
|
def pv_missing(self, pv_uuid):
|
||||||
# The uuid might not be a PV, default to false
|
|
||||||
if pv_uuid in self.pvs:
|
if pv_uuid in self.pvs:
|
||||||
if self.pvs[pv_uuid]['pv_missing'] == '':
|
if self.pvs[pv_uuid]['pv_missing'] == '':
|
||||||
return False
|
return False
|
||||||
else:
|
|
||||||
return True
|
return True
|
||||||
return False
|
|
||||||
|
|
||||||
def fetch_vgs(self, vg_name):
|
def fetch_vgs(self, vg_name):
|
||||||
if not vg_name:
|
if not vg_name:
|
||||||
@@ -437,8 +428,6 @@ class DataStore(object):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
os.environ["LC_ALL"] = "C"
|
|
||||||
os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
|
|
||||||
pp = prettyprint.PrettyPrinter(indent=4)
|
pp = prettyprint.PrettyPrinter(indent=4)
|
||||||
|
|
||||||
ds = DataStore()
|
ds = DataStore()
|
||||||
|
|||||||
@@ -22,9 +22,10 @@ from . import lvmdb
|
|||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
from .fetch import StateUpdate
|
from .fetch import StateUpdate
|
||||||
from .manager import Manager
|
from .manager import Manager
|
||||||
|
import traceback
|
||||||
import queue
|
import queue
|
||||||
from . import udevwatch
|
from . import udevwatch
|
||||||
from .utils import log_debug, log_error, log_msg, DebugMessages
|
from .utils import log_debug, log_error
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
@@ -41,7 +42,7 @@ def process_request():
|
|||||||
while cfg.run.value != 0:
|
while cfg.run.value != 0:
|
||||||
# noinspection PyBroadException
|
# noinspection PyBroadException
|
||||||
try:
|
try:
|
||||||
req = cfg.worker_q.get(True, cfg.G_LOOP_TMO)
|
req = cfg.worker_q.get(True, 5)
|
||||||
log_debug(
|
log_debug(
|
||||||
"Method start: %s with args %s (callback = %s)" %
|
"Method start: %s with args %s (callback = %s)" %
|
||||||
(str(req.method), str(req.arguments), str(req.cb)))
|
(str(req.method), str(req.arguments), str(req.cb)))
|
||||||
@@ -49,15 +50,12 @@ def process_request():
|
|||||||
log_debug("Method complete: %s" % str(req.method))
|
log_debug("Method complete: %s" % str(req.method))
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
except SystemExit:
|
except Exception:
|
||||||
break
|
st = traceback.format_exc()
|
||||||
except Exception as e:
|
|
||||||
st = utils.extract_stack_trace(e)
|
|
||||||
utils.log_error("process_request exception: \n%s" % st)
|
utils.log_error("process_request exception: \n%s" % st)
|
||||||
log_debug("process_request thread exiting!")
|
|
||||||
|
|
||||||
|
|
||||||
def check_fr_size(value):
|
def check_bb_size(value):
|
||||||
v = int(value)
|
v = int(value)
|
||||||
if v < 0:
|
if v < 0:
|
||||||
raise argparse.ArgumentTypeError(
|
raise argparse.ArgumentTypeError(
|
||||||
@@ -67,7 +65,7 @@ def check_fr_size(value):
|
|||||||
|
|
||||||
def install_signal_handlers():
|
def install_signal_handlers():
|
||||||
# Because of the glib main loop stuff the python signal handler code is
|
# Because of the glib main loop stuff the python signal handler code is
|
||||||
# apparently not usable, and we need to use the glib calls instead
|
# apparently not usable and we need to use the glib calls instead
|
||||||
signal_add = None
|
signal_add = None
|
||||||
|
|
||||||
if hasattr(GLib, 'unix_signal_add'):
|
if hasattr(GLib, 'unix_signal_add'):
|
||||||
@@ -79,13 +77,13 @@ def install_signal_handlers():
|
|||||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP, utils.handler, signal.SIGHUP)
|
signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP, utils.handler, signal.SIGHUP)
|
||||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, utils.handler, signal.SIGINT)
|
signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, utils.handler, signal.SIGINT)
|
||||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR1, utils.handler, signal.SIGUSR1)
|
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR1, utils.handler, signal.SIGUSR1)
|
||||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR2, utils.handler, signal.SIGUSR2)
|
|
||||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, utils.handler, signal.SIGTERM)
|
|
||||||
else:
|
else:
|
||||||
log_error("GLib.unix_signal_[add|add_full] are NOT available!")
|
log_error("GLib.unix_signal_[add|add_full] are NOT available!")
|
||||||
|
|
||||||
|
|
||||||
def process_args():
|
def main():
|
||||||
|
start = time.time()
|
||||||
|
# Add simple command line handling
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--udev", action='store_true',
|
"--udev", action='store_true',
|
||||||
@@ -106,15 +104,20 @@ def process_args():
|
|||||||
default=False,
|
default=False,
|
||||||
dest='use_lvm_shell')
|
dest='use_lvm_shell')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--frsize",
|
"--blackboxsize",
|
||||||
help="Size of the flight recorder (num. entries), 0 to disable (signal 12 to dump)",
|
help="Size of the black box flight recorder, 0 to disable",
|
||||||
default=10,
|
default=10,
|
||||||
type=check_fr_size,
|
type=check_bb_size,
|
||||||
dest='fr_size')
|
dest='bb_size')
|
||||||
|
|
||||||
args = parser.parse_args()
|
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
|
||||||
|
|
||||||
if not args.use_json:
|
# Ensure that we get consistent output for parsing stdout/stderr
|
||||||
|
os.environ["LC_ALL"] = "C"
|
||||||
|
|
||||||
|
cfg.args = parser.parse_args()
|
||||||
|
|
||||||
|
if not cfg.args.use_json:
|
||||||
log_error("Daemon no longer supports lvm without JSON support, exiting!")
|
log_error("Daemon no longer supports lvm without JSON support, exiting!")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
@@ -122,53 +125,16 @@ def process_args():
|
|||||||
log_error("Un-supported version of LVM, daemon requires JSON output, exiting!")
|
log_error("Un-supported version of LVM, daemon requires JSON output, exiting!")
|
||||||
sys.exit(1)
|
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.
|
|
||||||
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.create_request_entry = RequestEntry
|
cfg.create_request_entry = RequestEntry
|
||||||
|
|
||||||
# We create a flight recorder in cmdhandler too, but we replace it here
|
# We create a flight recorder in cmdhandler too, but we replace it here
|
||||||
# as the user may be specifying a different size. The default one in
|
# as the user may be specifying a different size. The default one in
|
||||||
# cmdhandler is for when we are running other code with a different main.
|
# cmdhandler is for when we are running other code with a different main.
|
||||||
cfg.flightrecorder = LvmFlightRecorder(cfg.args.fr_size)
|
cfg.blackbox = LvmFlightRecorder(cfg.args.bb_size)
|
||||||
|
|
||||||
# Create a circular buffer for debug logs
|
if cfg.args.use_lvm_shell and not cfg.args.use_json:
|
||||||
cfg.debug = DebugMessages()
|
log_error("You cannot specify --lvmshell and --nojson")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
|
log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
|
||||||
|
|
||||||
@@ -176,12 +142,15 @@ def main():
|
|||||||
# exists.
|
# exists.
|
||||||
cfg.vdo_support = supports_vdo()
|
cfg.vdo_support = supports_vdo()
|
||||||
|
|
||||||
|
if cfg.vdo_support and not cfg.args.use_json:
|
||||||
|
log_error("You cannot specify --nojson when lvm has VDO support")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# List of threads that we start up
|
# List of threads that we start up
|
||||||
thread_list = []
|
thread_list = []
|
||||||
|
|
||||||
install_signal_handlers()
|
install_signal_handlers()
|
||||||
|
|
||||||
with utils.LockFile(cfg.LOCK_FILE):
|
|
||||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||||
dbus.mainloop.glib.threads_init()
|
dbus.mainloop.glib.threads_init()
|
||||||
|
|
||||||
@@ -204,7 +173,7 @@ def main():
|
|||||||
thread_list.append(
|
thread_list.append(
|
||||||
threading.Thread(target=process_request, name='process_request'))
|
threading.Thread(target=process_request, name='process_request'))
|
||||||
|
|
||||||
# Have a single thread handling updating lvm and the dbus model, so we
|
# Have a single thread handling updating lvm and the dbus model so we
|
||||||
# don't have multiple threads doing this as the same time
|
# don't have multiple threads doing this as the same time
|
||||||
updater = StateUpdate()
|
updater = StateUpdate()
|
||||||
thread_list.append(updater.thread)
|
thread_list.append(updater.thread)
|
||||||
@@ -217,6 +186,10 @@ def main():
|
|||||||
thread.damon = True
|
thread.damon = True
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
|
# Add udev watching
|
||||||
|
if cfg.args.use_udev:
|
||||||
|
log_debug('Utilizing udev to trigger updates')
|
||||||
|
|
||||||
# In all cases we are going to monitor for udev until we get an
|
# 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
|
# ExternalEvent. In the case where we get an external event and the user
|
||||||
# didn't specify --udev we will stop monitoring udev
|
# didn't specify --udev we will stop monitoring udev
|
||||||
|
|||||||
@@ -137,8 +137,7 @@ class Manager(AutomatedProperties):
|
|||||||
"""
|
"""
|
||||||
Dump the flight recorder to syslog
|
Dump the flight recorder to syslog
|
||||||
"""
|
"""
|
||||||
cfg.debug.dump()
|
cfg.blackbox.dump()
|
||||||
cfg.flightrecorder.dump()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _lookup_by_lvm_id(key):
|
def _lookup_by_lvm_id(key):
|
||||||
@@ -195,7 +194,6 @@ class Manager(AutomatedProperties):
|
|||||||
def _external_event(command):
|
def _external_event(command):
|
||||||
utils.log_debug("Processing _external_event= %s" % command,
|
utils.log_debug("Processing _external_event= %s" % command,
|
||||||
'bg_black', 'fg_orange')
|
'bg_black', 'fg_orange')
|
||||||
cfg.got_external_event = True
|
|
||||||
cfg.load()
|
cfg.load()
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -203,6 +201,14 @@ class Manager(AutomatedProperties):
|
|||||||
in_signature='s', out_signature='i')
|
in_signature='s', out_signature='i')
|
||||||
def ExternalEvent(self, command):
|
def ExternalEvent(self, command):
|
||||||
utils.log_debug("ExternalEvent %s" % command)
|
utils.log_debug("ExternalEvent %s" % command)
|
||||||
|
# If a user didn't explicitly specify udev, we will turn it off now.
|
||||||
|
if not cfg.args.use_udev:
|
||||||
|
if udevwatch.remove():
|
||||||
|
utils.log_debug("ExternalEvent received, disabling "
|
||||||
|
"udev monitoring")
|
||||||
|
# We are dependent on external events now to stay current!
|
||||||
|
cfg.got_external_event = True
|
||||||
|
|
||||||
r = RequestEntry(
|
r = RequestEntry(
|
||||||
-1, Manager._external_event, (command,), None, None, False)
|
-1, Manager._external_event, (command,), None, None, False)
|
||||||
cfg.worker_q.put(r)
|
cfg.worker_q.put(r)
|
||||||
|
|||||||
@@ -9,11 +9,12 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
|
import traceback
|
||||||
import dbus
|
import dbus
|
||||||
import os
|
import os
|
||||||
import copy
|
import copy
|
||||||
from . import cfg
|
from . import cfg
|
||||||
from .utils import log_debug, log_error, extract_stack_trace
|
from .utils import log_debug, pv_obj_path_generate, log_error
|
||||||
from .automatedproperties import AutomatedProperties
|
from .automatedproperties import AutomatedProperties
|
||||||
|
|
||||||
|
|
||||||
@@ -39,8 +40,8 @@ class ObjectManager(AutomatedProperties):
|
|||||||
for k, v in list(obj._objects.items()):
|
for k, v in list(obj._objects.items()):
|
||||||
path, props = v[0].emit_data()
|
path, props = v[0].emit_data()
|
||||||
rc[path] = props
|
rc[path] = props
|
||||||
except Exception as e:
|
except Exception:
|
||||||
log_error("_get_managed_objects exception, bailing: \n%s" % extract_stack_trace(e))
|
traceback.print_exc(file=sys.stdout)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
@@ -52,6 +53,15 @@ class ObjectManager(AutomatedProperties):
|
|||||||
(self, ), cb, cbe, False)
|
(self, ), cb, cbe, False)
|
||||||
cfg.worker_q.put(r)
|
cfg.worker_q.put(r)
|
||||||
|
|
||||||
|
def locked(self):
|
||||||
|
"""
|
||||||
|
If some external code need to run across a number of different
|
||||||
|
calls into ObjectManager while blocking others they can use this method
|
||||||
|
to lock others out.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return ObjectManagerLock(self.rlock)
|
||||||
|
|
||||||
@dbus.service.signal(
|
@dbus.service.signal(
|
||||||
dbus_interface="org.freedesktop.DBus.ObjectManager",
|
dbus_interface="org.freedesktop.DBus.ObjectManager",
|
||||||
signature='oa{sa{sv}}')
|
signature='oa{sa{sv}}')
|
||||||
@@ -159,7 +169,7 @@ class ObjectManager(AutomatedProperties):
|
|||||||
# print('Registering object path %s for %s' %
|
# print('Registering object path %s for %s' %
|
||||||
# (path, dbus_object.lvm_id))
|
# (path, dbus_object.lvm_id))
|
||||||
|
|
||||||
# We want fast access to the object by a number of different ways,
|
# We want fast access to the object by a number of different ways
|
||||||
# so we use multiple hashs with different keys
|
# so we use multiple hashs with different keys
|
||||||
self._lookup_add(dbus_object, path, dbus_object.lvm_id,
|
self._lookup_add(dbus_object, path, dbus_object.lvm_id,
|
||||||
dbus_object.Uuid)
|
dbus_object.Uuid)
|
||||||
@@ -209,7 +219,7 @@ class ObjectManager(AutomatedProperties):
|
|||||||
|
|
||||||
def get_object_by_lvm_id(self, lvm_id):
|
def get_object_by_lvm_id(self, lvm_id):
|
||||||
"""
|
"""
|
||||||
Given a lvm identifier, return the object registered for it
|
Given an lvm identifier, return the object registered for it
|
||||||
:param lvm_id: The lvm identifier
|
:param lvm_id: The lvm identifier
|
||||||
"""
|
"""
|
||||||
with self.rlock:
|
with self.rlock:
|
||||||
@@ -220,7 +230,7 @@ class ObjectManager(AutomatedProperties):
|
|||||||
|
|
||||||
def get_object_path_by_lvm_id(self, lvm_id):
|
def get_object_path_by_lvm_id(self, lvm_id):
|
||||||
"""
|
"""
|
||||||
Given a lvm identifier, return the object path for it
|
Given an lvm identifier, return the object path for it
|
||||||
:param lvm_id: The lvm identifier
|
:param lvm_id: The lvm identifier
|
||||||
:return: Object path or '/' if not found
|
:return: Object path or '/' if not found
|
||||||
"""
|
"""
|
||||||
@@ -277,7 +287,7 @@ class ObjectManager(AutomatedProperties):
|
|||||||
register it with the object manager for the specified uuid & lvm_id.
|
register it with the object manager for the specified uuid & lvm_id.
|
||||||
Note: If path create is not None, uuid and lvm_id cannot be equal
|
Note: If path create is not None, uuid and lvm_id cannot be equal
|
||||||
:param uuid: The uuid for the lvm object we are searching for
|
:param uuid: The uuid for the lvm object we are searching for
|
||||||
:param lvm_id: The lvm name (e.g. pv device path, vg name, lv full name)
|
:param lvm_id: The lvm name (eg. pv device path, vg name, lv full name)
|
||||||
:param path_create: If not None, create the path using this function if
|
:param path_create: If not None, create the path using this function if
|
||||||
we fail to find the object by uuid or lvm_id.
|
we fail to find the object by uuid or lvm_id.
|
||||||
:returns None if lvm asset not found and path_create == None otherwise
|
:returns None if lvm asset not found and path_create == None otherwise
|
||||||
@@ -295,17 +305,18 @@ class ObjectManager(AutomatedProperties):
|
|||||||
if uuid == lvm_id:
|
if uuid == lvm_id:
|
||||||
path = self._id_lookup(lvm_id)
|
path = self._id_lookup(lvm_id)
|
||||||
else:
|
else:
|
||||||
# We have 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
|
# that they are consistent
|
||||||
|
|
||||||
# If a PV is missing its device path is '[unknown]' or some
|
# If a PV is missing it's device path is '[unknown]' or some
|
||||||
# other text derivation of unknown. When we find that a PV is
|
# other text derivation of unknown. When we find that a PV is
|
||||||
# missing we will clear out the lvm_id as it's not unique
|
# missing we will clear out the lvm_id as it's likely not unique
|
||||||
# and thus not useful and harmful for lookups.
|
# and thus not useful and potentially harmful for lookups.
|
||||||
if cfg.db.pv_missing(uuid):
|
if path_create == pv_obj_path_generate and \
|
||||||
|
cfg.db.pv_missing(uuid):
|
||||||
lvm_id = None
|
lvm_id = None
|
||||||
|
|
||||||
# Let's check for the uuid first
|
# Lets check for the uuid first
|
||||||
path = self._id_lookup(uuid)
|
path = self._id_lookup(uuid)
|
||||||
if path:
|
if path:
|
||||||
# Ensure table lookups are correct
|
# Ensure table lookups are correct
|
||||||
@@ -326,3 +337,29 @@ class ObjectManager(AutomatedProperties):
|
|||||||
# (uuid, lvm_id, str(path_create), path))
|
# (uuid, lvm_id, str(path_create), path))
|
||||||
|
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectManagerLock(object):
|
||||||
|
"""
|
||||||
|
The sole purpose of this class is to allow other code the ability to
|
||||||
|
lock the object manager using a `with` statement, eg.
|
||||||
|
|
||||||
|
with cfg.om.locked():
|
||||||
|
# Do stuff with object manager
|
||||||
|
|
||||||
|
This will ensure that the lock is always released (assuming this is done
|
||||||
|
correctly)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, recursive_lock):
|
||||||
|
self._lock = recursive_lock
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
# Acquire lock
|
||||||
|
self._lock.acquire()
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
|
def __exit__(self, e_type, e_value, e_traceback):
|
||||||
|
# Release lock
|
||||||
|
self._lock.release()
|
||||||
|
self._lock = None
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ import dbus
|
|||||||
from .cfg import PV_INTERFACE
|
from .cfg import PV_INTERFACE
|
||||||
from . import cmdhandler
|
from . import cmdhandler
|
||||||
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
|
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
|
||||||
lv_object_path_method, _handle_execute, lvm_column_key
|
lv_object_path_method, _handle_execute
|
||||||
from .loader import common
|
from .loader import common
|
||||||
from .request import RequestEntry
|
from .request import RequestEntry
|
||||||
from .state import State
|
from .state import State
|
||||||
from .utils import round_size, LvmBug
|
from .utils import round_size
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
@@ -28,7 +28,6 @@ def pvs_state_retrieve(selection, cache_refresh=True):
|
|||||||
if cache_refresh:
|
if cache_refresh:
|
||||||
cfg.db.refresh()
|
cfg.db.refresh()
|
||||||
|
|
||||||
try:
|
|
||||||
for p in cfg.db.fetch_pvs(selection):
|
for p in cfg.db.fetch_pvs(selection):
|
||||||
rc.append(
|
rc.append(
|
||||||
PvState(
|
PvState(
|
||||||
@@ -39,12 +38,6 @@ def pvs_state_retrieve(selection, cache_refresh=True):
|
|||||||
n(p["pv_ba_size"]), n(p["pe_start"]),
|
n(p["pv_ba_size"]), n(p["pe_start"]),
|
||||||
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
|
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
|
||||||
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
|
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
|
||||||
except KeyError as ke:
|
|
||||||
# Sometimes lvm omits returning one of the keys we requested.
|
|
||||||
key = ke.args[0]
|
|
||||||
if lvm_column_key(key):
|
|
||||||
raise LvmBug("missing JSON key: '%s'" % key)
|
|
||||||
raise ke
|
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,13 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import dbus
|
|
||||||
import threading
|
import threading
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
from .job import Job
|
from .job import Job
|
||||||
from . import cfg
|
from . import cfg
|
||||||
from .utils import log_error, mt_async_call, extract_stack_trace
|
import traceback
|
||||||
|
from .utils import log_error, mt_async_call
|
||||||
|
|
||||||
|
|
||||||
class RequestEntry(object):
|
class RequestEntry(object):
|
||||||
@@ -71,23 +71,13 @@ class RequestEntry(object):
|
|||||||
try:
|
try:
|
||||||
result = self.method(*self.arguments)
|
result = self.method(*self.arguments)
|
||||||
self.register_result(result)
|
self.register_result(result)
|
||||||
except SystemExit as se:
|
|
||||||
self.register_error(-1, str(se), se)
|
|
||||||
raise se
|
|
||||||
except dbus.exceptions.DBusException as dbe:
|
|
||||||
# This is an expected error path when something goes awry that
|
|
||||||
# we handled
|
|
||||||
self.register_error(-1, str(dbe), dbe)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Use the request entry to return the result as the client may
|
# Use the request entry to return the result as the client may
|
||||||
# have gotten a job by the time we hit an error
|
# have gotten a job by the time we hit an error
|
||||||
# Lets set the exception text as the error message and log the
|
# Lets get the stacktrace and set that to the error message
|
||||||
# exception in the journal for figuring out what went wrong.
|
st = traceback.format_exc()
|
||||||
cfg.debug.dump()
|
cfg.blackbox.dump()
|
||||||
cfg.flightrecorder.dump()
|
log_error("Exception returned to client: \n%s" % st)
|
||||||
tb = extract_stack_trace(e)
|
|
||||||
log_error("While processing %s: we encountered\n%s" % (str(self.method), tb))
|
|
||||||
log_error("Error returned to client: %s" % str(e))
|
|
||||||
self.register_error(-1, str(e), e)
|
self.register_error(-1, str(e), e)
|
||||||
|
|
||||||
def is_done(self):
|
def is_done(self):
|
||||||
@@ -141,7 +131,7 @@ class RequestEntry(object):
|
|||||||
|
|
||||||
mt_async_call(self.cb_error, error_exception)
|
mt_async_call(self.cb_error, error_exception)
|
||||||
else:
|
else:
|
||||||
# We have a job, and it's complete, indicate that it's done.
|
# We have a job and it's complete, indicate that it's done.
|
||||||
self._job.Complete = True
|
self._job.Complete = True
|
||||||
self._job = None
|
self._job = None
|
||||||
|
|
||||||
|
|||||||
@@ -52,29 +52,19 @@ def filter_event(action, device):
|
|||||||
# when appropriate.
|
# when appropriate.
|
||||||
refresh = False
|
refresh = False
|
||||||
|
|
||||||
# Ignore everything but change
|
|
||||||
if action != 'change':
|
|
||||||
return
|
|
||||||
|
|
||||||
if 'ID_FS_TYPE' in device:
|
if 'ID_FS_TYPE' in device:
|
||||||
fs_type_new = device['ID_FS_TYPE']
|
fs_type_new = device['ID_FS_TYPE']
|
||||||
|
|
||||||
if 'LVM' in fs_type_new:
|
if 'LVM' in fs_type_new:
|
||||||
# If we get a lvm related udev event for a block device
|
|
||||||
# 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 == '':
|
elif fs_type_new == '':
|
||||||
# Check to see if the device was one we knew about
|
# Check to see if the device was one we knew about
|
||||||
if 'DEVNAME' in device:
|
if 'DEVNAME' in device:
|
||||||
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
|
found = cfg.om.get_object_by_lvm_id(device['DEVNAME'])
|
||||||
|
if found:
|
||||||
refresh = True
|
refresh = True
|
||||||
else:
|
|
||||||
# This handles the wipefs -a path
|
if 'DM_LV_NAME' in device:
|
||||||
if not refresh and 'DEVNAME' in device:
|
|
||||||
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
|
|
||||||
refresh = True
|
refresh = True
|
||||||
|
|
||||||
if refresh:
|
if refresh:
|
||||||
|
|||||||
@@ -10,14 +10,11 @@
|
|||||||
import xml.etree.ElementTree as Et
|
import xml.etree.ElementTree as Et
|
||||||
import sys
|
import sys
|
||||||
import inspect
|
import inspect
|
||||||
import collections
|
import ctypes
|
||||||
import errno
|
|
||||||
import fcntl
|
|
||||||
import os
|
import os
|
||||||
import stat
|
|
||||||
import string
|
import string
|
||||||
import datetime
|
import datetime
|
||||||
import tempfile
|
from fcntl import fcntl, F_GETFL, F_SETFL
|
||||||
|
|
||||||
import dbus
|
import dbus
|
||||||
from lvmdbusd import cfg
|
from lvmdbusd import cfg
|
||||||
@@ -89,7 +86,7 @@ def init_class_from_arguments(
|
|||||||
nt = k
|
nt = k
|
||||||
|
|
||||||
# If the current attribute has a value, but the incoming does
|
# If the current attribute has a value, but the incoming does
|
||||||
# not, don't overwrite it. Otherwise, the default values on the
|
# not, don't overwrite it. Otherwise the default values on the
|
||||||
# property decorator don't work as expected.
|
# property decorator don't work as expected.
|
||||||
cur = getattr(obj_instance, nt, v)
|
cur = getattr(obj_instance, nt, v)
|
||||||
|
|
||||||
@@ -109,7 +106,7 @@ def init_class_from_arguments(
|
|||||||
|
|
||||||
def get_properties(f):
|
def get_properties(f):
|
||||||
"""
|
"""
|
||||||
Walks through an object instance, or it's parent class(es) and determines
|
Walks through an object instance or it's parent class(es) and determines
|
||||||
which attributes are properties and if they were created to be used for
|
which attributes are properties and if they were created to be used for
|
||||||
dbus.
|
dbus.
|
||||||
:param f: Object to inspect
|
:param f: Object to inspect
|
||||||
@@ -193,7 +190,7 @@ def add_properties(xml, interface, props):
|
|||||||
interface_element = c
|
interface_element = c
|
||||||
break
|
break
|
||||||
|
|
||||||
# Interface is not present, lets create it, so we have something to
|
# Interface is not present, lets create it so we have something to
|
||||||
# attach the properties too
|
# attach the properties too
|
||||||
if interface_element is None:
|
if interface_element is None:
|
||||||
interface_element = Et.Element("interface", name=interface)
|
interface_element = Et.Element("interface", name=interface)
|
||||||
@@ -283,64 +280,25 @@ def parse_tags(tags):
|
|||||||
return dbus.Array([], signature='s')
|
return dbus.Array([], signature='s')
|
||||||
|
|
||||||
|
|
||||||
class DebugMessages(object):
|
def _common_log(msg, *attributes):
|
||||||
|
cfg.stdout_lock.acquire()
|
||||||
|
tid = ctypes.CDLL('libc.so.6').syscall(186)
|
||||||
|
|
||||||
def __init__(self, size=5000):
|
if STDOUT_TTY:
|
||||||
self.queue = collections.deque(maxlen=size)
|
|
||||||
self.lock = threading.RLock()
|
|
||||||
|
|
||||||
def add(self, message):
|
|
||||||
with self.lock:
|
|
||||||
self.queue.append(message)
|
|
||||||
|
|
||||||
def dump(self):
|
|
||||||
if cfg.args and not cfg.args.debug:
|
|
||||||
with self.lock:
|
|
||||||
if len(self.queue):
|
|
||||||
log_error("LVM dbus debug messages START last (%d max) messages" % self.queue.maxlen)
|
|
||||||
for m in self.queue:
|
|
||||||
print(m)
|
|
||||||
log_error("LVM dbus debug messages END")
|
|
||||||
self.queue.clear()
|
|
||||||
|
|
||||||
|
|
||||||
def _get_tid():
|
|
||||||
try:
|
|
||||||
# Only 3.8 and later have this
|
|
||||||
return threading.get_native_id()
|
|
||||||
except:
|
|
||||||
return -1
|
|
||||||
|
|
||||||
|
|
||||||
def _format_log_entry(msg):
|
|
||||||
tid = _get_tid()
|
|
||||||
|
|
||||||
if not cfg.systemd and STDOUT_TTY:
|
|
||||||
msg = "%s: %d:%d - %s" % \
|
msg = "%s: %d:%d - %s" % \
|
||||||
(datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"),
|
(datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"),
|
||||||
os.getpid(), tid, msg)
|
os.getpid(), tid, msg)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if cfg.systemd:
|
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
|
||||||
# Systemd already puts the daemon pid in the log, we'll just add the tid
|
|
||||||
msg = "[%d]: %s" % (tid, msg)
|
|
||||||
else:
|
|
||||||
msg = "[%d:%d]: %s" % (os.getpid(), tid, msg)
|
|
||||||
return msg
|
|
||||||
|
|
||||||
|
|
||||||
def _common_log(msg, *attributes):
|
|
||||||
msg = _format_log_entry(msg)
|
|
||||||
|
|
||||||
cfg.stdout_lock.acquire()
|
|
||||||
|
|
||||||
if STDOUT_TTY and attributes:
|
if STDOUT_TTY and attributes:
|
||||||
print(color(msg, *attributes))
|
print(color(msg, *attributes))
|
||||||
else:
|
else:
|
||||||
print(msg)
|
print(msg)
|
||||||
|
|
||||||
sys.stdout.flush()
|
|
||||||
cfg.stdout_lock.release()
|
cfg.stdout_lock.release()
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
# Serializes access to stdout to prevent interleaved output
|
# Serializes access to stdout to prevent interleaved output
|
||||||
@@ -349,19 +307,12 @@ def _common_log(msg, *attributes):
|
|||||||
def log_debug(msg, *attributes):
|
def log_debug(msg, *attributes):
|
||||||
if cfg.args and cfg.args.debug:
|
if cfg.args and cfg.args.debug:
|
||||||
_common_log(msg, *attributes)
|
_common_log(msg, *attributes)
|
||||||
else:
|
|
||||||
if cfg.debug:
|
|
||||||
cfg.debug.add(_format_log_entry(msg))
|
|
||||||
|
|
||||||
|
|
||||||
def log_error(msg, *attributes):
|
def log_error(msg, *attributes):
|
||||||
_common_log(msg, *attributes)
|
_common_log(msg, *attributes)
|
||||||
|
|
||||||
|
|
||||||
def log_msg(msg, *attributes):
|
|
||||||
_common_log(msg, *attributes)
|
|
||||||
|
|
||||||
|
|
||||||
def dump_threads_stackframe():
|
def dump_threads_stackframe():
|
||||||
ident_to_name = {}
|
ident_to_name = {}
|
||||||
|
|
||||||
@@ -389,32 +340,15 @@ def dump_threads_stackframe():
|
|||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
def handler(signum):
|
def handler(signum):
|
||||||
try:
|
try:
|
||||||
# signal 10
|
|
||||||
if signum == signal.SIGUSR1:
|
if signum == signal.SIGUSR1:
|
||||||
cfg.debug.dump()
|
|
||||||
dump_threads_stackframe()
|
dump_threads_stackframe()
|
||||||
# signal 12
|
|
||||||
elif signum == signal.SIGUSR2:
|
|
||||||
cfg.debug.dump()
|
|
||||||
cfg.flightrecorder.dump()
|
|
||||||
else:
|
else:
|
||||||
# If we are getting a SIGTERM, and we sent one to the lvm shell we
|
|
||||||
# will ignore this and keep running.
|
|
||||||
if signum == signal.SIGTERM and cfg.ignore_sigterm:
|
|
||||||
# Clear the flag, so we will exit on SIGTERM if we didn't
|
|
||||||
# send it.
|
|
||||||
cfg.ignore_sigterm = False
|
|
||||||
return True
|
|
||||||
|
|
||||||
# If lvm shell is in use, tell it to exit
|
|
||||||
if cfg.SHELL_IN_USE is not None:
|
|
||||||
cfg.SHELL_IN_USE.exit_shell()
|
|
||||||
cfg.run.value = 0
|
cfg.run.value = 0
|
||||||
log_error('Exiting daemon with signal %d' % signum)
|
log_debug('Exiting daemon with signal %d' % signum)
|
||||||
if cfg.loop is not None:
|
if cfg.loop is not None:
|
||||||
cfg.loop.quit()
|
cfg.loop.quit()
|
||||||
except BaseException as be:
|
except:
|
||||||
st = extract_stack_trace(be)
|
st = traceback.format_exc()
|
||||||
log_error("signal handler: exception (logged, not reported!) \n %s" % st)
|
log_error("signal handler: exception (logged, not reported!) \n %s" % st)
|
||||||
|
|
||||||
# It's important we report that we handled the exception for the exception
|
# It's important we report that we handled the exception for the exception
|
||||||
@@ -543,7 +477,7 @@ def round_size(size_bytes):
|
|||||||
return size_bytes + bs - remainder
|
return size_bytes + bs - remainder
|
||||||
|
|
||||||
|
|
||||||
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_/%'
|
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_\/%'
|
||||||
_ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
|
_ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
|
||||||
|
|
||||||
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
|
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
|
||||||
@@ -638,23 +572,6 @@ def validate_tag(interface, tag):
|
|||||||
% (tag, _ALLOWABLE_TAG_CH))
|
% (tag, _ALLOWABLE_TAG_CH))
|
||||||
|
|
||||||
|
|
||||||
def add_config_option(cmdline, key, value):
|
|
||||||
if 'help' in cmdline:
|
|
||||||
return cmdline
|
|
||||||
|
|
||||||
if key in cmdline:
|
|
||||||
for i, arg in enumerate(cmdline):
|
|
||||||
if arg == key:
|
|
||||||
if len(cmdline) <= i + 1:
|
|
||||||
raise dbus.exceptions.DBusException("Missing value for --config option.")
|
|
||||||
cmdline[i + 1] += " %s" % value
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
cmdline.extend([key, value])
|
|
||||||
|
|
||||||
return cmdline
|
|
||||||
|
|
||||||
|
|
||||||
def add_no_notify(cmdline):
|
def add_no_notify(cmdline):
|
||||||
"""
|
"""
|
||||||
Given a command line to execute we will see if `--config` is present, if it
|
Given a command line to execute we will see if `--config` is present, if it
|
||||||
@@ -666,18 +583,27 @@ def add_no_notify(cmdline):
|
|||||||
:rtype: list
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Only after we have seen an external event will we disable lvm from sending
|
# Only after we have seen an external event will be disable lvm from sending
|
||||||
# us one when we call lvm
|
# us one when we call lvm
|
||||||
rv = cmdline
|
|
||||||
if cfg.got_external_event:
|
if cfg.got_external_event:
|
||||||
rv = add_config_option(rv, "--config", "global/notify_dbus=0")
|
if 'help' in cmdline:
|
||||||
|
return cmdline
|
||||||
|
|
||||||
return rv
|
if '--config' in cmdline:
|
||||||
|
for i, arg in enumerate(cmdline):
|
||||||
|
if arg == '--config':
|
||||||
|
if len(cmdline) <= i+1:
|
||||||
|
raise dbus.exceptions.DBusException("Missing value for --config option.")
|
||||||
|
cmdline[i+1] += " global/notify_dbus=0"
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
cmdline.extend(['--config', 'global/notify_dbus=0'])
|
||||||
|
return cmdline
|
||||||
|
|
||||||
|
|
||||||
# The methods below which start with mt_* are used to execute the desired code
|
# The methods below which start with mt_* are used to execute the desired code
|
||||||
# on the main thread of execution to alleviate any issues the dbus-python
|
# on the the main thread of execution to alleviate any issues the dbus-python
|
||||||
# library with regard to multithreaded access. Essentially, we are trying to
|
# library with regards to multi-threaded access. Essentially, we are trying to
|
||||||
# ensure all dbus library interaction is done from the same thread!
|
# ensure all dbus library interaction is done from the same thread!
|
||||||
|
|
||||||
|
|
||||||
@@ -691,8 +617,9 @@ def _async_handler(call_back, parameters):
|
|||||||
call_back(*parameters)
|
call_back(*parameters)
|
||||||
else:
|
else:
|
||||||
call_back()
|
call_back()
|
||||||
except BaseException as be:
|
except:
|
||||||
log_error("mt_async_call: exception (logged, not reported!) \n %s" % extract_stack_trace(be))
|
st = traceback.format_exc()
|
||||||
|
log_error("mt_async_call: exception (logged, not reported!) \n %s" % st)
|
||||||
|
|
||||||
|
|
||||||
# Execute the function on the main thread with the provided parameters, do
|
# Execute the function on the main thread with the provided parameters, do
|
||||||
@@ -742,6 +669,9 @@ class MThreadRunner(object):
|
|||||||
self.rc = self.f()
|
self.rc = self.f()
|
||||||
except BaseException as be:
|
except BaseException as be:
|
||||||
self.exception = be
|
self.exception = be
|
||||||
|
st = traceback.format_exc()
|
||||||
|
log_error("MThreadRunner: exception \n %s" % st)
|
||||||
|
log_error("Exception will be raised in calling thread!")
|
||||||
|
|
||||||
|
|
||||||
def _remove_objects(dbus_objects_rm):
|
def _remove_objects(dbus_objects_rm):
|
||||||
@@ -756,8 +686,8 @@ def mt_remove_dbus_objects(objs):
|
|||||||
|
|
||||||
# Make stream non-blocking
|
# Make stream non-blocking
|
||||||
def make_non_block(stream):
|
def make_non_block(stream):
|
||||||
flags = fcntl.fcntl(stream, fcntl.F_GETFL)
|
flags = fcntl(stream, F_GETFL)
|
||||||
fcntl.fcntl(stream, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
|
||||||
|
|
||||||
|
|
||||||
def read_decoded(stream):
|
def read_decoded(stream):
|
||||||
@@ -765,128 +695,3 @@ def read_decoded(stream):
|
|||||||
if tmp:
|
if tmp:
|
||||||
return tmp.decode("utf-8")
|
return tmp.decode("utf-8")
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
class LockFile(object):
|
|
||||||
"""
|
|
||||||
Simple lock file class
|
|
||||||
Based on Pg.1144 "The Linux Programming Interface" by Michael Kerrisk
|
|
||||||
"""
|
|
||||||
def __init__(self, lock_file):
|
|
||||||
self.fd = 0
|
|
||||||
self.lock_file = lock_file
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
try:
|
|
||||||
os.makedirs(os.path.dirname(self.lock_file), exist_ok=True)
|
|
||||||
self.fd = os.open(self.lock_file, os.O_CREAT | os.O_RDWR, stat.S_IRUSR | stat.S_IWUSR)
|
|
||||||
|
|
||||||
# Get and set the close on exec and lock the file
|
|
||||||
flags = fcntl.fcntl(self.fd, fcntl.F_GETFD)
|
|
||||||
flags |= fcntl.FD_CLOEXEC
|
|
||||||
fcntl.fcntl(self.fd, fcntl.F_SETFL, flags)
|
|
||||||
fcntl.lockf(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
||||||
except OSError as e:
|
|
||||||
if e.errno == errno.EAGAIN:
|
|
||||||
log_error("Daemon already running, exiting!")
|
|
||||||
else:
|
|
||||||
log_error("Error during creation of lock file(%s): errno(%d), exiting!" % (self.lock_file, e.errno))
|
|
||||||
sys.exit(114)
|
|
||||||
|
|
||||||
def __exit__(self, _type, _value, _traceback):
|
|
||||||
os.close(self.fd)
|
|
||||||
|
|
||||||
|
|
||||||
def extract_stack_trace(exception):
|
|
||||||
return ''.join(traceback.format_exception(None, exception, exception.__traceback__))
|
|
||||||
|
|
||||||
|
|
||||||
def lvm_column_key(key):
|
|
||||||
# Check LV
|
|
||||||
if key.startswith("lv_") or key.startswith("vg_") or key.startswith("pool_") or \
|
|
||||||
key.endswith("_percent") or key.startswith("move_") or key.startswith("vdo_") or \
|
|
||||||
key in ["origin_uuid", "segtype", "origin", "data_lv", "metadata_lv"]:
|
|
||||||
return True
|
|
||||||
# Check VG
|
|
||||||
if key.startswith("vg_") or key.startswith("lv_") or key.startswith("pv_") or \
|
|
||||||
key in ["max_lv", "max_pv", "snap_count"]:
|
|
||||||
return True
|
|
||||||
# Check PV
|
|
||||||
if key.startswith("pv") or key.startswith("vg") or (key in ['dev_size', 'pe_start']):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
class LvmBug(RuntimeError):
|
|
||||||
"""
|
|
||||||
Things that are clearly a bug with lvm itself.
|
|
||||||
"""
|
|
||||||
def __init__(self, msg):
|
|
||||||
super().__init__(msg)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "lvm bug encountered: %s" % ' '.join(self.args)
|
|
||||||
|
|
||||||
|
|
||||||
class LvmDebugData:
|
|
||||||
def __init__(self, do_collection):
|
|
||||||
self.fd = -1
|
|
||||||
self.fn = None
|
|
||||||
self.collect = do_collection
|
|
||||||
if self.collect:
|
|
||||||
log_msg("Collecting lvm debug data!")
|
|
||||||
|
|
||||||
def _remove_file(self):
|
|
||||||
if self.fn is not None:
|
|
||||||
os.unlink(self.fn)
|
|
||||||
self.fn = None
|
|
||||||
|
|
||||||
def _close_fd(self):
|
|
||||||
if self.fd != -1:
|
|
||||||
os.close(self.fd)
|
|
||||||
self.fd = -1
|
|
||||||
|
|
||||||
def setup(self):
|
|
||||||
# Create a secure filename
|
|
||||||
if self.collect:
|
|
||||||
self.fd, self.fn = tempfile.mkstemp(suffix=".log", prefix="lvmdbusd.lvm.debug.")
|
|
||||||
return self.fn
|
|
||||||
return None
|
|
||||||
|
|
||||||
def lvm_complete(self):
|
|
||||||
# Remove the file ASAP, so we decrease our odds of leaving it
|
|
||||||
# around if the daemon gets killed by a signal -9
|
|
||||||
self._remove_file()
|
|
||||||
|
|
||||||
def dump(self):
|
|
||||||
# Read the file and log it to log_err
|
|
||||||
if self.fd != -1:
|
|
||||||
# How big could the verbose debug get?
|
|
||||||
debug = os.read(self.fd, 1024*1024*5)
|
|
||||||
debug_txt = debug.decode("utf-8")
|
|
||||||
for line in debug_txt.split("\n"):
|
|
||||||
log_error("lvm debug >>> %s" % line)
|
|
||||||
self._close_fd()
|
|
||||||
# In case lvm_complete doesn't get called.
|
|
||||||
self._remove_file()
|
|
||||||
|
|
||||||
def complete(self):
|
|
||||||
self._close_fd()
|
|
||||||
# In case lvm_complete doesn't get called.
|
|
||||||
self._remove_file()
|
|
||||||
|
|
||||||
|
|
||||||
def get_error_msg(report_json):
|
|
||||||
# Get the error message from the returned JSON
|
|
||||||
if 'log' in report_json:
|
|
||||||
error_msg = ""
|
|
||||||
# Walk the entire log array and build an error string
|
|
||||||
for log_entry in report_json['log']:
|
|
||||||
if log_entry['log_type'] == "error":
|
|
||||||
if error_msg:
|
|
||||||
error_msg += ', ' + log_entry['log_message']
|
|
||||||
else:
|
|
||||||
error_msg = log_entry['log_message']
|
|
||||||
|
|
||||||
return error_msg
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from .request import RequestEntry
|
|||||||
from .loader import common
|
from .loader import common
|
||||||
from .state import State
|
from .state import State
|
||||||
from . import background
|
from . import background
|
||||||
from .utils import round_size, mt_remove_dbus_objects, LvmBug, lvm_column_key
|
from .utils import round_size, mt_remove_dbus_objects
|
||||||
from .job import JobState
|
from .job import JobState
|
||||||
|
|
||||||
|
|
||||||
@@ -31,7 +31,6 @@ def vgs_state_retrieve(selection, cache_refresh=True):
|
|||||||
if cache_refresh:
|
if cache_refresh:
|
||||||
cfg.db.refresh()
|
cfg.db.refresh()
|
||||||
|
|
||||||
try:
|
|
||||||
for v in cfg.db.fetch_vgs(selection):
|
for v in cfg.db.fetch_vgs(selection):
|
||||||
rc.append(
|
rc.append(
|
||||||
VgState(
|
VgState(
|
||||||
@@ -43,12 +42,6 @@ def vgs_state_retrieve(selection, cache_refresh=True):
|
|||||||
n(v['vg_seqno']), n(v['vg_mda_count']),
|
n(v['vg_seqno']), n(v['vg_mda_count']),
|
||||||
n(v['vg_mda_free']), n(v['vg_mda_size']),
|
n(v['vg_mda_free']), n(v['vg_mda_size']),
|
||||||
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
|
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
|
||||||
except KeyError as ke:
|
|
||||||
# Sometimes lvm omits returning one of the keys we requested.
|
|
||||||
key = ke.args[0]
|
|
||||||
if lvm_column_key(key):
|
|
||||||
raise LvmBug("missing JSON key: '%s'" % key)
|
|
||||||
raise ke
|
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
|
|
||||||
@@ -151,7 +144,6 @@ class Vg(AutomatedProperties):
|
|||||||
_AllocNormal_meta = ('b', VG_INTERFACE)
|
_AllocNormal_meta = ('b', VG_INTERFACE)
|
||||||
_AllocAnywhere_meta = ('b', VG_INTERFACE)
|
_AllocAnywhere_meta = ('b', VG_INTERFACE)
|
||||||
_Clustered_meta = ('b', VG_INTERFACE)
|
_Clustered_meta = ('b', VG_INTERFACE)
|
||||||
_Shared_meta = ('b', VG_INTERFACE)
|
|
||||||
_Name_meta = ('s', VG_INTERFACE)
|
_Name_meta = ('s', VG_INTERFACE)
|
||||||
|
|
||||||
# noinspection PyUnusedLocal,PyPep8Naming
|
# noinspection PyUnusedLocal,PyPep8Naming
|
||||||
@@ -786,10 +778,6 @@ class Vg(AutomatedProperties):
|
|||||||
def Clustered(self):
|
def Clustered(self):
|
||||||
return self._attribute(5, 'c')
|
return self._attribute(5, 'c')
|
||||||
|
|
||||||
@property
|
|
||||||
def Shared(self):
|
|
||||||
return self._attribute(5, 's')
|
|
||||||
|
|
||||||
|
|
||||||
class VgVdo(Vg):
|
class VgVdo(Vg):
|
||||||
|
|
||||||
|
|||||||
@@ -15,61 +15,61 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
USE_SD_NOTIFY=yes
|
||||||
|
|
||||||
SOURCES = lvmlockd-core.c
|
SOURCES = lvmlockd-core.c
|
||||||
SOURCES2 = lvmlockctl.c
|
|
||||||
|
|
||||||
TARGETS = lvmlockd lvmlockctl
|
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
|
||||||
|
|
||||||
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
|
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
|
||||||
SOURCES += lvmlockd-sanlock.c
|
SOURCES += lvmlockd-sanlock.c
|
||||||
CFLAGS += $(LIBSANLOCKCLIENT_CFLAGS)
|
LOCK_LIBS += -lsanlock_client
|
||||||
LOCK_LIBS += $(LIBSANLOCKCLIENT_LIBS)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ("@BUILD_LOCKDDLM@", "yes")
|
ifeq ("@BUILD_LOCKDDLM@", "yes")
|
||||||
SOURCES += lvmlockd-dlm.c
|
SOURCES += lvmlockd-dlm.c
|
||||||
CFLAGS += $(LIBDLM) $(LIBDLMCONTROL_CFLAGS)
|
LOCK_LIBS += -ldlm_lt
|
||||||
# LOCK_LIBS += $(LIBDLM_LIBS) $(LIBDLMCONTROL_LIBS)
|
LOCK_LIBS += -ldlmcontrol
|
||||||
LOCK_LIBS += -ldlm_lt $(LIBDLMCONTROL_LIBS)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ("@BUILD_LOCKDIDM@", "yes")
|
ifeq ("@BUILD_LOCKDIDM@", "yes")
|
||||||
SOURCES += lvmlockd-idm.c
|
SOURCES += lvmlockd-idm.c
|
||||||
LOCK_LIBS += $(LIBSEAGATEILM_LIBS) $(BLKID_LIBS)
|
LOCK_LIBS += -lseagate_ilm -lblkid
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
SOURCES2 = lvmlockctl.c
|
||||||
|
|
||||||
|
TARGETS = lvmlockd lvmlockctl
|
||||||
|
|
||||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||||
CFLOW_TARGET = lvmlockd
|
CFLOW_TARGET = lvmlockd
|
||||||
|
|
||||||
.PHONY: install_lvmlockd install_lvmlockctl
|
.PHONY: install_lvmlockd install_lvmlockctl
|
||||||
|
|
||||||
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||||
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
||||||
|
|
||||||
ifneq (,$(firstword $(LIBSYSTEMD_LIBS)))
|
ifeq ($(USE_SD_NOTIFY),yes)
|
||||||
DEFS += -DUSE_SD_NOTIFY
|
CFLAGS += $(shell pkg-config --cflags libsystemd) -DUSE_SD_NOTIFY
|
||||||
CFLAGS += $(LIBSYSTEMD_CFLAGS)
|
LIBS += $(shell pkg-config --libs libsystemd)
|
||||||
LIBS += $(LIBSYSTEMD_LIBS)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
|
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
|
||||||
$(SHOW) " [CC] $@"
|
@echo " [CC] $@"
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LOCK_LIBS) $(LIBS)
|
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LOCK_LIBS) $(LIBS)
|
||||||
|
|
||||||
lvmlockctl: lvmlockctl.o $(INTERNAL_LIBS)
|
lvmlockctl: lvmlockctl.o $(INTERNAL_LIBS)
|
||||||
$(SHOW) " [CC] $@"
|
@echo " [CC] $@"
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
|
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||||
|
|
||||||
install_lvmlockd: lvmlockd
|
install_lvmlockd: lvmlockd
|
||||||
$(SHOW) " [INSTALL] $<"
|
@echo " [INSTALL] $<"
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
|
|
||||||
install_lvmlockctl: lvmlockctl
|
install_lvmlockctl: lvmlockctl
|
||||||
$(SHOW) " [INSTALL] $<"
|
@echo " [INSTALL] $<"
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
|
|
||||||
install_lvm2: install_lvmlockd install_lvmlockctl
|
install_lvm2: install_lvmlockd install_lvmlockctl
|
||||||
|
|||||||
@@ -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)
|
static void format_info_line(char *line, char *r_name, char *r_type)
|
||||||
{
|
{
|
||||||
if (!strncmp(line, "info=structs ", sizeof("info=structs ") - 1)) {
|
if (!strncmp(line, "info=structs ", strlen("info=structs "))) {
|
||||||
/* only print this in the raw info dump */
|
/* only print this in the raw info dump */
|
||||||
|
|
||||||
} else if (!strncmp(line, "info=client ", sizeof("info=client ") - 1)) {
|
} else if (!strncmp(line, "info=client ", strlen("info=client "))) {
|
||||||
save_client_info(line);
|
save_client_info(line);
|
||||||
|
|
||||||
} else if (!strncmp(line, "info=ls ", sizeof("info=ls ") - 1)) {
|
} else if (!strncmp(line, "info=ls ", strlen("info=ls "))) {
|
||||||
format_info_ls(line);
|
format_info_ls(line);
|
||||||
|
|
||||||
} else if (!strncmp(line, "info=ls_action ", sizeof("info=ls_action ") - 1)) {
|
} else if (!strncmp(line, "info=ls_action ", strlen("info=ls_action "))) {
|
||||||
format_info_ls_action(line);
|
format_info_ls_action(line);
|
||||||
|
|
||||||
} else if (!strncmp(line, "info=r ", sizeof("info=r ") - 1)) {
|
} else if (!strncmp(line, "info=r ", strlen("info=r "))) {
|
||||||
/*
|
/*
|
||||||
* r_name/r_type are reset when a new resource is found.
|
* r_name/r_type are reset when a new resource is found.
|
||||||
* They are reused for the lock and action lines that
|
* They are reused for the lock and action lines that
|
||||||
@@ -286,11 +286,11 @@ static void format_info_line(char *line, char *r_name, char *r_type)
|
|||||||
memset(r_type, 0, MAX_NAME+1);
|
memset(r_type, 0, MAX_NAME+1);
|
||||||
format_info_r(line, r_name, r_type);
|
format_info_r(line, r_name, r_type);
|
||||||
|
|
||||||
} else if (!strncmp(line, "info=lk ", sizeof("info=lk ") - 1)) {
|
} else if (!strncmp(line, "info=lk ", strlen("info=lk "))) {
|
||||||
/* will use info from previous r */
|
/* will use info from previous r */
|
||||||
format_info_lk(line, r_name, r_type);
|
format_info_lk(line, r_name, r_type);
|
||||||
|
|
||||||
} else if (!strncmp(line, "info=r_action ", sizeof("info=r_action ") - 1)) {
|
} else if (!strncmp(line, "info=r_action ", strlen("info=r_action "))) {
|
||||||
/* will use info from previous r */
|
/* will use info from previous r */
|
||||||
format_info_r_action(line, r_name, r_type);
|
format_info_r_action(line, r_name, r_type);
|
||||||
} else {
|
} else {
|
||||||
@@ -940,7 +940,7 @@ static int read_options(int argc, char *argv[])
|
|||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
static const struct option _long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"help", no_argument, 0, 'h' },
|
{"help", no_argument, 0, 'h' },
|
||||||
{"quit", no_argument, 0, 'q' },
|
{"quit", no_argument, 0, 'q' },
|
||||||
{"info", no_argument, 0, 'i' },
|
{"info", no_argument, 0, 'i' },
|
||||||
@@ -962,7 +962,7 @@ static int read_options(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
c = getopt_long(argc, argv, "hqidE:D:w:k:r:Se", _long_options, &option_index);
|
c = getopt_long(argc, argv, "hqidE:D:w:k:r:Se", long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,9 @@
|
|||||||
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
|
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
|
||||||
#define LVMLOCKD_ADOPT_FILE DEFAULT_RUN_DIR "/lvmlockd.adopt"
|
#define LVMLOCKD_ADOPT_FILE DEFAULT_RUN_DIR "/lvmlockd.adopt"
|
||||||
|
|
||||||
#define LVMLOCKD_USE_SANLOCK_LVB 0
|
|
||||||
|
|
||||||
/* Wrappers to open/close connection */
|
/* Wrappers to open/close connection */
|
||||||
|
|
||||||
static inline __attribute__((always_inline))
|
static inline daemon_handle lvmlockd_open(const char *sock)
|
||||||
daemon_handle lvmlockd_open(const char *sock)
|
|
||||||
{
|
{
|
||||||
daemon_info lvmlockd_info = {
|
daemon_info lvmlockd_info = {
|
||||||
.path = "lvmlockd",
|
.path = "lvmlockd",
|
||||||
@@ -54,8 +51,5 @@ static inline void lvmlockd_close(daemon_handle h)
|
|||||||
#define EREMOVED 219
|
#define EREMOVED 219
|
||||||
#define EDEVOPEN 220 /* sanlock failed to open lvmlock LV */
|
#define EDEVOPEN 220 /* sanlock failed to open lvmlock LV */
|
||||||
#define ELMERR 221
|
#define ELMERR 221
|
||||||
#define EORPHAN 222
|
|
||||||
#define EADOPT_NONE 223
|
|
||||||
#define EADOPT_RETRY 224
|
|
||||||
|
|
||||||
#endif /* _LVM_LVMLOCKD_CLIENT_H */
|
#endif /* _LVM_LVMLOCKD_CLIENT_H */
|
||||||
|
|||||||
@@ -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.
|
* 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 const int lvmlockd_protocol_version = 1;
|
||||||
static int daemon_quit;
|
static int daemon_quit;
|
||||||
static int adopt_opt;
|
static int adopt_opt;
|
||||||
@@ -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)
|
int last_string_from_args(char *args_in, char *last)
|
||||||
{
|
{
|
||||||
const char *args = args_in;
|
const char *args = args_in;
|
||||||
@@ -1062,16 +1041,16 @@ static int lm_prepare_lockspace(struct lockspace *ls, struct action *act)
|
|||||||
return rv;
|
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;
|
int rv;
|
||||||
|
|
||||||
if (ls->lm_type == LD_LM_DLM)
|
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)
|
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)
|
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
|
else
|
||||||
return -1;
|
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,
|
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;
|
int rv;
|
||||||
|
|
||||||
if (ls->lm_type == LD_LM_DLM)
|
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)
|
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)
|
else if (ls->lm_type == LD_LM_IDM)
|
||||||
rv = lm_lock_idm(ls, r, mode, vb_out, act->lv_uuid,
|
rv = lm_lock_idm(ls, r, mode, vb_out, act->lv_uuid,
|
||||||
&act->pvs, adopt_only, adopt_ok);
|
&act->pvs, adopt);
|
||||||
else
|
else
|
||||||
return -1;
|
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()
|
* 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
|
* should be passed back to the adopt_locks() function through the
|
||||||
* adopt_results list, and not be sent back to a client via the
|
* adopt_results list, and not be sent back to a client via the
|
||||||
* client_list/client_thread. INTERNAL_CLIENT_ID indicates the
|
* client_list/client_thread.
|
||||||
* act was generated internally and not from a client, and
|
|
||||||
* distinguishes internal adopt request from those received from
|
|
||||||
* a client.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void add_client_result(struct action *act)
|
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);
|
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);
|
list_add_tail(&act->list, &adopt_results);
|
||||||
else
|
else
|
||||||
list_add_tail(&act->list, &client_results);
|
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;
|
r->last_client_id = act->client_id;
|
||||||
|
|
||||||
if (r->type == LD_RT_LV)
|
if (r->type == LD_RT_LV)
|
||||||
log_debug("%s:%s res_lock %s cl %u (%s)", ls->name, r->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);
|
||||||
mode_str(act->mode), act->client_id, act->lv_name);
|
|
||||||
else
|
else
|
||||||
log_debug("%s:%s res_lock %s cl %u", ls->name, r->name,
|
log_debug("S %s R %s res_lock cl %u mode %s", ls->name, r->name, act->client_id, mode_str(act->mode));
|
||||||
mode_str(act->mode), act->client_id);
|
|
||||||
|
|
||||||
if (r->mode == LD_LK_SH && act->mode == LD_LK_SH)
|
if (r->mode == LD_LK_SH && act->mode == LD_LK_SH)
|
||||||
goto add_lk;
|
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])
|
if (r->type == LD_RT_LV && act->lv_args[0])
|
||||||
memcpy(r->lv_args, act->lv_args, MAX_ARGS);
|
memcpy(r->lv_args, act->lv_args, MAX_ARGS);
|
||||||
|
|
||||||
rv = lm_lock(ls, r, act->mode, act, &vb, retry,
|
rv = lm_lock(ls, r, act->mode, act, &vb, retry, act->flags & LD_AF_ADOPT);
|
||||||
act->flags & LD_AF_ADOPT_ONLY ? 1 : 0,
|
|
||||||
act->flags & LD_AF_ADOPT ? 1 : 0);
|
|
||||||
|
|
||||||
if (rv && r->use_vb)
|
if (r->use_vb)
|
||||||
log_debug("%s:%s res_lock rv %d read vb %x %x %u",
|
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);
|
ls->name, r->name, rv, vb.version, vb.flags, vb.r_version);
|
||||||
else if (rv)
|
else
|
||||||
log_debug("%s:%s res_lock rv %d", ls->name, r->name, rv);
|
log_debug("S %s R %s res_lock rv %d", ls->name, r->name, rv);
|
||||||
|
|
||||||
if (rv < 0)
|
if (rv < 0)
|
||||||
return rv;
|
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
|
* be invalidated. When we need to invalidate the lvmetad
|
||||||
* cache, but don't have a usable r_version from the lvb,
|
* cache, but don't have a usable r_version from the lvb,
|
||||||
* send lvmetad new_version 0 which causes it to invalidate
|
* 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.
|
* 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. */
|
/* LV locks don't use an lvb. */
|
||||||
|
|
||||||
} else if (vb.version && ((vb.version & 0xFF00) > (VAL_BLK_VERSION & 0xFF00))) {
|
} 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);
|
ls->name, r->name, vb.version, vb.flags, vb.r_version);
|
||||||
inval_meta = 1;
|
inval_meta = 1;
|
||||||
new_version = 0;
|
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
|
* acquired it, and increased r_version so we know that our
|
||||||
* cache is invalid.
|
* 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);
|
ls->name, r->name, vb.r_version, r->version);
|
||||||
r->version = vb.r_version;
|
r->version = vb.r_version;
|
||||||
new_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.
|
* once someone uses the lock and writes a new lvb value.
|
||||||
* Do nothing.
|
* Do nothing.
|
||||||
*/
|
*/
|
||||||
/*
|
log_debug("S %s R %s res_lock version_zero_valid still zero", ls->name, r->name);
|
||||||
log_debug("%s:%s res_lock version_zero_valid still zero", ls->name, r->name);
|
|
||||||
*/
|
|
||||||
|
|
||||||
} else if (r->version_zero_valid && vb.r_version) {
|
} 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?)
|
* larger version?)
|
||||||
*/
|
*/
|
||||||
if (r->version && (r->version >= vb.r_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);
|
ls->name, r->name, vb.r_version, r->version);
|
||||||
new_version = 0;
|
new_version = 0;
|
||||||
} else {
|
} 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);
|
ls->name, r->name, vb.r_version, r->version);
|
||||||
new_version = vb.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.
|
* 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;
|
r->version = vb.r_version;
|
||||||
inval_meta = 1;
|
inval_meta = 1;
|
||||||
new_version = vb.r_version;
|
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.
|
* The lock may have never been used to change something.
|
||||||
* (e.g. a new sanlock GL?)
|
* (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) {
|
if (!r->version_zero_valid) {
|
||||||
inval_meta = 1;
|
inval_meta = 1;
|
||||||
new_version = 0;
|
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.
|
* is unchanged and we don't need to invalidate metadata.
|
||||||
*/
|
*/
|
||||||
if ((ls->lm_type == LD_LM_DLM) && !vb.version && !vb.flags)
|
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);
|
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);
|
ls->name, r->name, r->version, vb.version, vb.flags, vb.r_version);
|
||||||
r->version_zero_valid = 1;
|
r->version_zero_valid = 1;
|
||||||
inval_meta = 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
|
* FIXME: how does the cache validation and replacement in lvmetad
|
||||||
* work in this case?
|
* 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);
|
ls->name, r->name, vb.r_version, r->version);
|
||||||
r->version = vb.r_version;
|
r->version = vb.r_version;
|
||||||
inval_meta = 1;
|
inval_meta = 1;
|
||||||
new_version = 0;
|
new_version = 0;
|
||||||
r->version_zero_valid = 0;
|
r->version_zero_valid = 0;
|
||||||
} else {
|
} 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,
|
ls->name, r->name, r->version_zero_valid, r->version,
|
||||||
vb.version, vb.flags, vb.r_version);
|
vb.version, vb.flags, vb.r_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vb.version && vb.r_version && (vb.flags & VBF_REMOVED)) {
|
if (vb.version && vb.r_version && (vb.flags & VBF_REMOVED)) {
|
||||||
/* Should we set ls->thread_stop = 1 ? */
|
/* 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);
|
ls->name, r->name);
|
||||||
rv = -EREMOVED;
|
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)) {
|
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);
|
ls->name, r->name, new_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inval_meta && (r->type == LD_RT_GL)) {
|
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;
|
r->last_client_id = act->client_id;
|
||||||
|
|
||||||
log_debug("%s:%s res_convert %s cl %u", ls->name, r->name,
|
log_debug("S %s R %s res_convert cl %u mode %s", ls->name, r->name, act->client_id, mode_str(act->mode));
|
||||||
mode_str(act->mode), act->client_id);
|
|
||||||
|
|
||||||
if (act->mode == LD_LK_EX && lk->mode == LD_LK_SH && r->sh_count > 1)
|
if (act->mode == LD_LK_EX && lk->mode == LD_LK_SH && r->sh_count > 1)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
@@ -1578,7 +1547,7 @@ static int res_convert(struct lockspace *ls, struct resource *r,
|
|||||||
r_version = r->version;
|
r_version = r->version;
|
||||||
r->version_zero_valid = 0;
|
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);
|
ls->name, r->name, r_version);
|
||||||
|
|
||||||
} else if ((r->type == LD_RT_VG) && (r->mode == LD_LK_EX) && (lk->version > 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 = r->version;
|
||||||
r->version_zero_valid = 0;
|
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 {
|
} else {
|
||||||
r_version = 0;
|
r_version = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = lm_convert(ls, r, act->mode, act, r_version);
|
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)
|
if (rv < 0)
|
||||||
return rv;
|
return rv;
|
||||||
@@ -1604,7 +1573,7 @@ static int res_convert(struct lockspace *ls, struct resource *r,
|
|||||||
r->sh_count = 0;
|
r->sh_count = 0;
|
||||||
} else {
|
} else {
|
||||||
/* should not be possible */
|
/* 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);
|
ls->name, r->name, lk->mode, act->mode);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1643,7 +1612,7 @@ static int res_cancel(struct lockspace *ls, struct resource *r,
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
do_cancel:
|
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;
|
cact->result = -ECANCELED;
|
||||||
list_del(&cact->list);
|
list_del(&cact->list);
|
||||||
add_client_result(cact);
|
add_client_result(cact);
|
||||||
@@ -1691,12 +1660,12 @@ static int res_unlock(struct lockspace *ls, struct resource *r,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (act->op != LD_OP_CLOSE)
|
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;
|
return -ENOENT;
|
||||||
|
|
||||||
do_unlock:
|
do_unlock:
|
||||||
if ((act->flags & LD_AF_LV_UNLOCK) && (r->last_client_id != act->client_id)) {
|
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);
|
ls->name, r->name, act->client_id, r->last_client_id);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
@@ -1704,17 +1673,17 @@ do_unlock:
|
|||||||
r->last_client_id = act->client_id;
|
r->last_client_id = act->client_id;
|
||||||
|
|
||||||
if (act->op == LD_OP_CLOSE)
|
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)
|
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
|
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 */
|
/* send unlock to lm when last sh lock is unlocked */
|
||||||
if (lk->mode == LD_LK_SH) {
|
if (lk->mode == LD_LK_SH) {
|
||||||
r->sh_count--;
|
r->sh_count--;
|
||||||
if (r->sh_count > 0) {
|
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;
|
goto rem_lk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1725,14 +1694,14 @@ do_unlock:
|
|||||||
r_version = r->version;
|
r_version = r->version;
|
||||||
r->version_zero_valid = 0;
|
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)) {
|
} else if ((r->type == LD_RT_VG) && (r->mode == LD_LK_EX) && (lk->version > r->version)) {
|
||||||
r->version = lk->version;
|
r->version = lk->version;
|
||||||
r_version = r->version;
|
r_version = r->version;
|
||||||
r->version_zero_valid = 0;
|
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);
|
ls->name, r->name, r_version);
|
||||||
} else {
|
} else {
|
||||||
r_version = 0;
|
r_version = 0;
|
||||||
@@ -1741,11 +1710,11 @@ do_unlock:
|
|||||||
rv = lm_unlock(ls, r, act, r_version, 0);
|
rv = lm_unlock(ls, r, act, r_version, 0);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
/* should never happen, retry? */
|
/* 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;
|
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:
|
rem_lk:
|
||||||
list_del(&lk->list);
|
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);
|
lk = find_lock_client(r, act->client_id);
|
||||||
if (!lk) {
|
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);
|
ls->name, r->name, act->client_id);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->mode != LD_LK_EX) {
|
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);
|
ls->name, r->name, act->client_id);
|
||||||
return -EINVAL;
|
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
|
* force an invalidation on other hosts. The next change
|
||||||
* will return to using the seqno again.
|
* 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);
|
ls->name, r->name, act->client_id, r->version, act->version);
|
||||||
}
|
}
|
||||||
lk->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;
|
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) {
|
list_for_each_entry_safe(act, safe, &r->actions, list) {
|
||||||
if (act->op == LD_OP_FREE && act->rt == LD_RT_LV) {
|
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);
|
rv = free_lv(ls, r);
|
||||||
act->result = rv;
|
act->result = rv;
|
||||||
list_del(&act->list);
|
list_del(&act->list);
|
||||||
@@ -1972,7 +1941,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
|||||||
add_client_result(act);
|
add_client_result(act);
|
||||||
|
|
||||||
if (!rv && act->op == LD_OP_DISABLE) {
|
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;
|
goto r_free;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2190,7 +2159,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
|||||||
(act->retries <= act->max_retries) &&
|
(act->retries <= act->max_retries) &&
|
||||||
(lm_retry || (r->type != LD_RT_LV))) {
|
(lm_retry || (r->type != LD_RT_LV))) {
|
||||||
/* leave act on list */
|
/* 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++;
|
act->retries++;
|
||||||
*retry_out = 1;
|
*retry_out = 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -2223,7 +2192,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
|||||||
(act->retries <= act->max_retries) &&
|
(act->retries <= act->max_retries) &&
|
||||||
(lm_retry || (r->type != LD_RT_LV))) {
|
(lm_retry || (r->type != LD_RT_LV))) {
|
||||||
/* leave act on list */
|
/* 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++;
|
act->retries++;
|
||||||
*retry_out = 1;
|
*retry_out = 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -2242,13 +2211,13 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
|||||||
r_free:
|
r_free:
|
||||||
/* For the EUNATCH case it may be possible there are queued actions? */
|
/* For the EUNATCH case it may be possible there are queued actions? */
|
||||||
list_for_each_entry_safe(act, safe, &r->actions, list) {
|
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);
|
ls->name, r->name, op_str(act->op), act->client_id);
|
||||||
act->result = -ECANCELED;
|
act->result = -ECANCELED;
|
||||||
list_del(&act->list);
|
list_del(&act->list);
|
||||||
add_client_result(act);
|
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);
|
lm_rem_resource(ls, r);
|
||||||
list_del(&r->list);
|
list_del(&r->list);
|
||||||
free_resource(r);
|
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)
|
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
|
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)
|
if (lk->version > lk_version)
|
||||||
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)) {
|
if ((r->type == LD_RT_GL) && (r->mode == LD_LK_EX)) {
|
||||||
r->version++;
|
r->version++;
|
||||||
r_version = 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);
|
ls->name, r->name, r_version);
|
||||||
|
|
||||||
} else if ((r->type == LD_RT_VG) && (r->mode == LD_LK_EX) && (lk_version > r->version)) {
|
} else if ((r->type == LD_RT_VG) && (r->mode == LD_LK_EX) && (lk_version > r->version)) {
|
||||||
r->version = lk_version;
|
r->version = lk_version;
|
||||||
r_version = r->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);
|
ls->name, r->name, r_version);
|
||||||
|
|
||||||
} else {
|
} 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);
|
rv = lm_unlock(ls, r, NULL, r_version, free_vg ? LMUF_FREE_VG : 0);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
/* should never happen */
|
/* 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);
|
ls->name, r->name, free_vg, drop_vg, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry_safe(act, act_safe, &r->actions, list) {
|
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);
|
ls->name, r->name, op_str(act->op), act->client_id);
|
||||||
act->result = -ECANCELED;
|
act->result = -ECANCELED;
|
||||||
list_del(&act->list);
|
list_del(&act->list);
|
||||||
add_client_result(act);
|
add_client_result(act);
|
||||||
}
|
}
|
||||||
r_free:
|
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);
|
lm_rem_resource(ls, r);
|
||||||
list_del(&r->list);
|
list_del(&r->list);
|
||||||
free_resource(r);
|
free_resource(r);
|
||||||
@@ -2398,13 +2367,13 @@ static struct resource *find_resource_act(struct lockspace *ls,
|
|||||||
r->mode = LD_LK_UN;
|
r->mode = LD_LK_UN;
|
||||||
|
|
||||||
if (r->type == LD_RT_GL) {
|
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;
|
r->use_vb = 1;
|
||||||
} else if (r->type == LD_RT_VG) {
|
} 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;
|
r->use_vb = 1;
|
||||||
} else if (r->type == LD_RT_LV) {
|
} 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;
|
r->use_vb = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2488,18 +2457,15 @@ static void *lockspace_thread_main(void *arg_in)
|
|||||||
struct list_head tmp_act;
|
struct list_head tmp_act;
|
||||||
struct list_head act_close;
|
struct list_head act_close;
|
||||||
char tmp_name[MAX_NAME+5];
|
char tmp_name[MAX_NAME+5];
|
||||||
int fail_stop_busy;
|
|
||||||
int free_vg = 0;
|
int free_vg = 0;
|
||||||
int drop_vg = 0;
|
int drop_vg = 0;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
int adopt_only = 0;
|
int adopt_flag = 0;
|
||||||
int adopt_ok = 0;
|
|
||||||
int wait_flag = 0;
|
int wait_flag = 0;
|
||||||
int retry;
|
int retry;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&act_close);
|
INIT_LIST_HEAD(&act_close);
|
||||||
INIT_LIST_HEAD(&tmp_act);
|
|
||||||
|
|
||||||
/* first action may be client add */
|
/* first action may be client add */
|
||||||
pthread_mutex_lock(&ls->mutex);
|
pthread_mutex_lock(&ls->mutex);
|
||||||
@@ -2513,21 +2479,14 @@ static void *lockspace_thread_main(void *arg_in)
|
|||||||
|
|
||||||
if (add_act->flags & LD_AF_WAIT)
|
if (add_act->flags & LD_AF_WAIT)
|
||||||
wait_flag = 1;
|
wait_flag = 1;
|
||||||
if (add_act->flags & LD_AF_ADOPT_ONLY)
|
|
||||||
adopt_only = 1;
|
|
||||||
if (add_act->flags & LD_AF_ADOPT)
|
if (add_act->flags & LD_AF_ADOPT)
|
||||||
adopt_ok = 1;
|
adopt_flag = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&ls->mutex);
|
pthread_mutex_unlock(&ls->mutex);
|
||||||
|
|
||||||
if (ls->lm_type == LD_LM_DLM && !strcmp(gl_lsname_dlm, ls->name)) {
|
log_debug("S %s lm_add_lockspace %s wait %d adopt %d",
|
||||||
log_debug("dlm global lockspace adopt_ok");
|
ls->name, lm_str(ls->lm_type), wait_flag, adopt_flag);
|
||||||
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);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The prepare step does not wait for anything and is quick;
|
* 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.
|
* The actual lockspace join can take a while.
|
||||||
*/
|
*/
|
||||||
if (!error) {
|
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);
|
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)
|
if (error)
|
||||||
goto out_act;
|
goto out_act;
|
||||||
|
|
||||||
restart:
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
pthread_mutex_lock(&ls->mutex);
|
pthread_mutex_lock(&ls->mutex);
|
||||||
while (!ls->thread_work) {
|
while (!ls->thread_work) {
|
||||||
@@ -2755,7 +2712,7 @@ static void *lockspace_thread_main(void *arg_in)
|
|||||||
|
|
||||||
list_add_tail(&act->list, &r->actions);
|
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));
|
op_str(act->op), mode_str(act->mode));
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&ls->mutex);
|
pthread_mutex_unlock(&ls->mutex);
|
||||||
@@ -2827,48 +2784,17 @@ out_rem:
|
|||||||
* Leave the lockspace.
|
* Leave the lockspace.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fail_stop_busy = 0;
|
|
||||||
|
|
||||||
rv = lm_rem_lockspace(ls, NULL, free_vg);
|
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) {
|
log_debug("S %s rem_lockspace done %d", ls->name, rv);
|
||||||
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);
|
|
||||||
|
|
||||||
out_act:
|
out_act:
|
||||||
/*
|
/*
|
||||||
* Move remaining actions to results; this will usually (always?)
|
* Move remaining actions to results; this will usually (always?)
|
||||||
* be only the stop action.
|
* be only the stop action.
|
||||||
*/
|
*/
|
||||||
|
INIT_LIST_HEAD(&tmp_act);
|
||||||
|
|
||||||
pthread_mutex_lock(&ls->mutex);
|
pthread_mutex_lock(&ls->mutex);
|
||||||
list_for_each_entry_safe(act, safe, &ls->actions, list) {
|
list_for_each_entry_safe(act, safe, &ls->actions, list) {
|
||||||
if (act->op == LD_OP_FREE) {
|
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)
|
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);
|
log_error("vg name too long %s", vg_name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snprintf(ls_name, MAX_NAME, "%s%s", LVM_LS_PREFIX, vg_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3054,13 +2981,13 @@ static int add_lockspace_thread(const char *ls_name,
|
|||||||
|
|
||||||
if (vg_uuid)
|
if (vg_uuid)
|
||||||
/* coverity[buffer_size_warning] */
|
/* coverity[buffer_size_warning] */
|
||||||
memccpy(ls->vg_uuid, vg_uuid, 0, 64);
|
strncpy(ls->vg_uuid, vg_uuid, 64);
|
||||||
|
|
||||||
if (vg_name)
|
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)
|
if (vg_args)
|
||||||
dm_strncpy(ls->vg_args, vg_args, sizeof(ls->vg_args));
|
strncpy(ls->vg_args, vg_args, MAX_ARGS);
|
||||||
|
|
||||||
if (act)
|
if (act)
|
||||||
ls->host_id = act->host_id;
|
ls->host_id = act->host_id;
|
||||||
@@ -3602,7 +3529,7 @@ static void work_test_gl(void)
|
|||||||
is_enabled = lm_gl_is_enabled(ls);
|
is_enabled = lm_gl_is_enabled(ls);
|
||||||
if (is_enabled) {
|
if (is_enabled) {
|
||||||
log_debug("S %s worker found gl_is_enabled", ls->name);
|
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);
|
pthread_mutex_unlock(&ls->mutex);
|
||||||
@@ -4144,7 +4071,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",
|
log_debug("send %s[%d] cl %u %s %s rv %d %s %s",
|
||||||
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
|
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);
|
act->result, (act->result == -ENOLS) ? "ENOLS" : "", result_flags);
|
||||||
|
|
||||||
res = daemon_reply_simple("OK",
|
res = daemon_reply_simple("OK",
|
||||||
@@ -4228,26 +4155,12 @@ static int add_lock_action(struct action *act)
|
|||||||
vg_ls_name(act->vg_name, ls_name);
|
vg_ls_name(act->vg_name, ls_name);
|
||||||
} else {
|
} else {
|
||||||
if (!gl_use_dlm && !gl_use_sanlock && !gl_use_idm) {
|
if (!gl_use_dlm && !gl_use_sanlock && !gl_use_idm) {
|
||||||
int run_sanlock = lm_is_running_sanlock();
|
if (lm_is_running_dlm())
|
||||||
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;
|
gl_use_dlm = 1;
|
||||||
else if (run_sanlock)
|
else if (lm_is_running_sanlock())
|
||||||
gl_use_sanlock = 1;
|
gl_use_sanlock = 1;
|
||||||
else if (run_idm)
|
else if (lm_is_running_idm())
|
||||||
gl_use_idm = 1;
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
gl_ls_name(ls_name);
|
gl_ls_name(ls_name);
|
||||||
}
|
}
|
||||||
@@ -4553,12 +4466,6 @@ static uint32_t str_to_opts(const char *str)
|
|||||||
flags |= LD_AF_ENABLE;
|
flags |= LD_AF_ENABLE;
|
||||||
if (strstr(str, "disable"))
|
if (strstr(str, "disable"))
|
||||||
flags |= LD_AF_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:
|
out:
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
@@ -4783,12 +4690,9 @@ static int dump_info(int *dump_len)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* clients
|
* 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) {
|
list_for_each_entry(cl, &client_list, list) {
|
||||||
ret = print_client(cl, "client", pos, len);
|
ret = print_client(cl, "client", pos, len);
|
||||||
if (ret >= len - pos) {
|
if (ret >= len - pos) {
|
||||||
@@ -4802,7 +4706,6 @@ static int dump_info(int *dump_len)
|
|||||||
if (rv < 0)
|
if (rv < 0)
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
print_ls:
|
|
||||||
/*
|
/*
|
||||||
* lockspaces with their action/resource/lock info
|
* lockspaces with their action/resource/lock info
|
||||||
*/
|
*/
|
||||||
@@ -4999,13 +4902,13 @@ static void client_recv_action(struct client *cl)
|
|||||||
act->path = strdup(path);
|
act->path = strdup(path);
|
||||||
|
|
||||||
if (vg_name && strcmp(vg_name, "none"))
|
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"))
|
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"))
|
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);
|
str = daemon_request_str(req, "lv_name", NULL);
|
||||||
if (str && strcmp(str, "none"))
|
if (str && strcmp(str, "none"))
|
||||||
@@ -5071,9 +4974,9 @@ skip_pvs_path:
|
|||||||
dm_config_destroy(req.cft);
|
dm_config_destroy(req.cft);
|
||||||
buffer_destroy(&req.buffer);
|
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,
|
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()) {
|
if (lm == LD_LM_DLM && !lm_support_dlm()) {
|
||||||
log_debug("dlm not supported");
|
log_debug("dlm not supported");
|
||||||
@@ -5377,7 +5280,7 @@ static int match_dm_uuid(char *dm_uuid, char *lv_lock_uuid)
|
|||||||
{
|
{
|
||||||
char buf1[64];
|
char buf1[64];
|
||||||
char buf2[64];
|
char buf2[64];
|
||||||
unsigned i, j;
|
int i, j;
|
||||||
|
|
||||||
memset(buf1, 0, sizeof(buf1));
|
memset(buf1, 0, sizeof(buf1));
|
||||||
memset(buf2, 0, sizeof(buf2));
|
memset(buf2, 0, sizeof(buf2));
|
||||||
@@ -5461,7 +5364,7 @@ static int remove_inactive_lvs(struct list_head *vg_lockd)
|
|||||||
goto next_dmname;
|
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);
|
names->name, dm_uuid, vgname, lvname);
|
||||||
|
|
||||||
if (!vgname || !lvname) {
|
if (!vgname || !lvname) {
|
||||||
@@ -5482,7 +5385,8 @@ static int remove_inactive_lvs(struct list_head *vg_lockd)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Found an active LV in a lockd VG. */
|
/* 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;
|
r->adopt = 1;
|
||||||
goto next_dmname;
|
goto next_dmname;
|
||||||
}
|
}
|
||||||
@@ -5719,7 +5623,7 @@ static void adopt_locks(void)
|
|||||||
act->rt = LD_RT_VG;
|
act->rt = LD_RT_VG;
|
||||||
act->lm_type = ls->lm_type;
|
act->lm_type = ls->lm_type;
|
||||||
act->client_id = INTERNAL_CLIENT_ID;
|
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_uuid, ls->vg_uuid, 64);
|
||||||
memcpy(act->vg_args, ls->vg_args, MAX_ARGS);
|
memcpy(act->vg_args, ls->vg_args, MAX_ARGS);
|
||||||
act->host_id = ls->host_id;
|
act->host_id = ls->host_id;
|
||||||
@@ -5754,6 +5658,7 @@ static void adopt_locks(void)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
while (count_start_done < count_start) {
|
while (count_start_done < count_start) {
|
||||||
|
sleep(1);
|
||||||
act = NULL;
|
act = NULL;
|
||||||
|
|
||||||
pthread_mutex_lock(&client_mutex);
|
pthread_mutex_lock(&client_mutex);
|
||||||
@@ -5763,10 +5668,8 @@ static void adopt_locks(void)
|
|||||||
}
|
}
|
||||||
pthread_mutex_unlock(&client_mutex);
|
pthread_mutex_unlock(&client_mutex);
|
||||||
|
|
||||||
if (!act) {
|
if (!act)
|
||||||
usleep(500000);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (act->result < 0) {
|
if (act->result < 0) {
|
||||||
log_error("adopt add lockspace failed vg %s %d", act->vg_name, act->result);
|
log_error("adopt add lockspace failed vg %s %d", act->vg_name, act->result);
|
||||||
@@ -5809,12 +5712,12 @@ static void adopt_locks(void)
|
|||||||
act->op = LD_OP_LOCK;
|
act->op = LD_OP_LOCK;
|
||||||
act->rt = LD_RT_LV;
|
act->rt = LD_RT_LV;
|
||||||
act->mode = r->adopt_mode;
|
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->client_id = INTERNAL_CLIENT_ID;
|
||||||
act->lm_type = ls->lm_type;
|
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);
|
||||||
dm_strncpy(act->lv_uuid, r->name, sizeof(act->lv_uuid));
|
strncpy(act->lv_uuid, r->name, MAX_NAME);
|
||||||
dm_strncpy(act->lv_args, r->lv_args, sizeof(act->lv_args));
|
strncpy(act->lv_args, r->lv_args, MAX_ARGS);
|
||||||
|
|
||||||
log_debug("adopt lock for lv %s %s", act->vg_name, act->lv_uuid);
|
log_debug("adopt lock for lv %s %s", act->vg_name, act->lv_uuid);
|
||||||
|
|
||||||
@@ -5837,10 +5740,10 @@ static void adopt_locks(void)
|
|||||||
act->op = LD_OP_LOCK;
|
act->op = LD_OP_LOCK;
|
||||||
act->rt = LD_RT_VG;
|
act->rt = LD_RT_VG;
|
||||||
act->mode = LD_LK_SH;
|
act->mode = LD_LK_SH;
|
||||||
act->flags = LD_AF_ADOPT_ONLY;
|
act->flags = LD_AF_ADOPT;
|
||||||
act->client_id = INTERNAL_CLIENT_ID;
|
act->client_id = INTERNAL_CLIENT_ID;
|
||||||
act->lm_type = ls->lm_type;
|
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);
|
log_debug("adopt lock for vg %s", act->vg_name);
|
||||||
|
|
||||||
@@ -5863,7 +5766,7 @@ static void adopt_locks(void)
|
|||||||
act->op = LD_OP_LOCK;
|
act->op = LD_OP_LOCK;
|
||||||
act->rt = LD_RT_GL;
|
act->rt = LD_RT_GL;
|
||||||
act->mode = LD_LK_SH;
|
act->mode = LD_LK_SH;
|
||||||
act->flags = LD_AF_ADOPT_ONLY;
|
act->flags = LD_AF_ADOPT;
|
||||||
act->client_id = INTERNAL_CLIENT_ID;
|
act->client_id = INTERNAL_CLIENT_ID;
|
||||||
act->lm_type = (gl_use_sanlock ? LD_LM_SANLOCK : LD_LM_DLM);
|
act->lm_type = (gl_use_sanlock ? LD_LM_SANLOCK : LD_LM_DLM);
|
||||||
|
|
||||||
@@ -5884,6 +5787,7 @@ static void adopt_locks(void)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
while (count_adopt_done < count_adopt) {
|
while (count_adopt_done < count_adopt) {
|
||||||
|
sleep(1);
|
||||||
act = NULL;
|
act = NULL;
|
||||||
|
|
||||||
pthread_mutex_lock(&client_mutex);
|
pthread_mutex_lock(&client_mutex);
|
||||||
@@ -5893,16 +5797,14 @@ static void adopt_locks(void)
|
|||||||
}
|
}
|
||||||
pthread_mutex_unlock(&client_mutex);
|
pthread_mutex_unlock(&client_mutex);
|
||||||
|
|
||||||
if (!act) {
|
if (!act)
|
||||||
usleep(200000);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* lock adopt results
|
* lock adopt results
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (act->result == -EADOPT_RETRY) {
|
if (act->result == -EUCLEAN) {
|
||||||
/*
|
/*
|
||||||
* Adopt failed because the orphan has a different mode
|
* Adopt failed because the orphan has a different mode
|
||||||
* than initially requested. Repeat the lock-adopt operation
|
* than initially requested. Repeat the lock-adopt operation
|
||||||
@@ -5941,7 +5843,7 @@ static void adopt_locks(void)
|
|||||||
free_action(act);
|
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
|
* No orphan lock exists. This is common for GL/VG locks
|
||||||
* because they may not have been held when lvmlockd exited.
|
* because they may not have been held when lvmlockd exited.
|
||||||
@@ -6031,6 +5933,7 @@ static void adopt_locks(void)
|
|||||||
/* Wait for the unlocks to complete. */
|
/* Wait for the unlocks to complete. */
|
||||||
|
|
||||||
while (count_adopt_done < count_adopt) {
|
while (count_adopt_done < count_adopt) {
|
||||||
|
sleep(1);
|
||||||
act = NULL;
|
act = NULL;
|
||||||
|
|
||||||
pthread_mutex_lock(&client_mutex);
|
pthread_mutex_lock(&client_mutex);
|
||||||
@@ -6040,10 +5943,8 @@ static void adopt_locks(void)
|
|||||||
}
|
}
|
||||||
pthread_mutex_unlock(&client_mutex);
|
pthread_mutex_unlock(&client_mutex);
|
||||||
|
|
||||||
if (!act) {
|
if (!act)
|
||||||
usleep(200000);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (act->result < 0)
|
if (act->result < 0)
|
||||||
log_error("adopt unlock error %d", act->result);
|
log_error("adopt unlock error %d", act->result);
|
||||||
@@ -6053,18 +5954,7 @@ static void adopt_locks(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Try to purge the orphan locks when lock manager is dlm */
|
/* FIXME: purge any remaining orphan locks in each rejoined ls? */
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count_start_fail || count_adopt_fail)
|
if (count_start_fail || count_adopt_fail)
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -6102,7 +5992,7 @@ static void process_listener(int poll_fd)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(cl = alloc_client())) {
|
if (!(cl = alloc_client())) {
|
||||||
if (close(fd))
|
if (!close(fd))
|
||||||
log_error("failed to close lockd poll fd");
|
log_error("failed to close lockd poll fd");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -6379,8 +6269,9 @@ int main(int argc, char *argv[])
|
|||||||
.daemon_fini = NULL,
|
.daemon_fini = NULL,
|
||||||
.daemon_main = main_loop,
|
.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' },
|
{"help", no_argument, 0, 'h' },
|
||||||
{"version", no_argument, 0, 'V' },
|
{"version", no_argument, 0, 'V' },
|
||||||
{"test", no_argument, 0, 'T' },
|
{"test", no_argument, 0, 'T' },
|
||||||
@@ -6398,8 +6289,6 @@ int main(int argc, char *argv[])
|
|||||||
{0, 0, 0, 0 }
|
{0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
daemon_host_id_file = NULL;
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int c;
|
int c;
|
||||||
int lm;
|
int lm;
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ static int check_args_version(char *vg_args)
|
|||||||
|
|
||||||
static int read_cluster_name(char *clustername)
|
static int read_cluster_name(char *clustername)
|
||||||
{
|
{
|
||||||
|
static const char close_error_msg[] = "read_cluster_name: close_error %d";
|
||||||
char *n;
|
char *n;
|
||||||
int fd;
|
int fd;
|
||||||
int rv;
|
int rv;
|
||||||
@@ -114,19 +115,18 @@ static int read_cluster_name(char *clustername)
|
|||||||
rv = read(fd, clustername, MAX_ARGS);
|
rv = read(fd, clustername, MAX_ARGS);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("read_cluster_name: cluster name read error %d, check dlm_controld", fd);
|
log_error("read_cluster_name: cluster name read error %d, check dlm_controld", fd);
|
||||||
goto out;
|
if (close(fd))
|
||||||
|
log_error(close_error_msg, fd);
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
clustername[rv] = 0;
|
clustername[rv] = 0;
|
||||||
|
|
||||||
n = strstr(clustername, "\n");
|
n = strstr(clustername, "\n");
|
||||||
if (n)
|
if (n)
|
||||||
*n = '\0';
|
*n = '\0';
|
||||||
rv = 0;
|
|
||||||
out:
|
|
||||||
if (close(fd))
|
if (close(fd))
|
||||||
log_error("read_cluster_name: close_error %d", fd);
|
log_error(close_error_msg, fd);
|
||||||
|
return 0;
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_VERSION 16
|
#define MAX_VERSION 16
|
||||||
@@ -220,112 +220,20 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DLM_COMMS_PATH "/sys/kernel/config/dlm/cluster/comms"
|
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
|
||||||
#define LOCK_LINE_MAX 1024
|
|
||||||
static int get_local_nodeid(void)
|
|
||||||
{
|
|
||||||
struct dirent *de;
|
|
||||||
DIR *ls_dir;
|
|
||||||
char ls_comms_path[PATH_MAX] = { 0 };
|
|
||||||
char path[PATH_MAX] = { 0 };
|
|
||||||
FILE *file;
|
|
||||||
char line[LOCK_LINE_MAX];
|
|
||||||
char *str1, *str2;
|
|
||||||
int rv = -1, val;
|
|
||||||
|
|
||||||
snprintf(ls_comms_path, sizeof(ls_comms_path), "%s", DLM_COMMS_PATH);
|
|
||||||
|
|
||||||
if (!(ls_dir = opendir(ls_comms_path)))
|
|
||||||
return -ECONNREFUSED;
|
|
||||||
|
|
||||||
while ((de = readdir(ls_dir))) {
|
|
||||||
if (de->d_name[0] == '.')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "%s/%s/local",
|
|
||||||
DLM_COMMS_PATH, de->d_name);
|
|
||||||
|
|
||||||
if (!(file = fopen(ls_comms_path, "r")))
|
|
||||||
continue;
|
|
||||||
str1 = fgets(line, sizeof(line), file);
|
|
||||||
if (fclose(file))
|
|
||||||
log_sys_debug("fclose", path);
|
|
||||||
if (str1) {
|
|
||||||
rv = sscanf(line, "%d", &val);
|
|
||||||
if ((rv == 1) && (val == 1 )) {
|
|
||||||
snprintf(path, sizeof(path), "%s/%s/nodeid",
|
|
||||||
DLM_COMMS_PATH, de->d_name);
|
|
||||||
|
|
||||||
if (!(file = fopen(path, "r")))
|
|
||||||
continue;
|
|
||||||
str2 = fgets(line, sizeof(line), file);
|
|
||||||
if (fclose(file))
|
|
||||||
log_sys_debug("fclose", path);
|
|
||||||
if (str2) {
|
|
||||||
rv = sscanf(line, "%d", &val);
|
|
||||||
if (rv == 1) {
|
|
||||||
if (closedir(ls_dir))
|
|
||||||
log_sys_debug("closedir", ls_comms_path);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (closedir(ls_dir))
|
|
||||||
log_sys_debug("closedir", ls_comms_path);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_purge_locks_dlm(struct lockspace *ls)
|
|
||||||
{
|
|
||||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
|
||||||
int nodeid;
|
|
||||||
int rv = -1;
|
|
||||||
|
|
||||||
if (!lmd || !lmd->dh) {
|
|
||||||
log_error("purge_locks_dlm %s no dlm_handle_t error", ls->name);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeid = get_local_nodeid();
|
|
||||||
if (nodeid < 0) {
|
|
||||||
log_error("failed to get local nodeid");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (dlm_ls_purge(lmd->dh, nodeid, 0)) {
|
|
||||||
log_error("purge_locks_dlm %s error", ls->name);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = 0;
|
|
||||||
fail:
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok)
|
|
||||||
{
|
{
|
||||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
|
|
||||||
if (daemon_test)
|
if (daemon_test)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (adopt_only || adopt_ok) {
|
if (adopt)
|
||||||
lmd->dh = dlm_open_lockspace(ls->name);
|
lmd->dh = dlm_open_lockspace(ls->name);
|
||||||
if (!lmd->dh && adopt_ok)
|
else
|
||||||
lmd->dh = dlm_new_lockspace(ls->name, 0600, DLM_LSFL_NEWEXCL);
|
lmd->dh = dlm_new_lockspace(ls->name, 0600, DLM_LSFL_NEWEXCL);
|
||||||
if (!lmd->dh)
|
|
||||||
log_error("add_lockspace_dlm adopt_only %d adopt_ok %d %s error",
|
|
||||||
adopt_only, adopt_ok, ls->name);
|
|
||||||
} else {
|
|
||||||
lmd->dh = dlm_new_lockspace(ls->name, 0600, DLM_LSFL_NEWEXCL);
|
|
||||||
if (!lmd->dh)
|
|
||||||
log_error("add_lockspace_dlm %s error", ls->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lmd->dh) {
|
if (!lmd->dh) {
|
||||||
|
log_error("add_lockspace_dlm %s adopt %d error", ls->name, adopt);
|
||||||
free(lmd);
|
free(lmd);
|
||||||
ls->lm_data = NULL;
|
ls->lm_data = NULL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -393,7 +301,7 @@ static int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int wit
|
|||||||
r->name, strlen(r->name),
|
r->name, strlen(r->name),
|
||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("%s:%s add_resource_dlm lock error %d", ls->name, r->name, rv);
|
log_error("S %s R %s add_resource_dlm lock error %d", ls->name, r->name, rv);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
@@ -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);
|
rv = dlm_ls_unlock_wait(lmd->dh, lksb->sb_lkid, 0, lksb);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("%s:%s rem_resource_dlm unlock error %d", ls->name, r->name, rv);
|
log_error("S %s R %s rem_resource_dlm unlock error %d", ls->name, r->name, rv);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
free(rdd->vb);
|
free(rdd->vb);
|
||||||
@@ -472,7 +380,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("%s:%s adopt_dlm", ls->name, r->name);
|
log_debug("S %s R %s adopt_dlm", ls->name, r->name);
|
||||||
|
|
||||||
if (daemon_test)
|
if (daemon_test)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -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
|
* dlm returns 0 for success, -EAGAIN if an orphan is
|
||||||
* found with another mode, and -ENOENT if no orphan.
|
* found with another mode, and -ENOENT if no orphan.
|
||||||
*
|
*
|
||||||
* cast/bast/param are (void (*)(void*))1 because the kernel
|
* cast/bast/param are (void *)1 because the kernel
|
||||||
* returns errors if some are null.
|
* returns errors if some are null.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rv = dlm_ls_lockx(lmd->dh, mode, lksb, flags,
|
rv = dlm_ls_lockx(lmd->dh, mode, lksb, flags,
|
||||||
r->name, strlen(r->name), 0,
|
r->name, strlen(r->name), 0,
|
||||||
(void (*)(void*))1, (void (*)(void*))1, (void (*)(void*))1,
|
(void *)1, (void *)1, (void *)1,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
if (rv == -1 && (errno == EAGAIN)) {
|
if (rv == -1 && (errno == EAGAIN)) {
|
||||||
log_debug("%s:%s adopt_dlm adopt mode %d try other mode",
|
log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
|
||||||
ls->name, r->name, ld_mode);
|
ls->name, r->name, ld_mode);
|
||||||
rv = -EADOPT_RETRY;
|
rv = -EUCLEAN;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (rv == -1 && (errno == ENOENT)) {
|
if (rv == -1 && (errno == ENOENT)) {
|
||||||
log_debug("%s:%s adopt_dlm adopt mode %d no lock",
|
log_debug("S %s R %s adopt_dlm adopt mode %d no lock",
|
||||||
ls->name, r->name, ld_mode);
|
ls->name, r->name, ld_mode);
|
||||||
rv = -EADOPT_NONE;
|
rv = -ENOENT;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_debug("%s:%s adopt_dlm mode %d flags %x error %d errno %d",
|
log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
|
||||||
ls->name, r->name, mode, flags, rv, errno);
|
ls->name, r->name, mode, flags, rv, errno);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -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,
|
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int adopt_only, int adopt_ok)
|
struct val_blk *vb_out, int adopt)
|
||||||
{
|
{
|
||||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
@@ -543,13 +451,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
int mode;
|
int mode;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if (adopt_ok) {
|
if (adopt) {
|
||||||
log_debug("%s:%s lock_dlm adopt_ok not supported", ls->name, r->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adopt_only) {
|
|
||||||
log_debug("%s:%s lock_dlm adopt_only", ls->name, r->name);
|
|
||||||
/* When adopting, we don't follow the normal method
|
/* When adopting, we don't follow the normal method
|
||||||
of acquiring a NL lock then converting it to the
|
of acquiring a NL lock then converting it to the
|
||||||
desired mode. */
|
desired mode. */
|
||||||
@@ -578,7 +480,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("%s:%s lock_dlm", ls->name, r->name);
|
log_debug("S %s R %s lock_dlm", ls->name, r->name);
|
||||||
|
|
||||||
if (daemon_test) {
|
if (daemon_test) {
|
||||||
if (rdd->vb) {
|
if (rdd->vb) {
|
||||||
@@ -598,7 +500,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
r->name, strlen(r->name),
|
r->name, strlen(r->name),
|
||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
if (rv == -1) {
|
if (rv == -1) {
|
||||||
log_debug("%s:%s lock_dlm acquire mode PR for %d rv %d",
|
log_debug("S %s R %s lock_dlm acquire mode PR for %d rv %d",
|
||||||
ls->name, r->name, mode, rv);
|
ls->name, r->name, mode, rv);
|
||||||
goto lockrv;
|
goto lockrv;
|
||||||
}
|
}
|
||||||
@@ -611,17 +513,17 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
lockrv:
|
lockrv:
|
||||||
if (rv == -1 && errno == EAGAIN) {
|
if (rv == -1 && errno == EAGAIN) {
|
||||||
log_debug("%s:%s lock_dlm acquire mode %d rv EAGAIN", ls->name, r->name, mode);
|
log_debug("S %s R %s lock_dlm acquire mode %d rv EAGAIN", ls->name, r->name, mode);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("%s:%s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
|
log_error("S %s R %s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
|
||||||
return -ELMERR;
|
return -ELMERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rdd->vb) {
|
if (rdd->vb) {
|
||||||
if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
|
if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
|
||||||
log_debug("%s:%s lock_dlm VALNOTVALID", ls->name, r->name);
|
log_debug("S %s R %s lock_dlm VALNOTVALID", ls->name, r->name);
|
||||||
memset(rdd->vb, 0, sizeof(struct val_blk));
|
memset(rdd->vb, 0, sizeof(struct val_blk));
|
||||||
memset(vb_out, 0, sizeof(struct val_blk));
|
memset(vb_out, 0, sizeof(struct val_blk));
|
||||||
goto out;
|
goto out;
|
||||||
@@ -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 lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
struct dlm_lksb *lksb = &rdd->lksb;
|
struct dlm_lksb *lksb = &rdd->lksb;
|
||||||
int mode;
|
uint32_t mode;
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
log_debug("%s:%s convert_dlm", ls->name, r->name);
|
log_debug("S %s R %s convert_dlm", ls->name, r->name);
|
||||||
|
|
||||||
flags |= LKF_CONVERT;
|
flags |= LKF_CONVERT;
|
||||||
flags |= LKF_NOQUEUE;
|
flags |= LKF_NOQUEUE;
|
||||||
@@ -668,16 +570,14 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
rdd->vb->r_version = cpu_to_le32(r_version);
|
rdd->vb->r_version = cpu_to_le32(r_version);
|
||||||
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
|
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
|
||||||
|
|
||||||
log_debug("%s:%s convert_dlm set r_version %u",
|
log_debug("S %s R %s convert_dlm set r_version %u",
|
||||||
ls->name, r->name, r_version);
|
ls->name, r->name, r_version);
|
||||||
|
|
||||||
flags |= LKF_VALBLK;
|
flags |= LKF_VALBLK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mode = to_dlm_mode(ld_mode)) < 0) {
|
mode = to_dlm_mode(ld_mode);
|
||||||
log_error("lm_convert_dlm invalid mode %d", ld_mode);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (daemon_test)
|
if (daemon_test)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -686,11 +586,11 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
if (rv == -1 && errno == EAGAIN) {
|
if (rv == -1 && errno == EAGAIN) {
|
||||||
/* FIXME: When does this happen? Should something different be done? */
|
/* FIXME: When does this happen? Should something different be done? */
|
||||||
log_error("%s:%s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
|
log_error("S %s R %s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("%s:%s convert_dlm error %d", ls->name, r->name, rv);
|
log_error("S %s R %s convert_dlm error %d", ls->name, r->name, rv);
|
||||||
rv = -ELMERR;
|
rv = -ELMERR;
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
@@ -740,7 +640,7 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
memcpy(rdd->vb, &vb_next, sizeof(struct val_blk));
|
memcpy(rdd->vb, &vb_next, sizeof(struct val_blk));
|
||||||
memcpy(lksb->sb_lvbptr, &vb_next, sizeof(struct val_blk));
|
memcpy(lksb->sb_lvbptr, &vb_next, sizeof(struct val_blk));
|
||||||
|
|
||||||
log_debug("%s:%s unlock_dlm vb old %x %x %u new %x %x %u",
|
log_debug("S %s R %s unlock_dlm vb old %x %x %u new %x %x %u",
|
||||||
ls->name, r->name,
|
ls->name, r->name,
|
||||||
le16_to_cpu(vb_prev.version),
|
le16_to_cpu(vb_prev.version),
|
||||||
le16_to_cpu(vb_prev.flags),
|
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),
|
le16_to_cpu(vb_next.flags),
|
||||||
le32_to_cpu(vb_next.r_version));
|
le32_to_cpu(vb_next.r_version));
|
||||||
} else {
|
} else {
|
||||||
log_debug("%s:%s unlock_dlm vb unchanged", ls->name, r->name);
|
log_debug("S %s R %s unlock_dlm vb unchanged", ls->name, r->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
flags |= LKF_VALBLK;
|
flags |= LKF_VALBLK;
|
||||||
} else {
|
} else {
|
||||||
log_debug("%s:%s unlock_dlm", ls->name, r->name);
|
log_debug("S %s R %s unlock_dlm", ls->name, r->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (daemon_test)
|
if (daemon_test)
|
||||||
@@ -764,7 +664,7 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
r->name, strlen(r->name),
|
r->name, strlen(r->name),
|
||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("%s:%s unlock_dlm error %d", ls->name, r->name, rv);
|
log_error("S %s R %s unlock_dlm error %d", ls->name, r->name, rv);
|
||||||
rv = -ELMERR;
|
rv = -ELMERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -799,6 +699,7 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
|
|
||||||
int lm_hosts_dlm(struct lockspace *ls, int notify)
|
int lm_hosts_dlm(struct lockspace *ls, int notify)
|
||||||
{
|
{
|
||||||
|
static const char closedir_err_msg[] = "lm_hosts_dlm: closedir failed";
|
||||||
char ls_nodes_path[PATH_MAX];
|
char ls_nodes_path[PATH_MAX];
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
DIR *ls_dir;
|
DIR *ls_dir;
|
||||||
@@ -821,7 +722,7 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (closedir(ls_dir))
|
if (closedir(ls_dir))
|
||||||
log_error("lm_hosts_dlm: closedir failed");
|
log_error(closedir_err_msg);
|
||||||
|
|
||||||
if (!count) {
|
if (!count) {
|
||||||
log_error("lm_hosts_dlm found no nodes in %s", ls_nodes_path);
|
log_error("lm_hosts_dlm found no nodes in %s", ls_nodes_path);
|
||||||
@@ -838,10 +739,10 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
|
|||||||
|
|
||||||
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||||
{
|
{
|
||||||
|
static const char closedir_err_msg[] = "lm_get_lockspace_dlm: closedir failed";
|
||||||
struct lockspace *ls;
|
struct lockspace *ls;
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
DIR *ls_dir;
|
DIR *ls_dir;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (!(ls_dir = opendir(DLM_LOCKSPACES_PATH)))
|
if (!(ls_dir = opendir(DLM_LOCKSPACES_PATH)))
|
||||||
return -ECONNREFUSED;
|
return -ECONNREFUSED;
|
||||||
@@ -854,20 +755,20 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!(ls = alloc_lockspace())) {
|
if (!(ls = alloc_lockspace())) {
|
||||||
ret = -ENOMEM;
|
if (closedir(ls_dir))
|
||||||
goto out;
|
log_error(closedir_err_msg);
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ls->lm_type = LD_LM_DLM;
|
ls->lm_type = LD_LM_DLM;
|
||||||
dm_strncpy(ls->name, de->d_name, sizeof(ls->name));
|
strncpy(ls->name, de->d_name, MAX_NAME);
|
||||||
dm_strncpy(ls->vg_name, ls->name + strlen(LVM_LS_PREFIX), sizeof(ls->vg_name));
|
strncpy(ls->vg_name, ls->name + strlen(LVM_LS_PREFIX), MAX_NAME);
|
||||||
list_add_tail(&ls->list, ls_rejoin);
|
list_add_tail(&ls->list, ls_rejoin);
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
if (closedir(ls_dir))
|
|
||||||
log_error("lm_get_lockspace_dlm: closedir failed");
|
|
||||||
|
|
||||||
return ret;
|
if (closedir(ls_dir))
|
||||||
|
log_error(closedir_err_msg);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lm_is_running_dlm(void)
|
int lm_is_running_dlm(void)
|
||||||
@@ -897,7 +798,7 @@ int lm_refresh_lv_start_dlm(struct action *act)
|
|||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
/* split /dev/vgname/lvname into vgname and lvname strings */
|
/* split /dev/vgname/lvname into vgname and lvname strings */
|
||||||
dm_strncpy(path, act->path, sizeof(path));
|
strncpy(path, act->path, PATH_MAX-1);
|
||||||
|
|
||||||
/* skip past dev */
|
/* skip past dev */
|
||||||
if (!(p = strchr(path + 1, '/')))
|
if (!(p = strchr(path + 1, '/')))
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ int lm_prepare_lockspace_idm(struct lockspace *ls)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok)
|
int lm_add_lockspace_idm(struct lockspace *ls, int adopt)
|
||||||
{
|
{
|
||||||
char killpath[IDM_FAILURE_PATH_LEN];
|
char killpath[IDM_FAILURE_PATH_LEN];
|
||||||
char killargs[IDM_FAILURE_ARGS_LEN];
|
char killargs[IDM_FAILURE_ARGS_LEN];
|
||||||
@@ -530,7 +530,7 @@ static int to_idm_mode(int ld_mode)
|
|||||||
|
|
||||||
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
||||||
int adopt_only, int adopt_ok)
|
int adopt)
|
||||||
{
|
{
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
||||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
||||||
|
|||||||
@@ -107,12 +107,11 @@ struct client {
|
|||||||
#define LD_AF_SEARCH_LS 0x00000200
|
#define LD_AF_SEARCH_LS 0x00000200
|
||||||
#define LD_AF_WAIT_STARTING 0x00001000
|
#define LD_AF_WAIT_STARTING 0x00001000
|
||||||
#define LD_AF_DUP_GL_LS 0x00002000
|
#define LD_AF_DUP_GL_LS 0x00002000
|
||||||
#define LD_AF_ADOPT 0x00010000 /* adopt ok but not required */
|
#define LD_AF_ADOPT 0x00010000
|
||||||
#define LD_AF_WARN_GL_REMOVED 0x00020000
|
#define LD_AF_WARN_GL_REMOVED 0x00020000
|
||||||
#define LD_AF_LV_LOCK 0x00040000
|
#define LD_AF_LV_LOCK 0x00040000
|
||||||
#define LD_AF_LV_UNLOCK 0x00080000
|
#define LD_AF_LV_UNLOCK 0x00080000
|
||||||
#define LD_AF_SH_EXISTS 0x00100000
|
#define LD_AF_SH_EXISTS 0x00100000
|
||||||
#define LD_AF_ADOPT_ONLY 0x00200000 /* adopt orphan or fail */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of times to repeat a lock request after
|
* 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_debug(fmt, args...) log_level(LOG_DEBUG, fmt, ##args)
|
||||||
#define log_error(fmt, args...) log_level(LOG_ERR, fmt, ##args)
|
#define log_error(fmt, args...) log_level(LOG_ERR, fmt, ##args)
|
||||||
#define log_warn(fmt, args...) log_level(LOG_WARNING, fmt, ##args)
|
#define log_warn(fmt, args...) log_level(LOG_WARNING, fmt, ##args)
|
||||||
#define log_sys_debug(x, y) \
|
|
||||||
log_debug("%s: %s failed: %s", y, x, strerror(errno))
|
|
||||||
|
|
||||||
struct lockspace *alloc_lockspace(void);
|
struct lockspace *alloc_lockspace(void);
|
||||||
int lockspaces_empty(void);
|
int lockspaces_empty(void);
|
||||||
@@ -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_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||||
int lm_prepare_lockspace_dlm(struct lockspace *ls);
|
int lm_prepare_lockspace_dlm(struct lockspace *ls);
|
||||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok);
|
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
|
||||||
int lm_purge_locks_dlm(struct lockspace *ls);
|
|
||||||
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
|
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
|
||||||
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int adopt_only, int adopt_ok);
|
struct val_blk *vb_out, int adopt);
|
||||||
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||||
int ld_mode, uint32_t r_version);
|
int ld_mode, uint32_t r_version);
|
||||||
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||||
@@ -428,12 +424,7 @@ static inline int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok)
|
static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_purge_locks_dlm(struct lockspace *ls)
|
|
||||||
{
|
{
|
||||||
return -1;
|
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,
|
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;
|
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_free_lv_sanlock(struct lockspace *ls, struct resource *r);
|
||||||
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||||
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
|
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_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
|
||||||
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int *retry,
|
struct val_blk *vb_out, int *retry, int adopt);
|
||||||
int adopt_only, int adopt_ok);
|
|
||||||
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
||||||
int ld_mode, uint32_t r_version);
|
int ld_mode, uint32_t r_version);
|
||||||
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||||
@@ -561,7 +551,7 @@ static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok)
|
static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt)
|
||||||
{
|
{
|
||||||
return -1;
|
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,
|
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int *retry,
|
struct val_blk *vb_out, int *retry, int adopt)
|
||||||
int adopt_only, int adopt_ok)
|
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -647,11 +636,11 @@ static inline int lm_support_sanlock(void)
|
|||||||
int lm_data_size_idm(void);
|
int lm_data_size_idm(void);
|
||||||
int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||||
int lm_prepare_lockspace_idm(struct lockspace *ls);
|
int lm_prepare_lockspace_idm(struct lockspace *ls);
|
||||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok);
|
int lm_add_lockspace_idm(struct lockspace *ls, int adopt);
|
||||||
int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg);
|
int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg);
|
||||||
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
||||||
int adopt_only, int adopt_ok);
|
int adopt);
|
||||||
int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
||||||
int ld_mode, uint32_t r_version);
|
int ld_mode, uint32_t r_version);
|
||||||
int lm_unlock_idm(struct lockspace *ls, struct resource *r,
|
int lm_unlock_idm(struct lockspace *ls, struct resource *r,
|
||||||
@@ -684,7 +673,7 @@ static inline int lm_prepare_lockspace_idm(struct lockspace *ls)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok)
|
static inline int lm_add_lockspace_idm(struct lockspace *ls, int adopt)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -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,
|
static inline int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
||||||
int adopt_only, int adopt_ok)
|
int adopt)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,21 @@
|
|||||||
#include "sanlock_admin.h"
|
#include "sanlock_admin.h"
|
||||||
#include "sanlock_resource.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 <stddef.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -214,13 +229,13 @@ static uint64_t daemon_test_lv_count;
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy a null-terminated string "str" into a fixed
|
* Copy a null-terminated string "str" into a fixed
|
||||||
* size struct field "buf" which is not null terminated.
|
* size (SANLK_NAME_LEN) struct field "buf" which is
|
||||||
* (ATM SANLK_NAME_LEN is only 48 bytes.
|
* not null terminated.
|
||||||
* Use memccpy() instead of strncpy().
|
|
||||||
*/
|
*/
|
||||||
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)
|
static int lock_lv_name_from_args(char *vg_args, char *lock_lv_name)
|
||||||
@@ -516,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(&ss, 0, sizeof(ss));
|
||||||
memset(&rd, 0, sizeof(rd));
|
memset(&rd, 0, sizeof(rd));
|
||||||
memset(&disk, 0, sizeof(disk));
|
memset(&disk, 0, sizeof(disk));
|
||||||
|
memset(lock_lv_name, 0, sizeof(lock_lv_name));
|
||||||
memset(lock_args_version, 0, sizeof(lock_args_version));
|
memset(lock_args_version, 0, sizeof(lock_args_version));
|
||||||
|
|
||||||
if (!vg_args || !vg_args[0] || !strcmp(vg_args, "none")) {
|
if (!vg_args || !vg_args[0] || !strcmp(vg_args, "none")) {
|
||||||
@@ -527,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);
|
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
|
||||||
|
|
||||||
/* see comment above about input vg_args being only lock_lv_name */
|
/* 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)
|
if (strlen(lock_lv_name) + strlen(lock_args_version) + 2 > MAX_ARGS)
|
||||||
return -EARGS;
|
return -EARGS;
|
||||||
@@ -602,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;
|
gl_name = R_NAME_GL;
|
||||||
|
|
||||||
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
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);
|
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
||||||
rd.rs.disks[0].offset = align_size * GL_LOCK_BEGIN;
|
rd.rs.disks[0].offset = align_size * GL_LOCK_BEGIN;
|
||||||
rd.rs.num_disks = 1;
|
rd.rs.num_disks = 1;
|
||||||
@@ -617,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);
|
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);
|
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
||||||
rd.rs.disks[0].offset = align_size * VG_LOCK_BEGIN;
|
rd.rs.disks[0].offset = align_size * VG_LOCK_BEGIN;
|
||||||
rd.rs.num_disks = 1;
|
rd.rs.num_disks = 1;
|
||||||
@@ -632,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))
|
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);
|
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
|
||||||
if (rv >= MAX_ARGS)
|
if (rv >= MAX_ARGS)
|
||||||
@@ -652,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);
|
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||||
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
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.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;
|
offset = align_size * LV_LOCK_BEGIN;
|
||||||
|
|
||||||
@@ -999,16 +1015,16 @@ int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r)
|
|||||||
struct sanlk_resource *rs = &rds->rs;
|
struct sanlk_resource *rs = &rds->rs;
|
||||||
int rv;
|
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)
|
if (daemon_test)
|
||||||
return 0;
|
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);
|
rv = sanlock_write_resource(rs, 0, 0, 0);
|
||||||
if (rv < 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);
|
ls->name, r->name, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1039,10 +1055,10 @@ int lm_ex_disable_gl_sanlock(struct lockspace *ls)
|
|||||||
memset(&rd2, 0, sizeof(rd2));
|
memset(&rd2, 0, sizeof(rd2));
|
||||||
|
|
||||||
strcpy_name_len(rd1.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
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.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;
|
rd1.rs.num_disks = 1;
|
||||||
memcpy(rd1.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
memcpy(rd1.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||||
@@ -1108,7 +1124,7 @@ int lm_able_gl_sanlock(struct lockspace *ls, int enable)
|
|||||||
memset(&rd, 0, sizeof(rd));
|
memset(&rd, 0, sizeof(rd));
|
||||||
|
|
||||||
strcpy_name_len(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
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;
|
rd.rs.num_disks = 1;
|
||||||
memcpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
memcpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||||
@@ -1128,7 +1144,7 @@ out:
|
|||||||
ls->sanlock_gl_enabled = enable;
|
ls->sanlock_gl_enabled = enable;
|
||||||
|
|
||||||
if (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))
|
if (!enable && !strcmp(gl_lsname_sanlock, ls->name))
|
||||||
memset(gl_lsname_sanlock, 0, sizeof(gl_lsname_sanlock));
|
memset(gl_lsname_sanlock, 0, sizeof(gl_lsname_sanlock));
|
||||||
@@ -1319,7 +1335,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
struct lm_sanlock *lms = NULL;
|
struct lm_sanlock *lms = NULL;
|
||||||
char lock_lv_name[MAX_ARGS+1];
|
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 disk_path[SANLK_PATH_LEN];
|
||||||
char killpath[SANLK_PATH_LEN];
|
char killpath[SANLK_PATH_LEN];
|
||||||
char killargs[SANLK_PATH_LEN];
|
char killargs[SANLK_PATH_LEN];
|
||||||
@@ -1400,7 +1416,8 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
|||||||
goto fail;
|
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);
|
memcpy(lms->ss.name, lsname, SANLK_NAME_LEN);
|
||||||
lms->ss.host_id_disk.offset = 0;
|
lms->ss.host_id_disk.offset = 0;
|
||||||
@@ -1501,7 +1518,7 @@ fail:
|
|||||||
return ret;
|
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;
|
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
|
||||||
int rv;
|
int rv;
|
||||||
@@ -1512,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);
|
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. */
|
/* We could alternatively just skip the sanlock call for adopt. */
|
||||||
log_debug("S %s add_lockspace_san adopt found ls", ls->name);
|
log_debug("S %s add_lockspace_san adopt found ls", ls->name);
|
||||||
goto out;
|
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) {
|
if (rv < 0) {
|
||||||
/* retry for some errors? */
|
/* retry for some errors? */
|
||||||
log_error("S %s add_lockspace_san add_lockspace error %d", ls->name, rv);
|
log_error("S %s add_lockspace_san add_lockspace error %d", ls->name, rv);
|
||||||
@@ -1563,10 +1576,8 @@ int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
rv = sanlock_rem_lockspace(&lms->ss, 0);
|
rv = sanlock_rem_lockspace(&lms->ss, 0);
|
||||||
if (rv < 0) {
|
if (rv < 0)
|
||||||
log_error("S %s rem_lockspace_san error %d", ls->name, rv);
|
log_error("S %s rem_lockspace_san error %d", ls->name, rv);
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (free_vg) {
|
if (free_vg) {
|
||||||
/*
|
/*
|
||||||
@@ -1575,7 +1586,7 @@ int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
|
|||||||
* This shouldn't be generally necessary, but there may some races
|
* This shouldn't be generally necessary, but there may some races
|
||||||
* between nodes starting and removing a vg which this could help.
|
* 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);
|
rv = sanlock_write_lockspace(&lms->ss, 0, 0, sanlock_io_timeout);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
@@ -1616,17 +1627,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. */
|
/* 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) {
|
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
||||||
rds->vb = zalloc(sizeof(struct val_blk));
|
rds->vb = zalloc(sizeof(struct val_blk));
|
||||||
if (!rds->vb)
|
if (!rds->vb)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1635,16 +1641,16 @@ int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r)
|
|||||||
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
|
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
|
||||||
|
|
||||||
/* FIXME: assert r->mode == UN or unlock if it's not? */
|
/* FIXME: assert r->mode == UN or unlock if it's not? */
|
||||||
#ifdef LVMLOCKD_USE_SANLOCK_LVB
|
|
||||||
free(rds->vb);
|
free(rds->vb);
|
||||||
#endif
|
|
||||||
memset(rds, 0, sizeof(struct rd_sanlock));
|
memset(rds, 0, sizeof(struct rd_sanlock));
|
||||||
r->lm_init = 0;
|
r->lm_init = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int *retry, 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 lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
|
||||||
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
|
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
|
||||||
@@ -1684,20 +1690,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);
|
rv = check_args_version(r->lv_args, LV_LOCK_ARGS_MAJOR);
|
||||||
if (rv < 0) {
|
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);
|
ls->name, r->name, r->lv_args);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = lock_lv_offset_from_args(r->lv_args, &lock_lv_offset);
|
rv = lock_lv_offset_from_args(r->lv_args, &lock_lv_offset);
|
||||||
if (rv < 0) {
|
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);
|
ls->name, r->name, rv, r->lv_args);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!added && (rds->rs.disks[0].offset != lock_lv_offset)) {
|
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,
|
ls->name, r->name,
|
||||||
(unsigned long long)rds->rs.disks[0].offset,
|
(unsigned long long)rds->rs.disks[0].offset,
|
||||||
(unsigned long long)lock_lv_offset);
|
(unsigned long long)lock_lv_offset);
|
||||||
@@ -1723,7 +1729,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
|
|
||||||
rs->flags |= SANLK_RES_PERSISTENT;
|
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,
|
ls->name, r->name, mode_str(ld_mode), rs->disks[0].path,
|
||||||
(unsigned long long)rs->disks[0].offset);
|
(unsigned long long)rs->disks[0].offset);
|
||||||
|
|
||||||
@@ -1738,10 +1744,8 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
|
|
||||||
if (rds->vb)
|
if (rds->vb)
|
||||||
flags |= SANLK_ACQUIRE_LVB;
|
flags |= SANLK_ACQUIRE_LVB;
|
||||||
if (adopt_only)
|
if (adopt)
|
||||||
flags |= SANLK_ACQUIRE_ORPHAN_ONLY;
|
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
|
* Don't block waiting for a failed lease to expire since it causes
|
||||||
@@ -1767,7 +1771,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.
|
* a shared lock but the lock is held ex by another host.
|
||||||
* There's no point in retrying this case, just return an error.
|
* 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;
|
*retry = 0;
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
@@ -1781,31 +1785,31 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
* The lvm command will see this error, refresh the lvmlock
|
* The lvm command will see this error, refresh the lvmlock
|
||||||
* lv, and try again.
|
* 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);
|
ls->name, r->name, (unsigned long long)rs->disks[0].offset);
|
||||||
*retry = 0;
|
*retry = 0;
|
||||||
return -EMSGSIZE;
|
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
|
* The orphan lock exists but in a different mode than we asked
|
||||||
* for, so the caller should try again with the other mode.
|
* 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);
|
ls->name, r->name, ld_mode);
|
||||||
*retry = 0;
|
*retry = 0;
|
||||||
return -EADOPT_RETRY;
|
return -EUCLEAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adopt_only && (rv == -ENOENT)) {
|
if (adopt && (rv == -ENOENT)) {
|
||||||
/*
|
/*
|
||||||
* No orphan lock exists.
|
* 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);
|
ls->name, r->name, ld_mode);
|
||||||
*retry = 0;
|
*retry = 0;
|
||||||
return -EADOPT_NONE;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rv == SANLK_ACQUIRE_IDLIVE || rv == SANLK_ACQUIRE_OWNED || rv == SANLK_ACQUIRE_OTHER) {
|
if (rv == SANLK_ACQUIRE_IDLIVE || rv == SANLK_ACQUIRE_OWNED || rv == SANLK_ACQUIRE_OTHER) {
|
||||||
@@ -1824,7 +1828,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
* so if requesting a sh lock, retry a couple times,
|
* so if requesting a sh lock, retry a couple times,
|
||||||
* otherwise don't.
|
* 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;
|
*retry = (ld_mode == LD_LK_SH) ? 1 : 0;
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
@@ -1834,7 +1838,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
|
* sanlock got an i/o timeout when trying to acquire the
|
||||||
* lease on disk.
|
* 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;
|
*retry = 0;
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
@@ -1844,7 +1848,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
* There was contention with another host for the lease,
|
* There was contention with another host for the lease,
|
||||||
* and we lost.
|
* 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;
|
*retry = 0;
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
@@ -1863,19 +1867,19 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
* command can print an different error indicating that the
|
* command can print an different error indicating that the
|
||||||
* owner of the lease is in the process of expiring?
|
* 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;
|
*retry = 0;
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rv < 0) {
|
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);
|
ls->name, r->name, rv);
|
||||||
|
|
||||||
/* if the gl has been disabled, remove and free the gl resource */
|
/* if the gl has been disabled, remove and free the gl resource */
|
||||||
if ((rv == SANLK_LEADER_RESOURCE) && (r->type == LD_RT_GL)) {
|
if ((rv == SANLK_LEADER_RESOURCE) && (r->type == LD_RT_GL)) {
|
||||||
if (!lm_gl_is_enabled(ls)) {
|
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);
|
ls->name, r->name);
|
||||||
if (!strcmp(gl_lsname_sanlock, ls->name))
|
if (!strcmp(gl_lsname_sanlock, ls->name))
|
||||||
memset(gl_lsname_sanlock, 0, sizeof(gl_lsname_sanlock));
|
memset(gl_lsname_sanlock, 0, sizeof(gl_lsname_sanlock));
|
||||||
@@ -1888,7 +1892,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. */
|
/* sanlock gets i/o errors trying to read/write the leases. */
|
||||||
if (rv == -EIO)
|
if (rv == -EIO)
|
||||||
return -ELOCKIO;
|
rv = -ELOCKIO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The sanlock lockspace can disappear if the lease storage fails,
|
* The sanlock lockspace can disappear if the lease storage fails,
|
||||||
@@ -1897,11 +1901,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
* stop and free the lockspace.
|
* stop and free the lockspace.
|
||||||
*/
|
*/
|
||||||
if (rv == -ENOSPC)
|
if (rv == -ENOSPC)
|
||||||
return -ELOCKIO;
|
rv = -ELOCKIO;
|
||||||
|
|
||||||
/* The request conflicted with an orphan lock. */
|
|
||||||
if (rv == -EUCLEAN)
|
|
||||||
return -EORPHAN;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* generic error number for sanlock errors that we are not
|
* generic error number for sanlock errors that we are not
|
||||||
@@ -1917,7 +1917,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
if (rds->vb) {
|
if (rds->vb) {
|
||||||
rv = sanlock_get_lvb(0, rs, (char *)&vb, sizeof(vb));
|
rv = sanlock_get_lvb(0, rs, (char *)&vb, sizeof(vb));
|
||||||
if (rv < 0) {
|
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(rds->vb, 0, sizeof(struct val_blk));
|
||||||
memset(vb_out, 0, sizeof(struct val_blk));
|
memset(vb_out, 0, sizeof(struct val_blk));
|
||||||
/* the lock is still acquired, the vb values considered invalid */
|
/* the lock is still acquired, the vb values considered invalid */
|
||||||
@@ -1952,7 +1952,7 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
|||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
int rv;
|
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));
|
ls->name, r->name, mode_str(r->mode), mode_str(ld_mode));
|
||||||
|
|
||||||
if (daemon_test)
|
if (daemon_test)
|
||||||
@@ -1967,12 +1967,12 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
|||||||
rds->vb->r_version = cpu_to_le32(r_version);
|
rds->vb->r_version = cpu_to_le32(r_version);
|
||||||
memcpy(&vb, rds->vb, sizeof(vb));
|
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);
|
ls->name, r->name, r_version);
|
||||||
|
|
||||||
rv = sanlock_set_lvb(0, rs, (char *)&vb, sizeof(vb));
|
rv = sanlock_set_lvb(0, rs, (char *)&vb, sizeof(vb));
|
||||||
if (rv < 0) {
|
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);
|
ls->name, r->name, rv);
|
||||||
return -ELMERR;
|
return -ELMERR;
|
||||||
}
|
}
|
||||||
@@ -2011,10 +2011,10 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
|||||||
case SANLK_DBLOCK_LVER:
|
case SANLK_DBLOCK_LVER:
|
||||||
case SANLK_DBLOCK_MBAL:
|
case SANLK_DBLOCK_MBAL:
|
||||||
/* expected errors from known/normal cases like lock contention or io timeouts */
|
/* 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;
|
return -EAGAIN;
|
||||||
default:
|
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;
|
rv = -ELMERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2032,7 +2032,7 @@ static int release_rename(struct lockspace *ls, struct resource *r)
|
|||||||
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
|
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
|
||||||
int rv;
|
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 *));
|
res_args = malloc(2 * sizeof(struct sanlk_resource *));
|
||||||
if (!res_args)
|
if (!res_args)
|
||||||
@@ -2044,14 +2044,14 @@ static int release_rename(struct lockspace *ls, struct resource *r)
|
|||||||
res1 = (struct sanlk_resource *)&rd1;
|
res1 = (struct sanlk_resource *)&rd1;
|
||||||
res2 = (struct sanlk_resource *)&rd2;
|
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[0] = res1;
|
||||||
res_args[1] = res2;
|
res_args[1] = res2;
|
||||||
|
|
||||||
rv = sanlock_release(lms->sock, -1, SANLK_REL_RENAME, 2, res_args);
|
rv = sanlock_release(lms->sock, -1, SANLK_REL_RENAME, 2, res_args);
|
||||||
if (rv < 0) {
|
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;
|
rv = -ELMERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2080,7 +2080,7 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
|||||||
struct val_blk vb;
|
struct val_blk vb;
|
||||||
int rv;
|
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);
|
ls->name, r->name, mode_str(r->mode), r_version, lmu_flags);
|
||||||
|
|
||||||
if (daemon_test) {
|
if (daemon_test) {
|
||||||
@@ -2102,12 +2102,12 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
|||||||
rds->vb->r_version = cpu_to_le32(r_version);
|
rds->vb->r_version = cpu_to_le32(r_version);
|
||||||
memcpy(&vb, rds->vb, sizeof(vb));
|
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);
|
ls->name, r->name, r_version);
|
||||||
|
|
||||||
rv = sanlock_set_lvb(0, rs, (char *)&vb, sizeof(vb));
|
rv = sanlock_set_lvb(0, rs, (char *)&vb, sizeof(vb));
|
||||||
if (rv < 0) {
|
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);
|
ls->name, r->name, rv);
|
||||||
return -ELMERR;
|
return -ELMERR;
|
||||||
}
|
}
|
||||||
@@ -2124,7 +2124,7 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
|||||||
|
|
||||||
rv = sanlock_release(lms->sock, -1, 0, 1, &rs);
|
rv = sanlock_release(lms->sock, -1, 0, 1, &rs);
|
||||||
if (rv < 0)
|
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
|
* sanlock may return an error here if it fails to release the lease on
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
|||||||
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
||||||
|
|
||||||
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
|
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
|
||||||
$(SHOW) " [CC] $@"
|
@echo " [CC] $@"
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
|
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||||
|
|
||||||
install_lvmpolld: lvmpolld
|
install_lvmpolld: lvmpolld
|
||||||
$(SHOW) " [INSTALL] $<"
|
@echo " [INSTALL] $<"
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
|
|
||||||
install_lvm2: install_lvmpolld
|
install_lvm2: install_lvmpolld
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#define MIN_ARGV_SIZE 8
|
#define MIN_ARGV_SIZE 8
|
||||||
|
|
||||||
static const char *const _polling_ops[] = {
|
static const char *const polling_ops[] = {
|
||||||
[PVMOVE] = LVMPD_REQ_PVMOVE,
|
[PVMOVE] = LVMPD_REQ_PVMOVE,
|
||||||
[CONVERT] = LVMPD_REQ_CONVERT,
|
[CONVERT] = LVMPD_REQ_CONVERT,
|
||||||
[MERGE] = LVMPD_REQ_MERGE,
|
[MERGE] = LVMPD_REQ_MERGE,
|
||||||
@@ -28,7 +28,7 @@ static const char *const _polling_ops[] = {
|
|||||||
|
|
||||||
const char *polling_op(enum poll_type type)
|
const char *polling_op(enum poll_type type)
|
||||||
{
|
{
|
||||||
return type < POLL_TYPE_MAX ? _polling_ops[type] : "<undefined>";
|
return type < POLL_TYPE_MAX ? polling_ops[type] : "<undefined>";
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
|
static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
|
||||||
@@ -81,7 +81,7 @@ const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary,
|
|||||||
|
|
||||||
/* one of: "convert", "pvmove", "merge", "merge_thin" */
|
/* one of: "convert", "pvmove", "merge", "merge_thin" */
|
||||||
if (!add_to_cmd_arr(&cmd_argv, "--polloperation", &i) ||
|
if (!add_to_cmd_arr(&cmd_argv, "--polloperation", &i) ||
|
||||||
!add_to_cmd_arr(&cmd_argv, _polling_ops[pdlv->type], &i))
|
!add_to_cmd_arr(&cmd_argv, polling_ops[pdlv->type], &i))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
/* vg/lv name */
|
/* vg/lv name */
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ static pthread_key_t key;
|
|||||||
|
|
||||||
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
|
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
|
||||||
{
|
{
|
||||||
#if defined(_GNU_SOURCE) && defined(STRERROR_R_CHAR_P)
|
#ifdef _GNU_SOURCE
|
||||||
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
|
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
|
||||||
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
|
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
|
||||||
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
|
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
|
||||||
@@ -781,7 +781,7 @@ struct log_line_baton {
|
|||||||
const char *prefix;
|
const char *prefix;
|
||||||
};
|
};
|
||||||
|
|
||||||
static daemon_handle _lvmpolld = { .error = 0 };
|
daemon_handle _lvmpolld = { .error = 0 };
|
||||||
|
|
||||||
static daemon_handle _lvmpolld_open(const char *socket)
|
static daemon_handle _lvmpolld_open(const char *socket)
|
||||||
{
|
{
|
||||||
@@ -867,14 +867,14 @@ enum action_index {
|
|||||||
ACTION_MAX /* keep at the end */
|
ACTION_MAX /* keep at the end */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const action_fn_t actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump };
|
||||||
|
|
||||||
static int _make_action(enum action_index idx, void *args)
|
static int _make_action(enum action_index idx, void *args)
|
||||||
{
|
{
|
||||||
static const action_fn_t _actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump };
|
return idx < ACTION_MAX ? actions[idx](args) : 0;
|
||||||
|
|
||||||
return idx < ACTION_MAX ? _actions[idx](args) : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _lvmpolld_client(const char *socket, enum action_index action)
|
static int _lvmpolld_client(const char *socket, unsigned action)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@@ -892,9 +892,10 @@ static int _lvmpolld_client(const char *socket, enum action_index action)
|
|||||||
return r ? EXIT_SUCCESS : EXIT_FAILURE;
|
return r ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct option _long_options[] = {
|
static int action_idx = ACTION_MAX;
|
||||||
|
static struct option long_options[] = {
|
||||||
/* Have actions always at the beginning of the array. */
|
/* Have actions always at the beginning of the array. */
|
||||||
{"dump", no_argument, 0, ACTION_DUMP }, /* or an option_index ? */
|
{"dump", no_argument, &action_idx, ACTION_DUMP }, /* or an option_index ? */
|
||||||
|
|
||||||
/* other options */
|
/* other options */
|
||||||
{"binary", required_argument, 0, 'B' },
|
{"binary", required_argument, 0, 'B' },
|
||||||
@@ -913,7 +914,7 @@ int main(int argc, char *argv[])
|
|||||||
int opt;
|
int opt;
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
int client = 0, server = 0;
|
int client = 0, server = 0;
|
||||||
enum action_index action = ACTION_MAX;
|
unsigned action = ACTION_MAX;
|
||||||
struct timespec timeout;
|
struct timespec timeout;
|
||||||
daemon_idle di = { .ptimeout = &timeout };
|
daemon_idle di = { .ptimeout = &timeout };
|
||||||
struct lvmpolld_state ls = { .log_config = "" };
|
struct lvmpolld_state ls = { .log_config = "" };
|
||||||
@@ -929,16 +930,16 @@ int main(int argc, char *argv[])
|
|||||||
.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
|
.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
|
||||||
};
|
};
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, "fhVl:p:s:B:t:", _long_options, &option_index)) != -1) {
|
while ((opt = getopt_long(argc, argv, "fhVl:p:s:B:t:", long_options, &option_index)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 0 :
|
case 0 :
|
||||||
if (action != ACTION_MAX) {
|
if (action < ACTION_MAX) {
|
||||||
fprintf(stderr, "Can't perform more actions. Action already requested: %s\n",
|
fprintf(stderr, "Can't perform more actions. Action already requested: %s\n",
|
||||||
_long_options[action].name);
|
long_options[action].name);
|
||||||
_usage(argv[0], stderr);
|
_usage(argv[0], stderr);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
action = ACTION_DUMP;
|
action = action_idx;
|
||||||
client = 1;
|
client = 1;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
|
|||||||
@@ -45,18 +45,18 @@ struct lvmpolld_lv {
|
|||||||
* accessing following vars doesn't
|
* accessing following vars doesn't
|
||||||
* require struct lvmpolld_lv lock
|
* require struct lvmpolld_lv lock
|
||||||
*/
|
*/
|
||||||
struct lvmpolld_state *ls;
|
struct lvmpolld_state *const ls;
|
||||||
enum poll_type type;
|
const enum poll_type type;
|
||||||
const char *lvid;
|
const char *const lvid;
|
||||||
const char *lvmpolld_id;
|
const char *const lvmpolld_id;
|
||||||
const char *devicesfile;
|
const char *const devicesfile;
|
||||||
const char *lvname; /* full vg/lv name */
|
const char *const lvname; /* full vg/lv name */
|
||||||
unsigned pdtimeout; /* in seconds */
|
const unsigned pdtimeout; /* in seconds */
|
||||||
const char *sinterval;
|
const char *const sinterval;
|
||||||
const char *lvm_system_dir_env;
|
const char *const lvm_system_dir_env;
|
||||||
struct lvmpolld_store *pdst;
|
struct lvmpolld_store *const pdst;
|
||||||
const char **cmdargv;
|
const char *const *cmdargv;
|
||||||
const char **cmdenvp;
|
const char *const *cmdenvp;
|
||||||
|
|
||||||
/* only used by write */
|
/* only used by write */
|
||||||
pid_t cmd_pid;
|
pid_t cmd_pid;
|
||||||
@@ -66,7 +66,7 @@ struct lvmpolld_lv {
|
|||||||
|
|
||||||
/* block of shared variables protected by lock */
|
/* block of shared variables protected by lock */
|
||||||
struct lvmpolld_cmd_stat cmd_state;
|
struct lvmpolld_cmd_stat cmd_state;
|
||||||
unsigned init_rq_count; /* for debugging purposes only */
|
unsigned init_rq_count; /* for debuging purposes only */
|
||||||
unsigned polling_finished:1; /* no more updates */
|
unsigned polling_finished:1; /* no more updates */
|
||||||
unsigned error:1; /* unrecoverable error occured in lvmpolld */
|
unsigned error:1; /* unrecoverable error occured in lvmpolld */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (C) 2018 - 2022 Red Hat, Inc. All rights reserved.
|
# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# This file is part of the device-mapper userspace tools.
|
# This file is part of the device-mapper userspace tools.
|
||||||
#
|
#
|
||||||
@@ -29,7 +29,6 @@ DEVICE_MAPPER_SOURCE=\
|
|||||||
device_mapper/regex/parse_rx.c \
|
device_mapper/regex/parse_rx.c \
|
||||||
device_mapper/regex/ttree.c \
|
device_mapper/regex/ttree.c \
|
||||||
device_mapper/vdo/status.c \
|
device_mapper/vdo/status.c \
|
||||||
device_mapper/vdo/vdo_reader.c \
|
|
||||||
device_mapper/vdo/vdo_target.c
|
device_mapper/vdo/vdo_target.c
|
||||||
|
|
||||||
DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a
|
DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a
|
||||||
@@ -44,10 +43,10 @@ CLEAN_TARGETS += $(DEVICE_MAPPER_DEPENDS) $(DEVICE_MAPPER_OBJECTS) \
|
|||||||
#$(DEVICE_MAPPER_OBJECTS): INCLUDES+=$(VDO_INCLUDES)
|
#$(DEVICE_MAPPER_OBJECTS): INCLUDES+=$(VDO_INCLUDES)
|
||||||
|
|
||||||
$(DEVICE_MAPPER_TARGET): $(DEVICE_MAPPER_OBJECTS)
|
$(DEVICE_MAPPER_TARGET): $(DEVICE_MAPPER_OBJECTS)
|
||||||
$(SHOW) " [AR] $@"
|
@echo " [AR] $@"
|
||||||
$(Q) $(RM) $@
|
$(Q) $(RM) $@
|
||||||
$(Q) $(AR) rsv $@ $(DEVICE_MAPPER_OBJECTS) > /dev/null
|
$(Q) $(AR) rsv $@ $(DEVICE_MAPPER_OBJECTS) > /dev/null
|
||||||
|
|
||||||
ifeq ("$(USE_TRACKING)","yes")
|
ifeq ("$(DEPENDS)","yes")
|
||||||
-include $(DEVICE_MAPPER_DEPENDS)
|
-include $(DEVICE_MAPPER_DEPENDS)
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -175,11 +175,12 @@ struct dm_names {
|
|||||||
|
|
||||||
struct dm_active_device {
|
struct dm_active_device {
|
||||||
struct dm_list list;
|
struct dm_list list;
|
||||||
dev_t devno;
|
int major;
|
||||||
const char *name; /* device name */
|
int minor;
|
||||||
|
char *name; /* device name */
|
||||||
|
|
||||||
uint32_t event_nr; /* valid when DM_DEVICE_LIST_HAS_EVENT_NR is set */
|
uint32_t event_nr; /* valid when DM_DEVICE_LIST_HAS_EVENT_NR is set */
|
||||||
const char *uuid; /* valid uuid when DM_DEVICE_LIST_HAS_UUID is set */
|
char *uuid; /* valid uuid when DM_DEVICE_LIST_HAS_UUID is set */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dm_versions {
|
struct dm_versions {
|
||||||
@@ -229,6 +230,13 @@ struct dm_names *dm_task_get_names(struct dm_task *dmt);
|
|||||||
#define DM_DEVICE_LIST_HAS_UUID 2
|
#define DM_DEVICE_LIST_HAS_UUID 2
|
||||||
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
|
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
|
||||||
unsigned *devs_features);
|
unsigned *devs_features);
|
||||||
|
/*
|
||||||
|
* -1: no idea about uuid (not provided by DM_DEVICE_LIST ioctl)
|
||||||
|
* 0: uuid not present
|
||||||
|
* 1: listed and dm_active_device will be set for not NULL pointer
|
||||||
|
*/
|
||||||
|
int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
|
||||||
|
const struct dm_active_device **dev);
|
||||||
/* Release all associated memory with list of active DM devices */
|
/* Release all associated memory with list of active DM devices */
|
||||||
void dm_device_list_destroy(struct dm_list **devs_list);
|
void dm_device_list_destroy(struct dm_list **devs_list);
|
||||||
|
|
||||||
@@ -974,9 +982,7 @@ struct writecache_settings {
|
|||||||
uint32_t fua;
|
uint32_t fua;
|
||||||
uint32_t nofua;
|
uint32_t nofua;
|
||||||
uint32_t cleaner;
|
uint32_t cleaner;
|
||||||
uint32_t max_age; /* in milliseconds */
|
uint32_t max_age;
|
||||||
uint32_t metadata_only;
|
|
||||||
uint32_t pause_writeback; /* in milliseconds */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allow an unrecognized key and its val to be passed to the kernel for
|
* Allow an unrecognized key and its val to be passed to the kernel for
|
||||||
@@ -998,8 +1004,6 @@ struct writecache_settings {
|
|||||||
unsigned nofua_set:1;
|
unsigned nofua_set:1;
|
||||||
unsigned cleaner_set:1;
|
unsigned cleaner_set:1;
|
||||||
unsigned max_age_set:1;
|
unsigned max_age_set:1;
|
||||||
unsigned metadata_only_set:1;
|
|
||||||
unsigned pause_writeback_set:1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
|
int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
|
||||||
@@ -1867,7 +1871,6 @@ const void *dm_report_value_cache_get(struct dm_report *rh, const char *name);
|
|||||||
#define DM_REPORT_OUTPUT_FIELD_UNQUOTED 0x00000010
|
#define DM_REPORT_OUTPUT_FIELD_UNQUOTED 0x00000010
|
||||||
#define DM_REPORT_OUTPUT_COLUMNS_AS_ROWS 0x00000020
|
#define DM_REPORT_OUTPUT_COLUMNS_AS_ROWS 0x00000020
|
||||||
#define DM_REPORT_OUTPUT_MULTIPLE_TIMES 0x00000040
|
#define DM_REPORT_OUTPUT_MULTIPLE_TIMES 0x00000040
|
||||||
#define DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS 0x00000080
|
|
||||||
|
|
||||||
struct dm_report *dm_report_init(uint32_t *report_types,
|
struct dm_report *dm_report_init(uint32_t *report_types,
|
||||||
const struct dm_report_object_type *types,
|
const struct dm_report_object_type *types,
|
||||||
@@ -2236,7 +2239,7 @@ struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
|
|||||||
int dm_cookie_supported(void);
|
int dm_cookie_supported(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Udev synchronization functions.
|
* Udev synchronisation functions.
|
||||||
*/
|
*/
|
||||||
void dm_udev_set_sync_support(int sync_with_udev);
|
void dm_udev_set_sync_support(int sync_with_udev);
|
||||||
int dm_udev_get_sync_support(void);
|
int dm_udev_get_sync_support(void);
|
||||||
|
|||||||
@@ -87,8 +87,10 @@ static int _version_checked = 0;
|
|||||||
static int _version_ok = 1;
|
static int _version_ok = 1;
|
||||||
static unsigned _ioctl_buffer_double_factor = 0;
|
static unsigned _ioctl_buffer_double_factor = 0;
|
||||||
|
|
||||||
|
const int _dm_compat = 0;
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
static const struct cmd_data _cmd_data_v4[] = {
|
static struct cmd_data _cmd_data_v4[] = {
|
||||||
{"create", DM_DEV_CREATE, {4, 0, 0}},
|
{"create", DM_DEV_CREATE, {4, 0, 0}},
|
||||||
{"reload", DM_TABLE_LOAD, {4, 0, 0}},
|
{"reload", DM_TABLE_LOAD, {4, 0, 0}},
|
||||||
{"remove", DM_DEV_REMOVE, {4, 0, 0}},
|
{"remove", DM_DEV_REMOVE, {4, 0, 0}},
|
||||||
@@ -137,6 +139,7 @@ static char *_align(char *ptr, unsigned int a)
|
|||||||
return (char *) (((unsigned long) ptr + agn) & ~agn);
|
return (char *) (((unsigned long) ptr + agn) & ~agn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DM_IOCTLS
|
||||||
static unsigned _kernel_major = 0;
|
static unsigned _kernel_major = 0;
|
||||||
static unsigned _kernel_minor = 0;
|
static unsigned _kernel_minor = 0;
|
||||||
static unsigned _kernel_release = 0;
|
static unsigned _kernel_release = 0;
|
||||||
@@ -179,9 +182,6 @@ int get_uname_version(unsigned *major, unsigned *minor, unsigned *release)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DM_IOCTLS
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set number to NULL to populate _dm_bitset - otherwise first
|
* Set number to NULL to populate _dm_bitset - otherwise first
|
||||||
* match is returned.
|
* match is returned.
|
||||||
@@ -198,7 +198,6 @@ static int _get_proc_number(const char *file, const char *name,
|
|||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
size_t len;
|
size_t len;
|
||||||
uint32_t num;
|
uint32_t num;
|
||||||
unsigned blocksection = (strcmp(file, PROC_DEVICES) == 0) ? 0 : 1;
|
|
||||||
|
|
||||||
if (!(fl = fopen(file, "r"))) {
|
if (!(fl = fopen(file, "r"))) {
|
||||||
log_sys_error("fopen", file);
|
log_sys_error("fopen", file);
|
||||||
@@ -206,9 +205,7 @@ static int _get_proc_number(const char *file, const char *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (getline(&line, &len, fl) != -1) {
|
while (getline(&line, &len, fl) != -1) {
|
||||||
if (!blocksection && (line[0] == 'B'))
|
if (sscanf(line, "%u %255s\n", &num, &nm[0]) == 2) {
|
||||||
blocksection = 1;
|
|
||||||
else if (sscanf(line, "%u %255s\n", &num, &nm[0]) == 2) {
|
|
||||||
if (!strcmp(name, nm)) {
|
if (!strcmp(name, nm)) {
|
||||||
if (number) {
|
if (number) {
|
||||||
*number = num;
|
*number = num;
|
||||||
@@ -248,16 +245,6 @@ static int _control_device_number(uint32_t *major, uint32_t *minor)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _control_unlink(const char *control)
|
|
||||||
{
|
|
||||||
if (unlink(control) && (errno != ENOENT)) {
|
|
||||||
log_sys_error("unlink", control);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 1 if it exists on returning; 0 if it doesn't; -1 if it's wrong.
|
* Returns 1 if it exists on returning; 0 if it doesn't; -1 if it's wrong.
|
||||||
*/
|
*/
|
||||||
@@ -273,7 +260,10 @@ static int _control_exists(const char *control, uint32_t major, uint32_t minor)
|
|||||||
|
|
||||||
if (!S_ISCHR(buf.st_mode)) {
|
if (!S_ISCHR(buf.st_mode)) {
|
||||||
log_verbose("%s: Wrong inode type", control);
|
log_verbose("%s: Wrong inode type", control);
|
||||||
return _control_unlink(control);
|
if (!unlink(control))
|
||||||
|
return 0;
|
||||||
|
log_sys_error("unlink", control);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (major && buf.st_rdev != MKDEV(major, minor)) {
|
if (major && buf.st_rdev != MKDEV(major, minor)) {
|
||||||
@@ -281,7 +271,10 @@ static int _control_exists(const char *control, uint32_t major, uint32_t minor)
|
|||||||
"(%u, %u)", control,
|
"(%u, %u)", control,
|
||||||
MAJOR(buf.st_mode), MINOR(buf.st_mode),
|
MAJOR(buf.st_mode), MINOR(buf.st_mode),
|
||||||
major, minor);
|
major, minor);
|
||||||
return _control_unlink(control);
|
if (!unlink(control))
|
||||||
|
return 0;
|
||||||
|
log_sys_error("unlink", control);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -317,13 +310,8 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
|
|||||||
old_umask = umask(DM_CONTROL_NODE_UMASK);
|
old_umask = umask(DM_CONTROL_NODE_UMASK);
|
||||||
if (mknod(control, S_IFCHR | S_IRUSR | S_IWUSR,
|
if (mknod(control, S_IFCHR | S_IRUSR | S_IWUSR,
|
||||||
MKDEV(major, minor)) < 0) {
|
MKDEV(major, minor)) < 0) {
|
||||||
if (errno != EEXIST) {
|
|
||||||
log_sys_error("mknod", control);
|
log_sys_error("mknod", control);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else if (_control_exists(control, major, minor) != 1) {
|
|
||||||
stack; /* Invalid control node created by parallel command ? */
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
umask(old_umask);
|
umask(old_umask);
|
||||||
(void) dm_prepare_selinux_context(NULL, 0);
|
(void) dm_prepare_selinux_context(NULL, 0);
|
||||||
@@ -409,7 +397,7 @@ static void _close_control_fd(void)
|
|||||||
{
|
{
|
||||||
if (_control_fd != -1) {
|
if (_control_fd != -1) {
|
||||||
if (close(_control_fd) < 0)
|
if (close(_control_fd) < 0)
|
||||||
log_sys_debug("close", "_control_fd");
|
log_sys_error("close", "_control_fd");
|
||||||
_control_fd = -1;
|
_control_fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -598,9 +586,23 @@ int dm_check_version(void)
|
|||||||
|
|
||||||
_version_checked = 1;
|
_version_checked = 1;
|
||||||
|
|
||||||
if (_check_version(dmversion, sizeof(dmversion), 0))
|
if (_check_version(dmversion, sizeof(dmversion), _dm_compat))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
if (!_dm_compat)
|
||||||
|
goto_bad;
|
||||||
|
|
||||||
|
log_verbose("device-mapper ioctl protocol version %u failed. "
|
||||||
|
"Trying protocol version 1.", _dm_version);
|
||||||
|
_dm_version = 1;
|
||||||
|
if (_check_version(dmversion, sizeof(dmversion), 0)) {
|
||||||
|
log_verbose("Using device-mapper ioctl protocol version 1");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
compat = "(compat)";
|
||||||
|
|
||||||
|
bad:
|
||||||
dm_get_library_version(libversion, sizeof(libversion));
|
dm_get_library_version(libversion, sizeof(libversion));
|
||||||
|
|
||||||
log_error("Incompatible libdevmapper %s%s and kernel driver %s.",
|
log_error("Incompatible libdevmapper %s%s and kernel driver %s.",
|
||||||
@@ -748,11 +750,6 @@ uint32_t dm_task_get_read_ahead(const struct dm_task *dmt, uint32_t *read_ahead)
|
|||||||
|
|
||||||
struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
|
struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
|
||||||
{
|
{
|
||||||
if (!dmt) {
|
|
||||||
log_error(INTERNAL_ERROR "Missing dm_task.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (struct dm_deps *) (((char *) dmt->dmi.v4) +
|
return (struct dm_deps *) (((char *) dmt->dmi.v4) +
|
||||||
dmt->dmi.v4->data_start);
|
dmt->dmi.v4->data_start);
|
||||||
}
|
}
|
||||||
@@ -782,12 +779,19 @@ static int _check_has_event_nr(void) {
|
|||||||
return _has_event_nr;
|
return _has_event_nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dm_device_list {
|
||||||
|
struct dm_list list;
|
||||||
|
unsigned count;
|
||||||
|
unsigned features;
|
||||||
|
struct dm_hash_table *uuids;
|
||||||
|
};
|
||||||
|
|
||||||
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
|
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
|
||||||
unsigned *devs_features)
|
unsigned *devs_features)
|
||||||
{
|
{
|
||||||
struct dm_names *names, *names1;
|
struct dm_names *names, *names1;
|
||||||
struct dm_active_device *dm_dev, *dm_new_dev;
|
struct dm_active_device *dm_dev, *dm_new_dev;
|
||||||
struct dm_list *devs;
|
struct dm_device_list *devs;
|
||||||
unsigned next = 0;
|
unsigned next = 0;
|
||||||
uint32_t *event_nr;
|
uint32_t *event_nr;
|
||||||
char *uuid_ptr;
|
char *uuid_ptr;
|
||||||
@@ -808,12 +812,12 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
|
|||||||
} while (next);
|
} while (next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* buffer for devs + sorted ptrs + dm_devs + aligned strings */
|
if (!(devs = malloc(sizeof(*devs) + (cnt ? cnt * sizeof(*dm_dev) + (char*)names1 - (char*)names + 256 : 0))))
|
||||||
if (!(devs = malloc(sizeof(*devs) + cnt * (2 * sizeof(void*) + sizeof(*dm_dev)) +
|
|
||||||
(cnt ? (char*)names1 - (char*)names + 256 : 0))))
|
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
dm_list_init(devs);
|
dm_list_init(&devs->list);
|
||||||
|
devs->count = cnt;
|
||||||
|
devs->uuids = NULL;
|
||||||
|
|
||||||
if (!cnt) {
|
if (!cnt) {
|
||||||
/* nothing in the list -> mark all features present */
|
/* nothing in the list -> mark all features present */
|
||||||
@@ -821,22 +825,27 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
|
|||||||
goto out; /* nothing else to do */
|
goto out; /* nothing else to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Shift position where to store individual dm_devs */
|
dm_dev = (struct dm_active_device *) (devs + 1);
|
||||||
dm_dev = (struct dm_active_device *) ((long*) (devs + 1) + cnt);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
names = (struct dm_names *)((char *) names + next);
|
names = (struct dm_names *)((char *) names + next);
|
||||||
|
|
||||||
dm_dev->devno = (dev_t) names->dev;
|
dm_dev->major = MAJOR(names->dev);
|
||||||
dm_dev->name = (const char *)(dm_dev + 1);
|
dm_dev->minor = MINOR(names->dev);
|
||||||
|
dm_dev->name = (char*)(dm_dev + 1);
|
||||||
dm_dev->event_nr = 0;
|
dm_dev->event_nr = 0;
|
||||||
dm_dev->uuid = "";
|
dm_dev->uuid = NULL;
|
||||||
|
|
||||||
|
strcpy(dm_dev->name, names->name);
|
||||||
len = strlen(names->name) + 1;
|
len = strlen(names->name) + 1;
|
||||||
memcpy((char*)dm_dev->name, names->name, len);
|
|
||||||
|
|
||||||
dm_new_dev = _align_ptr((char*)(dm_dev + 1) + len);
|
dm_new_dev = _align_ptr((char*)(dm_dev + 1) + len);
|
||||||
if (_check_has_event_nr()) {
|
if (_check_has_event_nr()) {
|
||||||
|
/* Hash for UUIDs with some more bits to reduce colision count */
|
||||||
|
if (!devs->uuids && !(devs->uuids = dm_hash_create(cnt * 8))) {
|
||||||
|
free(devs);
|
||||||
|
return_0;
|
||||||
|
}
|
||||||
|
|
||||||
*devs_features |= DM_DEVICE_LIST_HAS_EVENT_NR;
|
*devs_features |= DM_DEVICE_LIST_HAS_EVENT_NR;
|
||||||
event_nr = _align_ptr(names->name + len);
|
event_nr = _align_ptr(names->name + len);
|
||||||
@@ -845,29 +854,54 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
|
|||||||
if ((event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
|
if ((event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
|
||||||
*devs_features |= DM_DEVICE_LIST_HAS_UUID;
|
*devs_features |= DM_DEVICE_LIST_HAS_UUID;
|
||||||
uuid_ptr = _align_ptr(event_nr + 2);
|
uuid_ptr = _align_ptr(event_nr + 2);
|
||||||
len = strlen(uuid_ptr) + 1;
|
dm_dev->uuid = (char*) dm_new_dev;
|
||||||
memcpy(dm_new_dev, uuid_ptr, len);
|
dm_new_dev = _align_ptr((char*)dm_new_dev + strlen(uuid_ptr) + 1);
|
||||||
dm_dev->uuid = (const char *) dm_new_dev;
|
strcpy(dm_dev->uuid, uuid_ptr);
|
||||||
dm_new_dev = _align_ptr((char*)dm_new_dev + len);
|
if (!dm_hash_insert(devs->uuids, dm_dev->uuid, dm_dev))
|
||||||
|
return_0; // FIXME
|
||||||
|
#if 0
|
||||||
|
log_debug("Active %s (%s) %d:%d event:%u",
|
||||||
|
dm_dev->name, dm_dev->uuid,
|
||||||
|
dm_dev->major, dm_dev->minor, dm_dev->event_nr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dm_list_add(devs, &dm_dev->list);
|
dm_list_add(&devs->list, &dm_dev->list);
|
||||||
dm_dev = dm_new_dev;
|
dm_dev = dm_new_dev;
|
||||||
next = names->next;
|
next = names->next;
|
||||||
} while (next);
|
} while (next);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
*devs_list = devs;
|
*devs_list = (struct dm_list *)devs;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
|
||||||
|
const struct dm_active_device **dev)
|
||||||
|
{
|
||||||
|
struct dm_device_list *devs = (struct dm_device_list *) devs_list;
|
||||||
|
struct dm_active_device *dm_dev;
|
||||||
|
|
||||||
|
if (devs->uuids &&
|
||||||
|
(dm_dev = dm_hash_lookup(devs->uuids, uuid))) {
|
||||||
|
if (dev)
|
||||||
|
*dev = dm_dev;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void dm_device_list_destroy(struct dm_list **devs_list)
|
void dm_device_list_destroy(struct dm_list **devs_list)
|
||||||
{
|
{
|
||||||
struct dm_device_list *devs = (struct dm_device_list *) *devs_list;
|
struct dm_device_list *devs = (struct dm_device_list *) *devs_list;
|
||||||
|
|
||||||
if (devs) {
|
if (devs) {
|
||||||
|
if (devs->uuids)
|
||||||
|
dm_hash_destroy(devs->uuids);
|
||||||
|
|
||||||
free(devs);
|
free(devs);
|
||||||
*devs_list = NULL;
|
*devs_list = NULL;
|
||||||
}
|
}
|
||||||
@@ -1160,10 +1194,9 @@ static char *_add_target(struct target *t, char *out, char *end)
|
|||||||
while (*pt)
|
while (*pt)
|
||||||
if (*pt++ == '\\')
|
if (*pt++ == '\\')
|
||||||
backslash_count++;
|
backslash_count++;
|
||||||
|
len = strlen(t->params) + backslash_count;
|
||||||
|
|
||||||
len = strlen(t->params) + 1;
|
if ((out >= end) || (out + len + 1) >= end) {
|
||||||
|
|
||||||
if ((out >= end) || (out + len + backslash_count) >= end) {
|
|
||||||
log_error("Ran out of memory building ioctl parameter");
|
log_error("Ran out of memory building ioctl parameter");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1179,8 +1212,8 @@ static char *_add_target(struct target *t, char *out, char *end)
|
|||||||
*out++ = '\0';
|
*out++ = '\0';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memcpy(out, t->params, len);
|
strcpy(out, t->params);
|
||||||
out += len + backslash_count;
|
out += len + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* align next block */
|
/* align next block */
|
||||||
@@ -1214,7 +1247,7 @@ static int _lookup_dev_name(uint64_t dev, char *buf, size_t len)
|
|||||||
do {
|
do {
|
||||||
names = (struct dm_names *)((char *) names + next);
|
names = (struct dm_names *)((char *) names + next);
|
||||||
if (names->dev == dev) {
|
if (names->dev == dev) {
|
||||||
memccpy(buf, names->name, 0, len);
|
strncpy(buf, names->name, len);
|
||||||
r = 1;
|
r = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1251,7 +1284,6 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
|||||||
struct target *t;
|
struct target *t;
|
||||||
struct dm_target_msg *tmsg;
|
struct dm_target_msg *tmsg;
|
||||||
size_t len = sizeof(struct dm_ioctl);
|
size_t len = sizeof(struct dm_ioctl);
|
||||||
size_t message_len = 0, newname_len = 0, geometry_len = 0;
|
|
||||||
char *b, *e;
|
char *b, *e;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
@@ -1312,20 +1344,14 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dmt->newname) {
|
if (dmt->newname)
|
||||||
newname_len = strlen(dmt->newname) + 1;
|
len += strlen(dmt->newname) + 1;
|
||||||
len += newname_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dmt->message) {
|
if (dmt->message)
|
||||||
message_len = strlen(dmt->message) + 1;
|
len += sizeof(struct dm_target_msg) + strlen(dmt->message) + 1;
|
||||||
len += sizeof(struct dm_target_msg) + message_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dmt->geometry) {
|
if (dmt->geometry)
|
||||||
geometry_len = strlen(dmt->geometry) + 1;
|
len += strlen(dmt->geometry) + 1;
|
||||||
len += geometry_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Give len a minimum size so that we have space to store
|
* Give len a minimum size so that we have space to store
|
||||||
@@ -1383,10 +1409,12 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
|||||||
/* FIXME Until resume ioctl supplies name, use dev_name for readahead */
|
/* FIXME Until resume ioctl supplies name, use dev_name for readahead */
|
||||||
if (DEV_NAME(dmt) && (dmt->type != DM_DEVICE_RESUME || dmt->minor < 0 ||
|
if (DEV_NAME(dmt) && (dmt->type != DM_DEVICE_RESUME || dmt->minor < 0 ||
|
||||||
dmt->major < 0))
|
dmt->major < 0))
|
||||||
memccpy(dmi->name, DEV_NAME(dmt), 0, sizeof(dmi->name));
|
/* coverity[buffer_size_warning] */
|
||||||
|
strncpy(dmi->name, DEV_NAME(dmt), sizeof(dmi->name));
|
||||||
|
|
||||||
if (DEV_UUID(dmt))
|
if (DEV_UUID(dmt))
|
||||||
memccpy(dmi->uuid, DEV_UUID(dmt), 0, sizeof(dmi->uuid));
|
/* coverity[buffer_size_warning] */
|
||||||
|
strncpy(dmi->uuid, DEV_UUID(dmt), sizeof(dmi->uuid));
|
||||||
|
|
||||||
if (dmt->type == DM_DEVICE_SUSPEND)
|
if (dmt->type == DM_DEVICE_SUSPEND)
|
||||||
dmi->flags |= DM_SUSPEND_FLAG;
|
dmi->flags |= DM_SUSPEND_FLAG;
|
||||||
@@ -1445,16 +1473,16 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
|||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
if (dmt->newname)
|
if (dmt->newname)
|
||||||
memcpy(b, dmt->newname, newname_len);
|
strcpy(b, dmt->newname);
|
||||||
|
|
||||||
if (dmt->message) {
|
if (dmt->message) {
|
||||||
tmsg = (struct dm_target_msg *) b;
|
tmsg = (struct dm_target_msg *) b;
|
||||||
tmsg->sector = dmt->sector;
|
tmsg->sector = dmt->sector;
|
||||||
memcpy(tmsg->message, dmt->message, message_len);
|
strcpy(tmsg->message, dmt->message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dmt->geometry)
|
if (dmt->geometry)
|
||||||
memcpy(b, dmt->geometry, geometry_len);
|
strcpy(b, dmt->geometry);
|
||||||
|
|
||||||
return dmi;
|
return dmi;
|
||||||
|
|
||||||
@@ -1576,7 +1604,7 @@ static int _check_uevent_generated(struct dm_ioctl *dmi)
|
|||||||
static int _create_and_load_v4(struct dm_task *dmt)
|
static int _create_and_load_v4(struct dm_task *dmt)
|
||||||
{
|
{
|
||||||
struct dm_task *task;
|
struct dm_task *task;
|
||||||
int r, ioctl_errno = 0;
|
int r;
|
||||||
uint32_t cookie;
|
uint32_t cookie;
|
||||||
|
|
||||||
/* Use new task struct to create the device */
|
/* Use new task struct to create the device */
|
||||||
@@ -1602,10 +1630,8 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
|||||||
task->cookie_set = dmt->cookie_set;
|
task->cookie_set = dmt->cookie_set;
|
||||||
task->add_node = dmt->add_node;
|
task->add_node = dmt->add_node;
|
||||||
|
|
||||||
if (!dm_task_run(task)) {
|
if (!dm_task_run(task))
|
||||||
ioctl_errno = task->ioctl_errno;
|
|
||||||
goto_bad;
|
goto_bad;
|
||||||
}
|
|
||||||
|
|
||||||
dm_task_destroy(task);
|
dm_task_destroy(task);
|
||||||
|
|
||||||
@@ -1631,8 +1657,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
|||||||
task->ima_measurement = dmt->ima_measurement;
|
task->ima_measurement = dmt->ima_measurement;
|
||||||
|
|
||||||
r = dm_task_run(task);
|
r = dm_task_run(task);
|
||||||
if (!r)
|
|
||||||
ioctl_errno = task->ioctl_errno;
|
|
||||||
|
|
||||||
task->head = NULL;
|
task->head = NULL;
|
||||||
task->tail = NULL;
|
task->tail = NULL;
|
||||||
@@ -1650,7 +1674,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
|||||||
dmt->uuid = NULL;
|
dmt->uuid = NULL;
|
||||||
free(dmt->mangled_uuid);
|
free(dmt->mangled_uuid);
|
||||||
dmt->mangled_uuid = NULL;
|
dmt->mangled_uuid = NULL;
|
||||||
/* coverity[double_free] recursive function call */
|
|
||||||
_dm_task_free_targets(dmt);
|
_dm_task_free_targets(dmt);
|
||||||
|
|
||||||
if (dm_task_run(dmt))
|
if (dm_task_run(dmt))
|
||||||
@@ -1662,7 +1685,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
|||||||
dmt->uuid = NULL;
|
dmt->uuid = NULL;
|
||||||
free(dmt->mangled_uuid);
|
free(dmt->mangled_uuid);
|
||||||
dmt->mangled_uuid = NULL;
|
dmt->mangled_uuid = NULL;
|
||||||
/* coverity[double_free] recursive function call */
|
|
||||||
_dm_task_free_targets(dmt);
|
_dm_task_free_targets(dmt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1681,18 +1703,12 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
|||||||
if (!dm_task_run(dmt))
|
if (!dm_task_run(dmt))
|
||||||
log_error("Failed to revert device creation.");
|
log_error("Failed to revert device creation.");
|
||||||
|
|
||||||
if (ioctl_errno != 0)
|
|
||||||
dmt->ioctl_errno = ioctl_errno;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
dm_task_destroy(task);
|
dm_task_destroy(task);
|
||||||
_udev_complete(dmt);
|
_udev_complete(dmt);
|
||||||
|
|
||||||
if (ioctl_errno != 0)
|
|
||||||
dmt->ioctl_errno = ioctl_errno;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2034,7 +2050,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
|||||||
/*
|
/*
|
||||||
* Prevent udev vs. libdevmapper race when processing nodes
|
* Prevent udev vs. libdevmapper race when processing nodes
|
||||||
* and symlinks. This can happen when the udev rules are
|
* and symlinks. This can happen when the udev rules are
|
||||||
* installed and udev synchronization code is enabled in
|
* installed and udev synchronisation code is enabled in
|
||||||
* libdevmapper but the software using libdevmapper does not
|
* libdevmapper but the software using libdevmapper does not
|
||||||
* make use of it (by not calling dm_task_set_cookie before).
|
* make use of it (by not calling dm_task_set_cookie before).
|
||||||
* We need to instruct the udev rules not to be applied at
|
* We need to instruct the udev rules not to be applied at
|
||||||
@@ -2044,7 +2060,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
|||||||
if (!dmt->cookie_set && dm_udev_get_sync_support()) {
|
if (!dmt->cookie_set && dm_udev_get_sync_support()) {
|
||||||
log_debug_activation("Cookie value is not set while trying to call %s "
|
log_debug_activation("Cookie value is not set while trying to call %s "
|
||||||
"ioctl. Please, consider using libdevmapper's udev "
|
"ioctl. Please, consider using libdevmapper's udev "
|
||||||
"synchronization interface or disable it explicitly "
|
"synchronisation interface or disable it explicitly "
|
||||||
"by calling dm_udev_set_sync_support(0).",
|
"by calling dm_udev_set_sync_support(0).",
|
||||||
dmt->type == DM_DEVICE_RESUME ? "DM_DEVICE_RESUME" :
|
dmt->type == DM_DEVICE_RESUME ? "DM_DEVICE_RESUME" :
|
||||||
dmt->type == DM_DEVICE_REMOVE ? "DM_DEVICE_REMOVE" :
|
dmt->type == DM_DEVICE_REMOVE ? "DM_DEVICE_REMOVE" :
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ struct dm_task {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct cmd_data {
|
struct cmd_data {
|
||||||
const char name[16];
|
const char *name;
|
||||||
const unsigned cmd;
|
const unsigned cmd;
|
||||||
const int version[3];
|
const int version[3];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -537,8 +537,7 @@ int unmangle_string(const char *str, const char *str_name, size_t len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (str[i] == '\\' && str[i+1] == 'x') {
|
if (str[i] == '\\' && str[i+1] == 'x') {
|
||||||
if (!sscanf(&str[i+2], "%2x%" DM_TO_STRING(DM_NAME_LEN) "s",
|
if (!sscanf(&str[i+2], "%2x%s", &code, str_rest)) {
|
||||||
&code, str_rest)) {
|
|
||||||
log_debug_activation("Hex encoding mismatch detected in %s \"%s\" "
|
log_debug_activation("Hex encoding mismatch detected in %s \"%s\" "
|
||||||
"while trying to unmangle it.", str_name, str);
|
"while trying to unmangle it.", str_name, str);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1061,8 +1060,9 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
|
|||||||
if (info.st_rdev == dev)
|
if (info.st_rdev == dev)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (unlink(path) && (errno != ENOENT)) {
|
if (unlink(path) < 0) {
|
||||||
log_sys_error("unlink", path);
|
log_error("Unable to unlink device node for '%s'",
|
||||||
|
dev_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (_warn_if_op_needed(warn_if_udev_failed))
|
} else if (_warn_if_op_needed(warn_if_udev_failed))
|
||||||
@@ -1106,8 +1106,8 @@ static int _rm_dev_node(const char *dev_name, int warn_if_udev_failed)
|
|||||||
"Falling back to direct node removal.", path);
|
"Falling back to direct node removal.", path);
|
||||||
|
|
||||||
/* udev may already have deleted the node. Ignore ENOENT. */
|
/* udev may already have deleted the node. Ignore ENOENT. */
|
||||||
if (unlink(path) && (errno != ENOENT)) {
|
if (unlink(path) < 0 && errno != ENOENT) {
|
||||||
log_sys_error("unlink", path);
|
log_error("Unable to unlink device node for '%s'", dev_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1451,10 +1451,9 @@ struct node_op_parms {
|
|||||||
|
|
||||||
static void _store_str(char **pos, char **ptr, const char *str)
|
static void _store_str(char **pos, char **ptr, const char *str)
|
||||||
{
|
{
|
||||||
size_t len = strlen(str) + 1;
|
strcpy(*pos, str);
|
||||||
memcpy(*pos, str, len);
|
|
||||||
*ptr = *pos;
|
*ptr = *pos;
|
||||||
*pos += len;
|
*pos += strlen(*ptr) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _del_node_op(struct node_op_parms *nop)
|
static void _del_node_op(struct node_op_parms *nop)
|
||||||
@@ -1704,17 +1703,15 @@ const char *dm_sysfs_dir(void)
|
|||||||
*/
|
*/
|
||||||
int dm_set_uuid_prefix(const char *uuid_prefix)
|
int dm_set_uuid_prefix(const char *uuid_prefix)
|
||||||
{
|
{
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (!uuid_prefix)
|
if (!uuid_prefix)
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
if ((len = strlen(uuid_prefix)) > DM_MAX_UUID_PREFIX_LEN) {
|
if (strlen(uuid_prefix) > DM_MAX_UUID_PREFIX_LEN) {
|
||||||
log_error("New uuid prefix %s too long.", uuid_prefix);
|
log_error("New uuid prefix %s too long.", uuid_prefix);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(_default_uuid_prefix, uuid_prefix, len + 1);
|
strcpy(_default_uuid_prefix, uuid_prefix);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1743,9 +1740,6 @@ static void _unmangle_mountinfo_string(const char *src, char *buf)
|
|||||||
*buf = '\0';
|
*buf = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* coverity[+tainted_string_sanitize_content:arg-0] */
|
|
||||||
static int _sanitize_line(const char *line) { return 1; }
|
|
||||||
|
|
||||||
/* Parse one line of mountinfo and unmangled target line */
|
/* Parse one line of mountinfo and unmangled target line */
|
||||||
static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min, char *buf)
|
static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min, char *buf)
|
||||||
{
|
{
|
||||||
@@ -1816,8 +1810,7 @@ int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (!feof(minfo) && fgets(buffer, sizeof(buffer), minfo))
|
while (!feof(minfo) && fgets(buffer, sizeof(buffer), minfo))
|
||||||
if (!_sanitize_line(buffer) ||
|
if (!_mountinfo_parse_line(buffer, &maj, &min, target) ||
|
||||||
!_mountinfo_parse_line(buffer, &maj, &min, target) ||
|
|
||||||
!read_fn(buffer, maj, min, target, cb_data)) {
|
!read_fn(buffer, maj, min, target, cb_data)) {
|
||||||
stack;
|
stack;
|
||||||
r = 0;
|
r = 0;
|
||||||
@@ -2318,7 +2311,7 @@ static int _check_semaphore_is_supported(void)
|
|||||||
|
|
||||||
if (maxid < 0) {
|
if (maxid < 0) {
|
||||||
log_warn("Kernel not configured for semaphores (System V IPC). "
|
log_warn("Kernel not configured for semaphores (System V IPC). "
|
||||||
"Not using udev synchronization code.");
|
"Not using udev synchronisation code.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2341,7 +2334,7 @@ static int _check_udev_is_running(void)
|
|||||||
|
|
||||||
if (!(r = udev_queue_get_udev_is_active(udev_queue)))
|
if (!(r = udev_queue_get_udev_is_active(udev_queue)))
|
||||||
log_debug_activation("Udev is not running. "
|
log_debug_activation("Udev is not running. "
|
||||||
"Not using udev synchronization code.");
|
"Not using udev synchronisation code.");
|
||||||
|
|
||||||
udev_queue_unref(udev_queue);
|
udev_queue_unref(udev_queue);
|
||||||
udev_unref(udev);
|
udev_unref(udev);
|
||||||
|
|||||||
@@ -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_tok(struct parser *p);
|
||||||
static char *_dup_token(struct dm_pool *mem, const char *b, const char *e);
|
static char *_dup_token(struct dm_pool *mem, const char *b, const char *e);
|
||||||
|
|
||||||
|
static const int _sep = '/';
|
||||||
|
|
||||||
#define MAX_INDENT 32
|
#define MAX_INDENT 32
|
||||||
|
|
||||||
#define match(t) do {\
|
#define match(t) do {\
|
||||||
@@ -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; */
|
/* TODO? if (start == end) return 1; */
|
||||||
|
|
||||||
struct parser p = {
|
struct parser *p;
|
||||||
.mem = cft->mem,
|
if (!(p = dm_pool_zalloc(cft->mem, sizeof(*p))))
|
||||||
.tb = start,
|
return_0;
|
||||||
.te = start,
|
|
||||||
.fb = start,
|
|
||||||
.fe = end,
|
|
||||||
.line = 1,
|
|
||||||
.no_dup_node_check = no_dup_node_check
|
|
||||||
};
|
|
||||||
|
|
||||||
_get_token(&p, TOK_SECTION_E);
|
p->mem = cft->mem;
|
||||||
if (!(cft->root = _file(&p)))
|
p->fb = start;
|
||||||
|
p->fe = end;
|
||||||
|
p->tb = p->te = p->fb;
|
||||||
|
p->line = 1;
|
||||||
|
p->no_dup_node_check = no_dup_node_check;
|
||||||
|
|
||||||
|
_get_token(p, TOK_SECTION_E);
|
||||||
|
if (!(cft->root = _file(p)))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
cft->root = _config_reverse(cft->root);
|
cft->root = _config_reverse(cft->root);
|
||||||
@@ -523,18 +526,17 @@ static struct dm_config_node *_find_or_make_node(struct dm_pool *mem,
|
|||||||
const char *path,
|
const char *path,
|
||||||
int no_dup_node_check)
|
int no_dup_node_check)
|
||||||
{
|
{
|
||||||
const int sep = '/';
|
|
||||||
const char *e;
|
const char *e;
|
||||||
struct dm_config_node *cn = parent ? parent->child : NULL;
|
struct dm_config_node *cn = parent ? parent->child : NULL;
|
||||||
struct dm_config_node *cn_found = NULL;
|
struct dm_config_node *cn_found = NULL;
|
||||||
|
|
||||||
while (cn || mem) {
|
while (cn || mem) {
|
||||||
/* trim any leading slashes */
|
/* trim any leading slashes */
|
||||||
while (*path && (*path == sep))
|
while (*path && (*path == _sep))
|
||||||
path++;
|
path++;
|
||||||
|
|
||||||
/* find the end of this segment */
|
/* find the end of this segment */
|
||||||
for (e = path; *e && (*e != sep); e++) ;
|
for (e = path; *e && (*e != _sep); e++) ;
|
||||||
|
|
||||||
/* hunt for the node */
|
/* hunt for the node */
|
||||||
cn_found = NULL;
|
cn_found = NULL;
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ struct load_segment {
|
|||||||
uint32_t region_size; /* Mirror + raid */
|
uint32_t region_size; /* Mirror + raid */
|
||||||
unsigned clustered; /* Mirror */
|
unsigned clustered; /* Mirror */
|
||||||
unsigned mirror_area_count; /* Mirror */
|
unsigned mirror_area_count; /* Mirror */
|
||||||
uint64_t flags; /* Mirror + Raid + Cache */
|
uint32_t flags; /* Mirror + raid + Cache */
|
||||||
char *uuid; /* Clustered mirror log */
|
char *uuid; /* Clustered mirror log */
|
||||||
|
|
||||||
const char *policy_name; /* Cache */
|
const char *policy_name; /* Cache */
|
||||||
@@ -294,10 +294,6 @@ struct load_properties {
|
|||||||
unsigned send_messages;
|
unsigned send_messages;
|
||||||
/* Skip suspending node's children, used when sending messages to thin-pool */
|
/* Skip suspending node's children, used when sending messages to thin-pool */
|
||||||
int skip_suspend;
|
int skip_suspend;
|
||||||
|
|
||||||
/* Suspend and Resume siblings after node activation with udev flags*/
|
|
||||||
unsigned reactivate_siblings;
|
|
||||||
uint16_t reactivate_udev_flags;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Two of these used to join two nodes with uses and used_by. */
|
/* Two of these used to join two nodes with uses and used_by. */
|
||||||
@@ -348,7 +344,7 @@ struct dm_tree {
|
|||||||
int retry_remove; /* 1 retries remove if not successful */
|
int retry_remove; /* 1 retries remove if not successful */
|
||||||
uint32_t cookie;
|
uint32_t cookie;
|
||||||
char buf[DM_NAME_LEN + 32]; /* print buffer for device_name (major:minor) */
|
char buf[DM_NAME_LEN + 32]; /* print buffer for device_name (major:minor) */
|
||||||
const char * const *optional_uuid_suffixes; /* uuid suffixes ignored when matching */
|
const char **optional_uuid_suffixes; /* uuid suffixes ignored when matching */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -590,7 +586,6 @@ void dm_tree_set_optional_uuid_suffixes(struct dm_tree *dtree, const char **opti
|
|||||||
dtree->optional_uuid_suffixes = optional_uuid_suffixes;
|
dtree->optional_uuid_suffixes = optional_uuid_suffixes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *_node_name(struct dm_tree_node *dnode);
|
|
||||||
static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
|
static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
|
||||||
const char *uuid)
|
const char *uuid)
|
||||||
{
|
{
|
||||||
@@ -598,26 +593,28 @@ static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
|
|||||||
const char *default_uuid_prefix;
|
const char *default_uuid_prefix;
|
||||||
size_t default_uuid_prefix_len;
|
size_t default_uuid_prefix_len;
|
||||||
const char *suffix, *suffix_position;
|
const char *suffix, *suffix_position;
|
||||||
char uuid_without_suffix[DM_UUID_LEN + 1];
|
char uuid_without_suffix[DM_UUID_LEN];
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
const char * const *suffix_list = dtree->optional_uuid_suffixes;
|
const char **suffix_list = dtree->optional_uuid_suffixes;
|
||||||
|
|
||||||
if ((node = dm_hash_lookup(dtree->uuids, uuid))) {
|
if ((node = dm_hash_lookup(dtree->uuids, uuid))) {
|
||||||
log_debug_activation("Matched uuid %s %s in deptree.", uuid, _node_name(node));
|
log_debug("Matched uuid %s in deptree.", uuid);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default_uuid_prefix = dm_uuid_prefix();
|
||||||
|
default_uuid_prefix_len = strlen(default_uuid_prefix);
|
||||||
|
|
||||||
if (suffix_list && (suffix_position = strrchr(uuid, '-'))) {
|
if (suffix_list && (suffix_position = strrchr(uuid, '-'))) {
|
||||||
while ((suffix = suffix_list[i++])) {
|
while ((suffix = suffix_list[i++])) {
|
||||||
if (strcmp(suffix_position + 1, suffix))
|
if (strcmp(suffix_position + 1, suffix))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dm_strncpy(uuid_without_suffix, uuid, sizeof(uuid_without_suffix));
|
(void) strncpy(uuid_without_suffix, uuid, sizeof(uuid_without_suffix));
|
||||||
uuid_without_suffix[suffix_position - uuid] = '\0';
|
uuid_without_suffix[suffix_position - uuid] = '\0';
|
||||||
|
|
||||||
if ((node = dm_hash_lookup(dtree->uuids, uuid_without_suffix))) {
|
if ((node = dm_hash_lookup(dtree->uuids, uuid_without_suffix))) {
|
||||||
log_debug_activation("Matched uuid %s %s (missing suffix -%s) in deptree.",
|
log_debug("Matched uuid %s (missing suffix -%s) in deptree.", uuid_without_suffix, suffix);
|
||||||
uuid_without_suffix, _node_name(node), suffix);
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,17 +622,15 @@ static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
default_uuid_prefix = dm_uuid_prefix();
|
if (strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len))
|
||||||
default_uuid_prefix_len = strlen(default_uuid_prefix);
|
return NULL;
|
||||||
|
|
||||||
if ((strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len) == 0) &&
|
if ((node = dm_hash_lookup(dtree->uuids, uuid + default_uuid_prefix_len))) {
|
||||||
(node = dm_hash_lookup(dtree->uuids, uuid + default_uuid_prefix_len))) {
|
log_debug("Matched uuid %s (missing prefix) in deptree.", uuid + default_uuid_prefix_len);
|
||||||
log_debug_activation("Matched uuid %s %s (missing prefix) in deptree.",
|
|
||||||
uuid + default_uuid_prefix_len, _node_name(node));
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug_activation("Not matched uuid %s in deptree.", uuid);
|
log_debug("Not matched uuid %s in deptree.", uuid);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2035,68 +2030,6 @@ static int _rename_conflict_exists(struct dm_tree_node *parent,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Reactivation of sibling nodes
|
|
||||||
*
|
|
||||||
* Function is used when activating origin and its thick snapshots
|
|
||||||
* to ensure udev is processing first the origin LV and all the
|
|
||||||
* snapshot LVs are processed afterwards.
|
|
||||||
*/
|
|
||||||
static int _reactivate_siblings(struct dm_tree_node *dnode,
|
|
||||||
const char *uuid_prefix,
|
|
||||||
size_t uuid_prefix_len)
|
|
||||||
{
|
|
||||||
struct dm_tree_node *child;
|
|
||||||
const char *uuid;
|
|
||||||
void *handle = NULL;
|
|
||||||
int r = 1;
|
|
||||||
|
|
||||||
/* Wait for udev before reactivating siblings */
|
|
||||||
if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
|
|
||||||
stack;
|
|
||||||
|
|
||||||
dm_tree_set_cookie(dnode, 0);
|
|
||||||
|
|
||||||
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
|
|
||||||
if (child->props.reactivate_siblings) {
|
|
||||||
/* Skip 'leading' device in this group, marked with flag */
|
|
||||||
child->props.reactivate_siblings = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(uuid = dm_tree_node_get_uuid(child))) {
|
|
||||||
stack;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!_suspend_node(child->name, child->info.major, child->info.minor,
|
|
||||||
child->dtree->skip_lockfs,
|
|
||||||
child->dtree->no_flush, &child->info)) {
|
|
||||||
log_error("Unable to suspend %s (" FMTu32
|
|
||||||
":" FMTu32 ")", child->name,
|
|
||||||
child->info.major, child->info.minor);
|
|
||||||
r = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!_resume_node(child->name, child->info.major, child->info.minor,
|
|
||||||
child->props.read_ahead, child->props.read_ahead_flags,
|
|
||||||
&child->info, &child->dtree->cookie,
|
|
||||||
child->props.reactivate_udev_flags, // use these flags
|
|
||||||
child->info.suspended)) {
|
|
||||||
log_error("Failed to suspend %s (" FMTu32
|
|
||||||
":" FMTu32 ")", child->name,
|
|
||||||
child->info.major, child->info.minor);
|
|
||||||
r = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dm_tree_activate_children(struct dm_tree_node *dnode,
|
int dm_tree_activate_children(struct dm_tree_node *dnode,
|
||||||
const char *uuid_prefix,
|
const char *uuid_prefix,
|
||||||
size_t uuid_prefix_len)
|
size_t uuid_prefix_len)
|
||||||
@@ -2107,7 +2040,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
|
|||||||
struct dm_tree_node *child = dnode;
|
struct dm_tree_node *child = dnode;
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *uuid;
|
const char *uuid;
|
||||||
int priority, next_priority;
|
int priority;
|
||||||
|
|
||||||
/* Activate children first */
|
/* Activate children first */
|
||||||
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
|
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
|
||||||
@@ -2125,16 +2058,12 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
handle = NULL;
|
handle = NULL;
|
||||||
|
|
||||||
for (priority = 0; priority < 3; priority++) {
|
for (priority = 0; priority < 3; priority++) {
|
||||||
awaiting_peer_rename = 0;
|
awaiting_peer_rename = 0;
|
||||||
next_priority = 0;
|
|
||||||
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
|
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
|
||||||
if (priority != child->activation_priority) {
|
if (priority != child->activation_priority)
|
||||||
if ((next_priority < child->activation_priority) &&
|
|
||||||
(child->activation_priority > priority))
|
|
||||||
next_priority = child->activation_priority;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (!(uuid = dm_tree_node_get_uuid(child))) {
|
if (!(uuid = dm_tree_node_get_uuid(child))) {
|
||||||
stack;
|
stack;
|
||||||
@@ -2189,16 +2118,9 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
|
|||||||
if (r && (child->props.send_messages > 1) &&
|
if (r && (child->props.send_messages > 1) &&
|
||||||
!(r = _node_send_messages(child, uuid_prefix, uuid_prefix_len, 1)))
|
!(r = _node_send_messages(child, uuid_prefix, uuid_prefix_len, 1)))
|
||||||
stack;
|
stack;
|
||||||
|
|
||||||
/* Reactivate only for fresh activated origin */
|
|
||||||
if (r && child->props.reactivate_siblings &&
|
|
||||||
(!(r = _reactivate_siblings(dnode, uuid_prefix, uuid_prefix_len))))
|
|
||||||
stack;
|
|
||||||
}
|
}
|
||||||
if (awaiting_peer_rename)
|
if (awaiting_peer_rename)
|
||||||
priority--; /* redo priority level */
|
priority--; /* redo priority level */
|
||||||
else if (!next_priority)
|
|
||||||
break; /* no more work, higher priority was not found in the chain */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
@@ -2757,10 +2679,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
|
|||||||
count += 1;
|
count += 1;
|
||||||
if (seg->writecache_settings.max_age_set)
|
if (seg->writecache_settings.max_age_set)
|
||||||
count += 2;
|
count += 2;
|
||||||
if (seg->writecache_settings.metadata_only_set)
|
|
||||||
count += 1;
|
|
||||||
if (seg->writecache_settings.pause_writeback_set)
|
|
||||||
count += 2;
|
|
||||||
if (seg->writecache_settings.new_key)
|
if (seg->writecache_settings.new_key)
|
||||||
count += 2;
|
count += 2;
|
||||||
|
|
||||||
@@ -2812,14 +2730,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
|
|||||||
EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age);
|
EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seg->writecache_settings.metadata_only_set) {
|
|
||||||
EMIT_PARAMS(pos, " metadata_only");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seg->writecache_settings.pause_writeback_set) {
|
|
||||||
EMIT_PARAMS(pos, " pause_writeback %u", seg->writecache_settings.pause_writeback);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seg->writecache_settings.new_key) {
|
if (seg->writecache_settings.new_key) {
|
||||||
EMIT_PARAMS(pos, " %s %s",
|
EMIT_PARAMS(pos, " %s %s",
|
||||||
seg->writecache_settings.new_key,
|
seg->writecache_settings.new_key,
|
||||||
@@ -2940,18 +2850,13 @@ static int _thin_pool_emit_segment_line(struct dm_task *dmt,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t minor,
|
static int _vdo_emit_segment_line(struct dm_task *dmt,
|
||||||
struct load_segment *seg,
|
struct load_segment *seg,
|
||||||
char *params, size_t paramsize)
|
char *params, size_t paramsize)
|
||||||
{
|
{
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
char data[DM_FORMAT_DEV_BUFSIZE];
|
char data[DM_FORMAT_DEV_BUFSIZE];
|
||||||
char data_dev[128]; // for /dev/dm-XXXX
|
char data_dev[128]; // for /dev/dm-XXXX
|
||||||
uint64_t logical_blocks;
|
|
||||||
struct dm_task *vdo_dmt;
|
|
||||||
uint64_t start, length = 0;
|
|
||||||
char *type = NULL;
|
|
||||||
char *vdo_params = NULL;
|
|
||||||
|
|
||||||
if (!_build_dev_string(data, sizeof(data), seg->vdo_data))
|
if (!_build_dev_string(data, sizeof(data), seg->vdo_data))
|
||||||
return_0;
|
return_0;
|
||||||
@@ -2961,34 +2866,6 @@ static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t
|
|||||||
return 0;
|
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) {
|
if (seg->vdo_version < 4) {
|
||||||
EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s ",
|
EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s ",
|
||||||
data_dev,
|
data_dev,
|
||||||
@@ -3002,15 +2879,12 @@ static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t
|
|||||||
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
|
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
|
||||||
seg->vdo_name);
|
seg->vdo_name);
|
||||||
} else {
|
} else {
|
||||||
EMIT_PARAMS(pos, "V4 %s " FMTu64 " %u " FMTu64 " %u "
|
EMIT_PARAMS(pos, "V4 %s " FMTu64 " %u " FMTu64 " %u ",
|
||||||
"deduplication %s compression %s ",
|
|
||||||
data_dev,
|
data_dev,
|
||||||
seg->vdo_data_size / 8, // this parameter is in 4K units
|
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.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_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
|
||||||
seg->vdo_params.block_map_era_length,
|
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, "maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
|
||||||
@@ -3088,7 +2962,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
|
|||||||
EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size);
|
EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size);
|
||||||
break;
|
break;
|
||||||
case SEG_VDO:
|
case SEG_VDO:
|
||||||
if (!_vdo_emit_segment_line(dmt, major, minor, seg, params, paramsize))
|
if (!_vdo_emit_segment_line(dmt, seg, params, paramsize))
|
||||||
return_0;
|
return_0;
|
||||||
break;
|
break;
|
||||||
case SEG_CRYPT:
|
case SEG_CRYPT:
|
||||||
@@ -3527,10 +3401,6 @@ int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
|
|||||||
/* Resume snapshot origins after new snapshots */
|
/* Resume snapshot origins after new snapshots */
|
||||||
dnode->activation_priority = 1;
|
dnode->activation_priority = 1;
|
||||||
|
|
||||||
if (!dnode->info.exists)
|
|
||||||
/* Reactivate siblings for this origin after being resumed */
|
|
||||||
dnode->props.reactivate_siblings = 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't resume the origin immediately in case it is a non-trivial
|
* Don't resume the origin immediately in case it is a non-trivial
|
||||||
* target that must not be active more than once concurrently!
|
* target that must not be active more than once concurrently!
|
||||||
@@ -3593,20 +3463,6 @@ static int _add_snapshot_target(struct dm_tree_node *node,
|
|||||||
/* Resume merging snapshot after snapshot-merge */
|
/* Resume merging snapshot after snapshot-merge */
|
||||||
seg->merge->activation_priority = 2;
|
seg->merge->activation_priority = 2;
|
||||||
}
|
}
|
||||||
} else if (!origin_node->info.exists) {
|
|
||||||
/* Keep original udev_flags for reactivation. */
|
|
||||||
node->props.reactivate_udev_flags = node->udev_flags;
|
|
||||||
|
|
||||||
/* Reactivation is needed if the origin's -real device is not in DM table.
|
|
||||||
* For this case after the resume of its origin LV we resume its snapshots
|
|
||||||
* with updated udev_flags to completely avoid udev scanning for the first resume.
|
|
||||||
* Reactivation then resumes snapshots with original udev_flags.
|
|
||||||
*/
|
|
||||||
node->udev_flags |= DM_SUBSYSTEM_UDEV_FLAG0 |
|
|
||||||
DM_UDEV_DISABLE_DISK_RULES_FLAG |
|
|
||||||
DM_UDEV_DISABLE_OTHER_RULES_FLAG;
|
|
||||||
log_debug_activation("Using udev_flags 0x%x for activation of %s.",
|
|
||||||
node->udev_flags, node->name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -3864,7 +3720,7 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
|
|||||||
{
|
{
|
||||||
struct dm_config_node *cn;
|
struct dm_config_node *cn;
|
||||||
struct load_segment *seg;
|
struct load_segment *seg;
|
||||||
const uint64_t modemask =
|
static const uint64_t _modemask =
|
||||||
DM_CACHE_FEATURE_PASSTHROUGH |
|
DM_CACHE_FEATURE_PASSTHROUGH |
|
||||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||||
DM_CACHE_FEATURE_WRITEBACK;
|
DM_CACHE_FEATURE_WRITEBACK;
|
||||||
@@ -3876,12 +3732,12 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (feature_flags & modemask) {
|
switch (feature_flags & _modemask) {
|
||||||
case DM_CACHE_FEATURE_PASSTHROUGH:
|
case DM_CACHE_FEATURE_PASSTHROUGH:
|
||||||
case DM_CACHE_FEATURE_WRITEBACK:
|
case DM_CACHE_FEATURE_WRITEBACK:
|
||||||
if (strcmp(policy_name, "cleaner") == 0) {
|
if (strcmp(policy_name, "cleaner") == 0) {
|
||||||
/* Enforce writethrough mode for cleaner policy */
|
/* Enforce writethrough mode for cleaner policy */
|
||||||
feature_flags = ~modemask;
|
feature_flags = ~_modemask;
|
||||||
feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||||
}
|
}
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
@@ -4364,12 +4220,6 @@ int dm_tree_node_set_thin_external_origin(struct dm_tree_node *node,
|
|||||||
|
|
||||||
seg->external = external;
|
seg->external = external;
|
||||||
|
|
||||||
if (!external->info.minor) {
|
|
||||||
log_debug_activation("Delaying resume for new external origin %s.",
|
|
||||||
external->name);
|
|
||||||
external->props.delay_resume_if_new = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4511,7 +4361,6 @@ int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
|
|||||||
seg->vdo_name = vdo_pool_name;
|
seg->vdo_name = vdo_pool_name;
|
||||||
seg->vdo_data_size = data_size;
|
seg->vdo_data_size = data_size;
|
||||||
|
|
||||||
if (seg->vdo_version < 4)
|
|
||||||
node->props.send_messages = 2;
|
node->props.send_messages = 2;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ retry_fcntl:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* coverity[leaked_handle] intentional leak of fd handle here */
|
/* coverity[leaked_handle] intentional leak of fd handle here */
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
fail_close_unlink:
|
fail_close_unlink:
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ struct op_def {
|
|||||||
* shorter one if one is a prefix of another!
|
* shorter one if one is a prefix of another!
|
||||||
* (e.g. =~ comes before =)
|
* (e.g. =~ comes before =)
|
||||||
*/
|
*/
|
||||||
static const struct op_def _op_cmp[] = {
|
static struct op_def _op_cmp[] = {
|
||||||
{ "=~", FLD_CMP_REGEX, "Matching regular expression. [regex]" },
|
{ "=~", FLD_CMP_REGEX, "Matching regular expression. [regex]" },
|
||||||
{ "!~", FLD_CMP_REGEX|FLD_CMP_NOT, "Not matching regular expression. [regex]" },
|
{ "!~", FLD_CMP_REGEX|FLD_CMP_NOT, "Not matching regular expression. [regex]" },
|
||||||
{ "=", FLD_CMP_EQUAL, "Equal to. [number, size, percent, string, string list, time]" },
|
{ "=", FLD_CMP_EQUAL, "Equal to. [number, size, percent, string, string list, time]" },
|
||||||
@@ -187,7 +187,7 @@ static const struct op_def _op_cmp[] = {
|
|||||||
#define SEL_LIST_SUBSET_LS 0x00040000
|
#define SEL_LIST_SUBSET_LS 0x00040000
|
||||||
#define SEL_LIST_SUBSET_LE 0x00080000
|
#define SEL_LIST_SUBSET_LE 0x00080000
|
||||||
|
|
||||||
static const struct op_def _op_log[] = {
|
static struct op_def _op_log[] = {
|
||||||
{ "&&", SEL_AND, "All fields must match" },
|
{ "&&", SEL_AND, "All fields must match" },
|
||||||
{ ",", SEL_AND, "All fields must match" },
|
{ ",", SEL_AND, "All fields must match" },
|
||||||
{ "||", SEL_OR, "At least one field must match" },
|
{ "||", SEL_OR, "At least one field must match" },
|
||||||
@@ -796,11 +796,11 @@ static const char *_get_field_type_name(unsigned field_type)
|
|||||||
static size_t _get_longest_field_id_len(const struct dm_report_field_type *fields)
|
static size_t _get_longest_field_id_len(const struct dm_report_field_type *fields)
|
||||||
{
|
{
|
||||||
uint32_t f;
|
uint32_t f;
|
||||||
size_t l, id_len = 0;
|
size_t id_len = 0;
|
||||||
|
|
||||||
for (f = 0; fields[f].report_fn; f++)
|
for (f = 0; fields[f].report_fn; f++)
|
||||||
if ((l = strlen(fields[f].id)) > id_len)
|
if (strlen(fields[f].id) > id_len)
|
||||||
id_len = l;
|
id_len = strlen(fields[f].id);
|
||||||
|
|
||||||
return id_len;
|
return id_len;
|
||||||
}
|
}
|
||||||
@@ -811,17 +811,16 @@ static void _display_fields_more(struct dm_report *rh,
|
|||||||
int display_field_types)
|
int display_field_types)
|
||||||
{
|
{
|
||||||
uint32_t f;
|
uint32_t f;
|
||||||
size_t l;
|
|
||||||
const struct dm_report_object_type *type;
|
const struct dm_report_object_type *type;
|
||||||
const char *desc, *last_desc = "";
|
const char *desc, *last_desc = "";
|
||||||
|
|
||||||
for (f = 0; fields[f].report_fn; f++)
|
for (f = 0; fields[f].report_fn; f++)
|
||||||
if ((l = strlen(fields[f].id)) > id_len)
|
if (strlen(fields[f].id) > id_len)
|
||||||
id_len = l;
|
id_len = strlen(fields[f].id);
|
||||||
|
|
||||||
for (type = rh->types; type->data_fn; type++)
|
for (type = rh->types; type->data_fn; type++)
|
||||||
if ((l = strlen(type->prefix) + 3) > id_len)
|
if (strlen(type->prefix) + 3 > id_len)
|
||||||
id_len = l;
|
id_len = strlen(type->prefix) + 3;
|
||||||
|
|
||||||
for (f = 0; fields[f].report_fn; f++) {
|
for (f = 0; fields[f].report_fn; f++) {
|
||||||
if (!(type = _find_type(rh, fields[f].type))) {
|
if (!(type = _find_type(rh, fields[f].type))) {
|
||||||
@@ -965,13 +964,16 @@ static int _get_canonical_field_name(const char *field,
|
|||||||
* Both names are always null-terminated.
|
* Both names are always null-terminated.
|
||||||
*/
|
*/
|
||||||
static int _is_same_field(const char *canonical_name1, const char *canonical_name2,
|
static int _is_same_field(const char *canonical_name1, const char *canonical_name2,
|
||||||
const char *prefix, size_t prefix_len)
|
const char *prefix)
|
||||||
{
|
{
|
||||||
|
size_t prefix_len;
|
||||||
|
|
||||||
/* Exact match? */
|
/* Exact match? */
|
||||||
if (!strcasecmp(canonical_name1, canonical_name2))
|
if (!strcasecmp(canonical_name1, canonical_name2))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Match including prefix? */
|
/* Match including prefix? */
|
||||||
|
prefix_len = strlen(prefix) - 1;
|
||||||
if (!strncasecmp(prefix, canonical_name1, prefix_len) &&
|
if (!strncasecmp(prefix, canonical_name1, prefix_len) &&
|
||||||
!strcasecmp(canonical_name1 + prefix_len, canonical_name2))
|
!strcasecmp(canonical_name1 + prefix_len, canonical_name2))
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1047,7 +1049,6 @@ static int _get_field(struct dm_report *rh, const char *field, size_t flen,
|
|||||||
{
|
{
|
||||||
char field_canon[DM_REPORT_FIELD_TYPE_ID_LEN];
|
char field_canon[DM_REPORT_FIELD_TYPE_ID_LEN];
|
||||||
uint32_t f;
|
uint32_t f;
|
||||||
size_t prefix_len;
|
|
||||||
|
|
||||||
if (!flen)
|
if (!flen)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1055,9 +1056,8 @@ static int _get_field(struct dm_report *rh, const char *field, size_t flen,
|
|||||||
if (!_get_canonical_field_name(field, flen, field_canon, sizeof(field_canon), NULL))
|
if (!_get_canonical_field_name(field, flen, field_canon, sizeof(field_canon), NULL))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
prefix_len = strlen(rh->field_prefix) - 1;
|
|
||||||
for (f = 0; _implicit_report_fields[f].report_fn; f++) {
|
for (f = 0; _implicit_report_fields[f].report_fn; f++) {
|
||||||
if (_is_same_field(_implicit_report_fields[f].id, field_canon, rh->field_prefix, prefix_len)) {
|
if (_is_same_field(_implicit_report_fields[f].id, field_canon, rh->field_prefix)) {
|
||||||
*f_ret = f;
|
*f_ret = f;
|
||||||
*implicit = 1;
|
*implicit = 1;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1065,7 +1065,7 @@ static int _get_field(struct dm_report *rh, const char *field, size_t flen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (f = 0; rh->fields[f].report_fn; f++) {
|
for (f = 0; rh->fields[f].report_fn; f++) {
|
||||||
if (_is_same_field(rh->canonical_field_ids[f], field_canon, rh->field_prefix, prefix_len)) {
|
if (_is_same_field(rh->canonical_field_ids[f], field_canon, rh->field_prefix)) {
|
||||||
*f_ret = f;
|
*f_ret = f;
|
||||||
*implicit = 0;
|
*implicit = 0;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1146,7 +1146,7 @@ static int _add_sort_key(struct dm_report *rh, uint32_t field_num, int implicit,
|
|||||||
static int _key_match(struct dm_report *rh, const char *key, size_t len,
|
static int _key_match(struct dm_report *rh, const char *key, size_t len,
|
||||||
unsigned report_type_only)
|
unsigned report_type_only)
|
||||||
{
|
{
|
||||||
int implicit;
|
char key_canon[DM_REPORT_FIELD_TYPE_ID_LEN];
|
||||||
uint32_t f;
|
uint32_t f;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
|
||||||
@@ -1169,8 +1169,16 @@ static int _key_match(struct dm_report *rh, const char *key, size_t len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_get_field(rh, key, len, &f, &implicit))
|
if (!_get_canonical_field_name(key, len, key_canon, sizeof(key_canon), NULL))
|
||||||
return _add_sort_key(rh, f, implicit, flags, report_type_only);
|
return_0;
|
||||||
|
|
||||||
|
for (f = 0; _implicit_report_fields[f].report_fn; f++)
|
||||||
|
if (_is_same_field(_implicit_report_fields[f].id, key_canon, rh->field_prefix))
|
||||||
|
return _add_sort_key(rh, f, 1, flags, report_type_only);
|
||||||
|
|
||||||
|
for (f = 0; rh->fields[f].report_fn; f++)
|
||||||
|
if (_is_same_field(rh->canonical_field_ids[f], key_canon, rh->field_prefix))
|
||||||
|
return _add_sort_key(rh, f, 0, flags, report_type_only);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1453,14 +1461,9 @@ static void *_report_get_field_data(struct dm_report *rh,
|
|||||||
const struct dm_report_field_type *fields = fp->implicit ? _implicit_report_fields
|
const struct dm_report_field_type *fields = fp->implicit ? _implicit_report_fields
|
||||||
: rh->fields;
|
: rh->fields;
|
||||||
|
|
||||||
char *ret;
|
char *ret = fp->type->data_fn(object);
|
||||||
|
|
||||||
if (!object) {
|
if (!ret)
|
||||||
log_error(INTERNAL_ERROR "_report_get_field_data: missing object.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(ret = fp->type->data_fn(object)))
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return (void *)(ret + fields[fp->field_num].offset);
|
return (void *)(ret + fields[fp->field_num].offset);
|
||||||
@@ -2261,7 +2264,7 @@ static const char * _skip_space(const char *s)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _tok_op(const struct op_def *t, const char *s, const char **end,
|
static int _tok_op(struct op_def *t, const char *s, const char **end,
|
||||||
uint32_t expect)
|
uint32_t expect)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
@@ -2502,7 +2505,7 @@ float dm_percent_to_float(dm_percent_t percent)
|
|||||||
|
|
||||||
float dm_percent_to_round_float(dm_percent_t percent, unsigned digits)
|
float dm_percent_to_round_float(dm_percent_t percent, unsigned digits)
|
||||||
{
|
{
|
||||||
const float power10[] = {
|
static const float power10[] = {
|
||||||
1.f, .1f, .01f, .001f, .0001f, .00001f, .000001f,
|
1.f, .1f, .01f, .001f, .0001f, .00001f, .000001f,
|
||||||
.0000001f, .00000001f, .000000001f,
|
.0000001f, .00000001f, .000000001f,
|
||||||
.0000000001f
|
.0000000001f
|
||||||
@@ -2568,12 +2571,12 @@ static int _check_reserved_values_supported(const struct dm_report_field_type fi
|
|||||||
const struct dm_report_reserved_value *iter;
|
const struct dm_report_reserved_value *iter;
|
||||||
const struct dm_report_field_reserved_value *field_res;
|
const struct dm_report_field_reserved_value *field_res;
|
||||||
const struct dm_report_field_type *field;
|
const struct dm_report_field_type *field;
|
||||||
const uint32_t supported_reserved_types = DM_REPORT_FIELD_TYPE_NUMBER |
|
static uint32_t supported_reserved_types = DM_REPORT_FIELD_TYPE_NUMBER |
|
||||||
DM_REPORT_FIELD_TYPE_SIZE |
|
DM_REPORT_FIELD_TYPE_SIZE |
|
||||||
DM_REPORT_FIELD_TYPE_PERCENT |
|
DM_REPORT_FIELD_TYPE_PERCENT |
|
||||||
DM_REPORT_FIELD_TYPE_STRING |
|
DM_REPORT_FIELD_TYPE_STRING |
|
||||||
DM_REPORT_FIELD_TYPE_TIME;
|
DM_REPORT_FIELD_TYPE_TIME;
|
||||||
const uint32_t supported_reserved_types_with_range = DM_REPORT_FIELD_RESERVED_VALUE_RANGE |
|
static uint32_t supported_reserved_types_with_range = DM_REPORT_FIELD_RESERVED_VALUE_RANGE |
|
||||||
DM_REPORT_FIELD_TYPE_NUMBER |
|
DM_REPORT_FIELD_TYPE_NUMBER |
|
||||||
DM_REPORT_FIELD_TYPE_SIZE |
|
DM_REPORT_FIELD_TYPE_SIZE |
|
||||||
DM_REPORT_FIELD_TYPE_PERCENT |
|
DM_REPORT_FIELD_TYPE_PERCENT |
|
||||||
@@ -2589,8 +2592,7 @@ static int _check_reserved_values_supported(const struct dm_report_field_type fi
|
|||||||
if (iter->type & DM_REPORT_FIELD_TYPE_MASK) {
|
if (iter->type & DM_REPORT_FIELD_TYPE_MASK) {
|
||||||
if (!(iter->type & supported_reserved_types) ||
|
if (!(iter->type & supported_reserved_types) ||
|
||||||
((iter->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE) &&
|
((iter->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE) &&
|
||||||
!(iter->type & (supported_reserved_types_with_range &
|
!(iter->type & supported_reserved_types_with_range))) {
|
||||||
~DM_REPORT_FIELD_RESERVED_VALUE_RANGE)))) {
|
|
||||||
log_error(INTERNAL_ERROR "_check_reserved_values_supported: "
|
log_error(INTERNAL_ERROR "_check_reserved_values_supported: "
|
||||||
"global reserved value for type 0x%x not supported",
|
"global reserved value for type 0x%x not supported",
|
||||||
iter->type);
|
iter->type);
|
||||||
@@ -2600,9 +2602,8 @@ static int _check_reserved_values_supported(const struct dm_report_field_type fi
|
|||||||
field_res = (const struct dm_report_field_reserved_value *) iter->value;
|
field_res = (const struct dm_report_field_reserved_value *) iter->value;
|
||||||
field = &fields[field_res->field_num];
|
field = &fields[field_res->field_num];
|
||||||
if (!(field->flags & supported_reserved_types) ||
|
if (!(field->flags & supported_reserved_types) ||
|
||||||
((field->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE) &&
|
((iter->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE) &&
|
||||||
!(field->type & (supported_reserved_types_with_range &
|
!(iter->type & supported_reserved_types_with_range))) {
|
||||||
~DM_REPORT_FIELD_RESERVED_VALUE_RANGE)))) {
|
|
||||||
log_error(INTERNAL_ERROR "_check_reserved_values_supported: "
|
log_error(INTERNAL_ERROR "_check_reserved_values_supported: "
|
||||||
"field-specific reserved value of type 0x%x for "
|
"field-specific reserved value of type 0x%x for "
|
||||||
"field %s not supported",
|
"field %s not supported",
|
||||||
@@ -2842,7 +2843,7 @@ struct time_value {
|
|||||||
time_t t2;
|
time_t t2;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char _out_of_range_msg[] = "Field selection value %s out of supported range for field %s.";
|
static const char *_out_of_range_msg = "Field selection value %s out of supported range for field %s.";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Standard formatted date and time - ISO8601.
|
* Standard formatted date and time - ISO8601.
|
||||||
@@ -2867,7 +2868,7 @@ static const char _out_of_range_msg[] = "Field selection value %s out of support
|
|||||||
#define DELIM_DATE '-'
|
#define DELIM_DATE '-'
|
||||||
#define DELIM_TIME ':'
|
#define DELIM_TIME ':'
|
||||||
|
|
||||||
static const int _days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
static int _days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
static int _is_leap_year(long year)
|
static int _is_leap_year(long year)
|
||||||
{
|
{
|
||||||
@@ -2892,6 +2893,7 @@ typedef enum {
|
|||||||
|
|
||||||
static char *_get_date(char *str, struct tm *tm, time_range_t *range)
|
static char *_get_date(char *str, struct tm *tm, time_range_t *range)
|
||||||
{
|
{
|
||||||
|
static const char incorrect_date_format_msg[] = "Incorrect date format.";
|
||||||
time_range_t tmp_range = RANGE_NONE;
|
time_range_t tmp_range = RANGE_NONE;
|
||||||
long n1, n2 = -1, n3 = -1;
|
long n1, n2 = -1, n3 = -1;
|
||||||
char *s = str, *end;
|
char *s = str, *end;
|
||||||
@@ -2937,15 +2939,19 @@ static char *_get_date(char *str, struct tm *tm, time_range_t *range)
|
|||||||
n3 = n1 % 100;
|
n3 = n1 % 100;
|
||||||
n2 = (n1 / 100) % 100;
|
n2 = (n1 / 100) % 100;
|
||||||
n1 = n1 / 10000;
|
n1 = n1 / 10000;
|
||||||
} else
|
} else {
|
||||||
goto_bad;
|
log_error(incorrect_date_format_msg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (len == 7) {
|
if (len == 7) {
|
||||||
tmp_range = RANGE_MONTH;
|
tmp_range = RANGE_MONTH;
|
||||||
/* YYYY-MM */
|
/* YYYY-MM */
|
||||||
n3 = 1;
|
n3 = 1;
|
||||||
} else
|
} else {
|
||||||
goto_bad;
|
log_error(incorrect_date_format_msg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2968,15 +2974,11 @@ static char *_get_date(char *str, struct tm *tm, time_range_t *range)
|
|||||||
*range = tmp_range;
|
*range = tmp_range;
|
||||||
|
|
||||||
return (char *) _skip_space(end);
|
return (char *) _skip_space(end);
|
||||||
|
|
||||||
bad:
|
|
||||||
log_error("Incorrect date format.");
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *_get_time(char *str, struct tm *tm, time_range_t *range)
|
static char *_get_time(char *str, struct tm *tm, time_range_t *range)
|
||||||
{
|
{
|
||||||
|
static const char incorrect_time_format_msg[] = "Incorrect time format.";
|
||||||
time_range_t tmp_range = RANGE_NONE;
|
time_range_t tmp_range = RANGE_NONE;
|
||||||
long n1, n2 = -1, n3 = -1;
|
long n1, n2 = -1, n3 = -1;
|
||||||
char *s = str, *end;
|
char *s = str, *end;
|
||||||
@@ -3024,15 +3026,19 @@ static char *_get_time(char *str, struct tm *tm, time_range_t *range)
|
|||||||
n3 = n1 % 100;
|
n3 = n1 % 100;
|
||||||
n2 = (n1 / 100) % 100;
|
n2 = (n1 / 100) % 100;
|
||||||
n1 = n1 / 10000;
|
n1 = n1 / 10000;
|
||||||
} else
|
} else {
|
||||||
goto_bad;
|
log_error(incorrect_time_format_msg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (len == 5) {
|
if (len == 5) {
|
||||||
/* HH:MM */
|
/* HH:MM */
|
||||||
tmp_range = RANGE_MINUTE;
|
tmp_range = RANGE_MINUTE;
|
||||||
n3 = 0;
|
n3 = 0;
|
||||||
} else
|
} else {
|
||||||
goto_bad;
|
log_error(incorrect_time_format_msg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3063,11 +3069,6 @@ static char *_get_time(char *str, struct tm *tm, time_range_t *range)
|
|||||||
*range = tmp_range;
|
*range = tmp_range;
|
||||||
|
|
||||||
return (char *) _skip_space(end);
|
return (char *) _skip_space(end);
|
||||||
|
|
||||||
bad:
|
|
||||||
log_error("Incorrect time format.");
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The offset is always an absolute offset against GMT! */
|
/* The offset is always an absolute offset against GMT! */
|
||||||
@@ -3516,6 +3517,7 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
|
|||||||
struct reserved_value_wrapper *rvw,
|
struct reserved_value_wrapper *rvw,
|
||||||
void *custom)
|
void *custom)
|
||||||
{
|
{
|
||||||
|
static const char *_field_selection_value_alloc_failed_msg = "dm_report: struct field_selection_value allocation failed for selection field %s";
|
||||||
const struct dm_report_field_type *fields = implicit ? _implicit_report_fields
|
const struct dm_report_field_type *fields = implicit ? _implicit_report_fields
|
||||||
: rh->fields;
|
: rh->fields;
|
||||||
struct field_properties *fp, *found = NULL;
|
struct field_properties *fp, *found = NULL;
|
||||||
@@ -3563,8 +3565,8 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(fs->value = dm_pool_zalloc(rh->selection->mem, sizeof(struct field_selection_value)))) {
|
if (!(fs->value = dm_pool_zalloc(rh->selection->mem, sizeof(struct field_selection_value)))) {
|
||||||
stack;
|
log_error(_field_selection_value_alloc_failed_msg, field_id);
|
||||||
goto error_field_id;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((rvw->reserved && (rvw->reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)) ||
|
if (((rvw->reserved && (rvw->reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)) ||
|
||||||
@@ -3572,8 +3574,8 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
|
|||||||
custom && ((struct time_value *) custom)->range))
|
custom && ((struct time_value *) custom)->range))
|
||||||
&&
|
&&
|
||||||
!(fs->value->next = dm_pool_zalloc(rh->selection->mem, sizeof(struct field_selection_value)))) {
|
!(fs->value->next = dm_pool_zalloc(rh->selection->mem, sizeof(struct field_selection_value)))) {
|
||||||
stack;
|
log_error(_field_selection_value_alloc_failed_msg, field_id);
|
||||||
goto error_field_id;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs->fp = found;
|
fs->fp = found;
|
||||||
@@ -3722,10 +3724,6 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return fs;
|
return fs;
|
||||||
error_field_id:
|
|
||||||
log_error("dm_report: struct field_selection_value allocation failed for selection field %s",
|
|
||||||
field_id);
|
|
||||||
goto error;
|
|
||||||
bad:
|
bad:
|
||||||
log_error(INTERNAL_ERROR "Forbiden NULL custom detected.");
|
log_error(INTERNAL_ERROR "Forbiden NULL custom detected.");
|
||||||
error:
|
error:
|
||||||
@@ -3754,7 +3752,7 @@ static struct selection_node *_alloc_selection_node(struct dm_pool *mem, uint32_
|
|||||||
static void _display_selection_help(struct dm_report *rh)
|
static void _display_selection_help(struct dm_report *rh)
|
||||||
{
|
{
|
||||||
static const char _grow_object_failed_msg[] = "_display_selection_help: dm_pool_grow_object failed";
|
static const char _grow_object_failed_msg[] = "_display_selection_help: dm_pool_grow_object failed";
|
||||||
const struct op_def *t;
|
struct op_def *t;
|
||||||
const struct dm_report_reserved_value *rv;
|
const struct dm_report_reserved_value *rv;
|
||||||
size_t len_all, len_final = 0;
|
size_t len_all, len_final = 0;
|
||||||
const char **rvs;
|
const char **rvs;
|
||||||
@@ -4107,7 +4105,7 @@ static int _alloc_rh_selection(struct dm_report *rh)
|
|||||||
static int _report_set_selection(struct dm_report *rh, const char *selection, int add_new_fields)
|
static int _report_set_selection(struct dm_report *rh, const char *selection, int add_new_fields)
|
||||||
{
|
{
|
||||||
struct selection_node *root = NULL;
|
struct selection_node *root = NULL;
|
||||||
const char *fin = NULL, *next;
|
const char *fin, *next;
|
||||||
|
|
||||||
if (rh->selection) {
|
if (rh->selection) {
|
||||||
if (rh->selection->selection_root)
|
if (rh->selection->selection_root)
|
||||||
@@ -4127,7 +4125,7 @@ static int _report_set_selection(struct dm_report *rh, const char *selection, in
|
|||||||
if (!(root = _alloc_selection_node(rh->selection->mem, SEL_OR)))
|
if (!(root = _alloc_selection_node(rh->selection->mem, SEL_OR)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!_parse_or_ex(rh, selection, &fin, root) || !fin)
|
if (!_parse_or_ex(rh, selection, &fin, root))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
next = _skip_space(fin);
|
next = _skip_space(fin);
|
||||||
@@ -4265,9 +4263,7 @@ static int _report_headings(struct dm_report *rh)
|
|||||||
|
|
||||||
fields = fp->implicit ? _implicit_report_fields : rh->fields;
|
fields = fp->implicit ? _implicit_report_fields : rh->fields;
|
||||||
|
|
||||||
heading = rh->flags & DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS ?
|
heading = fields[fp->field_num].heading;
|
||||||
fields[fp->field_num].id : fields[fp->field_num].heading;
|
|
||||||
|
|
||||||
if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
|
if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
|
||||||
if (dm_snprintf(buf, buf_size, "%-*.*s",
|
if (dm_snprintf(buf, buf_size, "%-*.*s",
|
||||||
fp->width, fp->width, heading) < 0) {
|
fp->width, fp->width, heading) < 0) {
|
||||||
@@ -4319,7 +4315,6 @@ static void _recalculate_fields(struct dm_report *rh)
|
|||||||
struct row *row;
|
struct row *row;
|
||||||
struct dm_report_field *field;
|
struct dm_report_field *field;
|
||||||
int len;
|
int len;
|
||||||
int id_len;
|
|
||||||
|
|
||||||
dm_list_iterate_items(row, &rh->rows) {
|
dm_list_iterate_items(row, &rh->rows) {
|
||||||
dm_list_iterate_items(field, &row->fields) {
|
dm_list_iterate_items(field, &row->fields) {
|
||||||
@@ -4334,12 +4329,6 @@ static void _recalculate_fields(struct dm_report *rh)
|
|||||||
field->props->width = len;
|
field->props->width = len;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rh->flags & DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS) {
|
|
||||||
id_len = (int) strlen(rh->fields[field->props->field_num].id);
|
|
||||||
if (field->props->width < id_len)
|
|
||||||
field->props->width = id_len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4426,9 +4415,8 @@ static int _sort_rows(struct dm_report *rh)
|
|||||||
qsort(rows, count, sizeof(**rows), _row_compare);
|
qsort(rows, count, sizeof(**rows), _row_compare);
|
||||||
|
|
||||||
dm_list_init(&rh->rows);
|
dm_list_init(&rh->rows);
|
||||||
|
while (count--)
|
||||||
while (count > 0)
|
dm_list_add_h(&rh->rows, &(*rows)[count]->list);
|
||||||
dm_list_add_h(&rh->rows, &(*rows)[--count]->list);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -4584,12 +4572,17 @@ bad:
|
|||||||
static int _safe_repstr_output(struct dm_report *rh, const char *repstr, size_t len)
|
static int _safe_repstr_output(struct dm_report *rh, const char *repstr, size_t len)
|
||||||
{
|
{
|
||||||
const char *p_repstr;
|
const char *p_repstr;
|
||||||
const char *repstr_end = len ? repstr + len : repstr + strlen(repstr);
|
const char *repstr_end = repstr + len;
|
||||||
|
|
||||||
/* Escape any JSON_QUOTE that may appear in reported string. */
|
/* Escape any JSON_QUOTE that may appear in reported string. */
|
||||||
while (1) {
|
while (1) {
|
||||||
|
if (len) {
|
||||||
if (!(p_repstr = memchr(repstr, JSON_QUOTE[0], repstr_end - repstr)))
|
if (!(p_repstr = memchr(repstr, JSON_QUOTE[0], repstr_end - repstr)))
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
if (!(p_repstr = strstr(repstr, JSON_QUOTE)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (p_repstr > repstr) {
|
if (p_repstr > repstr) {
|
||||||
if (!dm_pool_grow_object(rh->mem, repstr, p_repstr - repstr)) {
|
if (!dm_pool_grow_object(rh->mem, repstr, p_repstr - repstr)) {
|
||||||
@@ -4752,7 +4745,6 @@ static int _output_as_rows(struct dm_report *rh)
|
|||||||
struct field_properties *fp;
|
struct field_properties *fp;
|
||||||
struct dm_report_field *field;
|
struct dm_report_field *field;
|
||||||
struct row *row;
|
struct row *row;
|
||||||
const char *heading;
|
|
||||||
|
|
||||||
dm_list_iterate_items(fp, &rh->field_props) {
|
dm_list_iterate_items(fp, &rh->field_props) {
|
||||||
if (fp->flags & FLD_HIDDEN) {
|
if (fp->flags & FLD_HIDDEN) {
|
||||||
@@ -4771,10 +4763,7 @@ static int _output_as_rows(struct dm_report *rh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((rh->flags & DM_REPORT_OUTPUT_HEADINGS)) {
|
if ((rh->flags & DM_REPORT_OUTPUT_HEADINGS)) {
|
||||||
heading = rh->flags & DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS ?
|
if (!dm_pool_grow_object(rh->mem, fields[fp->field_num].heading, 0)) {
|
||||||
fields[fp->field_num].id : fields[fp->field_num].heading;
|
|
||||||
|
|
||||||
if (!dm_pool_grow_object(rh->mem, heading, 0)) {
|
|
||||||
log_error("dm_report: Failed to extend row for field name");
|
log_error("dm_report: Failed to extend row for field name");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@@ -4814,36 +4803,12 @@ static int _output_as_rows(struct dm_report *rh)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dm_list *_get_last_displayed_rowh(struct dm_report *rh)
|
|
||||||
{
|
|
||||||
struct dm_list *rowh;
|
|
||||||
struct row *row;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We need to find 'last displayed row', not just 'last row'.
|
|
||||||
*
|
|
||||||
* This is because the report may be marked with
|
|
||||||
* DM_REPORT_OUTPUT_MULTIPLE_TIMES flag. In that case, the report
|
|
||||||
* may be used more than once and with different selection
|
|
||||||
* criteria each time. Therefore, such report may also contain
|
|
||||||
* rows which we do not display on output with current selection
|
|
||||||
* criteria.
|
|
||||||
*/
|
|
||||||
for (rowh = dm_list_last(&rh->rows); rowh; rowh = dm_list_prev(&rh->rows, rowh)) {
|
|
||||||
row = dm_list_item(rowh, struct row);
|
|
||||||
if (_should_display_row(row))
|
|
||||||
return rowh;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _output_as_columns(struct dm_report *rh)
|
static int _output_as_columns(struct dm_report *rh)
|
||||||
{
|
{
|
||||||
struct dm_list *fh, *rowh, *ftmp, *rtmp;
|
struct dm_list *fh, *rowh, *ftmp, *rtmp;
|
||||||
struct row *row = NULL;
|
struct row *row = NULL;
|
||||||
struct dm_report_field *field;
|
struct dm_report_field *field;
|
||||||
struct dm_list *last_rowh;
|
struct dm_list *last_row;
|
||||||
int do_field_delim;
|
int do_field_delim;
|
||||||
char *line;
|
char *line;
|
||||||
|
|
||||||
@@ -4852,7 +4817,7 @@ static int _output_as_columns(struct dm_report *rh)
|
|||||||
_report_headings(rh);
|
_report_headings(rh);
|
||||||
|
|
||||||
/* Print and clear buffer */
|
/* Print and clear buffer */
|
||||||
last_rowh = _get_last_displayed_rowh(rh);
|
last_row = dm_list_last(&rh->rows);
|
||||||
dm_list_iterate_safe(rowh, rtmp, &rh->rows) {
|
dm_list_iterate_safe(rowh, rtmp, &rh->rows) {
|
||||||
row = dm_list_item(rowh, struct row);
|
row = dm_list_item(rowh, struct row);
|
||||||
|
|
||||||
@@ -4906,7 +4871,7 @@ static int _output_as_columns(struct dm_report *rh)
|
|||||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
if (rowh != last_rowh &&
|
if (rowh != last_row &&
|
||||||
!dm_pool_grow_object(rh->mem, JSON_SEPARATOR, 0)) {
|
!dm_pool_grow_object(rh->mem, JSON_SEPARATOR, 0)) {
|
||||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ int dm_asprintf(char **result, const char *format, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Count occurrences of 'c' in 'str' until we reach a null char.
|
* Count occurences of 'c' in 'str' until we reach a null char.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* len - incremented for each char we encounter.
|
* len - incremented for each char we encounter.
|
||||||
@@ -385,7 +385,7 @@ char *dm_build_dm_uuid(struct dm_pool *mem, const char *uuid_prefix, const char
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(dmuuid, len, "%s%s%s%s", uuid_prefix, lvid, (*layer) ? "-" : "", layer);
|
sprintf(dmuuid, "%s%s%s%s", uuid_prefix, lvid, (*layer) ? "-" : "", layer);
|
||||||
|
|
||||||
return dmuuid;
|
return dmuuid;
|
||||||
}
|
}
|
||||||
@@ -552,7 +552,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
|
|||||||
if (size == UINT64_C(0)) {
|
if (size == UINT64_C(0)) {
|
||||||
if (base == BASE_UNKNOWN)
|
if (base == BASE_UNKNOWN)
|
||||||
s = 0;
|
s = 0;
|
||||||
snprintf(size_buf, SIZE_BUF, "0%s", include_suffix ? size_str[base + s][suffix_type] : "");
|
sprintf(size_buf, "0%s", include_suffix ? size_str[base + s][suffix_type] : "");
|
||||||
return size_buf;
|
return size_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,31 +106,26 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
|
|||||||
|
|
||||||
/* Second field holds the device count */
|
/* Second field holds the device count */
|
||||||
msg_fields = "<#devs> ";
|
msg_fields = "<#devs> ";
|
||||||
if (!(pp = _skip_fields(params, 1)) || (sscanf(pp, "%d", &i) != 1) || !(p = _skip_fields(pp, 1)))
|
if (!(p = _skip_fields(params, 1)) || (sscanf(p, "%d", &i) != 1))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
msg_fields = "";
|
msg_fields = "";
|
||||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid))))
|
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid))))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> ";
|
if (!(s->raid_type = dm_pool_zalloc(mem, p - params)))
|
||||||
if (!(s->raid_type = dm_pool_strndup(mem, params, pp - params - 1)))
|
|
||||||
goto_bad; /* memory is freed when pool is destroyed */
|
goto_bad; /* memory is freed when pool is destroyed */
|
||||||
|
|
||||||
if (!(pp = _skip_fields(p, 1)))
|
if (!(s->dev_health = dm_pool_zalloc(mem, i + 1))) /* Space for health chars */
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
/* Raid target can actually report more then real number of legs in a case
|
msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> ";
|
||||||
* raid legs have been removed during initial raid array resynchronization */
|
if (sscanf(params, "%s %u %s " FMTu64 "/" FMTu64,
|
||||||
if (i > (pp - p - 1))
|
s->raid_type,
|
||||||
i = pp - p - 1;
|
&s->dev_count,
|
||||||
|
s->dev_health,
|
||||||
if (!(s->dev_health = dm_pool_strndup(mem, p, i))) /* health chars */
|
&s->insync_regions,
|
||||||
goto_bad;
|
&s->total_regions) != 5)
|
||||||
p = pp;
|
|
||||||
|
|
||||||
s->dev_count = i;
|
|
||||||
if (sscanf(p, FMTu64 "/" FMTu64, &s->insync_regions, &s->total_regions) != 2)
|
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -146,13 +141,13 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
|
|||||||
msg_fields = "<sync_action> and <mismatch_cnt> ";
|
msg_fields = "<sync_action> and <mismatch_cnt> ";
|
||||||
|
|
||||||
/* Skip pre-1.5.0 params */
|
/* Skip pre-1.5.0 params */
|
||||||
if (!(pp = _skip_fields(params, 4)) || !(p = _skip_fields(pp, 1)))
|
if (!(p = _skip_fields(params, 4)) || !(pp = _skip_fields(p, 1)))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
if (!(s->sync_action = dm_pool_strndup(mem, pp, p - pp - 1)))
|
if (!(s->sync_action = dm_pool_zalloc(mem, pp - p)))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
if (sscanf(p, FMTu64, &s->mismatch_count) != 1)
|
if (sscanf(p, "%s " FMTu64, s->sync_action, &s->mismatch_count) != 2)
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
if (num_fields < 7)
|
if (num_fields < 7)
|
||||||
@@ -171,36 +166,24 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
|
|||||||
if (sscanf(p, FMTu64, &s->data_offset) != 1)
|
if (sscanf(p, FMTu64, &s->data_offset) != 1)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
/* <journal_char> - 'A' - active write-through journal device.
|
|
||||||
* - 'a' - active write-back journal device.
|
|
||||||
* - 'D' - dead journal device.
|
|
||||||
* - '-' - no journal device.
|
|
||||||
*/
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
*status = s;
|
*status = s;
|
||||||
|
|
||||||
|
if (s->insync_regions == s->total_regions) {
|
||||||
|
/* FIXME: kernel gives misleading info here
|
||||||
|
* Trying to recognize a true state */
|
||||||
while (i-- > 0)
|
while (i-- > 0)
|
||||||
if (s->dev_health[i] == 'a')
|
if (s->dev_health[i] == 'a')
|
||||||
a++; /* Count number of 'a' */
|
a++; /* Count number of 'a' */
|
||||||
|
|
||||||
if (a) {
|
if (a && a < s->dev_count) {
|
||||||
if ((a < s->dev_count) && /* SOME legs are in 'a' */
|
/* SOME legs are in 'a' */
|
||||||
/* FIXME: kernel gives misleading info here
|
if (!strcasecmp(s->sync_action, "recover")
|
||||||
* Trying to recognize a true state */
|
|| !strcasecmp(s->sync_action, "idle"))
|
||||||
(s->insync_regions == s->total_regions) &&
|
|
||||||
(!strcasecmp(s->sync_action, "recover") ||
|
|
||||||
!strcasecmp(s->sync_action, "idle"))) {
|
|
||||||
/* Kernel may possibly start some action
|
/* Kernel may possibly start some action
|
||||||
* in near-by future, do not report 100% */
|
* in near-by future, do not report 100% */
|
||||||
s->insync_regions--;
|
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';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -528,21 +511,6 @@ int dm_get_status_thin(struct dm_pool *mem, const char *params,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static dm_status_mirror_health_t _get_health(char c)
|
|
||||||
{
|
|
||||||
switch (c) {
|
|
||||||
case 'A': return DM_STATUS_MIRROR_ALIVE;
|
|
||||||
case 'F': return DM_STATUS_MIRROR_FLUSH_FAILED;
|
|
||||||
case 'D': return DM_STATUS_MIRROR_WRITE_FAILED;
|
|
||||||
case 'S': return DM_STATUS_MIRROR_SYNC_FAILED;
|
|
||||||
case 'R': return DM_STATUS_MIRROR_READ_FAILED;
|
|
||||||
default:
|
|
||||||
log_warn("WARNING: Unknown mirror health status char: %c", c);
|
|
||||||
/* fall through */
|
|
||||||
case 'U': return DM_STATUS_MIRROR_UNCLASSIFIED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dm core parms: 0 409600 mirror
|
* dm core parms: 0 409600 mirror
|
||||||
* Mirror core parms: 2 253:4 253:5 400/400
|
* Mirror core parms: 2 253:4 253:5 400/400
|
||||||
@@ -596,7 +564,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
|
|||||||
pos += used;
|
pos += used;
|
||||||
|
|
||||||
for (i = 0; i < num_devs ; ++i)
|
for (i = 0; i < num_devs ; ++i)
|
||||||
s->devs[i].health = _get_health(pos[i]);
|
s->devs[i].health = pos[i];
|
||||||
|
|
||||||
if (!(pos = _skip_fields(pos, argc)))
|
if (!(pos = _skip_fields(pos, argc)))
|
||||||
goto_out;
|
goto_out;
|
||||||
@@ -641,7 +609,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
|
|||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
for (i = 0; i < s->log_count; ++i)
|
for (i = 0; i < s->log_count; ++i)
|
||||||
s->logs[i].health = _get_health(pos[i]);
|
s->logs[i].health = pos[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ struct dm_vdo_target_params {
|
|||||||
uint32_t block_map_era_length; // format period
|
uint32_t block_map_era_length; // format period
|
||||||
uint32_t block_map_period; // supported alias
|
uint32_t block_map_period; // supported alias
|
||||||
};
|
};
|
||||||
|
uint32_t check_point_frequency;
|
||||||
uint32_t index_memory_size_mb; // format
|
uint32_t index_memory_size_mb; // format
|
||||||
|
|
||||||
uint32_t slab_size_mb; // format
|
uint32_t slab_size_mb; // format
|
||||||
@@ -107,8 +108,6 @@ struct dm_vdo_target_params {
|
|||||||
bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
|
bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
|
||||||
uint64_t vdo_size);
|
uint64_t vdo_size);
|
||||||
|
|
||||||
bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks);
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -156,9 +156,9 @@ bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vdo_size > DM_VDO_LOGICAL_SIZE_MAXIMUM) {
|
if (vdo_size > DM_VDO_LOGICAL_SIZE_MAXIMUM) {
|
||||||
log_error("VDO logical size is larger than limit " FMTu64 " TiB by " FMTu64 " KiB.",
|
log_error("VDO logical size is by " FMTu64 "KiB bigger then limit " FMTu64 "TiB.",
|
||||||
DM_VDO_LOGICAL_SIZE_MAXIMUM / (UINT64_C(1024) * 1024 * 1024 * 1024 >> SECTOR_SHIFT),
|
(vdo_size - DM_VDO_LOGICAL_SIZE_MAXIMUM) / 2,
|
||||||
(vdo_size - DM_VDO_LOGICAL_SIZE_MAXIMUM) / 2);
|
DM_VDO_LOGICAL_SIZE_MAXIMUM / (UINT64_C(1024) * 1024 * 1024 * 1024 >> SECTOR_SHIFT));
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
|
||||||
|
|
||||||
@@ -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.
|
|
||||||
152
doc/index.mdwn
152
doc/index.mdwn
@@ -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
|
|
||||||
-->
|
|
||||||
@@ -67,7 +67,7 @@ the entries (each hotspot block covers a larger area than a single
|
|||||||
cache block).
|
cache block).
|
||||||
|
|
||||||
All this means smq uses ~25bytes per cache block. Still a lot of
|
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:
|
Level balancing:
|
||||||
mq placed entries in different levels of the multiqueue structures
|
mq placed entries in different levels of the multiqueue structures
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
|
|||||||
capi:authenc(hmac(sha256),xts(aes))-random
|
capi:authenc(hmac(sha256),xts(aes))-random
|
||||||
capi:rfc7539(chacha20,poly1305)-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>
|
||||||
Key used for encryption. It is encoded either as a hexadecimal number
|
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>
|
<#opt_params>
|
||||||
Number of optional parameters. If there are no optional parameters,
|
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.
|
Otherwise #opt_params is the number of following arguments.
|
||||||
|
|
||||||
Example of optional parameters section:
|
Example of optional parameters section:
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ journal_crypt:algorithm(:key) (the key is optional)
|
|||||||
"salsa20", "ctr(aes)" or "ecb(arc4)").
|
"salsa20", "ctr(aes)" or "ecb(arc4)").
|
||||||
|
|
||||||
The journal contains history of last writes to the block device,
|
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
|
that were written. From the sector numbers, the attacker can infer
|
||||||
the size of files that were written. To protect against this
|
the size of files that were written. To protect against this
|
||||||
situation, you can encrypt the journal.
|
situation, you can encrypt the journal.
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ Construction Parameters
|
|||||||
|
|
||||||
<#opt_params>
|
<#opt_params>
|
||||||
Number of optional parameters. If there are no optional parameters,
|
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.
|
Otherwise #opt_params is the number of following arguments.
|
||||||
|
|
||||||
Example of optional parameters section:
|
Example of optional parameters section:
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
.page {
|
|
||||||
max-width: 1280px;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
@@ -37,7 +37,7 @@ segment type. The available RAID types are:
|
|||||||
"raid6_nr" - RAID6 Rotating parity N with data restart
|
"raid6_nr" - RAID6 Rotating parity N with data restart
|
||||||
"raid6_nc" - RAID6 Rotating parity N with data continuation
|
"raid6_nc" - RAID6 Rotating parity N with data continuation
|
||||||
The exception to 'no shorthand options' will be where the RAID implementations
|
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
|
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
|
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
|
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 -
|
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
|
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
|
It will be simple enough to detect if the LV being up/down-converted is
|
||||||
new or old-style mirroring.
|
new or old-style mirroring.
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ RAID4 to RAID5 or RAID5 to RAID6.
|
|||||||
Line 02/03/04:
|
Line 02/03/04:
|
||||||
These are familiar options - all of which would now be available as options
|
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.
|
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.)
|
parameter to many functions in the LVM codebase.)
|
||||||
|
|
||||||
Line 05:
|
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
|
their index in the array. Unlike the "mirror" segment type, you will never have
|
||||||
an image named "*_rimage_1" occupying the index position 0.
|
an image named "*_rimage_1" occupying the index position 0.
|
||||||
|
|
||||||
As with adding images, removing images holds off on committing LVM metadata
|
As with adding images, removing images holds off on commiting LVM metadata
|
||||||
until all possible changes have been made. This reduces the likelihood of bad
|
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.
|
intermediate stages being left due to a failure of operation or machine crash.
|
||||||
|
|
||||||
RAID1 '--splitmirrors', '--trackchanges', and '--merge' operations
|
RAID1 '--splitmirrors', '--trackchanges', and '--merge' operations
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ are as follows:
|
|||||||
/etc/lvm/lvm.conf. Once this operation is complete, the logical volumes
|
/etc/lvm/lvm.conf. Once this operation is complete, the logical volumes
|
||||||
will be consistent. However, the volume group will still be inconsistent -
|
will be consistent. However, the volume group will still be inconsistent -
|
||||||
due to the refernced-but-missing device/PV - and operations will still be
|
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.
|
restored or 'vgreduce --removemissing' is run.
|
||||||
|
|
||||||
Device Revival (transient failures):
|
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
|
This error will propagate all the way up to the applications above the
|
||||||
logical volume (e.g. the file system). No automatic intervention will
|
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
|
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
|
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.
|
the failed image and proceed.
|
||||||
|
|
||||||
Mirror resynchronization errors:
|
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.
|
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 "allocate" policy takes the further action of trying to replace
|
||||||
the failed image using space that is available in the volume group.
|
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
|
resynchronizing - degrading the performance of the mirror. The
|
||||||
default policy for handling an image failure is "remove". This
|
default policy for handling an image failure is "remove". This
|
||||||
allows the mirror to still function, but gives the administrator the
|
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.
|
the failed image.
|
||||||
|
|
||||||
RAID logical volume device failures are handled differently from the "mirror"
|
RAID logical volume device failures are handled differently from the "mirror"
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ classical snapshot merge, thin snapshot merge.
|
|||||||
|
|
||||||
The second store is suited only for pvmove --abort operations in-progress. Both
|
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)
|
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).
|
guaranteed by lvm2 locking mechanism).
|
||||||
|
|
||||||
Locking order
|
Locking order
|
||||||
|
|||||||
@@ -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
|
This decision could well be contentious, so could distro maintainers feel
|
||||||
free to comment.
|
free to comment.
|
||||||
|
|
||||||
[[!tag legacy]]
|
|
||||||
|
|||||||
@@ -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"]]
|
|
||||||
@@ -1,22 +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 draft pending]]
|
|
||||||
<!--
|
|
||||||
For old releases add Release Timestamp like this, date from git show $COMMIT is fine.
|
|
||||||
\[[!meta date="Tue Nov 21 14:26:07 2023 +0100"]]
|
|
||||||
-->
|
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
# LVM Releases
|
|
||||||
|
|
||||||
This list is incomplete, only releases with a release-note are included.
|
|
||||||
|
|
||||||
For releases of legacy branch *2.02* see [[legacy]].
|
|
||||||
|
|
||||||
Too see what's cooking see [[pending]].
|
|
||||||
|
|
||||||
[[!inline pages="release-notes/2.03.* and !*/template and !*/Discussion and !tagged(draft) and !tagged(pending)" rootpage="release-notes"]]
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# Legacy 2.02 Releases
|
|
||||||
|
|
||||||
This list is incomplete, only releases with a release-note are included.
|
|
||||||
|
|
||||||
For releases of stable branch 2.03 see [[index]].
|
|
||||||
|
|
||||||
[[!inline pages="release-notes/2.02.* and !*/template and !*/Discussion and !tagged(draft) and !tagged(pending)" limit=2 rootpage="release-notes"]]
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# Pending Release
|
|
||||||
|
|
||||||
[[!inline pages="release-notes/* and !*/template and !*/Discussion and tagged(pending)" rootpage="release-notes"]]
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
<!-- Page title -->
|
|
||||||
[[!meta title="Version 2.03. - Feature and Bug Fix Release"]]
|
|
||||||
|
|
||||||
Version 2.03.
|
|
||||||
===============
|
|
||||||
|
|
||||||
* List of important/interesting changes
|
|
||||||
* And [[!toggle text="more"]]
|
|
||||||
|
|
||||||
[[!toggleable text="""
|
|
||||||
Features
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
* List new features worth mentioning here in one line.
|
|
||||||
|
|
||||||
### New Feature Worth a Paragraph or Two
|
|
||||||
|
|
||||||
Write a paragraph or two covering feature where some examples of usage are expected.
|
|
||||||
|
|
||||||
<!--
|
|
||||||
TODO: It would be nice if we could use a real session output, so we could test the examples
|
|
||||||
- During tests, save some outputs
|
|
||||||
-->
|
|
||||||
|
|
||||||
Changes in command line
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
Describe important changes in command line tools, especially any chnages of behavior, which user must be aware of:
|
|
||||||
|
|
||||||
* New options
|
|
||||||
* Removed options
|
|
||||||
* Use a separate page in *./doc* for larger features worth separate article, or a man page
|
|
||||||
|
|
||||||
Changes in lvm.conf
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
* New options.
|
|
||||||
* Change of defaults.
|
|
||||||
|
|
||||||
./configure options
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
* New options and features the enable.
|
|
||||||
|
|
||||||
"""]]
|
|
||||||
|
|
||||||
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
|
|
||||||
[[!tag draft pending]]
|
|
||||||
<!--
|
|
||||||
For old releases add Release Timestamp like this, date from git show $COMMIT is fine.
|
|
||||||
\[[!meta date="Tue Nov 21 14:26:07 2023 +0100"]]
|
|
||||||
-->
|
|
||||||
@@ -126,7 +126,7 @@ Usage Examples
|
|||||||
followed by 'vgchange -ay vg2'
|
followed by 'vgchange -ay vg2'
|
||||||
|
|
||||||
|
|
||||||
Option (ii) - localised admin & configuration
|
Option (ii) - localised admin & configuation
|
||||||
(i.e. each host holds *locally* which classes of volumes to activate)
|
(i.e. each host holds *locally* which classes of volumes to activate)
|
||||||
# Add @database tag to vg1's metadata
|
# Add @database tag to vg1's metadata
|
||||||
vgchange --addtag @database vg1
|
vgchange --addtag @database vg1
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user