mirror of
git://sourceware.org/git/lvm2.git
synced 2025-11-09 04:23:47 +03:00
Compare commits
2 Commits
main
...
dev-mcsont
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bb944fbcd | ||
|
|
d69aadf370 |
42
.gitignore
vendored
42
.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
|
||||||
@@ -31,37 +25,17 @@ make.tmpl
|
|||||||
|
|
||||||
/autom4te.cache/
|
/autom4te.cache/
|
||||||
/autoscan.log
|
/autoscan.log
|
||||||
/build/
|
|
||||||
/config.cache
|
|
||||||
/config.log
|
/config.log
|
||||||
/config.status
|
/config.status
|
||||||
/configure.scan
|
/configure.scan
|
||||||
/cscope.*
|
/cscope.out
|
||||||
/html/
|
|
||||||
/python/
|
|
||||||
/reports/
|
|
||||||
/tags
|
/tags
|
||||||
/tmp/
|
/tmp/
|
||||||
|
|
||||||
coverity/coverity_model.xml
|
|
||||||
|
|
||||||
/.cache/
|
|
||||||
/compile_commands.json
|
|
||||||
|
|
||||||
/doc/.ikiwiki
|
|
||||||
/public
|
|
||||||
|
|
||||||
/libdm/.symver_check
|
|
||||||
|
|
||||||
daemons/clvmd
|
|
||||||
daemons/dmfilemapd
|
|
||||||
daemons/lvmetad/
|
|
||||||
|
|
||||||
tools/man-generator
|
tools/man-generator
|
||||||
|
tools/man-generator.c
|
||||||
|
|
||||||
test/.lib-dir-stamp
|
|
||||||
test/.tests-stamp
|
|
||||||
test/lib/dmsecuretest
|
|
||||||
test/lib/lvchange
|
test/lib/lvchange
|
||||||
test/lib/lvconvert
|
test/lib/lvconvert
|
||||||
test/lib/lvcreate
|
test/lib/lvcreate
|
||||||
@@ -86,7 +60,6 @@ test/lib/pvremove
|
|||||||
test/lib/pvresize
|
test/lib/pvresize
|
||||||
test/lib/pvs
|
test/lib/pvs
|
||||||
test/lib/pvscan
|
test/lib/pvscan
|
||||||
test/lib/securetest
|
|
||||||
test/lib/vgcfgbackup
|
test/lib/vgcfgbackup
|
||||||
test/lib/vgcfgrestore
|
test/lib/vgcfgrestore
|
||||||
test/lib/vgchange
|
test/lib/vgchange
|
||||||
@@ -115,8 +88,6 @@ test/api/thin_percent.t
|
|||||||
test/api/vglist.t
|
test/api/vglist.t
|
||||||
test/api/vgtest.t
|
test/api/vgtest.t
|
||||||
test/lib/aux
|
test/lib/aux
|
||||||
test/lib/cache-mq.profile
|
|
||||||
test/lib/cache-smq.profile
|
|
||||||
test/lib/check
|
test/lib/check
|
||||||
test/lib/clvmd
|
test/lib/clvmd
|
||||||
test/lib/dm-version-expected
|
test/lib/dm-version-expected
|
||||||
@@ -126,7 +97,6 @@ test/lib/dmstats
|
|||||||
test/lib/fail
|
test/lib/fail
|
||||||
test/lib/flavour-ndev-cluster
|
test/lib/flavour-ndev-cluster
|
||||||
test/lib/flavour-ndev-cluster-lvmpolld
|
test/lib/flavour-ndev-cluster-lvmpolld
|
||||||
test/lib/flavour-ndev-devicesfile
|
|
||||||
test/lib/flavour-ndev-lvmetad
|
test/lib/flavour-ndev-lvmetad
|
||||||
test/lib/flavour-ndev-lvmetad-lvmpolld
|
test/lib/flavour-ndev-lvmetad-lvmpolld
|
||||||
test/lib/flavour-ndev-lvmpolld
|
test/lib/flavour-ndev-lvmpolld
|
||||||
@@ -136,7 +106,6 @@ test/lib/flavour-udev-cluster-lvmpolld
|
|||||||
test/lib/flavour-udev-lvmetad
|
test/lib/flavour-udev-lvmetad
|
||||||
test/lib/flavour-udev-lvmetad-lvmpolld
|
test/lib/flavour-udev-lvmetad-lvmpolld
|
||||||
test/lib/flavour-udev-lvmlockd-dlm
|
test/lib/flavour-udev-lvmlockd-dlm
|
||||||
test/lib/flavour-udev-lvmlockd-idm
|
|
||||||
test/lib/flavour-udev-lvmlockd-sanlock
|
test/lib/flavour-udev-lvmlockd-sanlock
|
||||||
test/lib/flavour-udev-lvmlockd-test
|
test/lib/flavour-udev-lvmlockd-test
|
||||||
test/lib/flavour-udev-lvmpolld
|
test/lib/flavour-udev-lvmpolld
|
||||||
@@ -149,13 +118,8 @@ test/lib/lvm
|
|||||||
test/lib/lvm-wrapper
|
test/lib/lvm-wrapper
|
||||||
test/lib/lvmchange
|
test/lib/lvmchange
|
||||||
test/lib/lvmdbusd.profile
|
test/lib/lvmdbusd.profile
|
||||||
test/lib/lvmdevices
|
|
||||||
test/lib/lvmetad
|
test/lib/lvmetad
|
||||||
test/lib/lvmlockctl
|
|
||||||
test/lib/lvmlockd
|
|
||||||
test/lib/lvmpolld
|
test/lib/lvmpolld
|
||||||
test/lib/lvm_import_vdo
|
|
||||||
test/lib/lvm_vdo_wrapper
|
|
||||||
test/lib/not
|
test/lib/not
|
||||||
test/lib/paths
|
test/lib/paths
|
||||||
test/lib/paths-common
|
test/lib/paths-common
|
||||||
@@ -165,7 +129,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
|
||||||
|
|||||||
129
.gitlab-ci.yml
129
.gitlab-ci.yml
@@ -1,129 +0,0 @@
|
|||||||
stages:
|
|
||||||
- approve
|
|
||||||
- test
|
|
||||||
- post
|
|
||||||
|
|
||||||
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
|
|
||||||
when: always
|
|
||||||
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|'))
|
|
||||||
- find test/results -type f -empty -delete
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# reboot must be configured to let runner finish cleanly while not accepting new jobs
|
|
||||||
# NOTE: If this causes warnings, gitlab-runner needs to be configured to be stopped using SIGQUIT
|
|
||||||
# See: https://docs.gitlab.com/runner/commands/#gitlab-runner-stop-doesnt-shut-down-gracefully
|
|
||||||
# NOTE: It should be possible to use after_script in test job, which runs
|
|
||||||
# before artifacts collection, but reboot may be too eager to stop the job
|
|
||||||
# while collecting artifacts
|
|
||||||
# NOTE: What would happen when there are multiple jobs in the queue for each
|
|
||||||
# tag? Could the tests run first and reboot only after them? I think so!
|
|
||||||
reboot:
|
|
||||||
stage: post
|
|
||||||
parallel:
|
|
||||||
matrix:
|
|
||||||
- TAG: rhel8
|
|
||||||
- TAG: rhel9
|
|
||||||
tags:
|
|
||||||
- ${TAG}
|
|
||||||
timeout: 1m
|
|
||||||
script:
|
|
||||||
- reboot
|
|
||||||
allow_failure: true
|
|
||||||
when: always
|
|
||||||
|
|
||||||
104
Makefile.in
104
Makefile.in
@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
|
|||||||
abs_top_builddir = @abs_top_builddir@
|
abs_top_builddir = @abs_top_builddir@
|
||||||
abs_top_srcdir = @abs_top_srcdir@
|
abs_top_srcdir = @abs_top_srcdir@
|
||||||
|
|
||||||
SUBDIRS = libdm conf daemons include lib libdaemon man scripts tools
|
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
|
||||||
|
|
||||||
ifeq ("@UDEV_RULES@", "yes")
|
ifeq ("@UDEV_RULES@", "yes")
|
||||||
SUBDIRS += udev
|
SUBDIRS += udev
|
||||||
@@ -38,29 +38,28 @@ 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
|
||||||
|
|
||||||
include $(top_srcdir)/base/Makefile
|
libdm: include
|
||||||
include $(top_srcdir)/device_mapper/Makefile
|
libdaemon: include
|
||||||
include $(top_srcdir)/test/unit/Makefile
|
lib: libdm libdaemon
|
||||||
|
|
||||||
lib: include libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
|
|
||||||
daemons: lib libdaemon tools
|
daemons: lib libdaemon tools
|
||||||
scripts: lib
|
tools: lib libdaemon device-mapper
|
||||||
tools: lib libdaemon
|
|
||||||
po: tools daemons
|
po: tools daemons
|
||||||
man: tools
|
man: tools
|
||||||
all_man: tools
|
all_man: tools
|
||||||
|
scripts: libdm
|
||||||
test: tools daemons
|
test: tools daemons
|
||||||
unit-test run-unit-test: test libdm
|
|
||||||
|
|
||||||
|
lib.device-mapper: include.device-mapper
|
||||||
|
libdm.device-mapper: include.device-mapper
|
||||||
daemons.device-mapper: libdm.device-mapper
|
daemons.device-mapper: libdm.device-mapper
|
||||||
tools.device-mapper: libdm.device-mapper
|
tools.device-mapper: libdm.device-mapper
|
||||||
|
scripts.device-mapper: include.device-mapper
|
||||||
device-mapper: tools.device-mapper daemons.device-mapper man.device-mapper
|
device-mapper: tools.device-mapper daemons.device-mapper man.device-mapper
|
||||||
device_mapper: device-mapper
|
|
||||||
|
|
||||||
ifeq ("@INTL@", "yes")
|
ifeq ("@INTL@", "yes")
|
||||||
lib.pofile: include.pofile
|
lib.pofile: include.pofile
|
||||||
@@ -76,10 +75,9 @@ daemons.cflow: tools.cflow
|
|||||||
cflow: include.cflow
|
cflow: include.cflow
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CSCOPE_DIRS = base daemons device_mapper include lib libdaemon scripts tools libdm test
|
|
||||||
ifneq ("@CSCOPE_CMD@", "")
|
ifneq ("@CSCOPE_CMD@", "")
|
||||||
cscope.out:
|
cscope.out:
|
||||||
@CSCOPE_CMD@ -b -R $(patsubst %,-s%,$(addprefix $(srcdir)/,$(CSCOPE_DIRS)))
|
@CSCOPE_CMD@ -b -R -s$(top_srcdir)
|
||||||
all: cscope.out
|
all: cscope.out
|
||||||
endif
|
endif
|
||||||
DISTCLEAN_TARGETS += cscope.out
|
DISTCLEAN_TARGETS += cscope.out
|
||||||
@@ -111,12 +109,12 @@ rpm: dist
|
|||||||
$(LN_S) -f $(abs_top_srcdir)/spec/macros.inc $(rpmbuilddir)/SOURCES
|
$(LN_S) -f $(abs_top_srcdir)/spec/macros.inc $(rpmbuilddir)/SOURCES
|
||||||
$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES
|
$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES
|
||||||
DM_VER=$$(cut -d- -f1 $(top_srcdir)/VERSION_DM);\
|
DM_VER=$$(cut -d- -f1 $(top_srcdir)/VERSION_DM);\
|
||||||
GIT_VER=$$(cd $(top_srcdir); git describe | cut -d- --output-delimiter=. -f2,3 || echo 0);\
|
GIT_VER=$$(cd $(top_srcdir); git describe | cut -d- --output-delimiter=. -f2- || echo 0);\
|
||||||
$(SED) -e "s,\(device_mapper_version\) [0-9.]*$$,\1 $$DM_VER," \
|
sed -e "s,\(device_mapper_version\) [0-9.]*$$,\1 $$DM_VER," \
|
||||||
-e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \
|
-e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \
|
||||||
-e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $$GIT_VER," \
|
-e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $$GIT_VER," \
|
||||||
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
|
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
|
||||||
V=$(V) rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
|
rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
|
||||||
|
|
||||||
generate: conf.generate man.generate
|
generate: conf.generate man.generate
|
||||||
$(MAKE) -C conf generate
|
$(MAKE) -C conf generate
|
||||||
@@ -127,14 +125,12 @@ 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)
|
||||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_LOCK_DIR)
|
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_LOCK_DIR)
|
||||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR)
|
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR)
|
||||||
$(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache
|
$(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache
|
||||||
$(INSTALL_ROOT_DIR) $(DESTDIR)/var/lib/lvm
|
|
||||||
|
|
||||||
install_initscripts:
|
install_initscripts:
|
||||||
$(MAKE) -C scripts install_initscripts
|
$(MAKE) -C scripts install_initscripts
|
||||||
@@ -152,34 +148,18 @@ install_all_man:
|
|||||||
install_tmpfiles_configuration:
|
install_tmpfiles_configuration:
|
||||||
$(MAKE) -C scripts install_tmpfiles_configuration
|
$(MAKE) -C scripts install_tmpfiles_configuration
|
||||||
|
|
||||||
help:
|
LCOV_TRACES = libdm.info lib.info tools.info \
|
||||||
@echo -e "\nAvailable targets:"
|
libdaemon/client.info libdaemon/server.info \
|
||||||
@echo " all Default target."
|
test/unit.info \
|
||||||
@echo " all_man Build all man pages with generators."
|
daemons/clvmd.info \
|
||||||
@echo " clean Remove all compile files."
|
daemons/dmeventd.info \
|
||||||
@echo " device-mapper Device mapper part of lvm2."
|
daemons/lvmlockd.info \
|
||||||
@echo " dist Generate distributable file."
|
daemons/lvmpolld.info
|
||||||
@echo " distclean Remove all build files."
|
|
||||||
@echo " generate Generate man pages for sources."
|
CLEAN_TARGETS += $(LCOV_TRACES)
|
||||||
@echo " help Display callable targets."
|
|
||||||
@echo " install Install all files."
|
|
||||||
@echo " install_all_man Install all man pages."
|
|
||||||
@echo " install_cluster Install cmirrord."
|
|
||||||
@echo " install_device-mapper Install device mapper files."
|
|
||||||
@echo " install_initscripts Install initialization scripts."
|
|
||||||
@echo " install_lvm2 Install lvm2 files."
|
|
||||||
@echo " install_systemd_units Install systemd units."
|
|
||||||
@echo " lcov Generate lcov output."
|
|
||||||
@echo " lcov-dated Generate lcov with timedate suffix."
|
|
||||||
@echo " lcov-reset Reset lcov counters"
|
|
||||||
@echo " man Build man pages."
|
|
||||||
@echo " print-VARIABLE Resolve make variable."
|
|
||||||
@echo " rpm Build rpm."
|
|
||||||
@echo " run-unit-test Run unit tests."
|
|
||||||
@echo " tags Generate c/etags."
|
|
||||||
|
|
||||||
ifneq ("$(LCOV)", "")
|
ifneq ("$(LCOV)", "")
|
||||||
.PHONY: lcov-reset lcov lcov-dated
|
.PHONY: lcov-reset lcov lcov-dated $(LCOV_TRACES)
|
||||||
|
|
||||||
ifeq ($(MAKECMDGOALS),lcov-dated)
|
ifeq ($(MAKECMDGOALS),lcov-dated)
|
||||||
LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S)
|
LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S)
|
||||||
@@ -189,27 +169,39 @@ LCOV_REPORTS_DIR := lcov_reports
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
lcov-reset:
|
lcov-reset:
|
||||||
$(LCOV) --zerocounters --directory $(top_builddir)
|
$(LCOV) --zerocounters $(addprefix -d , $(basename $(LCOV_TRACES)))
|
||||||
|
|
||||||
|
# maybe use subdirs processing to create tracefiles...
|
||||||
|
$(LCOV_TRACES):
|
||||||
|
$(LCOV) -b $(basename $@) -d $(basename $@) \
|
||||||
|
--ignore-errors source -c -o - | $(SED) \
|
||||||
|
-e "s/\(dmeventd_lvm.[ch]\)/plugins\/lvm2\/\1/" \
|
||||||
|
-e "s/dmeventd_\(mirror\|snapshot\|thin\|raid\)\.c/plugins\/\1\/dmeventd_\1\.c/" \
|
||||||
|
>$@
|
||||||
|
|
||||||
ifneq ("$(GENHTML)", "")
|
ifneq ("$(GENHTML)", "")
|
||||||
lcov:
|
lcov: $(LCOV_TRACES)
|
||||||
$(RM) -rf $(LCOV_REPORTS_DIR)
|
$(RM) -r $(LCOV_REPORTS_DIR)
|
||||||
$(MKDIR_P) $(LCOV_REPORTS_DIR)
|
$(MKDIR_P) $(LCOV_REPORTS_DIR)
|
||||||
-find . -name '*.gc[dn][ao]' ! -newer make.tmpl -delete
|
for i in $(LCOV_TRACES); do \
|
||||||
-$(LCOV) --capture --directory $(top_builddir) --ignore-errors source,negative,gcov \
|
test -s $$i -a $$(wc -w <$$i) -ge 100 && lc="$$lc $$i"; \
|
||||||
--output-file $(LCOV_REPORTS_DIR)/out.info
|
done; \
|
||||||
-test ! -s $(LCOV_REPORTS_DIR)/out.info || \
|
test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \
|
||||||
$(GENHTML) -o $(LCOV_REPORTS_DIR) --ignore-errors source \
|
-o $(LCOV_REPORTS_DIR) $$lc
|
||||||
$(LCOV_REPORTS_DIR)/out.info
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(shell which ctags 2>/dev/null),)
|
# FIXME: Drop once top-level make is resolved
|
||||||
|
-include test/unit/Makefile
|
||||||
|
include $(top_srcdir)/device_mapper/Makefile
|
||||||
|
include $(top_srcdir)/base/Makefile
|
||||||
|
|
||||||
|
ifneq ($(shell which ctags),)
|
||||||
.PHONY: tags
|
.PHONY: tags
|
||||||
tags:
|
tags:
|
||||||
test -z "$(shell find $(addprefix $(top_srcdir)/,$(CSCOPE_DIRS)) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
||||||
test -f tags || find $(addprefix $(top_srcdir)/,$(CSCOPE_DIRS)) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
test -f tags || find $(top_srcdir) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||||
|
|
||||||
CLEAN_TARGETS += tags
|
CLEAN_TARGETS += tags
|
||||||
endif
|
endif
|
||||||
|
|||||||
35
README
35
README
@@ -7,33 +7,24 @@ There is no warranty - see COPYING and COPYING.LIB.
|
|||||||
|
|
||||||
Tarballs are available from:
|
Tarballs are available from:
|
||||||
ftp://sourceware.org/pub/lvm2/
|
ftp://sourceware.org/pub/lvm2/
|
||||||
|
ftp://sources.redhat.com/pub/lvm2/
|
||||||
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,12 +40,8 @@ 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 here:
|
||||||
|
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2.
|
||||||
|
|
||||||
cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 login cvs
|
|
||||||
cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 checkout LVM2
|
|
||||||
|
|
||||||
The password is 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.211-git (2025-10-24)
|
1.02.147-git (2018-05-24)
|
||||||
|
|||||||
231
WHATS_NEW_DM
231
WHATS_NEW_DM
@@ -1,202 +1,13 @@
|
|||||||
Version 1.02.211 -
|
Version 1.02.147 -
|
||||||
===================
|
|
||||||
Dmeventd starts to use mutex per thread.
|
|
||||||
Consolidate dmsetup stats display functions using helper macros.
|
|
||||||
Refactor dmsetup _process_tree_options to use bsearch.
|
|
||||||
|
|
||||||
Version 1.02.210 - 24th October 2025
|
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
Version 1.02.209 - 09th September 2025
|
|
||||||
======================================
|
|
||||||
|
|
||||||
Version 1.02.208 - 30th July 2025
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Version 1.02.207 - 27th June 2025
|
|
||||||
=================================
|
|
||||||
Escape the escape character itself on JSON report format output.
|
|
||||||
Fail dm_report_group_create if radix char from locale unsuitable for JSON_STD.
|
|
||||||
|
|
||||||
Version 1.02.206 - 05th May 2025
|
|
||||||
================================
|
|
||||||
Add support for using regex in selection criteria for string lists.
|
|
||||||
Fix string list selection when using [<item> || <item> ...].
|
|
||||||
|
|
||||||
Version 1.02.205 - 27th February 2025
|
|
||||||
=====================================
|
|
||||||
Restore missing symbol dm_tree_node_size_changed@Base (1.02.175).
|
|
||||||
Restore missing symbol dm_bitset_parse_list@@DM_1_02_138 (1.02.175).
|
|
||||||
|
|
||||||
Version 1.02.204 - 14th January 2025
|
|
||||||
====================================
|
|
||||||
Create /dev/disk/by-diskseq/<DISKSEQ> symlink for public DM devices.
|
|
||||||
|
|
||||||
Version 1.02.203 - 09th December 2024
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
Version 1.02.202 - 04th November 2024
|
|
||||||
=====================================
|
|
||||||
Introduce dm_config_parse_only_section to stop parsing after section.
|
|
||||||
For shorter string use on stack buffers when generating sections.
|
|
||||||
Enhance dm_config tokenizer.
|
|
||||||
|
|
||||||
Version 1.02.201 - 02nd October 2024
|
|
||||||
====================================
|
|
||||||
Cleanup udev sync semaphore if dm_{udev_create,task_set}_cookie fails.
|
|
||||||
Improve error messages on failed udev cookie create/inc/dec operation.
|
|
||||||
|
|
||||||
Version 1.02.200 - 23rd August 2024
|
|
||||||
===================================
|
|
||||||
|
|
||||||
Version 1.02.199 - 12nd July 2024
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Version 1.02.198 - 16th May 2024
|
|
||||||
================================
|
|
||||||
Fix static only compilation of libdevmapper.a and dmsetup tool.
|
|
||||||
Use better code for closing opened descriptors when starting dmeventd.
|
|
||||||
Correct dmeventd -R for systemd environment.
|
|
||||||
Restart of dmeventd -R checks pid file to detect running dmeventd first.
|
|
||||||
Query with dmeventd -i quickly ends when there is no running dmeventd.
|
|
||||||
Enhance dm_get_status_raid to handle mismatching status or reported legs.
|
|
||||||
Create /dev/disk/by-label symlinks for DM devs that have crypto as next layer.
|
|
||||||
Persist udev db for DM devs on cleanup used in initrd to rootfs transition.
|
|
||||||
Process synthetic udev events other than 'add/change' as 'change' events.
|
|
||||||
Increase DM_UDEV_RULES_VSN to 3 to indicate changed udev rules.
|
|
||||||
Rename DM_NOSCAN to .DM_NOSCAN so it's not stored in udev db.
|
|
||||||
Rename DM_SUSPENDED to .DM_SUSPENDED so it's not stored in udev db.
|
|
||||||
Do not import DM_UDEV_DISABLE_OTHER_RULES_FLAG from db in 10-dm-disk.rules.
|
|
||||||
Test DISK_RO after importing properties from db in 10-dm.rules.
|
|
||||||
Also import ID_FS_TYPE in 13-dm-disk.rules from db if needed.
|
|
||||||
|
|
||||||
Version 1.02.197 - 21st November 2023
|
|
||||||
=====================================
|
|
||||||
Fix invalid JSON report if using DM_REPORT_OUTPUT_MULTIPLE_TIMES and selection.
|
|
||||||
Propagate ioctl errno from dm_task_run when creating new table line.
|
|
||||||
Add support for group aliases in dmstats.
|
|
||||||
Add support for exit-on file for dmeventd to reduce shutdown delays.
|
|
||||||
Add configure option --with-dmeventd-exit-on-path to specify default path.
|
|
||||||
Add dmsetup --headings none|abbrev|full to set report headings type.
|
|
||||||
Add DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS to provide alternative headings.
|
|
||||||
|
|
||||||
Version 1.02.196 - 02nd August 2023
|
|
||||||
===================================
|
|
||||||
|
|
||||||
Version 1.02.195 - 21st April 2023
|
|
||||||
==================================
|
|
||||||
|
|
||||||
Version 1.02.193 - 21st March 2023
|
|
||||||
==================================
|
|
||||||
|
|
||||||
Version 1.02.191 - 21st February 2023
|
|
||||||
=====================================
|
|
||||||
Improve parallel creation of /dev/mapper/control device node.
|
|
||||||
Import previous ID_FS_* udev records in 13-dm-disk.rules for suspended DM dev.
|
|
||||||
Remove NAME="mapper/control" rule from 10-dm.rules to avoid udev warnings.
|
|
||||||
|
|
||||||
Version 1.02.189 - 22nd December 2022
|
|
||||||
=====================================
|
|
||||||
Improve 'dmsetup create' without given table line with new kernels.
|
|
||||||
|
|
||||||
Version 1.02.187 - 10th November 2022
|
|
||||||
=====================================
|
|
||||||
Add DM_REPORT_GROUP_JSON_STD for more JSON standard compliant output format.
|
|
||||||
|
|
||||||
Version 1.02.185 - 18th May 2022
|
|
||||||
================================
|
|
||||||
|
|
||||||
Version 1.02.183 - 07th February 2022
|
|
||||||
=====================================
|
|
||||||
Unmangle UUIDs for DM_DEVICE_LIST ioctl.
|
|
||||||
|
|
||||||
Version 1.02.181 - 20th October 2021
|
|
||||||
====================================
|
|
||||||
Add IMA support with 'dmsetup measure' command.
|
|
||||||
Add defines DM_NAME_LIST_FLAG_HAS_UUID, DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID.
|
|
||||||
Enhance tracking of activated devices when preloading dm tree.
|
|
||||||
Fix bug in construction of cache table line (regression from 1.02.159).
|
|
||||||
|
|
||||||
Version 1.02.179 - 11th August 2021
|
|
||||||
===================================
|
|
||||||
|
|
||||||
Version 1.02.177 - 07th May 2021
|
|
||||||
================================
|
|
||||||
Configure proceeds without libaio to allow build of device-mapper only.
|
|
||||||
Fix symbol versioning build with -O2 -flto.
|
|
||||||
Add dm_tree_node_add_thin_pool_target_v1 with crop_metadata support.
|
|
||||||
|
|
||||||
Version 1.02.175 - 08th January 2021
|
|
||||||
====================================
|
|
||||||
|
|
||||||
Version 1.02.173 - 09th August 2020
|
|
||||||
===================================
|
|
||||||
Add support for VDO in blkdeactivate script.
|
|
||||||
|
|
||||||
Version 1.02.171 - 26th March 2020
|
|
||||||
==================================
|
|
||||||
Try to remove all created devices on dm preload tree error path.
|
|
||||||
Fix dm_list iterators with gcc 10 optimization (-ftree-pta).
|
|
||||||
Dmeventd handles timer without looping on short intervals.
|
|
||||||
|
|
||||||
Version 1.02.169 - 11th February 2020
|
|
||||||
=====================================
|
|
||||||
Enhance error messages for device creation.
|
|
||||||
|
|
||||||
Version 1.02.167 - 30th November 2019
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
Version 1.02.165 - 23rd October 2019
|
|
||||||
====================================
|
|
||||||
Add support for DM_DEVICE_GET_TARGET_VERSION.
|
|
||||||
Add debug of dmsetup udevcomplete with hexa print DM_COOKIE_COMPLETED.
|
|
||||||
Fix versioning of dm_stats_create_region and dm_stats_create_region.
|
|
||||||
|
|
||||||
Version 1.02.163 - 15th June 2019
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Version 1.02.161 - 10th June 2019
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Version 1.02.159 - 07th June 2019
|
|
||||||
=================================
|
|
||||||
Parsing of cache status understand no_discard_passdown.
|
|
||||||
Ensure migration_threshold for cache is at least 8 chunks.
|
|
||||||
|
|
||||||
Version 1.02.155 - 18th December 2018
|
|
||||||
=====================================
|
|
||||||
Include correct internal header inside libdm list.c.
|
|
||||||
Enhance ioctl flattening and add parameters only when needed.
|
|
||||||
Add DM_DEVICE_ARM_POLL for API completeness matching kernel.
|
|
||||||
Do not add parameters for RESUME with DM_DEVICE_CREATE dm task.
|
|
||||||
Fix dmstats report printing no output.
|
|
||||||
|
|
||||||
Version 1.02.153 - 31st October 2018
|
|
||||||
====================================
|
|
||||||
|
|
||||||
Version 1.02.151 - 10th October 2018
|
|
||||||
====================================
|
|
||||||
Add hot fix to avoiding locking collision when monitoring thin-pools.
|
|
||||||
|
|
||||||
Version 1.02.150 - 01 August 2018
|
|
||||||
=================================
|
|
||||||
Add vdo plugin for monitoring VDO devices.
|
Add vdo plugin for monitoring VDO devices.
|
||||||
|
|
||||||
Version 1.02.149 - 19th July 2018
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Version 1.02.148 - 18th June 2018
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Version 1.02.147 - 13th June 2018
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Version 1.02.147-rc1 - 24th May 2018
|
Version 1.02.147-rc1 - 24th May 2018
|
||||||
====================================
|
====================================
|
||||||
Reuse uname() result for mirror target.
|
Reuse uname() result for mirror target.
|
||||||
Recognize also mounted btrfs through dm_device_has_mounted_fs().
|
Recognize also mounted btrfs through dm_device_has_mounted_fs().
|
||||||
Add missing log_error() into dm_stats_populate() returning 0.
|
Add missing log_error() into dm_stats_populate() returning 0.
|
||||||
Avoid calling dm_stats_populate() for DM devices without any stats regions.
|
Avoid calling dm_stats_populat() for DM devices without any stats regions.
|
||||||
Support DM_DEBUG_WITH_LINE_NUMBERS envvar for debug msg with source:line.
|
Support DM_DEBUG_WITH_LINE_NUMBERS envvar for debug msg with source:line.
|
||||||
Configured command for thin pool threshold handling gets whole environment.
|
Configured command for thin pool threshold handling gets whole environment.
|
||||||
Fix tests for failing dm_snprintf() in stats code.
|
Fix tests for failing dm_snprintf() in stats code.
|
||||||
@@ -245,7 +56,7 @@ Version 1.02.141 - 28th June 2017
|
|||||||
Add dm_percent_to_round_float for adjusted percentage rounding.
|
Add dm_percent_to_round_float for adjusted percentage rounding.
|
||||||
Reset array with dead rimage devices once raid gets in sync.
|
Reset array with dead rimage devices once raid gets in sync.
|
||||||
Drop unneeded --config option from raid dmeventd plugin.
|
Drop unneeded --config option from raid dmeventd plugin.
|
||||||
dm_get_status_raid() handle better some inconsistent md statuses.
|
dm_get_status_raid() handle better some incosistent md statuses.
|
||||||
Accept truncated files in calls to dm_stats_update_regions_from_fd().
|
Accept truncated files in calls to dm_stats_update_regions_from_fd().
|
||||||
Restore Warning by 5% increment when thin-pool is over 80% (1.02.138).
|
Restore Warning by 5% increment when thin-pool is over 80% (1.02.138).
|
||||||
|
|
||||||
@@ -300,7 +111,7 @@ Version 1.02.136 - 5th November 2016
|
|||||||
Still produce output when dmsetup dependency tree building finds dev missing.
|
Still produce output when dmsetup dependency tree building finds dev missing.
|
||||||
Check and report pthread_sigmask() failure in dmeventd.
|
Check and report pthread_sigmask() failure in dmeventd.
|
||||||
Check mem alloc fail in _canonicalize_field_ids().
|
Check mem alloc fail in _canonicalize_field_ids().
|
||||||
Use unsigned math when checking more than 31 legs of raid.
|
Use unsigned math when checking more then 31 legs of raid.
|
||||||
Fix 'dmstats delete' with dmsetup older than v1.02.129
|
Fix 'dmstats delete' with dmsetup older than v1.02.129
|
||||||
Fix stats walk segfault with dmsetup older than v1.02.129
|
Fix stats walk segfault with dmsetup older than v1.02.129
|
||||||
|
|
||||||
@@ -440,7 +251,7 @@ Version 1.02.112 - 28th November 2015
|
|||||||
=====================================
|
=====================================
|
||||||
Show error message when trying to create unsupported raid type.
|
Show error message when trying to create unsupported raid type.
|
||||||
Improve preloading sequence of an active thin-pool target.
|
Improve preloading sequence of an active thin-pool target.
|
||||||
Drop extra space from cache target line to fix unneeded table reloads.
|
Drop extra space from cache target line to fix unneded table reloads.
|
||||||
|
|
||||||
Version 1.02.111 - 23rd November 2015
|
Version 1.02.111 - 23rd November 2015
|
||||||
=====================================
|
=====================================
|
||||||
@@ -455,7 +266,7 @@ Version 1.02.110 - 30th October 2015
|
|||||||
Disable thin monitoring plugin when it fails too often (>10 times).
|
Disable thin monitoring plugin when it fails too often (>10 times).
|
||||||
Fix/restore parsing of empty field '-' when processing dmeventd event.
|
Fix/restore parsing of empty field '-' when processing dmeventd event.
|
||||||
Enhance dm_tree_node_size_changed() to recognize size reduction.
|
Enhance dm_tree_node_size_changed() to recognize size reduction.
|
||||||
Support exit on idle for dmeventd (1 hour).
|
Support exit on idle for dmenventd (1 hour).
|
||||||
Add support to allow unmonitor device from plugin itself.
|
Add support to allow unmonitor device from plugin itself.
|
||||||
New design for thread co-operation in dmeventd.
|
New design for thread co-operation in dmeventd.
|
||||||
Dmeventd read device status with 'noflush'.
|
Dmeventd read device status with 'noflush'.
|
||||||
@@ -628,7 +439,7 @@ Version 1.02.93 - 21st January 2015
|
|||||||
Version 1.02.92 - 24th November 2014
|
Version 1.02.92 - 24th November 2014
|
||||||
====================================
|
====================================
|
||||||
Fix memory corruption with sorting empty string lists (1.02.86).
|
Fix memory corruption with sorting empty string lists (1.02.86).
|
||||||
Fix man dmsetup.8 syntax warning of Groff.
|
Fix man dmsetup.8 syntax warning of Groff
|
||||||
Accept unquoted strings and / in place of {} when parsing configs.
|
Accept unquoted strings and / in place of {} when parsing configs.
|
||||||
|
|
||||||
Version 1.02.91 - 11th November 2014
|
Version 1.02.91 - 11th November 2014
|
||||||
@@ -647,7 +458,7 @@ Version 1.02.90 - 1st September 2014
|
|||||||
Version 1.02.89 - 26th August 2014
|
Version 1.02.89 - 26th August 2014
|
||||||
==================================
|
==================================
|
||||||
Improve libdevmapper-event select() error handling.
|
Improve libdevmapper-event select() error handling.
|
||||||
Add extra check for matching transaction_id after message submitting.
|
Add extra check for matching transation_id after message submitting.
|
||||||
Add dm_report_field_string_list_unsorted for str. list report without sorting.
|
Add dm_report_field_string_list_unsorted for str. list report without sorting.
|
||||||
Support --deferred with dmsetup remove to defer removal of open devices.
|
Support --deferred with dmsetup remove to defer removal of open devices.
|
||||||
Update dm-ioctl.h to include DM_DEFERRED_REMOVE flag.
|
Update dm-ioctl.h to include DM_DEFERRED_REMOVE flag.
|
||||||
@@ -679,7 +490,7 @@ Version 1.02.86 - 23rd June 2014
|
|||||||
Add DM_REPORT_FIELD_TYPE_STRING_LIST: separate string and string list fields.
|
Add DM_REPORT_FIELD_TYPE_STRING_LIST: separate string and string list fields.
|
||||||
Add dm_str_list to libdevmapper for string list type definition and its reuse.
|
Add dm_str_list to libdevmapper for string list type definition and its reuse.
|
||||||
Add dmsetup -S/--select to define selection criteria for dmsetup reports.
|
Add dmsetup -S/--select to define selection criteria for dmsetup reports.
|
||||||
Add dm_report_init_with_selection to initialize report with selection criteria.
|
Add dm_report_init_with_selection to intialize report with selection criteria.
|
||||||
Add DM_REPORT_FIELD_TYPE_SIZE: separate number and size reporting fields.
|
Add DM_REPORT_FIELD_TYPE_SIZE: separate number and size reporting fields.
|
||||||
Use RemoveOnStop for dm-event.socket systemd unit.
|
Use RemoveOnStop for dm-event.socket systemd unit.
|
||||||
Document env var 'DM_DEFAULT_NAME_MANGLING_MODE' in dmsetup man page.
|
Document env var 'DM_DEFAULT_NAME_MANGLING_MODE' in dmsetup man page.
|
||||||
@@ -734,7 +545,7 @@ Version 1.02.82 - 4th October 2013
|
|||||||
|
|
||||||
Version 1.02.81 - 23rd September 2013
|
Version 1.02.81 - 23rd September 2013
|
||||||
=====================================
|
=====================================
|
||||||
Tidy dmeventd fifo initialization.
|
Tidy dmeventd fifo initialisation.
|
||||||
|
|
||||||
Version 1.02.80 - 20th September 2013
|
Version 1.02.80 - 20th September 2013
|
||||||
=====================================
|
=====================================
|
||||||
@@ -759,7 +570,7 @@ Version 1.02.78 - 24th July 2013
|
|||||||
Always return success on dmeventd -V command call.
|
Always return success on dmeventd -V command call.
|
||||||
Fix parsing of 64bit snapshot status in dmeventd snapshot plugin.
|
Fix parsing of 64bit snapshot status in dmeventd snapshot plugin.
|
||||||
Add dm_get_status_snapshot() for parsing snapshot status.
|
Add dm_get_status_snapshot() for parsing snapshot status.
|
||||||
Detect mounted fs also via reading /proc/self/mountinfo.
|
Detecte mounted fs also via reading /proc/self/mountinfo.
|
||||||
Add dm_mountinfo_read() for parsing /proc/self/mountinfo.
|
Add dm_mountinfo_read() for parsing /proc/self/mountinfo.
|
||||||
Report error for nonexisting devices in dmeventd communication.
|
Report error for nonexisting devices in dmeventd communication.
|
||||||
Prevent double free error after dmeventd call of _fill_device_data().
|
Prevent double free error after dmeventd call of _fill_device_data().
|
||||||
@@ -856,7 +667,7 @@ Version 1.02.71 - 20th February 2012
|
|||||||
Add "watch" rule to 13-dm-disk.rules.
|
Add "watch" rule to 13-dm-disk.rules.
|
||||||
Detect failing fifo and skip 20s retry communication period.
|
Detect failing fifo and skip 20s retry communication period.
|
||||||
Add DM_DEFAULT_NAME_MANGLING_MODE environment variable as an override.
|
Add DM_DEFAULT_NAME_MANGLING_MODE environment variable as an override.
|
||||||
Add dm_lib_init to automatically initialize device-mapper library on load.
|
Add dm_lib_init to automatically initialise device-mapper library on load.
|
||||||
Replace any '\' char with '\\' in dm table specification on input.
|
Replace any '\' char with '\\' in dm table specification on input.
|
||||||
Add mangle command to dmsetup to provide renaming to correct mangled form.
|
Add mangle command to dmsetup to provide renaming to correct mangled form.
|
||||||
Add 'mangled_name' and 'unmangled_name' fields to dmsetup info -c -o.
|
Add 'mangled_name' and 'unmangled_name' fields to dmsetup info -c -o.
|
||||||
@@ -950,7 +761,7 @@ Version 1.02.66 - 12th August 2011
|
|||||||
Fix memory leak in dmsetup _message() memory allocation error path.
|
Fix memory leak in dmsetup _message() memory allocation error path.
|
||||||
Use new oom killer adjustment interface (oom_score_adj) when available.
|
Use new oom killer adjustment interface (oom_score_adj) when available.
|
||||||
Add systemd unit files for dmeventd.
|
Add systemd unit files for dmeventd.
|
||||||
Fix read-only identical table reload suppression.
|
Fix read-only identical table reload supression.
|
||||||
|
|
||||||
Version 1.02.65 - 8th July 2011
|
Version 1.02.65 - 8th July 2011
|
||||||
===============================
|
===============================
|
||||||
@@ -965,7 +776,7 @@ Version 1.02.65 - 8th July 2011
|
|||||||
Add dm_get_suspended_counter() for number of devs in suspended state by lib.
|
Add dm_get_suspended_counter() for number of devs in suspended state by lib.
|
||||||
Fix "all" report field prefix matching to include label fields with pv_all.
|
Fix "all" report field prefix matching to include label fields with pv_all.
|
||||||
Delay resuming new preloaded mirror devices with core logs in deptree code.
|
Delay resuming new preloaded mirror devices with core logs in deptree code.
|
||||||
Accept new kernel version 3 uname formats in initialization.
|
Accept new kernel version 3 uname formats in initialisation.
|
||||||
|
|
||||||
Version 1.02.64 - 29th April 2011
|
Version 1.02.64 - 29th April 2011
|
||||||
==================================
|
==================================
|
||||||
@@ -979,7 +790,7 @@ Version 1.02.64 - 29th April 2011
|
|||||||
Improve stack debug reporting in dm_task_create().
|
Improve stack debug reporting in dm_task_create().
|
||||||
Fallback to control node creation only if node doesn't exist yet.
|
Fallback to control node creation only if node doesn't exist yet.
|
||||||
Change dm_hash binary functions to take void *key instead of char *.
|
Change dm_hash binary functions to take void *key instead of char *.
|
||||||
Fix uninitialized memory use with empty params in _reload_with_suppression_v4.
|
Fix uninitialised memory use with empty params in _reload_with_suppression_v4.
|
||||||
Lower severity of selabel_lookup and matchpathcon failure to log_debug.
|
Lower severity of selabel_lookup and matchpathcon failure to log_debug.
|
||||||
Add test for failed allocation from dm_task_set_uuid() in dmeventd.
|
Add test for failed allocation from dm_task_set_uuid() in dmeventd.
|
||||||
Add dm_event_get_version to dmeventd for use with -R.
|
Add dm_event_get_version to dmeventd for use with -R.
|
||||||
@@ -1148,7 +959,7 @@ Version 1.02.44 - 15th February 2010
|
|||||||
|
|
||||||
Version 1.02.43 - 21st January 2010
|
Version 1.02.43 - 21st January 2010
|
||||||
===================================
|
===================================
|
||||||
Remove bitset, hash and pool headers superseded by libdevmapper.h.
|
Remove bitset, hash and pool headers superceded by libdevmapper.h.
|
||||||
Fix off-by-one error causing bad cluster mirror table construction.
|
Fix off-by-one error causing bad cluster mirror table construction.
|
||||||
|
|
||||||
Version 1.02.42 - 14th January 2010
|
Version 1.02.42 - 14th January 2010
|
||||||
@@ -1204,7 +1015,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
|
||||||
================================
|
================================
|
||||||
@@ -1272,7 +1083,7 @@ Version 1.02.27 - 25th June 2008
|
|||||||
|
|
||||||
Version 1.02.26 - 6th June 2008
|
Version 1.02.26 - 6th June 2008
|
||||||
===============================
|
===============================
|
||||||
Initialize params buffer to empty string in _emit_segment.
|
Initialise params buffer to empty string in _emit_segment.
|
||||||
Skip add_dev_node when ioctls disabled.
|
Skip add_dev_node when ioctls disabled.
|
||||||
Make dm_hash_iter safe against deletion.
|
Make dm_hash_iter safe against deletion.
|
||||||
Accept a NULL pointer to dm_free silently.
|
Accept a NULL pointer to dm_free silently.
|
||||||
@@ -1328,7 +1139,7 @@ Version 1.02.20 - 15th June 2007
|
|||||||
|
|
||||||
Version 1.02.19 - 27th April 2007
|
Version 1.02.19 - 27th April 2007
|
||||||
=================================
|
=================================
|
||||||
Standardize protective include file #defines.
|
Standardise protective include file #defines.
|
||||||
Add regex functions to library.
|
Add regex functions to library.
|
||||||
Avoid trailing separator in reports when there are hidden sort fields.
|
Avoid trailing separator in reports when there are hidden sort fields.
|
||||||
Fix segfault in 'dmsetup status' without --showkeys against crypt target.
|
Fix segfault in 'dmsetup status' without --showkeys against crypt target.
|
||||||
@@ -1359,7 +1170,7 @@ Version 1.02.16 - 25th January 2007
|
|||||||
Streamline dm_report_field_* interface.
|
Streamline dm_report_field_* interface.
|
||||||
Add cmdline debug & version options to dmeventd.
|
Add cmdline debug & version options to dmeventd.
|
||||||
Add DM_LIB_VERSION definition to configure.h.
|
Add DM_LIB_VERSION definition to configure.h.
|
||||||
Suppress 'Unrecognized field' error if report field is 'help'.
|
Suppress 'Unrecognised field' error if report field is 'help'.
|
||||||
Add --separator and --sort to dmsetup (unused).
|
Add --separator and --sort to dmsetup (unused).
|
||||||
Make alignment flag optional when specifying report fields.
|
Make alignment flag optional when specifying report fields.
|
||||||
|
|
||||||
@@ -1607,5 +1418,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
|
||||||
# ===========================================================================
|
# ===========================================================================
|
||||||
|
|||||||
265
aclocal.m4
vendored
265
aclocal.m4
vendored
@@ -1,6 +1,6 @@
|
|||||||
# generated automatically by aclocal 1.18.1 -*- Autoconf -*-
|
# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
|
||||||
|
|
||||||
# Copyright (C) 1996-2025 Free Software Foundation, Inc.
|
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
||||||
|
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
@@ -69,8 +69,8 @@ AC_DEFUN([AX_PYTHON_MODULE],[
|
|||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*-
|
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||||
# serial 12 (pkg-config-0.29.2)
|
# serial 11 (pkg-config-0.29.1)
|
||||||
|
|
||||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
||||||
@@ -112,13 +112,13 @@ dnl
|
|||||||
dnl See the "Since" comment for each macro you use to see what version
|
dnl See the "Since" comment for each macro you use to see what version
|
||||||
dnl of the macros you require.
|
dnl of the macros you require.
|
||||||
m4_defun([PKG_PREREQ],
|
m4_defun([PKG_PREREQ],
|
||||||
[m4_define([PKG_MACROS_VERSION], [0.29.2])
|
[m4_define([PKG_MACROS_VERSION], [0.29.1])
|
||||||
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
|
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
|
||||||
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
|
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
|
||||||
])dnl PKG_PREREQ
|
])dnl PKG_PREREQ
|
||||||
|
|
||||||
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION], [ACTION-IF-NOT-FOUND])
|
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||||
dnl ---------------------------------------------------------
|
dnl ----------------------------------
|
||||||
dnl Since: 0.16
|
dnl Since: 0.16
|
||||||
dnl
|
dnl
|
||||||
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
|
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
|
||||||
@@ -126,12 +126,6 @@ dnl first found in the path. Checks that the version of pkg-config found
|
|||||||
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
|
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
|
||||||
dnl used since that's the first version where most current features of
|
dnl used since that's the first version where most current features of
|
||||||
dnl pkg-config existed.
|
dnl pkg-config existed.
|
||||||
dnl
|
|
||||||
dnl If pkg-config is not found or older than specified, it will result
|
|
||||||
dnl in an empty PKG_CONFIG variable. To avoid widespread issues with
|
|
||||||
dnl scripts not checking it, ACTION-IF-NOT-FOUND defaults to aborting.
|
|
||||||
dnl You can specify [PKG_CONFIG=false] as an action instead, which would
|
|
||||||
dnl result in pkg-config tests failing, but no bogus error messages.
|
|
||||||
AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||||||
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
|
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
|
||||||
@@ -152,9 +146,6 @@ if test -n "$PKG_CONFIG"; then
|
|||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
PKG_CONFIG=""
|
PKG_CONFIG=""
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
if test -z "$PKG_CONFIG"; then
|
|
||||||
m4_default([$2], [AC_MSG_ERROR([pkg-config not found])])
|
|
||||||
fi[]dnl
|
fi[]dnl
|
||||||
])dnl PKG_PROG_PKG_CONFIG
|
])dnl PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
@@ -166,7 +157,7 @@ dnl Check to see whether a particular set of modules exists. Similar to
|
|||||||
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
|
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||||
dnl
|
dnl
|
||||||
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||||
dnl only at the first occurrence in configure.ac, so if the first place
|
dnl only at the first occurence in configure.ac, so if the first place
|
||||||
dnl it's called might be skipped (such as if it is within an "if", you
|
dnl it's called might be skipped (such as if it is within an "if", you
|
||||||
dnl have to call PKG_CHECK_EXISTS manually
|
dnl have to call PKG_CHECK_EXISTS manually
|
||||||
AC_DEFUN([PKG_CHECK_EXISTS],
|
AC_DEFUN([PKG_CHECK_EXISTS],
|
||||||
@@ -222,7 +213,7 @@ AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
|||||||
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
|
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
|
||||||
|
|
||||||
pkg_failed=no
|
pkg_failed=no
|
||||||
AC_MSG_CHECKING([for $2])
|
AC_MSG_CHECKING([for $1])
|
||||||
|
|
||||||
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
||||||
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
||||||
@@ -422,7 +413,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
|
|||||||
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
|
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
|
||||||
])dnl PKG_HAVE_DEFINE_WITH_MODULES
|
])dnl PKG_HAVE_DEFINE_WITH_MODULES
|
||||||
|
|
||||||
# Copyright (C) 1999-2025 Free Software Foundation, Inc.
|
# Copyright (C) 1999-2017 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
@@ -455,15 +446,10 @@ AC_DEFUN([AM_PATH_PYTHON],
|
|||||||
[
|
[
|
||||||
dnl Find a Python interpreter. Python versions prior to 2.0 are not
|
dnl Find a Python interpreter. Python versions prior to 2.0 are not
|
||||||
dnl supported. (2.0 was released on October 16, 2000).
|
dnl supported. (2.0 was released on October 16, 2000).
|
||||||
|
dnl FIXME: Remove the need to hard-code Python versions here.
|
||||||
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
|
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
|
||||||
[python python3 dnl
|
[python python2 python3 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
|
||||||
python3.20 python3.19 python3.18 python3.17 python3.16 dnl
|
python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0])
|
||||||
python3.15 python3.14 python3.13 python3.12 python3.11 python3.10 dnl
|
|
||||||
python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 dnl
|
|
||||||
python3.2 python3.1 python3.0 dnl
|
|
||||||
python2 dnl
|
|
||||||
python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl
|
|
||||||
python2.0])
|
|
||||||
|
|
||||||
AC_ARG_VAR([PYTHON], [the Python interpreter])
|
AC_ARG_VAR([PYTHON], [the Python interpreter])
|
||||||
|
|
||||||
@@ -508,137 +494,30 @@ AC_DEFUN([AM_PATH_PYTHON],
|
|||||||
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
|
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
|
||||||
else
|
else
|
||||||
|
|
||||||
dnl Query Python for its version number. Although site.py simply uses
|
dnl Query Python for its version number. Getting [:3] seems to be
|
||||||
dnl sys.version[:3], printing that failed with Python 3.10, since the
|
dnl the best way to do this; it's what "site.py" does in the standard
|
||||||
dnl trailing zero was eliminated. So now we output just the major
|
dnl library.
|
||||||
dnl and minor version numbers, as numbers. Apparently the tertiary
|
|
||||||
dnl version is not of interest.
|
|
||||||
dnl
|
|
||||||
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
|
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
|
||||||
[am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[[:2]])"`])
|
[am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`])
|
||||||
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
|
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
|
||||||
|
|
||||||
dnl At times, e.g., when building shared libraries, you may want
|
dnl Use the values of $prefix and $exec_prefix for the corresponding
|
||||||
|
dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
|
||||||
|
dnl distinct variables so they can be overridden if need be. However,
|
||||||
|
dnl general consensus is that you shouldn't need this ability.
|
||||||
|
|
||||||
|
AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
|
||||||
|
AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
|
||||||
|
|
||||||
|
dnl At times (like when building shared libraries) you may want
|
||||||
dnl to know which OS platform Python thinks this is.
|
dnl to know which OS platform Python thinks this is.
|
||||||
dnl
|
|
||||||
AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
|
AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
|
||||||
[am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
|
[am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
|
||||||
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
|
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
|
||||||
|
|
||||||
dnl emacs-page
|
# Just factor out some code duplication.
|
||||||
dnl If --with-python-sys-prefix is given, use the values of sys.prefix
|
|
||||||
dnl and sys.exec_prefix for the corresponding values of PYTHON_PREFIX
|
|
||||||
dnl and PYTHON_EXEC_PREFIX. Otherwise, use the GNU ${prefix} and
|
|
||||||
dnl ${exec_prefix} variables.
|
|
||||||
dnl
|
|
||||||
dnl The two are made distinct variables so they can be overridden if
|
|
||||||
dnl need be, although general consensus is that you shouldn't need
|
|
||||||
dnl this separation.
|
|
||||||
dnl
|
|
||||||
dnl Also allow directly setting the prefixes via configure options,
|
|
||||||
dnl overriding any default.
|
|
||||||
dnl
|
|
||||||
if test "x$prefix" = xNONE; then
|
|
||||||
am__usable_prefix=$ac_default_prefix
|
|
||||||
else
|
|
||||||
am__usable_prefix=$prefix
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Allow user to request using sys.* values from Python,
|
|
||||||
# instead of the GNU $prefix values.
|
|
||||||
AC_ARG_WITH([python-sys-prefix],
|
|
||||||
[AS_HELP_STRING([--with-python-sys-prefix],
|
|
||||||
[use Python's sys.prefix and sys.exec_prefix values])],
|
|
||||||
[am_use_python_sys=:],
|
|
||||||
[am_use_python_sys=false])
|
|
||||||
|
|
||||||
# Allow user to override whatever the default Python prefix is.
|
|
||||||
AC_ARG_WITH([python_prefix],
|
|
||||||
[AS_HELP_STRING([--with-python_prefix],
|
|
||||||
[override the default PYTHON_PREFIX])],
|
|
||||||
[am_python_prefix_subst=$withval
|
|
||||||
am_cv_python_prefix=$withval
|
|
||||||
AC_MSG_CHECKING([for explicit $am_display_PYTHON prefix])
|
|
||||||
AC_MSG_RESULT([$am_cv_python_prefix])],
|
|
||||||
[
|
|
||||||
if $am_use_python_sys; then
|
|
||||||
# using python sys.prefix value, not GNU
|
|
||||||
AC_CACHE_CHECK([for python default $am_display_PYTHON prefix],
|
|
||||||
[am_cv_python_prefix],
|
|
||||||
[am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"`])
|
|
||||||
|
|
||||||
dnl If sys.prefix is a subdir of $prefix, replace the literal value of
|
|
||||||
dnl $prefix with a variable reference so it can be overridden.
|
|
||||||
case $am_cv_python_prefix in
|
|
||||||
$am__usable_prefix*)
|
|
||||||
am__strip_prefix=`echo "$am__usable_prefix" | sed 's|.|.|g'`
|
|
||||||
am_python_prefix_subst=`echo "$am_cv_python_prefix" | sed "s,^$am__strip_prefix,\\${prefix},"`
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
am_python_prefix_subst=$am_cv_python_prefix
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
else # using GNU prefix value, not python sys.prefix
|
|
||||||
am_python_prefix_subst='${prefix}'
|
|
||||||
am_python_prefix=$am_python_prefix_subst
|
|
||||||
AC_MSG_CHECKING([for GNU default $am_display_PYTHON prefix])
|
|
||||||
AC_MSG_RESULT([$am_python_prefix])
|
|
||||||
fi])
|
|
||||||
# Substituting python_prefix_subst value.
|
|
||||||
AC_SUBST([PYTHON_PREFIX], [$am_python_prefix_subst])
|
|
||||||
|
|
||||||
# emacs-page Now do it all over again for Python exec_prefix, but with yet
|
|
||||||
# another conditional: fall back to regular prefix if that was specified.
|
|
||||||
AC_ARG_WITH([python_exec_prefix],
|
|
||||||
[AS_HELP_STRING([--with-python_exec_prefix],
|
|
||||||
[override the default PYTHON_EXEC_PREFIX])],
|
|
||||||
[am_python_exec_prefix_subst=$withval
|
|
||||||
am_cv_python_exec_prefix=$withval
|
|
||||||
AC_MSG_CHECKING([for explicit $am_display_PYTHON exec_prefix])
|
|
||||||
AC_MSG_RESULT([$am_cv_python_exec_prefix])],
|
|
||||||
[
|
|
||||||
# no explicit --with-python_exec_prefix, but if
|
|
||||||
# --with-python_prefix was given, use its value for python_exec_prefix too.
|
|
||||||
AS_IF([test -n "$with_python_prefix"],
|
|
||||||
[am_python_exec_prefix_subst=$with_python_prefix
|
|
||||||
am_cv_python_exec_prefix=$with_python_prefix
|
|
||||||
AC_MSG_CHECKING([for python_prefix-given $am_display_PYTHON exec_prefix])
|
|
||||||
AC_MSG_RESULT([$am_cv_python_exec_prefix])],
|
|
||||||
[
|
|
||||||
# Set am__usable_exec_prefix whether using GNU or Python values,
|
|
||||||
# since we use that variable for pyexecdir.
|
|
||||||
if test "x$exec_prefix" = xNONE; then
|
|
||||||
am__usable_exec_prefix=$am__usable_prefix
|
|
||||||
else
|
|
||||||
am__usable_exec_prefix=$exec_prefix
|
|
||||||
fi
|
|
||||||
#
|
|
||||||
if $am_use_python_sys; then # using python sys.exec_prefix, not GNU
|
|
||||||
AC_CACHE_CHECK([for python default $am_display_PYTHON exec_prefix],
|
|
||||||
[am_cv_python_exec_prefix],
|
|
||||||
[am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"`])
|
|
||||||
dnl If sys.exec_prefix is a subdir of $exec_prefix, replace the
|
|
||||||
dnl literal value of $exec_prefix with a variable reference so it can
|
|
||||||
dnl be overridden.
|
|
||||||
case $am_cv_python_exec_prefix in
|
|
||||||
$am__usable_exec_prefix*)
|
|
||||||
am__strip_prefix=`echo "$am__usable_exec_prefix" | sed 's|.|.|g'`
|
|
||||||
am_python_exec_prefix_subst=`echo "$am_cv_python_exec_prefix" | sed "s,^$am__strip_prefix,\\${exec_prefix},"`
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
am_python_exec_prefix_subst=$am_cv_python_exec_prefix
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
else # using GNU $exec_prefix, not python sys.exec_prefix
|
|
||||||
am_python_exec_prefix_subst='${exec_prefix}'
|
|
||||||
am_python_exec_prefix=$am_python_exec_prefix_subst
|
|
||||||
AC_MSG_CHECKING([for GNU default $am_display_PYTHON exec_prefix])
|
|
||||||
AC_MSG_RESULT([$am_python_exec_prefix])
|
|
||||||
fi])])
|
|
||||||
# Substituting python_exec_prefix_subst.
|
|
||||||
AC_SUBST([PYTHON_EXEC_PREFIX], [$am_python_exec_prefix_subst])
|
|
||||||
|
|
||||||
# Factor out some code duplication into this shell variable.
|
|
||||||
am_python_setup_sysconfig="\
|
am_python_setup_sysconfig="\
|
||||||
import sys
|
import sys
|
||||||
# Prefer sysconfig over distutils.sysconfig, for better compatibility
|
# Prefer sysconfig over distutils.sysconfig, for better compatibility
|
||||||
@@ -656,59 +535,41 @@ try:
|
|||||||
if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7':
|
if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7':
|
||||||
can_use_sysconfig = 0
|
can_use_sysconfig = 0
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass" # end of am_python_setup_sysconfig
|
pass"
|
||||||
|
|
||||||
# More repeated code, for figuring out the installation scheme to use.
|
dnl Set up 4 directories:
|
||||||
am_python_setup_scheme="if hasattr(sysconfig, 'get_default_scheme'):
|
|
||||||
scheme = sysconfig.get_default_scheme()
|
|
||||||
else:
|
|
||||||
scheme = sysconfig._get_default_scheme()
|
|
||||||
if scheme == 'posix_local':
|
|
||||||
if '$am_py_prefix' == '/usr':
|
|
||||||
scheme = 'deb_system' # should only happen during Debian package builds
|
|
||||||
else:
|
|
||||||
# Debian's default scheme installs to /usr/local/ but we want to
|
|
||||||
# follow the prefix, as we always have.
|
|
||||||
# See bugs#54412, #64837, et al.
|
|
||||||
scheme = 'posix_prefix'" # end of am_python_setup_scheme
|
|
||||||
|
|
||||||
dnl emacs-page Set up 4 directories:
|
dnl pythondir -- where to install python scripts. This is the
|
||||||
|
|
||||||
dnl 1. pythondir: where to install python scripts. This is the
|
|
||||||
dnl site-packages directory, not the python standard library
|
dnl site-packages directory, not the python standard library
|
||||||
dnl directory as in early automake betas. This behavior
|
dnl directory like in previous automake betas. This behavior
|
||||||
dnl is more consistent with lispdir.m4 for example.
|
dnl is more consistent with lispdir.m4 for example.
|
||||||
dnl Query sysconfig or distutils (per above) for this directory.
|
dnl Query distutils for this directory.
|
||||||
dnl
|
AC_CACHE_CHECK([for $am_display_PYTHON script directory],
|
||||||
AC_CACHE_CHECK([for $am_display_PYTHON script directory (pythondir)],
|
|
||||||
[am_cv_python_pythondir],
|
[am_cv_python_pythondir],
|
||||||
[if test "x$am_cv_python_prefix" = x; then
|
[if test "x$prefix" = xNONE
|
||||||
am_py_prefix=$am__usable_prefix
|
then
|
||||||
|
am_py_prefix=$ac_default_prefix
|
||||||
else
|
else
|
||||||
am_py_prefix=$am_cv_python_prefix
|
am_py_prefix=$prefix
|
||||||
fi
|
fi
|
||||||
am_cv_python_pythondir=`$PYTHON -c "
|
am_cv_python_pythondir=`$PYTHON -c "
|
||||||
$am_python_setup_sysconfig
|
$am_python_setup_sysconfig
|
||||||
if can_use_sysconfig:
|
if can_use_sysconfig:
|
||||||
try:
|
|
||||||
$am_python_setup_scheme
|
|
||||||
sitedir = sysconfig.get_path('purelib', scheme, vars={'base':'$am_py_prefix'})
|
|
||||||
except:
|
|
||||||
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
|
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
|
||||||
else:
|
else:
|
||||||
from distutils import sysconfig
|
from distutils import sysconfig
|
||||||
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
|
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
|
||||||
sys.stdout.write(sitedir)"`
|
sys.stdout.write(sitedir)"`
|
||||||
#
|
|
||||||
case $am_cv_python_pythondir in
|
case $am_cv_python_pythondir in
|
||||||
$am_py_prefix*)
|
$am_py_prefix*)
|
||||||
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
|
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
|
||||||
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,\\${PYTHON_PREFIX},"`
|
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
case $am_py_prefix in
|
case $am_py_prefix in
|
||||||
/usr|/System*) ;;
|
/usr|/System*) ;;
|
||||||
*) am_cv_python_pythondir="\${PYTHON_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
|
*)
|
||||||
|
am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
@@ -716,46 +577,41 @@ sys.stdout.write(sitedir)"`
|
|||||||
])
|
])
|
||||||
AC_SUBST([pythondir], [$am_cv_python_pythondir])
|
AC_SUBST([pythondir], [$am_cv_python_pythondir])
|
||||||
|
|
||||||
dnl 2. pkgpythondir: $PACKAGE directory under pythondir. Was
|
dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
|
||||||
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
|
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
|
||||||
dnl more consistent with the rest of automake.
|
dnl more consistent with the rest of automake.
|
||||||
dnl
|
|
||||||
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
|
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
|
||||||
|
|
||||||
dnl 3. pyexecdir: directory for installing python extension modules
|
dnl pyexecdir -- directory for installing python extension modules
|
||||||
dnl (shared libraries).
|
dnl (shared libraries)
|
||||||
dnl Query sysconfig or distutils for this directory.
|
dnl Query distutils for this directory.
|
||||||
dnl Much of this is the same as for prefix setup above.
|
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
|
||||||
dnl
|
|
||||||
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory (pyexecdir)],
|
|
||||||
[am_cv_python_pyexecdir],
|
[am_cv_python_pyexecdir],
|
||||||
[if test "x$am_cv_python_exec_prefix" = x; then
|
[if test "x$exec_prefix" = xNONE
|
||||||
am_py_exec_prefix=$am__usable_exec_prefix
|
then
|
||||||
|
am_py_exec_prefix=$am_py_prefix
|
||||||
else
|
else
|
||||||
am_py_exec_prefix=$am_cv_python_exec_prefix
|
am_py_exec_prefix=$exec_prefix
|
||||||
fi
|
fi
|
||||||
am_cv_python_pyexecdir=`$PYTHON -c "
|
am_cv_python_pyexecdir=`$PYTHON -c "
|
||||||
$am_python_setup_sysconfig
|
$am_python_setup_sysconfig
|
||||||
if can_use_sysconfig:
|
if can_use_sysconfig:
|
||||||
try:
|
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
|
||||||
$am_python_setup_scheme
|
|
||||||
sitedir = sysconfig.get_path('platlib', scheme, vars={'platbase':'$am_py_exec_prefix'})
|
|
||||||
except:
|
|
||||||
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_exec_prefix'})
|
|
||||||
else:
|
else:
|
||||||
from distutils import sysconfig
|
from distutils import sysconfig
|
||||||
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix')
|
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
|
||||||
sys.stdout.write(sitedir)"`
|
sys.stdout.write(sitedir)"`
|
||||||
#
|
|
||||||
case $am_cv_python_pyexecdir in
|
case $am_cv_python_pyexecdir in
|
||||||
$am_py_exec_prefix*)
|
$am_py_exec_prefix*)
|
||||||
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
|
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
|
||||||
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,\\${PYTHON_EXEC_PREFIX},"`
|
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
case $am_py_exec_prefix in
|
case $am_py_exec_prefix in
|
||||||
/usr|/System*) ;;
|
/usr|/System*) ;;
|
||||||
*) am_cv_python_pyexecdir="\${PYTHON_EXEC_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
|
*)
|
||||||
|
am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
@@ -763,13 +619,14 @@ sys.stdout.write(sitedir)"`
|
|||||||
])
|
])
|
||||||
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
|
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
|
||||||
|
|
||||||
dnl 4. pkgpyexecdir: $(pyexecdir)/$(PACKAGE)
|
dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
|
||||||
dnl
|
|
||||||
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
|
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
|
||||||
|
|
||||||
dnl Run any user-specified action.
|
dnl Run any user-specified action.
|
||||||
$2
|
$2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@@ -792,7 +649,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
|
|||||||
sys.exit(sys.hexversion < minverhex)"
|
sys.exit(sys.hexversion < minverhex)"
|
||||||
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
|
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
|
||||||
|
|
||||||
# Copyright (C) 2001-2025 Free Software Foundation, Inc.
|
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
|||||||
1608
autoconf/config.guess
vendored
1608
autoconf/config.guess
vendored
File diff suppressed because it is too large
Load Diff
2873
autoconf/config.sub
vendored
2873
autoconf/config.sub
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/sh
|
#!/bin/sh
|
||||||
# install - install a program, script, or datafile
|
# install - install a program, script, or datafile
|
||||||
|
|
||||||
scriptversion=2020-11-14.01; # UTC
|
scriptversion=2006-10-14.15
|
||||||
|
|
||||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||||
@@ -35,62 +35,57 @@ scriptversion=2020-11-14.01; # UTC
|
|||||||
# FSF changes to this file are in the public domain.
|
# FSF changes to this file are in the public domain.
|
||||||
#
|
#
|
||||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||||
# 'make' implicit rules from creating a file called install from it
|
# `make' implicit rules from creating a file called install from it
|
||||||
# when there is no Makefile.
|
# when there is no Makefile.
|
||||||
#
|
#
|
||||||
# This script is compatible with the BSD install script, but was written
|
# This script is compatible with the BSD install script, but was written
|
||||||
# from scratch.
|
# from scratch.
|
||||||
|
|
||||||
tab=' '
|
|
||||||
nl='
|
nl='
|
||||||
'
|
'
|
||||||
IFS=" $tab$nl"
|
IFS=" "" $nl"
|
||||||
|
|
||||||
# Set DOITPROG to "echo" to test this script.
|
# set DOITPROG to echo to test this script
|
||||||
|
|
||||||
doit=${DOITPROG-}
|
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||||
doit_exec=${doit:-exec}
|
doit="${DOITPROG-}"
|
||||||
|
if test -z "$doit"; then
|
||||||
|
doit_exec=exec
|
||||||
|
else
|
||||||
|
doit_exec=$doit
|
||||||
|
fi
|
||||||
|
|
||||||
# Put in absolute file names if you don't have them in your path;
|
# Put in absolute file names if you don't have them in your path;
|
||||||
# or use environment vars.
|
# or use environment vars.
|
||||||
|
|
||||||
chgrpprog=${CHGRPPROG-chgrp}
|
mvprog="${MVPROG-mv}"
|
||||||
chmodprog=${CHMODPROG-chmod}
|
cpprog="${CPPROG-cp}"
|
||||||
chownprog=${CHOWNPROG-chown}
|
chmodprog="${CHMODPROG-chmod}"
|
||||||
cmpprog=${CMPPROG-cmp}
|
chownprog="${CHOWNPROG-chown}"
|
||||||
cpprog=${CPPROG-cp}
|
chgrpprog="${CHGRPPROG-chgrp}"
|
||||||
mkdirprog=${MKDIRPROG-mkdir}
|
stripprog="${STRIPPROG-strip}"
|
||||||
mvprog=${MVPROG-mv}
|
rmprog="${RMPROG-rm}"
|
||||||
rmprog=${RMPROG-rm}
|
mkdirprog="${MKDIRPROG-mkdir}"
|
||||||
stripprog=${STRIPPROG-strip}
|
|
||||||
|
|
||||||
|
posix_glob=
|
||||||
posix_mkdir=
|
posix_mkdir=
|
||||||
|
|
||||||
# Desired mode of installed file.
|
# Desired mode of installed file.
|
||||||
mode=0755
|
mode=0755
|
||||||
|
|
||||||
# Create dirs (including intermediate dirs) using mode 755.
|
|
||||||
# This is like GNU 'install' as of coreutils 8.32 (2020).
|
|
||||||
mkdir_umask=22
|
|
||||||
|
|
||||||
backupsuffix=
|
|
||||||
chgrpcmd=
|
|
||||||
chmodcmd=$chmodprog
|
chmodcmd=$chmodprog
|
||||||
chowncmd=
|
chowncmd=
|
||||||
mvcmd=$mvprog
|
chgrpcmd=
|
||||||
rmcmd="$rmprog -f"
|
|
||||||
stripcmd=
|
stripcmd=
|
||||||
|
rmcmd="$rmprog -f"
|
||||||
|
mvcmd="$mvprog"
|
||||||
src=
|
src=
|
||||||
dst=
|
dst=
|
||||||
dir_arg=
|
dir_arg=
|
||||||
dst_arg=
|
dstarg=
|
||||||
|
no_target_directory=
|
||||||
|
|
||||||
copy_on_change=false
|
usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||||
is_target_a_directory=possibly
|
|
||||||
|
|
||||||
usage="\
|
|
||||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
|
||||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||||
or: $0 [OPTION]... -d DIRECTORIES...
|
or: $0 [OPTION]... -d DIRECTORIES...
|
||||||
@@ -100,75 +95,65 @@ In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
|||||||
In the 4th, create DIRECTORIES.
|
In the 4th, create DIRECTORIES.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--help display this help and exit.
|
|
||||||
--version display version info and exit.
|
|
||||||
|
|
||||||
-c (ignored)
|
-c (ignored)
|
||||||
-C install only if different (preserve data modification time)
|
|
||||||
-d create directories instead of installing files.
|
-d create directories instead of installing files.
|
||||||
-g GROUP $chgrpprog installed files to GROUP.
|
-g GROUP $chgrpprog installed files to GROUP.
|
||||||
-m MODE $chmodprog installed files to MODE.
|
-m MODE $chmodprog installed files to MODE.
|
||||||
-o USER $chownprog installed files to USER.
|
-o USER $chownprog installed files to USER.
|
||||||
-p pass -p to $cpprog.
|
|
||||||
-s $stripprog installed files.
|
-s $stripprog installed files.
|
||||||
-S SUFFIX attempt to back up existing files, with suffix SUFFIX.
|
|
||||||
-t DIRECTORY install into DIRECTORY.
|
-t DIRECTORY install into DIRECTORY.
|
||||||
-T report an error if DSTFILE is a directory.
|
-T report an error if DSTFILE is a directory.
|
||||||
|
--help display this help and exit.
|
||||||
|
--version display version info and exit.
|
||||||
|
|
||||||
Environment variables override the default commands:
|
Environment variables override the default commands:
|
||||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
|
||||||
RMPROG STRIPPROG
|
|
||||||
|
|
||||||
By default, rm is invoked with -f; when overridden with RMPROG,
|
|
||||||
it's up to you to specify -f if you want it.
|
|
||||||
|
|
||||||
If -S is not specified, no backups are attempted.
|
|
||||||
|
|
||||||
Email bug reports to bug-automake@gnu.org.
|
|
||||||
Automake home page: https://www.gnu.org/software/automake/
|
|
||||||
"
|
"
|
||||||
|
|
||||||
while test $# -ne 0; do
|
while test $# -ne 0; do
|
||||||
case $1 in
|
case $1 in
|
||||||
-c) ;;
|
-c) shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
-C) copy_on_change=true;;
|
-d) dir_arg=true
|
||||||
|
shift
|
||||||
-d) dir_arg=true;;
|
continue;;
|
||||||
|
|
||||||
-g) chgrpcmd="$chgrpprog $2"
|
-g) chgrpcmd="$chgrpprog $2"
|
||||||
shift;;
|
shift
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
--help) echo "$usage"; exit $?;;
|
--help) echo "$usage"; exit $?;;
|
||||||
|
|
||||||
-m) mode=$2
|
-m) mode=$2
|
||||||
|
shift
|
||||||
|
shift
|
||||||
case $mode in
|
case $mode in
|
||||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
*' '* | *' '* | *'
|
||||||
|
'* | *'*'* | *'?'* | *'['*)
|
||||||
echo "$0: invalid mode: $mode" >&2
|
echo "$0: invalid mode: $mode" >&2
|
||||||
exit 1;;
|
exit 1;;
|
||||||
esac
|
esac
|
||||||
shift;;
|
continue;;
|
||||||
|
|
||||||
-o) chowncmd="$chownprog $2"
|
-o) chowncmd="$chownprog $2"
|
||||||
shift;;
|
shift
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
-p) cpprog="$cpprog -p";;
|
-s) stripcmd=$stripprog
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
-s) stripcmd=$stripprog;;
|
-t) dstarg=$2
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
-S) backupsuffix="$2"
|
-T) no_target_directory=true
|
||||||
shift;;
|
shift
|
||||||
|
continue;;
|
||||||
-t)
|
|
||||||
is_target_a_directory=always
|
|
||||||
dst_arg=$2
|
|
||||||
# Protect names problematic for 'test' and other utilities.
|
|
||||||
case $dst_arg in
|
|
||||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
|
||||||
esac
|
|
||||||
shift;;
|
|
||||||
|
|
||||||
-T) is_target_a_directory=never;;
|
|
||||||
|
|
||||||
--version) echo "$0 $scriptversion"; exit $?;;
|
--version) echo "$0 $scriptversion"; exit $?;;
|
||||||
|
|
||||||
@@ -180,36 +165,21 @@ while test $# -ne 0; do
|
|||||||
|
|
||||||
*) break;;
|
*) break;;
|
||||||
esac
|
esac
|
||||||
shift
|
|
||||||
done
|
done
|
||||||
|
|
||||||
# We allow the use of options -d and -T together, by making -d
|
if test $# -ne 0 && test -z "$dir_arg$dstarg"; then
|
||||||
# take the precedence; this is for compatibility with GNU install.
|
|
||||||
|
|
||||||
if test -n "$dir_arg"; then
|
|
||||||
if test -n "$dst_arg"; then
|
|
||||||
echo "$0: target directory not allowed when installing a directory." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
|
||||||
# When -d is used, all remaining arguments are directories to create.
|
# When -d is used, all remaining arguments are directories to create.
|
||||||
# When -t is used, the destination is already specified.
|
# When -t is used, the destination is already specified.
|
||||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||||
for arg
|
for arg
|
||||||
do
|
do
|
||||||
if test -n "$dst_arg"; then
|
if test -n "$dstarg"; then
|
||||||
# $@ is not empty: it contains at least $arg.
|
# $@ is not empty: it contains at least $arg.
|
||||||
set fnord "$@" "$dst_arg"
|
set fnord "$@" "$dstarg"
|
||||||
shift # fnord
|
shift # fnord
|
||||||
fi
|
fi
|
||||||
shift # arg
|
shift # arg
|
||||||
dst_arg=$arg
|
dstarg=$arg
|
||||||
# Protect names problematic for 'test' and other utilities.
|
|
||||||
case $dst_arg in
|
|
||||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
|
||||||
esac
|
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -218,26 +188,13 @@ if test $# -eq 0; then
|
|||||||
echo "$0: no input file specified." >&2
|
echo "$0: no input file specified." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
# It's OK to call 'install-sh -d' without argument.
|
# It's OK to call `install-sh -d' without argument.
|
||||||
# This can happen when creating conditional directories.
|
# This can happen when creating conditional directories.
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test -z "$dir_arg"; then
|
if test -z "$dir_arg"; then
|
||||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
trap '(exit $?); exit' 1 2 13 15
|
||||||
if test ! -d "$dst_arg"; then
|
|
||||||
echo "$0: $dst_arg: Is not a directory." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -z "$dir_arg"; then
|
|
||||||
do_exit='(exit $ret); exit $ret'
|
|
||||||
trap "ret=129; $do_exit" 1
|
|
||||||
trap "ret=130; $do_exit" 2
|
|
||||||
trap "ret=141; $do_exit" 13
|
|
||||||
trap "ret=143; $do_exit" 15
|
|
||||||
|
|
||||||
# Set umask so as not to create temps with too-generous modes.
|
# Set umask so as not to create temps with too-generous modes.
|
||||||
# However, 'strip' requires both read and write access to temps.
|
# However, 'strip' requires both read and write access to temps.
|
||||||
@@ -265,9 +222,9 @@ fi
|
|||||||
|
|
||||||
for src
|
for src
|
||||||
do
|
do
|
||||||
# Protect names problematic for 'test' and other utilities.
|
# Protect names starting with `-'.
|
||||||
case $src in
|
case $src in
|
||||||
-* | [=\(\)!]) src=./$src;;
|
-*) src=./$src ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if test -n "$dir_arg"; then
|
if test -n "$dir_arg"; then
|
||||||
@@ -275,10 +232,6 @@ do
|
|||||||
dstdir=$dst
|
dstdir=$dst
|
||||||
test -d "$dstdir"
|
test -d "$dstdir"
|
||||||
dstdir_status=$?
|
dstdir_status=$?
|
||||||
# Don't chown directories that already exist.
|
|
||||||
if test $dstdir_status = 0; then
|
|
||||||
chowncmd=""
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
|
|
||||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||||
@@ -289,42 +242,81 @@ do
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test -z "$dst_arg"; then
|
if test -z "$dstarg"; then
|
||||||
echo "$0: no destination specified." >&2
|
echo "$0: no destination specified." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
dst=$dst_arg
|
|
||||||
|
|
||||||
# If destination is a directory, append the input filename.
|
dst=$dstarg
|
||||||
|
# Protect names starting with `-'.
|
||||||
|
case $dst in
|
||||||
|
-*) dst=./$dst ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# If destination is a directory, append the input filename; won't work
|
||||||
|
# if double slashes aren't ignored.
|
||||||
if test -d "$dst"; then
|
if test -d "$dst"; then
|
||||||
if test "$is_target_a_directory" = never; then
|
if test -n "$no_target_directory"; then
|
||||||
echo "$0: $dst_arg: Is a directory" >&2
|
echo "$0: $dstarg: Is a directory" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
dstdir=$dst
|
dstdir=$dst
|
||||||
dstbase=`basename "$src"`
|
dst=$dstdir/`basename "$src"`
|
||||||
case $dst in
|
|
||||||
*/) dst=$dst$dstbase;;
|
|
||||||
*) dst=$dst/$dstbase;;
|
|
||||||
esac
|
|
||||||
dstdir_status=0
|
dstdir_status=0
|
||||||
else
|
else
|
||||||
dstdir=`dirname "$dst"`
|
# Prefer dirname, but fall back on a substitute if dirname fails.
|
||||||
|
dstdir=`
|
||||||
|
(dirname "$dst") 2>/dev/null ||
|
||||||
|
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||||
|
X"$dst" : 'X\(//\)[^/]' \| \
|
||||||
|
X"$dst" : 'X\(//\)$' \| \
|
||||||
|
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
||||||
|
echo X"$dst" |
|
||||||
|
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
||||||
|
s//\1/
|
||||||
|
q
|
||||||
|
}
|
||||||
|
/^X\(\/\/\)[^/].*/{
|
||||||
|
s//\1/
|
||||||
|
q
|
||||||
|
}
|
||||||
|
/^X\(\/\/\)$/{
|
||||||
|
s//\1/
|
||||||
|
q
|
||||||
|
}
|
||||||
|
/^X\(\/\).*/{
|
||||||
|
s//\1/
|
||||||
|
q
|
||||||
|
}
|
||||||
|
s/.*/./; q'
|
||||||
|
`
|
||||||
|
|
||||||
test -d "$dstdir"
|
test -d "$dstdir"
|
||||||
dstdir_status=$?
|
dstdir_status=$?
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case $dstdir in
|
|
||||||
*/) dstdirslash=$dstdir;;
|
|
||||||
*) dstdirslash=$dstdir/;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
obsolete_mkdir_used=false
|
obsolete_mkdir_used=false
|
||||||
|
|
||||||
if test $dstdir_status != 0; then
|
if test $dstdir_status != 0; then
|
||||||
case $posix_mkdir in
|
case $posix_mkdir in
|
||||||
'')
|
'')
|
||||||
|
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||||
|
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||||
|
umask=`umask`
|
||||||
|
case $stripcmd.$umask in
|
||||||
|
# Optimize common cases.
|
||||||
|
*[2367][2367]) mkdir_umask=$umask;;
|
||||||
|
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||||
|
|
||||||
|
*[0-7])
|
||||||
|
mkdir_umask=`expr $umask + 22 \
|
||||||
|
- $umask % 100 % 40 + $umask % 20 \
|
||||||
|
- $umask % 10 % 4 + $umask % 2
|
||||||
|
`;;
|
||||||
|
*) mkdir_umask=$umask,go-w;;
|
||||||
|
esac
|
||||||
|
|
||||||
# With -d, create the new directory with the user-specified mode.
|
# With -d, create the new directory with the user-specified mode.
|
||||||
# Otherwise, rely on $mkdir_umask.
|
# Otherwise, rely on $mkdir_umask.
|
||||||
if test -n "$dir_arg"; then
|
if test -n "$dir_arg"; then
|
||||||
@@ -334,49 +326,43 @@ do
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
posix_mkdir=false
|
posix_mkdir=false
|
||||||
# The $RANDOM variable is not portable (e.g., dash). Use it
|
case $umask in
|
||||||
# here however when possible just to lower collision chance.
|
*[123567][0-7][0-7])
|
||||||
|
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||||
|
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||||
|
;;
|
||||||
|
*)
|
||||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||||
|
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||||
|
|
||||||
trap '
|
|
||||||
ret=$?
|
|
||||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
|
|
||||||
exit $ret
|
|
||||||
' 0
|
|
||||||
|
|
||||||
# Because "mkdir -p" follows existing symlinks and we likely work
|
|
||||||
# directly in world-writeable /tmp, make sure that the '$tmpdir'
|
|
||||||
# directory is successfully created first before we actually test
|
|
||||||
# 'mkdir -p'.
|
|
||||||
if (umask $mkdir_umask &&
|
if (umask $mkdir_umask &&
|
||||||
$mkdirprog $mkdir_mode "$tmpdir" &&
|
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
|
|
||||||
then
|
then
|
||||||
if test -z "$dir_arg" || {
|
if test -z "$dir_arg" || {
|
||||||
# Check for POSIX incompatibilities with -m.
|
# Check for POSIX incompatibilities with -m.
|
||||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||||
# other-writable bit of parent directory when it shouldn't.
|
# other-writeable bit of parent directory when it shouldn't.
|
||||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||||
test_tmpdir="$tmpdir/a"
|
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||||
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
|
|
||||||
case $ls_ld_tmpdir in
|
case $ls_ld_tmpdir in
|
||||||
d????-?r-*) different_mode=700;;
|
d????-?r-*) different_mode=700;;
|
||||||
d????-?--*) different_mode=755;;
|
d????-?--*) different_mode=755;;
|
||||||
*) false;;
|
*) false;;
|
||||||
esac &&
|
esac &&
|
||||||
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
|
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||||
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
|
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
then posix_mkdir=:
|
then posix_mkdir=:
|
||||||
fi
|
fi
|
||||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
|
rmdir "$tmpdir/d" "$tmpdir"
|
||||||
else
|
else
|
||||||
# Remove any dirs left behind by ancient mkdir implementations.
|
# Remove any dirs left behind by ancient mkdir implementations.
|
||||||
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
|
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||||
fi
|
fi
|
||||||
trap '' 0;;
|
trap '' 0;;
|
||||||
|
esac;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if
|
if
|
||||||
@@ -387,36 +373,45 @@ do
|
|||||||
then :
|
then :
|
||||||
else
|
else
|
||||||
|
|
||||||
# mkdir does not conform to POSIX,
|
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||||
# or it failed possibly due to a race condition. Create the
|
# or it failed possibly due to a race condition. Create the
|
||||||
# directory the slow way, step by step, checking for races as we go.
|
# directory the slow way, step by step, checking for races as we go.
|
||||||
|
|
||||||
case $dstdir in
|
case $dstdir in
|
||||||
/*) prefix='/';;
|
/*) prefix=/ ;;
|
||||||
[-=\(\)!]*) prefix='./';;
|
-*) prefix=./ ;;
|
||||||
*) prefix='';;
|
*) prefix= ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case $posix_glob in
|
||||||
|
'')
|
||||||
|
if (set -f) 2>/dev/null; then
|
||||||
|
posix_glob=true
|
||||||
|
else
|
||||||
|
posix_glob=false
|
||||||
|
fi ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
oIFS=$IFS
|
oIFS=$IFS
|
||||||
IFS=/
|
IFS=/
|
||||||
set -f
|
$posix_glob && set -f
|
||||||
set fnord $dstdir
|
set fnord $dstdir
|
||||||
shift
|
shift
|
||||||
set +f
|
$posix_glob && set +f
|
||||||
IFS=$oIFS
|
IFS=$oIFS
|
||||||
|
|
||||||
prefixes=
|
prefixes=
|
||||||
|
|
||||||
for d
|
for d
|
||||||
do
|
do
|
||||||
test X"$d" = X && continue
|
test -z "$d" && continue
|
||||||
|
|
||||||
prefix=$prefix$d
|
prefix=$prefix$d
|
||||||
if test -d "$prefix"; then
|
if test -d "$prefix"; then
|
||||||
prefixes=
|
prefixes=
|
||||||
else
|
else
|
||||||
if $posix_mkdir; then
|
if $posix_mkdir; then
|
||||||
(umask $mkdir_umask &&
|
(umask=$mkdir_umask &&
|
||||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||||
# Don't fail if two instances are running concurrently.
|
# Don't fail if two instances are running concurrently.
|
||||||
test -d "$prefix" || exit 1
|
test -d "$prefix" || exit 1
|
||||||
@@ -449,25 +444,14 @@ do
|
|||||||
else
|
else
|
||||||
|
|
||||||
# Make a couple of temp file names in the proper directory.
|
# Make a couple of temp file names in the proper directory.
|
||||||
dsttmp=${dstdirslash}_inst.$$_
|
dsttmp=$dstdir/_inst.$$_
|
||||||
rmtmp=${dstdirslash}_rm.$$_
|
rmtmp=$dstdir/_rm.$$_
|
||||||
|
|
||||||
# Trap to clean up those temp files at exit.
|
# Trap to clean up those temp files at exit.
|
||||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||||
|
|
||||||
# Copy the file name to the temp name.
|
# Copy the file name to the temp name.
|
||||||
(umask $cp_umask &&
|
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||||
{ test -z "$stripcmd" || {
|
|
||||||
# Create $dsttmp read-write so that cp doesn't create it read-only,
|
|
||||||
# which would cause strip to fail.
|
|
||||||
if test -z "$doit"; then
|
|
||||||
: >"$dsttmp" # No need to fork-exec 'touch'.
|
|
||||||
else
|
|
||||||
$doit touch "$dsttmp"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
} &&
|
|
||||||
$doit_exec $cpprog "$src" "$dsttmp") &&
|
|
||||||
|
|
||||||
# and set any options; do chmod last to preserve setuid bits.
|
# and set any options; do chmod last to preserve setuid bits.
|
||||||
#
|
#
|
||||||
@@ -475,67 +459,49 @@ do
|
|||||||
# ignore errors from any of these, just make sure not to ignore
|
# ignore errors from any of these, just make sure not to ignore
|
||||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||||
#
|
#
|
||||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
|
||||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
|
||||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
&& { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
|
||||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
&& { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||||
|
|
||||||
# If -C, don't bother to copy if it wouldn't change the file.
|
|
||||||
if $copy_on_change &&
|
|
||||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
|
||||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
|
||||||
set -f &&
|
|
||||||
set X $old && old=:$2:$4:$5:$6 &&
|
|
||||||
set X $new && new=:$2:$4:$5:$6 &&
|
|
||||||
set +f &&
|
|
||||||
test "$old" = "$new" &&
|
|
||||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
rm -f "$dsttmp"
|
|
||||||
else
|
|
||||||
# If $backupsuffix is set, and the file being installed
|
|
||||||
# already exists, attempt a backup. Don't worry if it fails,
|
|
||||||
# e.g., if mv doesn't support -f.
|
|
||||||
if test -n "$backupsuffix" && test -f "$dst"; then
|
|
||||||
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Rename the file to the real destination.
|
|
||||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
|
||||||
|
|
||||||
|
# Now rename the file to the real destination.
|
||||||
|
{ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
|
||||||
|
|| {
|
||||||
# The rename failed, perhaps because mv can't rename something else
|
# The rename failed, perhaps because mv can't rename something else
|
||||||
# to itself, or perhaps because mv is so ancient that it does not
|
# to itself, or perhaps because mv is so ancient that it does not
|
||||||
# support -f.
|
# support -f.
|
||||||
{
|
|
||||||
# Now remove or move aside any old file at destination location.
|
# Now remove or move aside any old file at destination location.
|
||||||
# We try this two ways since rm can't unlink itself on some
|
# We try this two ways since rm can't unlink itself on some
|
||||||
# systems and the destination file might be busy for other
|
# systems and the destination file might be busy for other
|
||||||
# reasons. In this case, the final cleanup might fail but the new
|
# reasons. In this case, the final cleanup might fail but the new
|
||||||
# file should still install successfully.
|
# file should still install successfully.
|
||||||
{
|
{
|
||||||
test ! -f "$dst" ||
|
if test -f "$dst"; then
|
||||||
$doit $rmcmd "$dst" 2>/dev/null ||
|
$doit $rmcmd -f "$dst" 2>/dev/null \
|
||||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
|| { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \
|
||||||
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
|
&& { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\
|
||||||
} ||
|
|| {
|
||||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
echo "$0: cannot unlink or rename $dst" >&2
|
||||||
(exit 1); exit 1
|
(exit 1); exit 1
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
:
|
||||||
|
fi
|
||||||
} &&
|
} &&
|
||||||
|
|
||||||
# Now rename the file to the real destination.
|
# Now rename the file to the real destination.
|
||||||
$doit $mvcmd "$dsttmp" "$dst"
|
$doit $mvcmd "$dsttmp" "$dst"
|
||||||
}
|
}
|
||||||
fi || exit 1
|
} || exit 1
|
||||||
|
|
||||||
trap '' 0
|
trap '' 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Local variables:
|
# Local variables:
|
||||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||||
# time-stamp-start: "scriptversion="
|
# time-stamp-start: "scriptversion="
|
||||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||||
# time-stamp-time-zone: "UTC0"
|
# time-stamp-end: "$"
|
||||||
# time-stamp-end: "; # UTC"
|
|
||||||
# End:
|
# End:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
# Then byte compile w/optimization all the modules.
|
|
||||||
$PYTHON -O -c "
|
|
||||||
import sys, os, py_compile
|
|
||||||
|
|
||||||
try:
|
|
||||||
import importlib
|
|
||||||
except ImportError:
|
|
||||||
importlib = None
|
|
||||||
|
|
||||||
# importlib.util.cache_from_source was added in 3.4
|
|
||||||
if (
|
|
||||||
hasattr(importlib, 'util')
|
|
||||||
and hasattr(importlib.util, 'cache_from_source')
|
|
||||||
):
|
|
||||||
destpath = importlib.util.cache_from_source
|
|
||||||
else:
|
else:
|
||||||
destpath = lambda filepath: filepath + 'o'
|
py_compile.compile(filepath, filepath + 'c', path)
|
||||||
|
sys.stdout.write('\n')" || exit $?
|
||||||
|
|
||||||
# pypy2 does not use .pyo optimization
|
# this will fail for python < 1.5, but that doesn't matter ...
|
||||||
if sys.version_info.major <= 2 and hasattr(sys, 'pypy_translation_info'):
|
$PYTHON -O -c "
|
||||||
|
import sys, os, py_compile, imp
|
||||||
|
|
||||||
|
# pypy does not use .pyo optimization
|
||||||
|
if 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:
|
||||||
|
|||||||
@@ -14,27 +14,22 @@
|
|||||||
# Comment to build the advanced radix tree.
|
# Comment to build the advanced radix tree.
|
||||||
#base/data-struct/radix-tree.o: CFLAGS += -DSIMPLE_RADIX_TREE
|
#base/data-struct/radix-tree.o: CFLAGS += -DSIMPLE_RADIX_TREE
|
||||||
|
|
||||||
# NOTE: this Makefile only works as 'include' for toplevel Makefile
|
|
||||||
# which defined all top_* variables
|
|
||||||
|
|
||||||
BASE_SOURCE=\
|
BASE_SOURCE=\
|
||||||
|
base/data-struct/radix-tree.c \
|
||||||
base/data-struct/hash.c \
|
base/data-struct/hash.c \
|
||||||
base/data-struct/list.c \
|
base/data-struct/list.c
|
||||||
base/data-struct/radix-tree.c
|
|
||||||
|
|
||||||
BASE_TARGET = base/libbase.a
|
BASE_DEPENDS=$(addprefix $(top_builddir)/,$(subst .c,.d,$(BASE_SOURCE)))
|
||||||
BASE_DEPENDS = $(BASE_SOURCE:%.c=%.d)
|
BASE_OBJECTS=$(addprefix $(top_builddir)/,$(subst .c,.o,$(BASE_SOURCE)))
|
||||||
BASE_OBJECTS = $(BASE_SOURCE:%.c=%.o)
|
CLEAN_TARGETS+=$(BASE_DEPENDS) $(BASE_OBJECTS)
|
||||||
CLEAN_TARGETS += $(BASE_DEPENDS) $(BASE_OBJECTS) \
|
|
||||||
$(BASE_SOURCE:%.c=%.gcda) \
|
|
||||||
$(BASE_SOURCE:%.c=%.gcno) \
|
|
||||||
$(BASE_TARGET)
|
|
||||||
|
|
||||||
$(BASE_TARGET): $(BASE_OBJECTS)
|
-include $(BASE_DEPENDS)
|
||||||
$(SHOW) " [AR] $@"
|
|
||||||
|
$(BASE_OBJECTS): INCLUDES+=-I$(top_srcdir)/base/
|
||||||
|
|
||||||
|
$(top_builddir)/base/libbase.a: $(BASE_OBJECTS)
|
||||||
|
@echo " [AR] $@"
|
||||||
$(Q) $(RM) $@
|
$(Q) $(RM) $@
|
||||||
$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null
|
$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null
|
||||||
|
|
||||||
ifeq ("$(USE_TRACKING)","yes")
|
CLEAN_TARGETS+=$(top_builddir)/base/libbase.a
|
||||||
-include $(BASE_DEPENDS)
|
|
||||||
endif
|
|
||||||
|
|||||||
@@ -22,26 +22,17 @@ struct dm_hash_node {
|
|||||||
void *data;
|
void *data;
|
||||||
unsigned data_len;
|
unsigned data_len;
|
||||||
unsigned keylen;
|
unsigned keylen;
|
||||||
unsigned hash;
|
|
||||||
char key[0];
|
char key[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dm_hash_table {
|
struct dm_hash_table {
|
||||||
unsigned num_nodes;
|
unsigned num_nodes;
|
||||||
unsigned num_hint;
|
unsigned num_slots;
|
||||||
unsigned mask_slots; /* (slots - 1) -> used as hash mask */
|
|
||||||
unsigned collisions; /* Collisions of hash keys */
|
|
||||||
unsigned search; /* How many keys were searched */
|
|
||||||
unsigned found; /* How many nodes were found */
|
|
||||||
unsigned same_hash; /* Was there a collision with same masked hash and len ? */
|
|
||||||
struct dm_hash_node **slots;
|
struct dm_hash_node **slots;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0 /* TO BE REMOVED */
|
|
||||||
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,
|
||||||
@@ -68,14 +59,27 @@ static unsigned _hash(const void *key, unsigned len)
|
|||||||
209
|
209
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t *str = key;
|
static struct dm_hash_node *_create_node(const char *str, unsigned len)
|
||||||
unsigned h = 0, g;
|
{
|
||||||
|
struct dm_hash_node *n = malloc(sizeof(*n) + len);
|
||||||
|
|
||||||
|
if (n) {
|
||||||
|
memcpy(n->key, str, len);
|
||||||
|
n->keylen = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long _hash(const char *str, unsigned len)
|
||||||
|
{
|
||||||
|
unsigned long h = 0, g;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
h <<= 4;
|
h <<= 4;
|
||||||
h += _nums[*str++];
|
h += _nums[(unsigned char) *str++];
|
||||||
g = h & ((unsigned) 0xf << 16u);
|
g = h & ((unsigned long) 0xf << 16u);
|
||||||
if (g) {
|
if (g) {
|
||||||
h ^= g >> 16u;
|
h ^= g >> 16u;
|
||||||
h ^= g >> 5u;
|
h ^= g >> 5u;
|
||||||
@@ -85,99 +89,30 @@ static unsigned _hash(const void *key, unsigned len)
|
|||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In-kernel DM hashing, still lots of collisions */
|
|
||||||
static unsigned _hash_in_kernel(const char *key, unsigned len)
|
|
||||||
{
|
|
||||||
const unsigned char *str = (unsigned char *)key;
|
|
||||||
const unsigned hash_mult = 2654435387U;
|
|
||||||
unsigned hash = 0, i;
|
|
||||||
|
|
||||||
for (i = 0; i < len; ++i)
|
|
||||||
hash = (hash + str[i]) * hash_mult;
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef get16bits
|
|
||||||
#if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
|
|
||||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined (get16bits)
|
|
||||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
|
||||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adapted Bob Jenkins hash to read by 2 bytes if possible.
|
|
||||||
* https://secure.wikimedia.org/wikipedia/en/wiki/Jenkins_hash_function
|
|
||||||
*
|
|
||||||
* Reduces amount of hash collisions
|
|
||||||
*/
|
|
||||||
static unsigned _hash(const void *key, unsigned len)
|
|
||||||
{
|
|
||||||
const uint8_t *str = (uint8_t*) key;
|
|
||||||
unsigned hash = 0, i;
|
|
||||||
unsigned sz = len / 2;
|
|
||||||
|
|
||||||
for(i = 0; i < sz; ++i) {
|
|
||||||
hash += get16bits(str + 2 * i);
|
|
||||||
hash += (hash << 10);
|
|
||||||
hash ^= (hash >> 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len & 1) {
|
|
||||||
hash += str[len - 1];
|
|
||||||
hash += (hash << 10);
|
|
||||||
hash ^= (hash >> 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
hash += (hash << 3);
|
|
||||||
hash ^= (hash >> 11);
|
|
||||||
hash += (hash << 15);
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct dm_hash_node *_create_node(const void *key, unsigned len)
|
|
||||||
{
|
|
||||||
struct dm_hash_node *n = malloc(sizeof(*n) + len);
|
|
||||||
|
|
||||||
if (n) {
|
|
||||||
memcpy(n->key, key, len);
|
|
||||||
n->keylen = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dm_hash_table *dm_hash_create(unsigned size_hint)
|
struct dm_hash_table *dm_hash_create(unsigned size_hint)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned new_size = 16u;
|
unsigned new_size = 16u;
|
||||||
struct dm_hash_table *hc = zalloc(sizeof(*hc));
|
struct dm_hash_table *hc = zalloc(sizeof(*hc));
|
||||||
|
|
||||||
if (!hc) {
|
if (!hc)
|
||||||
log_error("Failed to allocate memory for hash.");
|
return_0;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
hc->num_hint = size_hint;
|
|
||||||
|
|
||||||
/* round size hint up to a power of two */
|
/* round size hint up to a power of two */
|
||||||
while (new_size < size_hint)
|
while (new_size < size_hint)
|
||||||
new_size = new_size << 1;
|
new_size = new_size << 1;
|
||||||
|
|
||||||
hc->mask_slots = new_size - 1;
|
hc->num_slots = new_size;
|
||||||
len = sizeof(*(hc->slots)) * new_size;
|
len = sizeof(*(hc->slots)) * new_size;
|
||||||
if (!(hc->slots = zalloc(len))) {
|
if (!(hc->slots = zalloc(len)))
|
||||||
free(hc);
|
goto_bad;
|
||||||
log_error("Failed to allocate slots for hash.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hc;
|
return hc;
|
||||||
|
|
||||||
|
bad:
|
||||||
|
free(hc->slots);
|
||||||
|
free(hc);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _free_nodes(struct dm_hash_table *t)
|
static void _free_nodes(struct dm_hash_table *t)
|
||||||
@@ -185,16 +120,7 @@ static void _free_nodes(struct dm_hash_table *t)
|
|||||||
struct dm_hash_node *c, *n;
|
struct dm_hash_node *c, *n;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
#ifdef DEBUG
|
for (i = 0; i < t->num_slots; i++)
|
||||||
log_debug("Free hash hint:%d slots:%d nodes:%d (s:%d f:%d c:%d h:%d)",
|
|
||||||
t->num_hint, t->mask_slots + 1, t->num_nodes,
|
|
||||||
t->search, t->found, t->collisions, t->same_hash);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!t->num_nodes)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; i <= t->mask_slots; i++)
|
|
||||||
for (c = t->slots[i]; c; c = n) {
|
for (c = t->slots[i]; c; c = n) {
|
||||||
n = c->next;
|
n = c->next;
|
||||||
free(c);
|
free(c);
|
||||||
@@ -208,30 +134,21 @@ void dm_hash_destroy(struct dm_hash_table *t)
|
|||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dm_hash_node **_findh(struct dm_hash_table *t, const void *key,
|
|
||||||
uint32_t len, unsigned hash)
|
|
||||||
{
|
|
||||||
struct dm_hash_node **c;
|
|
||||||
|
|
||||||
++t->search;
|
|
||||||
for (c = &t->slots[hash & t->mask_slots]; *c; c = &((*c)->next)) {
|
|
||||||
if ((*c)->keylen == len && (*c)->hash == hash) {
|
|
||||||
if (!memcmp(key, (*c)->key, len)) {
|
|
||||||
++t->found;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++t->same_hash;
|
|
||||||
}
|
|
||||||
++t->collisions;
|
|
||||||
}
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct dm_hash_node **_find(struct dm_hash_table *t, const void *key,
|
static struct dm_hash_node **_find(struct dm_hash_table *t, const void *key,
|
||||||
uint32_t len)
|
uint32_t len)
|
||||||
{
|
{
|
||||||
return _findh(t, key, len, _hash(key, len));
|
unsigned h = _hash(key, len) & (t->num_slots - 1);
|
||||||
|
struct dm_hash_node **c;
|
||||||
|
|
||||||
|
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
||||||
|
if ((*c)->keylen != len)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!memcmp(key, (*c)->key, len))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key,
|
void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key,
|
||||||
@@ -245,8 +162,7 @@ void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key,
|
|||||||
int dm_hash_insert_binary(struct dm_hash_table *t, const void *key,
|
int dm_hash_insert_binary(struct dm_hash_table *t, const void *key,
|
||||||
uint32_t len, void *data)
|
uint32_t len, void *data)
|
||||||
{
|
{
|
||||||
unsigned hash = _hash(key, len);
|
struct dm_hash_node **c = _find(t, key, len);
|
||||||
struct dm_hash_node **c = _findh(t, key, len, hash);
|
|
||||||
|
|
||||||
if (*c)
|
if (*c)
|
||||||
(*c)->data = data;
|
(*c)->data = data;
|
||||||
@@ -257,7 +173,6 @@ int dm_hash_insert_binary(struct dm_hash_table *t, const void *key,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
n->data = data;
|
n->data = data;
|
||||||
n->hash = hash;
|
|
||||||
n->next = 0;
|
n->next = 0;
|
||||||
*c = n;
|
*c = n;
|
||||||
t->num_nodes++;
|
t->num_nodes++;
|
||||||
@@ -301,7 +216,7 @@ static struct dm_hash_node **_find_str_with_val(struct dm_hash_table *t,
|
|||||||
struct dm_hash_node **c;
|
struct dm_hash_node **c;
|
||||||
unsigned h;
|
unsigned h;
|
||||||
|
|
||||||
h = _hash(key, len) & t->mask_slots;
|
h = _hash(key, len) & (t->num_slots - 1);
|
||||||
|
|
||||||
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
||||||
if ((*c)->keylen != len)
|
if ((*c)->keylen != len)
|
||||||
@@ -332,7 +247,7 @@ int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key,
|
|||||||
n->data = (void *)val;
|
n->data = (void *)val;
|
||||||
n->data_len = val_len;
|
n->data_len = val_len;
|
||||||
|
|
||||||
h = _hash(key, len) & t->mask_slots;
|
h = _hash(key, len) & (t->num_slots - 1);
|
||||||
|
|
||||||
first = t->slots[h];
|
first = t->slots[h];
|
||||||
|
|
||||||
@@ -348,7 +263,7 @@ int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Look through multiple entries with the same key for one that has a
|
* Look through multiple entries with the same key for one that has a
|
||||||
* matching val and return that. If none have matching val, return NULL.
|
* matching val and return that. If none have maching val, return NULL.
|
||||||
*/
|
*/
|
||||||
void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key,
|
void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key,
|
||||||
const void *val, uint32_t val_len)
|
const void *val, uint32_t val_len)
|
||||||
@@ -400,7 +315,7 @@ void *dm_hash_lookup_with_count(struct dm_hash_table *t, const char *key, int *c
|
|||||||
|
|
||||||
*count = 0;
|
*count = 0;
|
||||||
|
|
||||||
h = _hash(key, len) & t->mask_slots;
|
h = _hash(key, len) & (t->num_slots - 1);
|
||||||
|
|
||||||
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
||||||
if ((*c)->keylen != len)
|
if ((*c)->keylen != len)
|
||||||
@@ -429,7 +344,7 @@ void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f)
|
|||||||
struct dm_hash_node *c, *n;
|
struct dm_hash_node *c, *n;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
for (i = 0; i <= t->mask_slots; i++)
|
for (i = 0; i < t->num_slots; i++)
|
||||||
for (c = t->slots[i]; c; c = n) {
|
for (c = t->slots[i]; c; c = n) {
|
||||||
n = c->next;
|
n = c->next;
|
||||||
f(c->data);
|
f(c->data);
|
||||||
@@ -439,8 +354,8 @@ void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f)
|
|||||||
void dm_hash_wipe(struct dm_hash_table *t)
|
void dm_hash_wipe(struct dm_hash_table *t)
|
||||||
{
|
{
|
||||||
_free_nodes(t);
|
_free_nodes(t);
|
||||||
memset(t->slots, 0, sizeof(struct dm_hash_node *) * (t->mask_slots + 1));
|
memset(t->slots, 0, sizeof(struct dm_hash_node *) * t->num_slots);
|
||||||
t->num_nodes = t->collisions = t->search = t->same_hash = 0u;
|
t->num_nodes = 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *dm_hash_get_key(struct dm_hash_table *t __attribute__((unused)),
|
char *dm_hash_get_key(struct dm_hash_table *t __attribute__((unused)),
|
||||||
@@ -460,7 +375,7 @@ static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s)
|
|||||||
struct dm_hash_node *c = NULL;
|
struct dm_hash_node *c = NULL;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
for (i = s; i <= t->mask_slots && !c; i++)
|
for (i = s; i < t->num_slots && !c; i++)
|
||||||
c = t->slots[i];
|
c = t->slots[i];
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
@@ -473,5 +388,7 @@ struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t)
|
|||||||
|
|
||||||
struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n)
|
struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n)
|
||||||
{
|
{
|
||||||
return n->next ? n->next : _next_slot(t, (n->hash & t->mask_slots) + 1);
|
unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1);
|
||||||
|
|
||||||
|
return n->next ? n->next : _next_slot(t, h + 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#ifndef BASE_DATA_STRUCT_LIST_H
|
#ifndef BASE_DATA_STRUCT_LIST_H
|
||||||
#define BASE_DATA_STRUCT_LIST_H
|
#define BASE_DATA_STRUCT_LIST_H
|
||||||
|
|
||||||
#include "base/memory/container_of.h"
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -100,7 +98,7 @@ struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *e
|
|||||||
* contained in a structure of type t, return the containing structure.
|
* contained in a structure of type t, return the containing structure.
|
||||||
*/
|
*/
|
||||||
#define dm_list_struct_base(v, t, head) \
|
#define dm_list_struct_base(v, t, head) \
|
||||||
container_of(v, t, head)
|
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given the address v of an instance of 'struct dm_list list' contained in
|
* Given the address v of an instance of 'struct dm_list list' contained in
|
||||||
@@ -113,7 +111,7 @@ struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *e
|
|||||||
* return another element f.
|
* return another element f.
|
||||||
*/
|
*/
|
||||||
#define dm_struct_field(v, t, e, f) \
|
#define dm_struct_field(v, t, e, f) \
|
||||||
(((t *)((uintptr_t)(v) - offsetof(t, e)))->f)
|
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given the address v of a known element e in a known structure of type t,
|
* Given the address v of a known element e in a known structure of type t,
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
@@ -48,7 +46,7 @@ struct value_chain {
|
|||||||
struct prefix_chain {
|
struct prefix_chain {
|
||||||
struct value child;
|
struct value child;
|
||||||
unsigned len;
|
unsigned len;
|
||||||
uint8_t prefix[];
|
uint8_t prefix[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct node4 {
|
struct node4 {
|
||||||
@@ -179,9 +177,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;
|
||||||
|
|
||||||
@@ -191,8 +189,8 @@ static bool _insert_unset(struct radix_tree *rt, struct value *v, const uint8_t
|
|||||||
v->value = rv;
|
v->value = rv;
|
||||||
rt->nr_entries++;
|
rt->nr_entries++;
|
||||||
} else {
|
} else {
|
||||||
// prefix -> value (all fields explicitly initialized)
|
// prefix -> value
|
||||||
struct prefix_chain *pc = malloc(sizeof(*pc) + len);
|
struct prefix_chain *pc = zalloc(sizeof(*pc) + len);
|
||||||
if (!pc)
|
if (!pc)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -208,7 +206,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 +233,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 +247,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;
|
||||||
|
|
||||||
@@ -267,9 +265,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
|
|||||||
if (kb[i] != pc->prefix[i])
|
if (kb[i] != pc->prefix[i])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// All fields of pc2 are explicitly initialized
|
pc2 = zalloc(sizeof(*pc2) + pc->len - i);
|
||||||
if (!(pc2 = malloc(sizeof(*pc2) + pc->len - i)))
|
|
||||||
return false;
|
|
||||||
pc2->len = pc->len - i;
|
pc2->len = pc->len - i;
|
||||||
memmove(pc2->prefix, pc->prefix + i, pc2->len);
|
memmove(pc2->prefix, pc->prefix + i, pc2->len);
|
||||||
pc2->child = pc->child;
|
pc2->child = pc->child;
|
||||||
@@ -280,7 +276,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
|
|||||||
pc->len = i;
|
pc->len = i;
|
||||||
|
|
||||||
if (!_insert(rt, &pc->child, kb + i, ke, rv)) {
|
if (!_insert(rt, &pc->child, kb + i, ke, rv)) {
|
||||||
free(pc->child.value.ptr);
|
free(pc2);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +290,6 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
|
|||||||
if (pc->len == 1) {
|
if (pc->len == 1) {
|
||||||
n4->values[0] = pc->child;
|
n4->values[0] = pc->child;
|
||||||
free(pc);
|
free(pc);
|
||||||
v->value.ptr = NULL;
|
|
||||||
} else {
|
} else {
|
||||||
memmove(pc->prefix, pc->prefix + 1, pc->len - 1);
|
memmove(pc->prefix, pc->prefix + 1, pc->len - 1);
|
||||||
pc->len--;
|
pc->len--;
|
||||||
@@ -316,7 +311,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) {
|
||||||
@@ -346,7 +341,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;
|
||||||
|
|
||||||
@@ -358,7 +353,6 @@ static bool _insert_node16(struct radix_tree *rt, struct value *v, const uint8_t
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
n48->nr_entries = 17;
|
n48->nr_entries = 17;
|
||||||
/* coverity[bad_memset] intentional use of '0' */
|
|
||||||
memset(n48->keys, 48, sizeof(n48->keys));
|
memset(n48->keys, 48, sizeof(n48->keys));
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
@@ -385,7 +379,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) {
|
||||||
@@ -420,7 +414,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;
|
||||||
@@ -433,7 +427,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) {
|
||||||
@@ -445,8 +439,7 @@ static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, c
|
|||||||
v->value = rv;
|
v->value = rv;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// All fields explicitly initialized
|
struct value_chain *vc = zalloc(sizeof(*vc));
|
||||||
struct value_chain *vc = malloc(sizeof(*vc));
|
|
||||||
if (!vc)
|
if (!vc)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -491,10 +484,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;
|
||||||
@@ -504,7 +497,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) {
|
||||||
@@ -559,19 +552,24 @@ static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, c
|
|||||||
return (struct lookup_result) {.v = v, .kb = kb};
|
return (struct lookup_result) {.v = v, .kb = kb};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value rv)
|
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = key;
|
|
||||||
const uint8_t *ke = kb + keylen;
|
|
||||||
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
||||||
return _insert(rt, lr.v, lr.kb, ke, rv);
|
return _insert(rt, lr.v, lr.kb, ke, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int radix_tree_uniq_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value rv)
|
// Note the degrade functions also free the original node.
|
||||||
|
static void _degrade_to_n4(struct node16 *n16, struct value *result)
|
||||||
{
|
{
|
||||||
unsigned entries = rt->nr_entries;
|
struct node4 *n4 = zalloc(sizeof(*n4));
|
||||||
return radix_tree_insert(rt, key, keylen, rv) ?
|
|
||||||
((entries != rt->nr_entries) ? 1 : -1) : 0;
|
n4->nr_entries = n16->nr_entries;
|
||||||
|
memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys));
|
||||||
|
memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values));
|
||||||
|
free(n16);
|
||||||
|
|
||||||
|
result->type = NODE4;
|
||||||
|
result->value.ptr = n4;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _degrade_to_n16(struct node48 *n48, struct value *result)
|
static void _degrade_to_n16(struct node48 *n48, struct value *result)
|
||||||
@@ -579,8 +577,6 @@ static void _degrade_to_n16(struct node48 *n48, struct value *result)
|
|||||||
unsigned i, count = 0;
|
unsigned i, count = 0;
|
||||||
struct node16 *n16 = zalloc(sizeof(*n16));
|
struct node16 *n16 = zalloc(sizeof(*n16));
|
||||||
|
|
||||||
assert(n16 != NULL);
|
|
||||||
|
|
||||||
n16->nr_entries = n48->nr_entries;
|
n16->nr_entries = n48->nr_entries;
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
if (n48->keys[i] < 48) {
|
if (n48->keys[i] < 48) {
|
||||||
@@ -601,8 +597,6 @@ static void _degrade_to_n48(struct node256 *n256, struct value *result)
|
|||||||
unsigned i, count = 0;
|
unsigned i, count = 0;
|
||||||
struct node48 *n48 = zalloc(sizeof(*n48));
|
struct node48 *n48 = zalloc(sizeof(*n48));
|
||||||
|
|
||||||
assert(n48 != NULL);
|
|
||||||
|
|
||||||
n48->nr_entries = n256->nr_entries;
|
n48->nr_entries = n256->nr_entries;
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
if (n256->values[i].type == UNSET)
|
if (n256->values[i].type == UNSET)
|
||||||
@@ -622,21 +616,21 @@ static void _degrade_to_n48(struct node256 *n256, struct value *result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Removes an entry in an array by sliding the values above it down.
|
// Removes an entry in an array by sliding the values above it down.
|
||||||
static void _erase_elt(void *array, size_t obj_size, unsigned count, unsigned idx)
|
static void _erase_elt(void *array, unsigned obj_size, unsigned count, unsigned index)
|
||||||
{
|
{
|
||||||
if (idx == (count - 1))
|
if (index == (count - 1))
|
||||||
// The simple case
|
// The simple case
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memmove(((uint8_t *) array) + (obj_size * idx),
|
memmove(((uint8_t *) array) + (obj_size * index),
|
||||||
((uint8_t *) array) + (obj_size * (idx + 1)),
|
((uint8_t *) array) + (obj_size * (index + 1)),
|
||||||
obj_size * (count - idx - 1));
|
obj_size * (count - index - 1));
|
||||||
|
|
||||||
// Zero the now unused last elt (set's v.type to UNSET)
|
// Zero the now unused last elt (set's v.type to UNSET)
|
||||||
memset(((uint8_t *) array) + (count - 1) * obj_size, 0, obj_size);
|
memset(((uint8_t *) array) + (count - 1) * obj_size, 0, obj_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb, const uint8_t *ke)
|
static bool _remove(struct radix_tree *rt, struct value *root, uint8_t *kb, uint8_t *ke)
|
||||||
{
|
{
|
||||||
bool r;
|
bool r;
|
||||||
unsigned i, j;
|
unsigned i, j;
|
||||||
@@ -654,10 +648,9 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else if (root->type == VALUE_CHAIN) {
|
} else if (root->type == VALUE_CHAIN) {
|
||||||
// Free value_chain after copying child out
|
|
||||||
vc = root->value.ptr;
|
vc = root->value.ptr;
|
||||||
_dtr(rt, vc->value);
|
_dtr(rt, vc->value);
|
||||||
*root = vc->child;
|
memcpy(root, &vc->child, sizeof(*root));
|
||||||
free(vc);
|
free(vc);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -731,9 +724,8 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
|
|||||||
}
|
}
|
||||||
|
|
||||||
n16->nr_entries--;
|
n16->nr_entries--;
|
||||||
if (!n16->nr_entries) {
|
if (n16->nr_entries <= 4) {
|
||||||
free(n16);
|
_degrade_to_n4(n16, root);
|
||||||
root->type = UNSET;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
@@ -774,12 +766,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;
|
||||||
}
|
}
|
||||||
@@ -789,13 +778,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])
|
||||||
@@ -807,7 +796,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;
|
||||||
@@ -888,10 +877,8 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
|
|||||||
}
|
}
|
||||||
|
|
||||||
n16->nr_entries--;
|
n16->nr_entries--;
|
||||||
if (!n16->nr_entries) {
|
if (n16->nr_entries <= 4)
|
||||||
free(n16);
|
_degrade_to_n4(n16, root);
|
||||||
root->type = UNSET;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -935,10 +922,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))
|
||||||
@@ -949,11 +934,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) {
|
||||||
@@ -976,15 +959,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:
|
||||||
@@ -992,41 +975,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;
|
||||||
}
|
}
|
||||||
@@ -1035,14 +1018,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);
|
_iterate(lr.v, it);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
@@ -1217,7 +1198,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;
|
||||||
@@ -1242,22 +1222,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;
|
||||||
@@ -1266,7 +1233,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++)
|
||||||
@@ -1277,7 +1244,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++)
|
||||||
@@ -1289,7 +1256,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++) {
|
||||||
@@ -1303,7 +1270,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,21 +172,20 @@ 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 *prefix, size_t prefix_len)
|
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = prefix;
|
|
||||||
const uint8_t *ke = kb + prefix_len;
|
|
||||||
struct node **pn;
|
struct node **pn;
|
||||||
unsigned count = 0;
|
unsigned count;
|
||||||
|
|
||||||
pn = _lookup(&rt->root, kb, ke);
|
pn = _lookup(&rt->root, kb, ke);
|
||||||
|
|
||||||
@@ -210,19 +197,16 @@ unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, siz
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
|
bool
|
||||||
union radix_value *result)
|
radix_tree_lookup(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value *result)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = key;
|
|
||||||
const uint8_t *ke = kb + keylen;
|
|
||||||
struct node **pn = _lookup(&rt->root, kb, ke);
|
struct node **pn = _lookup(&rt->root, kb, ke);
|
||||||
struct node *n = *pn;
|
struct node *n = *pn;
|
||||||
|
|
||||||
if (n && n->has_value) {
|
if (n && n->has_value) {
|
||||||
*result = n->value;
|
*result = n->value;
|
||||||
return true;
|
return true;
|
||||||
}
|
} else
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,18 +219,15 @@ static void _iterate(struct node *n, struct radix_tree_iterator *it)
|
|||||||
|
|
||||||
if (n->has_value)
|
if (n->has_value)
|
||||||
// FIXME: fill out the key
|
// FIXME: fill out the key
|
||||||
it->visit(it, NULL, 0, n->value);
|
it->visit(it, NULL, NULL, n->value);
|
||||||
|
|
||||||
_iterate(n->center, it);
|
_iterate(n->center, it);
|
||||||
_iterate(n->right, it);
|
_iterate(n->right, it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
|
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
|
||||||
struct radix_tree_iterator *it)
|
struct radix_tree_iterator *it)
|
||||||
{
|
{
|
||||||
const uint8_t *kb = key;
|
|
||||||
const uint8_t *ke = kb + keylen;
|
|
||||||
|
|
||||||
if (kb == ke)
|
if (kb == ke)
|
||||||
_iterate(rt->root, it);
|
_iterate(rt->root, it);
|
||||||
|
|
||||||
@@ -256,7 +237,7 @@ void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
|
|||||||
|
|
||||||
if (n) {
|
if (n) {
|
||||||
if (n->has_value)
|
if (n->has_value)
|
||||||
it->visit(it, NULL, 0, n->value);
|
it->visit(it, NULL, NULL, n->value);
|
||||||
_iterate(n->center, it);
|
_iterate(n->center, it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,32 +248,8 @@ bool radix_tree_is_well_formed(struct radix_tree *rt)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dump(FILE *out, struct node *n, unsigned indent)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
if (!n)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_dump(out, n->left, indent + 1);
|
|
||||||
|
|
||||||
for (i = 0; i < 2 * indent; i++)
|
|
||||||
fprintf(out, " ");
|
|
||||||
|
|
||||||
if (n->has_value) {
|
|
||||||
fprintf(out, "value: %lu\n", (unsigned long) n->value.n);
|
|
||||||
} else {
|
|
||||||
fprintf(out, "key: '%c' [0x%02x] %u\n",
|
|
||||||
isprint(n->key) ? n->key : ' ', n->key, indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
_dump(out, n->center, indent + 1);
|
|
||||||
_dump(out, n->right, indent + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void radix_tree_dump(struct radix_tree *rt, FILE *out)
|
void radix_tree_dump(struct radix_tree *rt, FILE *out)
|
||||||
{
|
{
|
||||||
_dump(out, rt->root, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|||||||
@@ -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,18 +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: 1 success
|
|
||||||
// 0 failure during insert
|
|
||||||
// -1 key had already existing value (that was updated)
|
|
||||||
int radix_tree_uniq_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value v);
|
|
||||||
|
|
||||||
// Returns the number of values removed
|
// Returns the number of values removed
|
||||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, size_t prefix_len);
|
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *prefix_b, uint8_t *prefix_e);
|
||||||
|
|
||||||
bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
|
bool radix_tree_lookup(struct radix_tree *rt,
|
||||||
union radix_value *result);
|
uint8_t *kb, uint8_t *ke, union radix_value *result);
|
||||||
|
|
||||||
// The radix tree stores entries in lexicographical order. Which means
|
// The radix tree stores entries in lexicographical order. Which means
|
||||||
// we can iterate entries, in order. Or iterate entries with a particular
|
// we can iterate entries, in order. Or iterate entries with a particular
|
||||||
@@ -52,42 +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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int radix_tree_uniq_insert_ptr(struct radix_tree *rt, const void *key, size_t keylen, void *ptr)
|
|
||||||
{
|
|
||||||
union radix_value v = { .ptr = ptr };
|
|
||||||
return radix_tree_uniq_insert(rt, key, keylen, v);
|
|
||||||
}
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2018 - 2020 Red Hat, Inc. All rights reserved.
|
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
// This file is part of LVM2.
|
// This file is part of LVM2.
|
||||||
//
|
//
|
||||||
@@ -13,12 +13,10 @@
|
|||||||
#ifndef BASE_MEMORY_CONTAINER_OF_H
|
#ifndef BASE_MEMORY_CONTAINER_OF_H
|
||||||
#define BASE_MEMORY_CONTAINER_OF_H
|
#define BASE_MEMORY_CONTAINER_OF_H
|
||||||
|
|
||||||
#include <stddef.h> // offsetof
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
#define container_of(v, t, head) \
|
#define container_of(v, t, head) \
|
||||||
((t *)((char *)(v) - offsetof(t, head)))
|
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -14,12 +14,16 @@
|
|||||||
#define BASE_MEMORY_ZALLOC_H
|
#define BASE_MEMORY_ZALLOC_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
static inline void *zalloc(size_t len)
|
static inline void *zalloc(size_t len)
|
||||||
{
|
{
|
||||||
return calloc(1, len);
|
void *ptr = malloc(len);
|
||||||
|
if (ptr)
|
||||||
|
memset(ptr, 0, len);
|
||||||
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|||||||
@@ -49,9 +49,8 @@ install_localconf: $(CONFLOCAL)
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
install_profiles: $(PROFILES)
|
install_profiles: $(PROFILES)
|
||||||
$(SHOW) " [INSTALL] $<"
|
$(INSTALL_DIR) $(profiledir)
|
||||||
$(Q) $(INSTALL_DIR) $(profiledir)
|
$(INSTALL_DATA) $(PROFILES) $(profiledir)/
|
||||||
$(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/
|
|
||||||
|
|
||||||
install_lvm2: install_conf install_localconf install_profiles
|
install_lvm2: install_conf install_localconf install_profiles
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -38,14 +38,6 @@ local {
|
|||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# system_id = ""
|
# system_id = ""
|
||||||
|
|
||||||
# Configuration option local/pr_key.
|
|
||||||
# The local persistent reservation key in hexadecimal.
|
|
||||||
# The value must be unique among all hosts using the same VG.
|
|
||||||
# The max length is 16 hex characters (8 bytes), plus an optional
|
|
||||||
# 0x prefix. If pr_key is not set, host_id will be used to create a key.
|
|
||||||
# This configuration option has an automatic default value.
|
|
||||||
# pr_key = ""
|
|
||||||
|
|
||||||
# Configuration option local/extra_system_ids.
|
# Configuration option local/extra_system_ids.
|
||||||
# A list of extra VG system IDs the local host can access.
|
# A list of extra VG system IDs the local host can access.
|
||||||
# VGs with the system IDs listed here (in addition to the host's own
|
# VGs with the system IDs listed here (in addition to the host's own
|
||||||
@@ -57,12 +49,9 @@ local {
|
|||||||
# This configuration option does not have a default value defined.
|
# This configuration option does not have a default value defined.
|
||||||
|
|
||||||
# Configuration option local/host_id.
|
# Configuration option local/host_id.
|
||||||
# The sanlock host_id used by lvmlockd. This must be unique among all the hosts
|
# The lvmlockd sanlock host_id.
|
||||||
# using shared VGs with sanlock. Accepted values are 1-2000, except when sanlock_align_size
|
# This must be unique among all hosts, and must be between 1 and 2000.
|
||||||
# is configured to 1, 2 or 4, which correspond to max host_id values of 250, 500, or 1000.
|
# Applicable only if LVM is compiled with lockd support
|
||||||
# When using persistent reservations, lvm will generate a PR key from the host_id
|
|
||||||
# if pr_key is not defined. All hosts using a sanlock shared VG with PR must use
|
|
||||||
# the same approach for configuring their PR key (pr_key or host_id.)
|
|
||||||
# This configuration option has an automatic default value.
|
# This configuration option has an automatic default value.
|
||||||
# host_id = 0
|
# host_id = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
# Demo configuration for 'VDO' using less memory.
|
# Demo configuration for 'VDO' using less memory.
|
||||||
# ~lvmconfig --type full | grep vdo
|
#
|
||||||
|
|
||||||
allocation {
|
allocation {
|
||||||
vdo_use_compression = 1
|
vdo_use_compression = 1
|
||||||
vdo_use_deduplication = 1
|
vdo_use_deduplication = 1
|
||||||
vdo_minimum_io_size=4096
|
vdo_emulate_512_sectors = 0
|
||||||
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_use_read_cache = 0
|
||||||
|
vdo_read_cache_size_mb = 0
|
||||||
vdo_slab_size_mb = 2048
|
vdo_slab_size_mb = 2048
|
||||||
|
|
||||||
vdo_ack_threads = 1
|
vdo_ack_threads = 1
|
||||||
vdo_bio_threads = 1
|
vdo_bio_threads = 1
|
||||||
vdo_bio_rotation = 64
|
vdo_bio_rotation = 64
|
||||||
@@ -17,5 +21,5 @@ allocation {
|
|||||||
vdo_hash_zone_threads = 1
|
vdo_hash_zone_threads = 1
|
||||||
vdo_logical_threads = 1
|
vdo_logical_threads = 1
|
||||||
vdo_physical_threads = 1
|
vdo_physical_threads = 1
|
||||||
vdo_max_discard=1
|
vdo_write_policy = "auto"
|
||||||
}
|
}
|
||||||
|
|||||||
1786
configure.ac
1786
configure.ac
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2015 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -21,340 +21,126 @@
|
|||||||
* compile (using outdir 'cov'):
|
* compile (using outdir 'cov'):
|
||||||
* cov-build --dir=cov make CC=gcc
|
* cov-build --dir=cov make CC=gcc
|
||||||
*
|
*
|
||||||
* analyze (aggressively, using 'cov')
|
* analyze (agressively, using 'cov')
|
||||||
* cov-analyze --dir cov --wait-for-license --hfa --concurrency --enable-fnptr --enable-constraint-fpp --security --all --aggressiveness-level=high --field-offset-escape --user-model-file=coverity/coverity_model.xml
|
* cov-analyze --dir cov --wait-for-license --hfa --concurrency --enable-fnptr --enable-constraint-fpp --security --all --aggressiveness-level=high --field-offset-escape --user-model-file=coverity/coverity_model.xml
|
||||||
*
|
*
|
||||||
* generate html output (to 'html' from 'cov'):
|
* generate html output (to 'html' from 'cov'):
|
||||||
* cov-format-errors --dir cov --html-output html
|
* cov-format-errors --dir cov --html-output html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Define NULL for Coverity modeling */
|
|
||||||
#define NULL ((void *)0)
|
|
||||||
|
|
||||||
/* Forward declarations */
|
|
||||||
struct lv_segment;
|
struct lv_segment;
|
||||||
struct logical_volume;
|
struct logical_volume;
|
||||||
struct cmd_context;
|
|
||||||
struct profile;
|
|
||||||
struct dm_pool;
|
|
||||||
struct dm_list;
|
|
||||||
|
|
||||||
/* Partial definition of segment_type - only fields we need for modeling */
|
|
||||||
struct segment_type {
|
|
||||||
const char *name;
|
|
||||||
const char *dso;
|
|
||||||
/* other fields omitted */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* These functions never return NULL for valid LVs with segments
|
|
||||||
*/
|
|
||||||
struct lv_segment *first_seg(const struct logical_volume *lv)
|
struct lv_segment *first_seg(const struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct lv_segment *seg;
|
return ((struct lv_segment **)lv)[0];
|
||||||
|
|
||||||
/* Model: assume lv is valid and has at least one segment */
|
|
||||||
if (lv) {
|
|
||||||
__coverity_read_pointee__(lv);
|
|
||||||
return seg;
|
|
||||||
}
|
|
||||||
|
|
||||||
__coverity_panic__(); /* Should never happen in valid code */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lv_segment *last_seg(const struct logical_volume *lv)
|
struct lv_segment *last_seg(const struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct lv_segment *seg;
|
return ((struct lv_segment **)lv)[0];
|
||||||
|
|
||||||
if (lv) {
|
|
||||||
__coverity_read_pointee__(lv);
|
|
||||||
return seg;
|
|
||||||
}
|
|
||||||
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile)
|
const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile)
|
||||||
{
|
{
|
||||||
char *str;
|
return "STRING";
|
||||||
|
|
||||||
__coverity_read_pointee__(cmd);
|
|
||||||
|
|
||||||
if (str)
|
|
||||||
return str;
|
|
||||||
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, struct profile *profile)
|
struct logical_volume *origin_from_cow(const struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
char *str;
|
if (lv)
|
||||||
|
return lv;
|
||||||
__coverity_read_pointee__(cmd);
|
|
||||||
|
|
||||||
if (str)
|
|
||||||
return str;
|
|
||||||
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct segment_type *init_unknown_segtype(struct cmd_context *cmd, const char *name)
|
|
||||||
{
|
|
||||||
struct segment_type *seg_type;
|
|
||||||
|
|
||||||
__coverity_read_pointee__(cmd);
|
|
||||||
__coverity_read_pointee__(name);
|
|
||||||
|
|
||||||
if (seg_type)
|
|
||||||
return seg_type;
|
|
||||||
|
|
||||||
__coverity_panic__();
|
__coverity_panic__();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* simple_memccpy() from glibc */
|
/* simple_memccpy() from glibc */
|
||||||
void *memccpy(void *dest, const void *src, int c, unsigned long n)
|
void *memccpy(void *dest, const void *src, int c, size_t n)
|
||||||
{
|
{
|
||||||
int success;
|
const char *s = src;
|
||||||
|
char *d = dest;
|
||||||
|
|
||||||
__coverity_negative_sink__(n);
|
while (n-- > 0)
|
||||||
__coverity_negative_sink__(c);
|
if ((*d++ = *s++) == (char) c)
|
||||||
__coverity_tainted_data_transitive__(dest, src);
|
return d;
|
||||||
__coverity_write_buffer_bytes__(dest, n);
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dm_pool_alloc - can return NULL on allocation failure */
|
|
||||||
void *dm_pool_alloc(struct dm_pool *p, unsigned long s)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
int success;
|
|
||||||
|
|
||||||
if (!p) {
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
|
||||||
|
|
||||||
__coverity_negative_sink__(s); /* Catch negative sizes */
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ptr = __coverity_alloc__(s);
|
|
||||||
|
|
||||||
/* Mark as escaped - pool memory doesn't need individual free */
|
|
||||||
__coverity_escape__(ptr);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dm_pool_zalloc - allocates and zeros */
|
|
||||||
void *dm_pool_zalloc(struct dm_pool *p, unsigned long s)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
int success;
|
|
||||||
|
|
||||||
if (!p) {
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
|
||||||
|
|
||||||
__coverity_negative_sink__(s); /* Catch negative sizes */
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ptr = __coverity_alloc__(s);
|
|
||||||
__coverity_writeall0__(ptr); /* Memory is zeroed */
|
|
||||||
|
|
||||||
/* Mark as escaped - pool memory doesn't need individual free */
|
|
||||||
__coverity_escape__(ptr);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dm_pool_strdup - duplicates string in pool */
|
|
||||||
char *dm_pool_strdup(struct dm_pool *p, const char *str)
|
|
||||||
{
|
|
||||||
char *ptr;
|
|
||||||
unsigned long size;
|
|
||||||
int success;
|
|
||||||
|
|
||||||
if (!p || !str) {
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
|
||||||
|
|
||||||
__coverity_string_null_sink__(str); /* str must be null-terminated */
|
|
||||||
__coverity_string_size_sink__(str); /* Coverity tracks the size */
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Allocate symbolic size - Coverity will track this appropriately */
|
|
||||||
ptr = __coverity_alloc__(size);
|
|
||||||
__coverity_tainted_data_transitive__(ptr, str);
|
|
||||||
|
|
||||||
/* Mark as escaped - pool memory doesn't need individual free */
|
|
||||||
__coverity_escape__(ptr);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dm_pool_strndup - duplicates up to n characters */
|
|
||||||
char *dm_pool_strndup(struct dm_pool *p, const char *str, unsigned long n)
|
|
||||||
{
|
|
||||||
char *ptr;
|
|
||||||
int success;
|
|
||||||
|
|
||||||
if (!p) {
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
|
||||||
__coverity_string_size_source__(str);
|
|
||||||
__coverity_negative_sink__(n);
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ptr = __coverity_alloc__(n + 1);
|
|
||||||
|
|
||||||
__coverity_tainted_data_transitive__(ptr, str);
|
|
||||||
__coverity_string_null_copy__(ptr, str, n);
|
|
||||||
|
|
||||||
/* Mark as escaped - pool memory doesn't need individual free */
|
|
||||||
__coverity_escape__(ptr);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dm_pool_free - frees memory back to the pool */
|
|
||||||
void dm_pool_free(struct dm_pool *p, void *ptr)
|
|
||||||
{
|
|
||||||
if (!p || !ptr) {
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dm_pool_empty(struct dm_pool *p)
|
|
||||||
{
|
|
||||||
if (!p) {
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dm_malloc - standard malloc wrapper */
|
|
||||||
void *dm_malloc_wrapper(unsigned long s, const char *file, int line)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
int success;
|
|
||||||
|
|
||||||
__coverity_negative_sink__(s);
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ptr = __coverity_alloc__(s);
|
|
||||||
|
|
||||||
__coverity_mark_as_afm_allocated__(ptr, AFM_free);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dm_zalloc - standard calloc wrapper */
|
|
||||||
void *dm_zalloc_wrapper(unsigned long s, const char *file, int line)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
int success;
|
|
||||||
|
|
||||||
__coverity_negative_sink__(s);
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ptr = __coverity_alloc__(s);
|
|
||||||
|
|
||||||
__coverity_mark_as_afm_allocated__(ptr, AFM_free);
|
|
||||||
__coverity_writeall0__(ptr);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dm_free - standard free wrapper */
|
|
||||||
void dm_free_wrapper(void *ptr, const char *file, int line)
|
|
||||||
{
|
|
||||||
if (ptr) {
|
|
||||||
__coverity_free__(ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* dm_list_init - initializes a list head */
|
|
||||||
void dm_list_init(struct dm_list *head)
|
|
||||||
{
|
|
||||||
if (head) {
|
|
||||||
__coverity_writeall__(head);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dm_list_empty - checks if list is empty (never fails) */
|
|
||||||
int dm_list_empty(const struct dm_list *head)
|
|
||||||
{
|
|
||||||
int is_empty;
|
|
||||||
|
|
||||||
if (head)
|
|
||||||
return is_empty;
|
|
||||||
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dm_list_add - adds to list (never fails) */
|
|
||||||
void dm_list_add(struct dm_list *head, struct dm_list *elem)
|
|
||||||
{
|
|
||||||
if (!head || !elem) {
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Modification happens, but no failure */
|
|
||||||
__coverity_writeall__(head);
|
|
||||||
__coverity_writeall__(elem);
|
|
||||||
__coverity_escape__(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct segtype_library;
|
|
||||||
|
|
||||||
/* lvm_register_segtype - registers a segment type
|
|
||||||
* Returns 1 on success, 0 on failure
|
|
||||||
* On failure, it calls segtype->ops->destroy(segtype) which frees the resource
|
|
||||||
* On success, the segtype is added to the list and ownership is transferred
|
|
||||||
*/
|
|
||||||
int lvm_register_segtype(struct segtype_library *seglib,
|
|
||||||
struct segment_type *segtype)
|
|
||||||
{
|
|
||||||
int success;
|
|
||||||
char *dso;
|
|
||||||
|
|
||||||
if (!seglib || !segtype) {
|
|
||||||
__coverity_panic__();
|
|
||||||
}
|
|
||||||
|
|
||||||
__coverity_read_pointee__(seglib);
|
|
||||||
__coverity_read_pointee__(segtype);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
/* On failure, the function calls segtype->ops->destroy(segtype)
|
|
||||||
* which frees both segtype->dso and segtype itself */
|
|
||||||
|
|
||||||
/* Read dso field and mark it as freed if it exists */
|
|
||||||
dso = segtype->dso;
|
|
||||||
if (dso)
|
|
||||||
__coverity_free__(dso);
|
|
||||||
|
|
||||||
/* Then free the segtype structure itself */
|
|
||||||
__coverity_free__(segtype);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On success, segtype is added to the list and ownership transfers */
|
/*
|
||||||
__coverity_escape__(segtype);
|
* 2 lines bellow needs to be placed in coverity/config/user_nodefs.h
|
||||||
return 1;
|
* Not sure about any other way.
|
||||||
|
* Without them, coverity shows warning since x86 system header files
|
||||||
|
* are using inline assembly to reset fdset
|
||||||
|
*/
|
||||||
|
//#nodef FD_ZERO model_FD_ZERO
|
||||||
|
//void model_FD_ZERO(void *fdset);
|
||||||
|
|
||||||
|
void model_FD_ZERO(void *fdset)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < 1024 / 8 / sizeof(long); ++i)
|
||||||
|
((long*)fdset)[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Resent Coverity reports quite weird errors... */
|
||||||
|
int *__errno_location(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
const unsigned short **__ctype_b_loc (void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Added extra pointer check to not need these models,
|
||||||
|
* for now just keep then in file
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
struct cmd_context;
|
||||||
|
struct profile;
|
||||||
|
|
||||||
|
const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile)
|
||||||
|
{
|
||||||
|
return "text";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, struct profile *profile)
|
||||||
|
{
|
||||||
|
return "text";
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Until fixed coverity case# 00531860:
|
||||||
|
* A FORWARD_NULL false positive on a recursive function call
|
||||||
|
*
|
||||||
|
* model also these functions:
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
const struct dm_config_node;
|
||||||
|
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile)
|
||||||
|
{
|
||||||
|
const struct dm_config_node *cn;
|
||||||
|
|
||||||
|
return cn;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, int id, struct profile *profile)
|
||||||
|
{
|
||||||
|
const struct dm_config_node *cn;
|
||||||
|
|
||||||
|
return cn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|||||||
@@ -22,22 +22,15 @@ SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c
|
|||||||
|
|
||||||
TARGETS = cmirrord
|
TARGETS = cmirrord
|
||||||
|
|
||||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
|
||||||
CFLOW_TARGET := $(TARGETS)
|
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
LMLIBS += $(CPG_LIBS)
|
LMLIBS += $(CPG_LIBS)
|
||||||
CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
||||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||||
|
|
||||||
cmirrord: $(OBJECTS)
|
cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
|
||||||
$(SHOW) " [CC] $@"
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
$(LVMLIBS) $(LMLIBS) $(INTERNAL_LIBS) $(LIBS)
|
||||||
$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS)
|
|
||||||
|
|
||||||
install_cluster: $(TARGETS)
|
install: $(TARGETS)
|
||||||
$(SHOW) " [INSTALL] $<"
|
$(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(usrsbindir)/$(<F)
|
|
||||||
|
|
||||||
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;
|
||||||
@@ -245,7 +245,6 @@ static void daemonize(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
|
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
|
||||||
/* coverity[leaked_handle] devnull cannot leak here */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#include "link_mon.h"
|
#include "link_mon.h"
|
||||||
#include "local.h"
|
#include "local.h"
|
||||||
#include "lib/mm/xlate.h"
|
#include "lib/mm/xlate.h"
|
||||||
#include "base/memory/zalloc.h"
|
|
||||||
|
|
||||||
/* FIXME: remove this and the code */
|
/* FIXME: remove this and the code */
|
||||||
#define CMIRROR_HAS_CHECKPOINT 0
|
#define CMIRROR_HAS_CHECKPOINT 0
|
||||||
@@ -108,7 +107,7 @@ static SaVersionT version = { 'B', 1, 1 };
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUGGING_HISTORY 100
|
#define DEBUGGING_HISTORY 100
|
||||||
#define DEBUGGING_BUFLEN 270
|
#define DEBUGGING_BUFLEN 128
|
||||||
#define LOG_SPRINT(cc, f, arg...) do { \
|
#define LOG_SPRINT(cc, f, arg...) do { \
|
||||||
cc->idx++; \
|
cc->idx++; \
|
||||||
cc->idx = cc->idx % DEBUGGING_HISTORY; \
|
cc->idx = cc->idx % DEBUGGING_HISTORY; \
|
||||||
@@ -197,7 +196,7 @@ int cluster_send(struct clog_request *rq)
|
|||||||
iov.iov_base = rq;
|
iov.iov_base = rq;
|
||||||
iov.iov_len = sizeof(struct clog_request) + rq->u_rq.data_size;
|
iov.iov_len = sizeof(struct clog_request) + rq->u_rq.data_size;
|
||||||
|
|
||||||
rq->u.version[0] = htole64(CLOG_TFR_VERSION);
|
rq->u.version[0] = xlate64(CLOG_TFR_VERSION);
|
||||||
rq->u.version[1] = CLOG_TFR_VERSION;
|
rq->u.version[1] = CLOG_TFR_VERSION;
|
||||||
|
|
||||||
r = clog_request_to_network(rq);
|
r = clog_request_to_network(rq);
|
||||||
@@ -279,7 +278,7 @@ static int handle_cluster_request(struct clog_cpg *entry __attribute__((unused))
|
|||||||
* With resumes, we only handle our own.
|
* With resumes, we only handle our own.
|
||||||
* Resume is a special case that requires
|
* Resume is a special case that requires
|
||||||
* local action (to set up CPG), followed by
|
* local action (to set up CPG), followed by
|
||||||
* a cluster action to coordinate reading
|
* a cluster action to co-ordinate reading
|
||||||
* the disk and checkpointing
|
* the disk and checkpointing
|
||||||
*/
|
*/
|
||||||
if (tmp->u_rq.request_type == DM_ULOG_RESUME) {
|
if (tmp->u_rq.request_type == DM_ULOG_RESUME) {
|
||||||
@@ -403,12 +402,13 @@ static struct checkpoint_data *prepare_checkpoint(struct clog_cpg *entry,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = zalloc(sizeof(*new));
|
new = malloc(sizeof(*new));
|
||||||
if (!new) {
|
if (!new) {
|
||||||
LOG_ERROR("Unable to create checkpoint data for %u",
|
LOG_ERROR("Unable to create checkpoint data for %u",
|
||||||
cp_requester);
|
cp_requester);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
memset(new, 0, sizeof(*new));
|
||||||
new->requester = cp_requester;
|
new->requester = cp_requester;
|
||||||
strncpy(new->uuid, entry->name.value, entry->name.length);
|
strncpy(new->uuid, entry->name.value, entry->name.length);
|
||||||
|
|
||||||
@@ -643,12 +643,13 @@ static int export_checkpoint(struct checkpoint_data *cp)
|
|||||||
rq_size += RECOVERING_REGION_SECTION_SIZE;
|
rq_size += RECOVERING_REGION_SECTION_SIZE;
|
||||||
rq_size += cp->bitmap_size * 2; /* clean|sync_bits */
|
rq_size += cp->bitmap_size * 2; /* clean|sync_bits */
|
||||||
|
|
||||||
rq = zalloc(rq_size);
|
rq = malloc(rq_size);
|
||||||
if (!rq) {
|
if (!rq) {
|
||||||
LOG_ERROR("export_checkpoint: "
|
LOG_ERROR("export_checkpoint: "
|
||||||
"Unable to allocate transfer structs");
|
"Unable to allocate transfer structs");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
memset(rq, 0, rq_size);
|
||||||
|
|
||||||
dm_list_init(&rq->u.list);
|
dm_list_init(&rq->u.list);
|
||||||
rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY;
|
rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY;
|
||||||
@@ -1091,7 +1092,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 +1341,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: "
|
||||||
@@ -1385,7 +1384,7 @@ static void cpg_leave_callback(struct clog_cpg *match,
|
|||||||
size_t member_list_entries)
|
size_t member_list_entries)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
int j, fd = -1;
|
int j, fd;
|
||||||
uint32_t lowest = match->lowest_id;
|
uint32_t lowest = match->lowest_id;
|
||||||
struct clog_request *rq, *n;
|
struct clog_request *rq, *n;
|
||||||
struct checkpoint_data *p_cp, *c_cp;
|
struct checkpoint_data *p_cp, *c_cp;
|
||||||
@@ -1550,7 +1549,7 @@ static void cpg_config_callback(cpg_handle_t handle, const struct cpg_name *gnam
|
|||||||
member_list, member_list_entries);
|
member_list, member_list_entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
static cpg_callbacks_t cpg_callbacks = {
|
cpg_callbacks_t cpg_callbacks = {
|
||||||
.cpg_deliver_fn = cpg_message_callback,
|
.cpg_deliver_fn = cpg_message_callback,
|
||||||
.cpg_confchg_fn = cpg_config_callback,
|
.cpg_confchg_fn = cpg_config_callback,
|
||||||
};
|
};
|
||||||
@@ -1622,11 +1621,12 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
|
|||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = zalloc(sizeof(*new));
|
new = malloc(sizeof(*new));
|
||||||
if (!new) {
|
if (!new) {
|
||||||
LOG_ERROR("Unable to allocate memory for clog_cpg");
|
LOG_ERROR("Unable to allocate memory for clog_cpg");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
memset(new, 0, sizeof(*new));
|
||||||
dm_list_init(&new->list);
|
dm_list_init(&new->list);
|
||||||
new->lowest_id = 0xDEAD;
|
new->lowest_id = 0xDEAD;
|
||||||
dm_list_init(&new->startup_list);
|
dm_list_init(&new->startup_list);
|
||||||
@@ -1634,7 +1634,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;
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
#ifndef _LVM_CLOG_CLUSTER_H
|
#ifndef _LVM_CLOG_CLUSTER_H
|
||||||
#define _LVM_CLOG_CLUSTER_H
|
#define _LVM_CLOG_CLUSTER_H
|
||||||
|
|
||||||
#include "libdm/libdevmapper.h"
|
#include "device_mapper/misc/dm-log-userspace.h"
|
||||||
#include "libdm/misc/dm-log-userspace.h"
|
#include "device_mapper/all.h"
|
||||||
|
|
||||||
#define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */
|
#define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */
|
||||||
#define DM_ULOG_CHECKPOINT_READY 21
|
#define DM_ULOG_CHECKPOINT_READY 21
|
||||||
@@ -39,7 +39,7 @@ struct clog_request {
|
|||||||
* machine. If the two are equal, there is no need
|
* machine. If the two are equal, there is no need
|
||||||
* to do endian conversions.
|
* to do endian conversions.
|
||||||
*/
|
*/
|
||||||
union version_u {
|
union {
|
||||||
uint64_t version[2]; /* LE version and native version */
|
uint64_t version[2]; /* LE version and native version */
|
||||||
struct dm_list list;
|
struct dm_list list;
|
||||||
} u;
|
} u;
|
||||||
|
|||||||
@@ -52,19 +52,19 @@ static void v5_data_endian_switch(struct clog_request *rq, int to_network __attr
|
|||||||
case DM_ULOG_GET_REGION_SIZE:
|
case DM_ULOG_GET_REGION_SIZE:
|
||||||
case DM_ULOG_GET_SYNC_COUNT:
|
case DM_ULOG_GET_SYNC_COUNT:
|
||||||
pu64 = (uint64_t *)rq->u_rq.data;
|
pu64 = (uint64_t *)rq->u_rq.data;
|
||||||
*pu64 = htole64(*pu64);
|
*pu64 = xlate64(*pu64);
|
||||||
break;
|
break;
|
||||||
case DM_ULOG_IS_CLEAN:
|
case DM_ULOG_IS_CLEAN:
|
||||||
case DM_ULOG_IN_SYNC:
|
case DM_ULOG_IN_SYNC:
|
||||||
pi64 = (int64_t *)rq->u_rq.data;
|
pi64 = (int64_t *)rq->u_rq.data;
|
||||||
*pi64 = htole64(*pi64);
|
*pi64 = xlate64(*pi64);
|
||||||
break;
|
break;
|
||||||
case DM_ULOG_GET_RESYNC_WORK:
|
case DM_ULOG_GET_RESYNC_WORK:
|
||||||
case DM_ULOG_IS_REMOTE_RECOVERING:
|
case DM_ULOG_IS_REMOTE_RECOVERING:
|
||||||
pi64 = (int64_t *)rq->u_rq.data;
|
pi64 = (int64_t *)rq->u_rq.data;
|
||||||
pu64 = ((uint64_t *)rq->u_rq.data) + 1;
|
pu64 = ((uint64_t *)rq->u_rq.data) + 1;
|
||||||
*pi64 = htole64(*pi64);
|
*pi64 = xlate64(*pi64);
|
||||||
*pu64 = htole64(*pu64);
|
*pu64 = xlate64(*pu64);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("Unknown request type, %u", rq_type);
|
LOG_ERROR("Unknown request type, %u", rq_type);
|
||||||
@@ -94,7 +94,7 @@ static void v5_data_endian_switch(struct clog_request *rq, int to_network __attr
|
|||||||
case DM_ULOG_IN_SYNC:
|
case DM_ULOG_IN_SYNC:
|
||||||
case DM_ULOG_IS_REMOTE_RECOVERING:
|
case DM_ULOG_IS_REMOTE_RECOVERING:
|
||||||
pu64 = (uint64_t *)rq->u_rq.data;
|
pu64 = (uint64_t *)rq->u_rq.data;
|
||||||
*pu64 = htole64(*pu64);
|
*pu64 = xlate64(*pu64);
|
||||||
break;
|
break;
|
||||||
case DM_ULOG_MARK_REGION:
|
case DM_ULOG_MARK_REGION:
|
||||||
case DM_ULOG_CLEAR_REGION:
|
case DM_ULOG_CLEAR_REGION:
|
||||||
@@ -102,13 +102,13 @@ static void v5_data_endian_switch(struct clog_request *rq, int to_network __attr
|
|||||||
|
|
||||||
pu64 = (uint64_t *)rq->u_rq.data;
|
pu64 = (uint64_t *)rq->u_rq.data;
|
||||||
for (i = 0; i < end; i++)
|
for (i = 0; i < end; i++)
|
||||||
pu64[i] = htole64(pu64[i]);
|
pu64[i] = xlate64(pu64[i]);
|
||||||
break;
|
break;
|
||||||
case DM_ULOG_SET_REGION_SYNC:
|
case DM_ULOG_SET_REGION_SYNC:
|
||||||
pu64 = (uint64_t *)rq->u_rq.data;
|
pu64 = (uint64_t *)rq->u_rq.data;
|
||||||
pi64 = ((int64_t *)rq->u_rq.data) + 1;
|
pi64 = ((int64_t *)rq->u_rq.data) + 1;
|
||||||
*pu64 = htole64(*pu64);
|
*pu64 = xlate64(*pu64);
|
||||||
*pi64 = htole64(*pi64);
|
*pi64 = xlate64(*pi64);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("Unknown request type, %u", rq_type);
|
LOG_ERROR("Unknown request type, %u", rq_type);
|
||||||
@@ -124,15 +124,15 @@ static int v5_endian_to_network(struct clog_request *rq)
|
|||||||
|
|
||||||
size = sizeof(*rq) + u_rq->data_size;
|
size = sizeof(*rq) + u_rq->data_size;
|
||||||
|
|
||||||
u_rq->error = htole32(u_rq->error);
|
u_rq->error = xlate32(u_rq->error);
|
||||||
u_rq->seq = htole32(u_rq->seq);
|
u_rq->seq = xlate32(u_rq->seq);
|
||||||
|
|
||||||
rq->originator = htole32(rq->originator);
|
rq->originator = xlate32(rq->originator);
|
||||||
|
|
||||||
v5_data_endian_switch(rq, 1);
|
v5_data_endian_switch(rq, 1);
|
||||||
|
|
||||||
u_rq->request_type = htole32(u_rq->request_type);
|
u_rq->request_type = xlate32(u_rq->request_type);
|
||||||
u_rq->data_size = htole32(u_rq->data_size);
|
u_rq->data_size = xlate32(u_rq->data_size);
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ int clog_request_to_network(struct clog_request *rq)
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* FIXME: Remove this safety check */
|
/* FIXME: Remove this safety check */
|
||||||
if (rq->u.version[0] != htole64(rq->u.version[1])) {
|
if (rq->u.version[0] != xlate64(rq->u.version[1])) {
|
||||||
LOG_ERROR("Programmer error: version[0] must be LE");
|
LOG_ERROR("Programmer error: version[0] must be LE");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@@ -165,12 +165,12 @@ static int v5_endian_from_network(struct clog_request *rq)
|
|||||||
int size;
|
int size;
|
||||||
struct dm_ulog_request *u_rq = &rq->u_rq;
|
struct dm_ulog_request *u_rq = &rq->u_rq;
|
||||||
|
|
||||||
u_rq->error = htole32(u_rq->error);
|
u_rq->error = xlate32(u_rq->error);
|
||||||
u_rq->seq = htole32(u_rq->seq);
|
u_rq->seq = xlate32(u_rq->seq);
|
||||||
u_rq->request_type = htole32(u_rq->request_type);
|
u_rq->request_type = xlate32(u_rq->request_type);
|
||||||
u_rq->data_size = htole32(u_rq->data_size);
|
u_rq->data_size = xlate32(u_rq->data_size);
|
||||||
|
|
||||||
rq->originator = htole32(rq->originator);
|
rq->originator = xlate32(rq->originator);
|
||||||
|
|
||||||
size = sizeof(*rq) + u_rq->data_size;
|
size = sizeof(*rq) + u_rq->data_size;
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ static int v5_endian_from_network(struct clog_request *rq)
|
|||||||
int clog_request_from_network(void *data, size_t data_len)
|
int clog_request_from_network(void *data, size_t data_len)
|
||||||
{
|
{
|
||||||
uint64_t *vp = data;
|
uint64_t *vp = data;
|
||||||
uint64_t version = htole64(vp[0]);
|
uint64_t version = xlate64(vp[0]);
|
||||||
struct clog_request *rq = data;
|
struct clog_request *rq = data;
|
||||||
|
|
||||||
switch (version) {
|
switch (version) {
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
#ifndef _LVM_CLOG_COMPAT_H
|
#ifndef _LVM_CLOG_COMPAT_H
|
||||||
#define _LVM_CLOG_COMPAT_H
|
#define _LVM_CLOG_COMPAT_H
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The intermachine communication structure version are:
|
* The intermachine communication structure version are:
|
||||||
* 0: Unused
|
* 0: Unused
|
||||||
@@ -21,8 +19,6 @@
|
|||||||
*/
|
*/
|
||||||
#define CLOG_TFR_VERSION 5
|
#define CLOG_TFR_VERSION 5
|
||||||
|
|
||||||
struct clog_request;
|
|
||||||
|
|
||||||
int clog_request_to_network(struct clog_request *rq);
|
int clog_request_to_network(struct clog_request *rq);
|
||||||
int clog_request_from_network(void *data, size_t data_len);
|
int clog_request_from_network(void *data, size_t data_len);
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
#define LOG_OFFSET 2
|
#define LOG_OFFSET 2
|
||||||
|
|
||||||
#define RESYNC_HISTORY 50
|
#define RESYNC_HISTORY 50
|
||||||
#define RESYNC_BUFLEN 270
|
#define RESYNC_BUFLEN 128
|
||||||
//static char resync_history[RESYNC_HISTORY][128];
|
//static char resync_history[RESYNC_HISTORY][128];
|
||||||
//static int idx = 0;
|
//static int idx = 0;
|
||||||
#define LOG_SPRINT(_lc, f, arg...) do { \
|
#define LOG_SPRINT(_lc, f, arg...) do { \
|
||||||
@@ -67,7 +67,7 @@ struct log_c {
|
|||||||
uint32_t recoverer;
|
uint32_t recoverer;
|
||||||
uint64_t recovering_region; /* -1 means not recovering */
|
uint64_t recovering_region; /* -1 means not recovering */
|
||||||
uint64_t skip_bit_warning; /* used to warn if region skipped */
|
uint64_t skip_bit_warning; /* used to warn if region skipped */
|
||||||
unsigned sync_search;
|
int sync_search;
|
||||||
|
|
||||||
int resume_override;
|
int resume_override;
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ static int rw_log(struct log_c *lc, int do_write)
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
LOG_ERROR("[%s] rw_log: read failure: %s",
|
LOG_ERROR("[%s] rw_log: read failure: %s",
|
||||||
SHORT_UUID(lc->uuid), strerror(errno));
|
SHORT_UUID(lc->uuid), strerror(errno));
|
||||||
if ((unsigned) r != lc->disk_size)
|
if (r != lc->disk_size)
|
||||||
return -EIO; /* Failed disk read */
|
return -EIO; /* Failed disk read */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -254,7 +254,7 @@ static int read_log(struct log_c *lc)
|
|||||||
bitset_size = lc->region_count / 8;
|
bitset_size = lc->region_count / 8;
|
||||||
bitset_size += (lc->region_count % 8) ? 1 : 0;
|
bitset_size += (lc->region_count % 8) ? 1 : 0;
|
||||||
|
|
||||||
/* 'lc->clean_bits + 1' because dm_bitset_t leads with a uint32_t */
|
/* 'lc->clean_bits + 1' becasue dm_bitset_t leads with a uint32_t */
|
||||||
memcpy(lc->clean_bits + 1, (char *)lc->disk_buffer + 1024, bitset_size);
|
memcpy(lc->clean_bits + 1, (char *)lc->disk_buffer + 1024, bitset_size);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -281,7 +281,7 @@ static int write_log(struct log_c *lc)
|
|||||||
bitset_size = lc->region_count / 8;
|
bitset_size = lc->region_count / 8;
|
||||||
bitset_size += (lc->region_count % 8) ? 1 : 0;
|
bitset_size += (lc->region_count % 8) ? 1 : 0;
|
||||||
|
|
||||||
/* 'lc->clean_bits + 1' because dm_bitset_t leads with a uint32_t */
|
/* 'lc->clean_bits + 1' becasue dm_bitset_t leads with a uint32_t */
|
||||||
memcpy((char *)lc->disk_buffer + 1024, lc->clean_bits + 1, bitset_size);
|
memcpy((char *)lc->disk_buffer + 1024, lc->clean_bits + 1, bitset_size);
|
||||||
|
|
||||||
if (rw_log(lc, 1)) {
|
if (rw_log(lc, 1)) {
|
||||||
@@ -292,13 +292,13 @@ static int write_log(struct log_c *lc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME Rewrite this function taking advantage of the udev changes (where in use) to improve its efficiency! */
|
/* FIXME Rewrite this function taking advantage of the udev changes (where in use) to improve its efficiency! */
|
||||||
static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int *unlink_path __attribute__((unused)))
|
static int find_disk_path(char *major_minor_str, char *path_rtn, int *unlink_path __attribute__((unused)))
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
struct dirent *dep;
|
struct dirent *dep;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
unsigned major, minor;
|
int major, minor;
|
||||||
|
|
||||||
if (!strstr(major_minor_str, ":")) {
|
if (!strstr(major_minor_str, ":")) {
|
||||||
r = stat(major_minor_str, &statbuf);
|
r = stat(major_minor_str, &statbuf);
|
||||||
@@ -306,7 +306,7 @@ static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int
|
|||||||
return -errno;
|
return -errno;
|
||||||
if (!S_ISBLK(statbuf.st_mode))
|
if (!S_ISBLK(statbuf.st_mode))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
dm_strncpy(path_rtn, major_minor_str, sz);
|
sprintf(path_rtn, "%s", major_minor_str);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,7 +329,7 @@ static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int
|
|||||||
* wanted.
|
* wanted.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
snprintf(path_rtn, sz, "/dev/mapper/%s", dep->d_name);
|
sprintf(path_rtn, "/dev/mapper/%s", dep->d_name);
|
||||||
if (stat(path_rtn, &statbuf) < 0) {
|
if (stat(path_rtn, &statbuf) < 0) {
|
||||||
LOG_DBG("Unable to stat %s", path_rtn);
|
LOG_DBG("Unable to stat %s", path_rtn);
|
||||||
continue;
|
continue;
|
||||||
@@ -378,10 +378,10 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
|||||||
uint32_t block_on_error = 0;
|
uint32_t block_on_error = 0;
|
||||||
|
|
||||||
int disk_log;
|
int disk_log;
|
||||||
char disk_path[PATH_MAX] = { 0 };
|
char disk_path[PATH_MAX];
|
||||||
int unlink_path = 0;
|
int unlink_path = 0;
|
||||||
long ps;
|
long page_size;
|
||||||
size_t pages, page_size;
|
int pages;
|
||||||
|
|
||||||
/* If core log request, then argv[0] will be region_size */
|
/* If core log request, then argv[0] will be region_size */
|
||||||
if (!strtoll(argv[0], &p, 0) || *p) {
|
if (!strtoll(argv[0], &p, 0) || *p) {
|
||||||
@@ -394,7 +394,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = find_disk_path(argv[0], disk_path, sizeof(disk_path), &unlink_path);
|
r = find_disk_path(argv[0], disk_path, &unlink_path);
|
||||||
if (r) {
|
if (r) {
|
||||||
LOG_ERROR("Unable to find path to device %s", argv[0]);
|
LOG_ERROR("Unable to find path to device %s", argv[0]);
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -452,7 +452,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
|||||||
lc->skip_bit_warning = region_count;
|
lc->skip_bit_warning = region_count;
|
||||||
lc->disk_fd = -1;
|
lc->disk_fd = -1;
|
||||||
lc->log_dev_failed = 0;
|
lc->log_dev_failed = 0;
|
||||||
if (!_dm_strncpy(lc->uuid, uuid, DM_UUID_LEN)) {
|
if (!dm_strncpy(lc->uuid, uuid, DM_UUID_LEN)) {
|
||||||
LOG_ERROR("Cannot use too long UUID %s.", uuid);
|
LOG_ERROR("Cannot use too long UUID %s.", uuid);
|
||||||
r = -EINVAL;
|
r = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -488,15 +488,14 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
|||||||
lc->sync_count = (log_sync == NOSYNC) ? region_count : 0;
|
lc->sync_count = (log_sync == NOSYNC) ? region_count : 0;
|
||||||
|
|
||||||
if (disk_log) {
|
if (disk_log) {
|
||||||
if (((ps = sysconf(_SC_PAGESIZE)) <= 0) ||
|
if ((page_size = sysconf(_SC_PAGESIZE)) < 0) {
|
||||||
(ps > (1 << 24))) {
|
|
||||||
LOG_ERROR("Unable to read pagesize: %s",
|
LOG_ERROR("Unable to read pagesize: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
r = errno;
|
r = errno;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
page_size = (size_t)ps;
|
pages = *(lc->clean_bits) / page_size;
|
||||||
pages = (*(lc->clean_bits) + page_size - 1) / page_size;
|
pages += *(lc->clean_bits) % page_size ? 1 : 0;
|
||||||
pages += 1; /* for header */
|
pages += 1; /* for header */
|
||||||
|
|
||||||
r = open(disk_path, O_RDWR | O_DIRECT);
|
r = open(disk_path, O_RDWR | O_DIRECT);
|
||||||
@@ -659,6 +658,7 @@ static int clog_dtr(struct dm_ulog_request *rq)
|
|||||||
if (lc->disk_fd != -1 && close(lc->disk_fd))
|
if (lc->disk_fd != -1 && close(lc->disk_fd))
|
||||||
LOG_ERROR("Failed to close disk log: %s",
|
LOG_ERROR("Failed to close disk log: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
if (lc->disk_buffer)
|
||||||
free(lc->disk_buffer);
|
free(lc->disk_buffer);
|
||||||
free(lc->clean_bits);
|
free(lc->clean_bits);
|
||||||
free(lc->sync_bits);
|
free(lc->sync_bits);
|
||||||
@@ -928,7 +928,7 @@ int local_resume(struct dm_ulog_request *rq)
|
|||||||
*
|
*
|
||||||
* Since this value doesn't change, the kernel
|
* Since this value doesn't change, the kernel
|
||||||
* should not need to talk to server to get this
|
* should not need to talk to server to get this
|
||||||
* The function is here for completeness
|
* The function is here for completness
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, -EXXX on failure
|
* Returns: 0 on success, -EXXX on failure
|
||||||
*/
|
*/
|
||||||
@@ -1019,7 +1019,7 @@ static int clog_in_sync(struct dm_ulog_request *rq)
|
|||||||
* happen for reads is that additional read attempts may be
|
* happen for reads is that additional read attempts may be
|
||||||
* taken.
|
* taken.
|
||||||
*
|
*
|
||||||
* Further investigation may be required to determine if there are
|
* Futher investigation may be required to determine if there are
|
||||||
* similar possible outcomes when the mirror is in the process of
|
* similar possible outcomes when the mirror is in the process of
|
||||||
* recovering. In that case, lc->in_sync would not have been set
|
* recovering. In that case, lc->in_sync would not have been set
|
||||||
* yet.
|
* yet.
|
||||||
|
|||||||
@@ -12,9 +12,7 @@
|
|||||||
#ifndef _LVM_CLOG_FUNCTIONS_H
|
#ifndef _LVM_CLOG_FUNCTIONS_H
|
||||||
#define _LVM_CLOG_FUNCTIONS_H
|
#define _LVM_CLOG_FUNCTIONS_H
|
||||||
|
|
||||||
#include "libdm/libdevmapper.h"
|
#include "device_mapper/misc/dm-log-userspace.h"
|
||||||
#include "libdm/dm-tools/util.h"
|
|
||||||
#include "libdm/misc/dm-log-userspace.h"
|
|
||||||
#include "cluster.h"
|
#include "cluster.h"
|
||||||
|
|
||||||
#define LOG_RESUMED 1
|
#define LOG_RESUMED 1
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ static int do_local_work(void *data __attribute__((unused)))
|
|||||||
RQ_TYPE(u_rq->request_type));
|
RQ_TYPE(u_rq->request_type));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* ELSE */ /* fall through */
|
/* ELSE, fall through */
|
||||||
case DM_ULOG_IS_CLEAN:
|
case DM_ULOG_IS_CLEAN:
|
||||||
case DM_ULOG_FLUSH:
|
case DM_ULOG_FLUSH:
|
||||||
case DM_ULOG_MARK_REGION:
|
case DM_ULOG_MARK_REGION:
|
||||||
@@ -326,11 +326,10 @@ static int do_local_work(void *data __attribute__((unused)))
|
|||||||
*
|
*
|
||||||
* Returns: 0 on success, -EXXX on failure
|
* Returns: 0 on success, -EXXX on failure
|
||||||
*/
|
*/
|
||||||
int kernel_send(void *data)
|
int kernel_send(struct dm_ulog_request *u_rq)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
struct dm_ulog_request *u_rq = data;
|
|
||||||
|
|
||||||
if (!u_rq)
|
if (!u_rq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -354,7 +353,7 @@ int kernel_send(void *data)
|
|||||||
size = sizeof(struct dm_ulog_request);
|
size = sizeof(struct dm_ulog_request);
|
||||||
}
|
}
|
||||||
|
|
||||||
r = kernel_send_helper(data, size);
|
r = kernel_send_helper(u_rq, size);
|
||||||
if (r)
|
if (r)
|
||||||
LOG_ERROR("Failed to send msg to kernel.");
|
LOG_ERROR("Failed to send msg to kernel.");
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,9 @@
|
|||||||
#ifndef _LVM_CLOG_LOCAL_H
|
#ifndef _LVM_CLOG_LOCAL_H
|
||||||
#define _LVM_CLOG_LOCAL_H
|
#define _LVM_CLOG_LOCAL_H
|
||||||
|
|
||||||
struct dm_ulog_request;
|
|
||||||
|
|
||||||
int init_local(void);
|
int init_local(void);
|
||||||
void cleanup_local(void);
|
void cleanup_local(void);
|
||||||
|
|
||||||
int kernel_send(void *data);
|
int kernel_send(struct dm_ulog_request *rq);
|
||||||
|
|
||||||
#endif /* _LVM_CLOG_LOCAL_H */
|
#endif /* _LVM_CLOG_LOCAL_H */
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
#ifndef _LVM_CLOG_LOGGING_H
|
#ifndef _LVM_CLOG_LOGGING_H
|
||||||
#define _LVM_CLOG_LOGGING_H
|
#define _LVM_CLOG_LOGGING_H
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include "configure.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
@@ -20,7 +23,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;
|
||||||
|
|||||||
@@ -14,21 +14,11 @@
|
|||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
abs_srcdir = @abs_srcdir@
|
|
||||||
|
|
||||||
SOURCES = libdevmapper-event.c
|
SOURCES = libdevmapper-event.c
|
||||||
SOURCES2 = dmeventd.c
|
SOURCES2 = dmeventd.c
|
||||||
|
|
||||||
TARGETS = dmeventd
|
TARGETS = dmeventd
|
||||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES) $(SOURCES2) \
|
|
||||||
plugins/lvm2/dmeventd_lvm.c \
|
|
||||||
plugins/mirror/dmeventd_mirror.c \
|
|
||||||
plugins/raid/dmeventd_raid.c \
|
|
||||||
plugins/snapshot/dmeventd_snapshot.c \
|
|
||||||
plugins/thin/dmeventd_thin.c \
|
|
||||||
plugins/vdo/dmeventd_vdo.c \
|
|
||||||
)
|
|
||||||
CFLOW_TARGET := $(TARGETS)
|
|
||||||
|
|
||||||
.PHONY: install_lib_dynamic install_lib_static install_include \
|
.PHONY: install_lib_dynamic install_lib_static install_include \
|
||||||
install_pkgconfig install_dmeventd_dynamic install_dmeventd_static \
|
install_pkgconfig install_dmeventd_dynamic install_dmeventd_static \
|
||||||
@@ -47,7 +37,6 @@ endif
|
|||||||
|
|
||||||
LIB_VERSION = $(LIB_VERSION_DM)
|
LIB_VERSION = $(LIB_VERSION_DM)
|
||||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||||
LIBS = $(PTHREAD_LIBS) -L$(interfacebuilddir) -ldevmapper
|
|
||||||
|
|
||||||
CLEAN_TARGETS = dmeventd.static $(LIB_NAME).a
|
CLEAN_TARGETS = dmeventd.static $(LIB_NAME).a
|
||||||
|
|
||||||
@@ -57,6 +46,7 @@ endif
|
|||||||
|
|
||||||
CFLOW_LIST = $(SOURCES)
|
CFLOW_LIST = $(SOURCES)
|
||||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
CFLOW_TARGET = dmeventd
|
||||||
|
|
||||||
EXPORTED_HEADER = $(srcdir)/libdevmapper-event.h
|
EXPORTED_HEADER = $(srcdir)/libdevmapper-event.h
|
||||||
EXPORTED_FN_PREFIX = dm_event
|
EXPORTED_FN_PREFIX = dm_event
|
||||||
@@ -65,47 +55,48 @@ include $(top_builddir)/make.tmpl
|
|||||||
|
|
||||||
all: device-mapper
|
all: device-mapper
|
||||||
device-mapper: $(TARGETS)
|
device-mapper: $(TARGETS)
|
||||||
plugins.device-mapper: $(LIB_SHARED)
|
|
||||||
|
|
||||||
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
|
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
|
||||||
|
LIBS += $(PTHREAD_LIBS)
|
||||||
|
|
||||||
dmeventd: $(LIB_SHARED) dmeventd.o
|
dmeventd: $(LIB_SHARED) dmeventd.o
|
||||||
$(SHOW) " [CC] $@"
|
$(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(INTERNAL_LIBS) $(LIBS) -lm
|
||||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
|
|
||||||
|
|
||||||
dmeventd.static: $(LIB_STATIC) dmeventd.o
|
dmeventd.static: $(LIB_STATIC) dmeventd.o
|
||||||
$(SHOW) " [CC] $@"
|
$(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(STATIC_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")
|
||||||
INSTALL_LIB_TARGETS += install_pkgconfig
|
INSTALL_LIB_TARGETS += install_pkgconfig
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ("$(CFLOW_CMD)", "")
|
||||||
|
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||||
|
-include $(top_builddir)/lib/liblvm-internal.cflow
|
||||||
|
-include $(top_builddir)/lib/liblvm2cmd.cflow
|
||||||
|
-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
|
||||||
|
-include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow
|
||||||
|
endif
|
||||||
|
|
||||||
install_include: $(srcdir)/libdevmapper-event.h
|
install_include: $(srcdir)/libdevmapper-event.h
|
||||||
$(SHOW) " [INSTALL] $(<F)"
|
$(INSTALL_DATA) -D $< $(includedir)/$(<F)
|
||||||
$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F)
|
|
||||||
|
|
||||||
install_pkgconfig: libdevmapper-event.pc
|
install_pkgconfig: libdevmapper-event.pc
|
||||||
$(SHOW) " [INSTALL] $<"
|
$(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] $<"
|
$(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] $<"
|
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
|
||||||
|
|
||||||
install_dmeventd_static: dmeventd.static
|
install_dmeventd_static: dmeventd.static
|
||||||
$(SHOW) " [INSTALL] $<"
|
$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
|
|
||||||
|
|
||||||
install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
|
install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -15,8 +15,6 @@
|
|||||||
#ifndef __DMEVENTD_DOT_H__
|
#ifndef __DMEVENTD_DOT_H__
|
||||||
#define __DMEVENTD_DOT_H__
|
#define __DMEVENTD_DOT_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/* FIXME This stuff must be configurable. */
|
/* FIXME This stuff must be configurable. */
|
||||||
|
|
||||||
#define DM_EVENT_FIFO_CLIENT DEFAULT_DM_RUN_DIR "/dmeventd-client"
|
#define DM_EVENT_FIFO_CLIENT DEFAULT_DM_RUN_DIR "/dmeventd-client"
|
||||||
@@ -70,7 +68,7 @@ struct dm_event_fifos {
|
|||||||
int daemon_talk(struct dm_event_fifos *fifos,
|
int daemon_talk(struct dm_event_fifos *fifos,
|
||||||
struct dm_event_daemon_message *msg, int cmd,
|
struct dm_event_daemon_message *msg, int cmd,
|
||||||
const char *dso_name, const char *dev_name,
|
const char *dso_name, const char *dev_name,
|
||||||
unsigned evmask, uint32_t timeout);
|
enum dm_event_mask evmask, uint32_t timeout);
|
||||||
int init_fifos(struct dm_event_fifos *fifos);
|
int init_fifos(struct dm_event_fifos *fifos);
|
||||||
void fini_fifos(struct dm_event_fifos *fifos);
|
void fini_fifos(struct dm_event_fifos *fifos);
|
||||||
int dm_event_get_version(struct dm_event_fifos *fifos, int *version);
|
int dm_event_get_version(struct dm_event_fifos *fifos, int *version);
|
||||||
|
|||||||
@@ -12,11 +12,11 @@
|
|||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "libdevmapper-event.h"
|
#include "device_mapper/misc/dmlib.h"
|
||||||
#include "dmeventd.h"
|
|
||||||
#include "libdm/misc/dm-logging.h"
|
|
||||||
#include "base/memory/zalloc.h"
|
#include "base/memory/zalloc.h"
|
||||||
|
#include "device_mapper/misc/dm-logging.h"
|
||||||
|
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||||
|
#include "dmeventd.h"
|
||||||
#include "lib/misc/intl.h"
|
#include "lib/misc/intl.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -237,16 +237,16 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
|||||||
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
||||||
if (ret < 0 && errno != EINTR) {
|
if (ret < 0 && errno != EINTR) {
|
||||||
log_error("Unable to read from event server.");
|
log_error("Unable to read from event server.");
|
||||||
goto bad;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((ret == 0) && (i > 4) && !bytes) {
|
if ((ret == 0) && (i > 4) && !bytes) {
|
||||||
log_error("No input from event server.");
|
log_error("No input from event server.");
|
||||||
goto bad;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret < 1) {
|
if (ret < 1) {
|
||||||
log_error("Unable to read from event server.");
|
log_error("Unable to read from event server.");
|
||||||
goto bad;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = read(fifos->server, buf + bytes, size);
|
ret = read(fifos->server, buf + bytes, size);
|
||||||
@@ -255,32 +255,25 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
log_error("Unable to read from event server.");
|
log_error("Unable to read from event server.");
|
||||||
goto bad;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes += ret;
|
bytes += ret;
|
||||||
if (!msg->data && (bytes == 2 * sizeof(uint32_t))) {
|
if (header && (bytes == 2 * sizeof(uint32_t))) {
|
||||||
msg->cmd = ntohl(header[0]);
|
msg->cmd = ntohl(header[0]);
|
||||||
|
msg->size = ntohl(header[1]);
|
||||||
|
buf = msg->data = malloc(msg->size);
|
||||||
|
size = msg->size;
|
||||||
bytes = 0;
|
bytes = 0;
|
||||||
|
header = 0;
|
||||||
if (!(size = msg->size = ntohl(header[1])))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!(buf = msg->data = malloc(msg->size))) {
|
|
||||||
log_error("Unable to allocate message data.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes == size)
|
if (bytes != size) {
|
||||||
return 1;
|
|
||||||
|
|
||||||
bad:
|
|
||||||
free(msg->data);
|
free(msg->data);
|
||||||
msg->data = NULL;
|
msg->data = NULL;
|
||||||
|
}
|
||||||
return 0;
|
return bytes == size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write message to daemon. */
|
/* Write message to daemon. */
|
||||||
@@ -352,7 +345,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 +393,25 @@ int daemon_talk(struct dm_event_fifos *fifos,
|
|||||||
return (int32_t) msg->cmd;
|
return (int32_t) msg->cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for usable client fifo file
|
* start_daemon
|
||||||
*
|
*
|
||||||
* Returns: 2 client path does not exists, dmeventd should be restarted
|
* This function forks off a process (dmeventd) that will handle
|
||||||
* 1 on success, 0 otherwise
|
* the events. I am currently test opening one of the fifos to
|
||||||
|
* ensure that the daemon is running and listening... I thought
|
||||||
|
* this would be less expensive than fork/exec'ing every time.
|
||||||
|
* Perhaps there is an even quicker/better way (no, checking the
|
||||||
|
* lock file is _not_ a better way).
|
||||||
|
*
|
||||||
|
* Returns: 1 on success, 0 otherwise
|
||||||
*/
|
*/
|
||||||
static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *fifos)
|
static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
|
||||||
{
|
{
|
||||||
|
int pid, ret = 0;
|
||||||
|
int status;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
char default_dmeventd_path[] = DMEVENTD_PATH;
|
||||||
|
char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME Explicitly verify the code's requirement that client_path is secure:
|
* FIXME Explicitly verify the code's requirement that client_path is secure:
|
||||||
@@ -420,7 +422,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 +448,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 +462,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 +485,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 +506,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 +517,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 +545,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 */
|
||||||
@@ -649,8 +608,8 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct dm_event_fifos fifos = {
|
struct dm_event_fifos fifos = {
|
||||||
.client = -1,
|
|
||||||
.server = -1,
|
.server = -1,
|
||||||
|
.client = -1,
|
||||||
/* FIXME Make these either configurable or depend directly on dmeventd_path */
|
/* FIXME Make these either configurable or depend directly on dmeventd_path */
|
||||||
.client_path = DM_EVENT_FIFO_CLIENT,
|
.client_path = DM_EVENT_FIFO_CLIENT,
|
||||||
.server_path = DM_EVENT_FIFO_SERVER
|
.server_path = DM_EVENT_FIFO_SERVER
|
||||||
@@ -743,18 +702,22 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
|||||||
static char *_fetch_string(char **src, const int delimiter)
|
static char *_fetch_string(char **src, const int delimiter)
|
||||||
{
|
{
|
||||||
char *p, *ret;
|
char *p, *ret;
|
||||||
size_t len = (p = strchr(*src, delimiter)) ?
|
|
||||||
(size_t)(p - *src) : strlen(*src);
|
|
||||||
|
|
||||||
if ((ret = strndup(*src, len)))
|
if ((p = strchr(*src, delimiter)))
|
||||||
*src += len + 1;
|
*p = 0;
|
||||||
|
|
||||||
|
if ((ret = strdup(*src)))
|
||||||
|
*src += strlen(ret) + 1;
|
||||||
|
|
||||||
|
if (p)
|
||||||
|
*p = delimiter;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 +742,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
const char *uuid = NULL;
|
const char *uuid = NULL;
|
||||||
char *reply_dso = NULL, *reply_uuid = NULL;
|
char *reply_dso = NULL, *reply_uuid = NULL;
|
||||||
unsigned reply_mask = 0;
|
enum dm_event_mask reply_mask = 0;
|
||||||
struct dm_task *dmt = NULL;
|
struct dm_task *dmt = NULL;
|
||||||
struct dm_event_daemon_message msg = { 0 };
|
struct dm_event_daemon_message msg = { 0 };
|
||||||
struct dm_info info;
|
struct dm_info info;
|
||||||
@@ -829,7 +792,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dm_event_handler_set_dso(dmevh, reply_dso);
|
dm_event_handler_set_dso(dmevh, reply_dso);
|
||||||
dm_event_handler_set_event_mask(dmevh, (enum dm_event_mask) reply_mask);
|
dm_event_handler_set_event_mask(dmevh, reply_mask);
|
||||||
|
|
||||||
free(reply_dso);
|
free(reply_dso);
|
||||||
reply_dso = NULL;
|
reply_dso = NULL;
|
||||||
@@ -878,7 +841,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 +848,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 +869,11 @@ void dm_event_log(const char *subsys, int level, const char *file,
|
|||||||
{
|
{
|
||||||
static int _abort_on_internal_errors = -1;
|
static int _abort_on_internal_errors = -1;
|
||||||
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static long long _start = 0;
|
static time_t start = 0;
|
||||||
const char *indent = "";
|
const char *indent = "";
|
||||||
FILE *stream = log_stderr(level) ? stderr : stdout;
|
FILE *stream = log_stderr(level) ? stderr : stdout;
|
||||||
int prio;
|
int prio;
|
||||||
long long now, now_nsec;
|
time_t now;
|
||||||
int log_with_debug = 0;
|
int log_with_debug = 0;
|
||||||
|
|
||||||
if (subsys[0] == '#') {
|
if (subsys[0] == '#') {
|
||||||
@@ -962,33 +920,22 @@ void dm_event_log(const char *subsys, int level, const char *file,
|
|||||||
if (_use_syslog) {
|
if (_use_syslog) {
|
||||||
vsyslog(prio, format, ap);
|
vsyslog(prio, format, ap);
|
||||||
} else {
|
} else {
|
||||||
if (_debug_level) {
|
now = time(NULL);
|
||||||
#define _NSEC_PER_SEC (1000000000LL)
|
if (!start)
|
||||||
#ifdef HAVE_REALTIME
|
start = now;
|
||||||
struct timespec mono_time = { 0 };
|
now -= start;
|
||||||
if (clock_gettime(CLOCK_MONOTONIC, &mono_time) == 0)
|
if (_debug_level)
|
||||||
now = mono_time.tv_sec * _NSEC_PER_SEC + mono_time.tv_nsec;
|
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
|
||||||
else
|
(int)now / 60, (int)now % 60,
|
||||||
#endif
|
|
||||||
now = time(NULL) * _NSEC_PER_SEC;
|
|
||||||
|
|
||||||
if (!_start)
|
|
||||||
_start = now;
|
|
||||||
now -= _start;
|
|
||||||
now_nsec = now %_NSEC_PER_SEC;
|
|
||||||
now /= _NSEC_PER_SEC;
|
|
||||||
fprintf(stream, "[%2lld:%02lld.%06lld] %8x:%-6s%s",
|
|
||||||
now / 60, now % 60, now_nsec / 1000,
|
|
||||||
// TODO: Maybe use shorter ID
|
// TODO: Maybe use shorter ID
|
||||||
// ((int)(pthread_self()) >> 6) & 0xffff,
|
// ((int)(pthread_self()) >> 6) & 0xffff,
|
||||||
(int)pthread_self(), subsys,
|
(int)pthread_self(), subsys,
|
||||||
(_debug_level > 3) ? "" : indent);
|
(_debug_level > 3) ? "" : indent);
|
||||||
}
|
|
||||||
if (_debug_level > 3)
|
if (_debug_level > 3)
|
||||||
fprintf(stream, "%28s:%4d %s", file, line, indent);
|
fprintf(stream, "%28s:%4d %s", file, line, indent);
|
||||||
vfprintf(stream, _(format), ap);
|
vfprintf(stream, _(format), ap);
|
||||||
fputc('\n', stream);
|
fputc('\n', stream);
|
||||||
(void) fflush(stream);
|
fflush(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&_log_mutex);
|
pthread_mutex_unlock(&_log_mutex);
|
||||||
@@ -1007,7 +954,7 @@ void dm_event_log(const char *subsys, int level, const char *file,
|
|||||||
|
|
||||||
static char *_skip_string(char *src, const int delimiter)
|
static char *_skip_string(char *src, const int delimiter)
|
||||||
{
|
{
|
||||||
src = strchr(src, delimiter);
|
src = srtchr(src, delimiter);
|
||||||
if (src && *(src + 1))
|
if (src && *(src + 1))
|
||||||
return src + 1;
|
return src + 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#ifndef LIB_DMEVENT_H
|
#ifndef LIB_DMEVENT_H
|
||||||
#define LIB_DMEVENT_H
|
#define LIB_DMEVENT_H
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -29,22 +28,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
enum dm_event_mask {
|
enum dm_event_mask {
|
||||||
|
DM_EVENT_SETTINGS_MASK = 0x0000FF,
|
||||||
DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */
|
DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */
|
||||||
DM_EVENT_MULTI = 0x000002, /* Report all of them. */
|
DM_EVENT_MULTI = 0x000002, /* Report all of them. */
|
||||||
DM_EVENT_SETTINGS_MASK = 0x0000FF,
|
|
||||||
|
|
||||||
|
DM_EVENT_ERROR_MASK = 0x00FF00,
|
||||||
DM_EVENT_SECTOR_ERROR = 0x000100, /* Failure on a particular sector. */
|
DM_EVENT_SECTOR_ERROR = 0x000100, /* Failure on a particular sector. */
|
||||||
DM_EVENT_DEVICE_ERROR = 0x000200, /* Device failure. */
|
DM_EVENT_DEVICE_ERROR = 0x000200, /* Device failure. */
|
||||||
DM_EVENT_PATH_ERROR = 0x000400, /* Failure on an io path. */
|
DM_EVENT_PATH_ERROR = 0x000400, /* Failure on an io path. */
|
||||||
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */
|
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */
|
||||||
DM_EVENT_ERROR_MASK = 0x00FF00,
|
|
||||||
|
|
||||||
DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
|
|
||||||
DM_EVENT_TIMEOUT = 0x020000, /* Timeout has occurred */
|
|
||||||
|
|
||||||
DM_EVENT_ERROR_AND_TIMEOUT_MASK = 0x02FF00,
|
|
||||||
|
|
||||||
DM_EVENT_STATUS_MASK = 0xFF0000,
|
DM_EVENT_STATUS_MASK = 0xFF0000,
|
||||||
|
DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
|
||||||
|
DM_EVENT_TIMEOUT = 0x020000, /* Timeout has occured */
|
||||||
|
|
||||||
DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */
|
DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */
|
||||||
};
|
};
|
||||||
@@ -73,10 +69,10 @@ int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path);
|
|||||||
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path);
|
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Identify the device to monitor by exactly one of dev_name, uuid or
|
* Identify the device to monitor by exactly one of device_name, uuid or
|
||||||
* device number. String arguments are duplicated, see above.
|
* device number. String arguments are duplicated, see above.
|
||||||
*/
|
*/
|
||||||
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name);
|
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *device_name);
|
||||||
|
|
||||||
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid);
|
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid);
|
||||||
|
|
||||||
@@ -112,7 +108,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
|
|||||||
/* Set debug level for logging, and whether to log on stdout/stderr or syslog */
|
/* Set debug level for logging, and whether to log on stdout/stderr or syslog */
|
||||||
void dm_event_log_set(int debug_log_level, int use_syslog);
|
void dm_event_log_set(int debug_log_level, int use_syslog);
|
||||||
|
|
||||||
/* Log messages according to current debug level */
|
/* Log messages acroding to current debug level */
|
||||||
__attribute__((format(printf, 6, 0)))
|
__attribute__((format(printf, 6, 0)))
|
||||||
void dm_event_log(const char *subsys, int level, const char *file,
|
void dm_event_log(const char *subsys, int level, const char *file,
|
||||||
int line, int dm_errno_or_class,
|
int line, int dm_errno_or_class,
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ top_srcdir = @top_srcdir@
|
|||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
CLDFLAGS += -L$(top_builddir)/tools
|
CLDFLAGS += -L$(top_builddir)/tools
|
||||||
LIBS += $(DMEVENT_LIBS) $(PTHREAD_LIBS) @LVM2CMD_LIB@
|
|
||||||
|
|
||||||
SOURCES = dmeventd_lvm.c
|
SOURCES = dmeventd_lvm.c
|
||||||
|
|
||||||
@@ -25,6 +24,8 @@ LIB_VERSION = $(LIB_VERSION_LVM)
|
|||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += @LVM2CMD_LIB@ $(INTERNAL_LIBS) $(PTHREAD_LIBS)
|
||||||
|
|
||||||
install_lvm2: install_lib_shared
|
install_lvm2: install_lib_shared
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include "lib/misc/lib.h"
|
#include "lib/misc/lib.h"
|
||||||
#include "dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||||
#include "lib/metadata/metadata-exported.h" /* MIRROR_SYNC_LAYER */
|
|
||||||
#include "tools/lvm2cmd.h"
|
#include "tools/lvm2cmd.h"
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@@ -32,13 +31,6 @@ static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|||||||
static int _register_count = 0;
|
static int _register_count = 0;
|
||||||
static struct dm_pool *_mem_pool = NULL;
|
static struct dm_pool *_mem_pool = NULL;
|
||||||
static void *_lvm_handle = NULL;
|
static void *_lvm_handle = NULL;
|
||||||
static DM_LIST_INIT(_env_registry);
|
|
||||||
|
|
||||||
struct env_data {
|
|
||||||
struct dm_list list;
|
|
||||||
const char *cmd;
|
|
||||||
const char *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
DM_EVENT_LOG_FN("#lvm")
|
DM_EVENT_LOG_FN("#lvm")
|
||||||
|
|
||||||
@@ -72,7 +64,7 @@ int dmeventd_lvm2_init(void)
|
|||||||
if (!_lvm_handle) {
|
if (!_lvm_handle) {
|
||||||
lvm2_log_fn(_lvm2_print_log);
|
lvm2_log_fn(_lvm2_print_log);
|
||||||
|
|
||||||
if (!(_lvm_handle = lvm2_init_threaded()))
|
if (!(_lvm_handle = lvm2_init()))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -88,7 +80,7 @@ int dmeventd_lvm2_init(void)
|
|||||||
lvm2_disable_dmeventd_monitoring(_lvm_handle);
|
lvm2_disable_dmeventd_monitoring(_lvm_handle);
|
||||||
/* FIXME Temporary: move to dmeventd core */
|
/* FIXME Temporary: move to dmeventd core */
|
||||||
lvm2_run(_lvm_handle, "_memlock_inc");
|
lvm2_run(_lvm_handle, "_memlock_inc");
|
||||||
log_debug("lvm plugin initialized.");
|
log_debug("lvm plugin initilized.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_register_count++;
|
_register_count++;
|
||||||
@@ -104,11 +96,10 @@ void dmeventd_lvm2_exit(void)
|
|||||||
pthread_mutex_lock(&_register_mutex);
|
pthread_mutex_lock(&_register_mutex);
|
||||||
|
|
||||||
if (!--_register_count) {
|
if (!--_register_count) {
|
||||||
log_debug("lvm plugin shutting down.");
|
log_debug("lvm plugin shuting down.");
|
||||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||||
dm_pool_destroy(_mem_pool);
|
dm_pool_destroy(_mem_pool);
|
||||||
_mem_pool = NULL;
|
_mem_pool = NULL;
|
||||||
dm_list_init(&_env_registry);
|
|
||||||
lvm2_exit(_lvm_handle);
|
lvm2_exit(_lvm_handle);
|
||||||
_lvm_handle = NULL;
|
_lvm_handle = NULL;
|
||||||
log_debug("lvm plugin exited.");
|
log_debug("lvm plugin exited.");
|
||||||
@@ -124,7 +115,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,8 +124,6 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
|||||||
static char _internal_prefix[] = "_dmeventd_";
|
static char _internal_prefix[] = "_dmeventd_";
|
||||||
char *vg = NULL, *lv = NULL, *layer;
|
char *vg = NULL, *lv = NULL, *layer;
|
||||||
int r;
|
int r;
|
||||||
struct env_data *env_data;
|
|
||||||
const char *env = NULL;
|
|
||||||
|
|
||||||
if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
|
if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
|
||||||
log_error("Unable to determine VG name from %s.",
|
log_error("Unable to determine VG name from %s.",
|
||||||
@@ -144,41 +132,23 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* strip off the mirror component designations */
|
/* strip off the mirror component designations */
|
||||||
if ((layer = strstr(lv, MIRROR_SYNC_LAYER)) ||
|
if ((layer = strstr(lv, "_mimagetmp")) ||
|
||||||
(layer = strstr(lv, "_mlog")))
|
(layer = strstr(lv, "_mlog")))
|
||||||
*layer = '\0';
|
*layer = '\0';
|
||||||
|
|
||||||
if (!strncmp(cmd, _internal_prefix, sizeof(_internal_prefix) - 1)) {
|
if (!strncmp(cmd, _internal_prefix, sizeof(_internal_prefix) - 1)) {
|
||||||
/* check if ENVVAR wasn't already resolved */
|
|
||||||
dm_list_iterate_items(env_data, &_env_registry)
|
|
||||||
if (!strcmp(cmd, env_data->cmd)) {
|
|
||||||
env = env_data->data;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!env) {
|
|
||||||
/* run lvm2 command to find out setting value */
|
|
||||||
dmeventd_lvm2_lock();
|
dmeventd_lvm2_lock();
|
||||||
if (!dmeventd_lvm2_run(cmd) ||
|
/* output of internal command passed via env var */
|
||||||
!(env = getenv(cmd))) {
|
if (!dmeventd_lvm2_run(cmd))
|
||||||
|
cmd = NULL;
|
||||||
|
else if ((cmd = getenv(cmd)))
|
||||||
|
cmd = dm_pool_strdup(mem, cmd); /* copy with lock */
|
||||||
dmeventd_lvm2_unlock();
|
dmeventd_lvm2_unlock();
|
||||||
|
|
||||||
|
if (!cmd) {
|
||||||
log_error("Unable to find configured command.");
|
log_error("Unable to find configured command.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* output of internal command passed via env var */
|
|
||||||
env = dm_pool_strdup(_mem_pool, env); /* copy with lock */
|
|
||||||
dmeventd_lvm2_unlock();
|
|
||||||
if (!env ||
|
|
||||||
!(env_data = dm_pool_zalloc(_mem_pool, sizeof(*env_data))) ||
|
|
||||||
!(env_data->cmd = dm_pool_strdup(_mem_pool, cmd))) {
|
|
||||||
log_error("Unable to allocate env memory.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
env_data->data = env;
|
|
||||||
/* add to ENVVAR registry */
|
|
||||||
dm_list_add(&_env_registry, &env_data->list);
|
|
||||||
}
|
|
||||||
cmd = env;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv);
|
r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv);
|
||||||
|
|||||||
@@ -25,8 +25,6 @@
|
|||||||
#ifndef _DMEVENTD_LVMWRAP_H
|
#ifndef _DMEVENTD_LVMWRAP_H
|
||||||
#define _DMEVENTD_LVMWRAP_H
|
#define _DMEVENTD_LVMWRAP_H
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
struct dm_pool;
|
struct dm_pool;
|
||||||
|
|
||||||
int dmeventd_lvm2_init(void);
|
int dmeventd_lvm2_init(void);
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||||
LIBS += -ldevmapper-event-lvm2
|
|
||||||
|
|
||||||
SOURCES = dmeventd_mirror.c
|
SOURCES = dmeventd_mirror.c
|
||||||
|
|
||||||
@@ -25,8 +25,13 @@ LIB_NAME = libdevmapper-event-lvm2mirror
|
|||||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||||
|
|
||||||
|
CFLOW_LIST = $(SOURCES)
|
||||||
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
|
||||||
|
|
||||||
install_lvm2: install_dm_plugin
|
install_lvm2: install_dm_plugin
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/misc/lib.h"
|
#include "lib/misc/lib.h"
|
||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||||
|
#include "dmeventd_lvm.h"
|
||||||
#include "lib/activate/activate.h"
|
#include "lib/activate/activate.h"
|
||||||
|
|
||||||
/* FIXME Reformat to 80 char lines. */
|
/* FIXME Reformat to 80 char lines. */
|
||||||
@@ -38,7 +38,7 @@ static void _process_status_code(dm_status_mirror_health_t health,
|
|||||||
* A => Alive - No failures
|
* A => Alive - No failures
|
||||||
* D => Dead - A write failure occurred leaving mirror out-of-sync
|
* D => Dead - A write failure occurred leaving mirror out-of-sync
|
||||||
* F => Flush failed.
|
* F => Flush failed.
|
||||||
* S => Sync - A synchronization failure occurred, mirror out-of-sync
|
* S => Sync - A sychronization failure occurred, mirror out-of-sync
|
||||||
* R => Read - A read failure occurred, mirror data unaffected
|
* R => Read - A read failure occurred, mirror data unaffected
|
||||||
* U => Unclassified failure (bug)
|
* U => Unclassified failure (bug)
|
||||||
*/
|
*/
|
||||||
@@ -112,7 +112,7 @@ static int _remove_failed_devices(const char *cmd_lvconvert, const char *device)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask evmask __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **user)
|
void **user)
|
||||||
{
|
{
|
||||||
struct dso_state *state = *user;
|
struct dso_state *state = *user;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||||
LIBS += -ldevmapper-event-lvm2
|
|
||||||
|
|
||||||
SOURCES = dmeventd_raid.c
|
SOURCES = dmeventd_raid.c
|
||||||
|
|
||||||
@@ -24,8 +24,13 @@ LIB_NAME = libdevmapper-event-lvm2raid
|
|||||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||||
|
|
||||||
|
CFLOW_LIST = $(SOURCES)
|
||||||
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
|
||||||
|
|
||||||
install_lvm2: install_dm_plugin
|
install_lvm2: install_dm_plugin
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -13,11 +13,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/misc/lib.h"
|
#include "lib/misc/lib.h"
|
||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
|
||||||
#include "lib/config/defaults.h"
|
#include "lib/config/defaults.h"
|
||||||
|
#include "dmeventd_lvm.h"
|
||||||
|
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||||
|
|
||||||
/* Hold enough elements for the maximum number of RAID images */
|
/* Hold enough elements for the mximum number of RAID images */
|
||||||
#define RAID_DEVS_ELEMS ((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
|
#define RAID_DEVS_ELEMS ((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
|
||||||
|
|
||||||
struct dso_state {
|
struct dso_state {
|
||||||
@@ -76,17 +76,14 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dead) {
|
if (dead) {
|
||||||
/*
|
if (status->insync_regions < status->total_regions) {
|
||||||
* Use the first event to run a repair ignoring any additional ones.
|
if (!state->warned) {
|
||||||
*
|
|
||||||
* We presume lvconvert to do pre-repair
|
|
||||||
* checks to avoid bloat in this plugin.
|
|
||||||
*/
|
|
||||||
if (!state->warned && status->insync_regions < status->total_regions) {
|
|
||||||
state->warned = 1;
|
state->warned = 1;
|
||||||
log_warn("WARNING: Waiting for resynchronization to finish "
|
log_warn("WARNING: waiting for resynchronization to finish "
|
||||||
"before initiating repair on RAID device %s.", device);
|
"before initiating repair on RAID device %s.", device);
|
||||||
/* Fall through to allow lvconvert to run. */
|
}
|
||||||
|
|
||||||
|
goto out; /* Not yet done syncing with accessible devices */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->failed)
|
if (state->failed)
|
||||||
@@ -114,7 +111,7 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask evmask __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **user)
|
void **user)
|
||||||
{
|
{
|
||||||
struct dso_state *state = *user;
|
struct dso_state *state = *user;
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||||
LIBS += -ldevmapper-event-lvm2
|
|
||||||
|
|
||||||
SOURCES = dmeventd_snapshot.c
|
SOURCES = dmeventd_snapshot.c
|
||||||
|
|
||||||
@@ -26,6 +26,8 @@ LIB_VERSION = $(LIB_VERSION_LVM)
|
|||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
|
||||||
|
|
||||||
install_lvm2: install_dm_plugin
|
install_lvm2: install_dm_plugin
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/misc/lib.h"
|
#include "lib/misc/lib.h"
|
||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||||
|
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
@@ -163,7 +163,7 @@ static void _umount(const char *device, int major, int minor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask evmask __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **user)
|
void **user)
|
||||||
{
|
{
|
||||||
struct dso_state *state = *user;
|
struct dso_state *state = *user;
|
||||||
@@ -175,7 +175,6 @@ void process_event(struct dm_task *dmt,
|
|||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
int percent;
|
int percent;
|
||||||
struct dm_info info;
|
struct dm_info info;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* No longer monitoring, waiting for remove */
|
/* No longer monitoring, waiting for remove */
|
||||||
if (!state->percent_check)
|
if (!state->percent_check)
|
||||||
@@ -206,8 +205,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
/* Maybe configurable ? */
|
/* Maybe configurable ? */
|
||||||
_remove(dm_task_get_uuid(dmt));
|
_remove(dm_task_get_uuid(dmt));
|
||||||
#endif
|
#endif
|
||||||
if ((ret = pthread_kill(pthread_self(), SIGALRM)) && (ret != ESRCH))
|
pthread_kill(pthread_self(), SIGALRM);
|
||||||
log_sys_error("pthread_kill", "self");
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,8 +213,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
/* TODO eventually recognize earlier when room is enough */
|
/* TODO eventually recognize earlier when room is enough */
|
||||||
log_info("Dropping monitoring of fully provisioned snapshot %s.",
|
log_info("Dropping monitoring of fully provisioned snapshot %s.",
|
||||||
device);
|
device);
|
||||||
if ((ret = pthread_kill(pthread_self(), SIGALRM)) && (ret != ESRCH))
|
pthread_kill(pthread_self(), SIGALRM);
|
||||||
log_sys_error("pthread_kill", "self");
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||||
LIBS += -ldevmapper-event-lvm2
|
|
||||||
|
|
||||||
SOURCES = dmeventd_thin.c
|
SOURCES = dmeventd_thin.c
|
||||||
|
|
||||||
@@ -24,8 +24,13 @@ LIB_NAME = libdevmapper-event-lvm2thin
|
|||||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||||
|
|
||||||
|
CFLOW_LIST = $(SOURCES)
|
||||||
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
|
||||||
|
|
||||||
install_lvm2: install_dm_plugin
|
install_lvm2: install_dm_plugin
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/misc/lib.h"
|
#include "lib/misc/lib.h"
|
||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
@@ -45,10 +45,10 @@
|
|||||||
|
|
||||||
struct dso_state {
|
struct dso_state {
|
||||||
struct dm_pool *mem;
|
struct dm_pool *mem;
|
||||||
dm_percent_t metadata_percent_check;
|
int metadata_percent_check;
|
||||||
dm_percent_t metadata_percent;
|
int metadata_percent;
|
||||||
dm_percent_t data_percent_check;
|
int data_percent_check;
|
||||||
dm_percent_t data_percent;
|
int data_percent;
|
||||||
uint64_t known_metadata_size;
|
uint64_t known_metadata_size;
|
||||||
uint64_t known_data_size;
|
uint64_t known_data_size;
|
||||||
unsigned fails;
|
unsigned fails;
|
||||||
@@ -87,7 +87,7 @@ static int _run_command(struct dso_state *state)
|
|||||||
log_verbose("Executing command: %s", state->cmd_str);
|
log_verbose("Executing command: %s", state->cmd_str);
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* Support parallel run of 'task' and it's waitpid maintenance
|
* Support parallel run of 'task' and it's waitpid maintainence
|
||||||
* ATM we can't handle signaling of SIGALRM
|
* ATM we can't handle signaling of SIGALRM
|
||||||
* as signalling is not allowed while 'process_event()' is running
|
* as signalling is not allowed while 'process_event()' is running
|
||||||
*/
|
*/
|
||||||
@@ -155,7 +155,7 @@ static int _wait_for_pid(struct dso_state *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask evmask,
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **user)
|
void **user)
|
||||||
{
|
{
|
||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
@@ -179,7 +179,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evmask & DM_EVENT_DEVICE_ERROR) {
|
if (event & DM_EVENT_DEVICE_ERROR) {
|
||||||
/* Error -> no need to check and do instant resize */
|
/* Error -> no need to check and do instant resize */
|
||||||
state->data_percent = state->metadata_percent = 0;
|
state->data_percent = state->metadata_percent = 0;
|
||||||
if (_use_policy(dmt, state))
|
if (_use_policy(dmt, state))
|
||||||
@@ -223,12 +223,10 @@ void process_event(struct dm_task *dmt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if THIN_DEBUG
|
#if THIN_DEBUG
|
||||||
log_debug("Thin pool status " FMTu64 "/" FMTu64 " (" FMTu64 ") "
|
log_debug("Thin pool status " FMTu64 "/" FMTu64 " "
|
||||||
FMTu64 "/" FMTu64 " (" FMTu64").",
|
FMTu64 "/" FMTu64 ".",
|
||||||
tps->used_data_blocks, tps->total_data_blocks,
|
|
||||||
state->known_data_size,
|
|
||||||
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
||||||
state->known_metadata_size);
|
tps->used_data_blocks, tps->total_data_blocks);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Thin pool size had changed. Clear the threshold. */
|
/* Thin pool size had changed. Clear the threshold. */
|
||||||
@@ -247,7 +245,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
/*
|
/*
|
||||||
* Trigger action when threshold boundary is exceeded.
|
* Trigger action when threshold boundary is exceeded.
|
||||||
* Report 80% threshold warning when it's used above 80%.
|
* Report 80% threshold warning when it's used above 80%.
|
||||||
* Only 100% is exception as it cannot be surpassed so policy
|
* Only 100% is exception as it cannot be surpased so policy
|
||||||
* action is called for: >50%, >55% ... >95%, 100%
|
* action is called for: >50%, >55% ... >95%, 100%
|
||||||
*/
|
*/
|
||||||
state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
|
state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
|
||||||
@@ -288,7 +286,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
if (state->fails++ <= state->max_fails) {
|
if (state->fails++ <= state->max_fails) {
|
||||||
log_debug("Postponing frequently failing policy (%u <= %u).",
|
log_debug("Postponing frequently failing policy (%u <= %u).",
|
||||||
state->fails - 1, state->max_fails);
|
state->fails - 1, state->max_fails);
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
if (state->max_fails < MAX_FAILS)
|
if (state->max_fails < MAX_FAILS)
|
||||||
state->max_fails <<= 1;
|
state->max_fails <<= 1;
|
||||||
@@ -381,13 +379,14 @@ int register_device(const char *device,
|
|||||||
|
|
||||||
state->argv[1] = str + 1; /* 1 argument - vg/lv */
|
state->argv[1] = str + 1; /* 1 argument - vg/lv */
|
||||||
_init_thread_signals(state);
|
_init_thread_signals(state);
|
||||||
} else /* Unsupported command format */
|
} else /* Unuspported command format */
|
||||||
goto inval;
|
goto inval;
|
||||||
|
|
||||||
state->max_fails = 1;
|
|
||||||
state->pid = -1;
|
state->pid = -1;
|
||||||
*user = state;
|
*user = state;
|
||||||
|
|
||||||
|
log_info("Monitoring thin pool %s.", device);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
inval:
|
inval:
|
||||||
log_error("Invalid command for monitoring: %s.", cmd_str);
|
log_error("Invalid command for monitoring: %s.", cmd_str);
|
||||||
@@ -431,6 +430,7 @@ int unregister_device(const char *device,
|
|||||||
_restore_thread_signals(state);
|
_restore_thread_signals(state);
|
||||||
|
|
||||||
dmeventd_lvm2_exit_with_pool(state);
|
dmeventd_lvm2_exit_with_pool(state);
|
||||||
|
log_info("No longer monitoring thin pool %s.", device);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||||
LIBS += -ldevmapper-event-lvm2
|
|
||||||
|
|
||||||
SOURCES = dmeventd_vdo.c
|
SOURCES = dmeventd_vdo.c
|
||||||
|
|
||||||
@@ -24,8 +24,13 @@ LIB_NAME = libdevmapper-event-lvm2vdo
|
|||||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||||
|
|
||||||
|
CFLOW_LIST = $(SOURCES)
|
||||||
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
|
||||||
|
|
||||||
install_lvm2: install_dm_plugin
|
install_lvm2: install_dm_plugin
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -13,17 +13,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/misc/lib.h"
|
#include "lib/misc/lib.h"
|
||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||||
|
#include "device_mapper/vdo/target.h"
|
||||||
/*
|
|
||||||
* Use parser from new device_mapper library.
|
|
||||||
* Although during compilation we can see dm_vdo_status_parse()
|
|
||||||
* in runtime we are linked against systems libdm 'older' library
|
|
||||||
* which does not provide this symbol and plugin fails to load
|
|
||||||
*/
|
|
||||||
/* coverity[unnecessary_header] used for parsing */
|
|
||||||
#include "device_mapper/vdo/status.c"
|
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@@ -78,7 +70,7 @@ static int _run_command(struct dso_state *state)
|
|||||||
log_verbose("Executing command: %s", state->cmd_str);
|
log_verbose("Executing command: %s", state->cmd_str);
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* Support parallel run of 'task' and it's waitpid maintenance
|
* Support parallel run of 'task' and it's waitpid maintainence
|
||||||
* ATM we can't handle signaling of SIGALRM
|
* ATM we can't handle signaling of SIGALRM
|
||||||
* as signalling is not allowed while 'process_event()' is running
|
* as signalling is not allowed while 'process_event()' is running
|
||||||
*/
|
*/
|
||||||
@@ -146,7 +138,7 @@ static int _wait_for_pid(struct dso_state *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask evmask __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **user)
|
void **user)
|
||||||
{
|
{
|
||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
@@ -169,7 +161,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evmask & DM_EVENT_DEVICE_ERROR) {
|
if (event & DM_EVENT_DEVICE_ERROR) {
|
||||||
#if VDO_DEBUG
|
#if VDO_DEBUG
|
||||||
log_debug("VDO event error.");
|
log_debug("VDO event error.");
|
||||||
#endif
|
#endif
|
||||||
@@ -227,7 +219,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
/*
|
/*
|
||||||
* Trigger action when threshold boundary is exceeded.
|
* Trigger action when threshold boundary is exceeded.
|
||||||
* Report 80% threshold warning when it's used above 80%.
|
* Report 80% threshold warning when it's used above 80%.
|
||||||
* Only 100% is exception as it cannot be surpassed so policy
|
* Only 100% is exception as it cannot be surpased so policy
|
||||||
* action is called for: >50%, >55% ... >95%, 100%
|
* action is called for: >50%, >55% ... >95%, 100%
|
||||||
*/
|
*/
|
||||||
if ((state->percent > WARNING_THRESH) &&
|
if ((state->percent > WARNING_THRESH) &&
|
||||||
@@ -253,7 +245,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
if (state->fails++ <= state->max_fails) {
|
if (state->fails++ <= state->max_fails) {
|
||||||
log_debug("Postponing frequently failing policy (%u <= %u).",
|
log_debug("Postponing frequently failing policy (%u <= %u).",
|
||||||
state->fails - 1, state->max_fails);
|
state->fails - 1, state->max_fails);
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
if (state->max_fails < MAX_FAILS)
|
if (state->max_fails < MAX_FAILS)
|
||||||
state->max_fails <<= 1;
|
state->max_fails <<= 1;
|
||||||
@@ -261,7 +253,8 @@ void process_event(struct dm_task *dmt,
|
|||||||
} else
|
} else
|
||||||
state->max_fails = 1; /* Reset on success */
|
state->max_fails = 1; /* Reset on success */
|
||||||
|
|
||||||
if (needs_policy)
|
/* FIXME: ATM nothing can be done, drop 0, once it becomes useful */
|
||||||
|
if (0 && needs_policy)
|
||||||
_use_policy(dmt, state);
|
_use_policy(dmt, state);
|
||||||
out:
|
out:
|
||||||
if (vdop.status)
|
if (vdop.status)
|
||||||
@@ -354,7 +347,7 @@ int register_device(const char *device,
|
|||||||
_init_thread_signals(state);
|
_init_thread_signals(state);
|
||||||
} else if (cmd[0] == 0) {
|
} else if (cmd[0] == 0) {
|
||||||
state->name = "volume"; /* What to use with 'others?' */
|
state->name = "volume"; /* What to use with 'others?' */
|
||||||
} else/* Unsupported command format */
|
} else/* Unuspported command format */
|
||||||
goto inval;
|
goto inval;
|
||||||
|
|
||||||
state->pid = -1;
|
state->pid = -1;
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
lvmdbuspydir = $(python3dir)/lvmdbusd
|
lvmdbusdir = $(python3dir)/lvmdbusd
|
||||||
lvmdbusdir = $(DESTDIR)$(lvmdbuspydir)
|
|
||||||
|
|
||||||
LVMDBUS_SRCDIR_FILES = \
|
LVMDBUS_SRCDIR_FILES = \
|
||||||
automatedproperties.py \
|
automatedproperties.py \
|
||||||
@@ -24,10 +23,11 @@ LVMDBUS_SRCDIR_FILES = \
|
|||||||
cfg.py \
|
cfg.py \
|
||||||
cmdhandler.py \
|
cmdhandler.py \
|
||||||
fetch.py \
|
fetch.py \
|
||||||
|
__init__.py \
|
||||||
job.py \
|
job.py \
|
||||||
loader.py \
|
loader.py \
|
||||||
lv.py \
|
|
||||||
main.py \
|
main.py \
|
||||||
|
lv.py \
|
||||||
manager.py \
|
manager.py \
|
||||||
objectmanager.py \
|
objectmanager.py \
|
||||||
pv.py \
|
pv.py \
|
||||||
@@ -35,8 +35,7 @@ LVMDBUS_SRCDIR_FILES = \
|
|||||||
state.py \
|
state.py \
|
||||||
udevwatch.py \
|
udevwatch.py \
|
||||||
utils.py \
|
utils.py \
|
||||||
vg.py \
|
vg.py
|
||||||
__init__.py
|
|
||||||
|
|
||||||
LVMDBUS_BUILDDIR_FILES = \
|
LVMDBUS_BUILDDIR_FILES = \
|
||||||
lvmdb.py \
|
lvmdb.py \
|
||||||
@@ -51,15 +50,18 @@ include $(top_builddir)/make.tmpl
|
|||||||
|
|
||||||
.PHONY: install_lvmdbusd
|
.PHONY: install_lvmdbusd
|
||||||
|
|
||||||
install_lvmdbusd: $(LVMDBUSD)
|
all:
|
||||||
$(SHOW) " [INSTALL] $<"
|
test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
|
||||||
$(Q) $(INSTALL_DIR) $(sbindir)
|
|
||||||
$(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
install_lvmdbusd:
|
||||||
$(Q) $(INSTALL_DIR) $(lvmdbusdir) $(lvmdbusdir)/__pycache__
|
$(INSTALL_DIR) $(sbindir)
|
||||||
$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(lvmdbusdir))
|
$(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
||||||
$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir)
|
$(INSTALL_DIR) $(DESTDIR)$(lvmdbusdir)
|
||||||
$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbuspydir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
|
(cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(DESTDIR)$(lvmdbusdir))
|
||||||
$(Q) $(CHMOD) 444 $(lvmdbusdir)/__pycache__/*.py[co]
|
$(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(DESTDIR)$(lvmdbusdir)
|
||||||
|
PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbusdir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
|
||||||
|
$(CHMOD) 755 $(DESTDIR)$(lvmdbusdir)/__pycache__
|
||||||
|
$(CHMOD) 444 $(DESTDIR)$(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):
|
||||||
@@ -154,17 +155,16 @@ class AutomatedProperties(dbus.service.Object):
|
|||||||
# through all dbus objects as some don't have a search method, like
|
# through all dbus objects as some don't have a search method, like
|
||||||
# 'Manager' object.
|
# 'Manager' object.
|
||||||
if not self._ap_search_method:
|
if not self._ap_search_method:
|
||||||
return 0
|
return
|
||||||
|
|
||||||
|
search = self.lvm_id
|
||||||
|
if search_key:
|
||||||
|
search = search_key
|
||||||
|
|
||||||
# Either we have the new object state or we need to go fetch it
|
# Either we have the new object state or we need to go fetch it
|
||||||
if object_state:
|
if object_state:
|
||||||
new_state = object_state
|
new_state = object_state
|
||||||
else:
|
else:
|
||||||
if search_key:
|
|
||||||
search = search_key
|
|
||||||
else:
|
|
||||||
search = self.lvm_id
|
|
||||||
|
|
||||||
new_state = self._ap_search_method([search])[0]
|
new_state = self._ap_search_method([search])[0]
|
||||||
assert isinstance(new_state, State)
|
assert isinstance(new_state, State)
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +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 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
|
||||||
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,\
|
||||||
from .request import RequestEntry
|
add_no_notify
|
||||||
|
import os
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -37,47 +39,58 @@ def lv_merge_cmd(merge_options, lv_full_name):
|
|||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
def _load_wrapper(ignored):
|
|
||||||
cfg.load()
|
|
||||||
|
|
||||||
|
|
||||||
def _move_callback(job_state, line_str):
|
|
||||||
try:
|
|
||||||
if line_str.count(':') == 2:
|
|
||||||
(device, ignore, percentage) = line_str.split(':')
|
|
||||||
|
|
||||||
job_state.Percent = int(round(
|
|
||||||
float(percentage.strip()[:-1]), 1))
|
|
||||||
|
|
||||||
# While the move is in progress we need to periodically update
|
|
||||||
# the state to reflect where everything is at. we will do this
|
|
||||||
# by scheduling the load to occur in the main work queue.
|
|
||||||
r = RequestEntry(
|
|
||||||
-1, _load_wrapper, ("_move_callback: load",), None, None, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
except ValueError:
|
|
||||||
log_error("Trying to parse percentage which failed for %s" % 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.
|
||||||
|
command.insert(0, cfg.LVM_CMD)
|
||||||
|
|
||||||
meta = LvmExecutionMeta(time.time(), 0, command)
|
# Instruct lvm to not register an event with us
|
||||||
cfg.flightrecorder.add(meta)
|
command = add_no_notify(command)
|
||||||
|
|
||||||
ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
|
#(self, start, ended, cmd, ec, stdout_txt, stderr_txt)
|
||||||
cb_data=job_state)
|
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
|
||||||
ended = time.time()
|
|
||||||
meta.completed(ended, ec, stdout, stderr)
|
|
||||||
|
|
||||||
if ec == 0:
|
cfg.blackbox.add(meta)
|
||||||
|
|
||||||
|
process = subprocess.Popen(command, stdout=subprocess.PIPE,
|
||||||
|
env=os.environ,
|
||||||
|
stderr=subprocess.PIPE, close_fds=True)
|
||||||
|
|
||||||
|
log_debug("Background process for %s is %d" %
|
||||||
|
(str(command), process.pid))
|
||||||
|
|
||||||
|
lines_iterator = iter(process.stdout.readline, b"")
|
||||||
|
for line in lines_iterator:
|
||||||
|
line_str = line.decode("utf-8")
|
||||||
|
|
||||||
|
# Check to see if the line has the correct number of separators
|
||||||
|
try:
|
||||||
|
if line_str.count(':') == 2:
|
||||||
|
(device, ignore, percentage) = line_str.split(':')
|
||||||
|
job_state.Percent = round(
|
||||||
|
float(percentage.strip()[:-1]), 1)
|
||||||
|
|
||||||
|
# While the move is in progress we need to periodically update
|
||||||
|
# the state to reflect where everything is at.
|
||||||
|
cfg.load()
|
||||||
|
except ValueError:
|
||||||
|
log_error("Trying to parse percentage which failed for %s" %
|
||||||
|
line_str)
|
||||||
|
|
||||||
|
out = process.communicate()
|
||||||
|
|
||||||
|
with meta.lock:
|
||||||
|
meta.ended = time.time()
|
||||||
|
meta.ec = process.returncode
|
||||||
|
meta.stderr_txt = out[1]
|
||||||
|
|
||||||
|
if process.returncode == 0:
|
||||||
job_state.Percent = 100
|
job_state.Percent = 100
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
interface_name,
|
interface_name,
|
||||||
'Exit code %s, stderr = %s' % (str(ec), stderr))
|
'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
|
||||||
|
|
||||||
cfg.load()
|
cfg.load()
|
||||||
return '/'
|
return '/'
|
||||||
|
|||||||
@@ -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,20 +43,13 @@ 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'
|
||||||
VG_INTERFACE = BASE_INTERFACE + '.Vg'
|
VG_INTERFACE = BASE_INTERFACE + '.Vg'
|
||||||
VG_VDO_INTERFACE = BASE_INTERFACE + '.VgVdo'
|
|
||||||
LV_INTERFACE = BASE_INTERFACE + '.Lv'
|
LV_INTERFACE = BASE_INTERFACE + '.Lv'
|
||||||
LV_COMMON_INTERFACE = BASE_INTERFACE + '.LvCommon'
|
LV_COMMON_INTERFACE = BASE_INTERFACE + '.LvCommon'
|
||||||
THIN_POOL_INTERFACE = BASE_INTERFACE + '.ThinPool'
|
THIN_POOL_INTERFACE = BASE_INTERFACE + '.ThinPool'
|
||||||
VDO_POOL_INTERFACE = BASE_INTERFACE + '.VdoPool'
|
|
||||||
CACHE_POOL_INTERFACE = BASE_INTERFACE + '.CachePool'
|
CACHE_POOL_INTERFACE = BASE_INTERFACE + '.CachePool'
|
||||||
LV_CACHED = BASE_INTERFACE + '.CachedLv'
|
LV_CACHED = BASE_INTERFACE + '.CachedLv'
|
||||||
SNAPSHOT_INTERFACE = BASE_INTERFACE + '.Snapshot'
|
SNAPSHOT_INTERFACE = BASE_INTERFACE + '.Snapshot'
|
||||||
@@ -75,7 +61,6 @@ PV_OBJ_PATH = BASE_OBJ_PATH + '/Pv'
|
|||||||
VG_OBJ_PATH = BASE_OBJ_PATH + '/Vg'
|
VG_OBJ_PATH = BASE_OBJ_PATH + '/Vg'
|
||||||
LV_OBJ_PATH = BASE_OBJ_PATH + '/Lv'
|
LV_OBJ_PATH = BASE_OBJ_PATH + '/Lv'
|
||||||
THIN_POOL_PATH = BASE_OBJ_PATH + "/ThinPool"
|
THIN_POOL_PATH = BASE_OBJ_PATH + "/ThinPool"
|
||||||
VDO_POOL_PATH = BASE_OBJ_PATH + "/VdoPool"
|
|
||||||
CACHE_POOL_PATH = BASE_OBJ_PATH + "/CachePool"
|
CACHE_POOL_PATH = BASE_OBJ_PATH + "/CachePool"
|
||||||
HIDDEN_LV_PATH = BASE_OBJ_PATH + "/HiddenLv"
|
HIDDEN_LV_PATH = BASE_OBJ_PATH + "/HiddenLv"
|
||||||
MANAGER_OBJ_PATH = BASE_OBJ_PATH + '/Manager'
|
MANAGER_OBJ_PATH = BASE_OBJ_PATH + '/Manager'
|
||||||
@@ -86,7 +71,6 @@ pv_id = itertools.count()
|
|||||||
vg_id = itertools.count()
|
vg_id = itertools.count()
|
||||||
lv_id = itertools.count()
|
lv_id = itertools.count()
|
||||||
thin_id = itertools.count()
|
thin_id = itertools.count()
|
||||||
vdo_id = itertools.count()
|
|
||||||
cache_pool_id = itertools.count()
|
cache_pool_id = itertools.count()
|
||||||
job_id = itertools.count()
|
job_id = itertools.count()
|
||||||
hidden_lv = itertools.count()
|
hidden_lv = itertools.count()
|
||||||
@@ -95,30 +79,11 @@ hidden_lv = itertools.count()
|
|||||||
load = None
|
load = None
|
||||||
event = None
|
event = None
|
||||||
|
|
||||||
# Boolean to denote if lvm supports VDO integration
|
|
||||||
vdo_support = False
|
|
||||||
|
|
||||||
# Global cached state
|
# Global cached state
|
||||||
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():
|
|
||||||
"""
|
|
||||||
Exit the daemon cleanly
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if run and loop:
|
|
||||||
run.value = 0
|
|
||||||
loop.quit()
|
|
||||||
|
|
||||||
|
|
||||||
systemd = False
|
|
||||||
|
|||||||
@@ -6,18 +6,17 @@
|
|||||||
#
|
#
|
||||||
# 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 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
|
|
||||||
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
|
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -25,6 +24,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 +36,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 +47,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 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):
|
||||||
@@ -99,98 +82,33 @@ def _debug_c(cmd, exit_code, out):
|
|||||||
log_error(("STDERR=\n %s\n" % out[1]))
|
log_error(("STDERR=\n %s\n" % out[1]))
|
||||||
|
|
||||||
|
|
||||||
def call_lvm(command, debug=False, line_cb=None,
|
def call_lvm(command, debug=False):
|
||||||
cb_data=None):
|
|
||||||
"""
|
"""
|
||||||
Call an executable and return a tuple of exitcode, stdout, stderr
|
Call an executable and return a tuple of exitcode, stdout, stderr
|
||||||
:param command: Command to execute
|
:param command: Command to execute
|
||||||
:param debug: Dump debug to stdout
|
:param debug: Dump debug to stdout
|
||||||
:param line_cb: Call the supplied function for each line read from
|
|
||||||
stdin, CALL MUST EXECUTE QUICKLY and not *block*
|
|
||||||
otherwise call_lvm function will fail to read
|
|
||||||
stdin/stdout. Return value of call back is ignored
|
|
||||||
:param cb_data: Supplied to call back to allow caller access to
|
|
||||||
its own data
|
|
||||||
|
|
||||||
# Callback signature
|
|
||||||
def my_callback(my_context, line_read_stdin)
|
|
||||||
pass
|
|
||||||
"""
|
"""
|
||||||
|
# print 'STACK:'
|
||||||
|
# for line in traceback.format_stack():
|
||||||
|
# print line.strip()
|
||||||
|
|
||||||
# Prepend the full lvm executable so that we can run different versions
|
# Prepend the full lvm executable so that we can run different versions
|
||||||
# in different locations on the same box
|
# in different locations on the same box
|
||||||
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)
|
||||||
|
out = process.communicate()
|
||||||
|
|
||||||
stdout_text = ""
|
stdout_text = bytes(out[0]).decode("utf-8")
|
||||||
stderr_text = ""
|
stderr_text = bytes(out[1]).decode("utf-8")
|
||||||
stdout_index = 0
|
|
||||||
make_non_block(process.stdout)
|
|
||||||
make_non_block(process.stderr)
|
|
||||||
|
|
||||||
while True and cfg.run.value != 0:
|
if debug or process.returncode != 0:
|
||||||
try:
|
|
||||||
rd_fd = [process.stdout.fileno(), process.stderr.fileno()]
|
|
||||||
ready = select.select(rd_fd, [], [], cfg.G_LOOP_TMO)
|
|
||||||
|
|
||||||
for r in ready[0]:
|
|
||||||
if r == process.stdout.fileno():
|
|
||||||
stdout_text += read_decoded(process.stdout)
|
|
||||||
elif r == process.stderr.fileno():
|
|
||||||
stderr_text += read_decoded(process.stderr)
|
|
||||||
|
|
||||||
if line_cb is not None:
|
|
||||||
# Process the callback for each line read!
|
|
||||||
while True:
|
|
||||||
i = stdout_text.find("\n", stdout_index)
|
|
||||||
if i != -1:
|
|
||||||
try:
|
|
||||||
line_cb(cb_data, stdout_text[stdout_index:i])
|
|
||||||
except BaseException as be:
|
|
||||||
st = extract_stack_trace(be)
|
|
||||||
log_error("call_lvm: line_cb exception: \n %s" % st)
|
|
||||||
stdout_index = i + 1
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Check to see if process has terminated, None when running
|
|
||||||
if process.poll() is not None:
|
|
||||||
stdout_text += read_decoded(process.stdout)
|
|
||||||
stderr_text += read_decoded(process.stderr)
|
|
||||||
break
|
|
||||||
except IOError as ioe:
|
|
||||||
log_debug("call_lvm:" + str(ioe))
|
|
||||||
break
|
|
||||||
|
|
||||||
if process.returncode is not None:
|
|
||||||
cfg.lvmdebug.lvm_complete()
|
|
||||||
if debug or (process.returncode != 0 and (process.returncode != 5 and "fullreport" in command)):
|
|
||||||
_debug_c(command, process.returncode, (stdout_text, stderr_text))
|
_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
|
||||||
@@ -204,18 +122,18 @@ def _shell_cfg():
|
|||||||
_t_call = lvm_shell.call_lvm
|
_t_call = lvm_shell.call_lvm
|
||||||
cfg.SHELL_IN_USE = lvm_shell
|
cfg.SHELL_IN_USE = lvm_shell
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception:
|
||||||
_t_call = call_lvm
|
_t_call = call_lvm
|
||||||
cfg.SHELL_IN_USE = None
|
cfg.SHELL_IN_USE = None
|
||||||
log_error("Unable to utilize lvm shell, dropping "
|
log_error(traceback.format_exc())
|
||||||
"back to fork & exec\n%s" % extract_stack_trace(e))
|
log_error("Unable to utilize lvm shell, dropping back to fork & exec")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def set_execution(shell):
|
def set_execution(shell):
|
||||||
global _t_call
|
global _t_call
|
||||||
with cmd_lock:
|
with cmd_lock:
|
||||||
# If the user requested lvm shell, and we are currently setup that
|
# If the user requested lvm shell and we are currently setup that
|
||||||
# way, just return
|
# way, just return
|
||||||
if cfg.SHELL_IN_USE and shell:
|
if cfg.SHELL_IN_USE and shell:
|
||||||
return True
|
return True
|
||||||
@@ -239,15 +157,11 @@ def time_wrapper(command, debug=False):
|
|||||||
|
|
||||||
with cmd_lock:
|
with cmd_lock:
|
||||||
start = time.time()
|
start = time.time()
|
||||||
meta = LvmExecutionMeta(start, 0, command)
|
|
||||||
# Add the partial metadata to flight recorder, so if the command hangs
|
|
||||||
# we will see what it was.
|
|
||||||
cfg.flightrecorder.add(meta)
|
|
||||||
results = _t_call(command, debug)
|
results = _t_call(command, debug)
|
||||||
ended = time.time()
|
ended = time.time()
|
||||||
total_time += (ended - start)
|
total_time += (ended - start)
|
||||||
total_count += 1
|
total_count += 1
|
||||||
meta.completed(ended, *results)
|
cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
@@ -257,11 +171,44 @@ call = time_wrapper
|
|||||||
# Default cmd
|
# Default cmd
|
||||||
# Place default arguments for every command here.
|
# Place default arguments for every command here.
|
||||||
def _dc(cmd, args):
|
def _dc(cmd, args):
|
||||||
c = [cmd, '--nosuffix', '--unbuffered', '--units', 'b']
|
c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
|
||||||
|
'--unbuffered', '--units', 'b']
|
||||||
c.extend(args)
|
c.extend(args)
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def parse(out):
|
||||||
|
rc = []
|
||||||
|
|
||||||
|
for line in out.split('\n'):
|
||||||
|
# This line includes separators, so process them
|
||||||
|
if SEP in line:
|
||||||
|
elem = line.split(SEP)
|
||||||
|
cleaned_elem = []
|
||||||
|
for e in elem:
|
||||||
|
e = e.strip()
|
||||||
|
cleaned_elem.append(e)
|
||||||
|
|
||||||
|
if len(cleaned_elem) > 1:
|
||||||
|
rc.append(cleaned_elem)
|
||||||
|
else:
|
||||||
|
t = line.strip()
|
||||||
|
if len(t) > 0:
|
||||||
|
rc.append(t)
|
||||||
|
return rc
|
||||||
|
|
||||||
|
|
||||||
|
def parse_column_names(out, column_names):
|
||||||
|
lines = parse(out)
|
||||||
|
rc = []
|
||||||
|
|
||||||
|
for i in range(0, len(lines)):
|
||||||
|
d = dict(list(zip(column_names, lines[i])))
|
||||||
|
rc.append(d)
|
||||||
|
|
||||||
|
return rc
|
||||||
|
|
||||||
|
|
||||||
def options_to_cli_args(options):
|
def options_to_cli_args(options):
|
||||||
rc = []
|
rc = []
|
||||||
for k, v in list(dict(options).items()):
|
for k, v in list(dict(options).items()):
|
||||||
@@ -270,9 +217,6 @@ def options_to_cli_args(options):
|
|||||||
else:
|
else:
|
||||||
rc.append("--%s" % k)
|
rc.append("--%s" % k)
|
||||||
if v != "":
|
if v != "":
|
||||||
if isinstance(v, int):
|
|
||||||
rc.append(str(int(v)))
|
|
||||||
else:
|
|
||||||
rc.append(str(v))
|
rc.append(str(v))
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
@@ -319,26 +263,24 @@ def lv_tag(lv_name, add, rm, tag_options):
|
|||||||
return _tag('lvchange', lv_name, add, rm, tag_options)
|
return _tag('lvchange', lv_name, add, rm, tag_options)
|
||||||
|
|
||||||
|
|
||||||
def vg_rename(vg_uuid, new_name, rename_options):
|
def vg_rename(vg, new_name, rename_options):
|
||||||
cmd = ['vgrename']
|
cmd = ['vgrename']
|
||||||
cmd.extend(options_to_cli_args(rename_options))
|
cmd.extend(options_to_cli_args(rename_options))
|
||||||
cmd.extend([vg_uuid, new_name])
|
cmd.extend([vg, new_name])
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests):
|
def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests):
|
||||||
cmd = ['lvcreate']
|
cmd = ['lvcreate']
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
cmd.extend(['--size', '%dB' % size_bytes])
|
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||||
cmd.extend(['--name', name, vg_name, '--yes'])
|
cmd.extend(['--name', name, vg_name, '--yes'])
|
||||||
pv_dest_ranges(cmd, pv_dests)
|
pv_dest_ranges(cmd, pv_dests)
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
@@ -350,7 +292,7 @@ def vg_lv_snapshot(vg_name, snapshot_options, name, size_bytes):
|
|||||||
cmd.extend(["-s"])
|
cmd.extend(["-s"])
|
||||||
|
|
||||||
if size_bytes != 0:
|
if size_bytes != 0:
|
||||||
cmd.extend(['--size', '%dB' % size_bytes])
|
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||||
|
|
||||||
cmd.extend(['--name', name, vg_name])
|
cmd.extend(['--name', name, vg_name])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
@@ -361,9 +303,9 @@ def _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool):
|
|||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
|
|
||||||
if not thin_pool:
|
if not thin_pool:
|
||||||
cmd.extend(['--size', '%dB' % size_bytes])
|
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||||
else:
|
else:
|
||||||
cmd.extend(['--thin', '--size', '%dB' % size_bytes])
|
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
|
||||||
|
|
||||||
cmd.extend(['--yes'])
|
cmd.extend(['--yes'])
|
||||||
return cmd
|
return cmd
|
||||||
@@ -378,10 +320,10 @@ def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
|
|||||||
def vg_lv_create_striped(vg_name, create_options, name, size_bytes,
|
def vg_lv_create_striped(vg_name, create_options, name, size_bytes,
|
||||||
num_stripes, stripe_size_kb, thin_pool):
|
num_stripes, stripe_size_kb, thin_pool):
|
||||||
cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool)
|
cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool)
|
||||||
cmd.extend(['--stripes', str(int(num_stripes))])
|
cmd.extend(['--stripes', str(num_stripes)])
|
||||||
|
|
||||||
if stripe_size_kb != 0:
|
if stripe_size_kb != 0:
|
||||||
cmd.extend(['--stripesize', str(int(stripe_size_kb))])
|
cmd.extend(['--stripesize', str(stripe_size_kb)])
|
||||||
|
|
||||||
cmd.extend(['--name', name, vg_name])
|
cmd.extend(['--name', name, vg_name])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
@@ -394,13 +336,13 @@ def _vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
|
|||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
|
|
||||||
cmd.extend(['--type', raid_type])
|
cmd.extend(['--type', raid_type])
|
||||||
cmd.extend(['--size', '%dB' % size_bytes])
|
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||||
|
|
||||||
if num_stripes != 0:
|
if num_stripes != 0:
|
||||||
cmd.extend(['--stripes', str(int(num_stripes))])
|
cmd.extend(['--stripes', str(num_stripes)])
|
||||||
|
|
||||||
if stripe_size_kb != 0:
|
if stripe_size_kb != 0:
|
||||||
cmd.extend(['--stripesize', str(int(stripe_size_kb))])
|
cmd.extend(['--stripesize', str(stripe_size_kb)])
|
||||||
|
|
||||||
cmd.extend(['--name', name, vg_name, '--yes'])
|
cmd.extend(['--name', name, vg_name, '--yes'])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
@@ -421,8 +363,8 @@ def vg_lv_create_mirror(
|
|||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
|
|
||||||
cmd.extend(['--type', 'mirror'])
|
cmd.extend(['--type', 'mirror'])
|
||||||
cmd.extend(['--mirrors', str(int(num_copies))])
|
cmd.extend(['--mirrors', str(num_copies)])
|
||||||
cmd.extend(['--size', '%dB' % size_bytes])
|
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||||
cmd.extend(['--name', name, vg_name, '--yes'])
|
cmd.extend(['--name', name, vg_name, '--yes'])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
@@ -443,24 +385,6 @@ def vg_create_thin_pool(md_full_name, data_full_name, create_options):
|
|||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
|
|
||||||
def vg_create_vdo_pool_lv_and_lv(vg_name, pool_name, lv_name, data_size,
|
|
||||||
virtual_size, create_options):
|
|
||||||
cmd = ['lvcreate']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
cmd.extend(['-y', '--type', 'vdo', '-n', lv_name,
|
|
||||||
'-L', '%dB' % data_size, '-V', '%dB' % virtual_size,
|
|
||||||
"%s/%s" % (vg_name, pool_name)])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_create_vdo_pool(pool_full_name, lv_name, virtual_size, create_options):
|
|
||||||
cmd = ['lvconvert']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
cmd.extend(['--type', 'vdo-pool', '-n', lv_name, '--force', '-y',
|
|
||||||
'-V', '%dB' % virtual_size, pool_full_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_remove(lv_path, remove_options):
|
def lv_remove(lv_path, remove_options):
|
||||||
cmd = ['lvremove']
|
cmd = ['lvremove']
|
||||||
cmd.extend(options_to_cli_args(remove_options))
|
cmd.extend(options_to_cli_args(remove_options))
|
||||||
@@ -494,7 +418,7 @@ def lv_resize(lv_full_name, size_change, pv_dests,
|
|||||||
def lv_lv_create(lv_full_name, create_options, name, size_bytes):
|
def lv_lv_create(lv_full_name, create_options, name, size_bytes):
|
||||||
cmd = ['lvcreate']
|
cmd = ['lvcreate']
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
cmd.extend(['--virtualsize', '%dB' % size_bytes, '-T'])
|
cmd.extend(['--virtualsize', str(size_bytes) + 'B', '-T'])
|
||||||
cmd.extend(['--name', name, lv_full_name, '--yes'])
|
cmd.extend(['--name', name, lv_full_name, '--yes'])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
@@ -508,15 +432,6 @@ def lv_cache_lv(cache_pool_full_name, lv_full_name, cache_options):
|
|||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
|
|
||||||
def lv_writecache_lv(cache_lv_full_name, lv_full_name, cache_options):
|
|
||||||
# lvconvert --type writecache --cachevol VG/CacheLV VG/OriginLV
|
|
||||||
cmd = ['lvconvert']
|
|
||||||
cmd.extend(options_to_cli_args(cache_options))
|
|
||||||
cmd.extend(['-y', '--type', 'writecache', '--cachevol',
|
|
||||||
cache_lv_full_name, lv_full_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
|
def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
|
||||||
cmd = ['lvconvert']
|
cmd = ['lvconvert']
|
||||||
if destroy_cache:
|
if destroy_cache:
|
||||||
@@ -532,36 +447,6 @@ def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
|
|||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
|
|
||||||
def lv_vdo_compression(lv_path, enable, comp_options):
|
|
||||||
cmd = ['lvchange', '--compression']
|
|
||||||
if enable:
|
|
||||||
cmd.append('y')
|
|
||||||
else:
|
|
||||||
cmd.append('n')
|
|
||||||
cmd.extend(options_to_cli_args(comp_options))
|
|
||||||
cmd.append(lv_path)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_vdo_deduplication(lv_path, enable, dedup_options):
|
|
||||||
cmd = ['lvchange', '--deduplication']
|
|
||||||
if enable:
|
|
||||||
cmd.append('y')
|
|
||||||
else:
|
|
||||||
cmd.append('n')
|
|
||||||
cmd.extend(options_to_cli_args(dedup_options))
|
|
||||||
cmd.append(lv_path)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_raid_repair(lv_path, new_pvs, repair_options):
|
|
||||||
cmd = ['lvconvert', '-y', '--repair']
|
|
||||||
cmd.append(lv_path)
|
|
||||||
cmd.extend(new_pvs)
|
|
||||||
cmd.extend(options_to_cli_args(repair_options))
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def supports_json():
|
def supports_json():
|
||||||
cmd = ['help']
|
cmd = ['help']
|
||||||
rc, out, err = call(cmd)
|
rc, out, err = call(cmd)
|
||||||
@@ -574,16 +459,6 @@ def supports_json():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def supports_vdo():
|
|
||||||
cmd = ['segtypes']
|
|
||||||
rc, out, err = call(cmd)
|
|
||||||
if rc == 0:
|
|
||||||
if "vdo" in out:
|
|
||||||
log_debug("We have VDO support")
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def lvm_full_report_json():
|
def lvm_full_report_json():
|
||||||
pv_columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
|
pv_columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
|
||||||
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
|
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
|
||||||
@@ -611,47 +486,67 @@ def lvm_full_report_json():
|
|||||||
|
|
||||||
lv_seg_columns = ['seg_pe_ranges', 'segtype', 'lv_uuid']
|
lv_seg_columns = ['seg_pe_ranges', 'segtype', 'lv_uuid']
|
||||||
|
|
||||||
if cfg.vdo_support:
|
|
||||||
lv_columns.extend(
|
|
||||||
['vdo_operating_mode', 'vdo_compression_state', 'vdo_index_state',
|
|
||||||
'vdo_used_size', 'vdo_saving_percent']
|
|
||||||
)
|
|
||||||
|
|
||||||
lv_seg_columns.extend(
|
|
||||||
['vdo_compression', 'vdo_deduplication',
|
|
||||||
'vdo_use_metadata_hints', 'vdo_minimum_io_size',
|
|
||||||
'vdo_block_map_cache_size', 'vdo_block_map_era_length',
|
|
||||||
'vdo_use_sparse_index', 'vdo_index_memory_size',
|
|
||||||
'vdo_slab_size', 'vdo_ack_threads', 'vdo_bio_threads',
|
|
||||||
'vdo_bio_rotation', 'vdo_cpu_threads', 'vdo_hash_zone_threads',
|
|
||||||
'vdo_logical_threads', 'vdo_physical_threads',
|
|
||||||
'vdo_max_discard', 'vdo_write_policy', 'vdo_header_size'])
|
|
||||||
|
|
||||||
cmd = _dc('fullreport', [
|
cmd = _dc('fullreport', [
|
||||||
'-a', # Need hidden too
|
'-a', # Need hidden too
|
||||||
'--configreport', 'pv', '-o', ','.join(pv_columns),
|
'--configreport', 'pv', '-o', ','.join(pv_columns),
|
||||||
'--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
|
rc, out, err = call(cmd)
|
||||||
# data, so we can have the required information for lvm to debug the fullreport failures.
|
if rc == 0:
|
||||||
# Note: this is disabled by default and can be enabled with env. var.
|
# With the current implementation, if we are using the shell then we
|
||||||
# LVM_DBUSD_COLLECT_LVM_DEBUG=True
|
# are using JSON and JSON is returned back to us as it was parsed to
|
||||||
fn = cfg.lvmdebug.setup()
|
# figure out if we completed OK or not
|
||||||
if fn is not None:
|
if cfg.SHELL_IN_USE:
|
||||||
add_config_option(cmd, "--config", "log {level=7 file=%s syslog=0}" % fn)
|
assert(type(out) == dict)
|
||||||
|
return out
|
||||||
|
else:
|
||||||
|
return json.loads(out)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def pv_retrieve_with_segs(device=None):
|
||||||
|
d = []
|
||||||
|
err = ""
|
||||||
|
out = ""
|
||||||
|
rc = 0
|
||||||
|
|
||||||
|
columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
|
||||||
|
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
|
||||||
|
'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
|
||||||
|
'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
|
||||||
|
'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing']
|
||||||
|
|
||||||
|
# Lvm has some issues where it returns failure when querying pvs when other
|
||||||
|
# operations are in process, see:
|
||||||
|
# https://bugzilla.redhat.com/show_bug.cgi?id=1274085
|
||||||
|
for i in range(0, 10):
|
||||||
|
cmd = _dc('pvs', ['-o', ','.join(columns)])
|
||||||
|
|
||||||
|
if device:
|
||||||
|
cmd.extend(device)
|
||||||
|
|
||||||
rc, out, err = call(cmd)
|
rc, out, err = call(cmd)
|
||||||
# When we have an exported vg the exit code of lvs or fullreport will be 5
|
|
||||||
if rc == 0 or rc == 5:
|
if rc == 0:
|
||||||
if type(out) != dict:
|
d = parse_column_names(out, columns)
|
||||||
raise LvmBug("lvm likely returned invalid JSON, lvm exit code = %d, output = %s, err= %s" %
|
break
|
||||||
(rc, str(out), str(err)))
|
else:
|
||||||
return out
|
time.sleep(0.2)
|
||||||
raise LvmBug("'fullreport' exited with code '%d'" % rc)
|
log_debug("LVM Bug workaround, retrying pvs command...")
|
||||||
|
|
||||||
|
if rc != 0:
|
||||||
|
msg = "We were unable to get pvs to return without error after " \
|
||||||
|
"trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \
|
||||||
|
(rc, err, out)
|
||||||
|
log_error(msg)
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
def pv_resize(device, size_bytes, create_options):
|
def pv_resize(device, size_bytes, create_options):
|
||||||
@@ -660,7 +555,7 @@ def pv_resize(device, size_bytes, create_options):
|
|||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
|
|
||||||
if size_bytes != 0:
|
if size_bytes != 0:
|
||||||
cmd.extend(['--yes', '--setphysicalvolumesize', '%dB' % size_bytes])
|
cmd.extend(['--yes', '--setphysicalvolumesize', str(size_bytes) + 'B'])
|
||||||
|
|
||||||
cmd.extend([device])
|
cmd.extend([device])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
@@ -756,12 +651,12 @@ def vg_allocation_policy(vg_name, policy, policy_options):
|
|||||||
|
|
||||||
|
|
||||||
def vg_max_pv(vg_name, number, max_options):
|
def vg_max_pv(vg_name, number, max_options):
|
||||||
return _vg_value_set(vg_name, ['--maxphysicalvolumes', str(int(number))],
|
return _vg_value_set(vg_name, ['--maxphysicalvolumes', str(number)],
|
||||||
max_options)
|
max_options)
|
||||||
|
|
||||||
|
|
||||||
def vg_max_lv(vg_name, number, max_options):
|
def vg_max_lv(vg_name, number, max_options):
|
||||||
return _vg_value_set(vg_name, ['-l', str(int(number))], max_options)
|
return _vg_value_set(vg_name, ['-l', str(number)], max_options)
|
||||||
|
|
||||||
|
|
||||||
def vg_uuid_gen(vg_name, ignore, options):
|
def vg_uuid_gen(vg_name, ignore, options):
|
||||||
@@ -797,21 +692,63 @@ 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:
|
||||||
op += 'n'
|
op += 'n'
|
||||||
|
|
||||||
cmd.append(op)
|
cmd.append(op)
|
||||||
cmd.append("-y")
|
|
||||||
cmd.append(name)
|
cmd.append(name)
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def vg_retrieve(vg_specific):
|
||||||
|
if vg_specific:
|
||||||
|
assert isinstance(vg_specific, list)
|
||||||
|
|
||||||
|
columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free',
|
||||||
|
'vg_sysid', 'vg_extent_size', 'vg_extent_count',
|
||||||
|
'vg_free_count', 'vg_profile', 'max_lv', 'max_pv',
|
||||||
|
'pv_count', 'lv_count', 'snap_count', 'vg_seqno',
|
||||||
|
'vg_mda_count', 'vg_mda_free', 'vg_mda_size',
|
||||||
|
'vg_mda_used_count', 'vg_attr', 'vg_tags']
|
||||||
|
|
||||||
|
cmd = _dc('vgs', ['-o', ','.join(columns)])
|
||||||
|
|
||||||
|
if vg_specific:
|
||||||
|
cmd.extend(vg_specific)
|
||||||
|
|
||||||
|
d = []
|
||||||
|
rc, out, err = call(cmd)
|
||||||
|
if rc == 0:
|
||||||
|
d = parse_column_names(out, columns)
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def lv_retrieve_with_segments():
|
||||||
|
columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size',
|
||||||
|
'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid',
|
||||||
|
'origin', 'data_percent',
|
||||||
|
'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
|
||||||
|
'metadata_lv', 'seg_pe_ranges', 'segtype', 'lv_parent',
|
||||||
|
'lv_role', 'lv_layout',
|
||||||
|
'snap_percent', 'metadata_percent', 'copy_percent',
|
||||||
|
'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
|
||||||
|
|
||||||
|
cmd = _dc('lvs', ['-a', '-o', ','.join(columns)])
|
||||||
|
rc, out, err = call(cmd)
|
||||||
|
|
||||||
|
d = []
|
||||||
|
|
||||||
|
if rc == 0:
|
||||||
|
d = parse_column_names(out, columns)
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Leave this for future debug as needed
|
pv_data = pv_retrieve_with_segs()
|
||||||
pass
|
|
||||||
|
for p in pv_data:
|
||||||
|
print(str(p))
|
||||||
|
|||||||
@@ -6,69 +6,32 @@
|
|||||||
#
|
#
|
||||||
# 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 traceback
|
||||||
|
|
||||||
|
|
||||||
def _main_thread_load(refresh=True, emit_signal=True):
|
def _main_thread_load(refresh=True, emit_signal=True):
|
||||||
num_total_changes = 0
|
num_total_changes = 0
|
||||||
to_remove = []
|
|
||||||
|
|
||||||
(changes, remove) = load_pvs(
|
num_total_changes += load_pvs(
|
||||||
refresh=refresh,
|
refresh=refresh,
|
||||||
emit_signal=emit_signal,
|
emit_signal=emit_signal,
|
||||||
cache_refresh=False)[1:]
|
cache_refresh=False)[1]
|
||||||
num_total_changes += changes
|
num_total_changes += load_vgs(
|
||||||
to_remove.extend(remove)
|
|
||||||
|
|
||||||
(changes, remove) = load_vgs(
|
|
||||||
refresh=refresh,
|
refresh=refresh,
|
||||||
emit_signal=emit_signal,
|
emit_signal=emit_signal,
|
||||||
cache_refresh=False)[1:]
|
cache_refresh=False)[1]
|
||||||
|
num_total_changes += load_lvs(
|
||||||
num_total_changes += changes
|
|
||||||
to_remove.extend(remove)
|
|
||||||
|
|
||||||
(lv_changes, remove) = load_lvs(
|
|
||||||
refresh=refresh,
|
refresh=refresh,
|
||||||
emit_signal=emit_signal,
|
emit_signal=emit_signal,
|
||||||
cache_refresh=False)[1:]
|
cache_refresh=False)[1]
|
||||||
|
|
||||||
num_total_changes += lv_changes
|
|
||||||
to_remove.extend(remove)
|
|
||||||
|
|
||||||
# When the LVs change it can cause another change in the VGs which is
|
|
||||||
# missed if we don't scan through the VGs again. We could achieve this
|
|
||||||
# the other way and re-scan the LVs, but in general there are more LVs than
|
|
||||||
# VGs, thus this should be more efficient. This happens when a LV interface
|
|
||||||
# changes causing the dbus object representing it to be removed and
|
|
||||||
# recreated.
|
|
||||||
if refresh and lv_changes > 0:
|
|
||||||
(changes, remove) = load_vgs(
|
|
||||||
refresh=refresh,
|
|
||||||
emit_signal=emit_signal,
|
|
||||||
cache_refresh=False)[1:]
|
|
||||||
|
|
||||||
num_total_changes += changes
|
|
||||||
to_remove.extend(remove)
|
|
||||||
|
|
||||||
# Remove any objects that are no longer needed. We do this after we process
|
|
||||||
# all the objects to ensure that references still exist for objects that
|
|
||||||
# are processed after them.
|
|
||||||
to_remove.reverse()
|
|
||||||
for i in to_remove:
|
|
||||||
dbus_obj = cfg.om.get_object_by_path(i)
|
|
||||||
if dbus_obj:
|
|
||||||
cfg.om.remove_object(dbus_obj, True)
|
|
||||||
num_total_changes += 1
|
|
||||||
|
|
||||||
return num_total_changes
|
return num_total_changes
|
||||||
|
|
||||||
@@ -119,126 +82,74 @@ class StateUpdate(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_thread(obj):
|
def update_thread(obj):
|
||||||
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
|
||||||
# Update is done, let everyone know!
|
for i in queued_requests:
|
||||||
set_results(num_changes)
|
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
|
||||||
|
|
||||||
# We retrieved OK, clear exception count
|
num_changes = load(refresh, emit_signal, cache_refresh, log,
|
||||||
exception_count = 0
|
need_main_thread)
|
||||||
|
# Update is done, let everyone know!
|
||||||
|
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 = []
|
||||||
|
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
except SystemExit:
|
except Exception:
|
||||||
break
|
st = traceback.format_exc()
|
||||||
except LvmBug as bug:
|
log_error("update_thread exception: \n%s" % st)
|
||||||
# If a lvm bug occurred, we will dump the lvm debug data if
|
cfg.blackbox.dump()
|
||||||
# we have it.
|
|
||||||
cfg.lvmdebug.dump()
|
|
||||||
log_error(str(bug))
|
|
||||||
_handle_error()
|
|
||||||
except Exception as e:
|
|
||||||
log_error("update_thread: \n%s" % extract_stack_trace(e))
|
|
||||||
_handle_error()
|
|
||||||
finally:
|
|
||||||
cfg.lvmdebug.complete()
|
|
||||||
|
|
||||||
# Make sure to unblock any that may be waiting before we exit this thread
|
|
||||||
# otherwise they hang forever ...
|
|
||||||
bailing(Exception("update thread exiting"))
|
|
||||||
log_debug("update thread exiting!")
|
|
||||||
|
|
||||||
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
|
||||||
@@ -226,21 +226,3 @@ class Job(AutomatedProperties):
|
|||||||
def Uuid(self):
|
def Uuid(self):
|
||||||
import uuid
|
import uuid
|
||||||
return uuid.uuid1()
|
return uuid.uuid1()
|
||||||
|
|
||||||
# Override the property "getters" implementation for the job interface, so a user can query a job while the queue
|
|
||||||
# is processing items. Originally all the property get methods were this way, but we changed this in
|
|
||||||
# e53454d6de07de56736303dd2157c3859f6fa848
|
|
||||||
|
|
||||||
# Properties
|
|
||||||
# noinspection PyUnusedLocal
|
|
||||||
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
|
|
||||||
in_signature='ss', out_signature='v')
|
|
||||||
def Get(self, interface_name, property_name):
|
|
||||||
# Note: If we get an exception in this handler we won't know about it,
|
|
||||||
# only the side effect of no returned value!
|
|
||||||
return AutomatedProperties._get_prop(self, interface_name, property_name)
|
|
||||||
|
|
||||||
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
|
|
||||||
in_signature='s', out_signature='a{sv}')
|
|
||||||
def GetAll(self, interface_name):
|
|
||||||
return AutomatedProperties._get_all_prop(self, interface_name)
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -75,10 +75,11 @@ def common(retrieve, o_type, search_keys,
|
|||||||
|
|
||||||
object_path = None
|
object_path = None
|
||||||
|
|
||||||
to_remove = []
|
|
||||||
if refresh:
|
if refresh:
|
||||||
to_remove = list(existing_paths.keys())
|
for k in list(existing_paths.keys()):
|
||||||
|
cfg.om.remove_object(cfg.om.get_object_by_path(k), True)
|
||||||
|
num_changes += 1
|
||||||
|
|
||||||
num_changes += len(rc)
|
num_changes += len(rc)
|
||||||
|
|
||||||
return rc, num_changes, to_remove
|
return rc, num_changes
|
||||||
|
|||||||
@@ -10,23 +10,23 @@
|
|||||||
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
|
||||||
import dbus
|
import dbus
|
||||||
from . import cmdhandler
|
from . import cmdhandler
|
||||||
from . import cfg
|
from . import cfg
|
||||||
from .cfg import LV_INTERFACE, THIN_POOL_INTERFACE, SNAPSHOT_INTERFACE, \
|
from .cfg import LV_INTERFACE, THIN_POOL_INTERFACE, SNAPSHOT_INTERFACE, \
|
||||||
LV_COMMON_INTERFACE, CACHE_POOL_INTERFACE, LV_CACHED, VDO_POOL_INTERFACE
|
LV_COMMON_INTERFACE, CACHE_POOL_INTERFACE, LV_CACHED
|
||||||
from .request import RequestEntry
|
from .request import RequestEntry
|
||||||
from .utils import n, n32, d
|
from .utils import n, n32
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
# Try and build a key for a LV, so that we sort the LVs with the least dependencies
|
# 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
|
# 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,57 +65,13 @@ 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 dependent 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
|
||||||
# don't have information available yet.
|
# don't have information available yet.
|
||||||
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
|
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
|
||||||
|
|
||||||
for l in lvs:
|
for l in lvs:
|
||||||
if cfg.vdo_support:
|
|
||||||
rc.append(LvStateVdo(
|
|
||||||
l['lv_uuid'], l['lv_name'],
|
|
||||||
l['lv_path'], n(l['lv_size']),
|
|
||||||
l['vg_name'],
|
|
||||||
l['vg_uuid'], l['pool_lv_uuid'],
|
|
||||||
l['pool_lv'], l['origin_uuid'], l['origin'],
|
|
||||||
n32(l['data_percent']), l['lv_attr'],
|
|
||||||
l['lv_tags'], l['lv_active'], l['data_lv'],
|
|
||||||
l['metadata_lv'], l['segtype'], l['lv_role'],
|
|
||||||
l['lv_layout'],
|
|
||||||
n32(l['snap_percent']),
|
|
||||||
n32(l['metadata_percent']),
|
|
||||||
n32(l['copy_percent']),
|
|
||||||
n32(l['sync_percent']),
|
|
||||||
n(l['lv_metadata_size']),
|
|
||||||
l['move_pv'],
|
|
||||||
l['move_pv_uuid'],
|
|
||||||
l['vdo_operating_mode'],
|
|
||||||
l['vdo_compression_state'],
|
|
||||||
l['vdo_index_state'],
|
|
||||||
n(l['vdo_used_size']),
|
|
||||||
d(l['vdo_saving_percent']),
|
|
||||||
l['vdo_compression'],
|
|
||||||
l['vdo_deduplication'],
|
|
||||||
l['vdo_use_metadata_hints'],
|
|
||||||
n32(l['vdo_minimum_io_size']),
|
|
||||||
n(l['vdo_block_map_cache_size']),
|
|
||||||
n32(l['vdo_block_map_era_length']),
|
|
||||||
l['vdo_use_sparse_index'],
|
|
||||||
n(l['vdo_index_memory_size']),
|
|
||||||
n(l['vdo_slab_size']),
|
|
||||||
n32(l['vdo_ack_threads']),
|
|
||||||
n32(l['vdo_bio_threads']),
|
|
||||||
n32(l['vdo_bio_rotation']),
|
|
||||||
n32(l['vdo_cpu_threads']),
|
|
||||||
n32(l['vdo_hash_zone_threads']),
|
|
||||||
n32(l['vdo_logical_threads']),
|
|
||||||
n32(l['vdo_physical_threads']),
|
|
||||||
n32(l['vdo_max_discard']),
|
|
||||||
l['vdo_write_policy'],
|
|
||||||
n32(l['vdo_header_size'])))
|
|
||||||
else:
|
|
||||||
rc.append(LvState(
|
rc.append(LvState(
|
||||||
l['lv_uuid'], l['lv_name'],
|
l['lv_uuid'], l['lv_name'],
|
||||||
l['lv_path'], n(l['lv_size']),
|
l['lv_path'], n(l['lv_size']),
|
||||||
@@ -133,12 +89,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
|
||||||
|
|
||||||
|
|
||||||
@@ -242,8 +192,6 @@ class LvState(State):
|
|||||||
def _object_type_create(self):
|
def _object_type_create(self):
|
||||||
if self.Attr[0] == 't':
|
if self.Attr[0] == 't':
|
||||||
return LvThinPool
|
return LvThinPool
|
||||||
elif self.Attr[0] == 'd':
|
|
||||||
return LvVdoPool
|
|
||||||
elif self.Attr[0] == 'C':
|
elif self.Attr[0] == 'C':
|
||||||
if 'pool' in self.layout:
|
if 'pool' in self.layout:
|
||||||
return LvCachePool
|
return LvCachePool
|
||||||
@@ -270,34 +218,6 @@ class LvState(State):
|
|||||||
return (klass, path_method)
|
return (klass, path_method)
|
||||||
|
|
||||||
|
|
||||||
class LvStateVdo(LvState):
|
|
||||||
|
|
||||||
def __init__(self, Uuid, Name, Path, SizeBytes,
|
|
||||||
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
|
|
||||||
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
|
|
||||||
data_lv, metadata_lv, segtypes, role, layout, SnapPercent,
|
|
||||||
MetaDataPercent, CopyPercent, SyncPercent,
|
|
||||||
MetaDataSizeBytes, move_pv, move_pv_uuid,
|
|
||||||
vdo_operating_mode, vdo_compression_state, vdo_index_state,
|
|
||||||
vdo_used_size, vdo_saving_percent, vdo_compression,
|
|
||||||
vdo_deduplication, vdo_use_metadata_hints,
|
|
||||||
vdo_minimum_io_size, vdo_block_map_cache_size,
|
|
||||||
vdo_block_map_era_length, vdo_use_sparse_index,
|
|
||||||
vdo_index_memory_size, vdo_slab_size, vdo_ack_threads,
|
|
||||||
vdo_bio_threads, vdo_bio_rotation, vdo_cpu_threads,
|
|
||||||
vdo_hash_zone_threads, vdo_logical_threads,
|
|
||||||
vdo_physical_threads, vdo_max_discard,
|
|
||||||
vdo_write_policy, vdo_header_size):
|
|
||||||
super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
|
|
||||||
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
|
|
||||||
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
|
|
||||||
data_lv, metadata_lv, segtypes, role, layout, SnapPercent,
|
|
||||||
MetaDataPercent, CopyPercent, SyncPercent,
|
|
||||||
MetaDataSizeBytes, move_pv, move_pv_uuid)
|
|
||||||
|
|
||||||
utils.init_class_from_arguments(self, "vdo_", snake_to_pascal=True)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'Uuid', 's')
|
@utils.dbus_property(LV_COMMON_INTERFACE, 'Uuid', 's')
|
||||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'Name', 's')
|
@utils.dbus_property(LV_COMMON_INTERFACE, 'Name', 's')
|
||||||
@@ -353,7 +273,13 @@ class LvCommon(AutomatedProperties):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def handle_execute(rc, out, err):
|
def handle_execute(rc, out, err):
|
||||||
_handle_execute(rc, out, err, LV_INTERFACE)
|
if rc == 0:
|
||||||
|
cfg.load()
|
||||||
|
else:
|
||||||
|
# Need to work on error handling, need consistent
|
||||||
|
raise dbus.exceptions.DBusException(
|
||||||
|
LV_INTERFACE,
|
||||||
|
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_dbus_object(lv_uuid, lv_name):
|
def validate_dbus_object(lv_uuid, lv_name):
|
||||||
@@ -365,22 +291,6 @@ class LvCommon(AutomatedProperties):
|
|||||||
(lv_uuid, lv_name))
|
(lv_uuid, lv_name))
|
||||||
return dbo
|
return dbo
|
||||||
|
|
||||||
def attr_struct(self, index, type_map, default='undisclosed'):
|
|
||||||
try:
|
|
||||||
if self.state.Attr[index] not in type_map:
|
|
||||||
log_error("LV %s %s with lv_attr %s, lv_attr[%d] = "
|
|
||||||
"'%s' is not known" %
|
|
||||||
(self.Uuid, self.Name, self.Attr, index,
|
|
||||||
self.state.Attr[index]))
|
|
||||||
|
|
||||||
return dbus.Struct((self.state.Attr[index],
|
|
||||||
type_map.get(self.state.Attr[index], default)),
|
|
||||||
signature="(ss)")
|
|
||||||
except BaseException as b:
|
|
||||||
st = utils.extract_stack_trace(b)
|
|
||||||
log_error("attr_struct: \n%s" % st)
|
|
||||||
return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def VolumeType(self):
|
def VolumeType(self):
|
||||||
type_map = {'C': 'Cache', 'm': 'mirrored',
|
type_map = {'C': 'Cache', 'm': 'mirrored',
|
||||||
@@ -393,16 +303,17 @@ class LvCommon(AutomatedProperties):
|
|||||||
'l': 'mirror log device', 'c': 'under conversion',
|
'l': 'mirror log device', 'c': 'under conversion',
|
||||||
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
|
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
|
||||||
'e': 'raid or pool metadata or pool metadata spare',
|
'e': 'raid or pool metadata or pool metadata spare',
|
||||||
'd': 'vdo pool', 'D': 'vdo pool data', 'g': 'integrity',
|
|
||||||
'-': 'Unspecified'}
|
'-': 'Unspecified'}
|
||||||
return self.attr_struct(0, type_map)
|
return dbus.Struct((self.state.Attr[0], type_map[self.state.Attr[0]]),
|
||||||
|
signature="as")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def Permissions(self):
|
def Permissions(self):
|
||||||
type_map = {'w': 'writable', 'r': 'read-only',
|
type_map = {'w': 'writable', 'r': 'read-only',
|
||||||
'R': 'Read-only activation of non-read-only volume',
|
'R': 'Read-only activation of non-read-only volume',
|
||||||
'-': 'Unspecified'}
|
'-': 'Unspecified'}
|
||||||
return self.attr_struct(1, type_map)
|
return dbus.Struct((self.state.Attr[1], type_map[self.state.Attr[1]]),
|
||||||
|
signature="(ss)")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def AllocationPolicy(self):
|
def AllocationPolicy(self):
|
||||||
@@ -411,7 +322,8 @@ class LvCommon(AutomatedProperties):
|
|||||||
'i': 'inherited', 'I': 'inherited locked',
|
'i': 'inherited', 'I': 'inherited locked',
|
||||||
'l': 'cling', 'L': 'cling locked',
|
'l': 'cling', 'L': 'cling locked',
|
||||||
'n': 'normal', 'N': 'normal locked', '-': 'Unspecified'}
|
'n': 'normal', 'N': 'normal locked', '-': 'Unspecified'}
|
||||||
return self.attr_struct(2, type_map)
|
return dbus.Struct((self.state.Attr[2], type_map[self.state.Attr[2]]),
|
||||||
|
signature="(ss)")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def FixedMinor(self):
|
def FixedMinor(self):
|
||||||
@@ -419,20 +331,15 @@ class LvCommon(AutomatedProperties):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def State(self):
|
def State(self):
|
||||||
type_map = {'a': 'active',
|
type_map = {'a': 'active', 's': 'suspended', 'I': 'Invalid snapshot',
|
||||||
's': 'suspended',
|
|
||||||
'I': 'Invalid snapshot',
|
|
||||||
'S': 'invalid Suspended snapshot',
|
'S': 'invalid Suspended snapshot',
|
||||||
'm': 'snapshot merge failed',
|
'm': 'snapshot merge failed',
|
||||||
'M': 'suspended snapshot (M)erge failed',
|
'M': 'suspended snapshot (M)erge failed',
|
||||||
'd': 'mapped device present without tables',
|
'd': 'mapped device present without tables',
|
||||||
'i': 'mapped device present with inactive table',
|
'i': 'mapped device present with inactive table',
|
||||||
'h': 'historical',
|
'X': 'unknown', '-': 'Unspecified'}
|
||||||
'c': 'check needed suspended thin-pool',
|
return dbus.Struct((self.state.Attr[4], type_map[self.state.Attr[4]]),
|
||||||
'C': 'check needed',
|
signature="(ss)")
|
||||||
'X': 'unknown',
|
|
||||||
'-': 'Unspecified'}
|
|
||||||
return self.attr_struct(4, type_map)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def TargetType(self):
|
def TargetType(self):
|
||||||
@@ -448,18 +355,11 @@ class LvCommon(AutomatedProperties):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def Health(self):
|
def Health(self):
|
||||||
type_map = {'p': 'partial',
|
type_map = {'p': 'partial', 'r': 'refresh',
|
||||||
'r': 'refresh needed',
|
'm': 'mismatches', 'w': 'writemostly',
|
||||||
'm': 'mismatches',
|
'X': 'X unknown', '-': 'Unspecified'}
|
||||||
'w': 'writemostly',
|
return dbus.Struct((self.state.Attr[8], type_map[self.state.Attr[8]]),
|
||||||
'X': 'unknown',
|
signature="(ss)")
|
||||||
'-': 'unspecified',
|
|
||||||
's': 'reshaping',
|
|
||||||
'F': 'failed',
|
|
||||||
'D': 'Data space',
|
|
||||||
'R': 'Remove',
|
|
||||||
'M': 'Metadata'}
|
|
||||||
return self.attr_struct(8, type_map)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def SkipActivation(self):
|
def SkipActivation(self):
|
||||||
@@ -529,7 +429,8 @@ class Lv(LvCommon):
|
|||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||||
# Remove the LV, if successful then remove from the model
|
# Remove the LV, if successful then remove from the model
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_remove(lv_name, remove_options))
|
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -549,8 +450,9 @@ class Lv(LvCommon):
|
|||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||||
# Rename the logical volume
|
# Rename the logical volume
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_rename(lv_name, new_name,
|
rc, out, err = cmdhandler.lv_rename(lv_name, new_name,
|
||||||
rename_options))
|
rename_options)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -599,11 +501,13 @@ class Lv(LvCommon):
|
|||||||
remainder = space % 512
|
remainder = space % 512
|
||||||
optional_size = space + 512 - remainder
|
optional_size = space + 512 - remainder
|
||||||
|
|
||||||
LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
|
rc, out, err = cmdhandler.vg_lv_snapshot(
|
||||||
lv_name, snapshot_options, name, optional_size))
|
lv_name, snapshot_options, name, optional_size)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
dbus_interface=LV_INTERFACE,
|
dbus_interface=LV_INTERFACE,
|
||||||
in_signature='stia{sv}',
|
in_signature='stia{sv}',
|
||||||
@@ -639,8 +543,9 @@ class Lv(LvCommon):
|
|||||||
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
||||||
|
|
||||||
size_change = new_size_bytes - dbo.SizeBytes
|
size_change = new_size_bytes - dbo.SizeBytes
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_resize(
|
rc, out, err = cmdhandler.lv_resize(dbo.lvm_id, size_change,
|
||||||
dbo.lvm_id, size_change, pv_dests, resize_options))
|
pv_dests, resize_options)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
return "/"
|
return "/"
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -675,8 +580,9 @@ class Lv(LvCommon):
|
|||||||
options):
|
options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
LvCommon.validate_dbus_object(uuid, lv_name)
|
LvCommon.validate_dbus_object(uuid, lv_name)
|
||||||
LvCommon.handle_execute(*cmdhandler.activate_deactivate(
|
rc, out, err = cmdhandler.activate_deactivate(
|
||||||
'lvchange', lv_name, activate, control_flags, options))
|
'lvchange', lv_name, activate, control_flags, options)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -710,8 +616,9 @@ class Lv(LvCommon):
|
|||||||
def _add_rm_tags(uuid, lv_name, tags_add, tags_del, tag_options):
|
def _add_rm_tags(uuid, lv_name, tags_add, tags_del, tag_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
LvCommon.validate_dbus_object(uuid, lv_name)
|
LvCommon.validate_dbus_object(uuid, lv_name)
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_tag(
|
rc, out, err = cmdhandler.lv_tag(
|
||||||
lv_name, tags_add, tags_del, tag_options))
|
lv_name, tags_add, tags_del, tag_options)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -748,190 +655,6 @@ class Lv(LvCommon):
|
|||||||
cb, cbe, return_tuple=False)
|
cb, cbe, return_tuple=False)
|
||||||
cfg.worker_q.put(r)
|
cfg.worker_q.put(r)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _caching_common(method, lv_uuid, lv_name, lv_object_path, cache_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
|
||||||
|
|
||||||
# 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 = method(
|
|
||||||
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
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
|
|
||||||
return Lv._caching_common(cmdhandler.lv_writecache_lv, lv_uuid,
|
|
||||||
lv_name, lv_object_path, cache_options)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=LV_INTERFACE,
|
|
||||||
in_signature='oia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def WriteCacheLv(self, lv_object, tmo, cache_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Lv._writecache_lv,
|
|
||||||
(self.Uuid, self.lvm_id, lv_object,
|
|
||||||
cache_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _repair_raid_lv(lv_uuid, lv_name, new_pvs, repair_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
pv_dests = []
|
|
||||||
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
|
||||||
|
|
||||||
# If we have PVs, verify them
|
|
||||||
if len(new_pvs):
|
|
||||||
for pv in new_pvs:
|
|
||||||
pv_dbus_obj = cfg.om.get_object_by_path(pv)
|
|
||||||
if not pv_dbus_obj:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
LV_INTERFACE,
|
|
||||||
'PV Destination (%s) not found' % pv)
|
|
||||||
|
|
||||||
pv_dests.append(pv_dbus_obj.lvm_id)
|
|
||||||
|
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_raid_repair(
|
|
||||||
dbo.lvm_id, pv_dests, repair_options))
|
|
||||||
return "/"
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=LV_INTERFACE,
|
|
||||||
in_signature='aoia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def RepairRaidLv(self, new_pvs, tmo, repair_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Lv._repair_raid_lv,
|
|
||||||
(self.Uuid, self.lvm_id, new_pvs,
|
|
||||||
repair_options), cb, cbe, return_tuple=False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'OperatingMode', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'CompressionState', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'IndexState', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UsedSize', 't')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'SavingPercent', 'd')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'Compression', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'Deduplication', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UseMetadataHints', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'MinimumIoSize', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BlockMapCacheSize', "t")
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BlockMapEraLength', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UseSparseIndex', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'IndexMemorySize', 't')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'SlabSize', 't')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'AckThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BioThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BioRotation', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'CpuThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'HashZoneThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'LogicalThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'PhysicalThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'MaxDiscard', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'WritePolicy', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'HeaderSize', 'u')
|
|
||||||
class LvVdoPool(Lv):
|
|
||||||
_DataLv_meta = ("o", VDO_POOL_INTERFACE)
|
|
||||||
|
|
||||||
def __init__(self, object_path, object_state):
|
|
||||||
super(LvVdoPool, self).__init__(object_path, object_state)
|
|
||||||
self.set_interface(VDO_POOL_INTERFACE)
|
|
||||||
self._data_lv, _ = self._get_data_meta()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def DataLv(self):
|
|
||||||
return dbus.ObjectPath(self._data_lv)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _enable_disable_compression(pool_uuid, pool_name, enable, comp_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
LvCommon.validate_dbus_object(pool_uuid, pool_name)
|
|
||||||
# Rename the logical volume
|
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_vdo_compression(
|
|
||||||
pool_name, enable, comp_options))
|
|
||||||
return '/'
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VDO_POOL_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def EnableCompression(self, tmo, comp_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, LvVdoPool._enable_disable_compression,
|
|
||||||
(self.Uuid, self.lvm_id, True, comp_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VDO_POOL_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def DisableCompression(self, tmo, comp_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, LvVdoPool._enable_disable_compression,
|
|
||||||
(self.Uuid, self.lvm_id, False, comp_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _enable_disable_deduplication(pool_uuid, pool_name, enable, dedup_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
LvCommon.validate_dbus_object(pool_uuid, pool_name)
|
|
||||||
# Rename the logical volume
|
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_vdo_deduplication(
|
|
||||||
pool_name, enable, dedup_options))
|
|
||||||
return '/'
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VDO_POOL_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def EnableDeduplication(self, tmo, dedup_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, LvVdoPool._enable_disable_deduplication,
|
|
||||||
(self.Uuid, self.lvm_id, True, dedup_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VDO_POOL_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, LvVdoPool._enable_disable_deduplication,
|
|
||||||
(self.Uuid, self.lvm_id, False, dedup_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
class LvThinPool(Lv):
|
class LvThinPool(Lv):
|
||||||
@@ -955,8 +678,10 @@ class LvThinPool(Lv):
|
|||||||
def _lv_create(lv_uuid, lv_name, name, size_bytes, create_options):
|
def _lv_create(lv_uuid, lv_name, name, size_bytes, create_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)
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_lv_create(
|
|
||||||
lv_name, create_options, name, size_bytes))
|
rc, out, err = cmdhandler.lv_lv_create(
|
||||||
|
lv_name, create_options, name, size_bytes)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
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)
|
||||||
|
|
||||||
@@ -995,8 +720,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,
|
||||||
|
|||||||
@@ -13,13 +13,14 @@
|
|||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import shlex
|
import shlex
|
||||||
|
from fcntl import fcntl, F_GETFL, F_SETFL
|
||||||
import os
|
import os
|
||||||
import pty
|
import traceback
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import threading
|
|
||||||
import select
|
import select
|
||||||
|
import copy
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import simplejson as json
|
import simplejson as json
|
||||||
@@ -27,9 +28,8 @@ 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
|
||||||
read_decoded, extract_stack_trace, LvmBug, get_error_msg
|
|
||||||
|
|
||||||
SHELL_PROMPT = "lvm> "
|
SHELL_PROMPT = "lvm> "
|
||||||
|
|
||||||
@@ -43,11 +43,17 @@ def _quote_arg(arg):
|
|||||||
|
|
||||||
class LVMShellProxy(object):
|
class LVMShellProxy(object):
|
||||||
|
|
||||||
# Read REPORT FD until we have a complete and valid JSON record or give
|
@staticmethod
|
||||||
# up trying to get one.
|
def _read(stream):
|
||||||
#
|
tmp = stream.read()
|
||||||
# Returns stdout, report (JSON), stderr
|
if tmp:
|
||||||
def _read_response(self, no_output=False):
|
return tmp.decode("utf-8")
|
||||||
|
return ''
|
||||||
|
|
||||||
|
# Read until we get prompt back and a result
|
||||||
|
# @param: no_output Caller expects no output to report FD
|
||||||
|
# Returns stdout, report, stderr (report is JSON!)
|
||||||
|
def _read_until_prompt(self, no_output=False):
|
||||||
stdout = ""
|
stdout = ""
|
||||||
report = ""
|
report = ""
|
||||||
stderr = ""
|
stderr = ""
|
||||||
@@ -59,27 +65,24 @@ class LVMShellProxy(object):
|
|||||||
# Try reading from all FDs to prevent one from filling up and causing
|
# Try reading from all FDs to prevent one from filling up and causing
|
||||||
# a hang. Keep reading until we get the prompt back and the report
|
# a hang. Keep reading until we get the prompt back and the report
|
||||||
# FD does not contain valid JSON
|
# FD does not contain valid JSON
|
||||||
|
while keep_reading:
|
||||||
while keep_reading and cfg.run.value != 0:
|
|
||||||
try:
|
try:
|
||||||
rd_fd = [
|
rd_fd = [
|
||||||
self.parent_stdout_fd,
|
self.lvm_shell.stdout.fileno(),
|
||||||
self.report_stream.fileno(),
|
self.report_stream.fileno(),
|
||||||
self.parent_stderr_fd]
|
self.lvm_shell.stderr.fileno()]
|
||||||
ready = select.select(rd_fd, [], [], cfg.G_LOOP_TMO)
|
ready = select.select(rd_fd, [], [], 2)
|
||||||
|
|
||||||
for r in ready[0]:
|
for r in ready[0]:
|
||||||
if r == self.parent_stdout_fd:
|
if r == self.lvm_shell.stdout.fileno():
|
||||||
for line in self.parent_stdout.readlines():
|
stdout += LVMShellProxy._read(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 += LVMShellProxy._read(self.report_stream)
|
||||||
elif r == self.parent_stderr_fd:
|
elif r == self.lvm_shell.stderr.fileno():
|
||||||
for line in self.parent_stderr.readlines():
|
stderr += LVMShellProxy._read(self.lvm_shell.stderr)
|
||||||
stderr += line
|
|
||||||
|
|
||||||
# Check to see if the lvm process died on us
|
# Check to see if the lvm process died on us
|
||||||
if self.lvm_shell.poll() is not None:
|
if self.lvm_shell.poll():
|
||||||
raise Exception(self.lvm_shell.returncode, "%s" % stderr)
|
raise Exception(self.lvm_shell.returncode, "%s" % stderr)
|
||||||
|
|
||||||
if stdout.endswith(SHELL_PROMPT):
|
if stdout.endswith(SHELL_PROMPT):
|
||||||
@@ -103,106 +106,96 @@ class LVMShellProxy(object):
|
|||||||
extra_passes -= 1
|
extra_passes -= 1
|
||||||
if extra_passes <= 0:
|
if extra_passes <= 0:
|
||||||
if len(report):
|
if len(report):
|
||||||
raise LvmBug("Invalid json: %s" %
|
raise ValueError("Invalid json: %s" %
|
||||||
report)
|
report)
|
||||||
else:
|
else:
|
||||||
raise LvmBug(
|
raise ValueError(
|
||||||
"lvm returned no JSON output!")
|
"lvm returned no JSON output!")
|
||||||
except Exception as e:
|
|
||||||
log_error("While reading from lvm shell we encountered an error %s" % str(e))
|
|
||||||
log_error("stdout= %s\nstderr= %s\n" % (stdout, stderr))
|
|
||||||
if self.lvm_shell.poll() is not None:
|
|
||||||
log_error("Underlying lvm shell process unexpectedly exited: %d" % self.lvm_shell.returncode)
|
|
||||||
else:
|
|
||||||
log_error("Underlying lvm shell process is still present!")
|
|
||||||
raise e
|
|
||||||
|
|
||||||
if keep_reading and cfg.run.value == 0:
|
except IOError as ioe:
|
||||||
# We didn't complete as we are shutting down
|
log_debug(str(ioe))
|
||||||
# Try to clean up lvm shell process
|
pass
|
||||||
log_debug("exiting lvm shell as we are shutting down")
|
|
||||||
self.exit_shell()
|
|
||||||
raise SystemExit
|
|
||||||
|
|
||||||
return stdout, report_json, stderr
|
return stdout, report_json, stderr
|
||||||
|
|
||||||
def _write_cmd(self, cmd):
|
def _write_cmd(self, cmd):
|
||||||
self.parent_stdin.write(cmd)
|
cmd_bytes = bytes(cmd, "utf-8")
|
||||||
self.parent_stdin.flush()
|
num_written = self.lvm_shell.stdin.write(cmd_bytes)
|
||||||
|
assert (num_written == len(cmd_bytes))
|
||||||
|
self.lvm_shell.stdin.flush()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _make_non_block(stream):
|
||||||
|
flags = fcntl(stream, F_GETFL)
|
||||||
|
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
# Create a temp directory
|
# Create a temp directory
|
||||||
tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
|
tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
|
||||||
tmp_file = "%s/lvmdbus_report" % (tmp_dir)
|
tmp_file = "%s/lvmdbus_report" % (tmp_dir)
|
||||||
|
|
||||||
# Create a lock so that we don't step on each other when we are waiting for a command
|
try:
|
||||||
# to finish and some other request comes in concurrently, like to exit the shell.
|
# Lets create fifo for the report output
|
||||||
self.shell_lock = threading.RLock()
|
|
||||||
|
|
||||||
# Create a fifo for the report output
|
|
||||||
os.mkfifo(tmp_file, 0o600)
|
os.mkfifo(tmp_file, 0o600)
|
||||||
|
except FileExistsError:
|
||||||
|
pass
|
||||||
|
|
||||||
# Open the fifo for use to read and for lvm child process to write to.
|
# We have to open non-blocking as the other side isn't open until
|
||||||
|
# we actually fork the process.
|
||||||
self.report_fd = os.open(tmp_file, os.O_NONBLOCK)
|
self.report_fd = os.open(tmp_file, os.O_NONBLOCK)
|
||||||
self.report_stream = os.fdopen(self.report_fd, 'rb', 0)
|
self.report_stream = os.fdopen(self.report_fd, 'rb', 0)
|
||||||
lvm_fd = os.open(tmp_file, os.O_WRONLY)
|
|
||||||
|
|
||||||
# Set up the environment for using our own socket for reporting and disable the abort
|
# Setup the environment for using our own socket for reporting
|
||||||
# logic if lvm logs too much, which easily happens when utilizing the lvm shell.
|
local_env = copy.deepcopy(os.environ)
|
||||||
local_env = {"LC_ALL": "C", "LVM_REPORT_FD": "%s" % lvm_fd, "LVM_COMMAND_PROFILE": "lvmdbusd",
|
local_env["LVM_REPORT_FD"] = "32"
|
||||||
"LVM_LOG_FILE_MAX_LINES": "0"}
|
local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd"
|
||||||
|
|
||||||
# If any env variables contain LVM we will propagate them too
|
# Disable the abort logic if lvm logs too much, which easily happens
|
||||||
for k, v in os.environ.items():
|
# when utilizing the lvm shell.
|
||||||
if "PATH" in k:
|
local_env["LVM_LOG_FILE_MAX_LINES"] = "0"
|
||||||
local_env[k] = v
|
|
||||||
if "LVM" in k:
|
|
||||||
local_env[k] = v
|
|
||||||
|
|
||||||
self.parent_stdin_fd, child_stdin_fd = pty.openpty()
|
|
||||||
self.parent_stdout_fd, child_stdout_fd = pty.openpty()
|
|
||||||
self.parent_stderr_fd, child_stderr_fd = pty.openpty()
|
|
||||||
self.parent_stdin = os.fdopen(self.parent_stdin_fd, "w")
|
|
||||||
self.parent_stdout = os.fdopen(self.parent_stdout_fd, "r")
|
|
||||||
self.parent_stderr = os.fdopen(self.parent_stderr_fd, "r")
|
|
||||||
|
|
||||||
# run the lvm shell
|
# run the lvm shell
|
||||||
self.lvm_shell = subprocess.Popen(
|
self.lvm_shell = subprocess.Popen(
|
||||||
[cfg.LVM_CMD],
|
[LVM_CMD + " 32>%s" % tmp_file],
|
||||||
stdin=child_stdin_fd,
|
stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env,
|
||||||
stdout=child_stdout_fd, env=local_env,
|
stderr=subprocess.PIPE, close_fds=True, shell=True)
|
||||||
stderr=child_stderr_fd, close_fds=True,
|
|
||||||
pass_fds=(lvm_fd,), shell=False)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
make_non_block(self.parent_stdout_fd)
|
LVMShellProxy._make_non_block(self.lvm_shell.stdout)
|
||||||
make_non_block(self.parent_stderr_fd)
|
LVMShellProxy._make_non_block(self.lvm_shell.stderr)
|
||||||
|
|
||||||
# Close our copies of the child FDs there were created with the fork, we don't need them open.
|
|
||||||
os.close(lvm_fd)
|
|
||||||
os.close(child_stdin_fd)
|
|
||||||
os.close(child_stdout_fd)
|
|
||||||
os.close(child_stderr_fd)
|
|
||||||
|
|
||||||
# wait for the first prompt
|
# wait for the first prompt
|
||||||
log_debug("waiting for first prompt...")
|
errors = self._read_until_prompt(no_output=True)[2]
|
||||||
errors = self._read_response(no_output=True)[2]
|
|
||||||
if errors and len(errors):
|
if errors and len(errors):
|
||||||
raise LvmBug(errors)
|
raise RuntimeError(errors)
|
||||||
log_debug("lvm prompt read!!!")
|
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
# These will get deleted when the FD count goes to zero, so we
|
# These will get deleted when the FD count goes to zero so we
|
||||||
# can be sure to clean up correctly no matter how we finish
|
# can be sure to clean up correctly no matter how we finish
|
||||||
os.unlink(tmp_file)
|
os.unlink(tmp_file)
|
||||||
os.rmdir(tmp_dir)
|
os.rmdir(tmp_dir)
|
||||||
|
|
||||||
def _get_last_log(self):
|
def get_error_msg(self):
|
||||||
# Precondition, lock is held
|
# We got an error, lets go fetch the error message
|
||||||
self._write_cmd('lastlog\n')
|
self._write_cmd('lastlog\n')
|
||||||
report_json = self._read_response()[1]
|
|
||||||
return get_error_msg(report_json)
|
# read everything from the STDOUT to the next prompt
|
||||||
|
stdout, report_json, stderr = self._read_until_prompt()
|
||||||
|
if 'log' in report_json:
|
||||||
|
error_msg = ""
|
||||||
|
# Walk the entire log array and build an error string
|
||||||
|
for log_entry in report_json['log']:
|
||||||
|
if log_entry['log_type'] == "error":
|
||||||
|
if error_msg:
|
||||||
|
error_msg += ', ' + log_entry['log_message']
|
||||||
|
else:
|
||||||
|
error_msg = log_entry['log_message']
|
||||||
|
|
||||||
|
return error_msg
|
||||||
|
|
||||||
|
return 'No error reason provided! (missing "log" section)'
|
||||||
|
|
||||||
def call_lvm(self, argv, debug=False):
|
def call_lvm(self, argv, debug=False):
|
||||||
rc = 1
|
rc = 1
|
||||||
@@ -220,79 +213,45 @@ class LVMShellProxy(object):
|
|||||||
cmd += "\n"
|
cmd += "\n"
|
||||||
|
|
||||||
# run the command by writing it to the shell's STDIN
|
# run the command by writing it to the shell's STDIN
|
||||||
with self.shell_lock:
|
|
||||||
self._write_cmd(cmd)
|
self._write_cmd(cmd)
|
||||||
|
|
||||||
# read everything from the STDOUT to the next prompt
|
# read everything from the STDOUT to the next prompt
|
||||||
stdout, report_json, stderr = self._read_response()
|
stdout, report_json, stderr = self._read_until_prompt()
|
||||||
|
|
||||||
# Parse the report to see what happened
|
# Parse the report to see what happened
|
||||||
if 'log' in report_json:
|
if 'log' in report_json:
|
||||||
ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
|
if report_json['log'][-1:][0]['log_ret_code'] == '1':
|
||||||
# If we have an exported vg we get a log_ret_code == 5 when
|
|
||||||
# we do a 'fullreport'
|
|
||||||
# Note: 0 == error
|
|
||||||
if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
|
|
||||||
rc = 0
|
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)
|
|
||||||
|
|
||||||
try:
|
|
||||||
if len(sys.argv) > 1 and sys.argv[1] == "bisect":
|
|
||||||
shell = LVMShellProxy()
|
|
||||||
shell.exit_shell()
|
|
||||||
else:
|
|
||||||
shell = LVMShellProxy()
|
shell = LVMShellProxy()
|
||||||
in_line = "start"
|
in_line = "start"
|
||||||
try:
|
try:
|
||||||
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 +265,5 @@ 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(0)
|
|
||||||
|
|||||||
@@ -13,13 +13,14 @@ from collections import OrderedDict
|
|||||||
|
|
||||||
import pprint as prettyprint
|
import pprint as prettyprint
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
from lvmdbusd import cmdhandler
|
from lvmdbusd import cmdhandler
|
||||||
from lvmdbusd.utils import log_debug, log_error, lvm_column_key, LvmBug
|
from lvmdbusd.utils import log_debug, log_error
|
||||||
|
|
||||||
|
|
||||||
class DataStore(object):
|
class DataStore(object):
|
||||||
def __init__(self, vdo_support=False):
|
def __init__(self, usejson=True):
|
||||||
self.pvs = {}
|
self.pvs = {}
|
||||||
self.vgs = {}
|
self.vgs = {}
|
||||||
self.lvs = {}
|
self.lvs = {}
|
||||||
@@ -34,8 +35,38 @@ class DataStore(object):
|
|||||||
self.lvs_in_vgs = {}
|
self.lvs_in_vgs = {}
|
||||||
self.pvs_in_vgs = {}
|
self.pvs_in_vgs = {}
|
||||||
|
|
||||||
|
# self.refresh()
|
||||||
self.num_refreshes = 0
|
self.num_refreshes = 0
|
||||||
self.vdo_support = vdo_support
|
|
||||||
|
if usejson:
|
||||||
|
self.json = cmdhandler.supports_json()
|
||||||
|
else:
|
||||||
|
self.json = usejson
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _insert_record(table, key, record, allowed_multiple):
|
||||||
|
if key in table:
|
||||||
|
existing = table[key]
|
||||||
|
|
||||||
|
for rec_k, rec_v in record.items():
|
||||||
|
if rec_k in allowed_multiple:
|
||||||
|
# This column name allows us to store multiple value for
|
||||||
|
# each type
|
||||||
|
if not isinstance(existing[rec_k], list):
|
||||||
|
existing_value = existing[rec_k]
|
||||||
|
existing[rec_k] = [existing_value, rec_v]
|
||||||
|
else:
|
||||||
|
existing[rec_k].append(rec_v)
|
||||||
|
else:
|
||||||
|
# If something is not expected to have changing values
|
||||||
|
# lets ensure that
|
||||||
|
if existing[rec_k] != rec_v:
|
||||||
|
raise RuntimeError(
|
||||||
|
"existing[%s]=%s != %s" %
|
||||||
|
(rec_k, str(existing[rec_k]),
|
||||||
|
str(rec_v)))
|
||||||
|
else:
|
||||||
|
table[key] = record
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup):
|
def _pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup):
|
||||||
@@ -51,6 +82,22 @@ class DataStore(object):
|
|||||||
# Lookup for translating between /dev/<name> and pv uuid
|
# Lookup for translating between /dev/<name> and pv uuid
|
||||||
c_lookup[p['pv_name']] = p['pv_uuid']
|
c_lookup[p['pv_name']] = p['pv_uuid']
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _parse_pvs(_pvs):
|
||||||
|
pvs = sorted(_pvs, key=lambda pk: pk['pv_name'])
|
||||||
|
|
||||||
|
c_pvs = OrderedDict()
|
||||||
|
c_lookup = {}
|
||||||
|
c_pvs_in_vgs = {}
|
||||||
|
|
||||||
|
for p in pvs:
|
||||||
|
DataStore._insert_record(
|
||||||
|
c_pvs, p['pv_uuid'], p,
|
||||||
|
['pvseg_start', 'pvseg_size', 'segtype'])
|
||||||
|
|
||||||
|
DataStore._pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup)
|
||||||
|
return c_pvs, c_lookup, c_pvs_in_vgs
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_pvs_json(_all):
|
def _parse_pvs_json(_all):
|
||||||
|
|
||||||
@@ -58,7 +105,7 @@ class DataStore(object):
|
|||||||
c_lookup = {}
|
c_lookup = {}
|
||||||
c_pvs_in_vgs = {}
|
c_pvs_in_vgs = {}
|
||||||
|
|
||||||
# Each item in the report is a collection of information pertaining
|
# Each item item in the report is a collection of information pertaining
|
||||||
# to the vg
|
# to the vg
|
||||||
for r in _all['report']:
|
for r in _all['report']:
|
||||||
tmp_pv = []
|
tmp_pv = []
|
||||||
@@ -92,6 +139,19 @@ class DataStore(object):
|
|||||||
|
|
||||||
return c_pvs, c_lookup, c_pvs_in_vgs
|
return c_pvs, c_lookup, c_pvs_in_vgs
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _parse_vgs(_vgs):
|
||||||
|
vgs = sorted(_vgs, key=lambda vk: vk['vg_name'])
|
||||||
|
|
||||||
|
c_vgs = OrderedDict()
|
||||||
|
c_lookup = {}
|
||||||
|
|
||||||
|
for i in vgs:
|
||||||
|
c_lookup[i['vg_name']] = i['vg_uuid']
|
||||||
|
DataStore._insert_record(c_vgs, i['vg_uuid'], i, [])
|
||||||
|
|
||||||
|
return c_vgs, c_lookup
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_vgs_json(_all):
|
def _parse_vgs_json(_all):
|
||||||
|
|
||||||
@@ -102,22 +162,13 @@ class DataStore(object):
|
|||||||
tmp_vg.extend(r['vg'])
|
tmp_vg.extend(r['vg'])
|
||||||
|
|
||||||
# Sort for consistent output, however this is optional
|
# Sort for consistent output, however this is optional
|
||||||
vgs = sorted(tmp_vg, key=lambda vk: vk['vg_uuid'])
|
vgs = sorted(tmp_vg, key=lambda vk: vk['vg_name'])
|
||||||
|
|
||||||
c_vgs = OrderedDict()
|
c_vgs = OrderedDict()
|
||||||
c_lookup = {}
|
c_lookup = {}
|
||||||
|
|
||||||
for i in vgs:
|
for i in vgs:
|
||||||
vg_name = i['vg_name']
|
c_lookup[i['vg_name']] = i['vg_uuid']
|
||||||
|
|
||||||
# Lvm allows duplicate vg names. When this occurs, each subsequent
|
|
||||||
# matching VG name will be called vg_name:vg_uuid. Note: ':' is an
|
|
||||||
# invalid character for lvm VG names
|
|
||||||
if vg_name in c_lookup:
|
|
||||||
vg_name = "%s:%s" % (vg_name, i['vg_uuid'])
|
|
||||||
i['vg_name'] = vg_name
|
|
||||||
|
|
||||||
c_lookup[vg_name] = i['vg_uuid']
|
|
||||||
c_vgs[i['vg_uuid']] = i
|
c_vgs[i['vg_uuid']] = i
|
||||||
|
|
||||||
return c_vgs, c_lookup
|
return c_vgs, c_lookup
|
||||||
@@ -156,12 +207,29 @@ class DataStore(object):
|
|||||||
|
|
||||||
return c_lvs, c_lvs_in_vgs, c_lvs_hidden, c_lv_full_lookup
|
return c_lvs, c_lvs_in_vgs, c_lvs_hidden, c_lv_full_lookup
|
||||||
|
|
||||||
def _parse_lvs_json(self, _all):
|
@staticmethod
|
||||||
|
def _parse_lvs(_lvs):
|
||||||
|
lvs = sorted(_lvs, key=lambda vk: vk['lv_name'])
|
||||||
|
|
||||||
|
c_lvs = OrderedDict()
|
||||||
|
c_lv_full_lookup = OrderedDict()
|
||||||
|
|
||||||
|
for i in lvs:
|
||||||
|
full_name = "%s/%s" % (i['vg_name'], i['lv_name'])
|
||||||
|
c_lv_full_lookup[full_name] = i['lv_uuid']
|
||||||
|
DataStore._insert_record(
|
||||||
|
c_lvs, i['lv_uuid'], i,
|
||||||
|
['seg_pe_ranges', 'segtype'])
|
||||||
|
|
||||||
|
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _parse_lvs_json(_all):
|
||||||
|
|
||||||
c_lvs = OrderedDict()
|
c_lvs = OrderedDict()
|
||||||
c_lv_full_lookup = {}
|
c_lv_full_lookup = {}
|
||||||
|
|
||||||
# Each item in the report is a collection of information pertaining
|
# Each item item in the report is a collection of information pertaining
|
||||||
# to the vg
|
# to the vg
|
||||||
for r in _all['report']:
|
for r in _all['report']:
|
||||||
# Get the lv data for this VG.
|
# Get the lv data for this VG.
|
||||||
@@ -176,13 +244,8 @@ class DataStore(object):
|
|||||||
if 'seg' in r:
|
if 'seg' in r:
|
||||||
for s in r['seg']:
|
for s in r['seg']:
|
||||||
r = c_lvs[s['lv_uuid']]
|
r = c_lvs[s['lv_uuid']]
|
||||||
r.setdefault('seg_pe_ranges', []).\
|
r.setdefault('seg_pe_ranges', []).append(s['seg_pe_ranges'])
|
||||||
append(s['seg_pe_ranges'])
|
|
||||||
r.setdefault('segtype', []).append(s['segtype'])
|
r.setdefault('segtype', []).append(s['segtype'])
|
||||||
if self.vdo_support:
|
|
||||||
for seg_key, seg_val in s.items():
|
|
||||||
if seg_key.startswith("vdo_"):
|
|
||||||
r[seg_key] = seg_val
|
|
||||||
|
|
||||||
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
|
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
|
||||||
|
|
||||||
@@ -309,12 +372,12 @@ class DataStore(object):
|
|||||||
:param log Add debug log entry/exit messages
|
:param log Add debug log entry/exit messages
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
self.num_refreshes += 1
|
self.num_refreshes += 1
|
||||||
if log:
|
if log:
|
||||||
log_debug("lvmdb - refresh entry")
|
log_debug("lvmdb - refresh entry")
|
||||||
|
|
||||||
# Grab everything first then parse it
|
# Grab everything first then parse it
|
||||||
|
if self.json:
|
||||||
# Do a single lvm retrieve for everything in json
|
# Do a single lvm retrieve for everything in json
|
||||||
a = cmdhandler.lvm_full_report_json()
|
a = cmdhandler.lvm_full_report_json()
|
||||||
|
|
||||||
@@ -322,6 +385,15 @@ class DataStore(object):
|
|||||||
_vgs, _vgs_lookup = self._parse_vgs_json(a)
|
_vgs, _vgs_lookup = self._parse_vgs_json(a)
|
||||||
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs_json(a)
|
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs_json(a)
|
||||||
|
|
||||||
|
else:
|
||||||
|
_raw_pvs = cmdhandler.pv_retrieve_with_segs()
|
||||||
|
_raw_vgs = cmdhandler.vg_retrieve(None)
|
||||||
|
_raw_lvs = cmdhandler.lv_retrieve_with_segments()
|
||||||
|
|
||||||
|
_pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs(_raw_pvs)
|
||||||
|
_vgs, _vgs_lookup = self._parse_vgs(_raw_vgs)
|
||||||
|
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs(_raw_lvs)
|
||||||
|
|
||||||
# Set all
|
# Set all
|
||||||
self.pvs = _pvs
|
self.pvs = _pvs
|
||||||
self.pv_path_to_uuid = _pvs_lookup
|
self.pv_path_to_uuid = _pvs_lookup
|
||||||
@@ -336,11 +408,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")
|
||||||
@@ -351,7 +418,7 @@ class DataStore(object):
|
|||||||
else:
|
else:
|
||||||
rc = []
|
rc = []
|
||||||
for s in pv_name:
|
for s in pv_name:
|
||||||
# The user could be using a symlink instead of the actual
|
# Ths user could be using a symlink instead of the actual
|
||||||
# block device, make sure we are using actual block device file
|
# block device, make sure we are using actual block device file
|
||||||
# if the pv name isn't in the lookup
|
# if the pv name isn't in the lookup
|
||||||
if s not in self.pv_path_to_uuid:
|
if s not in self.pv_path_to_uuid:
|
||||||
@@ -360,13 +427,10 @@ class DataStore(object):
|
|||||||
return rc
|
return rc
|
||||||
|
|
||||||
def pv_missing(self, pv_uuid):
|
def pv_missing(self, pv_uuid):
|
||||||
# The uuid might not be a PV, default to false
|
|
||||||
if pv_uuid in self.pvs:
|
if pv_uuid in self.pvs:
|
||||||
if self.pvs[pv_uuid]['pv_missing'] == '':
|
if self.pvs[pv_uuid]['pv_missing'] == '':
|
||||||
return False
|
return False
|
||||||
else:
|
|
||||||
return True
|
return True
|
||||||
return False
|
|
||||||
|
|
||||||
def fetch_vgs(self, vg_name):
|
def fetch_vgs(self, vg_name):
|
||||||
if not vg_name:
|
if not vg_name:
|
||||||
@@ -437,11 +501,15 @@ class DataStore(object):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
os.environ["LC_ALL"] = "C"
|
|
||||||
os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
|
|
||||||
pp = prettyprint.PrettyPrinter(indent=4)
|
pp = prettyprint.PrettyPrinter(indent=4)
|
||||||
|
|
||||||
ds = DataStore()
|
use_json = False
|
||||||
|
|
||||||
|
if len(sys.argv) != 1:
|
||||||
|
print(len(sys.argv))
|
||||||
|
use_json = True
|
||||||
|
|
||||||
|
ds = DataStore(use_json)
|
||||||
ds.refresh()
|
ds.refresh()
|
||||||
|
|
||||||
print("PVS")
|
print("PVS")
|
||||||
@@ -453,10 +521,6 @@ if __name__ == "__main__":
|
|||||||
for v in ds.vgs.values():
|
for v in ds.vgs.values():
|
||||||
pp.pprint(v)
|
pp.pprint(v)
|
||||||
|
|
||||||
print("VG name to UUID")
|
|
||||||
for k, v in ds.vg_name_to_uuid.items():
|
|
||||||
print("%s: %s" % (k, v))
|
|
||||||
|
|
||||||
print("LVS")
|
print("LVS")
|
||||||
for v in ds.lvs.values():
|
for v in ds.lvs.values():
|
||||||
pp.pprint(v)
|
pp.pprint(v)
|
||||||
|
|||||||
@@ -22,13 +22,14 @@ from . import lvmdb
|
|||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
from .fetch import StateUpdate
|
from .fetch import StateUpdate
|
||||||
from .manager import Manager
|
from .manager import Manager
|
||||||
|
import traceback
|
||||||
import queue
|
import queue
|
||||||
from . import udevwatch
|
from . import udevwatch
|
||||||
from .utils import log_debug, log_error, log_msg, DebugMessages
|
from .utils import log_debug, log_error
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from .cmdhandler import LvmFlightRecorder, supports_vdo, supports_json
|
from .cmdhandler import LvmFlightRecorder
|
||||||
from .request import RequestEntry
|
from .request import RequestEntry
|
||||||
|
|
||||||
|
|
||||||
@@ -41,23 +42,20 @@ 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)" %
|
"Running method: %s with args %s" %
|
||||||
(str(req.method), str(req.arguments), str(req.cb)))
|
(str(req.method), str(req.arguments)))
|
||||||
req.run_cmd()
|
req.run_cmd()
|
||||||
log_debug("Method complete: %s" % str(req.method))
|
log_debug("Method complete ")
|
||||||
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,82 +104,34 @@ def process_args():
|
|||||||
default=False,
|
default=False,
|
||||||
dest='use_lvm_shell')
|
dest='use_lvm_shell')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--frsize",
|
"--blackboxsize",
|
||||||
help="Size of the flight recorder (num. entries), 0 to disable (signal 12 to dump)",
|
help="Size of the black box flight recorder, 0 to disable",
|
||||||
default=10,
|
default=10,
|
||||||
type=check_fr_size,
|
type=check_bb_size,
|
||||||
dest='fr_size')
|
dest='bb_size')
|
||||||
|
|
||||||
args = parser.parse_args()
|
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
|
||||||
|
|
||||||
if not args.use_json:
|
# Ensure that we get consistent output for parsing stdout/stderr
|
||||||
log_error("Daemon no longer supports lvm without JSON support, exiting!")
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
if not supports_json():
|
|
||||||
log_error("Un-supported version of LVM, daemon requires JSON output, exiting!")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Add udev watching
|
|
||||||
if args.use_udev:
|
|
||||||
# Make sure this msg ends up in the journal, so we know
|
|
||||||
log_msg('The --udev option is no longer supported,'
|
|
||||||
'the daemon always uses a combination of dbus notify from lvm tools and udev')
|
|
||||||
|
|
||||||
return args
|
|
||||||
|
|
||||||
|
|
||||||
def running_under_systemd():
|
|
||||||
""""
|
|
||||||
Checks to see if we are running under systemd, by checking daemon fd 0, 1
|
|
||||||
systemd sets stdin to /dev/null and 1 & 2 are a socket
|
|
||||||
"""
|
|
||||||
base = "/proc/self/fd"
|
|
||||||
stdout = os.readlink("%s/0" % base)
|
|
||||||
if stdout == "/dev/null":
|
|
||||||
stdout = os.readlink("%s/1" % base)
|
|
||||||
if "socket" in stdout:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
start = time.time()
|
|
||||||
use_session = os.getenv('LVM_DBUSD_USE_SESSION', False)
|
|
||||||
|
|
||||||
# Ensure that we get consistent output for parsing stdout/stderr and that we
|
|
||||||
# are using the lvmdbusd profile.
|
|
||||||
os.environ["LC_ALL"] = "C"
|
os.environ["LC_ALL"] = "C"
|
||||||
os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
|
|
||||||
|
|
||||||
# Indicator if we are running under systemd
|
|
||||||
cfg.systemd = running_under_systemd()
|
|
||||||
|
|
||||||
# Add simple command line handling
|
|
||||||
cfg.args = process_args()
|
|
||||||
|
|
||||||
|
cfg.args = parser.parse_args()
|
||||||
cfg.create_request_entry = RequestEntry
|
cfg.create_request_entry = RequestEntry
|
||||||
|
|
||||||
# We create a flight recorder in cmdhandler too, but we replace it here
|
# We create a flight recorder in cmdhandler too, but we replace it here
|
||||||
# as the user may be specifying a different size. The default one in
|
# as the user may be specifying a different size. The default one in
|
||||||
# cmdhandler is for when we are running other code with a different main.
|
# cmdhandler is for when we are running other code with a different main.
|
||||||
cfg.flightrecorder = LvmFlightRecorder(cfg.args.fr_size)
|
cfg.blackbox = LvmFlightRecorder(cfg.args.bb_size)
|
||||||
|
|
||||||
# Create a circular buffer for debug logs
|
if cfg.args.use_lvm_shell and not cfg.args.use_json:
|
||||||
cfg.debug = DebugMessages()
|
log_error("You cannot specify --lvmshell and --nojson")
|
||||||
|
sys.exit(1)
|
||||||
log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
|
|
||||||
|
|
||||||
# We will dynamically add interfaces which support vdo if it
|
|
||||||
# exists.
|
|
||||||
cfg.vdo_support = supports_vdo()
|
|
||||||
|
|
||||||
# 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()
|
||||||
|
|
||||||
@@ -197,14 +147,14 @@ def main():
|
|||||||
cfg.om = Lvm(BASE_OBJ_PATH)
|
cfg.om = Lvm(BASE_OBJ_PATH)
|
||||||
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
|
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
|
||||||
|
|
||||||
cfg.db = lvmdb.DataStore(vdo_support=cfg.vdo_support)
|
cfg.db = lvmdb.DataStore(cfg.args.use_json)
|
||||||
|
|
||||||
# Using a thread to process requests, we cannot hang the dbus library
|
# Using a thread to process requests, we cannot hang the dbus library
|
||||||
# thread that is handling the dbus interface
|
# thread that is handling the dbus interface
|
||||||
thread_list.append(
|
thread_list.append(threading.Thread(target=process_request,
|
||||||
threading.Thread(target=process_request, name='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)
|
||||||
@@ -214,9 +164,13 @@ def main():
|
|||||||
cfg.loop = GLib.MainLoop()
|
cfg.loop = GLib.MainLoop()
|
||||||
|
|
||||||
for thread in thread_list:
|
for thread in thread_list:
|
||||||
thread.daemon = True
|
thread.damon = True
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class Manager(AutomatedProperties):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def Version(self):
|
def Version(self):
|
||||||
return dbus.String('1.1.0')
|
return dbus.String('1.0.0')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def handle_execute(rc, out, err):
|
def handle_execute(rc, out, err):
|
||||||
@@ -107,10 +107,10 @@ class Manager(AutomatedProperties):
|
|||||||
rc = cfg.load(log=False)
|
rc = cfg.load(log=False)
|
||||||
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
utils.log_debug('Manager.Refresh - exit %d %d' % (rc, lc),
|
utils.log_debug('Manager.Refresh - exit %d' % (rc),
|
||||||
'bg_black', 'fg_light_red')
|
'bg_black', 'fg_light_red')
|
||||||
else:
|
else:
|
||||||
utils.log_debug('Manager.Refresh - exit %d %d' % (rc, lc))
|
utils.log_debug('Manager.Refresh - exit %d' % (rc))
|
||||||
return rc + lc
|
return rc + lc
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -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):
|
||||||
@@ -165,8 +164,6 @@ class Manager(AutomatedProperties):
|
|||||||
return the object path in O(1) time.
|
return the object path in O(1) time.
|
||||||
|
|
||||||
:param key: The lookup value
|
:param key: The lookup value
|
||||||
:param cb: dbus python call back parameter, not client visible
|
|
||||||
:param cbe: dbus python error call back parameter, not client visible
|
|
||||||
:return: Return the object path. If object not found you will get '/'
|
:return: Return the object path. If object not found you will get '/'
|
||||||
"""
|
"""
|
||||||
r = RequestEntry(-1, Manager._lookup_by_lvm_id, (key,), cb, cbe, False)
|
r = RequestEntry(-1, Manager._lookup_by_lvm_id, (key,), cb, cbe, False)
|
||||||
@@ -195,7 +192,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 +199,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,8 +169,8 @@ class ObjectManager(AutomatedProperties):
|
|||||||
# print('Registering object path %s for %s' %
|
# print('Registering object path %s for %s' %
|
||||||
# (path, dbus_object.lvm_id))
|
# (path, dbus_object.lvm_id))
|
||||||
|
|
||||||
# We want fast access to the object by a number of different ways,
|
# We want fast access to the object by a number of different ways
|
||||||
# so we use multiple hashes with different keys
|
# so we use multiple hashs with different keys
|
||||||
self._lookup_add(dbus_object, path, dbus_object.lvm_id,
|
self._lookup_add(dbus_object, path, dbus_object.lvm_id,
|
||||||
dbus_object.Uuid)
|
dbus_object.Uuid)
|
||||||
|
|
||||||
@@ -179,8 +189,8 @@ class ObjectManager(AutomatedProperties):
|
|||||||
path = dbus_object.dbus_object_path()
|
path = dbus_object.dbus_object_path()
|
||||||
interfaces = dbus_object.interface()
|
interfaces = dbus_object.interface()
|
||||||
|
|
||||||
# print('UN-Registering object path %s for %s' %
|
# print 'UN-Registering object path %s for %s' % \
|
||||||
# (path, dbus_object.lvm_id))
|
# (path, dbus_object.lvm_id)
|
||||||
|
|
||||||
self._lookup_remove(path)
|
self._lookup_remove(path)
|
||||||
|
|
||||||
@@ -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
|
||||||
"""
|
"""
|
||||||
@@ -230,17 +240,37 @@ class ObjectManager(AutomatedProperties):
|
|||||||
return lookup_rc
|
return lookup_rc
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
def _id_verify(self, path, uuid, lvm_id):
|
def _uuid_verify(self, path, uuid, lvm_id):
|
||||||
"""
|
"""
|
||||||
Ensure our lookups are correct
|
Ensure uuid is present for a successful lvm_id lookup
|
||||||
NOTE: Internal call, assumes under object manager lock
|
NOTE: Internal call, assumes under object manager lock
|
||||||
:param path: Path to object we looked up
|
:param path: Path to object we looked up
|
||||||
:param uuid: uuid lookup
|
:param uuid: lvm uuid to verify
|
||||||
:param lvm_id: lvm_id lookup
|
:param lvm_id: lvm_id used to find object
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
# There is no durable non-changeable name in lvm
|
# This gets called when we found an object based on lvm_id, ensure
|
||||||
|
# uuid is correct too, as they can change. There is no durable
|
||||||
|
# non-changeable name in lvm
|
||||||
if lvm_id != uuid:
|
if lvm_id != uuid:
|
||||||
|
if uuid and uuid not in self._id_to_object_path:
|
||||||
|
obj = self.get_object_by_path(path)
|
||||||
|
self._lookup_add(obj, path, lvm_id, uuid)
|
||||||
|
|
||||||
|
def _lvm_id_verify(self, path, uuid, lvm_id):
|
||||||
|
"""
|
||||||
|
Ensure lvm_id is present for a successful uuid lookup
|
||||||
|
NOTE: Internal call, assumes under object manager lock
|
||||||
|
:param path: Path to object we looked up
|
||||||
|
:param uuid: uuid used to find object
|
||||||
|
:param lvm_id: lvm_id to verify
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
# This gets called when we found an object based on uuid, ensure
|
||||||
|
# lvm_id is correct too, as they can change. There is no durable
|
||||||
|
# non-changeable name in lvm
|
||||||
|
if lvm_id != uuid:
|
||||||
|
if lvm_id and lvm_id not in self._id_to_object_path:
|
||||||
obj = self.get_object_by_path(path)
|
obj = self.get_object_by_path(path)
|
||||||
self._lookup_add(obj, path, lvm_id, uuid)
|
self._lookup_add(obj, path, lvm_id, uuid)
|
||||||
|
|
||||||
@@ -272,12 +302,12 @@ class ObjectManager(AutomatedProperties):
|
|||||||
For a given lvm asset return the dbus object path registered for it.
|
For a given lvm asset return the dbus object path registered for it.
|
||||||
This method first looks up by uuid and then by lvm_id. You
|
This method first looks up by uuid and then by lvm_id. You
|
||||||
can search by just one by setting uuid == lvm_id (uuid or lvm_id).
|
can search by just one by setting uuid == lvm_id (uuid or lvm_id).
|
||||||
If the object is not found and path_create is not None, the
|
If the object is not found and path_create is a not None, the
|
||||||
path_create function will be called to create a new object path and
|
path_create function will be called to create a new object path and
|
||||||
register it with the object manager for the specified uuid & lvm_id.
|
register it with the object manager for the specified uuid & lvm_id.
|
||||||
Note: If path create is not None, uuid and lvm_id cannot be equal
|
Note: If path create is not None, uuid and lvm_id cannot be equal
|
||||||
:param uuid: The uuid for the lvm object we are searching for
|
:param uuid: The uuid for the lvm object we are searching for
|
||||||
:param lvm_id: The lvm name (e.g. pv device path, vg name, lv full name)
|
:param lvm_id: The lvm name (eg. pv device path, vg name, lv full name)
|
||||||
:param path_create: If not None, create the path using this function if
|
:param path_create: If not None, create the path using this function if
|
||||||
we fail to find the object by uuid or lvm_id.
|
we fail to find the object by uuid or lvm_id.
|
||||||
:returns None if lvm asset not found and path_create == None otherwise
|
:returns None if lvm asset not found and path_create == None otherwise
|
||||||
@@ -295,34 +325,61 @@ class ObjectManager(AutomatedProperties):
|
|||||||
if uuid == lvm_id:
|
if uuid == lvm_id:
|
||||||
path = self._id_lookup(lvm_id)
|
path = self._id_lookup(lvm_id)
|
||||||
else:
|
else:
|
||||||
# We have a uuid and an lvm_id we can do sanity checks to ensure
|
# We have a uuid and a lvm_id we can do sanity checks to ensure
|
||||||
# that they are consistent
|
# that they are consistent
|
||||||
|
|
||||||
# If a PV is missing its device path is '[unknown]' or some
|
# If a PV is missing it's device path is '[unknown]' or some
|
||||||
# other text derivation of unknown. When we find that a PV is
|
# other text derivation of unknown. When we find that a PV is
|
||||||
# missing we will clear out the lvm_id as it's not unique
|
# missing we will clear out the lvm_id as it's likely not unique
|
||||||
# and thus not useful and harmful for lookups.
|
# and thus not useful and potentially harmful for lookups.
|
||||||
if cfg.db.pv_missing(uuid):
|
if path_create == pv_obj_path_generate and \
|
||||||
|
cfg.db.pv_missing(uuid):
|
||||||
lvm_id = None
|
lvm_id = None
|
||||||
|
|
||||||
# Let's check for the uuid first
|
# Lets check for the uuid first
|
||||||
path = self._id_lookup(uuid)
|
path = self._id_lookup(uuid)
|
||||||
if path:
|
if path:
|
||||||
# Ensure table lookups are correct
|
# Verify the lvm_id is sane
|
||||||
self._id_verify(path, uuid, lvm_id)
|
self._lvm_id_verify(path, uuid, lvm_id)
|
||||||
else:
|
else:
|
||||||
# Unable to find by UUID, lets lookup by lvm_id
|
# Unable to find by UUID, lets lookup by lvm_id
|
||||||
path = self._id_lookup(lvm_id)
|
path = self._id_lookup(lvm_id)
|
||||||
if path:
|
if path:
|
||||||
# Ensure table lookups are correct
|
# Verify the uuid is sane
|
||||||
self._id_verify(path, uuid, lvm_id)
|
self._uuid_verify(path, uuid, lvm_id)
|
||||||
else:
|
else:
|
||||||
# We have exhausted all lookups, let's create if we can
|
# We have exhausted all lookups, let's create if we can
|
||||||
if path_create:
|
if path_create:
|
||||||
path = path_create()
|
path = path_create()
|
||||||
self._lookup_add(None, path, lvm_id, uuid)
|
self._lookup_add(None, path, lvm_id, uuid)
|
||||||
|
|
||||||
# print('get_object_path_by_lvm_id(%s, %s, %s): return %s' %
|
# print('get_object_path_by_lvm_id(%s, %s, %s, %s: return %s' %
|
||||||
# (uuid, lvm_id, str(path_create), path))
|
# (uuid, lvm_id, str(path_create), str(gen_new), 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
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
@@ -145,12 +138,19 @@ class Pv(AutomatedProperties):
|
|||||||
# Remove the PV, if successful then remove from the model
|
# Remove the PV, if successful then remove from the model
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Pv.validate_dbus_object(pv_uuid, pv_name)
|
Pv.validate_dbus_object(pv_uuid, pv_name)
|
||||||
Pv.handle_execute(*cmdhandler.pv_remove(pv_name, remove_options))
|
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
|
||||||
|
Pv.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def handle_execute(rc, out, err):
|
def handle_execute(rc, out, err):
|
||||||
return _handle_execute(rc, out, err, PV_INTERFACE)
|
if rc == 0:
|
||||||
|
cfg.load()
|
||||||
|
else:
|
||||||
|
# Need to work on error handling, need consistent
|
||||||
|
raise dbus.exceptions.DBusException(
|
||||||
|
PV_INTERFACE,
|
||||||
|
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_dbus_object(pv_uuid, pv_name):
|
def validate_dbus_object(pv_uuid, pv_name):
|
||||||
@@ -178,8 +178,10 @@ class Pv(AutomatedProperties):
|
|||||||
def _resize(pv_uuid, pv_name, new_size_bytes, resize_options):
|
def _resize(pv_uuid, pv_name, new_size_bytes, resize_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Pv.validate_dbus_object(pv_uuid, pv_name)
|
Pv.validate_dbus_object(pv_uuid, pv_name)
|
||||||
Pv.handle_execute(*cmdhandler.pv_resize(pv_name, new_size_bytes,
|
|
||||||
resize_options))
|
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
|
||||||
|
resize_options)
|
||||||
|
Pv.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -198,8 +200,9 @@ class Pv(AutomatedProperties):
|
|||||||
def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options):
|
def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Pv.validate_dbus_object(pv_uuid, pv_name)
|
Pv.validate_dbus_object(pv_uuid, pv_name)
|
||||||
Pv.handle_execute(*cmdhandler.pv_allocatable(pv_name, yes_no,
|
rc, out, err = cmdhandler.pv_allocatable(
|
||||||
allocation_options))
|
pv_name, yes_no, allocation_options)
|
||||||
|
Pv.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
|
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# This copyrighted material is made available to anyone wishing to use,
|
# This copyrighted material is made available to anyone wishing to use,
|
||||||
# modify, copy, or redistribute it subject to the terms and conditions
|
# modify, copy, or redistribute it subject to the terms and conditions
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
import pyudev
|
import pyudev
|
||||||
import threading
|
import threading
|
||||||
import os
|
|
||||||
from . import cfg
|
from . import cfg
|
||||||
from .request import RequestEntry
|
from .request import RequestEntry
|
||||||
from . import utils
|
from . import utils
|
||||||
@@ -53,78 +52,19 @@ def filter_event(action, device):
|
|||||||
# when appropriate.
|
# when appropriate.
|
||||||
refresh = False
|
refresh = False
|
||||||
|
|
||||||
# Debug: Uncomment to log all udev events
|
if '.ID_FS_TYPE_NEW' in device:
|
||||||
#devlinks_str = device.get('DEVLINKS', '')
|
fs_type_new = device['.ID_FS_TYPE_NEW']
|
||||||
#utils.log_debug("Udev event: action='%s', DEVNAME='%s', ID_FS_TYPE='%s', subsystem='%s', DEVLINKS='%s'" %
|
|
||||||
# (action, device.get('DEVNAME', 'N/A'), device.get('ID_FS_TYPE', 'N/A'),
|
|
||||||
# device.get('SUBSYSTEM', 'N/A'), devlinks_str[:100] if devlinks_str else 'N/A'))
|
|
||||||
|
|
||||||
# Ignore everything but change
|
|
||||||
if action != 'change':
|
|
||||||
return
|
|
||||||
|
|
||||||
# Helper to lookup device with automatic path translation for test environments
|
|
||||||
dm_dev_dir = os.environ.get('DM_DEV_DIR', '/dev')
|
|
||||||
|
|
||||||
def lookup_with_translation(device):
|
|
||||||
"""Lookup device by name, with fallback to translated path if needed.
|
|
||||||
|
|
||||||
Try direct lookup first (fast path for production).
|
|
||||||
If not found and using test environment (DM_DEV_DIR != /dev):
|
|
||||||
- Extract dm-name from DEVLINKS (/dev/disk/by-id/dm-name-XXX)
|
|
||||||
- Construct path: $DM_DEV_DIR/mapper/XXX
|
|
||||||
- Try lookup again
|
|
||||||
|
|
||||||
Returns the found object or None.
|
|
||||||
"""
|
|
||||||
devname = device.get('DEVNAME', '')
|
|
||||||
obj = cfg.om.get_object_by_lvm_id(devname)
|
|
||||||
if not obj and dm_dev_dir != '/dev' and devname.startswith('/dev/dm-'):
|
|
||||||
devlinks = device.get('DEVLINKS', '')
|
|
||||||
if devlinks:
|
|
||||||
# Parse DEVLINKS to find dm-name-XXX
|
|
||||||
for link in devlinks.split():
|
|
||||||
if 'dm-name-' in link:
|
|
||||||
# Extract device-mapper name from /dev/disk/by-id/dm-name-XXX
|
|
||||||
dm_name = link.split('dm-name-', 1)[1]
|
|
||||||
# Construct path in DM_DEV_DIR and try lookup
|
|
||||||
mapped_path = os.path.join(dm_dev_dir, 'mapper', dm_name)
|
|
||||||
#utils.log_debug("Translating %s to %s (via dm-name)" % (devname, mapped_path))
|
|
||||||
obj = cfg.om.get_object_by_lvm_id(mapped_path)
|
|
||||||
break
|
|
||||||
return obj
|
|
||||||
|
|
||||||
if 'ID_FS_TYPE' in device:
|
|
||||||
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 lookup_with_translation(device):
|
|
||||||
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 lookup_with_translation(device):
|
found = cfg.om.get_object_by_lvm_id(device['DEVNAME'])
|
||||||
|
if found:
|
||||||
refresh = True
|
refresh = True
|
||||||
else:
|
|
||||||
# This handles the wipefs -a path
|
|
||||||
if not refresh and 'DEVNAME' in device:
|
|
||||||
found_obj = lookup_with_translation(device)
|
|
||||||
|
|
||||||
# Also check device symlinks - udev might report /dev/dm-X but
|
if 'DM_LV_NAME' in device:
|
||||||
# the PV is tracked under a different name
|
|
||||||
if not found_obj:
|
|
||||||
devlinks = device.get('DEVLINKS', '')
|
|
||||||
if devlinks:
|
|
||||||
for link in devlinks.split():
|
|
||||||
found_obj = cfg.om.get_object_by_lvm_id(link)
|
|
||||||
if found_obj:
|
|
||||||
break
|
|
||||||
|
|
||||||
if found_obj:
|
|
||||||
refresh = True
|
refresh = True
|
||||||
|
|
||||||
if refresh:
|
if refresh:
|
||||||
@@ -135,8 +75,7 @@ def add():
|
|||||||
with observer_lock:
|
with observer_lock:
|
||||||
global observer
|
global observer
|
||||||
context = pyudev.Context()
|
context = pyudev.Context()
|
||||||
# Use source='udev' to get processed udev events, not raw kernel events
|
monitor = pyudev.Monitor.from_netlink(context)
|
||||||
monitor = pyudev.Monitor.from_netlink(context, source='udev')
|
|
||||||
monitor.filter_by('block')
|
monitor.filter_by('block')
|
||||||
observer = pyudev.MonitorObserver(monitor, filter_event)
|
observer = pyudev.MonitorObserver(monitor, filter_event)
|
||||||
observer.start()
|
observer.start()
|
||||||
|
|||||||
@@ -10,14 +10,10 @@
|
|||||||
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
|
|
||||||
|
|
||||||
import dbus
|
import dbus
|
||||||
from lvmdbusd import cfg
|
from lvmdbusd import cfg
|
||||||
@@ -30,15 +26,6 @@ import signal
|
|||||||
STDOUT_TTY = os.isatty(sys.stdout.fileno())
|
STDOUT_TTY = os.isatty(sys.stdout.fileno())
|
||||||
|
|
||||||
|
|
||||||
def _handle_execute(rc, out, err, interface):
|
|
||||||
if rc == 0:
|
|
||||||
cfg.load()
|
|
||||||
else:
|
|
||||||
# Need to work on error handling, need consistent
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
interface, 'Exit code %s, stderr = %s' % (str(rc), err))
|
|
||||||
|
|
||||||
|
|
||||||
def rtype(dbus_type):
|
def rtype(dbus_type):
|
||||||
"""
|
"""
|
||||||
Decorator making sure that the decorated function returns a value of
|
Decorator making sure that the decorated function returns a value of
|
||||||
@@ -70,46 +57,25 @@ def n32(v):
|
|||||||
return int(float(v))
|
return int(float(v))
|
||||||
|
|
||||||
|
|
||||||
@rtype(dbus.Double)
|
|
||||||
def d(v):
|
|
||||||
if not v:
|
|
||||||
return 0.0
|
|
||||||
return float(v)
|
|
||||||
|
|
||||||
|
|
||||||
def _snake_to_pascal(s):
|
|
||||||
return ''.join(x.title() for x in s.split('_'))
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyProtectedMember
|
# noinspection PyProtectedMember
|
||||||
def init_class_from_arguments(
|
def init_class_from_arguments(obj_instance):
|
||||||
obj_instance, begin_suffix=None, snake_to_pascal=False):
|
|
||||||
for k, v in list(sys._getframe(1).f_locals.items()):
|
for k, v in list(sys._getframe(1).f_locals.items()):
|
||||||
if k != 'self':
|
if k != 'self':
|
||||||
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)
|
||||||
|
|
||||||
# print 'Init class %s = %s' % (nt, str(v))
|
# print 'Init class %s = %s' % (nt, str(v))
|
||||||
if not (cur and len(str(cur)) and (v is None or len(str(v))) == 0)\
|
if not (cur and len(str(cur)) and (v is None or len(str(v))) == 0):
|
||||||
and (begin_suffix is None or nt.startswith(begin_suffix)):
|
|
||||||
|
|
||||||
if begin_suffix and nt.startswith(begin_suffix):
|
|
||||||
name = nt[len(begin_suffix):]
|
|
||||||
if snake_to_pascal:
|
|
||||||
name = _snake_to_pascal(name)
|
|
||||||
|
|
||||||
setattr(obj_instance, name, v)
|
|
||||||
else:
|
|
||||||
setattr(obj_instance, nt, v)
|
setattr(obj_instance, nt, v)
|
||||||
|
|
||||||
|
|
||||||
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 +159,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 +249,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 +276,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,34 +309,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
|
|
||||||
|
|
||||||
# Set shutdown flag first so worker threads can detect shutdown
|
|
||||||
# even if exit_shell() blocks on shell_lock
|
|
||||||
cfg.run.value = 0
|
cfg.run.value = 0
|
||||||
# If lvm shell is in use, tell it to exit
|
log_debug('Exiting daemon with signal %d' % signum)
|
||||||
if cfg.SHELL_IN_USE is not None:
|
|
||||||
cfg.SHELL_IN_USE.exit_shell()
|
|
||||||
log_error('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
|
||||||
@@ -437,8 +338,6 @@ def lv_object_path_method(name, meta):
|
|||||||
return _hidden_lv_obj_path_generate
|
return _hidden_lv_obj_path_generate
|
||||||
elif meta[0][0] == 't':
|
elif meta[0][0] == 't':
|
||||||
return _thin_pool_obj_path_generate
|
return _thin_pool_obj_path_generate
|
||||||
elif meta[0][0] == 'd':
|
|
||||||
return _vdo_pool_object_path_generate
|
|
||||||
elif meta[0][0] == 'C' and 'pool' in meta[1]:
|
elif meta[0][0] == 'C' and 'pool' in meta[1]:
|
||||||
return _cache_pool_obj_path_generate
|
return _cache_pool_obj_path_generate
|
||||||
|
|
||||||
@@ -456,10 +355,6 @@ def _thin_pool_obj_path_generate():
|
|||||||
return cfg.THIN_POOL_PATH + "/%d" % next(cfg.thin_id)
|
return cfg.THIN_POOL_PATH + "/%d" % next(cfg.thin_id)
|
||||||
|
|
||||||
|
|
||||||
def _vdo_pool_object_path_generate():
|
|
||||||
return cfg.VDO_POOL_PATH + "/%d" % next(cfg.vdo_id)
|
|
||||||
|
|
||||||
|
|
||||||
def _cache_pool_obj_path_generate():
|
def _cache_pool_obj_path_generate():
|
||||||
return cfg.CACHE_POOL_PATH + "/%d" % next(cfg.cache_pool_id)
|
return cfg.CACHE_POOL_PATH + "/%d" % next(cfg.cache_pool_id)
|
||||||
|
|
||||||
@@ -545,13 +440,13 @@ 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 + '.-_+'
|
||||||
_ALLOWABLE_VG_LV_CH_SET = set(_ALLOWABLE_VG_LV_CH)
|
_ALLOWABLE_VG_LV_CH_SET = set(_ALLOWABLE_VG_LV_CH)
|
||||||
_LV_NAME_RESERVED = ("_cdata", "_cmeta", "_corig", "_mimage", "_mlog",
|
_LV_NAME_RESERVED = ("_cdata", "_cmeta", "_corig", "_mimage", "_mlog",
|
||||||
"_pmspare", "_rimage", "_rmeta", "_tdata", "_tmeta", "_vorigin", "_vdata")
|
"_pmspare", "_rimage", "_rmeta", "_tdata", "_tmeta", "_vorigin")
|
||||||
|
|
||||||
# Tags can have the characters, based on the code
|
# Tags can have the characters, based on the code
|
||||||
# a-zA-Z0-9._-+/=!:&#
|
# a-zA-Z0-9._-+/=!:&#
|
||||||
@@ -640,23 +535,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
|
||||||
@@ -668,18 +546,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!
|
||||||
|
|
||||||
|
|
||||||
@@ -693,8 +580,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
|
||||||
@@ -744,6 +632,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):
|
||||||
@@ -754,141 +645,3 @@ def _remove_objects(dbus_objects_rm):
|
|||||||
# Remove dbus objects from main thread
|
# Remove dbus objects from main thread
|
||||||
def mt_remove_dbus_objects(objs):
|
def mt_remove_dbus_objects(objs):
|
||||||
MThreadRunner(_remove_objects, objs).done()
|
MThreadRunner(_remove_objects, objs).done()
|
||||||
|
|
||||||
|
|
||||||
# Make stream non-blocking
|
|
||||||
def make_non_block(stream):
|
|
||||||
flags = fcntl.fcntl(stream, fcntl.F_GETFL)
|
|
||||||
fcntl.fcntl(stream, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
|
||||||
|
|
||||||
|
|
||||||
def read_decoded(stream):
|
|
||||||
tmp = stream.read()
|
|
||||||
if tmp:
|
|
||||||
return tmp.decode("utf-8")
|
|
||||||
return ''
|
|
||||||
|
|
||||||
|
|
||||||
class LockFile(object):
|
|
||||||
"""
|
|
||||||
Simple lock file class
|
|
||||||
Based on Pg.1144 "The Linux Programming Interface" by Michael Kerrisk
|
|
||||||
"""
|
|
||||||
def __init__(self, lock_file):
|
|
||||||
self.fd = 0
|
|
||||||
self.lock_file = lock_file
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
try:
|
|
||||||
os.makedirs(os.path.dirname(self.lock_file), exist_ok=True)
|
|
||||||
self.fd = os.open(self.lock_file, os.O_CREAT | os.O_RDWR, stat.S_IRUSR | stat.S_IWUSR)
|
|
||||||
|
|
||||||
# Get and set the close on exec and lock the file
|
|
||||||
flags = fcntl.fcntl(self.fd, fcntl.F_GETFD)
|
|
||||||
flags |= fcntl.FD_CLOEXEC
|
|
||||||
fcntl.fcntl(self.fd, fcntl.F_SETFL, flags)
|
|
||||||
fcntl.lockf(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
||||||
except OSError as e:
|
|
||||||
if e.errno == errno.EAGAIN:
|
|
||||||
log_error("Daemon already running, exiting!")
|
|
||||||
else:
|
|
||||||
log_error("Error during creation of lock file(%s): errno(%d), exiting!" % (self.lock_file, e.errno))
|
|
||||||
sys.exit(114)
|
|
||||||
|
|
||||||
def __exit__(self, _type, _value, _traceback):
|
|
||||||
os.close(self.fd)
|
|
||||||
|
|
||||||
|
|
||||||
def extract_stack_trace(exception):
|
|
||||||
return ''.join(traceback.format_exception(None, exception, exception.__traceback__))
|
|
||||||
|
|
||||||
|
|
||||||
def lvm_column_key(key):
|
|
||||||
# Check LV
|
|
||||||
if key.startswith("lv_") or key.startswith("vg_") or key.startswith("pool_") or \
|
|
||||||
key.endswith("_percent") or key.startswith("move_") or key.startswith("vdo_") or \
|
|
||||||
key in ["origin_uuid", "segtype", "origin", "data_lv", "metadata_lv"]:
|
|
||||||
return True
|
|
||||||
# Check VG
|
|
||||||
if key.startswith("vg_") or key.startswith("lv_") or key.startswith("pv_") or \
|
|
||||||
key in ["max_lv", "max_pv", "snap_count"]:
|
|
||||||
return True
|
|
||||||
# Check PV
|
|
||||||
if key.startswith("pv") or key.startswith("vg") or (key in ['dev_size', 'pe_start']):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
class LvmBug(RuntimeError):
|
|
||||||
"""
|
|
||||||
Things that are clearly a bug with lvm itself.
|
|
||||||
"""
|
|
||||||
def __init__(self, msg):
|
|
||||||
super().__init__(msg)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "lvm bug encountered: %s" % ' '.join(self.args)
|
|
||||||
|
|
||||||
|
|
||||||
class LvmDebugData:
|
|
||||||
def __init__(self, do_collection):
|
|
||||||
self.fd = -1
|
|
||||||
self.fn = None
|
|
||||||
self.collect = do_collection
|
|
||||||
if self.collect:
|
|
||||||
log_msg("Collecting lvm debug data!")
|
|
||||||
|
|
||||||
def _remove_file(self):
|
|
||||||
if self.fn is not None:
|
|
||||||
os.unlink(self.fn)
|
|
||||||
self.fn = None
|
|
||||||
|
|
||||||
def _close_fd(self):
|
|
||||||
if self.fd != -1:
|
|
||||||
os.close(self.fd)
|
|
||||||
self.fd = -1
|
|
||||||
|
|
||||||
def setup(self):
|
|
||||||
# Create a secure filename
|
|
||||||
if self.collect:
|
|
||||||
self.fd, self.fn = tempfile.mkstemp(suffix=".log", prefix="lvmdbusd.lvm.debug.")
|
|
||||||
return self.fn
|
|
||||||
return None
|
|
||||||
|
|
||||||
def lvm_complete(self):
|
|
||||||
# Remove the file ASAP, so we decrease our odds of leaving it
|
|
||||||
# around if the daemon gets killed by a signal -9
|
|
||||||
self._remove_file()
|
|
||||||
|
|
||||||
def dump(self):
|
|
||||||
# Read the file and log it to log_err
|
|
||||||
if self.fd != -1:
|
|
||||||
# How big could the verbose debug get?
|
|
||||||
debug = os.read(self.fd, 1024*1024*5)
|
|
||||||
debug_txt = debug.decode("utf-8")
|
|
||||||
for line in debug_txt.split("\n"):
|
|
||||||
log_error("lvm debug >>> %s" % line)
|
|
||||||
self._close_fd()
|
|
||||||
# In case lvm_complete doesn't get called.
|
|
||||||
self._remove_file()
|
|
||||||
|
|
||||||
def complete(self):
|
|
||||||
self._close_fd()
|
|
||||||
# In case lvm_complete doesn't get called.
|
|
||||||
self._remove_file()
|
|
||||||
|
|
||||||
|
|
||||||
def get_error_msg(report_json):
|
|
||||||
# Get the error message from the returned JSON
|
|
||||||
if 'log' in report_json:
|
|
||||||
error_msg = ""
|
|
||||||
# Walk the entire log array and build an error string
|
|
||||||
for log_entry in report_json['log']:
|
|
||||||
if log_entry['log_type'] == "error":
|
|
||||||
if error_msg:
|
|
||||||
error_msg += ', ' + log_entry['log_message']
|
|
||||||
else:
|
|
||||||
error_msg = log_entry['log_message']
|
|
||||||
|
|
||||||
return error_msg
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|||||||
@@ -10,17 +10,16 @@
|
|||||||
from .automatedproperties import AutomatedProperties
|
from .automatedproperties import AutomatedProperties
|
||||||
|
|
||||||
from . import utils
|
from . import utils
|
||||||
from .utils import pv_obj_path_generate, vg_obj_path_generate, n, \
|
from .utils import pv_obj_path_generate, vg_obj_path_generate, n
|
||||||
_handle_execute
|
|
||||||
import dbus
|
import dbus
|
||||||
from . import cfg
|
from . import cfg
|
||||||
from .cfg import VG_INTERFACE, VG_VDO_INTERFACE
|
from .cfg import VG_INTERFACE
|
||||||
from . import cmdhandler
|
from . import cmdhandler
|
||||||
from .request import RequestEntry
|
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 +30,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,40 +41,29 @@ 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
|
||||||
|
|
||||||
|
|
||||||
def load_vgs(vg_specific=None, object_path=None, refresh=False,
|
def load_vgs(vg_specific=None, object_path=None, refresh=False,
|
||||||
emit_signal=False, cache_refresh=True):
|
emit_signal=False, cache_refresh=True):
|
||||||
return common(vgs_state_retrieve, (Vg, VgVdo, ), vg_specific, object_path, refresh,
|
return common(vgs_state_retrieve, (Vg,), vg_specific, object_path, refresh,
|
||||||
emit_signal, cache_refresh)
|
emit_signal, cache_refresh)
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
|
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
|
||||||
class VgState(State):
|
class VgState(State):
|
||||||
|
|
||||||
@property
|
|
||||||
def internal_name(self):
|
|
||||||
return self.Name
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lvm_id(self):
|
def lvm_id(self):
|
||||||
return self.internal_name
|
return self.Name
|
||||||
|
|
||||||
def identifiers(self):
|
def identifiers(self):
|
||||||
return (self.Uuid, self.internal_name)
|
return (self.Uuid, self.Name)
|
||||||
|
|
||||||
def _lv_paths_build(self):
|
def _lv_paths_build(self):
|
||||||
rc = []
|
rc = []
|
||||||
for lv in cfg.db.lvs_in_vg(self.Uuid):
|
for lv in cfg.db.lvs_in_vg(self.Uuid):
|
||||||
(lv_name, meta, lv_uuid) = lv
|
(lv_name, meta, lv_uuid) = lv
|
||||||
full_name = "%s/%s" % (self.internal_name, lv_name)
|
full_name = "%s/%s" % (self.Name, lv_name)
|
||||||
|
|
||||||
gen = utils.lv_object_path_method(lv_name, meta)
|
gen = utils.lv_object_path_method(lv_name, meta)
|
||||||
|
|
||||||
@@ -105,11 +92,7 @@ class VgState(State):
|
|||||||
def create_dbus_object(self, path):
|
def create_dbus_object(self, path):
|
||||||
if not path:
|
if not path:
|
||||||
path = cfg.om.get_object_path_by_uuid_lvm_id(
|
path = cfg.om.get_object_path_by_uuid_lvm_id(
|
||||||
self.Uuid, self.internal_name, vg_obj_path_generate)
|
self.Uuid, self.Name, vg_obj_path_generate)
|
||||||
|
|
||||||
if cfg.vdo_support:
|
|
||||||
return VgVdo(path, self)
|
|
||||||
else:
|
|
||||||
return Vg(path, self)
|
return Vg(path, self)
|
||||||
|
|
||||||
# noinspection PyMethodMayBeStatic
|
# noinspection PyMethodMayBeStatic
|
||||||
@@ -119,6 +102,7 @@ class VgState(State):
|
|||||||
|
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
@utils.dbus_property(VG_INTERFACE, 'Uuid', 's')
|
@utils.dbus_property(VG_INTERFACE, 'Uuid', 's')
|
||||||
|
@utils.dbus_property(VG_INTERFACE, 'Name', 's')
|
||||||
@utils.dbus_property(VG_INTERFACE, 'Fmt', 's')
|
@utils.dbus_property(VG_INTERFACE, 'Fmt', 's')
|
||||||
@utils.dbus_property(VG_INTERFACE, 'SizeBytes', 't', 0)
|
@utils.dbus_property(VG_INTERFACE, 'SizeBytes', 't', 0)
|
||||||
@utils.dbus_property(VG_INTERFACE, 'FreeBytes', 't', 0)
|
@utils.dbus_property(VG_INTERFACE, 'FreeBytes', 't', 0)
|
||||||
@@ -151,8 +135,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)
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal,PyPep8Naming
|
# noinspection PyUnusedLocal,PyPep8Naming
|
||||||
def __init__(self, object_path, object_state):
|
def __init__(self, object_path, object_state):
|
||||||
@@ -167,7 +149,13 @@ class Vg(AutomatedProperties):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def handle_execute(rc, out, err):
|
def handle_execute(rc, out, err):
|
||||||
return _handle_execute(rc, out, err, VG_INTERFACE)
|
if rc == 0:
|
||||||
|
cfg.load()
|
||||||
|
else:
|
||||||
|
# Need to work on error handling, need consistent
|
||||||
|
raise dbus.exceptions.DBusException(
|
||||||
|
VG_INTERFACE,
|
||||||
|
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_dbus_object(vg_uuid, vg_name):
|
def validate_dbus_object(vg_uuid, vg_name):
|
||||||
@@ -183,8 +171,9 @@ class Vg(AutomatedProperties):
|
|||||||
def _rename(uuid, vg_name, new_name, rename_options):
|
def _rename(uuid, vg_name, new_name, rename_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_rename(
|
rc, out, err = cmdhandler.vg_rename(
|
||||||
uuid, new_name, rename_options))
|
vg_name, new_name, rename_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -203,7 +192,8 @@ class Vg(AutomatedProperties):
|
|||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
# Remove the VG, if successful then remove from the model
|
# Remove the VG, if successful then remove from the model
|
||||||
Vg.handle_execute(*cmdhandler.vg_remove(vg_name, remove_options))
|
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -219,13 +209,14 @@ class Vg(AutomatedProperties):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _change(uuid, vg_name, change_options):
|
def _change(uuid, vg_name, change_options):
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_change(change_options, vg_name))
|
rc, out, err = cmdhandler.vg_change(change_options, vg_name)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
# TODO: This should be broken into a number of different methods
|
# TODO: This should be broken into a number of different methods
|
||||||
# instead of having one method that takes a hash for parameters. Some of
|
# instead of having one method that takes a hash for parameters. Some of
|
||||||
# the changes that vgchange does works on entire system, not just a
|
# the changes that vgchange does works on entire system, not just a
|
||||||
# specific vg, thus that should be in the Manager interface.
|
# specfic vg, thus that should be in the Manager interface.
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
dbus_interface=VG_INTERFACE,
|
dbus_interface=VG_INTERFACE,
|
||||||
in_signature='ia{sv}',
|
in_signature='ia{sv}',
|
||||||
@@ -255,8 +246,9 @@ class Vg(AutomatedProperties):
|
|||||||
VG_INTERFACE,
|
VG_INTERFACE,
|
||||||
'PV Object path not found = %s!' % pv_op)
|
'PV Object path not found = %s!' % pv_op)
|
||||||
|
|
||||||
Vg.handle_execute(*cmdhandler.vg_reduce(
|
rc, out, err = cmdhandler.vg_reduce(vg_name, missing, pv_devices,
|
||||||
vg_name, missing, pv_devices, reduce_options))
|
reduce_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -286,8 +278,9 @@ class Vg(AutomatedProperties):
|
|||||||
VG_INTERFACE, 'PV Object path not found = %s!' % i)
|
VG_INTERFACE, 'PV Object path not found = %s!' % i)
|
||||||
|
|
||||||
if len(extend_devices):
|
if len(extend_devices):
|
||||||
Vg.handle_execute(*cmdhandler.vg_extend(
|
rc, out, err = cmdhandler.vg_extend(vg_name, extend_devices,
|
||||||
vg_name, extend_devices, extend_options))
|
extend_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
VG_INTERFACE, 'No pv_object_paths provided!')
|
VG_INTERFACE, 'No pv_object_paths provided!')
|
||||||
@@ -341,8 +334,10 @@ class Vg(AutomatedProperties):
|
|||||||
|
|
||||||
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
||||||
|
|
||||||
Vg.handle_execute(*cmdhandler.vg_lv_create(
|
rc, out, err = cmdhandler.vg_lv_create(
|
||||||
vg_name, create_options, name, size_bytes, pv_dests))
|
vg_name, create_options, name, size_bytes, pv_dests)
|
||||||
|
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return Vg.fetch_new_lv(vg_name, name)
|
return Vg.fetch_new_lv(vg_name, name)
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -380,8 +375,11 @@ class Vg(AutomatedProperties):
|
|||||||
thin_pool, create_options):
|
thin_pool, create_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_lv_create_linear(
|
|
||||||
vg_name, create_options, name, size_bytes, thin_pool))
|
rc, out, err = cmdhandler.vg_lv_create_linear(
|
||||||
|
vg_name, create_options, name, size_bytes, thin_pool)
|
||||||
|
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return Vg.fetch_new_lv(vg_name, name)
|
return Vg.fetch_new_lv(vg_name, name)
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -403,9 +401,10 @@ class Vg(AutomatedProperties):
|
|||||||
stripe_size_kb, thin_pool, create_options):
|
stripe_size_kb, thin_pool, create_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_lv_create_striped(
|
rc, out, err = cmdhandler.vg_lv_create_striped(
|
||||||
vg_name, create_options, name, size_bytes,
|
vg_name, create_options, name, size_bytes,
|
||||||
num_stripes, stripe_size_kb, thin_pool))
|
num_stripes, stripe_size_kb, thin_pool)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return Vg.fetch_new_lv(vg_name, name)
|
return Vg.fetch_new_lv(vg_name, name)
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -430,8 +429,9 @@ class Vg(AutomatedProperties):
|
|||||||
num_copies, create_options):
|
num_copies, create_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_lv_create_mirror(
|
rc, out, err = cmdhandler.vg_lv_create_mirror(
|
||||||
vg_name, create_options, name, size_bytes, num_copies))
|
vg_name, create_options, name, size_bytes, num_copies)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return Vg.fetch_new_lv(vg_name, name)
|
return Vg.fetch_new_lv(vg_name, name)
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -454,9 +454,10 @@ class Vg(AutomatedProperties):
|
|||||||
num_stripes, stripe_size_kb, create_options):
|
num_stripes, stripe_size_kb, create_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_lv_create_raid(
|
rc, out, err = cmdhandler.vg_lv_create_raid(
|
||||||
vg_name, create_options, name, raid_type, size_bytes,
|
vg_name, create_options, name, raid_type, size_bytes,
|
||||||
num_stripes, stripe_size_kb))
|
num_stripes, stripe_size_kb)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return Vg.fetch_new_lv(vg_name, name)
|
return Vg.fetch_new_lv(vg_name, name)
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -554,8 +555,9 @@ class Vg(AutomatedProperties):
|
|||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
VG_INTERFACE, 'PV object path = %s not found' % p)
|
VG_INTERFACE, 'PV object path = %s not found' % p)
|
||||||
|
|
||||||
Vg.handle_execute(*cmdhandler.pv_tag(
|
rc, out, err = cmdhandler.pv_tag(
|
||||||
pv_devices, tags_add, tags_del, tag_options))
|
pv_devices, tags_add, tags_del, tag_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -596,8 +598,9 @@ class Vg(AutomatedProperties):
|
|||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
|
|
||||||
Vg.handle_execute(*cmdhandler.vg_tag(
|
rc, out, err = cmdhandler.vg_tag(
|
||||||
vg_name, tags_add, tags_del, tag_options))
|
vg_name, tags_add, tags_del, tag_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -636,7 +639,8 @@ class Vg(AutomatedProperties):
|
|||||||
def _vg_change_set(uuid, vg_name, method, value, options):
|
def _vg_change_set(uuid, vg_name, method, value, options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*method(vg_name, value, options))
|
rc, out, err = method(vg_name, value, options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -696,8 +700,9 @@ class Vg(AutomatedProperties):
|
|||||||
options):
|
options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.activate_deactivate(
|
rc, out, err = cmdhandler.activate_deactivate(
|
||||||
'vgchange', vg_name, activate, control_flags, options))
|
'vgchange', vg_name, activate, control_flags, options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -724,12 +729,6 @@ class Vg(AutomatedProperties):
|
|||||||
cb, cbe, return_tuple=False)
|
cb, cbe, return_tuple=False)
|
||||||
cfg.worker_q.put(r)
|
cfg.worker_q.put(r)
|
||||||
|
|
||||||
@property
|
|
||||||
def Name(self):
|
|
||||||
if ':' in self.state.Name:
|
|
||||||
return self.state.Name.split(':')[0]
|
|
||||||
return self.state.Name
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def Tags(self):
|
def Tags(self):
|
||||||
return utils.parse_tags(self.state.tags)
|
return utils.parse_tags(self.state.tags)
|
||||||
@@ -785,75 +784,3 @@ class Vg(AutomatedProperties):
|
|||||||
@property
|
@property
|
||||||
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):
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal,PyPep8Naming
|
|
||||||
def __init__(self, object_path, object_state):
|
|
||||||
super(VgVdo, self).__init__(object_path, vgs_state_retrieve)
|
|
||||||
self.set_interface(VG_VDO_INTERFACE)
|
|
||||||
self._object_path = object_path
|
|
||||||
self.state = object_state
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _lv_vdo_pool_create_with_lv(uuid, vg_name, pool_name, lv_name,
|
|
||||||
data_size, virtual_size, create_options):
|
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
|
||||||
Vg.handle_execute(*cmdhandler.vg_create_vdo_pool_lv_and_lv(
|
|
||||||
vg_name, pool_name, lv_name, data_size, virtual_size,
|
|
||||||
create_options))
|
|
||||||
return Vg.fetch_new_lv(vg_name, pool_name)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_VDO_INTERFACE,
|
|
||||||
in_signature='ssttia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def CreateVdoPoolandLv(self, pool_name, lv_name, data_size, virtual_size,
|
|
||||||
tmo, create_options, cb, cbe):
|
|
||||||
utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, pool_name)
|
|
||||||
utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, lv_name)
|
|
||||||
|
|
||||||
r = RequestEntry(tmo, VgVdo._lv_vdo_pool_create_with_lv,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
pool_name, lv_name, round_size(data_size),
|
|
||||||
round_size(virtual_size),
|
|
||||||
create_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _vdo_pool_create(uuid, vg_name, pool_lv, name, virtual_size, create_options):
|
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
|
||||||
|
|
||||||
# Retrieve the full name of the pool lv
|
|
||||||
pool = cfg.om.get_object_by_path(pool_lv)
|
|
||||||
if not pool:
|
|
||||||
msg = 'LV with object path %s not present!' % \
|
|
||||||
(pool_lv)
|
|
||||||
raise dbus.exceptions.DBusException(VG_VDO_INTERFACE, msg)
|
|
||||||
|
|
||||||
Vg.handle_execute(*cmdhandler.vg_create_vdo_pool(
|
|
||||||
pool.lv_full_name(), name, virtual_size,
|
|
||||||
create_options))
|
|
||||||
return Vg.fetch_new_lv(vg_name, pool.Name)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_VDO_INTERFACE,
|
|
||||||
in_signature='ostia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def CreateVdoPool(self, pool_lv, name, virtual_size,
|
|
||||||
tmo, create_options, cb, cbe):
|
|
||||||
utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, name)
|
|
||||||
|
|
||||||
r = RequestEntry(tmo, VgVdo._vdo_pool_create,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
pool_lv, name,
|
|
||||||
round_size(virtual_size),
|
|
||||||
create_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|||||||
@@ -15,61 +15,51 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
SOURCES = lvmlockd-core.c lvmlockd-helper.c
|
USE_SD_NOTIFY=yes
|
||||||
SOURCES2 = lvmlockctl.c
|
|
||||||
|
|
||||||
TARGETS = lvmlockd lvmlockctl
|
SOURCES = lvmlockd-core.c
|
||||||
|
|
||||||
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 += -ldlm_lt $(LIBDLMCONTROL_LIBS)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ("@BUILD_LOCKDIDM@", "yes")
|
SOURCES2 = lvmlockctl.c
|
||||||
SOURCES += lvmlockd-idm.c
|
|
||||||
LOCK_LIBS += $(LIBSEAGATEILM_LIBS) $(BLKID_LIBS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
TARGETS = lvmlockd lvmlockctl
|
||||||
CFLOW_TARGET = lvmlockd
|
|
||||||
|
|
||||||
.PHONY: install_lvmlockd install_lvmlockctl
|
.PHONY: install_lvmlockd
|
||||||
|
|
||||||
|
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 += $(RT_LIBS) $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
||||||
|
|
||||||
ifeq ("@SD_NOTIFY_SUPPORT@", "yes")
|
|
||||||
CFLAGS += $(LIBSYSTEMD_CFLAGS)
|
ifeq ($(USE_SD_NOTIFY),yes)
|
||||||
LIBS += $(LIBSYSTEMD_LIBS)
|
CFLAGS += $(shell pkg-config --cflags libsystemd) -DUSE_SD_NOTIFY
|
||||||
|
LDFLAGS += $(shell pkg-config --libs libsystemd)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
|
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||||
$(SHOW) " [CC] $@"
|
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LOCK_LIBS) $(LIBS)
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LOCK_LIBS) -ldaemonserver $(INTERNAL_LIBS) $(LIBS)
|
||||||
|
|
||||||
lvmlockctl: lvmlockctl.o $(INTERNAL_LIBS)
|
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a
|
||||||
$(SHOW) " [CC] $@"
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(INTERNAL_LIBS) $(LIBS)
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
|
|
||||||
|
|
||||||
install_lvmlockd: lvmlockd
|
install_lvmlockd: lvmlockd
|
||||||
$(SHOW) " [INSTALL] $<"
|
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
|
||||||
|
|
||||||
install_lvmlockctl: lvmlockctl
|
install_lvmlockctl: lvmlockctl
|
||||||
$(SHOW) " [INSTALL] $<"
|
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
|
||||||
|
|
||||||
install_lvm2: install_lvmlockd install_lvmlockctl
|
install_lvm2: install_lvmlockd install_lvmlockctl
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -14,21 +14,17 @@
|
|||||||
#include "libdaemon/client/daemon-client.h"
|
#include "libdaemon/client/daemon-client.h"
|
||||||
|
|
||||||
#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_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",
|
||||||
.socket = sock ?: LVMLOCKD_SOCKET,
|
.socket = sock ?: LVMLOCKD_SOCKET,
|
||||||
.autostart = 0,
|
|
||||||
.protocol = "lvmlockd",
|
.protocol = "lvmlockd",
|
||||||
.protocol_version = 1,
|
.protocol_version = 1,
|
||||||
|
.autostart = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
return daemon_open(lvmlockd_info);
|
return daemon_open(lvmlockd_info);
|
||||||
@@ -36,7 +32,7 @@ static inline __attribute__((always_inline))
|
|||||||
|
|
||||||
static inline void lvmlockd_close(daemon_handle h)
|
static inline void lvmlockd_close(daemon_handle h)
|
||||||
{
|
{
|
||||||
daemon_close(h);
|
return daemon_close(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -54,17 +50,5 @@ static inline void lvmlockd_close(daemon_handle h)
|
|||||||
#define EREMOVED 219
|
#define EREMOVED 219
|
||||||
#define EDEVOPEN 220 /* sanlock failed to open lvmlock LV */
|
#define EDEVOPEN 220 /* sanlock failed to open lvmlock LV */
|
||||||
#define ELMERR 221
|
#define ELMERR 221
|
||||||
#define EORPHAN 222
|
|
||||||
#define EADOPT_NONE 223
|
|
||||||
#define EADOPT_RETRY 224
|
|
||||||
#define EIOTIMEOUT 225
|
|
||||||
#define ELOCKREPAIR 226
|
|
||||||
|
|
||||||
#define LOCKARGS_VERSION 0x00000001 /* meta only */
|
|
||||||
#define LOCKARGS_LVMLOCK 0x00000002 /* meta only */
|
|
||||||
#define LOCKARGS_TIMEOUT 0x00000004 /* user only */
|
|
||||||
#define LOCKARGS_NOTIMEOUT 0x00000008 /* meta or user */
|
|
||||||
#define LOCKARGS_PERSIST 0x00000010 /* meta or user */
|
|
||||||
#define LOCKARGS_NOPERSIST 0x00000020 /* user only */
|
|
||||||
|
|
||||||
#endif /* _LVM_LVMLOCKD_CLIENT_H */
|
#endif /* _LVM_LVMLOCKD_CLIENT_H */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#include "tools/tool.h"
|
#include "tools/tool.h"
|
||||||
|
|
||||||
#include "libdaemon/server/daemon-server.h"
|
#include "daemon-server.h"
|
||||||
#include "lib/mm/xlate.h"
|
#include "lib/mm/xlate.h"
|
||||||
|
|
||||||
#include "lvmlockd-internal.h"
|
#include "lvmlockd-internal.h"
|
||||||
@@ -24,13 +24,13 @@
|
|||||||
* link with non-threaded version of library, libdlm_lt.
|
* link with non-threaded version of library, libdlm_lt.
|
||||||
*/
|
*/
|
||||||
#include "libdlm.h"
|
#include "libdlm.h"
|
||||||
#include "libdlmcontrol.h"
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <byteswap.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ static int check_args_version(char *vg_args)
|
|||||||
unsigned int major = 0;
|
unsigned int major = 0;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
rv = lockd_lockargs_get_version(vg_args, &major, NULL, NULL);
|
rv = version_from_args(vg_args, &major, NULL, NULL);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("check_args_version %s error %d", vg_args, rv);
|
log_error("check_args_version %s error %d", vg_args, rv);
|
||||||
return rv;
|
return rv;
|
||||||
@@ -95,6 +95,7 @@ static int check_args_version(char *vg_args)
|
|||||||
|
|
||||||
static int read_cluster_name(char *clustername)
|
static int read_cluster_name(char *clustername)
|
||||||
{
|
{
|
||||||
|
static const char close_error_msg[] = "read_cluster_name: close_error %d";
|
||||||
char *n;
|
char *n;
|
||||||
int fd;
|
int fd;
|
||||||
int rv;
|
int rv;
|
||||||
@@ -113,33 +114,29 @@ 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;
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
char clustername[MAX_ARGS+1];
|
char clustername[MAX_ARGS+1];
|
||||||
char lock_args_version[MAX_VERSION+1];
|
char lock_args_version[MAX_ARGS+1];
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
memset(clustername, 0, sizeof(clustername));
|
memset(clustername, 0, sizeof(clustername));
|
||||||
memset(lock_args_version, 0, sizeof(lock_args_version));
|
memset(lock_args_version, 0, sizeof(lock_args_version));
|
||||||
|
|
||||||
snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
|
snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
|
||||||
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
|
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
|
||||||
|
|
||||||
rv = read_cluster_name(clustername);
|
rv = read_cluster_name(clustername);
|
||||||
@@ -151,9 +148,7 @@ int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
|||||||
return -EARGS;
|
return -EARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, clustername);
|
snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, clustername);
|
||||||
if (rv >= MAX_ARGS)
|
|
||||||
log_debug("init_vg_dlm vg_args may be too long %d %s", rv, vg_args);
|
|
||||||
rv = 0;
|
rv = 0;
|
||||||
|
|
||||||
log_debug("init_vg_dlm done %s vg_args %s", ls_name, vg_args);
|
log_debug("init_vg_dlm done %s vg_args %s", ls_name, vg_args);
|
||||||
@@ -168,10 +163,8 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
|||||||
struct lm_dlm *lmd;
|
struct lm_dlm *lmd;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if (daemon_test) {
|
if (daemon_test)
|
||||||
log_debug("lm_prepare_lockspace_dlm test");
|
|
||||||
goto skip_args;
|
goto skip_args;
|
||||||
}
|
|
||||||
|
|
||||||
memset(sys_clustername, 0, sizeof(sys_clustername));
|
memset(sys_clustername, 0, sizeof(sys_clustername));
|
||||||
memset(arg_clustername, 0, sizeof(arg_clustername));
|
memset(arg_clustername, 0, sizeof(arg_clustername));
|
||||||
@@ -221,112 +214,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;
|
||||||
@@ -362,7 +263,7 @@ int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl)
|
static int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl)
|
||||||
{
|
{
|
||||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
@@ -371,9 +272,10 @@ int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_
|
|||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
||||||
buf = zalloc(sizeof(struct val_blk) + DLM_LVB_LEN);
|
buf = malloc(sizeof(struct val_blk) + DLM_LVB_LEN);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
memset(buf, 0, sizeof(struct val_blk) + DLM_LVB_LEN);
|
||||||
|
|
||||||
rdd->vb = (struct val_blk *)buf;
|
rdd->vb = (struct val_blk *)buf;
|
||||||
rdd->lksb.sb_lvbptr = buf + sizeof(struct val_blk);
|
rdd->lksb.sb_lvbptr = buf + sizeof(struct val_blk);
|
||||||
@@ -394,7 +296,7 @@ int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_
|
|||||||
r->name, strlen(r->name),
|
r->name, strlen(r->name),
|
||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("%s:%s add_resource_dlm lock error %d", ls->name, r->name, rv);
|
log_error("S %s R %s add_resource_dlm lock error %d", ls->name, r->name, rv);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
@@ -418,9 +320,10 @@ 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:
|
||||||
|
if (rdd->vb)
|
||||||
free(rdd->vb);
|
free(rdd->vb);
|
||||||
|
|
||||||
memset(rdd, 0, sizeof(struct rd_dlm));
|
memset(rdd, 0, sizeof(struct rd_dlm));
|
||||||
@@ -473,7 +376,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("%s:%s adopt_dlm", ls->name, r->name);
|
log_debug("S %s R %s adopt_dlm", ls->name, r->name);
|
||||||
|
|
||||||
if (daemon_test)
|
if (daemon_test)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -482,29 +385,23 @@ 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;
|
|
||||||
}
|
|
||||||
if (rv == -1 && (errno == ENOENT)) {
|
|
||||||
log_debug("%s:%s adopt_dlm adopt mode %d no lock",
|
|
||||||
ls->name, r->name, ld_mode);
|
|
||||||
rv = -EADOPT_NONE;
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_debug("%s:%s adopt_dlm mode %d flags %x error %d errno %d",
|
log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
|
||||||
ls->name, r->name, mode, flags, rv, errno);
|
ls->name, r->name, mode, flags, rv, errno);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -534,7 +431,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int adopt_only, int adopt_ok)
|
struct val_blk *vb_out, int adopt)
|
||||||
{
|
{
|
||||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
@@ -544,13 +441,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
int mode;
|
int mode;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if (adopt_ok) {
|
if (adopt) {
|
||||||
log_debug("%s:%s lock_dlm adopt_ok not supported", ls->name, r->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adopt_only) {
|
|
||||||
log_debug("%s:%s lock_dlm adopt_only", ls->name, r->name);
|
|
||||||
/* When adopting, we don't follow the normal method
|
/* When adopting, we don't follow the normal method
|
||||||
of acquiring a NL lock then converting it to the
|
of acquiring a NL lock then converting it to the
|
||||||
desired mode. */
|
desired mode. */
|
||||||
@@ -579,13 +470,13 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("%s:%s lock_dlm", ls->name, r->name);
|
log_debug("S %s R %s lock_dlm", ls->name, r->name);
|
||||||
|
|
||||||
if (daemon_test) {
|
if (daemon_test) {
|
||||||
if (rdd->vb) {
|
if (rdd->vb) {
|
||||||
vb_out->version = le16toh(rdd->vb->version);
|
vb_out->version = le16_to_cpu(rdd->vb->version);
|
||||||
vb_out->flags = le16toh(rdd->vb->flags);
|
vb_out->flags = le16_to_cpu(rdd->vb->flags);
|
||||||
vb_out->r_version = le32toh(rdd->vb->r_version);
|
vb_out->r_version = le32_to_cpu(rdd->vb->r_version);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -599,7 +490,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
r->name, strlen(r->name),
|
r->name, strlen(r->name),
|
||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
if (rv == -1) {
|
if (rv == -1) {
|
||||||
log_debug("%s:%s lock_dlm acquire mode PR for %d rv %d",
|
log_debug("S %s R %s lock_dlm acquire mode PR for %d rv %d",
|
||||||
ls->name, r->name, mode, rv);
|
ls->name, r->name, mode, rv);
|
||||||
goto lockrv;
|
goto lockrv;
|
||||||
}
|
}
|
||||||
@@ -612,17 +503,17 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
lockrv:
|
lockrv:
|
||||||
if (rv == -1 && errno == EAGAIN) {
|
if (rv == -1 && errno == EAGAIN) {
|
||||||
log_debug("%s:%s lock_dlm acquire mode %d rv EAGAIN", ls->name, r->name, mode);
|
log_debug("S %s R %s lock_dlm acquire mode %d rv EAGAIN", ls->name, r->name, mode);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("%s:%s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
|
log_error("S %s R %s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
|
||||||
return -ELMERR;
|
return -ELMERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rdd->vb) {
|
if (rdd->vb) {
|
||||||
if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
|
if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
|
||||||
log_debug("%s:%s lock_dlm VALNOTVALID", ls->name, r->name);
|
log_debug("S %s R %s lock_dlm VALNOTVALID", ls->name, r->name);
|
||||||
memset(rdd->vb, 0, sizeof(struct val_blk));
|
memset(rdd->vb, 0, sizeof(struct val_blk));
|
||||||
memset(vb_out, 0, sizeof(struct val_blk));
|
memset(vb_out, 0, sizeof(struct val_blk));
|
||||||
goto out;
|
goto out;
|
||||||
@@ -637,9 +528,9 @@ lockrv:
|
|||||||
memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk));
|
memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk));
|
||||||
memcpy(rdd->vb, &vb, sizeof(vb));
|
memcpy(rdd->vb, &vb, sizeof(vb));
|
||||||
|
|
||||||
vb_out->version = le16toh(vb.version);
|
vb_out->version = le16_to_cpu(vb.version);
|
||||||
vb_out->flags = le16toh(vb.flags);
|
vb_out->flags = le16_to_cpu(vb.flags);
|
||||||
vb_out->r_version = le32toh(vb.r_version);
|
vb_out->r_version = le32_to_cpu(vb.r_version);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -651,11 +542,11 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
struct dlm_lksb *lksb = &rdd->lksb;
|
struct dlm_lksb *lksb = &rdd->lksb;
|
||||||
int mode;
|
uint32_t mode;
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
log_debug("%s:%s convert_dlm", ls->name, r->name);
|
log_debug("S %s R %s convert_dlm", ls->name, r->name);
|
||||||
|
|
||||||
flags |= LKF_CONVERT;
|
flags |= LKF_CONVERT;
|
||||||
flags |= LKF_NOQUEUE;
|
flags |= LKF_NOQUEUE;
|
||||||
@@ -664,21 +555,19 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
|
if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
|
||||||
if (!rdd->vb->version) {
|
if (!rdd->vb->version) {
|
||||||
/* first time vb has been written */
|
/* first time vb has been written */
|
||||||
rdd->vb->version = htole16(VAL_BLK_VERSION);
|
rdd->vb->version = cpu_to_le16(VAL_BLK_VERSION);
|
||||||
}
|
}
|
||||||
rdd->vb->r_version = htole32(r_version);
|
rdd->vb->r_version = cpu_to_le32(r_version);
|
||||||
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
|
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
|
||||||
|
|
||||||
log_debug("%s:%s convert_dlm set r_version %u",
|
log_debug("S %s R %s convert_dlm set r_version %u",
|
||||||
ls->name, r->name, r_version);
|
ls->name, r->name, r_version);
|
||||||
|
|
||||||
flags |= LKF_VALBLK;
|
flags |= LKF_VALBLK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mode = to_dlm_mode(ld_mode)) < 0) {
|
mode = to_dlm_mode(ld_mode);
|
||||||
log_error("lm_convert_dlm invalid mode %d", ld_mode);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (daemon_test)
|
if (daemon_test)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -687,11 +576,11 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
if (rv == -1 && errno == EAGAIN) {
|
if (rv == -1 && errno == EAGAIN) {
|
||||||
/* FIXME: When does this happen? Should something different be done? */
|
/* FIXME: When does this happen? Should something different be done? */
|
||||||
log_error("%s:%s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
|
log_error("S %s R %s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("%s:%s convert_dlm error %d", ls->name, r->name, rv);
|
log_error("S %s R %s convert_dlm error %d", ls->name, r->name, rv);
|
||||||
rv = -ELMERR;
|
rv = -ELMERR;
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
@@ -723,17 +612,17 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
memcpy(&vb_next, rdd->vb, sizeof(struct val_blk));
|
memcpy(&vb_next, rdd->vb, sizeof(struct val_blk));
|
||||||
|
|
||||||
if (!vb_prev.version) {
|
if (!vb_prev.version) {
|
||||||
vb_next.version = htole16(VAL_BLK_VERSION);
|
vb_next.version = cpu_to_le16(VAL_BLK_VERSION);
|
||||||
new_vb = 1;
|
new_vb = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((lmu_flags & LMUF_FREE_VG) && (r->type == LD_RT_VG)) {
|
if ((lmu_flags & LMUF_FREE_VG) && (r->type == LD_RT_VG)) {
|
||||||
vb_next.flags = htole16(VBF_REMOVED);
|
vb_next.flags = cpu_to_le16(VBF_REMOVED);
|
||||||
new_vb = 1;
|
new_vb = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r_version) {
|
if (r_version) {
|
||||||
vb_next.r_version = htole32(r_version);
|
vb_next.r_version = cpu_to_le32(r_version);
|
||||||
new_vb = 1;
|
new_vb = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,21 +630,21 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
memcpy(rdd->vb, &vb_next, sizeof(struct val_blk));
|
memcpy(rdd->vb, &vb_next, sizeof(struct val_blk));
|
||||||
memcpy(lksb->sb_lvbptr, &vb_next, sizeof(struct val_blk));
|
memcpy(lksb->sb_lvbptr, &vb_next, sizeof(struct val_blk));
|
||||||
|
|
||||||
log_debug("%s:%s unlock_dlm vb old %x %x %u new %x %x %u",
|
log_debug("S %s R %s unlock_dlm vb old %x %x %u new %x %x %u",
|
||||||
ls->name, r->name,
|
ls->name, r->name,
|
||||||
le16toh(vb_prev.version),
|
le16_to_cpu(vb_prev.version),
|
||||||
le16toh(vb_prev.flags),
|
le16_to_cpu(vb_prev.flags),
|
||||||
le32toh(vb_prev.r_version),
|
le32_to_cpu(vb_prev.r_version),
|
||||||
le16toh(vb_next.version),
|
le16_to_cpu(vb_next.version),
|
||||||
le16toh(vb_next.flags),
|
le16_to_cpu(vb_next.flags),
|
||||||
le32toh(vb_next.r_version));
|
le32_to_cpu(vb_next.r_version));
|
||||||
} else {
|
} else {
|
||||||
log_debug("%s:%s unlock_dlm vb unchanged", ls->name, r->name);
|
log_debug("S %s R %s unlock_dlm vb unchanged", ls->name, r->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
flags |= LKF_VALBLK;
|
flags |= LKF_VALBLK;
|
||||||
} else {
|
} else {
|
||||||
log_debug("%s:%s unlock_dlm", ls->name, r->name);
|
log_debug("S %s R %s unlock_dlm", ls->name, r->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (daemon_test)
|
if (daemon_test)
|
||||||
@@ -765,7 +654,7 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
r->name, strlen(r->name),
|
r->name, strlen(r->name),
|
||||||
0, NULL, NULL, NULL);
|
0, NULL, NULL, NULL);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("%s:%s unlock_dlm error %d", ls->name, r->name, rv);
|
log_error("S %s R %s unlock_dlm error %d", ls->name, r->name, rv);
|
||||||
rv = -ELMERR;
|
rv = -ELMERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -798,16 +687,9 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
|||||||
* the stale lockspaces on the others eventually.)
|
* the stale lockspaces on the others eventually.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* On error, returns < 0
|
|
||||||
*
|
|
||||||
* On success:
|
|
||||||
* If other hosts are found, returns the number.
|
|
||||||
* If no other hosts are found (only ourself), returns 0.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int lm_hosts_dlm(struct lockspace *ls, int notify)
|
int lm_hosts_dlm(struct lockspace *ls, int notify)
|
||||||
{
|
{
|
||||||
|
static const char closedir_err_msg[] = "lm_hosts_dlm: closedir failed";
|
||||||
char ls_nodes_path[PATH_MAX];
|
char ls_nodes_path[PATH_MAX];
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
DIR *ls_dir;
|
DIR *ls_dir;
|
||||||
@@ -830,7 +712,7 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (closedir(ls_dir))
|
if (closedir(ls_dir))
|
||||||
log_error("lm_hosts_dlm: closedir failed");
|
log_error(closedir_err_msg);
|
||||||
|
|
||||||
if (!count) {
|
if (!count) {
|
||||||
log_error("lm_hosts_dlm found no nodes in %s", ls_nodes_path);
|
log_error("lm_hosts_dlm found no nodes in %s", ls_nodes_path);
|
||||||
@@ -847,10 +729,10 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
|
|||||||
|
|
||||||
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||||
{
|
{
|
||||||
|
static const char closedir_err_msg[] = "lm_get_lockspace_dlm: closedir failed";
|
||||||
struct lockspace *ls;
|
struct lockspace *ls;
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
DIR *ls_dir;
|
DIR *ls_dir;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (!(ls_dir = opendir(DLM_LOCKSPACES_PATH)))
|
if (!(ls_dir = opendir(DLM_LOCKSPACES_PATH)))
|
||||||
return -ECONNREFUSED;
|
return -ECONNREFUSED;
|
||||||
@@ -863,20 +745,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)
|
||||||
@@ -895,108 +777,3 @@ int lm_is_running_dlm(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOCKDDLM_CONTROL_SUPPORT
|
|
||||||
|
|
||||||
int lm_refresh_lv_start_dlm(struct action *act)
|
|
||||||
{
|
|
||||||
char path[PATH_MAX] = { 0 };
|
|
||||||
char command[DLMC_RUN_COMMAND_LEN];
|
|
||||||
char run_uuid[DLMC_RUN_UUID_LEN];
|
|
||||||
char *p, *vgname, *lvname;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
/* split /dev/vgname/lvname into vgname and lvname strings */
|
|
||||||
dm_strncpy(path, act->path, sizeof(path));
|
|
||||||
|
|
||||||
/* skip past dev */
|
|
||||||
if (!(p = strchr(path + 1, '/')))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* skip past slashes */
|
|
||||||
while (*p == '/')
|
|
||||||
p++;
|
|
||||||
|
|
||||||
/* start of vgname */
|
|
||||||
vgname = p;
|
|
||||||
|
|
||||||
/* skip past vgname */
|
|
||||||
while (*p != '/')
|
|
||||||
p++;
|
|
||||||
|
|
||||||
/* terminate vgname */
|
|
||||||
*p = '\0';
|
|
||||||
p++;
|
|
||||||
|
|
||||||
/* skip past slashes */
|
|
||||||
while (*p == '/')
|
|
||||||
p++;
|
|
||||||
|
|
||||||
lvname = p;
|
|
||||||
|
|
||||||
memset(command, 0, sizeof(command));
|
|
||||||
memset(run_uuid, 0, sizeof(run_uuid));
|
|
||||||
|
|
||||||
/* todo: add --readonly */
|
|
||||||
|
|
||||||
snprintf(command, DLMC_RUN_COMMAND_LEN,
|
|
||||||
"lvm lvchange --refresh --partial --nolocking %s/%s",
|
|
||||||
vgname, lvname);
|
|
||||||
|
|
||||||
rv = dlmc_run_start(command, strlen(command), 0,
|
|
||||||
DLMC_FLAG_RUN_START_NODE_NONE,
|
|
||||||
run_uuid);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_debug("refresh_lv run_start error %d", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("refresh_lv run_start %s", run_uuid);
|
|
||||||
|
|
||||||
/* Bit of a hack here, we don't need path once started,
|
|
||||||
but we do need to save the run_uuid somewhere, so just
|
|
||||||
replace the path with the uuid. */
|
|
||||||
|
|
||||||
free(act->path);
|
|
||||||
act->path = strdup(run_uuid);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_refresh_lv_check_dlm(struct action *act)
|
|
||||||
{
|
|
||||||
uint32_t check_status = 0;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
/* NB act->path was replaced with run_uuid */
|
|
||||||
|
|
||||||
rv = dlmc_run_check(act->path, strlen(act->path), 0,
|
|
||||||
DLMC_FLAG_RUN_CHECK_CLEAR,
|
|
||||||
&check_status);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_debug("refresh_lv check error %d", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("refresh_lv check %s status %x", act->path, check_status);
|
|
||||||
|
|
||||||
if (!(check_status & DLMC_RUN_STATUS_DONE))
|
|
||||||
return -EAGAIN;
|
|
||||||
|
|
||||||
if (check_status & DLMC_RUN_STATUS_FAILED)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* LOCKDDLM_CONTROL_SUPPORT */
|
|
||||||
|
|
||||||
int lm_refresh_lv_start_dlm(struct action *act)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_refresh_lv_check_dlm(struct action *act)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LOCKDDLM_CONTROL_SUPPORT */
|
|
||||||
|
|||||||
@@ -1,264 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2025 Red Hat, Inc.
|
|
||||||
*
|
|
||||||
* 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 General Public License v2 or (at your option) any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <poll.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/prctl.h>
|
|
||||||
#include <grp.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
|
|
||||||
#include "lvmlockd-internal.h"
|
|
||||||
|
|
||||||
struct list_head commands; /* helper_msg_list entries */
|
|
||||||
|
|
||||||
static int _log_stderr;
|
|
||||||
|
|
||||||
#define log_helper(fmt, args...) \
|
|
||||||
do { \
|
|
||||||
if (_log_stderr) \
|
|
||||||
fprintf(stderr, fmt "\n", ##args); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static void _save_command(struct helper_msg *msg)
|
|
||||||
{
|
|
||||||
struct helper_msg_list *ml;
|
|
||||||
|
|
||||||
ml = malloc(sizeof(struct helper_msg_list));
|
|
||||||
if (!ml)
|
|
||||||
return;
|
|
||||||
|
|
||||||
memcpy(&ml->msg, msg, sizeof(struct helper_msg));
|
|
||||||
list_add_tail(&ml->list, &commands);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct helper_msg_list *_get_command(int pid)
|
|
||||||
{
|
|
||||||
struct helper_msg_list *ml;
|
|
||||||
|
|
||||||
list_for_each_entry(ml, &commands, list) {
|
|
||||||
if (ml->msg.pid == pid)
|
|
||||||
return ml;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_msg(int fd, struct helper_msg *msg)
|
|
||||||
{
|
|
||||||
int rv;
|
|
||||||
retry:
|
|
||||||
rv = read(fd, msg, sizeof(struct helper_msg));
|
|
||||||
if (rv == -1 && errno == EINTR)
|
|
||||||
goto retry;
|
|
||||||
|
|
||||||
if (rv != sizeof(struct helper_msg))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void exec_command(char *cmd_str)
|
|
||||||
{
|
|
||||||
char arg[ONE_ARG_LEN];
|
|
||||||
char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */
|
|
||||||
int av_count = 0;
|
|
||||||
int i, arg_len, cmd_len;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_AV_COUNT + 1; i++)
|
|
||||||
av[i] = NULL;
|
|
||||||
|
|
||||||
if (!cmd_str[0])
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* this should already be done, but make sure */
|
|
||||||
cmd_str[RUN_COMMAND_LEN - 1] = '\0';
|
|
||||||
|
|
||||||
memset(&arg, 0, sizeof(arg));
|
|
||||||
arg_len = 0;
|
|
||||||
cmd_len = strlen(cmd_str);
|
|
||||||
|
|
||||||
for (i = 0; i < cmd_len; i++) {
|
|
||||||
if (!cmd_str[i])
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (av_count == MAX_AV_COUNT)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (cmd_str[i] == '\\') {
|
|
||||||
if (i == (cmd_len - 1))
|
|
||||||
break;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (cmd_str[i] == '\\') {
|
|
||||||
arg[arg_len++] = cmd_str[i];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (isspace(cmd_str[i])) {
|
|
||||||
arg[arg_len++] = cmd_str[i];
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isalnum(cmd_str[i]) || ispunct(cmd_str[i])) {
|
|
||||||
arg[arg_len++] = cmd_str[i];
|
|
||||||
} else if (isspace(cmd_str[i])) {
|
|
||||||
if (arg_len)
|
|
||||||
av[av_count++] = strdup(arg);
|
|
||||||
|
|
||||||
memset(arg, 0, sizeof(arg));
|
|
||||||
arg_len = 0;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((av_count < MAX_AV_COUNT) && arg_len) {
|
|
||||||
av[av_count++] = strdup(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
execvp(av[0], av);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int send_result(struct helper_msg *msg, int fd)
|
|
||||||
{
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
rv = write(fd, msg, sizeof(struct helper_msg));
|
|
||||||
|
|
||||||
if (rv == sizeof(struct helper_msg))
|
|
||||||
return 0;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define IDLE_TIMEOUT_MS (30 * 1000)
|
|
||||||
#define ACTIVE_TIMEOUT_MS 500
|
|
||||||
|
|
||||||
__attribute__((noreturn)) void helper_main(int in_fd, int out_fd, int log_stderr)
|
|
||||||
{
|
|
||||||
struct pollfd pollfd;
|
|
||||||
struct helper_msg msg;
|
|
||||||
struct helper_msg_list *ml;
|
|
||||||
siginfo_t info;
|
|
||||||
unsigned int fork_count = 0;
|
|
||||||
unsigned int done_count = 0;
|
|
||||||
int timeout = IDLE_TIMEOUT_MS;
|
|
||||||
int rv, pid;
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&commands);
|
|
||||||
|
|
||||||
_log_stderr = log_stderr;
|
|
||||||
|
|
||||||
rv = setgroups(0, NULL);
|
|
||||||
if (rv < 0)
|
|
||||||
log_helper("error clearing helper groups errno %i", errno);
|
|
||||||
|
|
||||||
memset(&pollfd, 0, sizeof(pollfd));
|
|
||||||
pollfd.fd = in_fd;
|
|
||||||
pollfd.events = POLLIN;
|
|
||||||
|
|
||||||
openlog("lvmlockd-helper", LOG_CONS | LOG_PID, LOG_LOCAL4);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
rv = poll(&pollfd, 1, timeout);
|
|
||||||
if (rv == -1 && errno == EINTR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (rv < 0)
|
|
||||||
exit(0);
|
|
||||||
|
|
||||||
if (pollfd.revents & POLLIN) {
|
|
||||||
memset(&msg, 0, sizeof(msg));
|
|
||||||
|
|
||||||
rv = read_msg(in_fd, &msg);
|
|
||||||
if (rv)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (msg.type == HELPER_COMMAND) {
|
|
||||||
pid = fork();
|
|
||||||
if (!pid) {
|
|
||||||
exec_command(msg.command);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.pid = pid;
|
|
||||||
|
|
||||||
_save_command(&msg);
|
|
||||||
|
|
||||||
fork_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL))
|
|
||||||
exit(0);
|
|
||||||
|
|
||||||
/* collect child exits until no more children exist (ECHILD)
|
|
||||||
or none are ready (WNOHANG) */
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
memset(&info, 0, sizeof(info));
|
|
||||||
|
|
||||||
rv = waitid(P_ALL, 0, &info, WEXITED | WNOHANG);
|
|
||||||
|
|
||||||
if ((rv < 0) && (errno == ECHILD)) {
|
|
||||||
/*
|
|
||||||
log_helper("helper no children exist fork_count %d done_count %d", fork_count, done_count);
|
|
||||||
*/
|
|
||||||
timeout = IDLE_TIMEOUT_MS;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!rv && !info.si_pid) {
|
|
||||||
log_helper("helper no children ready fork_count %d done_count %d", fork_count, done_count);
|
|
||||||
timeout = ACTIVE_TIMEOUT_MS;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!rv && info.si_pid) {
|
|
||||||
done_count++;
|
|
||||||
|
|
||||||
if (!(ml = _get_command(info.si_pid))) {
|
|
||||||
log_helper("command for pid %d result %d not found",
|
|
||||||
info.si_pid, info.si_status);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_helper("command for pid %d result %d done", info.si_pid, info.si_status);
|
|
||||||
|
|
||||||
ml->msg.type = HELPER_COMMAND_RESULT;
|
|
||||||
ml->msg.result = info.si_status;
|
|
||||||
|
|
||||||
send_result(&ml->msg, out_fd);
|
|
||||||
|
|
||||||
list_del(&ml->list);
|
|
||||||
free(ml);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
log_helper("helper waitid rv %d errno %d fork_count %d done_count %d",
|
|
||||||
rv, errno, fork_count, done_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,837 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2020-2021 Seagate Ltd.
|
|
||||||
*
|
|
||||||
* This file is part of LVM2.
|
|
||||||
*
|
|
||||||
* This copyrighted material is made available to anyone wishing to use,
|
|
||||||
* modify, copy, or redistribute it subject to the terms and conditions
|
|
||||||
* of the GNU Lesser General Public License v.2.1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define _XOPEN_SOURCE 500 /* pthread */
|
|
||||||
#define _ISOC99_SOURCE
|
|
||||||
|
|
||||||
#include "tools/tool.h"
|
|
||||||
|
|
||||||
#include "libdaemon/server/daemon-server.h"
|
|
||||||
#include "lib/mm/xlate.h"
|
|
||||||
|
|
||||||
#include "lvmlockd-internal.h"
|
|
||||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
|
||||||
|
|
||||||
#include "ilm.h"
|
|
||||||
|
|
||||||
#include <blkid/blkid.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <poll.h>
|
|
||||||
#include <regex.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <sys/sysmacros.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#define IDM_TIMEOUT 60000 /* unit: millisecond, 60 seconds */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Each lockspace thread has its own In-Drive Mutex (IDM) lock manager's
|
|
||||||
* connection. After established socket connection, the lockspace has
|
|
||||||
* been created in IDM lock manager and afterwards use the socket file
|
|
||||||
* descriptor to send any requests for lock related operations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct lm_idm {
|
|
||||||
int sock; /* IDM lock manager connection */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rd_idm {
|
|
||||||
struct idm_lock_id id;
|
|
||||||
struct idm_lock_op op;
|
|
||||||
uint64_t vb_timestamp;
|
|
||||||
struct val_blk *vb;
|
|
||||||
};
|
|
||||||
|
|
||||||
int lm_data_size_idm(void)
|
|
||||||
{
|
|
||||||
return sizeof(struct rd_idm);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t read_utc_us(void)
|
|
||||||
{
|
|
||||||
struct timespec cur_time;
|
|
||||||
|
|
||||||
clock_gettime(CLOCK_REALTIME, &cur_time);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert to microseconds unit. IDM reserves the MSB in 8 bytes
|
|
||||||
* and the low 56 bits are used for timestamp; 56 bits can support
|
|
||||||
* calendar year to 2284, so it has 260 years for overflow. Thus it
|
|
||||||
* is quite safe for overflow issue when wrote this code.
|
|
||||||
*/
|
|
||||||
return cur_time.tv_sec * 1000000 + cur_time.tv_nsec / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int uuid_read_format(char *uuid_str, const char *buffer)
|
|
||||||
{
|
|
||||||
int out = 0;
|
|
||||||
|
|
||||||
/* just strip out any dashes */
|
|
||||||
while (*buffer) {
|
|
||||||
|
|
||||||
if (*buffer == '-') {
|
|
||||||
buffer++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out >= 32) {
|
|
||||||
log_error("Too many characters to be uuid.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uuid_str[out++] = *buffer;
|
|
||||||
buffer++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out != 32) {
|
|
||||||
log_error("Couldn't read uuid: incorrect number of "
|
|
||||||
"characters.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SYSFS_ROOT "/sys"
|
|
||||||
#define BUS_SCSI_DEVS "/bus/scsi/devices"
|
|
||||||
|
|
||||||
static struct idm_lock_op glb_lock_op;
|
|
||||||
|
|
||||||
static void lm_idm_free_dir_list(struct dirent **dir_list, int dir_num)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < dir_num; ++i)
|
|
||||||
free(dir_list[i]);
|
|
||||||
free(dir_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_scsi_directory_select(const struct dirent *s)
|
|
||||||
{
|
|
||||||
regex_t regex;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Only select directory with the format x:x:x:x */
|
|
||||||
ret = regcomp(®ex, "^[0-9]+:[0-9]+:[0-9]+:[0-9]+$", REG_EXTENDED);
|
|
||||||
if (ret)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ret = regexec(®ex, s->d_name, 0, NULL, 0);
|
|
||||||
if (!ret) {
|
|
||||||
regfree(®ex);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
regfree(®ex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_scsi_find_block_directory(const char *block_path)
|
|
||||||
{
|
|
||||||
struct stat stats;
|
|
||||||
|
|
||||||
if ((stat(block_path, &stats) >= 0) && S_ISDIR(stats.st_mode))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_scsi_block_node_select(const struct dirent *s)
|
|
||||||
{
|
|
||||||
if (DT_LNK != s->d_type && DT_DIR != s->d_type)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (DT_DIR == s->d_type) {
|
|
||||||
/* Skip this directory: '.' and parent: '..' */
|
|
||||||
if (!strcmp(s->d_name, ".") || !strcmp(s->d_name, ".."))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_scsi_find_block_node(const char *blk_path, char **blk_dev)
|
|
||||||
{
|
|
||||||
struct dirent **dir_list;
|
|
||||||
int dir_num;
|
|
||||||
|
|
||||||
dir_num = scandir(blk_path, &dir_list, lm_idm_scsi_block_node_select, NULL);
|
|
||||||
if (dir_num < 0) {
|
|
||||||
log_error("Cannot find valid directory entry in %s", blk_path);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Should have only one block name under the path, if the dir_num is
|
|
||||||
* not 1 (e.g. 0 or any number bigger than 1), it must be wrong and
|
|
||||||
* should never happen.
|
|
||||||
*/
|
|
||||||
if (dir_num == 1)
|
|
||||||
*blk_dev = strdup(dir_list[0]->d_name);
|
|
||||||
else
|
|
||||||
*blk_dev = NULL;
|
|
||||||
|
|
||||||
lm_idm_free_dir_list(dir_list, dir_num);
|
|
||||||
|
|
||||||
if (!*blk_dev)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return dir_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_scsi_search_propeller_partition(char *dev)
|
|
||||||
{
|
|
||||||
int i, nparts;
|
|
||||||
blkid_probe pr;
|
|
||||||
blkid_partlist ls;
|
|
||||||
int found = -1;
|
|
||||||
|
|
||||||
pr = blkid_new_probe_from_filename(dev);
|
|
||||||
if (!pr) {
|
|
||||||
log_error("%s: failed to create a new libblkid probe", dev);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Binary interface */
|
|
||||||
ls = blkid_probe_get_partitions(pr);
|
|
||||||
if (!ls) {
|
|
||||||
log_error("%s: failed to read partitions", dev);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List partitions */
|
|
||||||
nparts = blkid_partlist_numof_partitions(ls);
|
|
||||||
if (!nparts)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
for (i = 0; i < nparts; i++) {
|
|
||||||
const char *p;
|
|
||||||
blkid_partition par = blkid_partlist_get_partition(ls, i);
|
|
||||||
|
|
||||||
p = blkid_partition_get_name(par);
|
|
||||||
if (p) {
|
|
||||||
log_debug("partition name='%s'", p);
|
|
||||||
|
|
||||||
if (!strcmp(p, "propeller"))
|
|
||||||
found = blkid_partition_get_partno(par);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found >= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
blkid_free_probe(pr);
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *lm_idm_scsi_get_block_device_node(const char *scsi_path)
|
|
||||||
{
|
|
||||||
char *blk_path = NULL;
|
|
||||||
char *blk_dev = NULL;
|
|
||||||
char *dev_node = NULL;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Locate the "block" directory, such like:
|
|
||||||
* /sys/bus/scsi/devices/1:0:0:0/block
|
|
||||||
*/
|
|
||||||
ret = asprintf(&blk_path, "%s/%s", scsi_path, "block");
|
|
||||||
if (ret < 0) {
|
|
||||||
log_error("Fail to allocate block path for %s", scsi_path);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = lm_idm_scsi_find_block_directory(blk_path);
|
|
||||||
if (ret < 0) {
|
|
||||||
log_error("Fail to find block path %s", blk_path);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Locate the block device name, such like:
|
|
||||||
* /sys/bus/scsi/devices/1:0:0:0/block/sdb
|
|
||||||
*
|
|
||||||
* After return from this function and if it makes success,
|
|
||||||
* the global variable "blk_dev" points to the block device
|
|
||||||
* name, in this example it points to string "sdb".
|
|
||||||
*/
|
|
||||||
ret = lm_idm_scsi_find_block_node(blk_path, &blk_dev);
|
|
||||||
if (ret < 0) {
|
|
||||||
log_error("Fail to find block node");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = asprintf(&dev_node, "/dev/%s", blk_dev);
|
|
||||||
if (ret < 0) {
|
|
||||||
log_error("Fail to allocate memory for blk node path");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = lm_idm_scsi_search_propeller_partition(dev_node);
|
|
||||||
if (ret < 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
free(blk_path);
|
|
||||||
free(blk_dev);
|
|
||||||
return dev_node;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
free(blk_path);
|
|
||||||
free(blk_dev);
|
|
||||||
free(dev_node);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_get_gl_lock_pv_list(void)
|
|
||||||
{
|
|
||||||
struct dirent **dir_list;
|
|
||||||
char scsi_bus_path[PATH_MAX];
|
|
||||||
char *drive_path;
|
|
||||||
int i, dir_num, ret;
|
|
||||||
|
|
||||||
if (glb_lock_op.drive_num)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
snprintf(scsi_bus_path, sizeof(scsi_bus_path), "%s%s",
|
|
||||||
SYSFS_ROOT, BUS_SCSI_DEVS);
|
|
||||||
|
|
||||||
dir_num = scandir(scsi_bus_path, &dir_list,
|
|
||||||
lm_idm_scsi_directory_select, NULL);
|
|
||||||
if (dir_num < 0) { /* scsi mid level may not be loaded */
|
|
||||||
log_error("Attached devices: none");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < dir_num; i++) {
|
|
||||||
char *scsi_path;
|
|
||||||
|
|
||||||
ret = asprintf(&scsi_path, "%s/%s", scsi_bus_path,
|
|
||||||
dir_list[i]->d_name);
|
|
||||||
if (ret < 0) {
|
|
||||||
log_error("Fail to allocate memory for scsi directory");
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (glb_lock_op.drive_num >= ILM_DRIVE_MAX_NUM) {
|
|
||||||
log_error("Global lock: drive number %d exceeds limitation (%d) ?!",
|
|
||||||
glb_lock_op.drive_num, ILM_DRIVE_MAX_NUM);
|
|
||||||
free(scsi_path);
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
drive_path = lm_idm_scsi_get_block_device_node(scsi_path);
|
|
||||||
if (!drive_path) {
|
|
||||||
free(scsi_path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
glb_lock_op.drives[glb_lock_op.drive_num] = drive_path;
|
|
||||||
glb_lock_op.drive_num++;
|
|
||||||
|
|
||||||
free(scsi_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
lm_idm_free_dir_list(dir_list, dir_num);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
failed:
|
|
||||||
lm_idm_free_dir_list(dir_list, dir_num);
|
|
||||||
|
|
||||||
for (i = 0; i < glb_lock_op.drive_num; i++) {
|
|
||||||
if (glb_lock_op.drives[i]) {
|
|
||||||
free(glb_lock_op.drives[i]);
|
|
||||||
glb_lock_op.drives[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lm_idm_update_vb_timestamp(uint64_t *vb_timestamp)
|
|
||||||
{
|
|
||||||
uint64_t utc_us = read_utc_us();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* It's possible that the multiple nodes have no clock
|
|
||||||
* synchronization with microsecond precision and the time
|
|
||||||
* is going backward. For this case, simply increment the
|
|
||||||
* existing timestamp and write out to drive.
|
|
||||||
*/
|
|
||||||
if (*vb_timestamp >= utc_us)
|
|
||||||
(*vb_timestamp)++;
|
|
||||||
else
|
|
||||||
*vb_timestamp = utc_us;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_prepare_lockspace_idm(struct lockspace *ls)
|
|
||||||
{
|
|
||||||
struct lm_idm *lm = NULL;
|
|
||||||
|
|
||||||
lm = malloc(sizeof(struct lm_idm));
|
|
||||||
if (!lm) {
|
|
||||||
log_error("S %s prepare_lockspace_idm fail to allocate lm_idm for %s",
|
|
||||||
ls->name, ls->vg_name);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
memset(lm, 0x0, sizeof(struct lm_idm));
|
|
||||||
|
|
||||||
ls->lm_data = lm;
|
|
||||||
log_debug("S %s prepare_lockspace_idm done", ls->name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok)
|
|
||||||
{
|
|
||||||
char killpath[IDM_FAILURE_PATH_LEN];
|
|
||||||
char killargs[IDM_FAILURE_ARGS_LEN];
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!strcmp(ls->name, S_NAME_GL_IDM)) {
|
|
||||||
/*
|
|
||||||
* Prepare the pv list for global lock, if the drive contains
|
|
||||||
* "propeller" partition, then this drive will be considered
|
|
||||||
* as a member of pv list.
|
|
||||||
*/
|
|
||||||
rv = lm_idm_get_gl_lock_pv_list();
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s add_lockspace_idm fail to get pv list for glb lock",
|
|
||||||
ls->name);
|
|
||||||
return -EIO;
|
|
||||||
} else {
|
|
||||||
log_error("S %s add_lockspace_idm get pv list for glb lock",
|
|
||||||
ls->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Construct the execution path for command "lvmlockctl" by using the
|
|
||||||
* path to the lvm binary and appending "lockctl".
|
|
||||||
*/
|
|
||||||
memset(killpath, 0, sizeof(killpath));
|
|
||||||
snprintf(killpath, IDM_FAILURE_PATH_LEN, "%slockctl", LVM_PATH);
|
|
||||||
|
|
||||||
/* Pass the argument "--kill vg_name" for killpath */
|
|
||||||
memset(killargs, 0, sizeof(killargs));
|
|
||||||
snprintf(killargs, IDM_FAILURE_ARGS_LEN, "--kill %s", ls->vg_name);
|
|
||||||
|
|
||||||
/* Connect with IDM lock manager per every lockspace. */
|
|
||||||
rv = ilm_connect(&lmi->sock);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s add_lockspace_idm fail to connect the lock manager %d",
|
|
||||||
ls->name, lmi->sock);
|
|
||||||
lmi->sock = 0;
|
|
||||||
rv = -EMANAGER;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = ilm_set_killpath(lmi->sock, killpath, killargs);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s add_lockspace_idm fail to set kill path %d",
|
|
||||||
ls->name, rv);
|
|
||||||
rv = -EMANAGER;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("S %s add_lockspace_idm kill path is: \"%s %s\"",
|
|
||||||
ls->name, killpath, killargs);
|
|
||||||
|
|
||||||
log_debug("S %s add_lockspace_idm done", ls->name);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
if (lmi && lmi->sock)
|
|
||||||
close(lmi->sock);
|
|
||||||
|
|
||||||
free(lmi);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg)
|
|
||||||
{
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
int i, rv = 0;
|
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
rv = ilm_disconnect(lmi->sock);
|
|
||||||
if (rv < 0)
|
|
||||||
log_error("S %s rem_lockspace_idm error %d", ls->name, rv);
|
|
||||||
|
|
||||||
/* Release pv list for global lock */
|
|
||||||
if (!strcmp(ls->name, "lvm_global")) {
|
|
||||||
for (i = 0; i < glb_lock_op.drive_num; i++) {
|
|
||||||
if (glb_lock_op.drives[i]) {
|
|
||||||
free(glb_lock_op.drives[i]);
|
|
||||||
glb_lock_op.drives[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
free(lmi);
|
|
||||||
ls->lm_data = NULL;
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_add_resource_idm(struct lockspace *ls, struct resource *r)
|
|
||||||
{
|
|
||||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
|
|
||||||
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
|
||||||
rdi->vb = zalloc(sizeof(struct val_blk));
|
|
||||||
if (!rdi->vb)
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_rem_resource_idm(struct lockspace *ls, struct resource *r)
|
|
||||||
{
|
|
||||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
|
|
||||||
free(rdi->vb);
|
|
||||||
|
|
||||||
memset(rdi, 0, sizeof(struct rd_idm));
|
|
||||||
r->lm_init = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int to_idm_mode(int ld_mode)
|
|
||||||
{
|
|
||||||
switch (ld_mode) {
|
|
||||||
case LD_LK_EX:
|
|
||||||
return IDM_MODE_EXCLUSIVE;
|
|
||||||
case LD_LK_SH:
|
|
||||||
return IDM_MODE_SHAREABLE;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|
||||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
|
||||||
int adopt_only, int adopt_ok)
|
|
||||||
{
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
char **drive_path = NULL;
|
|
||||||
uint64_t timestamp;
|
|
||||||
int reset_vb = 0;
|
|
||||||
int rv, i;
|
|
||||||
|
|
||||||
if (!r->lm_init) {
|
|
||||||
rv = lm_add_resource_idm(ls, r);
|
|
||||||
if (rv < 0)
|
|
||||||
return rv;
|
|
||||||
r->lm_init = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdi->op.mode = to_idm_mode(ld_mode);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("lock_idm invalid mode %d", ld_mode);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("S %s R %s lock_idm", ls->name, r->name);
|
|
||||||
|
|
||||||
if (daemon_test) {
|
|
||||||
if (rdi->vb) {
|
|
||||||
vb_out->version = le16toh(rdi->vb->version);
|
|
||||||
vb_out->flags = le16toh(rdi->vb->flags);
|
|
||||||
vb_out->r_version = le32toh(rdi->vb->r_version);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdi->op.timeout = IDM_TIMEOUT;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate the UUID string, for RT_VG, it only needs to generate
|
|
||||||
* UUID string for VG level, for RT_LV, it needs to generate
|
|
||||||
* UUID strings for both VG and LV levels. At the end, these IDs
|
|
||||||
* are used as identifier for IDM in drive firmware.
|
|
||||||
*/
|
|
||||||
if (r->type == LD_RT_VG || r->type == LD_RT_LV)
|
|
||||||
log_debug("S %s R %s VG uuid %s", ls->name, r->name, ls->vg_uuid);
|
|
||||||
if (r->type == LD_RT_LV)
|
|
||||||
log_debug("S %s R %s LV uuid %s", ls->name, r->name, lv_uuid);
|
|
||||||
|
|
||||||
memset(&rdi->id, 0x0, sizeof(struct idm_lock_id));
|
|
||||||
if (r->type == LD_RT_VG) {
|
|
||||||
uuid_read_format(rdi->id.vg_uuid, ls->vg_uuid);
|
|
||||||
} else if (r->type == LD_RT_LV) {
|
|
||||||
uuid_read_format(rdi->id.vg_uuid, ls->vg_uuid);
|
|
||||||
uuid_read_format(rdi->id.lv_uuid, lv_uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Establish the drive path list for lock, since different lock type
|
|
||||||
* has different drive list; the GL lock uses the global pv list,
|
|
||||||
* the VG lock uses the pv list spanned for the whole volume group,
|
|
||||||
* the LV lock uses the pv list for the logical volume.
|
|
||||||
*/
|
|
||||||
switch (r->type) {
|
|
||||||
case LD_RT_GL:
|
|
||||||
drive_path = glb_lock_op.drives;
|
|
||||||
rdi->op.drive_num = glb_lock_op.drive_num;
|
|
||||||
break;
|
|
||||||
case LD_RT_VG:
|
|
||||||
drive_path = (char **)ls->pvs.path;
|
|
||||||
rdi->op.drive_num = ls->pvs.num;
|
|
||||||
break;
|
|
||||||
case LD_RT_LV:
|
|
||||||
drive_path = (char **)pvs->path;
|
|
||||||
rdi->op.drive_num = pvs->num;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!drive_path) {
|
|
||||||
log_error("S %s R %s cannot find the valid drive path array",
|
|
||||||
ls->name, r->name);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rdi->op.drive_num >= ILM_DRIVE_MAX_NUM) {
|
|
||||||
log_error("S %s R %s exceeds limitation for drive path array",
|
|
||||||
ls->name, r->name);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < rdi->op.drive_num; i++)
|
|
||||||
rdi->op.drives[i] = drive_path[i];
|
|
||||||
|
|
||||||
log_debug("S %s R %s mode %d drive_num %d timeout %d",
|
|
||||||
ls->name, r->name, rdi->op.mode,
|
|
||||||
rdi->op.drive_num, rdi->op.timeout);
|
|
||||||
|
|
||||||
for (i = 0; i < rdi->op.drive_num; i++)
|
|
||||||
log_debug("S %s R %s drive path[%d] %s",
|
|
||||||
ls->name, r->name, i, rdi->op.drives[i]);
|
|
||||||
|
|
||||||
rv = ilm_lock(lmi->sock, &rdi->id, &rdi->op);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_debug("S %s R %s lock_idm acquire mode %d rv %d",
|
|
||||||
ls->name, r->name, ld_mode, rv);
|
|
||||||
return -ELOCKIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rdi->vb) {
|
|
||||||
rv = ilm_read_lvb(lmi->sock, &rdi->id, (char *)×tamp,
|
|
||||||
sizeof(uint64_t));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If fail to read value block, which might be caused by drive
|
|
||||||
* failure, notify up layer to invalidate metadata.
|
|
||||||
*/
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s R %s lock_idm get_lvb error %d",
|
|
||||||
ls->name, r->name, rv);
|
|
||||||
reset_vb = 1;
|
|
||||||
|
|
||||||
/* Reset timestamp */
|
|
||||||
rdi->vb_timestamp = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the cached timestamp mismatches with the stored value
|
|
||||||
* in the IDM, this means another host has updated timestamp
|
|
||||||
* for the new VB. Let's reset VB and notify up layer to
|
|
||||||
* invalidate metadata.
|
|
||||||
*/
|
|
||||||
} else if (rdi->vb_timestamp != timestamp) {
|
|
||||||
log_debug("S %s R %s lock_idm get lvb timestamp %lu:%lu",
|
|
||||||
ls->name, r->name, rdi->vb_timestamp,
|
|
||||||
timestamp);
|
|
||||||
|
|
||||||
rdi->vb_timestamp = timestamp;
|
|
||||||
reset_vb = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reset_vb == 1) {
|
|
||||||
memset(rdi->vb, 0, sizeof(struct val_blk));
|
|
||||||
memset(vb_out, 0, sizeof(struct val_blk));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The lock is still acquired, but the vb values has
|
|
||||||
* been invalidated.
|
|
||||||
*/
|
|
||||||
rv = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise, copy the cached VB to up layer */
|
|
||||||
memcpy(vb_out, rdi->vb, sizeof(struct val_blk));
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
int ld_mode, uint32_t r_version)
|
|
||||||
{
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
int mode, rv;
|
|
||||||
|
|
||||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
|
||||||
if (!rdi->vb->version) {
|
|
||||||
/* first time vb has been written */
|
|
||||||
rdi->vb->version = VAL_BLK_VERSION;
|
|
||||||
}
|
|
||||||
rdi->vb->r_version = r_version;
|
|
||||||
|
|
||||||
log_debug("S %s R %s convert_idm set r_version %u",
|
|
||||||
ls->name, r->name, r_version);
|
|
||||||
|
|
||||||
lm_idm_update_vb_timestamp(&rdi->vb_timestamp);
|
|
||||||
log_debug("S %s R %s convert_idm vb %x %x %u timestamp %lu",
|
|
||||||
ls->name, r->name, rdi->vb->version, rdi->vb->flags,
|
|
||||||
rdi->vb->r_version, rdi->vb_timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
mode = to_idm_mode(ld_mode);
|
|
||||||
if (mode < 0) {
|
|
||||||
log_error("S %s R %s convert_idm invalid mode %d",
|
|
||||||
ls->name, r->name, ld_mode);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("S %s R %s convert_idm", ls->name, r->name);
|
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
|
||||||
rv = ilm_write_lvb(lmi->sock, &rdi->id,
|
|
||||||
(char *)rdi->vb_timestamp, sizeof(uint64_t));
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s R %s convert_idm write lvb error %d",
|
|
||||||
ls->name, r->name, rv);
|
|
||||||
return -ELMERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = ilm_convert(lmi->sock, &rdi->id, mode);
|
|
||||||
if (rv < 0)
|
|
||||||
log_error("S %s R %s convert_idm convert error %d",
|
|
||||||
ls->name, r->name, rv);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_unlock_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
uint32_t r_version, uint32_t lmu_flags)
|
|
||||||
{
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
|
||||||
if (!rdi->vb->version) {
|
|
||||||
/* first time vb has been written */
|
|
||||||
rdi->vb->version = VAL_BLK_VERSION;
|
|
||||||
}
|
|
||||||
if (r_version)
|
|
||||||
rdi->vb->r_version = r_version;
|
|
||||||
|
|
||||||
lm_idm_update_vb_timestamp(&rdi->vb_timestamp);
|
|
||||||
log_debug("S %s R %s unlock_idm vb %x %x %u timestamp %lu",
|
|
||||||
ls->name, r->name, rdi->vb->version, rdi->vb->flags,
|
|
||||||
rdi->vb->r_version, rdi->vb_timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("S %s R %s unlock_idm", ls->name, r->name);
|
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
|
||||||
rv = ilm_write_lvb(lmi->sock, &rdi->id,
|
|
||||||
(char *)&rdi->vb_timestamp, sizeof(uint64_t));
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s R %s unlock_idm set_lvb error %d",
|
|
||||||
ls->name, r->name, rv);
|
|
||||||
return -ELMERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = ilm_unlock(lmi->sock, &rdi->id);
|
|
||||||
if (rv < 0)
|
|
||||||
log_error("S %s R %s unlock_idm error %d", ls->name, r->name, rv);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_hosts_idm(struct lockspace *ls, int notify)
|
|
||||||
{
|
|
||||||
struct resource *r;
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
struct rd_idm *rdi;
|
|
||||||
int count, self, found_others = 0;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
list_for_each_entry(r, &ls->resources, list) {
|
|
||||||
if (!r->lm_init)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
|
|
||||||
rv = ilm_get_host_count(lmi->sock, &rdi->id, &rdi->op,
|
|
||||||
&count, &self);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s lm_hosts_idm error %d", ls->name, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fixup: need to reduce self count */
|
|
||||||
if (count > found_others)
|
|
||||||
found_others = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return found_others;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_get_lockspaces_idm(struct list_head *ls_rejoin)
|
|
||||||
{
|
|
||||||
/* TODO: Need to add support for adoption. */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_is_running_idm(void)
|
|
||||||
{
|
|
||||||
int sock, rv;
|
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
return gl_use_idm;
|
|
||||||
|
|
||||||
rv = ilm_connect(&sock);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("Fail to connect seagate IDM lock manager %d", rv);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ilm_disconnect(sock);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@@ -11,11 +11,6 @@
|
|||||||
#ifndef _LVM_LVMLOCKD_INTERNAL_H
|
#ifndef _LVM_LVMLOCKD_INTERNAL_H
|
||||||
#define _LVM_LVMLOCKD_INTERNAL_H
|
#define _LVM_LVMLOCKD_INTERNAL_H
|
||||||
|
|
||||||
#include "base/memory/container_of.h"
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#define MAX_NAME 64
|
#define MAX_NAME 64
|
||||||
#define MAX_ARGS 64
|
#define MAX_ARGS 64
|
||||||
|
|
||||||
@@ -23,7 +18,6 @@
|
|||||||
#define R_NAME_GL "GLLK"
|
#define R_NAME_GL "GLLK"
|
||||||
#define R_NAME_VG "VGLK"
|
#define R_NAME_VG "VGLK"
|
||||||
#define S_NAME_GL_DLM "lvm_global"
|
#define S_NAME_GL_DLM "lvm_global"
|
||||||
#define S_NAME_GL_IDM "lvm_global"
|
|
||||||
#define LVM_LS_PREFIX "lvm_" /* ls name is prefix + vg_name */
|
#define LVM_LS_PREFIX "lvm_" /* ls name is prefix + vg_name */
|
||||||
/* global lockspace name for sanlock is a vg name */
|
/* global lockspace name for sanlock is a vg name */
|
||||||
|
|
||||||
@@ -33,7 +27,6 @@ enum {
|
|||||||
LD_LM_UNUSED = 1, /* place holder so values match lib/locking/lvmlockd.h */
|
LD_LM_UNUSED = 1, /* place holder so values match lib/locking/lvmlockd.h */
|
||||||
LD_LM_DLM = 2,
|
LD_LM_DLM = 2,
|
||||||
LD_LM_SANLOCK = 3,
|
LD_LM_SANLOCK = 3,
|
||||||
LD_LM_IDM = 4,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* operation types */
|
/* operation types */
|
||||||
@@ -60,13 +53,6 @@ enum {
|
|||||||
LD_OP_KILL_VG,
|
LD_OP_KILL_VG,
|
||||||
LD_OP_DROP_VG,
|
LD_OP_DROP_VG,
|
||||||
LD_OP_BUSY,
|
LD_OP_BUSY,
|
||||||
LD_OP_QUERY_LOCK,
|
|
||||||
LD_OP_REFRESH_LV,
|
|
||||||
LD_OP_VG_STATUS,
|
|
||||||
LD_OP_FENCE,
|
|
||||||
LD_OP_FENCE_RESULT,
|
|
||||||
LD_OP_SETLOCKARGS_BEFORE,
|
|
||||||
LD_OP_SETLOCKARGS_FINAL,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* resource types */
|
/* resource types */
|
||||||
@@ -115,16 +101,10 @@ 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_ADOPT_ONLY 0x00200000 /* adopt orphan or fail */
|
|
||||||
#define LD_AF_NODELAY 0x00400000
|
|
||||||
#define LD_AF_REPAIR 0x00800000
|
|
||||||
#define LD_AF_NO_TIMEOUT 0x01000000
|
|
||||||
#define LD_AF_HOSTS_UNKNOWN 0x02000000
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of times to repeat a lock request after
|
* Number of times to repeat a lock request after
|
||||||
@@ -133,59 +113,12 @@ struct client {
|
|||||||
*/
|
*/
|
||||||
#define DEFAULT_MAX_RETRIES 4
|
#define DEFAULT_MAX_RETRIES 4
|
||||||
|
|
||||||
struct pvs {
|
|
||||||
char **path;
|
|
||||||
int num;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define RUN_COMMAND_LEN 1024
|
|
||||||
#define MAX_AV_COUNT 32
|
|
||||||
#define ONE_ARG_LEN 256
|
|
||||||
|
|
||||||
/* helper_msg types */
|
|
||||||
#define HELPER_COMMAND 0x1
|
|
||||||
#define HELPER_COMMAND_RESULT 0x2
|
|
||||||
|
|
||||||
struct helper_msg {
|
|
||||||
uint8_t type;
|
|
||||||
uint8_t act;
|
|
||||||
uint16_t unused1;
|
|
||||||
uint32_t msg_id;
|
|
||||||
int pid;
|
|
||||||
int result;
|
|
||||||
char ls_name[MAX_NAME+1];
|
|
||||||
uint8_t unused2;
|
|
||||||
uint16_t unused3;
|
|
||||||
char command[RUN_COMMAND_LEN];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct helper_msg_list {
|
|
||||||
struct helper_msg msg;
|
|
||||||
struct list_head list;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define OWNER_NAME_SIZE 64
|
|
||||||
#define OWNER_STATE_SIZE 32
|
|
||||||
|
|
||||||
struct owner {
|
|
||||||
uint32_t host_id;
|
|
||||||
uint32_t generation;
|
|
||||||
uint32_t timestamp;
|
|
||||||
char state[OWNER_STATE_SIZE];
|
|
||||||
char name[OWNER_NAME_SIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct action {
|
struct action {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
uint32_t client_id;
|
uint32_t client_id;
|
||||||
uint32_t flags; /* LD_AF_ */
|
uint32_t flags; /* LD_AF_ */
|
||||||
uint32_t msg_id;
|
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t host_id;
|
uint64_t host_id;
|
||||||
uint64_t ourkey;
|
|
||||||
uint64_t remkey;
|
|
||||||
uint64_t lv_size_bytes;
|
|
||||||
uint64_t ls_generation;
|
|
||||||
int8_t op; /* operation type LD_OP_ */
|
int8_t op; /* operation type LD_OP_ */
|
||||||
int8_t rt; /* resource type LD_RT_ */
|
int8_t rt; /* resource type LD_RT_ */
|
||||||
int8_t mode; /* lock mode LD_LK_ */
|
int8_t mode; /* lock mode LD_LK_ */
|
||||||
@@ -194,17 +127,13 @@ struct action {
|
|||||||
int max_retries;
|
int max_retries;
|
||||||
int result;
|
int result;
|
||||||
int lm_rv; /* return value from lm_ function */
|
int lm_rv; /* return value from lm_ function */
|
||||||
int align_mb;
|
|
||||||
char *path;
|
|
||||||
char vg_uuid[64];
|
char vg_uuid[64];
|
||||||
char vg_name[MAX_NAME+1];
|
char vg_name[MAX_NAME+1];
|
||||||
char lv_name[MAX_NAME+1];
|
char lv_name[MAX_NAME+1];
|
||||||
char lv_uuid[MAX_NAME+1];
|
char lv_uuid[MAX_NAME+1];
|
||||||
char vg_args[MAX_ARGS+1];
|
char vg_args[MAX_ARGS+1];
|
||||||
char lv_args[MAX_ARGS+1];
|
char lv_args[MAX_ARGS+1];
|
||||||
char other_args[MAX_ARGS+1];
|
char vg_sysid[MAX_NAME+1];
|
||||||
struct owner owner;
|
|
||||||
struct pvs pvs; /* PV list for idm */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct resource {
|
struct resource {
|
||||||
@@ -212,20 +141,17 @@ struct resource {
|
|||||||
char name[MAX_NAME+1]; /* vg name or lv name */
|
char name[MAX_NAME+1]; /* vg name or lv name */
|
||||||
int8_t type; /* resource type LD_RT_ */
|
int8_t type; /* resource type LD_RT_ */
|
||||||
int8_t mode;
|
int8_t mode;
|
||||||
int8_t adopt_mode;
|
|
||||||
unsigned int sh_count; /* number of sh locks on locks list */
|
unsigned int sh_count; /* number of sh locks on locks list */
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t last_client_id; /* last client_id to lock or unlock resource */
|
uint32_t last_client_id; /* last client_id to lock or unlock resource */
|
||||||
uint32_t dispose_client_id; /* client_id disposing of resource struct */
|
|
||||||
unsigned int lm_init : 1; /* lm_data is initialized */
|
unsigned int lm_init : 1; /* lm_data is initialized */
|
||||||
unsigned int adopt : 1; /* temp flag in remove_inactive_lvs */
|
unsigned int adopt : 1; /* temp flag in remove_inactive_lvs */
|
||||||
unsigned int version_zero_valid : 1;
|
unsigned int version_zero_valid : 1;
|
||||||
unsigned int use_vb : 1;
|
unsigned int use_vb : 1;
|
||||||
struct list_head locks;
|
struct list_head locks;
|
||||||
struct list_head actions;
|
struct list_head actions;
|
||||||
struct list_head fence_wait_actions;
|
|
||||||
char lv_args[MAX_ARGS+1];
|
char lv_args[MAX_ARGS+1];
|
||||||
char lm_data[]; /* lock manager specific data */
|
char lm_data[0]; /* lock manager specific data */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LD_LF_PERSISTENT 0x00000001
|
#define LD_LF_PERSISTENT 0x00000001
|
||||||
@@ -244,13 +170,11 @@ struct lockspace {
|
|||||||
char vg_name[MAX_NAME+1];
|
char vg_name[MAX_NAME+1];
|
||||||
char vg_uuid[64];
|
char vg_uuid[64];
|
||||||
char vg_args[MAX_ARGS+1]; /* lock manager specific args */
|
char vg_args[MAX_ARGS+1]; /* lock manager specific args */
|
||||||
|
char vg_sysid[MAX_NAME+1];
|
||||||
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
|
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
|
||||||
void *lm_data;
|
void *lm_data;
|
||||||
uint32_t lock_args_flags;
|
uint64_t host_id;
|
||||||
uint32_t host_id;
|
uint64_t free_lock_offset; /* start search for free lock here */
|
||||||
uint64_t generation;
|
|
||||||
uint64_t free_lock_offset; /* for sanlock, start search for free lock here */
|
|
||||||
struct pvs pvs; /* for idm: PV list */
|
|
||||||
|
|
||||||
uint32_t start_client_id; /* client_id that started the lockspace */
|
uint32_t start_client_id; /* client_id that started the lockspace */
|
||||||
pthread_t thread; /* makes synchronous lock requests */
|
pthread_t thread; /* makes synchronous lock requests */
|
||||||
@@ -263,14 +187,12 @@ struct lockspace {
|
|||||||
unsigned int thread_done : 1;
|
unsigned int thread_done : 1;
|
||||||
unsigned int sanlock_gl_enabled: 1;
|
unsigned int sanlock_gl_enabled: 1;
|
||||||
unsigned int sanlock_gl_dup: 1;
|
unsigned int sanlock_gl_dup: 1;
|
||||||
|
unsigned int free_vg: 1;
|
||||||
unsigned int kill_vg: 1;
|
unsigned int kill_vg: 1;
|
||||||
unsigned int fence_pr: 1;
|
unsigned int drop_vg: 1;
|
||||||
unsigned int no_timeout: 1;
|
|
||||||
|
|
||||||
struct list_head actions; /* new client actions */
|
struct list_head actions; /* new client actions */
|
||||||
struct list_head resources; /* resource/lock state for gl/vg/lv */
|
struct list_head resources; /* resource/lock state for gl/vg/lv */
|
||||||
struct list_head dispose; /* resources to free */
|
|
||||||
struct list_head fence_history; /* internally created actions for fencing */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* val_blk version */
|
/* val_blk version */
|
||||||
@@ -288,6 +210,10 @@ struct val_blk {
|
|||||||
/* lm_unlock flags */
|
/* lm_unlock flags */
|
||||||
#define LMUF_FREE_VG 0x00000001
|
#define LMUF_FREE_VG 0x00000001
|
||||||
|
|
||||||
|
#define container_of(ptr, type, member) ({ \
|
||||||
|
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||||
|
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||||
|
|
||||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||||
{
|
{
|
||||||
list->next = list;
|
list->next = list;
|
||||||
@@ -337,15 +263,15 @@ static inline int list_empty(const struct list_head *head)
|
|||||||
list_entry((ptr)->next, type, member)
|
list_entry((ptr)->next, type, member)
|
||||||
|
|
||||||
#define list_for_each_entry(pos, head, member) \
|
#define list_for_each_entry(pos, head, member) \
|
||||||
for (pos = list_entry((head)->next, __typeof__(*pos), member); \
|
for (pos = list_entry((head)->next, typeof(*pos), member); \
|
||||||
&pos->member != (head); \
|
&pos->member != (head); \
|
||||||
pos = list_entry(pos->member.next, __typeof__(*pos), member))
|
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||||
|
|
||||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||||
for (pos = list_entry((head)->next, __typeof__(*pos), member), \
|
for (pos = list_entry((head)->next, typeof(*pos), member), \
|
||||||
n = list_entry(pos->member.next, __typeof__(*pos), member); \
|
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||||
&pos->member != (head); \
|
&pos->member != (head); \
|
||||||
pos = n, n = list_entry(n->member.next, __typeof__(*n), member))
|
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||||
|
|
||||||
|
|
||||||
/* to improve readability */
|
/* to improve readability */
|
||||||
@@ -394,13 +320,10 @@ static inline int list_empty(const struct list_head *head)
|
|||||||
EXTERN int gl_type_static;
|
EXTERN int gl_type_static;
|
||||||
EXTERN int gl_use_dlm;
|
EXTERN int gl_use_dlm;
|
||||||
EXTERN int gl_use_sanlock;
|
EXTERN int gl_use_sanlock;
|
||||||
EXTERN int gl_use_idm;
|
|
||||||
EXTERN int gl_vg_removed;
|
EXTERN int gl_vg_removed;
|
||||||
EXTERN char gl_lsname_dlm[MAX_NAME+1];
|
EXTERN char gl_lsname_dlm[MAX_NAME+1];
|
||||||
EXTERN char gl_lsname_sanlock[MAX_NAME+1];
|
EXTERN char gl_lsname_sanlock[MAX_NAME+1];
|
||||||
EXTERN char gl_lsname_idm[MAX_NAME+1];
|
|
||||||
EXTERN int global_dlm_lockspace_exists;
|
EXTERN int global_dlm_lockspace_exists;
|
||||||
EXTERN int global_idm_lockspace_exists;
|
|
||||||
|
|
||||||
EXTERN int daemon_test; /* run as much as possible without a live lock manager */
|
EXTERN int daemon_test; /* run as much as possible without a live lock manager */
|
||||||
EXTERN int daemon_debug;
|
EXTERN int daemon_debug;
|
||||||
@@ -423,15 +346,11 @@ 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);
|
||||||
int last_string_from_args(char *args_in, char *last);
|
int last_string_from_args(char *args_in, char *last);
|
||||||
void helper_main(int in_fd, int out_fd, int log_stderr);
|
int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsigned int *patch);
|
||||||
int lockd_lockargs_get_user_flags(const char *str, uint32_t *flags);
|
|
||||||
int lockd_lockargs_get_version(char *str, unsigned int *major, unsigned int *minor, unsigned int *patch);
|
|
||||||
|
|
||||||
static inline const char *mode_str(int x)
|
static inline const char *mode_str(int x)
|
||||||
{
|
{
|
||||||
@@ -455,12 +374,10 @@ static inline const char *mode_str(int x)
|
|||||||
|
|
||||||
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||||
int lm_prepare_lockspace_dlm(struct lockspace *ls);
|
int lm_prepare_lockspace_dlm(struct lockspace *ls);
|
||||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok);
|
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
|
||||||
int lm_purge_locks_dlm(struct lockspace *ls);
|
|
||||||
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
|
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
|
||||||
int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl);
|
|
||||||
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int adopt_only, int adopt_ok);
|
struct val_blk *vb_out, int adopt);
|
||||||
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||||
int ld_mode, uint32_t r_version);
|
int ld_mode, uint32_t r_version);
|
||||||
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||||
@@ -470,8 +387,6 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin);
|
|||||||
int lm_data_size_dlm(void);
|
int lm_data_size_dlm(void);
|
||||||
int lm_is_running_dlm(void);
|
int lm_is_running_dlm(void);
|
||||||
int lm_hosts_dlm(struct lockspace *ls, int notify);
|
int lm_hosts_dlm(struct lockspace *ls, int notify);
|
||||||
int lm_refresh_lv_start_dlm(struct action *act);
|
|
||||||
int lm_refresh_lv_check_dlm(struct action *act);
|
|
||||||
|
|
||||||
static inline int lm_support_dlm(void)
|
static inline int lm_support_dlm(void)
|
||||||
{
|
{
|
||||||
@@ -482,102 +397,64 @@ static inline int lm_support_dlm(void)
|
|||||||
|
|
||||||
static inline int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
static inline int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
static inline int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok)
|
static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_purge_locks_dlm(struct lockspace *ls)
|
|
||||||
{
|
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
|
static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl)
|
|
||||||
{
|
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
static inline int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int adopt_only, int adopt_ok)
|
struct val_blk *vb_out, int adopt)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
static inline int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||||
int ld_mode, uint32_t r_version)
|
int ld_mode, uint32_t r_version)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
static inline int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||||
uint32_t r_version, uint32_t lmu_flags)
|
uint32_t r_version, uint32_t lmu_flags)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
|
static inline int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
static inline int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_data_size_dlm(void)
|
static inline int lm_data_size_dlm(void)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_is_running_dlm(void)
|
static inline int lm_is_running_dlm(void)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_support_dlm(void)
|
static inline int lm_support_dlm(void)
|
||||||
{
|
{
|
||||||
if (daemon_test)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,48 +463,32 @@ static inline int lm_hosts_dlm(struct lockspace *ls, int notify)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_refresh_lv_start_dlm(struct action *act)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_refresh_lv_check_dlm(struct action *act)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* dlm support */
|
#endif /* dlm support */
|
||||||
|
|
||||||
#ifdef LOCKDSANLOCK_SUPPORT
|
#ifdef LOCKDSANLOCK_SUPPORT
|
||||||
|
|
||||||
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb, char *other_args);
|
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||||
int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args);
|
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset);
|
||||||
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
|
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
|
||||||
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||||
int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation, int repair);
|
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
|
||||||
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok, int nodelay);
|
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt);
|
||||||
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
|
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
|
||||||
int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r);
|
|
||||||
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int *retry, struct owner *owner,
|
struct val_blk *vb_out, int *retry, int adopt);
|
||||||
int adopt_only, int adopt_ok, int repair);
|
|
||||||
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
||||||
int ld_mode, uint32_t r_version);
|
int ld_mode, uint32_t r_version);
|
||||||
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||||
uint32_t r_version, uint32_t lmu_flags);
|
uint32_t r_version, uint32_t lmu_flags);
|
||||||
int lm_able_gl_sanlock(struct lockspace *ls, int enable);
|
int lm_able_gl_sanlock(struct lockspace *ls, int enable);
|
||||||
int lm_ex_disable_gl_sanlock(struct lockspace *ls);
|
int lm_ex_disable_gl_sanlock(struct lockspace *ls);
|
||||||
int lm_hosts_sanlock(struct lockspace *ls, int notify, int *hosts_unknown);
|
int lm_hosts_sanlock(struct lockspace *ls, int notify);
|
||||||
int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r);
|
int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r);
|
||||||
int lm_gl_is_enabled(struct lockspace *ls);
|
int lm_gl_is_enabled(struct lockspace *ls);
|
||||||
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
|
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
|
||||||
int lm_data_size_sanlock(void);
|
int lm_data_size_sanlock(void);
|
||||||
int lm_is_running_sanlock(void);
|
int lm_is_running_sanlock(void);
|
||||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes);
|
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset);
|
||||||
int lm_vg_status_sanlock(struct lockspace *ls, struct action *act);
|
|
||||||
void lm_set_host_dead_sanlock(struct lockspace *ls, struct owner *owner);
|
|
||||||
int lm_setlockargs_supported_sanlock(struct lockspace *ls, struct action *act);
|
|
||||||
int lm_setlockargs_vg_sanlock(char *ls_name, char *vg_name, struct action *act);
|
|
||||||
|
|
||||||
static inline int lm_support_sanlock(void)
|
static inline int lm_support_sanlock(void)
|
||||||
{
|
{
|
||||||
@@ -636,12 +497,12 @@ static inline int lm_support_sanlock(void)
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb, char *other_args)
|
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args)
|
static inline int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -656,12 +517,12 @@ static inline int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t fl
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation, int repair)
|
static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok, int nodelay)
|
static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -671,14 +532,8 @@ static inline int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
struct val_blk *vb_out, int *retry, struct owner *owner,
|
struct val_blk *vb_out, int *retry, int adopt)
|
||||||
int adopt_only, int adopt_ok, int repair)
|
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -705,7 +560,7 @@ static inline int lm_ex_disable_gl_sanlock(struct lockspace *ls)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_hosts_sanlock(struct lockspace *ls, int notify, int *hosts_unknown)
|
static inline int lm_hosts_sanlock(struct lockspace *ls, int notify)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -735,12 +590,7 @@ static inline int lm_is_running_sanlock(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes)
|
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_vg_status_sanlock(struct lockspace *ls, struct action *act)
|
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -750,124 +600,6 @@ static inline int lm_support_sanlock(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void lm_set_host_dead_sanlock(struct lockspace *ls, struct owner *owner)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_setlockargs_supported_sanlock(struct lockspace *ls, struct action *act)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_setlockargs_vg_sanlock(char *ls_name, char *vg_name, struct action *act)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* sanlock support */
|
#endif /* sanlock support */
|
||||||
|
|
||||||
#ifdef LOCKDIDM_SUPPORT
|
|
||||||
|
|
||||||
int lm_data_size_idm(void);
|
|
||||||
int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
|
||||||
int lm_prepare_lockspace_idm(struct lockspace *ls);
|
|
||||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok);
|
|
||||||
int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg);
|
|
||||||
int lm_add_resource_idm(struct lockspace *ls, struct resource *r);
|
|
||||||
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|
||||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
|
||||||
int adopt_only, int adopt_ok);
|
|
||||||
int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
int ld_mode, uint32_t r_version);
|
|
||||||
int lm_unlock_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
uint32_t r_version, uint32_t lmu_flags);
|
|
||||||
int lm_hosts_idm(struct lockspace *ls, int notify);
|
|
||||||
int lm_get_lockspaces_idm(struct list_head *ls_rejoin);
|
|
||||||
int lm_is_running_idm(void);
|
|
||||||
int lm_rem_resource_idm(struct lockspace *ls, struct resource *r);
|
|
||||||
|
|
||||||
static inline int lm_support_idm(void)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static inline int lm_data_size_idm(void)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags,
|
|
||||||
char *vg_args)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_prepare_lockspace_idm(struct lockspace *ls)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_add_resource_idm(struct lockspace *ls, struct resource *r)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|
||||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
|
||||||
int adopt_only, int adopt_ok)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
int ld_mode, uint32_t r_version)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_unlock_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
uint32_t r_version, uint32_t lmu_flags)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_hosts_idm(struct lockspace *ls, int notify)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_get_lockspaces_idm(struct list_head *ls_rejoin)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_is_running_idm(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_rem_resource_idm(struct lockspace *ls, struct resource *r)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_support_idm(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* Seagate IDM support */
|
|
||||||
|
|
||||||
#endif /* _LVM_LVMLOCKD_INTERNAL_H */
|
#endif /* _LVM_LVMLOCKD_INTERNAL_H */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -19,25 +19,25 @@ SOURCES = lvmpolld-core.c lvmpolld-data-utils.c lvmpolld-cmd-utils.c
|
|||||||
|
|
||||||
TARGETS = lvmpolld
|
TARGETS = lvmpolld
|
||||||
|
|
||||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
|
||||||
CFLOW_TARGET := $(TARGETS)
|
|
||||||
|
|
||||||
.PHONY: install_lvmpolld
|
.PHONY: install_lvmpolld
|
||||||
|
|
||||||
|
CFLOW_LIST = $(SOURCES)
|
||||||
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
CFLOW_TARGET = lvmpolld
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
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 += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||||
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
LIBS += $(DAEMON_LIBS) -ldaemonserver $(PTHREAD_LIBS)
|
||||||
|
|
||||||
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
|
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||||
$(SHOW) " [CC] $@"
|
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(INTERNAL_LIBS) $(LIBS)
|
||||||
|
|
||||||
install_lvmpolld: lvmpolld
|
install_lvmpolld: lvmpolld
|
||||||
$(SHOW) " [INSTALL] $<"
|
$(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 */
|
||||||
@@ -92,12 +92,6 @@ const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary,
|
|||||||
if (!add_to_cmd_arr(&cmd_argv, "-An", &i))
|
if (!add_to_cmd_arr(&cmd_argv, "-An", &i))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (pdlv->devicesfile) {
|
|
||||||
if (!add_to_cmd_arr(&cmd_argv, "--devicesfile", &i) ||
|
|
||||||
!add_to_cmd_arr(&cmd_argv, pdlv->devicesfile, &i))
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* terminating NULL */
|
/* terminating NULL */
|
||||||
if (!add_to_cmd_arr(&cmd_argv, NULL, &i))
|
if (!add_to_cmd_arr(&cmd_argv, NULL, &i))
|
||||||
goto err;
|
goto err;
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#ifndef _LVM_LVMPOLLD_COMMON_H
|
#ifndef _LVM_LVMPOLLD_COMMON_H
|
||||||
#define _LVM_LVMPOLLD_COMMON_H
|
#define _LVM_LVMPOLLD_COMMON_H
|
||||||
|
|
||||||
|
#define _REENTRANT
|
||||||
|
|
||||||
#include "tools/tool.h"
|
#include "tools/tool.h"
|
||||||
|
|
||||||
#include "lvmpolld-cmd-utils.h"
|
#include "lvmpolld-cmd-utils.h"
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
#include "lvmpolld-common.h"
|
#include "lvmpolld-common.h"
|
||||||
|
|
||||||
#include "lvm-version.h"
|
#include "lvm-version.h"
|
||||||
#include "libdaemon/server/daemon-server.h"
|
#include "daemon-server.h"
|
||||||
#include "libdaemon/server/daemon-log.h"
|
#include "daemon-log.h"
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
@@ -52,7 +52,7 @@ static pthread_key_t key;
|
|||||||
|
|
||||||
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
|
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
|
||||||
{
|
{
|
||||||
#if defined(_GNU_SOURCE) && defined(STRERROR_R_CHAR_P)
|
#ifdef _GNU_SOURCE
|
||||||
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
|
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
|
||||||
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
|
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
|
||||||
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
|
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
|
||||||
@@ -75,7 +75,7 @@ static void _usage(const char *prog, FILE *file)
|
|||||||
" -p|--pidfile Set path to the pidfile\n"
|
" -p|--pidfile Set path to the pidfile\n"
|
||||||
" -s|--socket Set path to the communication socket\n"
|
" -s|--socket Set path to the communication socket\n"
|
||||||
" -B|--binary Path to lvm2 binary\n"
|
" -B|--binary Path to lvm2 binary\n"
|
||||||
" -t|--timeout Time to wait in seconds before shutdown on idle (missing or 0 = infinite)\n\n", prog, prog);
|
" -t|--timeout Time to wait in seconds before shutdown on idle (missing or 0 = inifinite)\n\n", prog, prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _init(struct daemon_state *s)
|
static int _init(struct daemon_state *s)
|
||||||
@@ -149,7 +149,7 @@ static void _lvmpolld_global_unlock(struct lvmpolld_state *ls)
|
|||||||
static int _fini(struct daemon_state *s)
|
static int _fini(struct daemon_state *s)
|
||||||
{
|
{
|
||||||
int done;
|
int done;
|
||||||
const struct timespec t = { .tv_nsec = 10000000 }; /* .01 sec */
|
const struct timespec t = { .tv_nsec = 250000000 }; /* .25 sec */
|
||||||
struct lvmpolld_state *ls = s->private;
|
struct lvmpolld_state *ls = s->private;
|
||||||
|
|
||||||
DEBUGLOG(s, "fini");
|
DEBUGLOG(s, "fini");
|
||||||
@@ -236,7 +236,9 @@ static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
do {
|
||||||
r = poll(fds, 2, pdlv_get_timeout(pdlv) * 1000);
|
r = poll(fds, 2, pdlv_get_timeout(pdlv) * 1000);
|
||||||
|
} while (r < 0 && errno == EINTR);
|
||||||
|
|
||||||
DEBUGLOG(pdlv->ls, "%s: %s %d", PD_LOG_PREFIX, "poll() returned", r);
|
DEBUGLOG(pdlv->ls, "%s: %s %d", PD_LOG_PREFIX, "poll() returned", r);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@@ -372,7 +374,7 @@ static void debug_print(struct lvmpolld_state *ls, const char * const* ptr)
|
|||||||
|
|
||||||
static void *fork_and_poll(void *args)
|
static void *fork_and_poll(void *args)
|
||||||
{
|
{
|
||||||
int outfd, errfd, state = 0;
|
int outfd, errfd, state;
|
||||||
struct lvmpolld_thread_data *data;
|
struct lvmpolld_thread_data *data;
|
||||||
pid_t r;
|
pid_t r;
|
||||||
|
|
||||||
@@ -390,11 +392,6 @@ static void *fork_and_poll(void *args)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pdlv->cmdargv || !*(pdlv->cmdargv)) {
|
|
||||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "Missing command");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd line arguments:");
|
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd line arguments:");
|
||||||
debug_print(ls, pdlv->cmdargv);
|
debug_print(ls, pdlv->cmdargv);
|
||||||
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
|
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
|
||||||
@@ -558,15 +555,14 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
|
|||||||
const char *interval, const char *id,
|
const char *interval, const char *id,
|
||||||
const char *vgname, const char *lvname,
|
const char *vgname, const char *lvname,
|
||||||
const char *sysdir, enum poll_type type,
|
const char *sysdir, enum poll_type type,
|
||||||
unsigned abort_polling, unsigned uinterval,
|
unsigned abort_polling, unsigned uinterval)
|
||||||
const char *devicesfile)
|
|
||||||
{
|
{
|
||||||
const char **cmdargv, **cmdenvp;
|
const char **cmdargv, **cmdenvp;
|
||||||
struct lvmpolld_lv *pdlv;
|
struct lvmpolld_lv *pdlv;
|
||||||
unsigned handle_missing_pvs = daemon_request_int(req, LVMPD_PARM_HANDLE_MISSING_PVS, 0);
|
unsigned handle_missing_pvs = daemon_request_int(req, LVMPD_PARM_HANDLE_MISSING_PVS, 0);
|
||||||
|
|
||||||
pdlv = pdlv_create(ls, id, vgname, lvname, sysdir, type,
|
pdlv = pdlv_create(ls, id, vgname, lvname, sysdir, type,
|
||||||
interval, uinterval, pdst, devicesfile);
|
interval, uinterval, pdst);
|
||||||
|
|
||||||
if (!pdlv) {
|
if (!pdlv) {
|
||||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to create internal LV data structure.");
|
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to create internal LV data structure.");
|
||||||
@@ -625,7 +621,6 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
|||||||
const char *lvname = daemon_request_str(req, LVMPD_PARM_LVNAME, NULL);
|
const char *lvname = daemon_request_str(req, LVMPD_PARM_LVNAME, NULL);
|
||||||
const char *vgname = daemon_request_str(req, LVMPD_PARM_VGNAME, NULL);
|
const char *vgname = daemon_request_str(req, LVMPD_PARM_VGNAME, NULL);
|
||||||
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
|
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
|
||||||
const char *devicesfile = daemon_request_str(req, LVMPD_PARM_DEVICESFILE, NULL);
|
|
||||||
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
|
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
|
||||||
|
|
||||||
assert(type < POLL_TYPE_MAX);
|
assert(type < POLL_TYPE_MAX);
|
||||||
@@ -685,7 +680,7 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
|||||||
pdlv->init_rq_count++; /* safe. protected by store lock */
|
pdlv->init_rq_count++; /* safe. protected by store lock */
|
||||||
} else {
|
} else {
|
||||||
pdlv = construct_pdlv(req, ls, pdst, interval, id, vgname,
|
pdlv = construct_pdlv(req, ls, pdst, interval, id, vgname,
|
||||||
lvname, sysdir, type, abort_polling, 2 * uinterval, devicesfile);
|
lvname, sysdir, type, abort_polling, 2 * uinterval);
|
||||||
if (!pdlv) {
|
if (!pdlv) {
|
||||||
pdst_unlock(pdst);
|
pdst_unlock(pdst);
|
||||||
free(id);
|
free(id);
|
||||||
@@ -786,7 +781,7 @@ struct log_line_baton {
|
|||||||
const char *prefix;
|
const char *prefix;
|
||||||
};
|
};
|
||||||
|
|
||||||
static daemon_handle _lvmpolld = { .error = 0 };
|
daemon_handle _lvmpolld = { .error = 0 };
|
||||||
|
|
||||||
static daemon_handle _lvmpolld_open(const char *socket)
|
static daemon_handle _lvmpolld_open(const char *socket)
|
||||||
{
|
{
|
||||||
@@ -872,14 +867,14 @@ enum action_index {
|
|||||||
ACTION_MAX /* keep at the end */
|
ACTION_MAX /* keep at the end */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const action_fn_t actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump };
|
||||||
|
|
||||||
static int _make_action(enum action_index idx, void *args)
|
static int _make_action(enum action_index idx, void *args)
|
||||||
{
|
{
|
||||||
static const action_fn_t _actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump };
|
return idx < ACTION_MAX ? actions[idx](args) : 0;
|
||||||
|
|
||||||
return idx < ACTION_MAX ? _actions[idx](args) : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _lvmpolld_client(const char *socket, enum action_index action)
|
static int _lvmpolld_client(const char *socket, unsigned action)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@@ -897,9 +892,10 @@ static int _lvmpolld_client(const char *socket, enum action_index action)
|
|||||||
return r ? EXIT_SUCCESS : EXIT_FAILURE;
|
return r ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct option _long_options[] = {
|
static int action_idx = ACTION_MAX;
|
||||||
|
static struct option long_options[] = {
|
||||||
/* Have actions always at the beginning of the array. */
|
/* Have actions always at the beginning of the array. */
|
||||||
{"dump", no_argument, 0, ACTION_DUMP }, /* or an option_index ? */
|
{"dump", no_argument, &action_idx, ACTION_DUMP }, /* or an option_index ? */
|
||||||
|
|
||||||
/* other options */
|
/* other options */
|
||||||
{"binary", required_argument, 0, 'B' },
|
{"binary", required_argument, 0, 'B' },
|
||||||
@@ -918,8 +914,8 @@ 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 timeval timeout;
|
||||||
daemon_idle di = { .ptimeout = &timeout };
|
daemon_idle di = { .ptimeout = &timeout };
|
||||||
struct lvmpolld_state ls = { .log_config = "" };
|
struct lvmpolld_state ls = { .log_config = "" };
|
||||||
daemon_state s = {
|
daemon_state s = {
|
||||||
@@ -934,16 +930,16 @@ int main(int argc, char *argv[])
|
|||||||
.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
|
.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
|
||||||
};
|
};
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, "fhVl:p:s:B:t:", _long_options, &option_index)) != -1) {
|
while ((opt = getopt_long(argc, argv, "fhVl:p:s:B:t:", long_options, &option_index)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 0 :
|
case 0 :
|
||||||
if (action != ACTION_MAX) {
|
if (action < ACTION_MAX) {
|
||||||
fprintf(stderr, "Can't perform more actions. Action already requested: %s\n",
|
fprintf(stderr, "Can't perform more actions. Action already requested: %s\n",
|
||||||
_long_options[action].name);
|
long_options[action].name);
|
||||||
_usage(argv[0], stderr);
|
_usage(argv[0], stderr);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
action = ACTION_DUMP;
|
action = action_idx;
|
||||||
client = 1;
|
client = 1;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ static char *_construct_lvm_system_dir_env(const char *sysdir)
|
|||||||
* - or -
|
* - or -
|
||||||
* just single char to store NULL byte
|
* just single char to store NULL byte
|
||||||
*/
|
*/
|
||||||
size_t l = sysdir ? strlen(sysdir) + sizeof(LVM_SYSTEM_DIR): 1;
|
size_t l = sysdir ? strlen(sysdir) + 16 : 1;
|
||||||
char *env = (char *) malloc(l * sizeof(char));
|
char *env = (char *) malloc(l * sizeof(char));
|
||||||
|
|
||||||
if (!env)
|
if (!env)
|
||||||
@@ -89,44 +89,34 @@ char *construct_id(const char *sysdir, const char *uuid)
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _free_lvmpolld_lv(struct lvmpolld_lv *p)
|
|
||||||
{
|
|
||||||
free((void *)p->devicesfile);
|
|
||||||
free((void *)p->lvm_system_dir_env);
|
|
||||||
free((void *)p->lvmpolld_id);
|
|
||||||
free((void *)p->lvname);
|
|
||||||
free((void *)p->sinterval);
|
|
||||||
free((void *)p->cmdargv);
|
|
||||||
free((void *)p->cmdenvp);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||||
const char *vgname, const char *lvname,
|
const char *vgname, const char *lvname,
|
||||||
const char *sysdir, enum poll_type type,
|
const char *sysdir, enum poll_type type,
|
||||||
const char *sinterval, unsigned pdtimeout,
|
const char *sinterval, unsigned pdtimeout,
|
||||||
struct lvmpolld_store *pdst,
|
struct lvmpolld_store *pdst)
|
||||||
const char *devicesfile)
|
|
||||||
{
|
{
|
||||||
|
char *lvmpolld_id = strdup(id), /* copy */
|
||||||
|
*full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
|
||||||
|
*lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
|
||||||
|
|
||||||
struct lvmpolld_lv tmp = {
|
struct lvmpolld_lv tmp = {
|
||||||
.ls = ls,
|
.ls = ls,
|
||||||
.type = type,
|
.type = type,
|
||||||
.lvmpolld_id = strdup(id),
|
.lvmpolld_id = lvmpolld_id,
|
||||||
.lvname = _construct_full_lvname(vgname, lvname),
|
.lvid = _get_lvid(lvmpolld_id, sysdir),
|
||||||
.devicesfile = devicesfile ? strdup(devicesfile) : NULL,
|
.lvname = full_lvname,
|
||||||
.lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir),
|
.lvm_system_dir_env = lvm_system_dir_env,
|
||||||
.sinterval = strdup(sinterval),
|
.sinterval = strdup(sinterval), /* copy */
|
||||||
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
|
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
|
||||||
.cmd_state = { .retcode = -1, .signal = 0 },
|
.cmd_state = { .retcode = -1, .signal = 0 },
|
||||||
.pdst = pdst,
|
.pdst = pdst,
|
||||||
.init_rq_count = 1
|
.init_rq_count = 1
|
||||||
}, *pdlv = (struct lvmpolld_lv *) malloc(sizeof(struct lvmpolld_lv));
|
}, *pdlv = (struct lvmpolld_lv *) malloc(sizeof(struct lvmpolld_lv));
|
||||||
|
|
||||||
if (!pdlv || !tmp.lvmpolld_id || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
|
if (!pdlv || !tmp.lvid || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
tmp.lvid = _get_lvid(tmp.lvmpolld_id, sysdir),
|
memcpy(pdlv, &tmp, sizeof(*pdlv));
|
||||||
|
|
||||||
*pdlv = tmp;
|
|
||||||
|
|
||||||
if (pthread_mutex_init(&pdlv->lock, NULL))
|
if (pthread_mutex_init(&pdlv->lock, NULL))
|
||||||
goto err;
|
goto err;
|
||||||
@@ -134,20 +124,27 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
|||||||
return pdlv;
|
return pdlv;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
_free_lvmpolld_lv(&tmp);
|
free((void *)full_lvname);
|
||||||
|
free((void *)lvmpolld_id);
|
||||||
free(pdlv);
|
free((void *)lvm_system_dir_env);
|
||||||
|
free((void *)tmp.sinterval);
|
||||||
|
free((void *)pdlv);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pdlv_destroy(struct lvmpolld_lv *pdlv)
|
void pdlv_destroy(struct lvmpolld_lv *pdlv)
|
||||||
{
|
{
|
||||||
_free_lvmpolld_lv(pdlv);
|
free((void *)pdlv->lvmpolld_id);
|
||||||
|
free((void *)pdlv->lvname);
|
||||||
|
free((void *)pdlv->sinterval);
|
||||||
|
free((void *)pdlv->lvm_system_dir_env);
|
||||||
|
free((void *)pdlv->cmdargv);
|
||||||
|
free((void *)pdlv->cmdenvp);
|
||||||
|
|
||||||
pthread_mutex_destroy(&pdlv->lock);
|
pthread_mutex_destroy(&pdlv->lock);
|
||||||
|
|
||||||
free(pdlv);
|
free((void *)pdlv);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)
|
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)
|
||||||
@@ -271,12 +268,12 @@ static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdl
|
|||||||
buffer_append(buff, tmp);
|
buffer_append(buff, tmp);
|
||||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\tpolling_finished=%d\n", pdlv->polling_finished) > 0)
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\tpolling_finished=%d\n", pdlv->polling_finished) > 0)
|
||||||
buffer_append(buff, tmp);
|
buffer_append(buff, tmp);
|
||||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\terror_occurred=%d\n", pdlv->error) > 0)
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\terror_occured=%d\n", pdlv->error) > 0)
|
||||||
buffer_append(buff, tmp);
|
buffer_append(buff, tmp);
|
||||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\tinit_requests_count=%d\n", pdlv->init_rq_count) > 0)
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\tinit_requests_count=%d\n", pdlv->init_rq_count) > 0)
|
||||||
buffer_append(buff, tmp);
|
buffer_append(buff, tmp);
|
||||||
|
|
||||||
/* lvm_command-section { */
|
/* lvm_commmand-section { */
|
||||||
buffer_append(buff, "\t\tlvm_command {\n");
|
buffer_append(buff, "\t\tlvm_command {\n");
|
||||||
if (cmd_state->retcode == -1 && !cmd_state->signal)
|
if (cmd_state->retcode == -1 && !cmd_state->signal)
|
||||||
buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_IN_PROGRESS "\"\n");
|
buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_IN_PROGRESS "\"\n");
|
||||||
@@ -288,7 +285,7 @@ static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdl
|
|||||||
buffer_append(buff, tmp);
|
buffer_append(buff, tmp);
|
||||||
}
|
}
|
||||||
buffer_append(buff, "\t\t}\n");
|
buffer_append(buff, "\t\t}\n");
|
||||||
/* } lvm_command-section */
|
/* } lvm_commmand-section */
|
||||||
|
|
||||||
buffer_append(buff, "\t}\n");
|
buffer_append(buff, "\t}\n");
|
||||||
/* } pdlv-section */
|
/* } pdlv-section */
|
||||||
|
|||||||
@@ -15,10 +15,7 @@
|
|||||||
#ifndef _LVM_LVMPOLLD_DATA_UTILS_H
|
#ifndef _LVM_LVMPOLLD_DATA_UTILS_H
|
||||||
#define _LVM_LVMPOLLD_DATA_UTILS_H
|
#define _LVM_LVMPOLLD_DATA_UTILS_H
|
||||||
|
|
||||||
#include "base/data-struct/hash.h"
|
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
struct buffer;
|
struct buffer;
|
||||||
struct lvmpolld_state;
|
struct lvmpolld_state;
|
||||||
@@ -48,18 +45,17 @@ 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 lvname; /* full vg/lv name */
|
||||||
const char *lvname; /* full vg/lv name */
|
const unsigned pdtimeout; /* in seconds */
|
||||||
unsigned pdtimeout; /* in seconds */
|
const char *const sinterval;
|
||||||
const char *sinterval;
|
const char *const lvm_system_dir_env;
|
||||||
const char *lvm_system_dir_env;
|
struct lvmpolld_store *const pdst;
|
||||||
struct lvmpolld_store *pdst;
|
const char *const *cmdargv;
|
||||||
const char **cmdargv;
|
const char *const *cmdenvp;
|
||||||
const char **cmdenvp;
|
|
||||||
|
|
||||||
/* only used by write */
|
/* only used by write */
|
||||||
pid_t cmd_pid;
|
pid_t cmd_pid;
|
||||||
@@ -69,9 +65,9 @@ struct lvmpolld_lv {
|
|||||||
|
|
||||||
/* block of shared variables protected by lock */
|
/* block of shared variables protected by lock */
|
||||||
struct lvmpolld_cmd_stat cmd_state;
|
struct lvmpolld_cmd_stat cmd_state;
|
||||||
unsigned init_rq_count; /* for debugging purposes only */
|
unsigned init_rq_count; /* for debuging purposes only */
|
||||||
unsigned polling_finished:1; /* no more updates */
|
unsigned polling_finished:1; /* no more updates */
|
||||||
unsigned error:1; /* unrecoverable error occurred in lvmpolld */
|
unsigned error:1; /* unrecoverable error occured in lvmpolld */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*lvmpolld_parse_output_fn_t) (struct lvmpolld_lv *pdlv, const char *line);
|
typedef void (*lvmpolld_parse_output_fn_t) (struct lvmpolld_lv *pdlv, const char *line);
|
||||||
@@ -96,7 +92,7 @@ struct lvmpolld_thread_data {
|
|||||||
struct lvmpolld_lv *pdlv;
|
struct lvmpolld_lv *pdlv;
|
||||||
};
|
};
|
||||||
|
|
||||||
char *construct_id(const char *sysdir, const char *uuid);
|
char *construct_id(const char *sysdir, const char *lvid);
|
||||||
|
|
||||||
/* LVMPOLLD_LV_T section */
|
/* LVMPOLLD_LV_T section */
|
||||||
|
|
||||||
@@ -105,8 +101,7 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
|||||||
const char *vgname, const char *lvname,
|
const char *vgname, const char *lvname,
|
||||||
const char *sysdir, enum poll_type type,
|
const char *sysdir, enum poll_type type,
|
||||||
const char *sinterval, unsigned pdtimeout,
|
const char *sinterval, unsigned pdtimeout,
|
||||||
struct lvmpolld_store *pdst,
|
struct lvmpolld_store *pdst);
|
||||||
const char *devicesfile);
|
|
||||||
|
|
||||||
/* only call with appropriate struct lvmpolld_store lock held */
|
/* only call with appropriate struct lvmpolld_store lock held */
|
||||||
void pdlv_destroy(struct lvmpolld_lv *pdlv);
|
void pdlv_destroy(struct lvmpolld_lv *pdlv);
|
||||||
|
|||||||
@@ -35,7 +35,6 @@
|
|||||||
#define LVMPD_PARM_SYSDIR "sysdir"
|
#define LVMPD_PARM_SYSDIR "sysdir"
|
||||||
#define LVMPD_PARM_VALUE "value" /* either retcode or signal value */
|
#define LVMPD_PARM_VALUE "value" /* either retcode or signal value */
|
||||||
#define LVMPD_PARM_VGNAME "vgname"
|
#define LVMPD_PARM_VGNAME "vgname"
|
||||||
#define LVMPD_PARM_DEVICESFILE "devicesfile"
|
|
||||||
|
|
||||||
#define LVMPD_RESP_FAILED "failed"
|
#define LVMPD_RESP_FAILED "failed"
|
||||||
#define LVMPD_RESP_FINISHED "finished"
|
#define LVMPD_RESP_FINISHED "finished"
|
||||||
@@ -45,7 +44,7 @@
|
|||||||
#define LVMPD_RESP_OK "OK"
|
#define LVMPD_RESP_OK "OK"
|
||||||
|
|
||||||
#define LVMPD_REAS_RETCODE "retcode" /* lvm cmd ret code */
|
#define LVMPD_REAS_RETCODE "retcode" /* lvm cmd ret code */
|
||||||
#define LVMPD_REAS_SIGNAL "signal" /* lvm cmd terminating signal */
|
#define LVMPD_REAS_SIGNAL "signal" /* lvm cmd terminating singal */
|
||||||
|
|
||||||
#define LVMPD_RET_DUP_FAILED 100
|
#define LVMPD_RET_DUP_FAILED 100
|
||||||
#define LVMPD_RET_EXC_FAILED 101
|
#define LVMPD_RET_EXC_FAILED 101
|
||||||
|
|||||||
@@ -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.
|
||||||
#
|
#
|
||||||
@@ -10,12 +10,8 @@
|
|||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
# NOTE: this Makefile only works as 'include' for toplevel Makefile
|
|
||||||
# which defined all top_* variables
|
|
||||||
|
|
||||||
DEVICE_MAPPER_SOURCE=\
|
DEVICE_MAPPER_SOURCE=\
|
||||||
device_mapper/datastruct/bitset.c \
|
device_mapper/datastruct/bitset.c \
|
||||||
device_mapper/ioctl/libdm-iface.c \
|
|
||||||
device_mapper/libdm-common.c \
|
device_mapper/libdm-common.c \
|
||||||
device_mapper/libdm-config.c \
|
device_mapper/libdm-config.c \
|
||||||
device_mapper/libdm-deptree.c \
|
device_mapper/libdm-deptree.c \
|
||||||
@@ -25,30 +21,32 @@ DEVICE_MAPPER_SOURCE=\
|
|||||||
device_mapper/libdm-targets.c \
|
device_mapper/libdm-targets.c \
|
||||||
device_mapper/libdm-timestamp.c \
|
device_mapper/libdm-timestamp.c \
|
||||||
device_mapper/mm/pool.c \
|
device_mapper/mm/pool.c \
|
||||||
device_mapper/raid/raid_parser.c \
|
|
||||||
device_mapper/regex/matcher.c \
|
device_mapper/regex/matcher.c \
|
||||||
device_mapper/regex/parse_rx.c \
|
device_mapper/regex/parse_rx.c \
|
||||||
device_mapper/regex/ttree.c \
|
device_mapper/regex/ttree.c \
|
||||||
device_mapper/vdo/status.c \
|
device_mapper/ioctl/libdm-iface.c \
|
||||||
device_mapper/vdo/vdo_reader.c \
|
device_mapper/vdo/vdo_target.c \
|
||||||
device_mapper/vdo/vdo_target.c
|
device_mapper/vdo/status.c
|
||||||
|
|
||||||
DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a
|
DEVICE_MAPPER_DEPENDS=$(addprefix $(top_builddir)/,$(subst .c,.d,$(DEVICE_MAPPER_SOURCE)))
|
||||||
DEVICE_MAPPER_DEPENDS = $(DEVICE_MAPPER_SOURCE:%.c=%.d)
|
DEVICE_MAPPER_OBJECTS=$(addprefix $(top_builddir)/,$(subst .c,.o,$(DEVICE_MAPPER_SOURCE)))
|
||||||
DEVICE_MAPPER_OBJECTS = $(DEVICE_MAPPER_SOURCE:%.c=%.o)
|
CLEAN_TARGETS+=$(DEVICE_MAPPER_DEPENDS) $(DEVICE_MAPPER_OBJECTS)
|
||||||
CLEAN_TARGETS += $(DEVICE_MAPPER_DEPENDS) $(DEVICE_MAPPER_OBJECTS) \
|
|
||||||
$(DEVICE_MAPPER_SOURCE:%.c=%.gcda) \
|
|
||||||
$(DEVICE_MAPPER_SOURCE:%.c=%.gcno) \
|
|
||||||
$(DEVICE_MAPPER_TARGET)
|
|
||||||
|
|
||||||
#$(DEVICE_MAPPER_DEPENDS): INCLUDES+=$(VDO_INCLUDES)
|
#$(DEVICE_MAPPER_DEPENDS): INCLUDES+=$(VDO_INCLUDES)
|
||||||
#$(DEVICE_MAPPER_OBJECTS): INCLUDES+=$(VDO_INCLUDES)
|
#$(DEVICE_MAPPER_OBJECTS): INCLUDES+=$(VDO_INCLUDES)
|
||||||
|
|
||||||
$(DEVICE_MAPPER_TARGET): $(DEVICE_MAPPER_OBJECTS)
|
ifeq ("$(USE_TRACKING)","yes")
|
||||||
$(SHOW) " [AR] $@"
|
ifeq (,$(findstring $(MAKECMDGOALS),cscope.out cflow clean distclean lcov \
|
||||||
|
help check check_local check_cluster check_lvmetad check_lvmpolld))
|
||||||
|
-include $(DEVICE_MAPPER_DEPENDS)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(DEVICE_MAPPER_OBJECTS): INCLUDES+=-I$(top_srcdir)/device_mapper/
|
||||||
|
|
||||||
|
$(top_builddir)/device_mapper/libdevice-mapper.a: $(DEVICE_MAPPER_OBJECTS)
|
||||||
|
@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")
|
CLEAN_TARGETS+=$(top_builddir)/device_mapper/libdevice-mapper.a
|
||||||
-include $(DEVICE_MAPPER_DEPENDS)
|
|
||||||
endif
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "base/data-struct/list.h"
|
#include "base/data-struct/list.h"
|
||||||
#include "base/data-struct/hash.h"
|
#include "base/data-struct/hash.h"
|
||||||
#include "raid/target.h"
|
|
||||||
#include "vdo/target.h"
|
#include "vdo/target.h"
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
@@ -120,11 +119,7 @@ enum {
|
|||||||
|
|
||||||
DM_DEVICE_TARGET_MSG,
|
DM_DEVICE_TARGET_MSG,
|
||||||
|
|
||||||
DM_DEVICE_SET_GEOMETRY,
|
DM_DEVICE_SET_GEOMETRY
|
||||||
|
|
||||||
DM_DEVICE_ARM_POLL,
|
|
||||||
|
|
||||||
DM_DEVICE_GET_TARGET_VERSION
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -165,34 +160,25 @@ struct dm_info {
|
|||||||
struct dm_deps {
|
struct dm_deps {
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
uint32_t filler;
|
uint32_t filler;
|
||||||
uint64_t device[];
|
uint64_t device[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dm_names {
|
struct dm_names {
|
||||||
uint64_t dev;
|
uint64_t dev;
|
||||||
uint32_t next; /* Offset to next struct from start of this struct */
|
uint32_t next; /* Offset to next struct from start of this struct */
|
||||||
char name[];
|
char name[0];
|
||||||
};
|
|
||||||
|
|
||||||
struct dm_active_device {
|
|
||||||
struct dm_list list;
|
|
||||||
dev_t devno;
|
|
||||||
const char *name; /* device name */
|
|
||||||
|
|
||||||
uint32_t event_nr; /* valid when DM_DEVICE_LIST_HAS_EVENT_NR is set */
|
|
||||||
const char *uuid; /* valid uuid when DM_DEVICE_LIST_HAS_UUID is set */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dm_versions {
|
struct dm_versions {
|
||||||
uint32_t next; /* Offset to next struct from start of this struct */
|
uint32_t next; /* Offset to next struct from start of this struct */
|
||||||
uint32_t version[3];
|
uint32_t version[3];
|
||||||
|
|
||||||
char name[];
|
char name[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
int dm_get_library_version(char *version, size_t size);
|
int dm_get_library_version(char *version, size_t size);
|
||||||
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
|
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
|
||||||
int dm_task_get_info(struct dm_task *dmt, struct dm_info *info);
|
int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function returns dm device's UUID based on the value
|
* This function returns dm device's UUID based on the value
|
||||||
@@ -220,18 +206,6 @@ const char *dm_task_get_message_response(struct dm_task *dmt);
|
|||||||
*/
|
*/
|
||||||
const char *dm_task_get_name(const struct dm_task *dmt);
|
const char *dm_task_get_name(const struct dm_task *dmt);
|
||||||
struct dm_names *dm_task_get_names(struct dm_task *dmt);
|
struct dm_names *dm_task_get_names(struct dm_task *dmt);
|
||||||
/*
|
|
||||||
* Retrieve the list of devices and put them into easily accessible
|
|
||||||
* struct dm_active_device list elements.
|
|
||||||
* devs_features provides flag-set with used features so it's easy to check
|
|
||||||
* whether the kernel provides i.e. UUID info together with DM names
|
|
||||||
*/
|
|
||||||
#define DM_DEVICE_LIST_HAS_EVENT_NR 1
|
|
||||||
#define DM_DEVICE_LIST_HAS_UUID 2
|
|
||||||
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
|
|
||||||
unsigned *devs_features);
|
|
||||||
/* Release all associated memory with list of active DM devices */
|
|
||||||
void dm_device_list_destroy(struct dm_list **devs_list);
|
|
||||||
|
|
||||||
int dm_task_set_ro(struct dm_task *dmt);
|
int dm_task_set_ro(struct dm_task *dmt);
|
||||||
int dm_task_set_newname(struct dm_task *dmt, const char *newname);
|
int dm_task_set_newname(struct dm_task *dmt, const char *newname);
|
||||||
@@ -256,8 +230,6 @@ int dm_task_suppress_identical_reload(struct dm_task *dmt);
|
|||||||
int dm_task_secure_data(struct dm_task *dmt);
|
int dm_task_secure_data(struct dm_task *dmt);
|
||||||
int dm_task_retry_remove(struct dm_task *dmt);
|
int dm_task_retry_remove(struct dm_task *dmt);
|
||||||
int dm_task_deferred_remove(struct dm_task *dmt);
|
int dm_task_deferred_remove(struct dm_task *dmt);
|
||||||
int dm_task_ima_measurement(struct dm_task *dmt);
|
|
||||||
void dm_task_skip_reload_params_compare(struct dm_task *dmt);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record timestamp immediately after the ioctl returns.
|
* Record timestamp immediately after the ioctl returns.
|
||||||
@@ -305,15 +277,15 @@ int dm_task_add_target(struct dm_task *dmt,
|
|||||||
#define DM_FORMAT_DEV_BUFSIZE 13 /* Minimum bufsize to handle worst case. */
|
#define DM_FORMAT_DEV_BUFSIZE 13 /* Minimum bufsize to handle worst case. */
|
||||||
int dm_format_dev(char *buf, int bufsize, uint32_t dev_major, uint32_t dev_minor);
|
int dm_format_dev(char *buf, int bufsize, uint32_t dev_major, uint32_t dev_minor);
|
||||||
|
|
||||||
/* Use this to retrieve target information returned from a STATUS call */
|
/* Use this to retrive target information returned from a STATUS call */
|
||||||
void *dm_get_next_target(struct dm_task *dmt,
|
void *dm_get_next_target(struct dm_task *dmt,
|
||||||
void *next, uint64_t *start, uint64_t *length,
|
void *next, uint64_t *start, uint64_t *length,
|
||||||
char **target_type, char **params);
|
char **target_type, char **params);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Following dm_get_status_* functions will allocate appropriate status structure
|
* Following dm_get_status_* functions will allocate approriate status structure
|
||||||
* from passed mempool together with the necessary character arrays.
|
* from passed mempool together with the necessary character arrays.
|
||||||
* Destroying the mempool will release all associated allocation.
|
* Destroying the mempool will release all asociated allocation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Parse params from STATUS call for mirror target */
|
/* Parse params from STATUS call for mirror target */
|
||||||
@@ -406,25 +378,6 @@ struct dm_status_cache {
|
|||||||
int dm_get_status_cache(struct dm_pool *mem, const char *params,
|
int dm_get_status_cache(struct dm_pool *mem, const char *params,
|
||||||
struct dm_status_cache **status);
|
struct dm_status_cache **status);
|
||||||
|
|
||||||
struct dm_status_writecache {
|
|
||||||
uint64_t error;
|
|
||||||
uint64_t total_blocks;
|
|
||||||
uint64_t free_blocks;
|
|
||||||
uint64_t writeback_blocks;
|
|
||||||
};
|
|
||||||
|
|
||||||
int dm_get_status_writecache(struct dm_pool *mem, const char *params,
|
|
||||||
struct dm_status_writecache **status);
|
|
||||||
|
|
||||||
struct dm_status_integrity {
|
|
||||||
uint64_t number_of_mismatches;
|
|
||||||
uint64_t provided_data_sectors;
|
|
||||||
uint64_t recalc_sector;
|
|
||||||
};
|
|
||||||
|
|
||||||
int dm_get_status_integrity(struct dm_pool *mem, const char *params,
|
|
||||||
struct dm_status_integrity **status);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse params from STATUS call for snapshot target
|
* Parse params from STATUS call for snapshot target
|
||||||
*
|
*
|
||||||
@@ -542,7 +495,7 @@ const char *dm_sysfs_dir(void);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure default UUID prefix string.
|
* Configure default UUID prefix string.
|
||||||
* Conventionally this is a short capitalized prefix indicating the subsystem
|
* Conventionally this is a short capitalised prefix indicating the subsystem
|
||||||
* that is managing the devices, e.g. "LVM-" or "MPATH-".
|
* that is managing the devices, e.g. "LVM-" or "MPATH-".
|
||||||
* To support stacks of devices from different subsystems, recursive functions
|
* To support stacks of devices from different subsystems, recursive functions
|
||||||
* stop recursing if they reach a device with a different prefix.
|
* stop recursing if they reach a device with a different prefix.
|
||||||
@@ -585,7 +538,7 @@ int dm_device_has_mounted_fs(uint32_t major, uint32_t minor);
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Callback is invoked for individual mountinfo lines,
|
* Callback is invoked for individal mountinfo lines,
|
||||||
* minor, major and mount target are parsed and unmangled.
|
* minor, major and mount target are parsed and unmangled.
|
||||||
*/
|
*/
|
||||||
typedef int (*dm_mountinfo_line_callback_fn) (char *line, unsigned maj, unsigned min,
|
typedef int (*dm_mountinfo_line_callback_fn) (char *line, unsigned maj, unsigned min,
|
||||||
@@ -699,7 +652,7 @@ void *dm_tree_node_get_context(const struct dm_tree_node *node);
|
|||||||
/*
|
/*
|
||||||
* Returns 0 when node size and its children is unchanged.
|
* Returns 0 when node size and its children is unchanged.
|
||||||
* Returns 1 when node or any of its children has increased size.
|
* Returns 1 when node or any of its children has increased size.
|
||||||
* Returns -1 when node or any of its children has reduced size.
|
* Rerurns -1 when node or any of its children has reduced size.
|
||||||
*/
|
*/
|
||||||
int dm_tree_node_size_changed(const struct dm_tree_node *dnode);
|
int dm_tree_node_size_changed(const struct dm_tree_node *dnode);
|
||||||
|
|
||||||
@@ -886,7 +839,7 @@ struct dm_tree_node_raid_params {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Version 2 of above node raid params struct to keep API compatibility.
|
* Version 2 of above node raid params struct to keeep API compatibility.
|
||||||
*
|
*
|
||||||
* Extended for more than 64 legs (max 253 in the MD kernel runtime!),
|
* Extended for more than 64 legs (max 253 in the MD kernel runtime!),
|
||||||
* delta_disks for disk add/remove reshaping,
|
* delta_disks for disk add/remove reshaping,
|
||||||
@@ -909,7 +862,7 @@ struct dm_tree_node_raid_params_v2 {
|
|||||||
* 'rebuilds' and 'writemostly' are bitfields that signify
|
* 'rebuilds' and 'writemostly' are bitfields that signify
|
||||||
* which devices in the array are to be rebuilt or marked
|
* which devices in the array are to be rebuilt or marked
|
||||||
* writemostly. The kernel supports up to 253 legs.
|
* writemostly. The kernel supports up to 253 legs.
|
||||||
* We limit ourselves by choosing a lower value
|
* We limit ourselvs by choosing a lower value
|
||||||
* for DEFAULT_RAID_MAX_IMAGES.
|
* for DEFAULT_RAID_MAX_IMAGES.
|
||||||
*/
|
*/
|
||||||
uint64_t rebuilds[RAID_BITMAP_SIZE];
|
uint64_t rebuilds[RAID_BITMAP_SIZE];
|
||||||
@@ -938,7 +891,6 @@ int dm_tree_node_add_raid_target_with_params_v2(struct dm_tree_node *node,
|
|||||||
#define DM_CACHE_FEATURE_WRITETHROUGH 0x00000002
|
#define DM_CACHE_FEATURE_WRITETHROUGH 0x00000002
|
||||||
#define DM_CACHE_FEATURE_PASSTHROUGH 0x00000004
|
#define DM_CACHE_FEATURE_PASSTHROUGH 0x00000004
|
||||||
#define DM_CACHE_FEATURE_METADATA2 0x00000008 /* cache v1.10 */
|
#define DM_CACHE_FEATURE_METADATA2 0x00000008 /* cache v1.10 */
|
||||||
#define DM_CACHE_FEATURE_NO_DISCARD_PASSDOWN 0x00000010
|
|
||||||
|
|
||||||
struct dm_config_node;
|
struct dm_config_node;
|
||||||
/*
|
/*
|
||||||
@@ -946,7 +898,7 @@ struct dm_config_node;
|
|||||||
*
|
*
|
||||||
* policy_settings {
|
* policy_settings {
|
||||||
* migration_threshold=2048
|
* migration_threshold=2048
|
||||||
* sequential_threshold=100
|
* sequention_threashold=100
|
||||||
* ...
|
* ...
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
@@ -960,99 +912,15 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
|
|||||||
const char *origin_uuid,
|
const char *origin_uuid,
|
||||||
const char *policy_name,
|
const char *policy_name,
|
||||||
const struct dm_config_node *policy_settings,
|
const struct dm_config_node *policy_settings,
|
||||||
uint64_t metadata_start,
|
|
||||||
uint64_t metadata_len,
|
|
||||||
uint64_t data_start,
|
|
||||||
uint64_t data_len,
|
|
||||||
uint32_t data_block_size);
|
uint32_t data_block_size);
|
||||||
|
|
||||||
struct writecache_settings {
|
|
||||||
uint64_t high_watermark;
|
|
||||||
uint64_t low_watermark;
|
|
||||||
uint64_t writeback_jobs;
|
|
||||||
uint64_t autocommit_blocks;
|
|
||||||
uint64_t autocommit_time; /* in milliseconds */
|
|
||||||
uint32_t fua;
|
|
||||||
uint32_t nofua;
|
|
||||||
uint32_t cleaner;
|
|
||||||
uint32_t max_age; /* in milliseconds */
|
|
||||||
uint32_t metadata_only;
|
|
||||||
uint32_t pause_writeback; /* in milliseconds */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allow an unrecognized key and its val to be passed to the kernel for
|
|
||||||
* cases where a new kernel setting is added but lvm doesn't know about
|
|
||||||
* it yet.
|
|
||||||
*/
|
|
||||||
char *new_key;
|
|
||||||
char *new_val;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Flag is 1 if a value has been set.
|
|
||||||
*/
|
|
||||||
unsigned high_watermark_set:1;
|
|
||||||
unsigned low_watermark_set:1;
|
|
||||||
unsigned writeback_jobs_set:1;
|
|
||||||
unsigned autocommit_blocks_set:1;
|
|
||||||
unsigned autocommit_time_set:1;
|
|
||||||
unsigned fua_set:1;
|
|
||||||
unsigned nofua_set:1;
|
|
||||||
unsigned cleaner_set:1;
|
|
||||||
unsigned max_age_set:1;
|
|
||||||
unsigned metadata_only_set:1;
|
|
||||||
unsigned pause_writeback_set:1;
|
|
||||||
};
|
|
||||||
|
|
||||||
int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
|
|
||||||
uint64_t size,
|
|
||||||
const char *origin_uuid,
|
|
||||||
const char *cache_uuid,
|
|
||||||
int pmem,
|
|
||||||
uint32_t writecache_block_size,
|
|
||||||
struct writecache_settings *settings);
|
|
||||||
|
|
||||||
struct integrity_settings {
|
|
||||||
char mode[8];
|
|
||||||
uint32_t tag_size;
|
|
||||||
uint32_t block_size; /* optional table param always set by lvm */
|
|
||||||
const char *internal_hash; /* optional table param always set by lvm */
|
|
||||||
|
|
||||||
uint32_t journal_sectors;
|
|
||||||
uint32_t interleave_sectors;
|
|
||||||
uint32_t buffer_sectors;
|
|
||||||
uint32_t journal_watermark;
|
|
||||||
uint32_t commit_time;
|
|
||||||
uint32_t bitmap_flush_interval;
|
|
||||||
uint64_t sectors_per_bit;
|
|
||||||
uint32_t allow_discards;
|
|
||||||
|
|
||||||
unsigned journal_sectors_set:1;
|
|
||||||
unsigned interleave_sectors_set:1;
|
|
||||||
unsigned buffer_sectors_set:1;
|
|
||||||
unsigned journal_watermark_set:1;
|
|
||||||
unsigned commit_time_set:1;
|
|
||||||
unsigned bitmap_flush_interval_set:1;
|
|
||||||
unsigned sectors_per_bit_set:1;
|
|
||||||
unsigned allow_discards_set:1;
|
|
||||||
};
|
|
||||||
|
|
||||||
int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
|
|
||||||
uint64_t size,
|
|
||||||
const char *origin_uuid,
|
|
||||||
const char *meta_uuid,
|
|
||||||
struct integrity_settings *settings,
|
|
||||||
int recalculate);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VDO target
|
* VDO target
|
||||||
*/
|
*/
|
||||||
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
|
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
|
||||||
uint64_t size,
|
uint64_t size,
|
||||||
uint32_t vdo_version,
|
|
||||||
const char *vdo_pool_name,
|
|
||||||
const char *data_uuid,
|
const char *data_uuid,
|
||||||
uint64_t data_size,
|
const struct dm_vdo_target_params *param);
|
||||||
const struct dm_vdo_target_params *vtp);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME Add individual cache policy pairs <key> = value, like:
|
* FIXME Add individual cache policy pairs <key> = value, like:
|
||||||
@@ -1095,17 +963,17 @@ int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
|
|||||||
/* End of Replicator API */
|
/* End of Replicator API */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: Defines below are based on kernel's dm-thin.c defines
|
* FIXME: Defines bellow are based on kernel's dm-thin.c defines
|
||||||
* DATA_DEV_BLOCK_SIZE_MIN_SECTORS (64 * 1024 >> SECTOR_SHIFT)
|
* DATA_DEV_BLOCK_SIZE_MIN_SECTORS (64 * 1024 >> SECTOR_SHIFT)
|
||||||
* DATA_DEV_BLOCK_SIZE_MAX_SECTORS (1024 * 1024 * 1024 >> SECTOR_SHIFT)
|
* DATA_DEV_BLOCK_SIZE_MAX_SECTORS (1024 * 1024 * 1024 >> SECTOR_SHIFT)
|
||||||
*/
|
*/
|
||||||
#define DM_THIN_MIN_DATA_BLOCK_SIZE (UINT32_C(128))
|
#define DM_THIN_MIN_DATA_BLOCK_SIZE (UINT32_C(128))
|
||||||
#define DM_THIN_MAX_DATA_BLOCK_SIZE (UINT32_C(2097152))
|
#define DM_THIN_MAX_DATA_BLOCK_SIZE (UINT32_C(2097152))
|
||||||
/*
|
/*
|
||||||
* Max supported size for thin pool metadata device (17045913600 bytes)
|
* Max supported size for thin pool metadata device (17112760320 bytes)
|
||||||
|
* Limitation is hardcoded into the kernel and bigger device size
|
||||||
|
* is not accepted.
|
||||||
* drivers/md/dm-thin-metadata.h THIN_METADATA_MAX_SECTORS
|
* drivers/md/dm-thin-metadata.h THIN_METADATA_MAX_SECTORS
|
||||||
* But here DM_THIN_MAX_METADATA_SIZE got defined incorrectly
|
|
||||||
* Correct size is (UINT64_C(255) * ((1 << 14) - 64) * (4096 / (1 << 9)))
|
|
||||||
*/
|
*/
|
||||||
#define DM_THIN_MAX_METADATA_SIZE (UINT64_C(255) * (1 << 14) * (4096 / (1 << 9)) - 256 * 1024)
|
#define DM_THIN_MAX_METADATA_SIZE (UINT64_C(255) * (1 << 14) * (4096 / (1 << 9)) - 256 * 1024)
|
||||||
|
|
||||||
@@ -1118,16 +986,6 @@ int dm_tree_node_add_thin_pool_target(struct dm_tree_node *node,
|
|||||||
uint64_t low_water_mark,
|
uint64_t low_water_mark,
|
||||||
unsigned skip_block_zeroing);
|
unsigned skip_block_zeroing);
|
||||||
|
|
||||||
int dm_tree_node_add_thin_pool_target_v1(struct dm_tree_node *node,
|
|
||||||
uint64_t size,
|
|
||||||
uint64_t transaction_id,
|
|
||||||
const char *metadata_uuid,
|
|
||||||
const char *pool_uuid,
|
|
||||||
uint32_t data_block_size,
|
|
||||||
uint64_t low_water_mark,
|
|
||||||
unsigned skip_block_zeroing,
|
|
||||||
unsigned crop_metadata);
|
|
||||||
|
|
||||||
/* Supported messages for thin provision target */
|
/* Supported messages for thin provision target */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DM_THIN_MESSAGE_CREATE_SNAP, /* device_id, origin_id */
|
DM_THIN_MESSAGE_CREATE_SNAP, /* device_id, origin_id */
|
||||||
@@ -1161,7 +1019,7 @@ int dm_tree_node_set_thin_pool_error_if_no_space(struct dm_tree_node *node,
|
|||||||
int dm_tree_node_set_thin_pool_read_only(struct dm_tree_node *node,
|
int dm_tree_node_set_thin_pool_read_only(struct dm_tree_node *node,
|
||||||
unsigned read_only);
|
unsigned read_only);
|
||||||
/*
|
/*
|
||||||
* FIXME: Defines below are based on kernel's dm-thin.c defines
|
* FIXME: Defines bellow are based on kernel's dm-thin.c defines
|
||||||
* MAX_DEV_ID ((1 << 24) - 1)
|
* MAX_DEV_ID ((1 << 24) - 1)
|
||||||
*/
|
*/
|
||||||
#define DM_THIN_MAX_DEVICE_ID (UINT32_C((1 << 24) - 1))
|
#define DM_THIN_MAX_DEVICE_ID (UINT32_C((1 << 24) - 1))
|
||||||
@@ -1180,7 +1038,7 @@ void dm_tree_node_set_presuspend_node(struct dm_tree_node *node,
|
|||||||
|
|
||||||
int dm_tree_node_add_target_area(struct dm_tree_node *node,
|
int dm_tree_node_add_target_area(struct dm_tree_node *node,
|
||||||
const char *dev_name,
|
const char *dev_name,
|
||||||
const char *uuid,
|
const char *dlid,
|
||||||
uint64_t offset);
|
uint64_t offset);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1358,7 +1216,7 @@ int dm_bit_get_next(dm_bitset_t bs, int last_bit);
|
|||||||
int dm_bit_get_last(dm_bitset_t bs);
|
int dm_bit_get_last(dm_bitset_t bs);
|
||||||
int dm_bit_get_prev(dm_bitset_t bs, int last_bit);
|
int dm_bit_get_prev(dm_bitset_t bs, int last_bit);
|
||||||
|
|
||||||
#define DM_BITS_PER_INT ((unsigned)sizeof(int) * CHAR_BIT)
|
#define DM_BITS_PER_INT (sizeof(int) * CHAR_BIT)
|
||||||
|
|
||||||
#define dm_bit(bs, i) \
|
#define dm_bit(bs, i) \
|
||||||
((bs)[((i) / DM_BITS_PER_INT) + 1] & (0x1 << ((i) & (DM_BITS_PER_INT - 1))))
|
((bs)[((i) / DM_BITS_PER_INT) + 1] & (0x1 << ((i) & (DM_BITS_PER_INT - 1))))
|
||||||
@@ -1591,9 +1449,9 @@ int dm_fclose(FILE *stream);
|
|||||||
* Pointer to the buffer is stored in *buf.
|
* Pointer to the buffer is stored in *buf.
|
||||||
* Returns -1 on failure leaving buf undefined.
|
* Returns -1 on failure leaving buf undefined.
|
||||||
*/
|
*/
|
||||||
int dm_asprintf(char **result, const char *format, ...)
|
int dm_asprintf(char **buf, const char *format, ...)
|
||||||
__attribute__ ((format(printf, 2, 3)));
|
__attribute__ ((format(printf, 2, 3)));
|
||||||
int dm_vasprintf(char **result, const char *format, va_list aq)
|
int dm_vasprintf(char **buf, const char *format, va_list ap)
|
||||||
__attribute__ ((format(printf, 2, 0)));
|
__attribute__ ((format(printf, 2, 0)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1870,7 +1728,6 @@ const void *dm_report_value_cache_get(struct dm_report *rh, const char *name);
|
|||||||
#define DM_REPORT_OUTPUT_FIELD_UNQUOTED 0x00000010
|
#define DM_REPORT_OUTPUT_FIELD_UNQUOTED 0x00000010
|
||||||
#define DM_REPORT_OUTPUT_COLUMNS_AS_ROWS 0x00000020
|
#define DM_REPORT_OUTPUT_COLUMNS_AS_ROWS 0x00000020
|
||||||
#define DM_REPORT_OUTPUT_MULTIPLE_TIMES 0x00000040
|
#define DM_REPORT_OUTPUT_MULTIPLE_TIMES 0x00000040
|
||||||
#define DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS 0x00000080
|
|
||||||
|
|
||||||
struct dm_report *dm_report_init(uint32_t *report_types,
|
struct dm_report *dm_report_init(uint32_t *report_types,
|
||||||
const struct dm_report_object_type *types,
|
const struct dm_report_object_type *types,
|
||||||
@@ -1942,7 +1799,7 @@ void dm_report_free(struct dm_report *rh);
|
|||||||
* Prefix added to each field name with DM_REPORT_OUTPUT_FIELD_NAME_PREFIX
|
* Prefix added to each field name with DM_REPORT_OUTPUT_FIELD_NAME_PREFIX
|
||||||
*/
|
*/
|
||||||
int dm_report_set_output_field_name_prefix(struct dm_report *rh,
|
int dm_report_set_output_field_name_prefix(struct dm_report *rh,
|
||||||
const char *output_field_name_prefix);
|
const char *report_prefix);
|
||||||
|
|
||||||
int dm_report_set_selection(struct dm_report *rh, const char *selection);
|
int dm_report_set_selection(struct dm_report *rh, const char *selection);
|
||||||
|
|
||||||
@@ -1983,8 +1840,7 @@ struct dm_report_group;
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
DM_REPORT_GROUP_SINGLE,
|
DM_REPORT_GROUP_SINGLE,
|
||||||
DM_REPORT_GROUP_BASIC,
|
DM_REPORT_GROUP_BASIC,
|
||||||
DM_REPORT_GROUP_JSON,
|
DM_REPORT_GROUP_JSON
|
||||||
DM_REPORT_GROUP_JSON_STD
|
|
||||||
} dm_report_group_type_t;
|
} dm_report_group_type_t;
|
||||||
|
|
||||||
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data);
|
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data);
|
||||||
@@ -2035,7 +1891,6 @@ struct dm_config_tree *dm_config_create(void);
|
|||||||
struct dm_config_tree *dm_config_from_string(const char *config_settings);
|
struct dm_config_tree *dm_config_from_string(const char *config_settings);
|
||||||
int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end);
|
int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end);
|
||||||
int dm_config_parse_without_dup_node_check(struct dm_config_tree *cft, const char *start, const char *end);
|
int dm_config_parse_without_dup_node_check(struct dm_config_tree *cft, const char *start, const char *end);
|
||||||
int dm_config_parse_only_section(struct dm_config_tree *cft, const char *start, const char *end, const char *section);
|
|
||||||
|
|
||||||
void *dm_config_get_custom(struct dm_config_tree *cft);
|
void *dm_config_get_custom(struct dm_config_tree *cft);
|
||||||
void dm_config_set_custom(struct dm_config_tree *cft, void *custom);
|
void dm_config_set_custom(struct dm_config_tree *cft, void *custom);
|
||||||
@@ -2060,7 +1915,7 @@ void dm_config_destroy(struct dm_config_tree *cft);
|
|||||||
|
|
||||||
/* Simple output line by line. */
|
/* Simple output line by line. */
|
||||||
typedef int (*dm_putline_fn)(const char *line, void *baton);
|
typedef int (*dm_putline_fn)(const char *line, void *baton);
|
||||||
/* More advanced output with config node reference. */
|
/* More advaced output with config node reference. */
|
||||||
typedef int (*dm_config_node_out_fn)(const struct dm_config_node *cn, const char *line, void *baton);
|
typedef int (*dm_config_node_out_fn)(const struct dm_config_node *cn, const char *line, void *baton);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2082,7 +1937,7 @@ int dm_config_write_one_node_out(const struct dm_config_node *cn, const struct d
|
|||||||
|
|
||||||
struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn, const char *path);
|
struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn, const char *path);
|
||||||
int dm_config_has_node(const struct dm_config_node *cn, const char *path);
|
int dm_config_has_node(const struct dm_config_node *cn, const char *path);
|
||||||
int dm_config_remove_node(struct dm_config_node *parent, struct dm_config_node *rem_node);
|
int dm_config_remove_node(struct dm_config_node *parent, struct dm_config_node *remove);
|
||||||
const char *dm_config_find_str(const struct dm_config_node *cn, const char *path, const char *fail);
|
const char *dm_config_find_str(const struct dm_config_node *cn, const char *path, const char *fail);
|
||||||
const char *dm_config_find_str_allow_empty(const struct dm_config_node *cn, const char *path, const char *fail);
|
const char *dm_config_find_str_allow_empty(const struct dm_config_node *cn, const char *path, const char *fail);
|
||||||
int dm_config_find_int(const struct dm_config_node *cn, const char *path, int fail);
|
int dm_config_find_int(const struct dm_config_node *cn, const char *path, int fail);
|
||||||
@@ -2114,7 +1969,7 @@ unsigned dm_config_maybe_section(const char *str, unsigned len);
|
|||||||
|
|
||||||
const char *dm_config_parent_name(const struct dm_config_node *n);
|
const char *dm_config_parent_name(const struct dm_config_node *n);
|
||||||
|
|
||||||
struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *cn, int siblings);
|
struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *node, int siblings);
|
||||||
struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key);
|
struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key);
|
||||||
struct dm_config_value *dm_config_create_value(struct dm_config_tree *cft);
|
struct dm_config_value *dm_config_create_value(struct dm_config_tree *cft);
|
||||||
struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *cn, int siblings);
|
struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *cn, int siblings);
|
||||||
@@ -2123,7 +1978,7 @@ struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const st
|
|||||||
* Common formatting flags applicable to all config node types (lower 16 bits).
|
* Common formatting flags applicable to all config node types (lower 16 bits).
|
||||||
*/
|
*/
|
||||||
#define DM_CONFIG_VALUE_FMT_COMMON_ARRAY 0x00000001 /* value is array */
|
#define DM_CONFIG_VALUE_FMT_COMMON_ARRAY 0x00000001 /* value is array */
|
||||||
#define DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES 0x00000002 /* add spaces in "key = value" pairs in contrast to "key=value" for better readability */
|
#define DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES 0x00000002 /* add spaces in "key = value" pairs in constrast to "key=value" for better readability */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Type-related config node formatting flags (higher 16 bits).
|
* Type-related config node formatting flags (higher 16 bits).
|
||||||
@@ -2169,7 +2024,7 @@ struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
|
|||||||
*/
|
*/
|
||||||
#define DM_UDEV_DISABLE_DM_RULES_FLAG 0x0001
|
#define DM_UDEV_DISABLE_DM_RULES_FLAG 0x0001
|
||||||
/*
|
/*
|
||||||
* DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG is set in case we need to disable
|
* DM_UDEV_DISABLE_SUBSYTEM_RULES_FLAG is set in case we need to disable
|
||||||
* subsystem udev rules, but still we need the general DM udev rules to
|
* subsystem udev rules, but still we need the general DM udev rules to
|
||||||
* be applied (to create the nodes and symlinks under /dev and /dev/disk).
|
* be applied (to create the nodes and symlinks under /dev and /dev/disk).
|
||||||
*/
|
*/
|
||||||
@@ -2240,7 +2095,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);
|
||||||
|
|||||||
@@ -150,8 +150,7 @@ dm_bitset_t dm_bitset_parse_list(const char *str, struct dm_pool *mem,
|
|||||||
size_t min_num_bits)
|
size_t min_num_bits)
|
||||||
{
|
{
|
||||||
unsigned a, b;
|
unsigned a, b;
|
||||||
int c, old_c, totaldigits, ndigits;
|
int c, old_c, totaldigits, ndigits, nmaskbits;
|
||||||
size_t nmaskbits;
|
|
||||||
int at_start, in_range;
|
int at_start, in_range;
|
||||||
dm_bitset_t mask = NULL;
|
dm_bitset_t mask = NULL;
|
||||||
const char *start = str;
|
const char *start = str;
|
||||||
@@ -243,3 +242,18 @@ bad:
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
/*
|
||||||
|
* Maintain backward compatibility with older versions that did not
|
||||||
|
* accept a 'min_num_bits' argument to dm_bitset_parse_list().
|
||||||
|
*/
|
||||||
|
dm_bitset_t dm_bitset_parse_list_v1_02_129(const char *str, struct dm_pool *mem);
|
||||||
|
dm_bitset_t dm_bitset_parse_list_v1_02_129(const char *str, struct dm_pool *mem)
|
||||||
|
{
|
||||||
|
return dm_bitset_parse_list(str, mem, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* if defined(__GNUC__) */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
#include "base/memory/zalloc.h"
|
#include "base/memory/zalloc.h"
|
||||||
#include "device_mapper/misc/dmlib.h"
|
#include "device_mapper/misc/dmlib.h"
|
||||||
#include "device_mapper/misc/dm-ioctl.h"
|
|
||||||
#include "device_mapper/ioctl/libdm-targets.h"
|
#include "device_mapper/ioctl/libdm-targets.h"
|
||||||
#include "device_mapper/libdm-common.h"
|
#include "device_mapper/libdm-common.h"
|
||||||
|
|
||||||
@@ -33,9 +32,11 @@
|
|||||||
#else
|
#else
|
||||||
# define MAJOR(x) major((x))
|
# define MAJOR(x) major((x))
|
||||||
# define MINOR(x) minor((x))
|
# define MINOR(x) minor((x))
|
||||||
# define MKDEV(x,y) makedev(((dev_t)x),((dev_t)y))
|
# define MKDEV(x,y) makedev((x),(y))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "device_mapper/misc/dm-ioctl.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure build compatibility.
|
* Ensure build compatibility.
|
||||||
* The hard-coded versions here are the highest present
|
* The hard-coded versions here are the highest present
|
||||||
@@ -70,7 +71,6 @@ static unsigned _dm_version_minor = 0;
|
|||||||
static unsigned _dm_version_patchlevel = 0;
|
static unsigned _dm_version_patchlevel = 0;
|
||||||
static int _log_suppress = 0;
|
static int _log_suppress = 0;
|
||||||
static struct dm_timestamp *_dm_ioctl_timestamp = NULL;
|
static struct dm_timestamp *_dm_ioctl_timestamp = NULL;
|
||||||
static int _dm_warn_inactive_suppress = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the kernel dm driver only supports one major number
|
* If the kernel dm driver only supports one major number
|
||||||
@@ -88,8 +88,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}},
|
||||||
@@ -115,12 +117,6 @@ static const struct cmd_data _cmd_data_v4[] = {
|
|||||||
#ifdef DM_DEV_SET_GEOMETRY
|
#ifdef DM_DEV_SET_GEOMETRY
|
||||||
{"setgeometry", DM_DEV_SET_GEOMETRY, {4, 6, 0}},
|
{"setgeometry", DM_DEV_SET_GEOMETRY, {4, 6, 0}},
|
||||||
#endif
|
#endif
|
||||||
#ifdef DM_DEV_ARM_POLL
|
|
||||||
{"armpoll", DM_DEV_ARM_POLL, {4, 36, 0}},
|
|
||||||
#endif
|
|
||||||
#ifdef DM_GET_TARGET_VERSION
|
|
||||||
{"target-version", DM_GET_TARGET_VERSION, {4, 41, 0}},
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
@@ -138,6 +134,7 @@ static char *_align(char *ptr, unsigned int a)
|
|||||||
return (char *) (((unsigned long) ptr + agn) & ~agn);
|
return (char *) (((unsigned long) ptr + agn) & ~agn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DM_IOCTLS
|
||||||
static unsigned _kernel_major = 0;
|
static unsigned _kernel_major = 0;
|
||||||
static unsigned _kernel_minor = 0;
|
static unsigned _kernel_minor = 0;
|
||||||
static unsigned _kernel_release = 0;
|
static unsigned _kernel_release = 0;
|
||||||
@@ -180,9 +177,6 @@ int get_uname_version(unsigned *major, unsigned *minor, unsigned *release)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DM_IOCTLS
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set number to NULL to populate _dm_bitset - otherwise first
|
* Set number to NULL to populate _dm_bitset - otherwise first
|
||||||
* match is returned.
|
* match is returned.
|
||||||
@@ -199,7 +193,6 @@ static int _get_proc_number(const char *file, const char *name,
|
|||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
size_t len;
|
size_t len;
|
||||||
uint32_t num;
|
uint32_t num;
|
||||||
unsigned blocksection = (strcmp(file, PROC_DEVICES) == 0) ? 0 : 1;
|
|
||||||
|
|
||||||
if (!(fl = fopen(file, "r"))) {
|
if (!(fl = fopen(file, "r"))) {
|
||||||
log_sys_error("fopen", file);
|
log_sys_error("fopen", file);
|
||||||
@@ -207,9 +200,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, "%d %255s\n", &num, &nm[0]) == 2) {
|
||||||
blocksection = 1;
|
|
||||||
else if (sscanf(line, "%u %255s\n", &num, &nm[0]) == 2) {
|
|
||||||
if (!strcmp(name, nm)) {
|
if (!strcmp(name, nm)) {
|
||||||
if (number) {
|
if (number) {
|
||||||
*number = num;
|
*number = num;
|
||||||
@@ -249,16 +240,6 @@ static int _control_device_number(uint32_t *major, uint32_t *minor)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _control_unlink(const char *control)
|
|
||||||
{
|
|
||||||
if (unlink(control) && (errno != ENOENT)) {
|
|
||||||
log_sys_error("unlink", control);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 1 if it exists on returning; 0 if it doesn't; -1 if it's wrong.
|
* Returns 1 if it exists on returning; 0 if it doesn't; -1 if it's wrong.
|
||||||
*/
|
*/
|
||||||
@@ -274,15 +255,21 @@ 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((dev_t)major, (dev_t)minor)) {
|
||||||
log_verbose("%s: Wrong device number: (%u, %u) instead of "
|
log_verbose("%s: Wrong device number: (%u, %u) instead of "
|
||||||
"(%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,14 +304,9 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
|
|||||||
(void) dm_prepare_selinux_context(control, S_IFCHR);
|
(void) dm_prepare_selinux_context(control, S_IFCHR);
|
||||||
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((dev_t)major, (dev_t)minor)) < 0) {
|
||||||
if (errno != EEXIST) {
|
|
||||||
log_sys_error("mknod", control);
|
log_sys_error("mknod", control);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else if (_control_exists(control, major, minor) != 1) {
|
|
||||||
stack; /* Invalid control node created by parallel command ? */
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
umask(old_umask);
|
umask(old_umask);
|
||||||
(void) dm_prepare_selinux_context(NULL, 0);
|
(void) dm_prepare_selinux_context(NULL, 0);
|
||||||
@@ -410,7 +392,7 @@ static void _close_control_fd(void)
|
|||||||
{
|
{
|
||||||
if (_control_fd != -1) {
|
if (_control_fd != -1) {
|
||||||
if (close(_control_fd) < 0)
|
if (close(_control_fd) < 0)
|
||||||
log_sys_debug("close", "_control_fd");
|
log_sys_error("close", "_control_fd");
|
||||||
_control_fd = -1;
|
_control_fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -486,7 +468,6 @@ static void _dm_zfree_string(char *string)
|
|||||||
{
|
{
|
||||||
if (string) {
|
if (string) {
|
||||||
memset(string, 0, strlen(string));
|
memset(string, 0, strlen(string));
|
||||||
__asm__ volatile ("" ::: "memory"); /* Compiler barrier. */
|
|
||||||
free(string);
|
free(string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -495,7 +476,6 @@ static void _dm_zfree_dmi(struct dm_ioctl *dmi)
|
|||||||
{
|
{
|
||||||
if (dmi) {
|
if (dmi) {
|
||||||
memset(dmi, 0, dmi->data_size);
|
memset(dmi, 0, dmi->data_size);
|
||||||
__asm__ volatile ("" ::: "memory"); /* Compiler barrier. */
|
|
||||||
free(dmi);
|
free(dmi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -506,10 +486,7 @@ static void _dm_task_free_targets(struct dm_task *dmt)
|
|||||||
|
|
||||||
for (t = dmt->head; t; t = n) {
|
for (t = dmt->head; t; t = n) {
|
||||||
n = t->next;
|
n = t->next;
|
||||||
if (dmt->secure_data)
|
|
||||||
_dm_zfree_string(t->params);
|
_dm_zfree_string(t->params);
|
||||||
else
|
|
||||||
free(t->params);
|
|
||||||
free(t->type);
|
free(t->type);
|
||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
@@ -520,10 +497,7 @@ static void _dm_task_free_targets(struct dm_task *dmt)
|
|||||||
void dm_task_destroy(struct dm_task *dmt)
|
void dm_task_destroy(struct dm_task *dmt)
|
||||||
{
|
{
|
||||||
_dm_task_free_targets(dmt);
|
_dm_task_free_targets(dmt);
|
||||||
if (dmt->secure_data)
|
|
||||||
_dm_zfree_dmi(dmt->dmi.v4);
|
_dm_zfree_dmi(dmt->dmi.v4);
|
||||||
else
|
|
||||||
free(dmt->dmi.v4);
|
|
||||||
free(dmt->dev_name);
|
free(dmt->dev_name);
|
||||||
free(dmt->mangled_dev_name);
|
free(dmt->mangled_dev_name);
|
||||||
free(dmt->newname);
|
free(dmt->newname);
|
||||||
@@ -599,9 +573,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.",
|
||||||
@@ -615,7 +603,8 @@ int dm_check_version(void)
|
|||||||
int dm_cookie_supported(void)
|
int dm_cookie_supported(void)
|
||||||
{
|
{
|
||||||
return (dm_check_version() &&
|
return (dm_check_version() &&
|
||||||
((_dm_version == 4) ? _dm_version_minor >= 15 : _dm_version > 4));
|
_dm_version >= 4 &&
|
||||||
|
_dm_version_minor >= 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _dm_inactive_supported(void)
|
static int _dm_inactive_supported(void)
|
||||||
@@ -660,7 +649,7 @@ void *dm_get_next_target(struct dm_task *dmt, void *next,
|
|||||||
return t->next;
|
return t->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unmarshal the target info returned from a status call */
|
/* Unmarshall the target info returned from a status call */
|
||||||
static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi)
|
static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi)
|
||||||
{
|
{
|
||||||
char *outbuf = (char *) dmi + dmi->data_start;
|
char *outbuf = (char *) dmi + dmi->data_start;
|
||||||
@@ -749,131 +738,10 @@ uint32_t dm_task_get_read_ahead(const struct dm_task *dmt, uint32_t *read_ahead)
|
|||||||
|
|
||||||
struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Round up the ptr to an 8-byte boundary.
|
|
||||||
* Follow kernel pattern.
|
|
||||||
*/
|
|
||||||
#define ALIGN_MASK 7
|
|
||||||
static size_t _align_val(size_t val)
|
|
||||||
{
|
|
||||||
return (val + ALIGN_MASK) & ~ALIGN_MASK;
|
|
||||||
}
|
|
||||||
static void *_align_ptr(void *ptr)
|
|
||||||
{
|
|
||||||
return (void *)(uintptr_t)_align_val((size_t)ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _check_has_event_nr(void) {
|
|
||||||
static int _has_event_nr = -1;
|
|
||||||
|
|
||||||
if (_has_event_nr < 0)
|
|
||||||
_has_event_nr = dm_check_version() &&
|
|
||||||
((_dm_version == 4) ? _dm_version_minor >= 38 : _dm_version > 4);
|
|
||||||
|
|
||||||
return _has_event_nr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
|
|
||||||
unsigned *devs_features)
|
|
||||||
{
|
|
||||||
struct dm_names *names, *names1;
|
|
||||||
struct dm_active_device *dm_dev, *dm_new_dev;
|
|
||||||
struct dm_list *devs;
|
|
||||||
unsigned next = 0;
|
|
||||||
uint32_t *event_nr;
|
|
||||||
char *uuid_ptr;
|
|
||||||
size_t len;
|
|
||||||
int cnt = 0;
|
|
||||||
|
|
||||||
*devs_list = 0;
|
|
||||||
*devs_features = 0;
|
|
||||||
|
|
||||||
if ((names = dm_task_get_names(dmt)) && names->dev) {
|
|
||||||
names1 = names;
|
|
||||||
if (!names->name[0])
|
|
||||||
cnt = -1; /* -> cnt == 0 when no device is really present */
|
|
||||||
do {
|
|
||||||
names1 = (struct dm_names *)((char *) names1 + next);
|
|
||||||
next = names1->next;
|
|
||||||
++cnt;
|
|
||||||
} while (next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* buffer for devs + sorted ptrs + dm_devs + aligned strings */
|
|
||||||
if (!(devs = malloc(sizeof(*devs) + cnt * (2 * sizeof(void*) + sizeof(*dm_dev)) +
|
|
||||||
(cnt ? (char*)names1 - (char*)names + 256 : 0))))
|
|
||||||
return_0;
|
|
||||||
|
|
||||||
dm_list_init(devs);
|
|
||||||
|
|
||||||
if (!cnt) {
|
|
||||||
/* nothing in the list -> mark all features present */
|
|
||||||
*devs_features |= (DM_DEVICE_LIST_HAS_EVENT_NR | DM_DEVICE_LIST_HAS_UUID);
|
|
||||||
goto out; /* nothing else to do */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift position where to store individual dm_devs */
|
|
||||||
dm_dev = (struct dm_active_device *) ((long*) (devs + 1) + cnt);
|
|
||||||
|
|
||||||
do {
|
|
||||||
names = (struct dm_names *)((char *) names + next);
|
|
||||||
|
|
||||||
dm_dev->devno = (dev_t) names->dev;
|
|
||||||
dm_dev->name = (const char *)(dm_dev + 1);
|
|
||||||
dm_dev->event_nr = 0;
|
|
||||||
dm_dev->uuid = "";
|
|
||||||
|
|
||||||
len = strlen(names->name) + 1;
|
|
||||||
memcpy((char*)dm_dev->name, names->name, len);
|
|
||||||
|
|
||||||
dm_new_dev = _align_ptr((char*)(dm_dev + 1) + len);
|
|
||||||
if (_check_has_event_nr()) {
|
|
||||||
|
|
||||||
*devs_features |= DM_DEVICE_LIST_HAS_EVENT_NR;
|
|
||||||
event_nr = _align_ptr(names->name + len);
|
|
||||||
dm_dev->event_nr = event_nr[0];
|
|
||||||
|
|
||||||
if ((event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
|
|
||||||
*devs_features |= DM_DEVICE_LIST_HAS_UUID;
|
|
||||||
uuid_ptr = _align_ptr(event_nr + 2);
|
|
||||||
len = strlen(uuid_ptr) + 1;
|
|
||||||
memcpy(dm_new_dev, uuid_ptr, len);
|
|
||||||
dm_dev->uuid = (const char *) dm_new_dev;
|
|
||||||
dm_new_dev = _align_ptr((char*)dm_new_dev + len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dm_list_add(devs, &dm_dev->list);
|
|
||||||
dm_dev = dm_new_dev;
|
|
||||||
next = names->next;
|
|
||||||
} while (next);
|
|
||||||
|
|
||||||
out:
|
|
||||||
*devs_list = devs;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dm_device_list_destroy(struct dm_list **devs_list)
|
|
||||||
{
|
|
||||||
struct dm_device_list *devs = (struct dm_device_list *) *devs_list;
|
|
||||||
|
|
||||||
if (devs) {
|
|
||||||
free(devs);
|
|
||||||
*devs_list = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dm_names *dm_task_get_names(struct dm_task *dmt)
|
struct dm_names *dm_task_get_names(struct dm_task *dmt)
|
||||||
{
|
{
|
||||||
return (struct dm_names *) (((char *) dmt->dmi.v4) +
|
return (struct dm_names *) (((char *) dmt->dmi.v4) +
|
||||||
@@ -930,11 +798,6 @@ int dm_task_suppress_identical_reload(struct dm_task *dmt)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dm_task_skip_reload_params_compare(struct dm_task *dmt)
|
|
||||||
{
|
|
||||||
dmt->skip_reload_params_compare = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dm_task_set_add_node(struct dm_task *dmt, dm_add_node_t add_node)
|
int dm_task_set_add_node(struct dm_task *dmt, dm_add_node_t add_node)
|
||||||
{
|
{
|
||||||
switch (add_node) {
|
switch (add_node) {
|
||||||
@@ -1045,13 +908,6 @@ int dm_task_secure_data(struct dm_task *dmt)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dm_task_ima_measurement(struct dm_task *dmt)
|
|
||||||
{
|
|
||||||
dmt->ima_measurement = 1;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dm_task_retry_remove(struct dm_task *dmt)
|
int dm_task_retry_remove(struct dm_task *dmt)
|
||||||
{
|
{
|
||||||
dmt->retry_remove = 1;
|
dmt->retry_remove = 1;
|
||||||
@@ -1161,10 +1017,9 @@ static char *_add_target(struct target *t, char *out, char *end)
|
|||||||
while (*pt)
|
while (*pt)
|
||||||
if (*pt++ == '\\')
|
if (*pt++ == '\\')
|
||||||
backslash_count++;
|
backslash_count++;
|
||||||
|
len = strlen(t->params) + backslash_count;
|
||||||
|
|
||||||
len = strlen(t->params) + 1;
|
if ((out >= end) || (out + len + 1) >= end) {
|
||||||
|
|
||||||
if ((out >= end) || (out + len + backslash_count) >= end) {
|
|
||||||
log_error("Ran out of memory building ioctl parameter");
|
log_error("Ran out of memory building ioctl parameter");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1180,8 +1035,8 @@ static char *_add_target(struct target *t, char *out, char *end)
|
|||||||
*out++ = '\0';
|
*out++ = '\0';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memcpy(out, t->params, len);
|
strcpy(out, t->params);
|
||||||
out += len + backslash_count;
|
out += len + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* align next block */
|
/* align next block */
|
||||||
@@ -1215,7 +1070,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;
|
||||||
}
|
}
|
||||||
@@ -1227,56 +1082,23 @@ static int _lookup_dev_name(uint64_t dev, char *buf, size_t len)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _add_params(int type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case DM_DEVICE_REMOVE_ALL:
|
|
||||||
case DM_DEVICE_CREATE:
|
|
||||||
case DM_DEVICE_REMOVE:
|
|
||||||
case DM_DEVICE_SUSPEND:
|
|
||||||
case DM_DEVICE_STATUS:
|
|
||||||
case DM_DEVICE_CLEAR:
|
|
||||||
case DM_DEVICE_ARM_POLL:
|
|
||||||
return 0; /* IOCTL_FLAGS_NO_PARAMS in drivers/md/dm-ioctl.c */
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||||
{
|
{
|
||||||
size_t min_size;
|
const size_t min_size = 16 * 1024;
|
||||||
const int (*version)[3];
|
const int (*version)[3];
|
||||||
|
|
||||||
struct dm_ioctl *dmi;
|
struct dm_ioctl *dmi;
|
||||||
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;
|
||||||
|
|
||||||
if (_add_params(dmt->type))
|
|
||||||
for (t = dmt->head; t; t = t->next) {
|
for (t = dmt->head; t; t = t->next) {
|
||||||
len += sizeof(struct dm_target_spec);
|
len += sizeof(struct dm_target_spec);
|
||||||
len += strlen(t->params) + 1 + ALIGNMENT;
|
len += strlen(t->params) + 1 + ALIGNMENT;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
else if (dmt->head)
|
|
||||||
log_debug_activation(INTERNAL_ERROR "dm '%s' ioctl should not define parameters.",
|
|
||||||
_cmd_data_v4[dmt->type].name);
|
|
||||||
switch (dmt->type) {
|
|
||||||
case DM_DEVICE_CREATE:
|
|
||||||
case DM_DEVICE_DEPS:
|
|
||||||
case DM_DEVICE_LIST:
|
|
||||||
case DM_DEVICE_STATUS:
|
|
||||||
case DM_DEVICE_TABLE:
|
|
||||||
case DM_DEVICE_TARGET_MSG:
|
|
||||||
min_size = 16 * 1024;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
min_size = 2 * 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count && (dmt->sector || dmt->message)) {
|
if (count && (dmt->sector || dmt->message)) {
|
||||||
log_error("targets and message are incompatible");
|
log_error("targets and message are incompatible");
|
||||||
@@ -1313,20 +1135,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
|
||||||
@@ -1366,7 +1182,7 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dmi->flags |= DM_PERSISTENT_DEV_FLAG;
|
dmi->flags |= DM_PERSISTENT_DEV_FLAG;
|
||||||
dmi->dev = MKDEV(dmt->major, dmt->minor);
|
dmi->dev = MKDEV((dev_t)dmt->major, (dev_t)dmt->minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Does driver support device number referencing? */
|
/* Does driver support device number referencing? */
|
||||||
@@ -1384,10 +1200,10 @@ 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));
|
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));
|
strncpy(dmi->uuid, DEV_UUID(dmt), sizeof(dmi->uuid));
|
||||||
|
|
||||||
if (dmt->type == DM_DEVICE_SUSPEND)
|
if (dmt->type == DM_DEVICE_SUSPEND)
|
||||||
dmi->flags |= DM_SUSPEND_FLAG;
|
dmi->flags |= DM_SUSPEND_FLAG;
|
||||||
@@ -1413,27 +1229,18 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
|||||||
}
|
}
|
||||||
if (dmt->query_inactive_table) {
|
if (dmt->query_inactive_table) {
|
||||||
if (!_dm_inactive_supported())
|
if (!_dm_inactive_supported())
|
||||||
log_warn_suppress(_dm_warn_inactive_suppress++,
|
log_warn("WARNING: Inactive table query unsupported "
|
||||||
"WARNING: Inactive table query unsupported by kernel. "
|
"by kernel. It will use live table.");
|
||||||
"It will use live table.");
|
|
||||||
dmi->flags |= DM_QUERY_INACTIVE_TABLE_FLAG;
|
dmi->flags |= DM_QUERY_INACTIVE_TABLE_FLAG;
|
||||||
}
|
}
|
||||||
if (dmt->new_uuid) {
|
if (dmt->new_uuid) {
|
||||||
if (_dm_version_minor < 19) {
|
if (_dm_version_minor < 19) {
|
||||||
log_error("Setting UUID unsupported by kernel. "
|
log_error("WARNING: Setting UUID unsupported by "
|
||||||
"Aborting operation.");
|
"kernel. Aborting operation.");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
dmi->flags |= DM_UUID_FLAG;
|
dmi->flags |= DM_UUID_FLAG;
|
||||||
}
|
}
|
||||||
if (dmt->ima_measurement) {
|
|
||||||
if (_dm_version_minor < 45) {
|
|
||||||
log_error("IMA measurement unsupported by kernel. "
|
|
||||||
"Aborting operation.");
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
dmi->flags |= DM_IMA_MEASUREMENT_FLAG;
|
|
||||||
}
|
|
||||||
|
|
||||||
dmi->target_count = count;
|
dmi->target_count = count;
|
||||||
dmi->event_nr = dmt->event_nr;
|
dmi->event_nr = dmt->event_nr;
|
||||||
@@ -1441,22 +1248,21 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
|||||||
b = (char *) (dmi + 1);
|
b = (char *) (dmi + 1);
|
||||||
e = (char *) dmi + len;
|
e = (char *) dmi + len;
|
||||||
|
|
||||||
if (_add_params(dmt->type))
|
|
||||||
for (t = dmt->head; t; t = t->next)
|
for (t = dmt->head; t; t = t->next)
|
||||||
if (!(b = _add_target(t, b, e)))
|
if (!(b = _add_target(t, b, e)))
|
||||||
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;
|
||||||
|
|
||||||
@@ -1495,7 +1301,7 @@ static int _process_mapper_dir(struct dm_task *dmt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (closedir(d))
|
if (closedir(d))
|
||||||
log_sys_debug("closedir", dir);
|
log_sys_error("closedir", dir);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -1567,7 +1373,8 @@ static int _udev_complete(struct dm_task *dmt)
|
|||||||
static int _check_uevent_generated(struct dm_ioctl *dmi)
|
static int _check_uevent_generated(struct dm_ioctl *dmi)
|
||||||
{
|
{
|
||||||
if (!dm_check_version() ||
|
if (!dm_check_version() ||
|
||||||
((_dm_version == 4) ? _dm_version_minor < 17 : _dm_version < 4))
|
_dm_version < 4 ||
|
||||||
|
_dm_version_minor < 17)
|
||||||
/* can't check, assume uevent is generated */
|
/* can't check, assume uevent is generated */
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -1578,7 +1385,7 @@ static int _check_uevent_generated(struct dm_ioctl *dmi)
|
|||||||
static int _create_and_load_v4(struct dm_task *dmt)
|
static int _create_and_load_v4(struct dm_task *dmt)
|
||||||
{
|
{
|
||||||
struct dm_task *task;
|
struct dm_task *task;
|
||||||
int r, ioctl_errno = 0;
|
int r;
|
||||||
uint32_t cookie;
|
uint32_t cookie;
|
||||||
|
|
||||||
/* Use new task struct to create the device */
|
/* Use new task struct to create the device */
|
||||||
@@ -1604,10 +1411,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);
|
||||||
|
|
||||||
@@ -1630,11 +1435,8 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
|||||||
task->head = dmt->head;
|
task->head = dmt->head;
|
||||||
task->tail = dmt->tail;
|
task->tail = dmt->tail;
|
||||||
task->secure_data = dmt->secure_data;
|
task->secure_data = dmt->secure_data;
|
||||||
task->ima_measurement = dmt->ima_measurement;
|
|
||||||
|
|
||||||
r = dm_task_run(task);
|
r = dm_task_run(task);
|
||||||
if (!r)
|
|
||||||
ioctl_errno = task->ioctl_errno;
|
|
||||||
|
|
||||||
task->head = NULL;
|
task->head = NULL;
|
||||||
task->tail = NULL;
|
task->tail = NULL;
|
||||||
@@ -1652,8 +1454,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);
|
|
||||||
|
|
||||||
if (dm_task_run(dmt))
|
if (dm_task_run(dmt))
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1664,8 +1464,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);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Also udev-synchronize "remove" dm task that is a part of this revert!
|
* Also udev-synchronize "remove" dm task that is a part of this revert!
|
||||||
@@ -1683,18 +1481,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1753,36 +1545,11 @@ static int _reload_with_suppression_v4(struct dm_task *dmt)
|
|||||||
len = strlen(t2->params);
|
len = strlen(t2->params);
|
||||||
while (len-- > 0 && t2->params[len] == ' ')
|
while (len-- > 0 && t2->params[len] == ' ')
|
||||||
t2->params[len] = '\0';
|
t2->params[len] = '\0';
|
||||||
|
if ((t1->start != t2->start) ||
|
||||||
if (t1->start != t2->start) {
|
(t1->length != t2->length) ||
|
||||||
log_debug("reload %u:%u diff start %llu %llu type %s %s", task->major, task->minor,
|
(strcmp(t1->type, t2->type)) ||
|
||||||
(unsigned long long)t1->start, (unsigned long long)t2->start, t1->type, t2->type);
|
(strcmp(t1->params, t2->params)))
|
||||||
goto no_match;
|
goto no_match;
|
||||||
}
|
|
||||||
if (t1->length != t2->length) {
|
|
||||||
log_debug("reload %u:%u diff length %llu %llu type %s %s", task->major, task->minor,
|
|
||||||
(unsigned long long)t1->length, (unsigned long long)t2->length, t1->type, t2->type);
|
|
||||||
goto no_match;
|
|
||||||
}
|
|
||||||
if (strcmp(t1->type, t2->type)) {
|
|
||||||
log_debug("reload %u:%u diff type %s %s", task->major, task->minor, t1->type, t2->type);
|
|
||||||
goto no_match;
|
|
||||||
}
|
|
||||||
if (strcmp(t1->params, t2->params)) {
|
|
||||||
if (dmt->skip_reload_params_compare) {
|
|
||||||
log_debug("reload %u:%u diff params ignore for type %s",
|
|
||||||
task->major, task->minor, t1->type);
|
|
||||||
log_debug("reload params1 %s", t1->params);
|
|
||||||
log_debug("reload params2 %s", t2->params);
|
|
||||||
} else {
|
|
||||||
log_debug("reload %u:%u diff params for type %s",
|
|
||||||
task->major, task->minor, t1->type);
|
|
||||||
log_debug("reload params1 %s", t1->params);
|
|
||||||
log_debug("reload params2 %s", t2->params);
|
|
||||||
goto no_match;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
t1 = t1->next;
|
t1 = t1->next;
|
||||||
t2 = t2->next;
|
t2 = t2->next;
|
||||||
}
|
}
|
||||||
@@ -1945,34 +1712,23 @@ static int _do_dm_ioctl_unmangle_string(char *str, const char *str_name,
|
|||||||
static int _dm_ioctl_unmangle_names(int type, struct dm_ioctl *dmi)
|
static int _dm_ioctl_unmangle_names(int type, struct dm_ioctl *dmi)
|
||||||
{
|
{
|
||||||
char buf[DM_NAME_LEN];
|
char buf[DM_NAME_LEN];
|
||||||
char buf_uuid[DM_UUID_LEN];
|
struct dm_names *names;
|
||||||
struct dm_name_list *names;
|
|
||||||
unsigned next = 0;
|
unsigned next = 0;
|
||||||
char *name;
|
char *name;
|
||||||
int r = 1;
|
int r = 1;
|
||||||
uint32_t *event_nr;
|
|
||||||
char *uuid_ptr;
|
|
||||||
dm_string_mangling_t mangling_mode = dm_get_name_mangling_mode();
|
|
||||||
|
|
||||||
if ((name = dmi->name))
|
if ((name = dmi->name))
|
||||||
r &= _do_dm_ioctl_unmangle_string(name, "name", buf, sizeof(buf),
|
r = _do_dm_ioctl_unmangle_string(name, "name", buf, sizeof(buf),
|
||||||
mangling_mode);
|
dm_get_name_mangling_mode());
|
||||||
|
|
||||||
if (type == DM_DEVICE_LIST &&
|
if (type == DM_DEVICE_LIST &&
|
||||||
((names = ((struct dm_name_list *) ((char *)dmi + dmi->data_start)))) &&
|
((names = ((struct dm_names *) ((char *)dmi + dmi->data_start)))) &&
|
||||||
names->dev) {
|
names->dev) {
|
||||||
do {
|
do {
|
||||||
names = (struct dm_name_list *)((char *) names + next);
|
names = (struct dm_names *)((char *) names + next);
|
||||||
event_nr = _align_ptr(names->name + strlen(names->name) + 1);
|
r = _do_dm_ioctl_unmangle_string(names->name, "name",
|
||||||
r &= _do_dm_ioctl_unmangle_string(names->name, "name",
|
buf, sizeof(buf),
|
||||||
buf, sizeof(buf), mangling_mode);
|
dm_get_name_mangling_mode());
|
||||||
/* Unmangle also UUID within same loop */
|
|
||||||
if (_check_has_event_nr() &&
|
|
||||||
(event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
|
|
||||||
uuid_ptr = _align_ptr(event_nr + 2);
|
|
||||||
r &= _do_dm_ioctl_unmangle_string(uuid_ptr, "UUID", buf_uuid,
|
|
||||||
sizeof(buf_uuid), mangling_mode);
|
|
||||||
}
|
|
||||||
next = names->next;
|
next = names->next;
|
||||||
} while (next);
|
} while (next);
|
||||||
}
|
}
|
||||||
@@ -2036,7 +1792,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
|||||||
/*
|
/*
|
||||||
* Prevent udev vs. libdevmapper race when processing nodes
|
* Prevent udev vs. libdevmapper race when processing nodes
|
||||||
* and symlinks. This can happen when the udev rules are
|
* and symlinks. This can happen when the udev rules are
|
||||||
* installed and udev synchronization code is enabled in
|
* installed and udev synchronisation code is enabled in
|
||||||
* libdevmapper but the software using libdevmapper does not
|
* libdevmapper but the software using libdevmapper does not
|
||||||
* make use of it (by not calling dm_task_set_cookie before).
|
* make use of it (by not calling dm_task_set_cookie before).
|
||||||
* We need to instruct the udev rules not to be applied at
|
* We need to instruct the udev rules not to be applied at
|
||||||
@@ -2046,7 +1802,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" :
|
||||||
@@ -2065,7 +1821,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
|||||||
}
|
}
|
||||||
|
|
||||||
log_debug_activation("dm %s %s%s %s%s%s %s%.0d%s%.0d%s"
|
log_debug_activation("dm %s %s%s %s%s%s %s%.0d%s%.0d%s"
|
||||||
"%s[ %s%s%s%s%s%s%s%s%s%s] %.0" PRIu64 " %s [%u] (*%u)",
|
"%s[ %s%s%s%s%s%s%s%s%s] %.0" PRIu64 " %s [%u] (*%u)",
|
||||||
_cmd_data_v4[dmt->type].name,
|
_cmd_data_v4[dmt->type].name,
|
||||||
dmt->new_uuid ? "UUID " : "",
|
dmt->new_uuid ? "UUID " : "",
|
||||||
dmi->name, dmi->uuid, dmt->newname ? " " : "",
|
dmi->name, dmi->uuid, dmt->newname ? " " : "",
|
||||||
@@ -2083,7 +1839,6 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
|||||||
dmt->retry_remove ? "retryremove " : "",
|
dmt->retry_remove ? "retryremove " : "",
|
||||||
dmt->deferred_remove ? "deferredremove " : "",
|
dmt->deferred_remove ? "deferredremove " : "",
|
||||||
dmt->secure_data ? "securedata " : "",
|
dmt->secure_data ? "securedata " : "",
|
||||||
dmt->ima_measurement ? "ima_measurement " : "",
|
|
||||||
dmt->query_inactive_table ? "inactive " : "",
|
dmt->query_inactive_table ? "inactive " : "",
|
||||||
dmt->enable_checks ? "enablechecks " : "",
|
dmt->enable_checks ? "enablechecks " : "",
|
||||||
dmt->sector, _sanitise_message(dmt->message),
|
dmt->sector, _sanitise_message(dmt->message),
|
||||||
@@ -2376,3 +2131,52 @@ void dm_lib_exit(void)
|
|||||||
_version_ok = 1;
|
_version_ok = 1;
|
||||||
_version_checked = 0;
|
_version_checked = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
/*
|
||||||
|
* Maintain binary backward compatibility.
|
||||||
|
* Version script mechanism works with 'gcc' compatible compilers only.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This following code is here to retain ABI compatibility after adding
|
||||||
|
* the field deferred_remove to struct dm_info in version 1.02.89.
|
||||||
|
*
|
||||||
|
* Binaries linked against version 1.02.88 of libdevmapper or earlier
|
||||||
|
* will use this function that returns dm_info without the
|
||||||
|
* deferred_remove field.
|
||||||
|
*
|
||||||
|
* Binaries compiled against version 1.02.89 onwards will use
|
||||||
|
* the new function dm_task_get_info_with_deferred_remove due to the
|
||||||
|
* #define.
|
||||||
|
*
|
||||||
|
* N.B. Keep this function at the end of the file to make sure that
|
||||||
|
* no code in this file accidentally calls it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int dm_task_get_info_base(struct dm_task *dmt, struct dm_info *info);
|
||||||
|
int dm_task_get_info_base(struct dm_task *dmt, struct dm_info *info)
|
||||||
|
{
|
||||||
|
struct dm_info new_info;
|
||||||
|
|
||||||
|
if (!dm_task_get_info(dmt, &new_info))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(info, &new_info, offsetof(struct dm_info, deferred_remove));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dm_task_get_info_with_deferred_remove(struct dm_task *dmt, struct dm_info *info);
|
||||||
|
int dm_task_get_info_with_deferred_remove(struct dm_task *dmt, struct dm_info *info)
|
||||||
|
{
|
||||||
|
struct dm_info new_info;
|
||||||
|
|
||||||
|
if (!dm_task_get_info(dmt, &new_info))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(info, &new_info, offsetof(struct dm_info, internal_suspend));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user