mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-11-04 12:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			main
			...
			dev-dct-no
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					556889f170 | 
							
								
								
									
										32
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										32
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -14,14 +14,8 @@
 | 
			
		||||
*.so
 | 
			
		||||
*.so.*
 | 
			
		||||
*.sw*
 | 
			
		||||
*.su
 | 
			
		||||
*.patch
 | 
			
		||||
*~
 | 
			
		||||
 | 
			
		||||
# gcov files:
 | 
			
		||||
*.gcda
 | 
			
		||||
*.gcno
 | 
			
		||||
 | 
			
		||||
.export.sym
 | 
			
		||||
.exported_symbols_generated
 | 
			
		||||
.gdb_history
 | 
			
		||||
@@ -45,19 +39,12 @@ make.tmpl
 | 
			
		||||
 | 
			
		||||
coverity/coverity_model.xml
 | 
			
		||||
 | 
			
		||||
/.cache/
 | 
			
		||||
/compile_commands.json
 | 
			
		||||
 | 
			
		||||
/doc/.ikiwiki
 | 
			
		||||
/public
 | 
			
		||||
 | 
			
		||||
/libdm/.symver_check
 | 
			
		||||
 | 
			
		||||
daemons/clvmd
 | 
			
		||||
daemons/dmfilemapd
 | 
			
		||||
daemons/lvmetad/
 | 
			
		||||
# gcov files:
 | 
			
		||||
*.gcda
 | 
			
		||||
*.gcno
 | 
			
		||||
 | 
			
		||||
tools/man-generator
 | 
			
		||||
tools/man-generator.c
 | 
			
		||||
 | 
			
		||||
test/.lib-dir-stamp
 | 
			
		||||
test/.tests-stamp
 | 
			
		||||
@@ -115,8 +102,6 @@ test/api/thin_percent.t
 | 
			
		||||
test/api/vglist.t
 | 
			
		||||
test/api/vgtest.t
 | 
			
		||||
test/lib/aux
 | 
			
		||||
test/lib/cache-mq.profile
 | 
			
		||||
test/lib/cache-smq.profile
 | 
			
		||||
test/lib/check
 | 
			
		||||
test/lib/clvmd
 | 
			
		||||
test/lib/dm-version-expected
 | 
			
		||||
@@ -126,7 +111,6 @@ test/lib/dmstats
 | 
			
		||||
test/lib/fail
 | 
			
		||||
test/lib/flavour-ndev-cluster
 | 
			
		||||
test/lib/flavour-ndev-cluster-lvmpolld
 | 
			
		||||
test/lib/flavour-ndev-devicesfile
 | 
			
		||||
test/lib/flavour-ndev-lvmetad
 | 
			
		||||
test/lib/flavour-ndev-lvmetad-lvmpolld
 | 
			
		||||
test/lib/flavour-ndev-lvmpolld
 | 
			
		||||
@@ -136,7 +120,6 @@ test/lib/flavour-udev-cluster-lvmpolld
 | 
			
		||||
test/lib/flavour-udev-lvmetad
 | 
			
		||||
test/lib/flavour-udev-lvmetad-lvmpolld
 | 
			
		||||
test/lib/flavour-udev-lvmlockd-dlm
 | 
			
		||||
test/lib/flavour-udev-lvmlockd-idm
 | 
			
		||||
test/lib/flavour-udev-lvmlockd-sanlock
 | 
			
		||||
test/lib/flavour-udev-lvmlockd-test
 | 
			
		||||
test/lib/flavour-udev-lvmpolld
 | 
			
		||||
@@ -149,13 +132,8 @@ test/lib/lvm
 | 
			
		||||
test/lib/lvm-wrapper
 | 
			
		||||
test/lib/lvmchange
 | 
			
		||||
test/lib/lvmdbusd.profile
 | 
			
		||||
test/lib/lvmdevices
 | 
			
		||||
test/lib/lvmetad
 | 
			
		||||
test/lib/lvmlockctl
 | 
			
		||||
test/lib/lvmlockd
 | 
			
		||||
test/lib/lvmpolld
 | 
			
		||||
test/lib/lvm_import_vdo
 | 
			
		||||
test/lib/lvm_vdo_wrapper
 | 
			
		||||
test/lib/not
 | 
			
		||||
test/lib/paths
 | 
			
		||||
test/lib/paths-common
 | 
			
		||||
@@ -165,7 +143,5 @@ test/lib/test
 | 
			
		||||
test/lib/thin-performance.profile
 | 
			
		||||
test/lib/utils
 | 
			
		||||
test/lib/version-expected
 | 
			
		||||
test/lib/vgimportdevices
 | 
			
		||||
 | 
			
		||||
test/unit/dmraid_t.c
 | 
			
		||||
test/unit/unit-test
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								Makefile.in
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								Makefile.in
									
									
									
									
									
								
							@@ -38,7 +38,7 @@ ifeq ($(MAKECMDGOALS),distclean)
 | 
			
		||||
    udev po
 | 
			
		||||
tools.distclean: test.distclean
 | 
			
		||||
endif
 | 
			
		||||
DISTCLEAN_DIRS += lcov_reports* autom4te.cache
 | 
			
		||||
DISTCLEAN_DIRS += lcov_reports*
 | 
			
		||||
DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
 | 
			
		||||
 | 
			
		||||
include make.tmpl
 | 
			
		||||
@@ -47,7 +47,7 @@ include $(top_srcdir)/base/Makefile
 | 
			
		||||
include $(top_srcdir)/device_mapper/Makefile
 | 
			
		||||
include $(top_srcdir)/test/unit/Makefile
 | 
			
		||||
 | 
			
		||||
lib: include libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
 | 
			
		||||
lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
 | 
			
		||||
daemons: lib libdaemon tools
 | 
			
		||||
scripts: lib
 | 
			
		||||
tools: lib libdaemon
 | 
			
		||||
@@ -55,7 +55,7 @@ po: tools daemons
 | 
			
		||||
man: tools
 | 
			
		||||
all_man: tools
 | 
			
		||||
test: tools daemons
 | 
			
		||||
unit-test  run-unit-test: test libdm
 | 
			
		||||
unit-test  run-unit-test: test
 | 
			
		||||
 | 
			
		||||
daemons.device-mapper: libdm.device-mapper
 | 
			
		||||
tools.device-mapper: libdm.device-mapper
 | 
			
		||||
@@ -127,14 +127,12 @@ all_man:
 | 
			
		||||
 | 
			
		||||
install_system_dirs:
 | 
			
		||||
	$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
 | 
			
		||||
	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)/devices
 | 
			
		||||
	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
 | 
			
		||||
	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_BACKUP_DIR)
 | 
			
		||||
	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_CACHE_DIR)
 | 
			
		||||
	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_LOCK_DIR)
 | 
			
		||||
	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR)
 | 
			
		||||
	$(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache
 | 
			
		||||
	$(INSTALL_ROOT_DIR) $(DESTDIR)/var/lib/lvm
 | 
			
		||||
 | 
			
		||||
install_initscripts:
 | 
			
		||||
	$(MAKE) -C scripts install_initscripts
 | 
			
		||||
@@ -173,7 +171,6 @@ help:
 | 
			
		||||
	@echo "  lcov-dated		Generate lcov with timedate suffix."
 | 
			
		||||
	@echo "  lcov-reset		Reset lcov counters"
 | 
			
		||||
	@echo "  man			Build man pages."
 | 
			
		||||
	@echo "  print-VARIABLE 	Resolve make variable."
 | 
			
		||||
	@echo "  rpm			Build rpm."
 | 
			
		||||
	@echo "  run-unit-test		Run unit tests."
 | 
			
		||||
	@echo "  tags			Generate c/etags."
 | 
			
		||||
@@ -195,8 +192,7 @@ ifneq ("$(GENHTML)", "")
 | 
			
		||||
lcov:
 | 
			
		||||
	$(RM) -rf $(LCOV_REPORTS_DIR)
 | 
			
		||||
	$(MKDIR_P) $(LCOV_REPORTS_DIR)
 | 
			
		||||
	-find . -name '*.gc[dn][ao]' ! -newer make.tmpl -delete
 | 
			
		||||
	-$(LCOV) --capture --directory $(top_builddir) --ignore-errors source,negative,gcov \
 | 
			
		||||
	$(LCOV) --capture --directory $(top_builddir) --ignore-errors source \
 | 
			
		||||
		--output-file $(LCOV_REPORTS_DIR)/out.info
 | 
			
		||||
	-test ! -s $(LCOV_REPORTS_DIR)/out.info || \
 | 
			
		||||
		$(GENHTML) -o $(LCOV_REPORTS_DIR) --ignore-errors source \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								README
									
									
									
									
									
								
							@@ -1,5 +1,7 @@
 | 
			
		||||
This tree contains the LVM2 and device-mapper tools and libraries.
 | 
			
		||||
 | 
			
		||||
This is development branch, for stable 2.02 release see stable-2.02 branch.
 | 
			
		||||
 | 
			
		||||
For more information about LVM2 read the changelog in the WHATS_NEW file.
 | 
			
		||||
Installation instructions are in INSTALL.
 | 
			
		||||
 | 
			
		||||
@@ -10,30 +12,20 @@ Tarballs are available from:
 | 
			
		||||
  https://github.com/lvmteam/lvm2/releases
 | 
			
		||||
 | 
			
		||||
The source code is stored in git:
 | 
			
		||||
  https://gitlab.com/lvmteam/lvm2
 | 
			
		||||
Clone:
 | 
			
		||||
  git clone git@gitlab.com:lvmteam/lvm2.git
 | 
			
		||||
Anonymous access:
 | 
			
		||||
  git clone https://gitlab.com/lvmteam/lvm2.git
 | 
			
		||||
Mirrored to:
 | 
			
		||||
* https://github.com/lvmteam/lvm2
 | 
			
		||||
  https://sourceware.org/git/?p=lvm2.git
 | 
			
		||||
  git clone git://sourceware.org/git/lvm2.git
 | 
			
		||||
mirrored to:
 | 
			
		||||
  https://github.com/lvmteam/lvm2
 | 
			
		||||
  git clone https://github.com/lvmteam/lvm2.git
 | 
			
		||||
  git clone git@github.com:lvmteam/lvm2.git
 | 
			
		||||
* https://sourceware.org/git/?p=lvm2.git
 | 
			
		||||
  git clone https://sourceware.org/git/lvm2.git
 | 
			
		||||
  git clone git://sourceware.org/git/lvm2.git
 | 
			
		||||
 | 
			
		||||
Mailing list for general discussion related to LVM2:
 | 
			
		||||
  linux-lvm@lists.linux.dev
 | 
			
		||||
  Subscribe via email to: linux-lvm+subscribe@lists.linux.dev
 | 
			
		||||
  Archive https://lore.kernel.org/linux-lvm/
 | 
			
		||||
  Older archive https://listman.redhat.com/archives/linux-lvm/
 | 
			
		||||
  linux-lvm@redhat.com
 | 
			
		||||
  Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm
 | 
			
		||||
 | 
			
		||||
Mailing lists for LVM2 development, patches and commits:
 | 
			
		||||
  lvm-devel@lists.linux.dev
 | 
			
		||||
  Subscribe via email to: lvm-devel+subscribe@lists.linux.dev
 | 
			
		||||
  Archive https://lore.kernel.org/lvm-devel/
 | 
			
		||||
  Older archive https://listman.redhat.com/archives/lvm-devel/
 | 
			
		||||
  lvm-devel@redhat.com
 | 
			
		||||
  Subscribe from https://www.redhat.com/mailman/listinfo/lvm-devel
 | 
			
		||||
 | 
			
		||||
  lvm2-commits@lists.fedorahosted.org (Read-only archive of commits)
 | 
			
		||||
  Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits
 | 
			
		||||
@@ -49,7 +41,6 @@ Website:
 | 
			
		||||
Report upstream bugs at:
 | 
			
		||||
  https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper
 | 
			
		||||
or open issues at:
 | 
			
		||||
  https://gitlab.com/groups/lvmteam/-/issues
 | 
			
		||||
  https://github.com/lvmteam/lvm2/issues
 | 
			
		||||
 | 
			
		||||
The source code repository used until 7th June 2012 is accessible using CVS:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								TESTING
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								TESTING
									
									
									
									
									
								
							@@ -21,15 +21,10 @@ You MUST disable (or mask) any LVM daemons:
 | 
			
		||||
- clvmd
 | 
			
		||||
- cmirrord
 | 
			
		||||
 | 
			
		||||
Some lvm.conf options should be set:
 | 
			
		||||
 | 
			
		||||
- global/event_activation = 0
 | 
			
		||||
- activation/monitoring = 0
 | 
			
		||||
 | 
			
		||||
For running cluster tests, we are using singlenode locking. Pass
 | 
			
		||||
`--with-clvmd=singlenode` to configure.
 | 
			
		||||
 | 
			
		||||
NOTE: This is useful only for testing, and should not be used in production
 | 
			
		||||
NOTE: This is useful only for testing, and should not be used in produciton
 | 
			
		||||
code.
 | 
			
		||||
 | 
			
		||||
To run D-Bus daemon tests, existing D-Bus session is required.
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
1.02.211-git (2025-10-24)
 | 
			
		||||
1.02.183-git (2021-10-20)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										473
									
								
								WHATS_NEW
									
									
									
									
									
								
							
							
						
						
									
										473
									
								
								WHATS_NEW
									
									
									
									
									
								
							@@ -1,320 +1,5 @@
 | 
			
		||||
Version 2.03.37 - 
 | 
			
		||||
==================
 | 
			
		||||
  Add missing synchronization while converting cachevols.
 | 
			
		||||
  Warn on classic snapshot on raid creation and error on activation + test.
 | 
			
		||||
  Translate udev device paths in lvmdbusd for test environments.
 | 
			
		||||
  Use source='udev' in lvmdbusd to monitor processed udev events.
 | 
			
		||||
  Symlink to /dev nodes when using alternative dev dir to trigger udev.
 | 
			
		||||
  Avoid passing uninitilized buffer in dmeventd to fix valgrind report.
 | 
			
		||||
  Improve lvmdbusd matching of udevd reported device paths.
 | 
			
		||||
 | 
			
		||||
Version 2.03.36 - 24th October 2025
 | 
			
		||||
Version 2.03.15 - 
 | 
			
		||||
===================================
 | 
			
		||||
  Fix uninitialized chunk_size_calc_policy in pool parameter functions.
 | 
			
		||||
  Fix approximate allocation for Raid with insufficient extents.
 | 
			
		||||
  Fix race in dmeventd remonitoring optimization (2.03.35).
 | 
			
		||||
  Use -real suffix for pvmove UUID.
 | 
			
		||||
  Add support pvmove segmentation allocation/pvmove_max_segmentation_size_mb.
 | 
			
		||||
  Allow creating _imeta with multiple segments.
 | 
			
		||||
  Fix driver_version() accepts NULL version buffer pointer.
 | 
			
		||||
  Fix invalid free() call in error path of _add_metadata_area_to_pv().
 | 
			
		||||
  Avoid destroying aio context in forked process.
 | 
			
		||||
  Add lvs -o cache_promotions,cache_promotions fields.
 | 
			
		||||
  Update pvmove logic when moving i.e. raid legs.
 | 
			
		||||
  Display integrity info in lvdisplay.
 | 
			
		||||
  Increase storage size for internal filter chain.
 | 
			
		||||
  Add helper function display_mb_size().
 | 
			
		||||
  Enhance code for adding and removing integrity to RAID volumes.
 | 
			
		||||
  Add code for basic validation of integrity segment.
 | 
			
		||||
  Use -real private suffix for integrity origin and meta volumes.
 | 
			
		||||
  Use -real private suffix for mirror and raid legs.
 | 
			
		||||
  Detect and use existing XFS quota mount options for lvresize --fs resize.
 | 
			
		||||
 | 
			
		||||
Version 2.03.35 - 09th September 2025
 | 
			
		||||
=====================================
 | 
			
		||||
  Fix unlocking devices file only after all PVs are processed.
 | 
			
		||||
  Avoid creating system.devices when deleting entries.
 | 
			
		||||
  Fix existing issues with persistent reservations.
 | 
			
		||||
  Fix possible report output format inconsistencies while processing PVs.
 | 
			
		||||
  Allow report options for pv/vg/lvdisplay only if used with -C|--columns.
 | 
			
		||||
  Fix vgsplit failing to split a VG with RAID+integrity or cache with cachevol.
 | 
			
		||||
  Fix --lockopt handling in lvmlockd when --nolocking is used.
 | 
			
		||||
  Optimize dmeventd when remonitoring active devices.
 | 
			
		||||
 | 
			
		||||
Version 2.03.34 - 30th July 2025
 | 
			
		||||
================================
 | 
			
		||||
  Support dmeventd restart when there are no monitored devices.
 | 
			
		||||
  Dmeventd no longer calls 'action commands' on removed devices.
 | 
			
		||||
  Fix reader of VDO metadata on 32bit architecture.
 | 
			
		||||
  Fix lvmdevices --deldev/--delpvid to error out if devices file not writeable.
 | 
			
		||||
  Fix lvresize corruption in LV->crypt->FS stack if near crypt min size limit.
 | 
			
		||||
  Enhanced lvresize -r support for btrfs.
 | 
			
		||||
  Use glibc standard functions htoX, Xtoh functions for endian conversion.
 | 
			
		||||
  Fix structure copying within sanlock's release_rename().
 | 
			
		||||
  Fix autoactivation on top of loop dev PVs to trigger once for change uevents.
 | 
			
		||||
  Add lvmlockd --lockopt repair to reinitialize corrupted sanlock leases.
 | 
			
		||||
  Fix support for lvcreate -T --setautoactivation.
 | 
			
		||||
  Add lvm.conf global/lvresize_fs_helper_executable.
 | 
			
		||||
  Enable lvm to use persistent reservations on a VG.
 | 
			
		||||
 | 
			
		||||
Version 2.03.33 - 27th June 2025
 | 
			
		||||
================================
 | 
			
		||||
  Various spelling, grammar, formatting, test, and build script improvements.
 | 
			
		||||
  Override LC_NUMERIC locale if unsuitable for json_std report format.
 | 
			
		||||
  Repair raid arrays with transiently lost devices.
 | 
			
		||||
 | 
			
		||||
Version 2.03.32 - 05th May 2025
 | 
			
		||||
===============================
 | 
			
		||||
  Lvconvert vdopool conversion properly validates acceptable LVs.
 | 
			
		||||
  Accept thin pool data LV as cacheable LV.
 | 
			
		||||
  Allow using zram block devices (likely for testing).
 | 
			
		||||
  Fix lvresize when resizing COW snapshots already covering origin.
 | 
			
		||||
  Fix lvmdbusd read of executed lvm commands output.
 | 
			
		||||
  Fix construction of DM UUID for cachevol _cdata and _cmeta devices.
 | 
			
		||||
  Ignore PV claims from old metadata when then PV belongs to a new VG.
 | 
			
		||||
  Fix integrity metadata rounding.
 | 
			
		||||
  Accept --autobackup option in pvresize.
 | 
			
		||||
 | 
			
		||||
Version 2.03.31 - 27th February 2025
 | 
			
		||||
====================================
 | 
			
		||||
  Reduce 'mandoc -T lint' reported issues for man pages.
 | 
			
		||||
  Restore support for LVM_SUPPRESS_FD_WARNINGS (2.03.24).
 | 
			
		||||
  Fix uncache and split cache restoring original state of volume.
 | 
			
		||||
  Extend use of lockopt skip to more scenarios.
 | 
			
		||||
  Enhance error path resolving in polling code.
 | 
			
		||||
  Disallow shared activation of LV with CoW snapshot.
 | 
			
		||||
  Fix lvmlockd use in lvremove of CoW snapshot, VDO pool, and uncache.
 | 
			
		||||
  Improve mirror split with opened temporary volumes.
 | 
			
		||||
  Improve pvmove finish with opened temporary volumes.
 | 
			
		||||
  Fix backup limit for devices file, handle over 10,000 files.
 | 
			
		||||
  Ignore reported optimal_io_size not divisible by 4096.
 | 
			
		||||
  Fix busy-loop in config reading when read returned 0.
 | 
			
		||||
  Fix DM cache preserving logic (2.03.28).
 | 
			
		||||
  Improve use of lvmlockd for usecases involving thin volumes and pools.
 | 
			
		||||
 | 
			
		||||
Version 2.03.30 - 14th January 2025
 | 
			
		||||
===================================
 | 
			
		||||
  Lvresize reports origin vdo volume cannot be resized.
 | 
			
		||||
  Support setting reserved_memory|stack of --config cmdline.
 | 
			
		||||
  Fix support for disabling memory locking (2.03.27).
 | 
			
		||||
  Do not extend an LV if FS resize unsupported and '--fs resize' used.
 | 
			
		||||
  Prevent leftover temporary device when converting in use volume to a pool.
 | 
			
		||||
  lvconvert detects early volume in use when converting it to a pool.
 | 
			
		||||
  Handle NVMe with quirk changed WWID not matching WWID in devices file.
 | 
			
		||||
 | 
			
		||||
Version 2.03.29 - 09th December 2024
 | 
			
		||||
====================================
 | 
			
		||||
  Configure --enable/disable-sd-notify to control lvmlockd build with sd-notify.
 | 
			
		||||
  Allow test mode when lvmlockd is built without dlm support.
 | 
			
		||||
  Add a note about RAID + integrity synchronization to lvmraid(7) man page.
 | 
			
		||||
  Add a function for running lvconvert --repair on RAID LVs to lvmdbusd.
 | 
			
		||||
  Improve option section of man pages for listing commands ({pv,lv,vg}{s,display}).
 | 
			
		||||
  Fix renaming of raid sub LVs when converting a volume to raid (2.03.28).
 | 
			
		||||
  Fix segfault/VG write error for raid LV lvextend -i|--stripes -I|--stripesize.
 | 
			
		||||
  Revert ignore -i|--stripes, -I|--stripesize for lvextend on raid0 LV (2.03.27).
 | 
			
		||||
 | 
			
		||||
Version 2.03.28 - 04th November 2024
 | 
			
		||||
====================================
 | 
			
		||||
  Use radix_tree to lookup for UUID within committed metadata.
 | 
			
		||||
  Use radix_tree to lookup LV list entry within VG struct.
 | 
			
		||||
  Introduce setting config/validate_metadata = full | none.
 | 
			
		||||
  Restore fs resize call for lvresize -r on the same size LV (2.03.17).
 | 
			
		||||
  Correct off-by-one devicesfile backup counting.
 | 
			
		||||
  Replace use of dm_hash with radix_tree for lv names and uuids.
 | 
			
		||||
  Refactor vg_validate with uniq_insert and better use of CPU caches.
 | 
			
		||||
  Add radix_tree_uniq_insert.
 | 
			
		||||
  Update DM cache when taking next VG lock instead of dropping it.
 | 
			
		||||
  Generate json string id only for json reporting.
 | 
			
		||||
  For vgsummary use new API call dm_config_parse_only_section().
 | 
			
		||||
  Use radix_tree for PV names mapping.
 | 
			
		||||
  Split check_lv_segment into separate _in/complete_vg variant.
 | 
			
		||||
  Use find_lv instead of find_lv_in_vg when possible.
 | 
			
		||||
  Do a mirror fixup only when mirrors with logs are imported.
 | 
			
		||||
  Add faster crc32 calculation from zlib code for x86_64.
 | 
			
		||||
  Fall back to direct zeroing if BLKZEROOUT fails during new LV initialization.
 | 
			
		||||
 | 
			
		||||
Version 2.03.27 - 02nd October 2024
 | 
			
		||||
===================================
 | 
			
		||||
  Fix swap device size detection using blkid for lvresize/lvreduce/lvextend.
 | 
			
		||||
  Detect GPT partition table and pass partition filter if no partitions defined.
 | 
			
		||||
  Add global/sanlock_align_size option to configure sanlock lease size.
 | 
			
		||||
  Disable mem locking when activation/reserved_stack or reserved_memory is 0.
 | 
			
		||||
  Fix locking issues in lvmlockd leaving thin pool locked.
 | 
			
		||||
  Deprecate vdo settings vdo_write_policy and vdo_write_policy.
 | 
			
		||||
  Lots of typo fixes across lvm2 code base (codespell).
 | 
			
		||||
  Corrected integrity parameter interleave_sectors for DM table line.
 | 
			
		||||
  Ignore -i|--stripes, -I|--stripesize for lvextend on raid0 LV, like raid10.
 | 
			
		||||
  Do not accept duplicate device names for pvcreate.
 | 
			
		||||
 | 
			
		||||
Version 2.03.26 - 23rd August 2024
 | 
			
		||||
==================================
 | 
			
		||||
  Fix internal error reported by pvmove on a VG with single PV.
 | 
			
		||||
  Also accept --mknodes --refresh for vgscan.
 | 
			
		||||
  Fix vgmknodes --refresh to wait for udev before checking /dev content.
 | 
			
		||||
  Use log/report_command_log=1 config setting by default for JSON output format.
 | 
			
		||||
  Fix unreleased memory pools on RAID lvextend.
 | 
			
		||||
  Add --integritysettings option to manipulate dm-integrity settings.
 | 
			
		||||
 | 
			
		||||
Version 2.03.25 - 12nd July 2024
 | 
			
		||||
================================
 | 
			
		||||
  Utilize more radix_tree instead of dm_hash and btree.
 | 
			
		||||
  Refactor DM uuid caching from device_mapper directory.
 | 
			
		||||
  Enhance checking for DM uuid device.
 | 
			
		||||
  Fix lvm shell command completion on tab key (2.03.24).
 | 
			
		||||
  Avoid lockd_vg call to lvmlockd for local VGs.
 | 
			
		||||
  Allow forced change of locktype from none.
 | 
			
		||||
  Handle OPTIONS defined in /etc/sysconfig/lvmlockd.
 | 
			
		||||
 | 
			
		||||
Version 2.03.24 - 16th May 2024
 | 
			
		||||
===============================
 | 
			
		||||
  Lvconvert supports VDO options for thin-pool with vdo conversion.
 | 
			
		||||
  Improve placement to .data.rel.ro and .rodata sections.
 | 
			
		||||
  Fix support for -y and -W when creating thinpool with vdo.
 | 
			
		||||
  Better support for runtime valgrind detection.
 | 
			
		||||
  Allow command interruption when communicating with dmeventd.
 | 
			
		||||
  Fix resize of VDO volume used for thin pool data volume.
 | 
			
		||||
  Use -Wl,-z,now and -Wl,--as-needed for compilation by default.
 | 
			
		||||
  Require 3.7 as minimal version for sanlock.
 | 
			
		||||
  Share code for closing opened descriptors on program startup.
 | 
			
		||||
  Fix memleak in lvmcache.
 | 
			
		||||
  Add configure --with-default-event-activation=ON setting.
 | 
			
		||||
  Fix return value from reporter function when hitting internal error.
 | 
			
		||||
  Skip checking of pools for lvremove and vgremove commands.
 | 
			
		||||
  VDO modprobes dm-vdo for 6.9 kernel and kvdo for older kernel version.
 | 
			
		||||
  Fix lvs reporting for VDO volumes with new upstream kernel driver.
 | 
			
		||||
  Don't import DM_UDEV_DISABLE_OTHER_RULES_FLAG in LVM rules, DM rules cover it.
 | 
			
		||||
  Fix table line generation for cache snapshots using cachevol.
 | 
			
		||||
  Enhance lvconvert support for external origins stacking.
 | 
			
		||||
  When swapping LV names also swap properties like hostname, time and data.
 | 
			
		||||
  Fix removal of stacked external origins.
 | 
			
		||||
  Lock filesystem when converting volume to read-only external origin.
 | 
			
		||||
  Support external origin between different thin-pool.
 | 
			
		||||
  Improve validation of acceptable volumes for external origins.
 | 
			
		||||
  Reduce amount of preloaded devices for complex device trees.
 | 
			
		||||
  Avoid logging problems from monitoring snapshots with inactive origins.
 | 
			
		||||
  Check for cache policy module presence in kernel's builtin modules file.
 | 
			
		||||
  Add configure --with-modulesdir to select kernel modules directory.
 | 
			
		||||
  Support creation of thin-pool with VDO use for its data volume.
 | 
			
		||||
 | 
			
		||||
Version 2.03.23 - 21st November 2023
 | 
			
		||||
====================================
 | 
			
		||||
  Set the first lv_attr flag for raid integrity images to i or I.
 | 
			
		||||
  Add -A option for pvs and pvscan to show PVs outside devices file.
 | 
			
		||||
  Improve searched_devnames temp file usage to prevent redundant scanning.
 | 
			
		||||
  Change default search_for_devnames from auto to all.
 | 
			
		||||
  Add lvmdevices --refresh to search for missing PVIDs on all devices.
 | 
			
		||||
  Add comparison between old and new entries in lvmdevices --check.
 | 
			
		||||
  Fix device_id matching order - match non-devname first.
 | 
			
		||||
  Fix "lvconvert -m 0" when there is other than first in-sync leg.
 | 
			
		||||
  Use system.devices as default for dmeventd when dmeventd.devices is undefined.
 | 
			
		||||
  Accept WWIDs containing QEMU HARDDISK for device_id.
 | 
			
		||||
  Improve handling of non-standard WWID prefixes used for device_id.
 | 
			
		||||
  Configure automatically enables cmdlib for dmeventd and notify-dbus for dbus.
 | 
			
		||||
  Fix hint calculation for pools with zero or error segment.
 | 
			
		||||
  Configure supports --disable-shared to build only static binaries.
 | 
			
		||||
  Configure supports --without-{blkid|systemd|udev} for easier static build.
 | 
			
		||||
  Refresh device ids if the system changes.
 | 
			
		||||
  Fix pvmove when specifying raid components as moved LVs.
 | 
			
		||||
  Enhance error detection for lvm_import_vdo.
 | 
			
		||||
  Support PV lists with thin lvconvert.
 | 
			
		||||
  Fix support for lvm_import_vdo with SCSI VDO volumes.
 | 
			
		||||
  Fix locking issue leading to hanging concurrent vgchange --refresh.
 | 
			
		||||
  Recognise lvm.conf report/headings=2 for full column names in report headings.
 | 
			
		||||
  Add --headings none|abbrev|full cmd line option to set report headings type.
 | 
			
		||||
  Fix conversion to thin pool using lvmlockd.
 | 
			
		||||
  Fix conversion from thick into thin volume using lvmlockd.
 | 
			
		||||
  Require writable LV for conversion to vdo pool.
 | 
			
		||||
  Fix return value from lvconvert integrity remove.
 | 
			
		||||
  Preserve UUID for pool metadata spare.
 | 
			
		||||
  Preserve UUID for swapped pool metadata.
 | 
			
		||||
  Rewrite validation of device name entries used as device_id.
 | 
			
		||||
 | 
			
		||||
version 2.03.22 - 02nd August 2023
 | 
			
		||||
==================================
 | 
			
		||||
  Fix pv_major/pv_minor report field types so they are integers, not strings.
 | 
			
		||||
  Add lvmdevices --delnotfound to delete entries for missing devices.
 | 
			
		||||
  Always use cachepool name for metadata backup LV for lvconvert --repair.
 | 
			
		||||
  Make metadata backup LVs read-only after pool's lvconvert --repair.
 | 
			
		||||
  Improve VDO and Thin support with lvmlockd.
 | 
			
		||||
  Handle 'lvextend --usepolicies' for pools for all activation variants.
 | 
			
		||||
  Fix memleak in vgchange autoactivation setup.
 | 
			
		||||
  Update py-compile building script.
 | 
			
		||||
  Support conversion from thick to fully provisioned thin LV.
 | 
			
		||||
  Cache/Thin-pool can use error and zero volumes for testing.
 | 
			
		||||
  Individual thin volume can be cached, but cannot take snapshot.
 | 
			
		||||
  Better internal support for handling error and zero target (for testing).
 | 
			
		||||
  Resize COW above trimmed maximal size is does not return error.
 | 
			
		||||
  Support parsing of vdo geometry format version 4.
 | 
			
		||||
  Add lvm.conf thin_restore and cache_restore settings.
 | 
			
		||||
  Handle multiple mounts while resizing volume with a FS.
 | 
			
		||||
  Handle leading/trailing spaces in sys_wwid and sys_serial used by device_id.
 | 
			
		||||
  Enhance lvm_import_vdo and use snapshot when converting VDO volume.
 | 
			
		||||
  Fix parsing of VDO metadata.
 | 
			
		||||
  Fix failing -S|--select for non-reporting cmds if using LV info/status fields.
 | 
			
		||||
  Allow snapshots of raid+integrity LV.
 | 
			
		||||
  Fix multisegment RAID1 allocator to prevent using single disk for more legs.
 | 
			
		||||
 | 
			
		||||
version 2.03.21 - 21st April 2023
 | 
			
		||||
=================================
 | 
			
		||||
  Fix activation of vdo-pool for with 0 length headers (converted pools).
 | 
			
		||||
  Avoid printing internal init messages when creation integration devices.
 | 
			
		||||
  Allow (write)cache over raid+integrity LV.
 | 
			
		||||
 | 
			
		||||
version 2.03.20 - 21st March 2023
 | 
			
		||||
=================================
 | 
			
		||||
  Fix segfault if using -S|--select with log/report_command_log=1 setting.
 | 
			
		||||
  Configure now fails when requested lvmlockd dependencies are missing.
 | 
			
		||||
  Add some configure Gentoo enhancements for static builds.
 | 
			
		||||
 | 
			
		||||
version 2.03.19 - 21st February 2023
 | 
			
		||||
====================================
 | 
			
		||||
  Configure supports --with-systemd-run executed from udev rules.
 | 
			
		||||
  Enhancement for build with MuslC systemd and non-bash system shells (dash).
 | 
			
		||||
  Do not reset SYSTEMD_READY variable in udev for PVs on MD and loop devices.
 | 
			
		||||
  Ensure udev is processing origin LV before its thick snapshots LVs.
 | 
			
		||||
  Fix and improve runtime memory size detection for VDO volumes.
 | 
			
		||||
 | 
			
		||||
version 2.03.18 - 22nd December 2022
 | 
			
		||||
====================================
 | 
			
		||||
  Fix issues reported by coverity scan.
 | 
			
		||||
  Fix warning for thin pool overprovisioning on lvextend (2.03.17).
 | 
			
		||||
  Add support for writecache metadata_only and pause_writeback settings.
 | 
			
		||||
  Fix missing error messages in lvmdbusd.
 | 
			
		||||
 | 
			
		||||
Version 2.03.17 - 10th November 2022
 | 
			
		||||
====================================
 | 
			
		||||
  Add new options (--fs, --fsmode) for FS handling when resizing LVs.
 | 
			
		||||
  Fix 'lvremove -S|--select LV' to not also remove its historical LV right away.
 | 
			
		||||
  Fix lv_active field type to binary so --select and --binary applies properly.
 | 
			
		||||
  Switch to use mallinfo2 and use it only with glibc.
 | 
			
		||||
  Error out in lvm shell if using a cmd argument not supported in the shell.
 | 
			
		||||
  Fix lvm shell's lastlog command to report previous pre-command failures.
 | 
			
		||||
  Keep libaio locked in memory in critical section.
 | 
			
		||||
  Extend VDO and VDOPOOL without flushing and locking fs.
 | 
			
		||||
  Add --valuesonly option to lvmconfig to print only values without keys.
 | 
			
		||||
  Updates configure with recent autoconf tooling.
 | 
			
		||||
  Fix lvconvert --test --type vdo-pool execution.
 | 
			
		||||
  Add json_std output format for more JSON standard compliant version of output.
 | 
			
		||||
  Fix vdo_slab_size_mb value for converted VDO volume.
 | 
			
		||||
  Fix many corner cases in device_id, including handling of S/N duplicates.
 | 
			
		||||
  Fix various issues in lvmdbusd.
 | 
			
		||||
 | 
			
		||||
Version 2.03.16 - 18th May 2022
 | 
			
		||||
===============================
 | 
			
		||||
  Fix segfault when handling selection with historical LVs.
 | 
			
		||||
  Add support --vdosettings with lvcreate, lvconvert, lvchange.
 | 
			
		||||
  Filtering multipath devices respects blacklist setting from multipath
 | 
			
		||||
  configuration.
 | 
			
		||||
  lvmdevices support for removing by device id using --deviceidtype and
 | 
			
		||||
  --deldev.
 | 
			
		||||
  Display writecache block size with lvs -o writecache_block_size.
 | 
			
		||||
  Improve cachesettings description in man lvmcache.
 | 
			
		||||
  Fix losing of delete message on thin-pool extension.
 | 
			
		||||
 | 
			
		||||
Version 2.03.15 - 07th February 2022
 | 
			
		||||
====================================
 | 
			
		||||
  Remove service based autoactivation. global/event_activation = 0 is NOOP.
 | 
			
		||||
  Improve support for metadata profiles for --type writecache.
 | 
			
		||||
  Use cache or active DM device when available with new kernels.
 | 
			
		||||
  Introduce function to utilize UUIDs from DM_DEVICE_LIST.
 | 
			
		||||
  Increase some hash table size to better support large device sets.
 | 
			
		||||
@@ -396,8 +81,8 @@ Version 2.03.12 - 07th May 2021
 | 
			
		||||
  Fix problem with unbound variable usage within fsadm.
 | 
			
		||||
  Fix IMSM MD RAID detection on 4k devices.
 | 
			
		||||
  Check for presence of VDO target before starting any conversion.
 | 
			
		||||
  Support metadata profiles with volume VDO pool conversions.
 | 
			
		||||
  Support -Zn for conversion of already formatted VDO pools.
 | 
			
		||||
  Support metatadata profiles with volume VDO pool conversions.
 | 
			
		||||
  Support -Zn for conversion of already formated VDO pools.
 | 
			
		||||
  Avoid removing LVs on error path of lvconvert during creation volumes.
 | 
			
		||||
  Fix crashing lvdisplay when thin volume was waiting for merge.
 | 
			
		||||
  Support option --errorwhenfull when converting volume to thin-pool.
 | 
			
		||||
@@ -427,7 +112,7 @@ Version 2.03.11 - 08th January 2021
 | 
			
		||||
  Enhance error handling for fsadm and handle correct fsck result.
 | 
			
		||||
  Dmeventd lvm plugin ignores higher reserved_stack lvm.conf values.
 | 
			
		||||
  Support using BLKZEROOUT for clearing devices.
 | 
			
		||||
  Support interruption when wiping LVs.
 | 
			
		||||
  Support interruption when wipping LVs.
 | 
			
		||||
  Support interruption for bcache waiting.
 | 
			
		||||
  Fix bcache when device has too many failing writes.
 | 
			
		||||
  Fix bcache waiting for IO completion with failing disks.
 | 
			
		||||
@@ -470,7 +155,7 @@ Version 2.03.10 - 09th August 2020
 | 
			
		||||
 | 
			
		||||
Version 2.03.09 - 26th March 2020
 | 
			
		||||
=================================
 | 
			
		||||
  Fix formatting of vdopool (vdo_slab_size_mb was smaller by 2 bits).
 | 
			
		||||
  Fix formating of vdopool (vdo_slab_size_mb was smaller by 2 bits).
 | 
			
		||||
  Fix showing of a dm kernel error when uncaching a volume with cachevol.
 | 
			
		||||
 | 
			
		||||
Version 2.03.08 - 11th February 2020
 | 
			
		||||
@@ -554,7 +239,7 @@ Version 2.03.03 - 07th June 2019
 | 
			
		||||
  Ignore foreign and shared PVs for pvscan online files.
 | 
			
		||||
  Add config setting to control fields in debug file and verbose output.
 | 
			
		||||
  Add command[pid] and timestamp to debug file and verbose output.
 | 
			
		||||
  Fix missing growth of _pmspare volume when extending _tmeta volume.
 | 
			
		||||
  Fix missing growth of _pmsmare volume when extending _tmeta volume.
 | 
			
		||||
  Automatically grow thin metadata, when thin data gets too big.
 | 
			
		||||
  Add synchronization with udev before removing cached devices.
 | 
			
		||||
  Add support for caching VDO LVs and VDOPOOL LVs.
 | 
			
		||||
@@ -567,14 +252,14 @@ Version 2.03.03 - 07th June 2019
 | 
			
		||||
  Change scan_lvs default to 0 so LVs are not scanned for PVs.
 | 
			
		||||
  Thin-pool selects power-of-2 chunk size by default.
 | 
			
		||||
  Cache selects power-of-2 chunk size by default.
 | 
			
		||||
  Support resizing for VDOPoolLV and VDOLV.
 | 
			
		||||
  Support reszing for VDOPoolLV and VDOLV.
 | 
			
		||||
  Improve -lXXX%VG modifier which improves cache segment estimation.
 | 
			
		||||
  Ensure migration_threshold for cache is at least 8 chunks.
 | 
			
		||||
  Restore missing man info lvcreate --zero for thin-pools.
 | 
			
		||||
  Drop misleading comment for metadata minimum_io_size for VDO segment.
 | 
			
		||||
  Drop misleadning comment for metadata minimum_io_size for VDO segment.
 | 
			
		||||
  Add device hints to reduce scanning.
 | 
			
		||||
  Introduce LVM_SUPPRESS_SYSLOG to suppress syslog usage by generator.
 | 
			
		||||
  Fix generator querying lvmconfig unpresent config option.
 | 
			
		||||
  Fix generator quering lvmconfig unpresent config option.
 | 
			
		||||
  Fix memleak on bcache error path code.
 | 
			
		||||
  Fix missing unlock on lvm2 dmeventd plugin error path initialization.
 | 
			
		||||
  Improve Makefile dependency tracking.
 | 
			
		||||
@@ -636,7 +321,7 @@ Version 2.02.178-rc1 - 24th May 2018
 | 
			
		||||
  --with-cache switch for ./configure has been removed.
 | 
			
		||||
  Include new unit-test framework and unit tests.
 | 
			
		||||
  Extend validation of region_size for mirror segment.
 | 
			
		||||
  Reload whole device stack when reinitializing mirror log.
 | 
			
		||||
  Reload whole device stack when reinitilizing mirror log.
 | 
			
		||||
  Mirrors without monitoring are WARNING and not blocking on error.
 | 
			
		||||
  Detect too big region_size with clustered mirrors.
 | 
			
		||||
  Fix evaluation of maximal region size for mirror log.
 | 
			
		||||
@@ -681,7 +366,7 @@ Version 2.02.178-rc1 - 24th May 2018
 | 
			
		||||
  Restore pvmove support for wide-clustered active volumes (2.02.177).
 | 
			
		||||
  Avoid non-exclusive activation of exclusive segment types.
 | 
			
		||||
  Fix trimming sibling PVs when doing a pvmove of raid subLVs.
 | 
			
		||||
  Preserve exclusive activation during thin snapshot merge.
 | 
			
		||||
  Preserve exclusive activation during thin snaphost merge.
 | 
			
		||||
  Avoid exceeding array bounds in allocation tag processing.
 | 
			
		||||
  Add --lockopt to common options and add option to skip selected locks.
 | 
			
		||||
 | 
			
		||||
@@ -697,7 +382,7 @@ Version 2.02.177 - 18th December 2017
 | 
			
		||||
  Fix lvmlockd to use pool lock when accessing _tmeta volume.
 | 
			
		||||
  Report expected sanlock_convert errors only when retries fail.
 | 
			
		||||
  Avoid blocking in sanlock_convert on SH to EX lock conversion.
 | 
			
		||||
  Deactivate missing raid LV legs (_rimage_X-missing_Y_Z) on deactivation.
 | 
			
		||||
  Deactivate missing raid LV legs (_rimage_X-missing_Y_Z) on decativation.
 | 
			
		||||
  Skip read-modify-write when entire block is replaced.
 | 
			
		||||
  Categorise I/O with reason annotations in debug messages.
 | 
			
		||||
  Allow extending of raid LVs created with --nosync after a failed repair.
 | 
			
		||||
@@ -719,7 +404,7 @@ Version 2.02.177 - 18th December 2017
 | 
			
		||||
  Check raid reshape flags in vg_validate().
 | 
			
		||||
  Add support for pvmove of cache and snapshot origins.
 | 
			
		||||
  Avoid using precommitted metadata for suspending pvmove tree.
 | 
			
		||||
  Enhance pvmove locking.
 | 
			
		||||
  Ehnance pvmove locking.
 | 
			
		||||
  Deactivate activated LVs on error path when pvmove activation fails.
 | 
			
		||||
  Add "io" to log/debug_classes for logging low-level I/O.
 | 
			
		||||
  Eliminate redundant nested VG metadata in VG struct.
 | 
			
		||||
@@ -809,13 +494,13 @@ Version 2.02.173 - 20th July 2017
 | 
			
		||||
 | 
			
		||||
Version 2.02.172 - 28th June 2017
 | 
			
		||||
=================================
 | 
			
		||||
  Add missing NULL to argv array when splitting cmdline arguments.
 | 
			
		||||
  Add missing NULL to argv array when spliting cmdline arguments.
 | 
			
		||||
  Add display_percent helper function for printing percent values.
 | 
			
		||||
  lvconvert --repair handles failing raid legs (present but marked 'D'ead).
 | 
			
		||||
  Do not lvdisplay --maps unset settings of cache pool.
 | 
			
		||||
  Fix lvdisplay --maps for cache pool without policy settings.
 | 
			
		||||
  Support aborting of flushing cache LV.
 | 
			
		||||
  Re-enable conversion of data and metadata thin-pool volumes to raid.
 | 
			
		||||
  Reenable conversion of data and metadata thin-pool volumes to raid.
 | 
			
		||||
  Improve raid status reporting with lvs.
 | 
			
		||||
  No longer necessary to '--force' a repair for RAID1.
 | 
			
		||||
  Linear to RAID1 upconverts now use "recover" sync action, not "resync".
 | 
			
		||||
@@ -883,7 +568,7 @@ Version 2.02.169 - 28th March 2017
 | 
			
		||||
  Support cache segment with configurable metadata format.
 | 
			
		||||
  Add allocation/cache_metadata_format profilable settings.
 | 
			
		||||
  Use function cache_set_params() for both lvcreate and lvconvert.
 | 
			
		||||
  Skip rounding on cache chunk size boundary when create cache LV.
 | 
			
		||||
  Skip rounding on cache chunk size boudary when create cache LV.
 | 
			
		||||
  Improve cache_set_params support for chunk_size selection.
 | 
			
		||||
  Fix metadata profile allocation/cache_[mode|policy] setting.
 | 
			
		||||
  Fix missing support for using allocation/cache_pool_chunk_size setting.
 | 
			
		||||
@@ -933,8 +618,8 @@ Version 2.02.169 - 28th March 2017
 | 
			
		||||
  Extend metadata validation of external origin LV use count.
 | 
			
		||||
  Fix dm table when the last user of active external origin is removed.
 | 
			
		||||
  Improve reported lvs status for active external origin volume.
 | 
			
		||||
  Fix table load for split RAID LV and require explicit activation.
 | 
			
		||||
  Always active split RAID LV exclusively locally.
 | 
			
		||||
  Fix table load for splitted RAID LV and require explicit activation.
 | 
			
		||||
  Always active splitted RAID LV exclusively locally.
 | 
			
		||||
  Do not use LV RAID status bit for segment status.
 | 
			
		||||
  Check segtype directly instead of checking RAID in segment status.
 | 
			
		||||
  Reusing exiting code for raid image removal.
 | 
			
		||||
@@ -997,7 +682,7 @@ Version 2.02.166 - 26th September 2016
 | 
			
		||||
  Use --alloc normal for mirror logs even if the mimages were stricter.
 | 
			
		||||
  Use O_DIRECT to gather metadata in lvmdump.
 | 
			
		||||
  Ignore creation_time when checking for matching metadata for lvmetad.
 | 
			
		||||
  Fix possible NULL pointer dereference when checking for monitoring.
 | 
			
		||||
  Fix possible NULL pointer derefence when checking for monitoring.
 | 
			
		||||
  Add lvmreport(7) man page.
 | 
			
		||||
  Don't install lvmraid(7) man page when raid excluded. (2.02.165)
 | 
			
		||||
  Report 0% as dirty (copy%) for cache without any used block.
 | 
			
		||||
@@ -1037,7 +722,7 @@ Version 2.02.164 - 15th August 2016
 | 
			
		||||
Version 2.02.163 - 10th August 2016
 | 
			
		||||
===================================
 | 
			
		||||
  Add profile for lvmdbusd which uses lvm shell json report output.
 | 
			
		||||
  Restrict in-command modification of some params in lvm shell.
 | 
			
		||||
  Restrict in-command modification of some parms in lvm shell.
 | 
			
		||||
  Apply LVM_COMMAND_PROFILE early for lvm shell.
 | 
			
		||||
  Refactor reporting so lvm shell log report collects whole of cmd execution.
 | 
			
		||||
  Support LVM_*_FD envvars to redirect output to file descriptors.
 | 
			
		||||
@@ -1190,11 +875,11 @@ Version 2.02.152 - 30th April 2016
 | 
			
		||||
==================================
 | 
			
		||||
  Use any inherited tags when wiping metadata sub LVs to ensure activation.
 | 
			
		||||
  Add str_list_wipe.
 | 
			
		||||
  Improve support for interrupting processing of volumes during lvchange.
 | 
			
		||||
  Improve support for interrupting procesing of volumes during lvchange.
 | 
			
		||||
  Use failed command return code when lvchanging read-only volume.
 | 
			
		||||
  Show creation transaction_id and zeroing state of pool with thin volume.
 | 
			
		||||
  Stop checking for dm_cache_mq policy with cache target 1.9 (alias to smq).
 | 
			
		||||
  Check first /sys/module/dm_* dir existence before using modprobe.
 | 
			
		||||
  Check first /sys/module/dm_* dir existance before using modprobe.
 | 
			
		||||
  Remove mpath from 10-dm.rules, superseded by 11-dm-mpath.rules (mpath>=0.6.0).
 | 
			
		||||
 | 
			
		||||
Version 2.02.151 - 23rd April 2016
 | 
			
		||||
@@ -1219,7 +904,7 @@ Version 2.02.150 - 9th April 2016
 | 
			
		||||
=================================
 | 
			
		||||
  Avoid using flushing dm status ioctl when checking for usable DM device.
 | 
			
		||||
  Check for devices without LVM- uuid prefix only with kernels < 3.X.
 | 
			
		||||
  Reuse %FREE size approximation with lvcreate -l%PVS thin-pool.
 | 
			
		||||
  Reuse %FREE size aproximation with lvcreate -l%PVS thin-pool.
 | 
			
		||||
  Allow the lvmdump directory to exist already provided it is empty.
 | 
			
		||||
  Show lvconverted percentage with 2 decimal digits.
 | 
			
		||||
  Fix regression in suspend when repairing --type mirror (2.02.133).
 | 
			
		||||
@@ -1296,7 +981,7 @@ Version 2.02.143 - 21st February 2016
 | 
			
		||||
  Fix error path when sending thin-pool message fails in update_pool_lv().
 | 
			
		||||
  Support reporting CheckNeeded and Fail state for thin-pool and thin LV.
 | 
			
		||||
  For failing thin-pool and thin volume correctly report percentage as INVALID.
 | 
			
		||||
  Report -1, not 'unknown' for lv_{snapshot_invalid,merge_failed} with --binary.
 | 
			
		||||
  Report -1, not 'unkown' for lv_{snapshot_invalid,merge_failed} with --binary.
 | 
			
		||||
  Add configure --enable-dbus-service for an LVM D-Bus service.
 | 
			
		||||
  Replace configure --enable-python_bindings with python2 and python3 versions.
 | 
			
		||||
  If PV belongs to some VG and metadata missing, skip it if system ID is used.
 | 
			
		||||
@@ -1325,7 +1010,7 @@ Version 2.02.141 - 25th January 2016
 | 
			
		||||
  Restore support for command breaking in process_each_lv_in_vg() (2.02.118).
 | 
			
		||||
  Use correct mempool when process_each_lv_in_vg() (2.02.118).
 | 
			
		||||
  Fix lvm.8 man to show again prohibited suffixes.
 | 
			
		||||
  Fix configure to set proper use_blkid_wiping if autodetection as disabled.
 | 
			
		||||
  Fix configure to set proper use_blkid_wiping if autodetected as disabled.
 | 
			
		||||
  Initialise udev in clvmd for use in device scanning. (2.02.116)
 | 
			
		||||
  Add seg_le_ranges report field for common format when displaying seg devices.
 | 
			
		||||
  Honour report/list_item_separator for seg_metadata_le_ranges report field.
 | 
			
		||||
@@ -1475,7 +1160,7 @@ Version 2.02.129 - 26th August 2015
 | 
			
		||||
  Fix shared library generation to stop exporting internal functions.(2.02.120)
 | 
			
		||||
  Accept --cachemode with lvconvert.
 | 
			
		||||
  Fix and improve reporting properties of cache-pool.
 | 
			
		||||
  Enable usage of --cachepolicy and --cachesettings with lvconvert.
 | 
			
		||||
  Enable usage of --cachepolicy and --cachesetting with lvconvert.
 | 
			
		||||
  Don't allow to reduce size of thin-pool metadata.
 | 
			
		||||
  Fix debug buffer overflows in cmirrord logging.
 | 
			
		||||
  Add --foreground and --help to cmirrord.
 | 
			
		||||
@@ -1632,7 +1317,7 @@ Version 2.02.119 - 2nd May 2015
 | 
			
		||||
  Add --enable-halvm and --disable-halvm options to lvmconf script.
 | 
			
		||||
  Add --services, --mirrorservice and --startstopservices option to lvmconf.
 | 
			
		||||
  Use proper default value of global/use_lvmetad when processing lvmconf script.
 | 
			
		||||
  Respect allocation/cling_tag_list during initial contiguous allocation.
 | 
			
		||||
  Respect allocation/cling_tag_list during intial contiguous allocation.
 | 
			
		||||
  Add A_PARTITION_BY_TAGS set when allocated areas should not share tags.
 | 
			
		||||
  Make changes persist with python addTag/removeTag.
 | 
			
		||||
  Set correct vgid when updating cache when writing PV metadata.
 | 
			
		||||
@@ -1710,7 +1395,7 @@ Version 2.02.116 - 30th January 2015
 | 
			
		||||
  Scan pools in for_each_sub_lv() and add for_each_sub_lv_except_pools().
 | 
			
		||||
  Fix lvm2app lvm_lv_get_property return value for fields with info/status ioctl.
 | 
			
		||||
  Fix lvm2app regression in lvm_lv_get_attr causing unknown values (2.02.115).
 | 
			
		||||
  Set default cache_mode to writethrough when missing in metadata.
 | 
			
		||||
  Set default cache_mode to writehrough when missing in metadata.
 | 
			
		||||
  Preserve chunk size with repair and metadata swap of a thin pool.
 | 
			
		||||
  Fix raid --splitmirror 1 functionality (2.02.112).
 | 
			
		||||
  Fix tree preload to handle splitting raid images.
 | 
			
		||||
@@ -1776,13 +1461,13 @@ Version 2.02.112 - 11th November 2014
 | 
			
		||||
  Properly report error when taking snapshot of any cache type LV.
 | 
			
		||||
  Add basic thread debugging messages to dmeventd.
 | 
			
		||||
  Include threads being shutdown in dmeventd device registration responses.
 | 
			
		||||
  Initial support for external users of thin pools based on transaction_id.
 | 
			
		||||
  Inital support for external users of thin pools based on transaction_id.
 | 
			
		||||
  Report some basic percentage info for cache pools.
 | 
			
		||||
  Introduce size_mb_arg_with_percent() for advanced size arg reading.
 | 
			
		||||
  Add extra support for '.' as decimal point in size args.
 | 
			
		||||
  Add configure parameters for default segment type choices.
 | 
			
		||||
  Add global/sparse_segtype_default setting to use thin for --type sparse.
 | 
			
		||||
  Update and correct lvcreate and lvconvert man pages.
 | 
			
		||||
  Update and correct lvcreate and lvcovert man pages.
 | 
			
		||||
  Mark pools and snapshots as unzeroable volumes.
 | 
			
		||||
  Check for zeroing of volume after segment type is fully detected.
 | 
			
		||||
  Better support for persistent major and minor options with lvcreate.
 | 
			
		||||
@@ -1835,7 +1520,7 @@ Version 2.02.112 - 11th November 2014
 | 
			
		||||
  Support DEBUG_MEMLOCK to trap unsupported mmap usage.
 | 
			
		||||
  Enable cache segment type by default.
 | 
			
		||||
  Ensure only supported volume types are used with cache segments.
 | 
			
		||||
  Fix inability to specify cachemode when 'lvconvert'ing to cache-pool.
 | 
			
		||||
  Fix inablility to specify cachemode when 'lvconvert'ing to cache-pool.
 | 
			
		||||
  Grab cluster lock for active LVs when setting clustered attribute.
 | 
			
		||||
  Use va_copy to properly pass va_list through functions.
 | 
			
		||||
  Add function to detect rotational devices.
 | 
			
		||||
@@ -1903,7 +1588,7 @@ Version 2.02.108 - 23rd July 2014
 | 
			
		||||
  Enhance lvconvert thin, thinpool, cache and cachepool command line support.
 | 
			
		||||
  Display 'C' only for cache and cache-pool target types in lvs.
 | 
			
		||||
  Prompt for confirmation before change LV into a snapshot exception store.
 | 
			
		||||
  Return proper error codes for some failing lvconvert functions.
 | 
			
		||||
  Return proper error codes for some failing lvconvert funtions.
 | 
			
		||||
  Add initial code to use cache tools (cache_check|dump|repair|restore).
 | 
			
		||||
  Support lvdisplay --maps for raid.
 | 
			
		||||
  Add --activationmode degraded to activate degraded raid volumes by default.
 | 
			
		||||
@@ -1922,7 +1607,7 @@ Version 2.02.108 - 23rd July 2014
 | 
			
		||||
  Support lvremove -ff to remove thin volumes from broken thin pools.
 | 
			
		||||
  Require --yes to skip raid repair prompt.
 | 
			
		||||
  Change makefile %.d generation to handle filename changes without make clean.
 | 
			
		||||
  Fix use of builddir in make pofile.
 | 
			
		||||
  Fix use of buildir in make pofile.
 | 
			
		||||
  Enhance private volumes UUIDs with suffixed for easier detection.
 | 
			
		||||
  Do not use reserved _[tc]meta volumes for temporary LVs.
 | 
			
		||||
  Leave backup pool metadata with _meta%d suffix instead of reserved _tmeta%d.
 | 
			
		||||
@@ -2027,7 +1712,7 @@ Version 2.02.106 - 10th April 2014
 | 
			
		||||
  Include 'lvm dumpconfig --type missing' and '--type diff' output to lvmdump.
 | 
			
		||||
  Return failure when specifying negative size for pvresize.
 | 
			
		||||
  Fix memory corruption in cmd context refresh if clvmd leaks opened device.
 | 
			
		||||
  Reinitialize lvmcache properly on fork to fix premature polldaemon exit.
 | 
			
		||||
  Reinitialise lvmcache properly on fork to fix premature polldaemon exit.
 | 
			
		||||
  Add 'lvm dumpconfig --type diff' to show differences from defaults.
 | 
			
		||||
  Fix swap signature detection for devices smaller then 2MB.
 | 
			
		||||
  Use dm_malloc function in clvmd.c.
 | 
			
		||||
@@ -2054,7 +1739,7 @@ Version 2.02.106 - 10th April 2014
 | 
			
		||||
  Don't print an error and accept empty value for global/thin_disabled_features.
 | 
			
		||||
  Update API for internal function build_dm_uuid().
 | 
			
		||||
  Do not try to check empty pool with scheduled messages.
 | 
			
		||||
  Fix return value in pool_has_message() when querying for any message.
 | 
			
		||||
  Fix return value in pool_has_message() when quering for any message.
 | 
			
		||||
  Cleanup all client resources on clvmd exit.
 | 
			
		||||
  Use dm_zalloc to clear members of clvmd client struct.
 | 
			
		||||
  Use BLKID_CFLAGS when compiling with blkid support.
 | 
			
		||||
@@ -2096,7 +1781,7 @@ Version 2.02.106 - 10th April 2014
 | 
			
		||||
  Fix test when checking target version for available thin features.
 | 
			
		||||
  Detect thin feature external_origin_extend and limit extend when missing.
 | 
			
		||||
  Rename internal pool_can_resize_metadata() to thin_pool_feature_supported().
 | 
			
		||||
  Issue error if libblkid detects signature and fails to return offset/length.
 | 
			
		||||
  Issue error if libbblkid detects signature and fails to return offset/length.
 | 
			
		||||
  Update autoconf config.guess/sub to 2014-01-01.
 | 
			
		||||
  Online thin pool metadata resize requires 1.10 kernel thin pool target.
 | 
			
		||||
 | 
			
		||||
@@ -2169,7 +1854,7 @@ Version 2.02.104 - 13th November 2013
 | 
			
		||||
=====================================
 | 
			
		||||
  Workaround VG refresh race during autoactivation by retrying the refresh.
 | 
			
		||||
  Handle failures in temporary mirror used when adding images to mirrors.
 | 
			
		||||
  Fix and improve logic for implicitly exclusive activations.
 | 
			
		||||
  Fix and improve logic for implicitely exclusive activations.
 | 
			
		||||
  Return success when LV cannot be activated because of volume_list filter.
 | 
			
		||||
  Return proper error state for remote exclusive activation.
 | 
			
		||||
  Fix missing lvmetad scan for PVs found on MD partitions.
 | 
			
		||||
@@ -2332,11 +2017,11 @@ Version 2.02.99 - 24th July 2013
 | 
			
		||||
  Add support for persistent flagging of LVs to be skipped during activation.
 | 
			
		||||
  Add --type profilable to lvm dumpconfig to show profilable config settings.
 | 
			
		||||
  Add --mergedconfig to lvm dumpconfig for merged --config/--profile/lvm.conf.
 | 
			
		||||
  Release memory and unblock signals in lock_vol error path.
 | 
			
		||||
  Relase memory and unblock signals in lock_vol error path.
 | 
			
		||||
  Define LVM2_* command errors in lvm2cmd.h and use in dmeventd plugins.
 | 
			
		||||
  Move errors.h to tools dir.
 | 
			
		||||
  Add man page entries for profile configuration and related options.
 | 
			
		||||
  Improve error logging when user tries to interrupt commands.
 | 
			
		||||
  Improve error loging when user tries to interrupt commands.
 | 
			
		||||
  Rename _swap_lv to _swap_lv_identifiers and move to allow an additional user.
 | 
			
		||||
  Rename snapshot segment returning methods from find_*_cow to find_*_snapshot.
 | 
			
		||||
  liblvm/python API: Additions: PV create/removal/resize/listing
 | 
			
		||||
@@ -2537,7 +2222,7 @@ Version 2.02.98 - 15th October 2012
 | 
			
		||||
  Do not start dmeventd for lvchange --resync when monitoring is off.
 | 
			
		||||
  Remove pvscan --cache from lvm2-lvmetad init script.
 | 
			
		||||
  Remove ExecStartPost with pvscan --cache from lvm2-lvmetad.service.
 | 
			
		||||
  Report invalid percentage for property snap_percent of non-snapshot LVs.
 | 
			
		||||
  Report invalid percentage for property snap_percent of non-snaphot LVs.
 | 
			
		||||
  Disallow conversion of thin LVs to mirrors.
 | 
			
		||||
  Fix lvm2api data_percent reporting for thin volumes.
 | 
			
		||||
  Do not allow RAID LVs in a clustered volume group.
 | 
			
		||||
@@ -2587,7 +2272,7 @@ Version 2.02.98 - 15th October 2012
 | 
			
		||||
 | 
			
		||||
Version 2.02.97 - 7th August 2012
 | 
			
		||||
=================================
 | 
			
		||||
  Improve documentation of allocation policies in lvm.8.
 | 
			
		||||
  Improve documention of allocation policies in lvm.8.
 | 
			
		||||
  Increase limit for major:minor to 4095:1048575 when using -My option.
 | 
			
		||||
  Add make install_systemd_generators.
 | 
			
		||||
  Add generator for lvm2 activation systemd units.
 | 
			
		||||
@@ -2671,7 +2356,7 @@ Version 2.02.96 - 8th June 2012
 | 
			
		||||
  Check for buffer overwrite in get_cluster_type() in clvmd.
 | 
			
		||||
  Fix global/detect_internal_vg_cache_corruption config check.
 | 
			
		||||
  Update lcov Makefile target to support all dmeventd plugins.
 | 
			
		||||
  Fix initialization of thin monitoring. (2.02.92)
 | 
			
		||||
  Fix initializiation of thin monitoring. (2.02.92)
 | 
			
		||||
  Cope with improperly formatted device numbers in /proc/devices. (2.02.91)
 | 
			
		||||
  Exit if LISTEN_PID environment variable incorrect in lvmetad systemd handover.
 | 
			
		||||
  Use pvscan --cache instead of vgscan in lvmetad scripts.
 | 
			
		||||
@@ -2684,7 +2369,7 @@ Version 2.02.96 - 8th June 2012
 | 
			
		||||
  Add --with-thin-check configure option for path to thin_check.
 | 
			
		||||
  Fix error message when pvmove LV activation fails with name already in use.
 | 
			
		||||
  Better structure layout for device_info in dev_subsystem_name().
 | 
			
		||||
  Change message severity for creation of VG over uninitialized devices.
 | 
			
		||||
  Change message severity for creation of VG over uninitialised devices.
 | 
			
		||||
  Fix error path for failed toolcontext creation.
 | 
			
		||||
  Detect lvm binary path in lvmetad udev rules.
 | 
			
		||||
  Don't unlink socket on lvmetad shutdown if instantiated from systemd.
 | 
			
		||||
@@ -2719,7 +2404,7 @@ Version 2.02.94 - 3rd March 2012
 | 
			
		||||
  Add some close() and dev_close() error path backtraces.
 | 
			
		||||
  Set stdin/stdout/stderr to /dev/null for polldaemon.
 | 
			
		||||
  Limit the max size of processed clvmd message to ~8KB.
 | 
			
		||||
  Do not send uninitialized bytes in cluster error reply messages.
 | 
			
		||||
  Do not send uninitialised bytes in cluster error reply messages.
 | 
			
		||||
  Use unsigned type for bitmask instead of enum type for lvm properties.
 | 
			
		||||
  Add missing cleanup of excl_uuid hash on some exit paths of clvmd.
 | 
			
		||||
  Check for existence of vg_name in _format1/_pool_vg_read().
 | 
			
		||||
@@ -2792,7 +2477,7 @@ Version 2.02.91 - 12th February 2012
 | 
			
		||||
 | 
			
		||||
Version 2.02.90 - 1st February 2012
 | 
			
		||||
===================================
 | 
			
		||||
  sync_local_dev_names before (re)activating mirror log for initialization.
 | 
			
		||||
  sync_local_dev_names before (re)activating mirror log for initialisation.
 | 
			
		||||
  Disable partial activation for thin LVs and LVs with all missing segments.
 | 
			
		||||
  Do not print warning for pv_min_size between 512KB and 2MB.
 | 
			
		||||
  Clean up systemd unit ordering and requirements.
 | 
			
		||||
@@ -2811,7 +2496,7 @@ Version 2.02.89 - 26th January 2012
 | 
			
		||||
  Add data_percent and metadata_percent for thin pools to lvs -v.
 | 
			
		||||
  Add data_lv & metadata_lv fields to lvs for thin pools.
 | 
			
		||||
  Add data_percent & pool_lv fields to lvs for thin volumes.
 | 
			
		||||
  Rename origin_only param to use_layer for lv_info and use with thin LVs.
 | 
			
		||||
  Rename origin_only parm to use_layer for lv_info and use with thin LVs.
 | 
			
		||||
  Add lv_thin_pool_transaction_id to read the transaction_id value.
 | 
			
		||||
  Use {suspend,resume}_origin_only when up-converting RAID, as mirrors do.
 | 
			
		||||
  Always add RAID metadata LVs to deptree (even when origin_only is set).
 | 
			
		||||
@@ -2841,7 +2526,7 @@ Version 2.02.89 - 26th January 2012
 | 
			
		||||
  Add _dev_init to initialize common struct device members.
 | 
			
		||||
  Always zalloc struct device during initialization.
 | 
			
		||||
  Fix missing thread list manipulation protection in dmeventd.
 | 
			
		||||
  Do not dereference lv pointer in _percent_run() function before NULL check.
 | 
			
		||||
  Do not derefence lv pointer in _percent_run() function before NULL check.
 | 
			
		||||
  Allow empty strings for description and creation_host config fields.
 | 
			
		||||
  Issue deprecation warning when removing last lvm1-format snapshot.
 | 
			
		||||
  Reinstate support for snapshot removal with lvm1 format. (2.02.86)
 | 
			
		||||
@@ -2912,11 +2597,11 @@ Version 2.02.89 - 26th January 2012
 | 
			
		||||
  Change vg_revert to void and remove superfluous calls after failed vg_commit.
 | 
			
		||||
  Use execvp for CLVMD restart to preserve environment settings.
 | 
			
		||||
  Restart CLVMD with same cluster manager.
 | 
			
		||||
  Fix log_error() usage in raid and unknown segtype initialization.
 | 
			
		||||
  Fix log_error() usage in raid and unknown segtype initialisation.
 | 
			
		||||
  Improve testing Makefile.
 | 
			
		||||
  Fix install_ocf make target when srcdir != builddir. (2.02.80)
 | 
			
		||||
  Support env vars LVM_CLVMD_BINARY and LVM_BINARY in clvmd.
 | 
			
		||||
  Fix restart of clvmd (preserve exclusive locks). (2.02.64)
 | 
			
		||||
  Fix restart of clvmd (preserve exlusive locks). (2.02.64)
 | 
			
		||||
  Add 'Volume Type' lv_attr characters for RAID and RAID_IMAGE.
 | 
			
		||||
  Add activation/retry_deactivation to lvm.conf to retry deactivation of an LV.
 | 
			
		||||
  Replace open_count check with holders/mounted_fs check on lvremove path.
 | 
			
		||||
@@ -2982,13 +2667,13 @@ Version 2.02.87 - 12th August 2011
 | 
			
		||||
  Cache and share generated VG structs.
 | 
			
		||||
  Fix possible format instance memory leaks and premature releases in _vg_read.
 | 
			
		||||
  Suppress locking error messages in monitoring init scripts.
 | 
			
		||||
  If pipe in clvmd fails return busy instead of using uninitialized descriptors.
 | 
			
		||||
  If pipe in clvmd fails return busy instead of using uninitialised descriptors.
 | 
			
		||||
  Add ability to reduce the number of mirrors in raid1 arrays to lvconvert.
 | 
			
		||||
  Add dmeventd plugin for raid.
 | 
			
		||||
  Replace free_vg with release_vg and move it to vg.c.
 | 
			
		||||
  Remove INCONSISTENT_VG flag from the code.
 | 
			
		||||
  Remove lock from cache in _lock_vol even if unlock fails.
 | 
			
		||||
  Initialize clvmd locks before lvm context to avoid open descriptor leaks.
 | 
			
		||||
  Initialise clvmd locks before lvm context to avoid open descriptor leaks.
 | 
			
		||||
  Remove obsolete gulm clvmd cluster locking support.
 | 
			
		||||
  Suppress low-level locking errors and warnings while using --sysinit.
 | 
			
		||||
  Remove unused inconsistent_seqno variable in _vg_read().
 | 
			
		||||
@@ -3061,7 +2746,7 @@ Version 2.02.85 - 29th April 2011
 | 
			
		||||
  Issue discards on lvremove and lvreduce etc. if enabled and supported.
 | 
			
		||||
  Add seg_pe_ranges and devices fields to liblvm.
 | 
			
		||||
  Fix incorrect tests for dm_snprintf() failure.
 | 
			
		||||
  Fix some unmatching sign comparison gcc warnings in the code.
 | 
			
		||||
  Fix some unmatching sign comparation gcc warnings in the code.
 | 
			
		||||
  Support lv_extend() on empty LVs.
 | 
			
		||||
  Avoid regenerating cache content when exported VG buffer is unchanged.
 | 
			
		||||
  Extend the set of memory regions that are not locked to memory.
 | 
			
		||||
@@ -3087,7 +2772,7 @@ Version 2.02.85 - 29th April 2011
 | 
			
		||||
  Use only vg_set_fid and new pv_set_fid fn to assign the format instance.
 | 
			
		||||
  Make create_text_context fn static and move it inside create_instance fn.
 | 
			
		||||
  Add mem and ref_count fields to struct format_instance for own mempool use.
 | 
			
		||||
  Use new alloc_fid fn for common format instance initialization.
 | 
			
		||||
  Use new alloc_fid fn for common format instance initialisation.
 | 
			
		||||
  Optimise _get_token() and _eat_space().
 | 
			
		||||
  Add _lv_postorder_vg() to improve efficiency for all LVs in VG.
 | 
			
		||||
  Add gdbinit script for debugging.
 | 
			
		||||
@@ -3096,10 +2781,10 @@ Version 2.02.85 - 29th April 2011
 | 
			
		||||
  Avoid possible endless loop in _free_vginfo when 4 or more VGs have same name.
 | 
			
		||||
  Use empty string instead of /dev// for LV path when there's no VG.
 | 
			
		||||
  Don't allocate unused VG mempool in _pvsegs_sub_single.
 | 
			
		||||
  Do not send uninitialized bytes in local clvmd messages.
 | 
			
		||||
  Do not send uninitialised bytes in local clvmd messages.
 | 
			
		||||
  Support --help option for clvmd and return error for unknown option.
 | 
			
		||||
  Avoid reading freed memory when printing LV segment type.
 | 
			
		||||
  Fix syslog initialization in clvmd to respect lvm.conf setting.
 | 
			
		||||
  Fix syslog initialisation in clvmd to respect lvm.conf setting.
 | 
			
		||||
  Fix possible overflow in maximum stripe size and physical extent size.
 | 
			
		||||
  Improve pvremove error message when PV belongs to a VG.
 | 
			
		||||
  Extend normal policy to allow mirror logs on same PVs as images if necessary.
 | 
			
		||||
@@ -3113,7 +2798,7 @@ Version 2.02.85 - 29th April 2011
 | 
			
		||||
  Restructure existing pv_setup and pv_write and add pv_initialise.
 | 
			
		||||
  Add internal interface to support adding and removing metadata areas.
 | 
			
		||||
  Allow internal indexing of metadata areas (PV id + mda order).
 | 
			
		||||
  Generalise internal format_instance infrastructure for PV and VG use.
 | 
			
		||||
  Generalise internal format_instance infrastrusture for PV and VG use.
 | 
			
		||||
  Handle decimal digits with --units instead of ignoring them silently.
 | 
			
		||||
  Fix remaining warnings and compile with -Wpointer-arith.
 | 
			
		||||
  Fix gcc warnings for unused variables and const casts.
 | 
			
		||||
@@ -3127,7 +2812,7 @@ Version 2.02.85 - 29th April 2011
 | 
			
		||||
  Make pv_min_size configurable and increase to 2048KB to exclude floppy drives.
 | 
			
		||||
  Add find_config_tree_int64 to read 64-bit ints from config.
 | 
			
		||||
  Ensure resuming exclusive cluster mirror continues to use local mirror target.
 | 
			
		||||
  Clear temporary postorder LV status flags to allow reuse with same LV struct.
 | 
			
		||||
  Clear temporary postorder LV status flags to allow re-use with same LV struct.
 | 
			
		||||
  Remove invalid snapshot umount mesg which floods syslog from dmeventd plugin.
 | 
			
		||||
  Add extended examples to pvmove man page.
 | 
			
		||||
  Support LVM_TEST_DEVDIR env var for private /dev during testing.
 | 
			
		||||
@@ -3182,7 +2867,7 @@ Version 2.02.80 - 10th January 2011
 | 
			
		||||
  Speed up command processing by caching resolved config tree.
 | 
			
		||||
  Pass config_tree to renamed function import_vg_from_config_tree().
 | 
			
		||||
  Detect NULL handle in get_property().
 | 
			
		||||
  Fix superfluous /usr in ocf_scriptdir installation path.
 | 
			
		||||
  Fix superfluous /usr in ocf_scriptdir instalation path.
 | 
			
		||||
  Add --with-ocfdir configurable option.
 | 
			
		||||
  Add aclocal.m4 (for pkgconfig).
 | 
			
		||||
  Fix memory leak in persistent filter creation error path.
 | 
			
		||||
@@ -3214,7 +2899,7 @@ Version 2.02.79 - 20th December 2010
 | 
			
		||||
  Add copy_percent and snap_percent to liblvm.
 | 
			
		||||
  Enhance vg_validate to ensure integrity of LV and PV structs referenced.
 | 
			
		||||
  Enhance vg_validate to check composition of pvmove LVs.
 | 
			
		||||
  Create /var/run/lvm directory during clvmd initialization if missing.
 | 
			
		||||
  Create /var/run/lvm directory during clvmd initialisation if missing.
 | 
			
		||||
  Use new dm_prepare_selinux_context instead of dm_set_selinux_context.
 | 
			
		||||
  Avoid revalidating the label cache immediately after scanning.
 | 
			
		||||
  Support scanning for a single VG in independent mdas.
 | 
			
		||||
@@ -3483,7 +3168,7 @@ Version 2.02.68 - 23rd June 2010
 | 
			
		||||
  Add device name and offset to raw_read_mda_header error messages.
 | 
			
		||||
  Honour log argument when down-converting stacked mirror.
 | 
			
		||||
  Sleep to workaround clvmd -S race: socket closed early and server drops cmd.
 | 
			
		||||
  Use early udev synchronization and update of dev nodes for clustered mirrors.
 | 
			
		||||
  Use early udev synchronisation and update of dev nodes for clustered mirrors.
 | 
			
		||||
  Remove incorrect inclusion of kdev_t.h from cmirrord/functions.h.
 | 
			
		||||
  Add man pages for lvmconf and non-existent lvmsadc and lvmsar tools.
 | 
			
		||||
  Exit successfully when using -o help (but not -o +help) with LVM reports.
 | 
			
		||||
@@ -3511,7 +3196,7 @@ Version 2.02.67 - 4th June 2010
 | 
			
		||||
  Avoid selecting names under /dev/block if there is an alternative.
 | 
			
		||||
  Update clustered log kernel module name to log-userspace for 2.6.31 onwards.
 | 
			
		||||
  Add replicators' LVs to dtree for activation.
 | 
			
		||||
  Suppress activation message if there is a missing replicator VG.
 | 
			
		||||
  Supress activation message if there is a missing replicator VG.
 | 
			
		||||
  Fix scripts/relpath.awk to work in mawk
 | 
			
		||||
  Extend lock_vol to check for missing replicator VGs first.
 | 
			
		||||
  Update _process_one_vg and process_each_lv_in_vg to populate cmd_vg.
 | 
			
		||||
@@ -3562,7 +3247,7 @@ Version 2.02.65 - 17th May 2010
 | 
			
		||||
 | 
			
		||||
Version 2.02.64 - 30th April 2010
 | 
			
		||||
=================================
 | 
			
		||||
  Avoid pointless initialization when the 'version' command is run directly.
 | 
			
		||||
  Avoid pointless initialisation when the 'version' command is run directly.
 | 
			
		||||
  Fix memory leak for invalid regex pattern input.
 | 
			
		||||
  Display invalid regex pattern for filter configuration in case of error.
 | 
			
		||||
  Remove no-longer-used arg_ptr_value.
 | 
			
		||||
@@ -3721,7 +3406,7 @@ Version 2.02.60 - 23rd January 2010
 | 
			
		||||
  Disable memory debugging if dmeventd is configured. (Not thread-safe.)
 | 
			
		||||
  Fix first log message prefix in syslog for dmeventd plugins.
 | 
			
		||||
  Fix exported symbols names for dmeventd lvm2 wrapper plugin.
 | 
			
		||||
  Make failed locking initialization messages more descriptive.
 | 
			
		||||
  Make failed locking initialisation messages more descriptive.
 | 
			
		||||
 | 
			
		||||
Version 2.02.59 - 21st January 2010
 | 
			
		||||
===================================
 | 
			
		||||
@@ -3737,7 +3422,7 @@ Version 2.02.59 - 21st January 2010
 | 
			
		||||
  Fix detection of completed snapshot merge.
 | 
			
		||||
  Add Red Hat cmirror initscript (unfinished).
 | 
			
		||||
  Add cmirrord man page (incomplete).
 | 
			
		||||
  Make cluster log communication structures architecture independent.
 | 
			
		||||
  Make cluster log communication structures architecture independant.
 | 
			
		||||
  Fix cluster log in-memory bitmap handling.
 | 
			
		||||
  Improve snapshot merge metadata import validation.
 | 
			
		||||
  Improve target type compatibility checking in _percent_run().
 | 
			
		||||
@@ -3813,7 +3498,7 @@ Version 2.02.57 - 12th January 2010
 | 
			
		||||
  Impose limit of 8 mirror images to match the in-kernel kcopyd restriction.
 | 
			
		||||
  Use locking_type 3 (compiled in) for lvmconf --enable-cluster.
 | 
			
		||||
  Remove list.c and list.h with no-longer-used dm_list macros and functions.
 | 
			
		||||
  Log failure type and recognize type 'F' (flush) in dmeventd mirror plugin.
 | 
			
		||||
  Log failure type and recognise type 'F' (flush) in dmeventd mirror plugin.
 | 
			
		||||
  Extend internal PV/VG/LV/segment status variables from 32-bit to 64-bit.
 | 
			
		||||
 | 
			
		||||
Version 2.02.56 - 24th November 2009
 | 
			
		||||
@@ -3851,14 +3536,14 @@ Version 2.02.54 - 26th October 2009
 | 
			
		||||
  Fix clvmd segfault when refresh_toolcontext fails.
 | 
			
		||||
  Remember to clear 'global lock held during cache refresh' state after use.
 | 
			
		||||
  Use udev flags support in LVM and apply various fixes to udev rules.
 | 
			
		||||
  Delay announcing mirror monitoring to syslog until initialization succeeded.
 | 
			
		||||
  Delay announcing mirror monitoring to syslog until initialisation succeeded.
 | 
			
		||||
  Handle metadata with unknown segment types more gracefully.
 | 
			
		||||
  Set default owner and group to null.
 | 
			
		||||
  Add dmeventd.static to the build.
 | 
			
		||||
  Disable realtime support code by default.
 | 
			
		||||
  Make clvmd return 0 on success rather than 1.
 | 
			
		||||
  Add --pvmetadatacopies for pvcreate, vgcreate, vgextend, vgconvert.
 | 
			
		||||
  Add implicit pvcreate support to vgcreate and vgextend.
 | 
			
		||||
  Add implict pvcreate support to vgcreate and vgextend.
 | 
			
		||||
  Correct example.conf to indicate that lvm2 not lvm1 is the default format.
 | 
			
		||||
  Remove an unused stray LVM1_SUPPORT ifdef.
 | 
			
		||||
  Only include selinux libs in libdevmapper.pc when selinux build enabled.
 | 
			
		||||
@@ -4038,7 +3723,7 @@ Version 2.02.48 - 30th June 2009
 | 
			
		||||
  Reinstate partial activation support in clustered mode. (2.02.40)
 | 
			
		||||
  Allow metadata correction even when PVs are missing.
 | 
			
		||||
  Use 'lvm lvresize' instead of 'lvresize' in fsadm.
 | 
			
		||||
  Do not use '-n' realine option in fsadm for busybox compatibility.
 | 
			
		||||
  Do not use '-n' realine option in fsadm for busybox compatiblity.
 | 
			
		||||
  Add vg_lock_newname() library function for vgrename, vgsplit and vgcreate.
 | 
			
		||||
  Round up requested readahead to at least one page and print warning.
 | 
			
		||||
  Try to repair vg before actual vgremove when force flag provided.
 | 
			
		||||
@@ -4099,7 +3784,7 @@ Version 2.02.46 - 21st May 2009
 | 
			
		||||
  Fix first_seg() call for empty segment list.
 | 
			
		||||
  Add install_lvm2 makefile target to install only the LVM2 components.
 | 
			
		||||
  Reject missing PVs from allocation in toollib.
 | 
			
		||||
  Fix PV dataalignment for values starting prior to MDA area. (2.02.45)
 | 
			
		||||
  Fix PV datalignment for values starting prior to MDA area. (2.02.45)
 | 
			
		||||
  Add sparse devices: lvcreate -s --virtualoriginsize (hidden zero origin).
 | 
			
		||||
  Fix minimum width of devices column in reports.
 | 
			
		||||
  Add lvs origin_size field.
 | 
			
		||||
@@ -4172,7 +3857,7 @@ Version 2.02.45 - 3rd March 2009
 | 
			
		||||
  Separate PV label attributes which do not need parse metadata when reporting.
 | 
			
		||||
  Remove external dependency on the 'cut' command from fsadm.
 | 
			
		||||
  Fix pvs segfault when pv mda attributes requested for not available PV.
 | 
			
		||||
  Add fsadm support for resizing ext4 filesystems.
 | 
			
		||||
  Add fsadm support for reszing ext4 filesysystems.
 | 
			
		||||
  Move locking_type reading inside init_locking().
 | 
			
		||||
  Rename get_vgs() to get_vgnames() and clarify related error messages.
 | 
			
		||||
  Allow clvmd to be built with all cluster managers & select one on cmdline.
 | 
			
		||||
@@ -4349,7 +4034,7 @@ Version 2.02.37 - 6th June 2008
 | 
			
		||||
  Refactor some vginfo manipulation code.
 | 
			
		||||
  Add assertions to trap deprecated P_ and V_ lock usage.
 | 
			
		||||
  Add missing mutex around clvmd lvmcache_drop_metadata library call.
 | 
			
		||||
  Fix uninitialized mutex in clvmd if all daemons are not running at startup.
 | 
			
		||||
  Fix uninitialised mutex in clvmd if all daemons are not running at startup.
 | 
			
		||||
  Avoid using DLM locks with LCK_CACHE type P_ lock requests.
 | 
			
		||||
  When asked to drop cached committed VG metadata, invalidate cached PV labels.
 | 
			
		||||
  Drop metadata cache before writing precommitted metadata instead of after.
 | 
			
		||||
@@ -4396,7 +4081,7 @@ Version 2.02.34 - 10th April 2008
 | 
			
		||||
  Mention default --clustered setting in vgcreate man page.
 | 
			
		||||
  Add config file overrides to clvmd when it reads the active LVs list.
 | 
			
		||||
  Fix vgreduce to use vg_split_mdas to check sufficient mdas remain.
 | 
			
		||||
  Add (empty) orphan VGs to lvmcache during initialization.
 | 
			
		||||
  Add (empty) orphan VGs to lvmcache during initialisation.
 | 
			
		||||
  Fix orphan VG name used for format_pool.
 | 
			
		||||
  Create a fid for internal orphan VGs.
 | 
			
		||||
  Update lvmcache VG lock state for all locking types now.
 | 
			
		||||
@@ -4414,7 +4099,7 @@ Version 2.02.34 - 10th April 2008
 | 
			
		||||
  Fix redundant lvresize message if vg doesn't exist.
 | 
			
		||||
  Fix another allocation bug with clvmd and large node IDs.
 | 
			
		||||
  Add find_lv_in_lv_list() and find_pv_in_pv_list().
 | 
			
		||||
  Fix uninitialized variable in clvmd that could cause odd hangs.
 | 
			
		||||
  Fix uninitialised variable in clvmd that could cause odd hangs.
 | 
			
		||||
  Add vgmerge tests.
 | 
			
		||||
  Add pvseg_is_allocated() for identifying a PV segment allocated to a LV.
 | 
			
		||||
  Add list_move() for moving elements from one list to another.
 | 
			
		||||
@@ -4422,7 +4107,7 @@ Version 2.02.34 - 10th April 2008
 | 
			
		||||
  Correct command name in lvmdiskscan man page.
 | 
			
		||||
  clvmd no longer crashes if it sees nodeids over 50.
 | 
			
		||||
  Fix potential deadlock in clvmd thread handling.
 | 
			
		||||
  Refactor text format initialization into _init_text_import.
 | 
			
		||||
  Refactor text format initialisation into _init_text_import.
 | 
			
		||||
  Escape double quotes and backslashes in external metadata and config data.
 | 
			
		||||
  Add functions for escaping double quotes in strings.
 | 
			
		||||
  Rename count_chars_len to count_chars.
 | 
			
		||||
@@ -4472,7 +4157,7 @@ Version 2.02.31 - 19th January 2008
 | 
			
		||||
 | 
			
		||||
Version 2.02.30 - 17th January 2008
 | 
			
		||||
===================================
 | 
			
		||||
  Set default readahead to twice maximum stripe size.
 | 
			
		||||
  Set default readahead to twice maximium stripe size.
 | 
			
		||||
  Reinstate VG extent size and stripe size defaults (halved). (2.02.29)
 | 
			
		||||
  Add lists of stacked LV segments using each LV to the internal metadata.
 | 
			
		||||
  Change vgsplit -l (for unimplemented --list) into --maxlogicalvolumes.
 | 
			
		||||
@@ -4844,7 +4529,7 @@ Version 2.02.11 - 12th October 2006
 | 
			
		||||
  Capture error messages in clvmd and pass them back to the user.
 | 
			
		||||
  Remove unused #defines from filter-md.c.
 | 
			
		||||
  Make clvmd restart init script wait until clvmd has died before starting it.
 | 
			
		||||
  Add -R to clvmd which tells running clvmd to reload their device cache.
 | 
			
		||||
  Add -R to clvmd which tells running clvmds to reload their device cache.
 | 
			
		||||
  Add LV column to reports listing kernel modules needed for activation.
 | 
			
		||||
  Show available fields if report given invalid field. (e.g. lvs -o list)
 | 
			
		||||
  Add timestamp functions with --disable-realtime configure option.
 | 
			
		||||
@@ -5171,7 +4856,7 @@ Version 2.01.08 - 22nd March 2005
 | 
			
		||||
  Improve detection of external changes affecting internal cache.
 | 
			
		||||
  Add 'already in device cache' debug message.
 | 
			
		||||
  Add -a to pvdisplay -C.
 | 
			
		||||
  Avoid rmdir opendir error messages when dir was already removed.
 | 
			
		||||
  Avoid rmdir opendir error messsages when dir was already removed.
 | 
			
		||||
  Tighten signal handlers.
 | 
			
		||||
  Avoid some compiler warnings.
 | 
			
		||||
  Additional rename failure error message.
 | 
			
		||||
@@ -5402,7 +5087,7 @@ Version 2.00.17 - 20 June 2004
 | 
			
		||||
  fsadm support for fsck and resizing - needs testing.
 | 
			
		||||
  Add read-only GFS pool support.
 | 
			
		||||
  Add lvm2create_initrd script from http://poochiereds.net/svn/lvm2/
 | 
			
		||||
  Fix rounding of large displayed sizes.
 | 
			
		||||
  Fix rounding of large diplayed sizes.
 | 
			
		||||
  Suppress decimal point when using units of sectors/bytes.
 | 
			
		||||
  Additional kernel target checks before pvmove & snapshot creation.
 | 
			
		||||
  Add i2o_block.
 | 
			
		||||
@@ -5617,5 +5302,3 @@ Display output.  Some metadata information cannot yet be displayed.
 | 
			
		||||
 | 
			
		||||
Recovery tools to salvage "lost" metadata directly from the disks:
 | 
			
		||||
but we hope the new format will mean such tools are hardly ever needed!
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										151
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										151
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							@@ -1,112 +1,5 @@
 | 
			
		||||
Version 1.02.211 - 
 | 
			
		||||
===================
 | 
			
		||||
  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.183 - 
 | 
			
		||||
====================================
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
@@ -135,7 +28,7 @@ Version 1.02.173 - 09th August 2020
 | 
			
		||||
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).
 | 
			
		||||
  Fix dm_list interators with gcc 10 optimization (-ftree-pta).
 | 
			
		||||
  Dmeventd handles timer without looping on short intervals.
 | 
			
		||||
 | 
			
		||||
Version 1.02.169 - 11th February 2020
 | 
			
		||||
@@ -166,7 +59,7 @@ 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.
 | 
			
		||||
  Add DM_DEVICE_ARM_POLL for API completness matching kernel.
 | 
			
		||||
  Do not add parameters for RESUME with DM_DEVICE_CREATE dm task.
 | 
			
		||||
  Fix dmstats report printing no output.
 | 
			
		||||
 | 
			
		||||
@@ -195,7 +88,7 @@ Version 1.02.147-rc1 - 24th May 2018
 | 
			
		||||
  Reuse uname() result for mirror target.
 | 
			
		||||
  Recognize also mounted btrfs through dm_device_has_mounted_fs().
 | 
			
		||||
  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.
 | 
			
		||||
  Configured command for thin pool threshold handling gets whole environment.
 | 
			
		||||
  Fix tests for failing dm_snprintf() in stats code.
 | 
			
		||||
@@ -244,7 +137,7 @@ Version 1.02.141 - 28th June 2017
 | 
			
		||||
  Add dm_percent_to_round_float for adjusted percentage rounding.
 | 
			
		||||
  Reset array with dead rimage devices once raid gets in sync.
 | 
			
		||||
  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().
 | 
			
		||||
  Restore Warning by 5% increment when thin-pool is over 80% (1.02.138).
 | 
			
		||||
 | 
			
		||||
@@ -299,7 +192,7 @@ Version 1.02.136 - 5th November 2016
 | 
			
		||||
  Still produce output when dmsetup dependency tree building finds dev missing.
 | 
			
		||||
  Check and report pthread_sigmask() failure in dmeventd.
 | 
			
		||||
  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 stats walk segfault with dmsetup older than v1.02.129
 | 
			
		||||
 | 
			
		||||
@@ -439,7 +332,7 @@ Version 1.02.112 - 28th November 2015
 | 
			
		||||
=====================================
 | 
			
		||||
  Show error message when trying to create unsupported raid type.
 | 
			
		||||
  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
 | 
			
		||||
=====================================
 | 
			
		||||
@@ -454,7 +347,7 @@ Version 1.02.110 - 30th October 2015
 | 
			
		||||
  Disable thin monitoring plugin when it fails too often (>10 times).
 | 
			
		||||
  Fix/restore parsing of empty field '-' when processing dmeventd event.
 | 
			
		||||
  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.
 | 
			
		||||
  New design for thread co-operation in dmeventd.
 | 
			
		||||
  Dmeventd read device status with 'noflush'.
 | 
			
		||||
@@ -627,7 +520,7 @@ Version 1.02.93 - 21st January 2015
 | 
			
		||||
Version 1.02.92 - 24th November 2014
 | 
			
		||||
====================================
 | 
			
		||||
  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.
 | 
			
		||||
 | 
			
		||||
Version 1.02.91 - 11th November 2014
 | 
			
		||||
@@ -646,7 +539,7 @@ Version 1.02.90 - 1st September 2014
 | 
			
		||||
Version 1.02.89 - 26th August 2014
 | 
			
		||||
==================================
 | 
			
		||||
  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.
 | 
			
		||||
  Support --deferred with dmsetup remove to defer removal of open devices.
 | 
			
		||||
  Update dm-ioctl.h to include DM_DEFERRED_REMOVE flag.
 | 
			
		||||
@@ -733,7 +626,7 @@ Version 1.02.82 - 4th October 2013
 | 
			
		||||
 | 
			
		||||
Version 1.02.81 - 23rd September 2013
 | 
			
		||||
=====================================
 | 
			
		||||
  Tidy dmeventd fifo initialization.
 | 
			
		||||
  Tidy dmeventd fifo initialisation.
 | 
			
		||||
 | 
			
		||||
Version 1.02.80 - 20th September 2013
 | 
			
		||||
=====================================
 | 
			
		||||
@@ -758,7 +651,7 @@ Version 1.02.78 - 24th July 2013
 | 
			
		||||
  Always return success on dmeventd -V command call.
 | 
			
		||||
  Fix parsing of 64bit snapshot status in dmeventd snapshot plugin.
 | 
			
		||||
  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.
 | 
			
		||||
  Report error for nonexisting devices in dmeventd communication.
 | 
			
		||||
  Prevent double free error after dmeventd call of _fill_device_data().
 | 
			
		||||
@@ -855,7 +748,7 @@ Version 1.02.71 - 20th February 2012
 | 
			
		||||
  Add "watch" rule to 13-dm-disk.rules.
 | 
			
		||||
  Detect failing fifo and skip 20s retry communication period.
 | 
			
		||||
  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.
 | 
			
		||||
  Add mangle command to dmsetup to provide renaming to correct mangled form.
 | 
			
		||||
  Add 'mangled_name' and 'unmangled_name' fields to dmsetup info -c -o.
 | 
			
		||||
@@ -949,7 +842,7 @@ Version 1.02.66 - 12th August 2011
 | 
			
		||||
  Fix memory leak in dmsetup _message() memory allocation error path.
 | 
			
		||||
  Use new oom killer adjustment interface (oom_score_adj) when available.
 | 
			
		||||
  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
 | 
			
		||||
===============================
 | 
			
		||||
@@ -964,7 +857,7 @@ Version 1.02.65 - 8th July 2011
 | 
			
		||||
  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.
 | 
			
		||||
  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
 | 
			
		||||
==================================
 | 
			
		||||
@@ -978,7 +871,7 @@ Version 1.02.64 - 29th April 2011
 | 
			
		||||
  Improve stack debug reporting in dm_task_create().
 | 
			
		||||
  Fallback to control node creation only if node doesn't exist yet.
 | 
			
		||||
  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.
 | 
			
		||||
  Add test for failed allocation from dm_task_set_uuid() in dmeventd.
 | 
			
		||||
  Add dm_event_get_version to dmeventd for use with -R.
 | 
			
		||||
@@ -1147,7 +1040,7 @@ Version 1.02.44 - 15th February 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.
 | 
			
		||||
 | 
			
		||||
Version 1.02.42 - 14th January 2010
 | 
			
		||||
@@ -1203,7 +1096,7 @@ Version 1.02.37 - 15th September 2009
 | 
			
		||||
Version 1.02.36 - 6th August 2009
 | 
			
		||||
=================================
 | 
			
		||||
  Add udevcookies, udevcomplete, udevcomplete_all and --noudevwait to dmsetup.
 | 
			
		||||
  Add libdevmapper functions to support synchronization with udev.
 | 
			
		||||
  Add libdevmapper functions to support synchronisation with udev.
 | 
			
		||||
 | 
			
		||||
Version 1.02.35 - 28th July 2009
 | 
			
		||||
================================
 | 
			
		||||
@@ -1271,7 +1164,7 @@ Version 1.02.27 - 25th 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.
 | 
			
		||||
  Make dm_hash_iter safe against deletion.
 | 
			
		||||
  Accept a NULL pointer to dm_free silently.
 | 
			
		||||
@@ -1327,7 +1220,7 @@ Version 1.02.20 - 15th June 2007
 | 
			
		||||
 | 
			
		||||
Version 1.02.19 - 27th April 2007
 | 
			
		||||
=================================
 | 
			
		||||
  Standardize protective include file #defines.
 | 
			
		||||
  Standardise protective include file #defines.
 | 
			
		||||
  Add regex functions to library.
 | 
			
		||||
  Avoid trailing separator in reports when there are hidden sort fields.
 | 
			
		||||
  Fix segfault in 'dmsetup status' without --showkeys against crypt target.
 | 
			
		||||
@@ -1358,7 +1251,7 @@ Version 1.02.16 - 25th January 2007
 | 
			
		||||
  Streamline dm_report_field_* interface.
 | 
			
		||||
  Add cmdline debug & version options to dmeventd.
 | 
			
		||||
  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).
 | 
			
		||||
  Make alignment flag optional when specifying report fields.
 | 
			
		||||
 | 
			
		||||
@@ -1606,5 +1499,3 @@ Version 1.00.08 - 27 Feb 2004
 | 
			
		||||
  Fixed DESTDIR for make install/install_static_lib.
 | 
			
		||||
  Updated README/INSTALL to reflect move to sources.redhat.com.
 | 
			
		||||
  Updated autoconf files to 2003-06-17.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								acinclude.m4
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								acinclude.m4
									
									
									
									
									
								
							@@ -62,24 +62,6 @@ AC_DEFUN([AC_TRY_LDFLAGS],
 | 
			
		||||
    fi
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
 | 
			
		||||
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
 | 
			
		||||
dnl -------------------------------------------
 | 
			
		||||
dnl Since: 0.28
 | 
			
		||||
dnl
 | 
			
		||||
dnl Retrieves the value of the pkg-config variable for the given module.
 | 
			
		||||
AC_DEFUN([PKG_CHECK_VAR],
 | 
			
		||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 | 
			
		||||
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
 | 
			
		||||
 | 
			
		||||
_PKG_CONFIG([$1], [variable="][$3]["], [$2])
 | 
			
		||||
AS_VAR_COPY([$1], [pkg_cv_][$1])
 | 
			
		||||
 | 
			
		||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
 | 
			
		||||
])dnl PKG_CHECK_VAR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# ===========================================================================
 | 
			
		||||
#      http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html
 | 
			
		||||
# ===========================================================================
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										351
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										351
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
# generated automatically by aclocal 1.18.1 -*- Autoconf -*-
 | 
			
		||||
# generated automatically by aclocal 1.16.2 -*- Autoconf -*-
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 1996-2025 Free Software Foundation, Inc.
 | 
			
		||||
# Copyright (C) 1996-2020 Free Software Foundation, Inc.
 | 
			
		||||
 | 
			
		||||
# This file is free software; the Free Software Foundation
 | 
			
		||||
# gives unlimited permission to copy and/or distribute it,
 | 
			
		||||
@@ -69,8 +69,8 @@ AC_DEFUN([AX_PYTHON_MODULE],[
 | 
			
		||||
    fi
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
# pkg.m4 - Macros to locate and use pkg-config.   -*- Autoconf -*-
 | 
			
		||||
# serial 12 (pkg-config-0.29.2)
 | 
			
		||||
# pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
 | 
			
		||||
# serial 11 (pkg-config-0.29.1)
 | 
			
		||||
 | 
			
		||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
 | 
			
		||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
 | 
			
		||||
@@ -112,13 +112,13 @@ dnl
 | 
			
		||||
dnl See the "Since" comment for each macro you use to see what version
 | 
			
		||||
dnl of the macros you require.
 | 
			
		||||
m4_defun([PKG_PREREQ],
 | 
			
		||||
[m4_define([PKG_MACROS_VERSION], [0.29.2])
 | 
			
		||||
[m4_define([PKG_MACROS_VERSION], [0.29.1])
 | 
			
		||||
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
 | 
			
		||||
    [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
 | 
			
		||||
])dnl PKG_PREREQ
 | 
			
		||||
 | 
			
		||||
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION], [ACTION-IF-NOT-FOUND])
 | 
			
		||||
dnl ---------------------------------------------------------
 | 
			
		||||
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
 | 
			
		||||
dnl ----------------------------------
 | 
			
		||||
dnl Since: 0.16
 | 
			
		||||
dnl
 | 
			
		||||
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 used since that's the first version where most current features of
 | 
			
		||||
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],
 | 
			
		||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
 | 
			
		||||
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])
 | 
			
		||||
		PKG_CONFIG=""
 | 
			
		||||
	fi
 | 
			
		||||
fi
 | 
			
		||||
if test -z "$PKG_CONFIG"; then
 | 
			
		||||
	m4_default([$2], [AC_MSG_ERROR([pkg-config not found])])
 | 
			
		||||
fi[]dnl
 | 
			
		||||
])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
 | 
			
		||||
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
 | 
			
		||||
dnl only at the first occurrence in configure.ac, so if the first place
 | 
			
		||||
dnl only at the first occurence in configure.ac, so if the first place
 | 
			
		||||
dnl it's called might be skipped (such as if it is within an "if", you
 | 
			
		||||
dnl have to call PKG_CHECK_EXISTS manually
 | 
			
		||||
AC_DEFUN([PKG_CHECK_EXISTS],
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
pkg_failed=no
 | 
			
		||||
AC_MSG_CHECKING([for $2])
 | 
			
		||||
AC_MSG_CHECKING([for $1])
 | 
			
		||||
 | 
			
		||||
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
 | 
			
		||||
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
 | 
			
		||||
@@ -232,17 +223,17 @@ and $1[]_LIBS to avoid the need to call pkg-config.
 | 
			
		||||
See the pkg-config man page for more details.])
 | 
			
		||||
 | 
			
		||||
if test $pkg_failed = yes; then
 | 
			
		||||
        AC_MSG_RESULT([no])
 | 
			
		||||
   	AC_MSG_RESULT([no])
 | 
			
		||||
        _PKG_SHORT_ERRORS_SUPPORTED
 | 
			
		||||
        if test $_pkg_short_errors_supported = yes; then
 | 
			
		||||
                $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
 | 
			
		||||
        else
 | 
			
		||||
                $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
 | 
			
		||||
	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
 | 
			
		||||
        else 
 | 
			
		||||
	        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
 | 
			
		||||
        fi
 | 
			
		||||
        # Put the nasty error message in config.log where it belongs
 | 
			
		||||
        echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
 | 
			
		||||
	# Put the nasty error message in config.log where it belongs
 | 
			
		||||
	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
 | 
			
		||||
 | 
			
		||||
        m4_default([$4], [AC_MSG_ERROR(
 | 
			
		||||
	m4_default([$4], [AC_MSG_ERROR(
 | 
			
		||||
[Package requirements ($2) were not met:
 | 
			
		||||
 | 
			
		||||
$$1_PKG_ERRORS
 | 
			
		||||
@@ -253,8 +244,8 @@ installed software in a non-standard prefix.
 | 
			
		||||
_PKG_TEXT])[]dnl
 | 
			
		||||
        ])
 | 
			
		||||
elif test $pkg_failed = untried; then
 | 
			
		||||
        AC_MSG_RESULT([no])
 | 
			
		||||
        m4_default([$4], [AC_MSG_FAILURE(
 | 
			
		||||
     	AC_MSG_RESULT([no])
 | 
			
		||||
	m4_default([$4], [AC_MSG_FAILURE(
 | 
			
		||||
[The pkg-config script could not be found or is too old.  Make sure it
 | 
			
		||||
is in your PATH or set the PKG_CONFIG environment variable to the full
 | 
			
		||||
path to pkg-config.
 | 
			
		||||
@@ -264,10 +255,10 @@ _PKG_TEXT
 | 
			
		||||
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
 | 
			
		||||
        ])
 | 
			
		||||
else
 | 
			
		||||
        $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
 | 
			
		||||
        $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
 | 
			
		||||
	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
 | 
			
		||||
	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
 | 
			
		||||
        AC_MSG_RESULT([yes])
 | 
			
		||||
        $3
 | 
			
		||||
	$3
 | 
			
		||||
fi[]dnl
 | 
			
		||||
])dnl PKG_CHECK_MODULES
 | 
			
		||||
 | 
			
		||||
@@ -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])])
 | 
			
		||||
])dnl PKG_HAVE_DEFINE_WITH_MODULES
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 1999-2025 Free Software Foundation, Inc.
 | 
			
		||||
# Copyright (C) 1999-2020 Free Software Foundation, Inc.
 | 
			
		||||
#
 | 
			
		||||
# This file is free software; the Free Software Foundation
 | 
			
		||||
# gives unlimited permission to copy and/or distribute it,
 | 
			
		||||
@@ -456,12 +447,9 @@ AC_DEFUN([AM_PATH_PYTHON],
 | 
			
		||||
  dnl Find a Python interpreter.  Python versions prior to 2.0 are not
 | 
			
		||||
  dnl supported. (2.0 was released on October 16, 2000).
 | 
			
		||||
  m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
 | 
			
		||||
[python python3 dnl
 | 
			
		||||
 python3.20 python3.19 python3.18 python3.17 python3.16 dnl
 | 
			
		||||
 python3.15 python3.14 python3.13 python3.12 python3.11 python3.10 dnl
 | 
			
		||||
[python python2 python3 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])
 | 
			
		||||
 | 
			
		||||
@@ -504,7 +492,7 @@ AC_DEFUN([AM_PATH_PYTHON],
 | 
			
		||||
  ])
 | 
			
		||||
 | 
			
		||||
  if test "$PYTHON" = :; then
 | 
			
		||||
    dnl Run any user-specified action, or abort.
 | 
			
		||||
  dnl Run any user-specified action, or abort.
 | 
			
		||||
    m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
 | 
			
		||||
  else
 | 
			
		||||
 | 
			
		||||
@@ -513,132 +501,27 @@ AC_DEFUN([AM_PATH_PYTHON],
 | 
			
		||||
  dnl trailing zero was eliminated. So now we output just the major
 | 
			
		||||
  dnl and minor version numbers, as numbers. Apparently the tertiary
 | 
			
		||||
  dnl version is not of interest.
 | 
			
		||||
  dnl
 | 
			
		||||
 | 
			
		||||
  AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
 | 
			
		||||
    [am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[[:2]])"`])
 | 
			
		||||
    [am_cv_python_version=`$PYTHON -c "import sys; print('%u.%u' % sys.version_info[[:2]])"`])
 | 
			
		||||
  AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
 | 
			
		||||
 | 
			
		||||
  dnl At times, e.g., when building shared libraries, you may want
 | 
			
		||||
  dnl Use the values of $prefix and $exec_prefix for the corresponding
 | 
			
		||||
  dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX.  These are made
 | 
			
		||||
  dnl distinct variables so they can be overridden if need be.  However,
 | 
			
		||||
  dnl general consensus is that you shouldn't need this ability.
 | 
			
		||||
 | 
			
		||||
  AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
 | 
			
		||||
  AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
 | 
			
		||||
 | 
			
		||||
  dnl At times (like when building shared libraries) you may want
 | 
			
		||||
  dnl to know which OS platform Python thinks this is.
 | 
			
		||||
  dnl
 | 
			
		||||
 | 
			
		||||
  AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
 | 
			
		||||
    [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
 | 
			
		||||
  AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
 | 
			
		||||
 | 
			
		||||
  dnl emacs-page
 | 
			
		||||
  dnl If --with-python-sys-prefix is given, use the values of sys.prefix
 | 
			
		||||
  dnl and sys.exec_prefix for the corresponding values of PYTHON_PREFIX
 | 
			
		||||
  dnl and PYTHON_EXEC_PREFIX. Otherwise, use the GNU ${prefix} and
 | 
			
		||||
  dnl ${exec_prefix} variables.
 | 
			
		||||
  dnl
 | 
			
		||||
  dnl The two are made distinct variables so they can be overridden if
 | 
			
		||||
  dnl need be, although general consensus is that you shouldn't need
 | 
			
		||||
  dnl this separation.
 | 
			
		||||
  dnl
 | 
			
		||||
  dnl Also allow directly setting the prefixes via configure options,
 | 
			
		||||
  dnl overriding any default.
 | 
			
		||||
  dnl
 | 
			
		||||
  if test "x$prefix" = xNONE; then
 | 
			
		||||
    am__usable_prefix=$ac_default_prefix
 | 
			
		||||
  else
 | 
			
		||||
    am__usable_prefix=$prefix
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Allow user to request using sys.* values from Python,
 | 
			
		||||
  # instead of the GNU $prefix values.
 | 
			
		||||
  AC_ARG_WITH([python-sys-prefix],
 | 
			
		||||
  [AS_HELP_STRING([--with-python-sys-prefix],
 | 
			
		||||
                  [use Python's sys.prefix and sys.exec_prefix values])],
 | 
			
		||||
  [am_use_python_sys=:],
 | 
			
		||||
  [am_use_python_sys=false])
 | 
			
		||||
 | 
			
		||||
  # Allow user to override whatever the default Python prefix is.
 | 
			
		||||
  AC_ARG_WITH([python_prefix],
 | 
			
		||||
  [AS_HELP_STRING([--with-python_prefix],
 | 
			
		||||
                  [override the default PYTHON_PREFIX])],
 | 
			
		||||
  [am_python_prefix_subst=$withval
 | 
			
		||||
   am_cv_python_prefix=$withval
 | 
			
		||||
   AC_MSG_CHECKING([for explicit $am_display_PYTHON prefix])
 | 
			
		||||
   AC_MSG_RESULT([$am_cv_python_prefix])],
 | 
			
		||||
  [
 | 
			
		||||
   if $am_use_python_sys; then
 | 
			
		||||
     # using python sys.prefix value, not GNU
 | 
			
		||||
     AC_CACHE_CHECK([for python default $am_display_PYTHON prefix],
 | 
			
		||||
     [am_cv_python_prefix],
 | 
			
		||||
     [am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"`])
 | 
			
		||||
 | 
			
		||||
     dnl If sys.prefix is a subdir of $prefix, replace the literal value of
 | 
			
		||||
     dnl $prefix with a variable reference so it can be overridden.
 | 
			
		||||
     case $am_cv_python_prefix in
 | 
			
		||||
     $am__usable_prefix*)
 | 
			
		||||
       am__strip_prefix=`echo "$am__usable_prefix" | sed 's|.|.|g'`
 | 
			
		||||
       am_python_prefix_subst=`echo "$am_cv_python_prefix" | sed "s,^$am__strip_prefix,\\${prefix},"`
 | 
			
		||||
       ;;
 | 
			
		||||
     *)
 | 
			
		||||
       am_python_prefix_subst=$am_cv_python_prefix
 | 
			
		||||
       ;;
 | 
			
		||||
     esac
 | 
			
		||||
   else # using GNU prefix value, not python sys.prefix
 | 
			
		||||
     am_python_prefix_subst='${prefix}'
 | 
			
		||||
     am_python_prefix=$am_python_prefix_subst
 | 
			
		||||
     AC_MSG_CHECKING([for GNU default $am_display_PYTHON prefix])
 | 
			
		||||
     AC_MSG_RESULT([$am_python_prefix])
 | 
			
		||||
   fi])
 | 
			
		||||
  # Substituting python_prefix_subst value.
 | 
			
		||||
  AC_SUBST([PYTHON_PREFIX], [$am_python_prefix_subst])
 | 
			
		||||
 | 
			
		||||
  # emacs-page Now do it all over again for Python exec_prefix, but with yet
 | 
			
		||||
  # another conditional: fall back to regular prefix if that was specified.
 | 
			
		||||
  AC_ARG_WITH([python_exec_prefix],
 | 
			
		||||
  [AS_HELP_STRING([--with-python_exec_prefix],
 | 
			
		||||
                  [override the default PYTHON_EXEC_PREFIX])],
 | 
			
		||||
  [am_python_exec_prefix_subst=$withval
 | 
			
		||||
   am_cv_python_exec_prefix=$withval
 | 
			
		||||
   AC_MSG_CHECKING([for explicit $am_display_PYTHON exec_prefix])
 | 
			
		||||
   AC_MSG_RESULT([$am_cv_python_exec_prefix])],
 | 
			
		||||
  [
 | 
			
		||||
   # no explicit --with-python_exec_prefix, but if
 | 
			
		||||
   # --with-python_prefix was given, use its value for python_exec_prefix too.
 | 
			
		||||
   AS_IF([test -n "$with_python_prefix"],
 | 
			
		||||
   [am_python_exec_prefix_subst=$with_python_prefix
 | 
			
		||||
    am_cv_python_exec_prefix=$with_python_prefix
 | 
			
		||||
    AC_MSG_CHECKING([for python_prefix-given $am_display_PYTHON exec_prefix])
 | 
			
		||||
    AC_MSG_RESULT([$am_cv_python_exec_prefix])],
 | 
			
		||||
   [
 | 
			
		||||
    # Set am__usable_exec_prefix whether using GNU or Python values,
 | 
			
		||||
    # since we use that variable for pyexecdir.
 | 
			
		||||
    if test "x$exec_prefix" = xNONE; then
 | 
			
		||||
      am__usable_exec_prefix=$am__usable_prefix
 | 
			
		||||
    else
 | 
			
		||||
      am__usable_exec_prefix=$exec_prefix
 | 
			
		||||
    fi
 | 
			
		||||
    #
 | 
			
		||||
    if $am_use_python_sys; then # using python sys.exec_prefix, not GNU
 | 
			
		||||
      AC_CACHE_CHECK([for python default $am_display_PYTHON exec_prefix],
 | 
			
		||||
      [am_cv_python_exec_prefix],
 | 
			
		||||
      [am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"`])
 | 
			
		||||
      dnl If sys.exec_prefix is a subdir of $exec_prefix, replace the
 | 
			
		||||
      dnl literal value of $exec_prefix with a variable reference so it can
 | 
			
		||||
      dnl be overridden.
 | 
			
		||||
      case $am_cv_python_exec_prefix in
 | 
			
		||||
      $am__usable_exec_prefix*)
 | 
			
		||||
        am__strip_prefix=`echo "$am__usable_exec_prefix" | sed 's|.|.|g'`
 | 
			
		||||
        am_python_exec_prefix_subst=`echo "$am_cv_python_exec_prefix" | sed "s,^$am__strip_prefix,\\${exec_prefix},"`
 | 
			
		||||
        ;;
 | 
			
		||||
      *)
 | 
			
		||||
        am_python_exec_prefix_subst=$am_cv_python_exec_prefix
 | 
			
		||||
        ;;
 | 
			
		||||
     esac
 | 
			
		||||
   else # using GNU $exec_prefix, not python sys.exec_prefix
 | 
			
		||||
     am_python_exec_prefix_subst='${exec_prefix}'
 | 
			
		||||
     am_python_exec_prefix=$am_python_exec_prefix_subst
 | 
			
		||||
     AC_MSG_CHECKING([for GNU default $am_display_PYTHON exec_prefix])
 | 
			
		||||
     AC_MSG_RESULT([$am_python_exec_prefix])
 | 
			
		||||
   fi])])
 | 
			
		||||
  # Substituting python_exec_prefix_subst.
 | 
			
		||||
  AC_SUBST([PYTHON_EXEC_PREFIX], [$am_python_exec_prefix_subst])
 | 
			
		||||
 | 
			
		||||
  # Factor out some code duplication into this shell variable.
 | 
			
		||||
  # Just factor out some code duplication.
 | 
			
		||||
  am_python_setup_sysconfig="\
 | 
			
		||||
import sys
 | 
			
		||||
# Prefer sysconfig over distutils.sysconfig, for better compatibility
 | 
			
		||||
@@ -656,120 +539,98 @@ try:
 | 
			
		||||
    if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7':
 | 
			
		||||
        can_use_sysconfig = 0
 | 
			
		||||
except ImportError:
 | 
			
		||||
    pass" # end of am_python_setup_sysconfig
 | 
			
		||||
    pass"
 | 
			
		||||
 | 
			
		||||
  # More repeated code, for figuring out the installation scheme to use.
 | 
			
		||||
  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 Set up 4 directories:
 | 
			
		||||
 | 
			
		||||
  dnl emacs-page Set up 4 directories:
 | 
			
		||||
 | 
			
		||||
  dnl 1. pythondir: where to install python scripts.  This is the
 | 
			
		||||
  dnl    site-packages directory, not the python standard library
 | 
			
		||||
  dnl    directory as in early automake betas.  This behavior
 | 
			
		||||
  dnl    is more consistent with lispdir.m4 for example.
 | 
			
		||||
  dnl Query sysconfig or distutils (per above) for this directory.
 | 
			
		||||
  dnl
 | 
			
		||||
  AC_CACHE_CHECK([for $am_display_PYTHON script directory (pythondir)],
 | 
			
		||||
  [am_cv_python_pythondir],
 | 
			
		||||
  [if test "x$am_cv_python_prefix" = x; then
 | 
			
		||||
     am_py_prefix=$am__usable_prefix
 | 
			
		||||
   else
 | 
			
		||||
     am_py_prefix=$am_cv_python_prefix
 | 
			
		||||
   fi
 | 
			
		||||
   am_cv_python_pythondir=`$PYTHON -c "
 | 
			
		||||
  dnl pythondir -- where to install python scripts.  This is the
 | 
			
		||||
  dnl   site-packages directory, not the python standard library
 | 
			
		||||
  dnl   directory like in previous automake betas.  This behavior
 | 
			
		||||
  dnl   is more consistent with lispdir.m4 for example.
 | 
			
		||||
  dnl Query distutils for this directory.
 | 
			
		||||
  AC_CACHE_CHECK([for $am_display_PYTHON script directory],
 | 
			
		||||
    [am_cv_python_pythondir],
 | 
			
		||||
    [if test "x$prefix" = xNONE
 | 
			
		||||
     then
 | 
			
		||||
       am_py_prefix=$ac_default_prefix
 | 
			
		||||
     else
 | 
			
		||||
       am_py_prefix=$prefix
 | 
			
		||||
     fi
 | 
			
		||||
     am_cv_python_pythondir=`$PYTHON -c "
 | 
			
		||||
$am_python_setup_sysconfig
 | 
			
		||||
if can_use_sysconfig:
 | 
			
		||||
  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'})
 | 
			
		||||
else:
 | 
			
		||||
  from distutils import sysconfig
 | 
			
		||||
  sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
 | 
			
		||||
    from distutils import sysconfig
 | 
			
		||||
    sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
 | 
			
		||||
sys.stdout.write(sitedir)"`
 | 
			
		||||
   #
 | 
			
		||||
   case $am_cv_python_pythondir in
 | 
			
		||||
   $am_py_prefix*)
 | 
			
		||||
     am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
 | 
			
		||||
     am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,\\${PYTHON_PREFIX},"`
 | 
			
		||||
     ;;
 | 
			
		||||
   *)
 | 
			
		||||
     case $am_py_prefix in
 | 
			
		||||
       /usr|/System*) ;;
 | 
			
		||||
       *) am_cv_python_pythondir="\${PYTHON_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
 | 
			
		||||
          ;;
 | 
			
		||||
     case $am_cv_python_pythondir in
 | 
			
		||||
     $am_py_prefix*)
 | 
			
		||||
       am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
 | 
			
		||||
       am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
 | 
			
		||||
       ;;
 | 
			
		||||
     *)
 | 
			
		||||
       case $am_py_prefix in
 | 
			
		||||
         /usr|/System*) ;;
 | 
			
		||||
         *)
 | 
			
		||||
	  am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
 | 
			
		||||
	  ;;
 | 
			
		||||
       esac
 | 
			
		||||
       ;;
 | 
			
		||||
     esac
 | 
			
		||||
     ;;
 | 
			
		||||
   esac
 | 
			
		||||
  ])
 | 
			
		||||
    ])
 | 
			
		||||
  AC_SUBST([pythondir], [$am_cv_python_pythondir])
 | 
			
		||||
 | 
			
		||||
  dnl 2. pkgpythondir: $PACKAGE directory under pythondir.  Was
 | 
			
		||||
  dnl    PYTHON_SITE_PACKAGE in previous betas, but this naming is
 | 
			
		||||
  dnl    more consistent with the rest of automake.
 | 
			
		||||
  dnl
 | 
			
		||||
  dnl pkgpythondir -- $PACKAGE directory under pythondir.  Was
 | 
			
		||||
  dnl   PYTHON_SITE_PACKAGE in previous betas, but this naming is
 | 
			
		||||
  dnl   more consistent with the rest of automake.
 | 
			
		||||
 | 
			
		||||
  AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
 | 
			
		||||
 | 
			
		||||
  dnl 3. pyexecdir: directory for installing python extension modules
 | 
			
		||||
  dnl    (shared libraries).
 | 
			
		||||
  dnl Query sysconfig or distutils for this directory.
 | 
			
		||||
  dnl Much of this is the same as for prefix setup above.
 | 
			
		||||
  dnl
 | 
			
		||||
  AC_CACHE_CHECK([for $am_display_PYTHON extension module directory (pyexecdir)],
 | 
			
		||||
  [am_cv_python_pyexecdir],
 | 
			
		||||
  [if test "x$am_cv_python_exec_prefix" = x; then
 | 
			
		||||
     am_py_exec_prefix=$am__usable_exec_prefix
 | 
			
		||||
   else
 | 
			
		||||
     am_py_exec_prefix=$am_cv_python_exec_prefix
 | 
			
		||||
   fi
 | 
			
		||||
   am_cv_python_pyexecdir=`$PYTHON -c "
 | 
			
		||||
  dnl pyexecdir -- directory for installing python extension modules
 | 
			
		||||
  dnl   (shared libraries)
 | 
			
		||||
  dnl Query distutils for this directory.
 | 
			
		||||
  AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
 | 
			
		||||
    [am_cv_python_pyexecdir],
 | 
			
		||||
    [if test "x$exec_prefix" = xNONE
 | 
			
		||||
     then
 | 
			
		||||
       am_py_exec_prefix=$am_py_prefix
 | 
			
		||||
     else
 | 
			
		||||
       am_py_exec_prefix=$exec_prefix
 | 
			
		||||
     fi
 | 
			
		||||
     am_cv_python_pyexecdir=`$PYTHON -c "
 | 
			
		||||
$am_python_setup_sysconfig
 | 
			
		||||
if can_use_sysconfig:
 | 
			
		||||
  try:
 | 
			
		||||
    $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'})
 | 
			
		||||
    sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
 | 
			
		||||
else:
 | 
			
		||||
  from distutils import sysconfig
 | 
			
		||||
  sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix')
 | 
			
		||||
    from distutils import sysconfig
 | 
			
		||||
    sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
 | 
			
		||||
sys.stdout.write(sitedir)"`
 | 
			
		||||
   #
 | 
			
		||||
   case $am_cv_python_pyexecdir in
 | 
			
		||||
   $am_py_exec_prefix*)
 | 
			
		||||
     am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
 | 
			
		||||
     am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,\\${PYTHON_EXEC_PREFIX},"`
 | 
			
		||||
     ;;
 | 
			
		||||
   *)
 | 
			
		||||
     case $am_py_exec_prefix in
 | 
			
		||||
       /usr|/System*) ;;
 | 
			
		||||
       *) am_cv_python_pyexecdir="\${PYTHON_EXEC_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
 | 
			
		||||
          ;;
 | 
			
		||||
     case $am_cv_python_pyexecdir in
 | 
			
		||||
     $am_py_exec_prefix*)
 | 
			
		||||
       am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
 | 
			
		||||
       am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
 | 
			
		||||
       ;;
 | 
			
		||||
     *)
 | 
			
		||||
       case $am_py_exec_prefix in
 | 
			
		||||
         /usr|/System*) ;;
 | 
			
		||||
         *)
 | 
			
		||||
	   am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
 | 
			
		||||
	   ;;
 | 
			
		||||
       esac
 | 
			
		||||
       ;;
 | 
			
		||||
     esac
 | 
			
		||||
     ;;
 | 
			
		||||
   esac
 | 
			
		||||
  ])
 | 
			
		||||
    ])
 | 
			
		||||
  AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
 | 
			
		||||
 | 
			
		||||
  dnl 4. pkgpyexecdir: $(pyexecdir)/$(PACKAGE)
 | 
			
		||||
  dnl
 | 
			
		||||
  dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
 | 
			
		||||
 | 
			
		||||
  AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
 | 
			
		||||
 | 
			
		||||
  dnl Run any user-specified action.
 | 
			
		||||
  $2
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -792,7 +653,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
 | 
			
		||||
sys.exit(sys.hexversion < minverhex)"
 | 
			
		||||
  AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 2001-2025 Free Software Foundation, Inc.
 | 
			
		||||
# Copyright (C) 2001-2020 Free Software Foundation, Inc.
 | 
			
		||||
#
 | 
			
		||||
# This file is free software; the Free Software Foundation
 | 
			
		||||
# gives unlimited permission to copy and/or distribute it,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1712
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1712
									
								
								autoconf/config.guess
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2881
									
								
								autoconf/config.sub
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2881
									
								
								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
 | 
			
		||||
 | 
			
		||||
scriptversion=2020-11-14.01; # UTC
 | 
			
		||||
scriptversion=2006-10-14.15
 | 
			
		||||
 | 
			
		||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
 | 
			
		||||
# later released in X11R6 (xc/config/util/install.sh) with the
 | 
			
		||||
@@ -35,62 +35,57 @@ scriptversion=2020-11-14.01; # UTC
 | 
			
		||||
# FSF changes to this file are in the public domain.
 | 
			
		||||
#
 | 
			
		||||
# Calling this script install-sh is preferred over install.sh, to prevent
 | 
			
		||||
# 'make' implicit rules from creating a file called install from it
 | 
			
		||||
# `make' implicit rules from creating a file called install from it
 | 
			
		||||
# when there is no Makefile.
 | 
			
		||||
#
 | 
			
		||||
# This script is compatible with the BSD install script, but was written
 | 
			
		||||
# from scratch.
 | 
			
		||||
 | 
			
		||||
tab='	'
 | 
			
		||||
nl='
 | 
			
		||||
'
 | 
			
		||||
IFS=" $tab$nl"
 | 
			
		||||
IFS=" ""	$nl"
 | 
			
		||||
 | 
			
		||||
# Set DOITPROG to "echo" to test this script.
 | 
			
		||||
# set DOITPROG to echo to test this script
 | 
			
		||||
 | 
			
		||||
doit=${DOITPROG-}
 | 
			
		||||
doit_exec=${doit:-exec}
 | 
			
		||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
 | 
			
		||||
doit="${DOITPROG-}"
 | 
			
		||||
if test -z "$doit"; then
 | 
			
		||||
  doit_exec=exec
 | 
			
		||||
else
 | 
			
		||||
  doit_exec=$doit
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Put in absolute file names if you don't have them in your path;
 | 
			
		||||
# or use environment vars.
 | 
			
		||||
 | 
			
		||||
chgrpprog=${CHGRPPROG-chgrp}
 | 
			
		||||
chmodprog=${CHMODPROG-chmod}
 | 
			
		||||
chownprog=${CHOWNPROG-chown}
 | 
			
		||||
cmpprog=${CMPPROG-cmp}
 | 
			
		||||
cpprog=${CPPROG-cp}
 | 
			
		||||
mkdirprog=${MKDIRPROG-mkdir}
 | 
			
		||||
mvprog=${MVPROG-mv}
 | 
			
		||||
rmprog=${RMPROG-rm}
 | 
			
		||||
stripprog=${STRIPPROG-strip}
 | 
			
		||||
mvprog="${MVPROG-mv}"
 | 
			
		||||
cpprog="${CPPROG-cp}"
 | 
			
		||||
chmodprog="${CHMODPROG-chmod}"
 | 
			
		||||
chownprog="${CHOWNPROG-chown}"
 | 
			
		||||
chgrpprog="${CHGRPPROG-chgrp}"
 | 
			
		||||
stripprog="${STRIPPROG-strip}"
 | 
			
		||||
rmprog="${RMPROG-rm}"
 | 
			
		||||
mkdirprog="${MKDIRPROG-mkdir}"
 | 
			
		||||
 | 
			
		||||
posix_glob=
 | 
			
		||||
posix_mkdir=
 | 
			
		||||
 | 
			
		||||
# Desired mode of installed file.
 | 
			
		||||
mode=0755
 | 
			
		||||
 | 
			
		||||
# Create dirs (including intermediate dirs) using mode 755.
 | 
			
		||||
# This is like GNU 'install' as of coreutils 8.32 (2020).
 | 
			
		||||
mkdir_umask=22
 | 
			
		||||
 | 
			
		||||
backupsuffix=
 | 
			
		||||
chgrpcmd=
 | 
			
		||||
chmodcmd=$chmodprog
 | 
			
		||||
chowncmd=
 | 
			
		||||
mvcmd=$mvprog
 | 
			
		||||
rmcmd="$rmprog -f"
 | 
			
		||||
chgrpcmd=
 | 
			
		||||
stripcmd=
 | 
			
		||||
 | 
			
		||||
rmcmd="$rmprog -f"
 | 
			
		||||
mvcmd="$mvprog"
 | 
			
		||||
src=
 | 
			
		||||
dst=
 | 
			
		||||
dir_arg=
 | 
			
		||||
dst_arg=
 | 
			
		||||
dstarg=
 | 
			
		||||
no_target_directory=
 | 
			
		||||
 | 
			
		||||
copy_on_change=false
 | 
			
		||||
is_target_a_directory=possibly
 | 
			
		||||
 | 
			
		||||
usage="\
 | 
			
		||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
 | 
			
		||||
usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
 | 
			
		||||
   or: $0 [OPTION]... SRCFILES... DIRECTORY
 | 
			
		||||
   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
 | 
			
		||||
   or: $0 [OPTION]... -d DIRECTORIES...
 | 
			
		||||
@@ -100,116 +95,91 @@ In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
 | 
			
		||||
In the 4th, create DIRECTORIES.
 | 
			
		||||
 | 
			
		||||
Options:
 | 
			
		||||
     --help     display this help and exit.
 | 
			
		||||
     --version  display version info and exit.
 | 
			
		||||
 | 
			
		||||
  -c            (ignored)
 | 
			
		||||
  -C            install only if different (preserve data modification time)
 | 
			
		||||
  -d            create directories instead of installing files.
 | 
			
		||||
  -g GROUP      $chgrpprog installed files to GROUP.
 | 
			
		||||
  -m MODE       $chmodprog installed files to MODE.
 | 
			
		||||
  -o USER       $chownprog installed files to USER.
 | 
			
		||||
  -p            pass -p to $cpprog.
 | 
			
		||||
  -s            $stripprog installed files.
 | 
			
		||||
  -S SUFFIX     attempt to back up existing files, with suffix SUFFIX.
 | 
			
		||||
  -t DIRECTORY  install into DIRECTORY.
 | 
			
		||||
  -T            report an error if DSTFILE is a directory.
 | 
			
		||||
-c         (ignored)
 | 
			
		||||
-d         create directories instead of installing files.
 | 
			
		||||
-g GROUP   $chgrpprog installed files to GROUP.
 | 
			
		||||
-m MODE    $chmodprog installed files to MODE.
 | 
			
		||||
-o USER    $chownprog installed files to USER.
 | 
			
		||||
-s         $stripprog installed files.
 | 
			
		||||
-t DIRECTORY  install into DIRECTORY.
 | 
			
		||||
-T         report an error if DSTFILE is a directory.
 | 
			
		||||
--help     display this help and exit.
 | 
			
		||||
--version  display version info and exit.
 | 
			
		||||
 | 
			
		||||
Environment variables override the default commands:
 | 
			
		||||
  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
 | 
			
		||||
  RMPROG STRIPPROG
 | 
			
		||||
 | 
			
		||||
By default, rm is invoked with -f; when overridden with RMPROG,
 | 
			
		||||
it's up to you to specify -f if you want it.
 | 
			
		||||
 | 
			
		||||
If -S is not specified, no backups are attempted.
 | 
			
		||||
 | 
			
		||||
Email bug reports to bug-automake@gnu.org.
 | 
			
		||||
Automake home page: https://www.gnu.org/software/automake/
 | 
			
		||||
  CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
 | 
			
		||||
"
 | 
			
		||||
 | 
			
		||||
while test $# -ne 0; do
 | 
			
		||||
  case $1 in
 | 
			
		||||
    -c) ;;
 | 
			
		||||
    -c) shift
 | 
			
		||||
        continue;;
 | 
			
		||||
 | 
			
		||||
    -C) copy_on_change=true;;
 | 
			
		||||
 | 
			
		||||
    -d) dir_arg=true;;
 | 
			
		||||
    -d) dir_arg=true
 | 
			
		||||
        shift
 | 
			
		||||
        continue;;
 | 
			
		||||
 | 
			
		||||
    -g) chgrpcmd="$chgrpprog $2"
 | 
			
		||||
        shift;;
 | 
			
		||||
        shift
 | 
			
		||||
        shift
 | 
			
		||||
        continue;;
 | 
			
		||||
 | 
			
		||||
    --help) echo "$usage"; exit $?;;
 | 
			
		||||
 | 
			
		||||
    -m) mode=$2
 | 
			
		||||
        case $mode in
 | 
			
		||||
          *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
 | 
			
		||||
            echo "$0: invalid mode: $mode" >&2
 | 
			
		||||
            exit 1;;
 | 
			
		||||
        esac
 | 
			
		||||
        shift;;
 | 
			
		||||
        shift
 | 
			
		||||
        shift
 | 
			
		||||
	case $mode in
 | 
			
		||||
	  *' '* | *'	'* | *'
 | 
			
		||||
'*	  | *'*'* | *'?'* | *'['*)
 | 
			
		||||
	    echo "$0: invalid mode: $mode" >&2
 | 
			
		||||
	    exit 1;;
 | 
			
		||||
	esac
 | 
			
		||||
        continue;;
 | 
			
		||||
 | 
			
		||||
    -o) chowncmd="$chownprog $2"
 | 
			
		||||
        shift;;
 | 
			
		||||
        shift
 | 
			
		||||
        shift
 | 
			
		||||
        continue;;
 | 
			
		||||
 | 
			
		||||
    -p) cpprog="$cpprog -p";;
 | 
			
		||||
    -s) stripcmd=$stripprog
 | 
			
		||||
        shift
 | 
			
		||||
        continue;;
 | 
			
		||||
 | 
			
		||||
    -s) stripcmd=$stripprog;;
 | 
			
		||||
    -t) dstarg=$2
 | 
			
		||||
	shift
 | 
			
		||||
	shift
 | 
			
		||||
	continue;;
 | 
			
		||||
 | 
			
		||||
    -S) backupsuffix="$2"
 | 
			
		||||
        shift;;
 | 
			
		||||
 | 
			
		||||
    -t)
 | 
			
		||||
        is_target_a_directory=always
 | 
			
		||||
        dst_arg=$2
 | 
			
		||||
        # Protect names problematic for 'test' and other utilities.
 | 
			
		||||
        case $dst_arg in
 | 
			
		||||
          -* | [=\(\)!]) dst_arg=./$dst_arg;;
 | 
			
		||||
        esac
 | 
			
		||||
        shift;;
 | 
			
		||||
 | 
			
		||||
    -T) is_target_a_directory=never;;
 | 
			
		||||
    -T) no_target_directory=true
 | 
			
		||||
	shift
 | 
			
		||||
	continue;;
 | 
			
		||||
 | 
			
		||||
    --version) echo "$0 $scriptversion"; exit $?;;
 | 
			
		||||
 | 
			
		||||
    --) shift
 | 
			
		||||
        break;;
 | 
			
		||||
    --)	shift
 | 
			
		||||
	break;;
 | 
			
		||||
 | 
			
		||||
    -*) echo "$0: invalid option: $1" >&2
 | 
			
		||||
        exit 1;;
 | 
			
		||||
    -*)	echo "$0: invalid option: $1" >&2
 | 
			
		||||
	exit 1;;
 | 
			
		||||
 | 
			
		||||
    *)  break;;
 | 
			
		||||
  esac
 | 
			
		||||
  shift
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# We allow the use of options -d and -T together, by making -d
 | 
			
		||||
# take the precedence; this is for compatibility with GNU install.
 | 
			
		||||
 | 
			
		||||
if test -n "$dir_arg"; then
 | 
			
		||||
  if test -n "$dst_arg"; then
 | 
			
		||||
    echo "$0: target directory not allowed when installing a directory." >&2
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
 | 
			
		||||
if test $# -ne 0 && test -z "$dir_arg$dstarg"; then
 | 
			
		||||
  # When -d is used, all remaining arguments are directories to create.
 | 
			
		||||
  # When -t is used, the destination is already specified.
 | 
			
		||||
  # Otherwise, the last argument is the destination.  Remove it from $@.
 | 
			
		||||
  for arg
 | 
			
		||||
  do
 | 
			
		||||
    if test -n "$dst_arg"; then
 | 
			
		||||
    if test -n "$dstarg"; then
 | 
			
		||||
      # $@ is not empty: it contains at least $arg.
 | 
			
		||||
      set fnord "$@" "$dst_arg"
 | 
			
		||||
      set fnord "$@" "$dstarg"
 | 
			
		||||
      shift # fnord
 | 
			
		||||
    fi
 | 
			
		||||
    shift # arg
 | 
			
		||||
    dst_arg=$arg
 | 
			
		||||
    # Protect names problematic for 'test' and other utilities.
 | 
			
		||||
    case $dst_arg in
 | 
			
		||||
      -* | [=\(\)!]) dst_arg=./$dst_arg;;
 | 
			
		||||
    esac
 | 
			
		||||
    dstarg=$arg
 | 
			
		||||
  done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
@@ -218,26 +188,13 @@ if test $# -eq 0; then
 | 
			
		||||
    echo "$0: no input file specified." >&2
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
  # It's OK to call 'install-sh -d' without argument.
 | 
			
		||||
  # It's OK to call `install-sh -d' without argument.
 | 
			
		||||
  # This can happen when creating conditional directories.
 | 
			
		||||
  exit 0
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test -z "$dir_arg"; then
 | 
			
		||||
  if test $# -gt 1 || test "$is_target_a_directory" = always; then
 | 
			
		||||
    if test ! -d "$dst_arg"; then
 | 
			
		||||
      echo "$0: $dst_arg: Is not a directory." >&2
 | 
			
		||||
      exit 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test -z "$dir_arg"; then
 | 
			
		||||
  do_exit='(exit $ret); exit $ret'
 | 
			
		||||
  trap "ret=129; $do_exit" 1
 | 
			
		||||
  trap "ret=130; $do_exit" 2
 | 
			
		||||
  trap "ret=141; $do_exit" 13
 | 
			
		||||
  trap "ret=143; $do_exit" 15
 | 
			
		||||
  trap '(exit $?); exit' 1 2 13 15
 | 
			
		||||
 | 
			
		||||
  # Set umask so as not to create temps with too-generous modes.
 | 
			
		||||
  # However, 'strip' requires both read and write access to temps.
 | 
			
		||||
@@ -248,16 +205,16 @@ if test -z "$dir_arg"; then
 | 
			
		||||
 | 
			
		||||
    *[0-7])
 | 
			
		||||
      if test -z "$stripcmd"; then
 | 
			
		||||
        u_plus_rw=
 | 
			
		||||
	u_plus_rw=
 | 
			
		||||
      else
 | 
			
		||||
        u_plus_rw='% 200'
 | 
			
		||||
	u_plus_rw='% 200'
 | 
			
		||||
      fi
 | 
			
		||||
      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
 | 
			
		||||
    *)
 | 
			
		||||
      if test -z "$stripcmd"; then
 | 
			
		||||
        u_plus_rw=
 | 
			
		||||
	u_plus_rw=
 | 
			
		||||
      else
 | 
			
		||||
        u_plus_rw=,u+rw
 | 
			
		||||
	u_plus_rw=,u+rw
 | 
			
		||||
      fi
 | 
			
		||||
      cp_umask=$mode$u_plus_rw;;
 | 
			
		||||
  esac
 | 
			
		||||
@@ -265,9 +222,9 @@ fi
 | 
			
		||||
 | 
			
		||||
for src
 | 
			
		||||
do
 | 
			
		||||
  # Protect names problematic for 'test' and other utilities.
 | 
			
		||||
  # Protect names starting with `-'.
 | 
			
		||||
  case $src in
 | 
			
		||||
    -* | [=\(\)!]) src=./$src;;
 | 
			
		||||
    -*) src=./$src ;;
 | 
			
		||||
  esac
 | 
			
		||||
 | 
			
		||||
  if test -n "$dir_arg"; then
 | 
			
		||||
@@ -275,10 +232,6 @@ do
 | 
			
		||||
    dstdir=$dst
 | 
			
		||||
    test -d "$dstdir"
 | 
			
		||||
    dstdir_status=$?
 | 
			
		||||
    # Don't chown directories that already exist.
 | 
			
		||||
    if test $dstdir_status = 0; then
 | 
			
		||||
      chowncmd=""
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
 | 
			
		||||
    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
 | 
			
		||||
@@ -289,154 +242,196 @@ do
 | 
			
		||||
      exit 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if test -z "$dst_arg"; then
 | 
			
		||||
    if test -z "$dstarg"; then
 | 
			
		||||
      echo "$0: no destination specified." >&2
 | 
			
		||||
      exit 1
 | 
			
		||||
    fi
 | 
			
		||||
    dst=$dst_arg
 | 
			
		||||
 | 
			
		||||
    # If destination is a directory, append the input filename.
 | 
			
		||||
    dst=$dstarg
 | 
			
		||||
    # Protect names starting with `-'.
 | 
			
		||||
    case $dst in
 | 
			
		||||
      -*) dst=./$dst ;;
 | 
			
		||||
    esac
 | 
			
		||||
 | 
			
		||||
    # If destination is a directory, append the input filename; won't work
 | 
			
		||||
    # if double slashes aren't ignored.
 | 
			
		||||
    if test -d "$dst"; then
 | 
			
		||||
      if test "$is_target_a_directory" = never; then
 | 
			
		||||
        echo "$0: $dst_arg: Is a directory" >&2
 | 
			
		||||
        exit 1
 | 
			
		||||
      if test -n "$no_target_directory"; then
 | 
			
		||||
	echo "$0: $dstarg: Is a directory" >&2
 | 
			
		||||
	exit 1
 | 
			
		||||
      fi
 | 
			
		||||
      dstdir=$dst
 | 
			
		||||
      dstbase=`basename "$src"`
 | 
			
		||||
      case $dst in
 | 
			
		||||
	*/) dst=$dst$dstbase;;
 | 
			
		||||
	*)  dst=$dst/$dstbase;;
 | 
			
		||||
      esac
 | 
			
		||||
      dst=$dstdir/`basename "$src"`
 | 
			
		||||
      dstdir_status=0
 | 
			
		||||
    else
 | 
			
		||||
      dstdir=`dirname "$dst"`
 | 
			
		||||
      # Prefer dirname, but fall back on a substitute if dirname fails.
 | 
			
		||||
      dstdir=`
 | 
			
		||||
	(dirname "$dst") 2>/dev/null ||
 | 
			
		||||
	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
 | 
			
		||||
	     X"$dst" : 'X\(//\)[^/]' \| \
 | 
			
		||||
	     X"$dst" : 'X\(//\)$' \| \
 | 
			
		||||
	     X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
 | 
			
		||||
	echo X"$dst" |
 | 
			
		||||
	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
 | 
			
		||||
		   s//\1/
 | 
			
		||||
		   q
 | 
			
		||||
		 }
 | 
			
		||||
		 /^X\(\/\/\)[^/].*/{
 | 
			
		||||
		   s//\1/
 | 
			
		||||
		   q
 | 
			
		||||
		 }
 | 
			
		||||
		 /^X\(\/\/\)$/{
 | 
			
		||||
		   s//\1/
 | 
			
		||||
		   q
 | 
			
		||||
		 }
 | 
			
		||||
		 /^X\(\/\).*/{
 | 
			
		||||
		   s//\1/
 | 
			
		||||
		   q
 | 
			
		||||
		 }
 | 
			
		||||
		 s/.*/./; q'
 | 
			
		||||
      `
 | 
			
		||||
 | 
			
		||||
      test -d "$dstdir"
 | 
			
		||||
      dstdir_status=$?
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  case $dstdir in
 | 
			
		||||
    */) dstdirslash=$dstdir;;
 | 
			
		||||
    *)  dstdirslash=$dstdir/;;
 | 
			
		||||
  esac
 | 
			
		||||
 | 
			
		||||
  obsolete_mkdir_used=false
 | 
			
		||||
 | 
			
		||||
  if test $dstdir_status != 0; then
 | 
			
		||||
    case $posix_mkdir in
 | 
			
		||||
      '')
 | 
			
		||||
        # With -d, create the new directory with the user-specified mode.
 | 
			
		||||
        # Otherwise, rely on $mkdir_umask.
 | 
			
		||||
        if test -n "$dir_arg"; then
 | 
			
		||||
          mkdir_mode=-m$mode
 | 
			
		||||
        else
 | 
			
		||||
          mkdir_mode=
 | 
			
		||||
        fi
 | 
			
		||||
	# Create intermediate dirs using mode 755 as modified by the umask.
 | 
			
		||||
	# This is like FreeBSD 'install' as of 1997-10-28.
 | 
			
		||||
	umask=`umask`
 | 
			
		||||
	case $stripcmd.$umask in
 | 
			
		||||
	  # Optimize common cases.
 | 
			
		||||
	  *[2367][2367]) mkdir_umask=$umask;;
 | 
			
		||||
	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
 | 
			
		||||
 | 
			
		||||
        posix_mkdir=false
 | 
			
		||||
	# The $RANDOM variable is not portable (e.g., dash).  Use it
 | 
			
		||||
	# here however when possible just to lower collision chance.
 | 
			
		||||
	tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
 | 
			
		||||
	  *[0-7])
 | 
			
		||||
	    mkdir_umask=`expr $umask + 22 \
 | 
			
		||||
	      - $umask % 100 % 40 + $umask % 20 \
 | 
			
		||||
	      - $umask % 10 % 4 + $umask % 2
 | 
			
		||||
	    `;;
 | 
			
		||||
	  *) mkdir_umask=$umask,go-w;;
 | 
			
		||||
	esac
 | 
			
		||||
 | 
			
		||||
	trap '
 | 
			
		||||
	  ret=$?
 | 
			
		||||
	  rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
 | 
			
		||||
	  exit $ret
 | 
			
		||||
	' 0
 | 
			
		||||
 | 
			
		||||
	# Because "mkdir -p" follows existing symlinks and we likely work
 | 
			
		||||
	# directly in world-writeable /tmp, make sure that the '$tmpdir'
 | 
			
		||||
	# directory is successfully created first before we actually test
 | 
			
		||||
	# 'mkdir -p'.
 | 
			
		||||
	if (umask $mkdir_umask &&
 | 
			
		||||
	    $mkdirprog $mkdir_mode "$tmpdir" &&
 | 
			
		||||
	    exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
 | 
			
		||||
	then
 | 
			
		||||
	  if test -z "$dir_arg" || {
 | 
			
		||||
	       # Check for POSIX incompatibilities with -m.
 | 
			
		||||
	       # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
 | 
			
		||||
	       # other-writable bit of parent directory when it shouldn't.
 | 
			
		||||
	       # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
 | 
			
		||||
	       test_tmpdir="$tmpdir/a"
 | 
			
		||||
	       ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
 | 
			
		||||
	       case $ls_ld_tmpdir in
 | 
			
		||||
		 d????-?r-*) different_mode=700;;
 | 
			
		||||
		 d????-?--*) different_mode=755;;
 | 
			
		||||
		 *) false;;
 | 
			
		||||
	       esac &&
 | 
			
		||||
	       $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
 | 
			
		||||
		 ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
 | 
			
		||||
		 test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
 | 
			
		||||
	       }
 | 
			
		||||
	     }
 | 
			
		||||
	  then posix_mkdir=:
 | 
			
		||||
	  fi
 | 
			
		||||
	  rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
 | 
			
		||||
	# With -d, create the new directory with the user-specified mode.
 | 
			
		||||
	# Otherwise, rely on $mkdir_umask.
 | 
			
		||||
	if test -n "$dir_arg"; then
 | 
			
		||||
	  mkdir_mode=-m$mode
 | 
			
		||||
	else
 | 
			
		||||
	  # Remove any dirs left behind by ancient mkdir implementations.
 | 
			
		||||
	  rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
 | 
			
		||||
	  mkdir_mode=
 | 
			
		||||
	fi
 | 
			
		||||
	trap '' 0;;
 | 
			
		||||
 | 
			
		||||
	posix_mkdir=false
 | 
			
		||||
	case $umask in
 | 
			
		||||
	  *[123567][0-7][0-7])
 | 
			
		||||
	    # POSIX mkdir -p sets u+wx bits regardless of umask, which
 | 
			
		||||
	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
 | 
			
		||||
	    ;;
 | 
			
		||||
	  *)
 | 
			
		||||
	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
 | 
			
		||||
	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
 | 
			
		||||
 | 
			
		||||
	    if (umask $mkdir_umask &&
 | 
			
		||||
		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
 | 
			
		||||
	    then
 | 
			
		||||
	      if test -z "$dir_arg" || {
 | 
			
		||||
		   # Check for POSIX incompatibilities with -m.
 | 
			
		||||
		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
 | 
			
		||||
		   # other-writeable bit of parent directory when it shouldn't.
 | 
			
		||||
		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
 | 
			
		||||
		   ls_ld_tmpdir=`ls -ld "$tmpdir"`
 | 
			
		||||
		   case $ls_ld_tmpdir in
 | 
			
		||||
		     d????-?r-*) different_mode=700;;
 | 
			
		||||
		     d????-?--*) different_mode=755;;
 | 
			
		||||
		     *) false;;
 | 
			
		||||
		   esac &&
 | 
			
		||||
		   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
 | 
			
		||||
		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
 | 
			
		||||
		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
 | 
			
		||||
		   }
 | 
			
		||||
		 }
 | 
			
		||||
	      then posix_mkdir=:
 | 
			
		||||
	      fi
 | 
			
		||||
	      rmdir "$tmpdir/d" "$tmpdir"
 | 
			
		||||
	    else
 | 
			
		||||
	      # Remove any dirs left behind by ancient mkdir implementations.
 | 
			
		||||
	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
 | 
			
		||||
	    fi
 | 
			
		||||
	    trap '' 0;;
 | 
			
		||||
	esac;;
 | 
			
		||||
    esac
 | 
			
		||||
 | 
			
		||||
    if
 | 
			
		||||
      $posix_mkdir && (
 | 
			
		||||
        umask $mkdir_umask &&
 | 
			
		||||
        $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
 | 
			
		||||
	umask $mkdir_umask &&
 | 
			
		||||
	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
 | 
			
		||||
      )
 | 
			
		||||
    then :
 | 
			
		||||
    else
 | 
			
		||||
 | 
			
		||||
      # mkdir does not conform to POSIX,
 | 
			
		||||
      # The umask is ridiculous, or mkdir does not conform to POSIX,
 | 
			
		||||
      # or it failed possibly due to a race condition.  Create the
 | 
			
		||||
      # directory the slow way, step by step, checking for races as we go.
 | 
			
		||||
 | 
			
		||||
      case $dstdir in
 | 
			
		||||
        /*) prefix='/';;
 | 
			
		||||
        [-=\(\)!]*) prefix='./';;
 | 
			
		||||
        *)  prefix='';;
 | 
			
		||||
	/*) prefix=/ ;;
 | 
			
		||||
	-*) prefix=./ ;;
 | 
			
		||||
	*)  prefix= ;;
 | 
			
		||||
      esac
 | 
			
		||||
 | 
			
		||||
      case $posix_glob in
 | 
			
		||||
        '')
 | 
			
		||||
	  if (set -f) 2>/dev/null; then
 | 
			
		||||
	    posix_glob=true
 | 
			
		||||
	  else
 | 
			
		||||
	    posix_glob=false
 | 
			
		||||
	  fi ;;
 | 
			
		||||
      esac
 | 
			
		||||
 | 
			
		||||
      oIFS=$IFS
 | 
			
		||||
      IFS=/
 | 
			
		||||
      set -f
 | 
			
		||||
      $posix_glob && set -f
 | 
			
		||||
      set fnord $dstdir
 | 
			
		||||
      shift
 | 
			
		||||
      set +f
 | 
			
		||||
      $posix_glob && set +f
 | 
			
		||||
      IFS=$oIFS
 | 
			
		||||
 | 
			
		||||
      prefixes=
 | 
			
		||||
 | 
			
		||||
      for d
 | 
			
		||||
      do
 | 
			
		||||
        test X"$d" = X && continue
 | 
			
		||||
	test -z "$d" && continue
 | 
			
		||||
 | 
			
		||||
        prefix=$prefix$d
 | 
			
		||||
        if test -d "$prefix"; then
 | 
			
		||||
          prefixes=
 | 
			
		||||
        else
 | 
			
		||||
          if $posix_mkdir; then
 | 
			
		||||
            (umask $mkdir_umask &&
 | 
			
		||||
             $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
 | 
			
		||||
            # Don't fail if two instances are running concurrently.
 | 
			
		||||
            test -d "$prefix" || exit 1
 | 
			
		||||
          else
 | 
			
		||||
            case $prefix in
 | 
			
		||||
              *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
 | 
			
		||||
              *) qprefix=$prefix;;
 | 
			
		||||
            esac
 | 
			
		||||
            prefixes="$prefixes '$qprefix'"
 | 
			
		||||
          fi
 | 
			
		||||
        fi
 | 
			
		||||
        prefix=$prefix/
 | 
			
		||||
	prefix=$prefix$d
 | 
			
		||||
	if test -d "$prefix"; then
 | 
			
		||||
	  prefixes=
 | 
			
		||||
	else
 | 
			
		||||
	  if $posix_mkdir; then
 | 
			
		||||
	    (umask=$mkdir_umask &&
 | 
			
		||||
	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
 | 
			
		||||
	    # Don't fail if two instances are running concurrently.
 | 
			
		||||
	    test -d "$prefix" || exit 1
 | 
			
		||||
	  else
 | 
			
		||||
	    case $prefix in
 | 
			
		||||
	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
 | 
			
		||||
	      *) qprefix=$prefix;;
 | 
			
		||||
	    esac
 | 
			
		||||
	    prefixes="$prefixes '$qprefix'"
 | 
			
		||||
	  fi
 | 
			
		||||
	fi
 | 
			
		||||
	prefix=$prefix/
 | 
			
		||||
      done
 | 
			
		||||
 | 
			
		||||
      if test -n "$prefixes"; then
 | 
			
		||||
        # Don't fail if two instances are running concurrently.
 | 
			
		||||
        (umask $mkdir_umask &&
 | 
			
		||||
         eval "\$doit_exec \$mkdirprog $prefixes") ||
 | 
			
		||||
          test -d "$dstdir" || exit 1
 | 
			
		||||
        obsolete_mkdir_used=true
 | 
			
		||||
	# Don't fail if two instances are running concurrently.
 | 
			
		||||
	(umask $mkdir_umask &&
 | 
			
		||||
	 eval "\$doit_exec \$mkdirprog $prefixes") ||
 | 
			
		||||
	  test -d "$dstdir" || exit 1
 | 
			
		||||
	obsolete_mkdir_used=true
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
@@ -449,25 +444,14 @@ do
 | 
			
		||||
  else
 | 
			
		||||
 | 
			
		||||
    # Make a couple of temp file names in the proper directory.
 | 
			
		||||
    dsttmp=${dstdirslash}_inst.$$_
 | 
			
		||||
    rmtmp=${dstdirslash}_rm.$$_
 | 
			
		||||
    dsttmp=$dstdir/_inst.$$_
 | 
			
		||||
    rmtmp=$dstdir/_rm.$$_
 | 
			
		||||
 | 
			
		||||
    # Trap to clean up those temp files at exit.
 | 
			
		||||
    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
 | 
			
		||||
 | 
			
		||||
    # Copy the file name to the temp name.
 | 
			
		||||
    (umask $cp_umask &&
 | 
			
		||||
     { test -z "$stripcmd" || {
 | 
			
		||||
	 # Create $dsttmp read-write so that cp doesn't create it read-only,
 | 
			
		||||
	 # which would cause strip to fail.
 | 
			
		||||
	 if test -z "$doit"; then
 | 
			
		||||
	   : >"$dsttmp" # No need to fork-exec 'touch'.
 | 
			
		||||
	 else
 | 
			
		||||
	   $doit touch "$dsttmp"
 | 
			
		||||
	 fi
 | 
			
		||||
       }
 | 
			
		||||
     } &&
 | 
			
		||||
     $doit_exec $cpprog "$src" "$dsttmp") &&
 | 
			
		||||
    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
 | 
			
		||||
 | 
			
		||||
    # and set any options; do chmod last to preserve setuid bits.
 | 
			
		||||
    #
 | 
			
		||||
@@ -475,67 +459,49 @@ do
 | 
			
		||||
    # ignore errors from any of these, just make sure not to ignore
 | 
			
		||||
    # errors from the above "$doit $cpprog $src $dsttmp" command.
 | 
			
		||||
    #
 | 
			
		||||
    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
 | 
			
		||||
    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
 | 
			
		||||
    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
 | 
			
		||||
    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
 | 
			
		||||
    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
 | 
			
		||||
      && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
 | 
			
		||||
      && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
 | 
			
		||||
      && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
 | 
			
		||||
 | 
			
		||||
    # If -C, don't bother to copy if it wouldn't change the file.
 | 
			
		||||
    if $copy_on_change &&
 | 
			
		||||
       old=`LC_ALL=C ls -dlL "$dst"     2>/dev/null` &&
 | 
			
		||||
       new=`LC_ALL=C ls -dlL "$dsttmp"  2>/dev/null` &&
 | 
			
		||||
       set -f &&
 | 
			
		||||
       set X $old && old=:$2:$4:$5:$6 &&
 | 
			
		||||
       set X $new && new=:$2:$4:$5:$6 &&
 | 
			
		||||
       set +f &&
 | 
			
		||||
       test "$old" = "$new" &&
 | 
			
		||||
       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
 | 
			
		||||
    then
 | 
			
		||||
      rm -f "$dsttmp"
 | 
			
		||||
    else
 | 
			
		||||
      # If $backupsuffix is set, and the file being installed
 | 
			
		||||
      # already exists, attempt a backup.  Don't worry if it fails,
 | 
			
		||||
      # e.g., if mv doesn't support -f.
 | 
			
		||||
      if test -n "$backupsuffix" && test -f "$dst"; then
 | 
			
		||||
        $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
 | 
			
		||||
      fi
 | 
			
		||||
    # Now rename the file to the real destination.
 | 
			
		||||
    { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
 | 
			
		||||
      || {
 | 
			
		||||
	   # The rename failed, perhaps because mv can't rename something else
 | 
			
		||||
	   # to itself, or perhaps because mv is so ancient that it does not
 | 
			
		||||
	   # support -f.
 | 
			
		||||
 | 
			
		||||
      # Rename the file to the real destination.
 | 
			
		||||
      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
 | 
			
		||||
	   # Now remove or move aside any old file at destination location.
 | 
			
		||||
	   # We try this two ways since rm can't unlink itself on some
 | 
			
		||||
	   # systems and the destination file might be busy for other
 | 
			
		||||
	   # reasons.  In this case, the final cleanup might fail but the new
 | 
			
		||||
	   # file should still install successfully.
 | 
			
		||||
	   {
 | 
			
		||||
	     if test -f "$dst"; then
 | 
			
		||||
	       $doit $rmcmd -f "$dst" 2>/dev/null \
 | 
			
		||||
	       || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \
 | 
			
		||||
		     && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\
 | 
			
		||||
	       || {
 | 
			
		||||
		 echo "$0: cannot unlink or rename $dst" >&2
 | 
			
		||||
		 (exit 1); exit 1
 | 
			
		||||
	       }
 | 
			
		||||
	     else
 | 
			
		||||
	       :
 | 
			
		||||
	     fi
 | 
			
		||||
	   } &&
 | 
			
		||||
 | 
			
		||||
      # The rename failed, perhaps because mv can't rename something else
 | 
			
		||||
      # to itself, or perhaps because mv is so ancient that it does not
 | 
			
		||||
      # support -f.
 | 
			
		||||
      {
 | 
			
		||||
        # Now remove or move aside any old file at destination location.
 | 
			
		||||
        # We try this two ways since rm can't unlink itself on some
 | 
			
		||||
        # systems and the destination file might be busy for other
 | 
			
		||||
        # reasons.  In this case, the final cleanup might fail but the new
 | 
			
		||||
        # file should still install successfully.
 | 
			
		||||
        {
 | 
			
		||||
          test ! -f "$dst" ||
 | 
			
		||||
          $doit $rmcmd "$dst" 2>/dev/null ||
 | 
			
		||||
          { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
 | 
			
		||||
            { $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
 | 
			
		||||
          } ||
 | 
			
		||||
          { echo "$0: cannot unlink or rename $dst" >&2
 | 
			
		||||
            (exit 1); exit 1
 | 
			
		||||
          }
 | 
			
		||||
        } &&
 | 
			
		||||
 | 
			
		||||
        # Now rename the file to the real destination.
 | 
			
		||||
        $doit $mvcmd "$dsttmp" "$dst"
 | 
			
		||||
      }
 | 
			
		||||
    fi || exit 1
 | 
			
		||||
	   # Now rename the file to the real destination.
 | 
			
		||||
	   $doit $mvcmd "$dsttmp" "$dst"
 | 
			
		||||
	 }
 | 
			
		||||
    } || exit 1
 | 
			
		||||
 | 
			
		||||
    trap '' 0
 | 
			
		||||
  fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# Local variables:
 | 
			
		||||
# eval: (add-hook 'before-save-hook 'time-stamp)
 | 
			
		||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
 | 
			
		||||
# time-stamp-start: "scriptversion="
 | 
			
		||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
 | 
			
		||||
# time-stamp-time-zone: "UTC0"
 | 
			
		||||
# time-stamp-end: "; # UTC"
 | 
			
		||||
# time-stamp-end: "$"
 | 
			
		||||
# End:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
# py-compile - Compile a Python program
 | 
			
		||||
 | 
			
		||||
scriptversion=2023-03-30.00; # UTC
 | 
			
		||||
scriptversion=2011-06-08.12; # UTC
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 2000-2023 Free Software Foundation, Inc.
 | 
			
		||||
# Copyright (C) 2000-2014 Free Software Foundation, Inc.
 | 
			
		||||
 | 
			
		||||
# This program is free software; you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
@@ -16,7 +16,7 @@ scriptversion=2023-03-30.00; # UTC
 | 
			
		||||
# GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
# As a special exception to the GNU General Public License, if you
 | 
			
		||||
# distribute this file as part of a program that contains a
 | 
			
		||||
@@ -27,7 +27,7 @@ scriptversion=2023-03-30.00; # UTC
 | 
			
		||||
# bugs to <bug-automake@gnu.org> or send patches to
 | 
			
		||||
# <automake-patches@gnu.org>.
 | 
			
		||||
 | 
			
		||||
if test -z "$PYTHON"; then
 | 
			
		||||
if [ -z "$PYTHON" ]; then
 | 
			
		||||
  PYTHON=python
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
@@ -62,19 +62,13 @@ while test $# -ne 0; do
 | 
			
		||||
      ;;
 | 
			
		||||
    -h|--help)
 | 
			
		||||
      cat <<\EOF
 | 
			
		||||
Usage: py-compile [options] FILES...
 | 
			
		||||
Usage: py-compile [--help] [--version] [--basedir DIR] [--destdir DIR] FILES..."
 | 
			
		||||
 | 
			
		||||
Byte compile some python scripts FILES.  Use --destdir to specify any
 | 
			
		||||
leading directory path to the FILES that you don't want to include in the
 | 
			
		||||
byte compiled file.  Specify --basedir for any additional path information you
 | 
			
		||||
do want to be shown in the byte compiled file.
 | 
			
		||||
 | 
			
		||||
Options:
 | 
			
		||||
  --basedir DIR   Prefix all FILES with DIR, and include in error messages.
 | 
			
		||||
  --destdir DIR   Prefix all FILES with DIR before compiling.
 | 
			
		||||
  -v, --version   Display version information.
 | 
			
		||||
  -h, --help      This help screen.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
  py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py
 | 
			
		||||
 | 
			
		||||
@@ -100,143 +94,77 @@ EOF
 | 
			
		||||
  shift
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
if test $# -eq 0; then
 | 
			
		||||
  usage_error "no files given"
 | 
			
		||||
files=$*
 | 
			
		||||
if test -z "$files"; then
 | 
			
		||||
    usage_error "no files given"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# if basedir was given, then it should be prepended to filenames before
 | 
			
		||||
# byte compilation.
 | 
			
		||||
if test -z "$basedir"; then
 | 
			
		||||
  pathtrans="path = file"
 | 
			
		||||
if [ -z "$basedir" ]; then
 | 
			
		||||
    pathtrans="path = file"
 | 
			
		||||
else
 | 
			
		||||
  pathtrans="path = os.path.join('$basedir', file)"
 | 
			
		||||
    pathtrans="path = os.path.join('$basedir', file)"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# if destdir was given, then it needs to be prepended to the filename to
 | 
			
		||||
# byte compile but not go into the compiled file.
 | 
			
		||||
if test -z "$destdir"; then
 | 
			
		||||
  filetrans="filepath = path"
 | 
			
		||||
if [ -z "$destdir" ]; then
 | 
			
		||||
    filetrans="filepath = path"
 | 
			
		||||
else
 | 
			
		||||
  filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
 | 
			
		||||
    filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
python_major=`$PYTHON -c 'import sys; print(sys.version_info[0])'`
 | 
			
		||||
if test -z "$python_major"; then
 | 
			
		||||
  usage_error "could not determine $PYTHON major version"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
case $python_major in
 | 
			
		||||
[01])
 | 
			
		||||
  usage_error "python version 0.x and 1.x not supported"
 | 
			
		||||
  ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
python_minor=`$PYTHON -c 'import sys; print(sys.version_info[1])'`
 | 
			
		||||
 | 
			
		||||
# NB: When adding support for newer versions, prefer copying & adding new cases
 | 
			
		||||
# rather than try to keep things merged with shell variables.
 | 
			
		||||
 | 
			
		||||
# First byte compile (no optimization) all the modules.
 | 
			
		||||
# This works for all currently known Python versions.
 | 
			
		||||
$PYTHON -c "
 | 
			
		||||
import sys, os, py_compile
 | 
			
		||||
import sys, os, py_compile, imp
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    import importlib
 | 
			
		||||
except ImportError:
 | 
			
		||||
    importlib = None
 | 
			
		||||
 | 
			
		||||
# importlib.util.cache_from_source was added in 3.4
 | 
			
		||||
if (
 | 
			
		||||
        hasattr(importlib, 'util')
 | 
			
		||||
        and hasattr(importlib.util, 'cache_from_source')
 | 
			
		||||
):
 | 
			
		||||
    destpath = importlib.util.cache_from_source
 | 
			
		||||
else:
 | 
			
		||||
    destpath = lambda filepath: filepath + 'c'
 | 
			
		||||
files = '''$files'''
 | 
			
		||||
 | 
			
		||||
sys.stdout.write('Byte-compiling python modules...\n')
 | 
			
		||||
for file in sys.argv[1:]:
 | 
			
		||||
for file in files.split():
 | 
			
		||||
    $pathtrans
 | 
			
		||||
    $filetrans
 | 
			
		||||
    if (
 | 
			
		||||
            not os.path.exists(filepath)
 | 
			
		||||
            or not (len(filepath) >= 3 and filepath[-3:] == '.py')
 | 
			
		||||
     ):
 | 
			
		||||
        continue
 | 
			
		||||
    sys.stdout.write(file + ' ')
 | 
			
		||||
    if not os.path.exists(filepath) or not (len(filepath) >= 3
 | 
			
		||||
                                            and filepath[-3:] == '.py'):
 | 
			
		||||
	    continue
 | 
			
		||||
    sys.stdout.write(file)
 | 
			
		||||
    sys.stdout.flush()
 | 
			
		||||
    py_compile.compile(filepath, destpath(filepath), path)
 | 
			
		||||
sys.stdout.write('\n')" "$@" || exit $?
 | 
			
		||||
    if hasattr(imp, 'get_tag'):
 | 
			
		||||
        py_compile.compile(filepath, imp.cache_from_source(filepath), path)
 | 
			
		||||
    else:
 | 
			
		||||
        py_compile.compile(filepath, filepath + 'c', path)
 | 
			
		||||
sys.stdout.write('\n')" || exit $?
 | 
			
		||||
 | 
			
		||||
# Then byte compile w/optimization all the modules.
 | 
			
		||||
# this will fail for python < 1.5, but that doesn't matter ...
 | 
			
		||||
$PYTHON -O -c "
 | 
			
		||||
import sys, os, py_compile
 | 
			
		||||
import sys, os, py_compile, imp
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    import importlib
 | 
			
		||||
except ImportError:
 | 
			
		||||
    importlib = None
 | 
			
		||||
 | 
			
		||||
# importlib.util.cache_from_source was added in 3.4
 | 
			
		||||
if (
 | 
			
		||||
        hasattr(importlib, 'util')
 | 
			
		||||
        and hasattr(importlib.util, 'cache_from_source')
 | 
			
		||||
):
 | 
			
		||||
    destpath = importlib.util.cache_from_source
 | 
			
		||||
else:
 | 
			
		||||
    destpath = lambda filepath: filepath + 'o'
 | 
			
		||||
 | 
			
		||||
# pypy2 does not use .pyo optimization
 | 
			
		||||
if sys.version_info.major <= 2 and hasattr(sys, 'pypy_translation_info'):
 | 
			
		||||
# pypy does not use .pyo optimization
 | 
			
		||||
if hasattr(sys, 'pypy_translation_info'):
 | 
			
		||||
    sys.exit(0)
 | 
			
		||||
 | 
			
		||||
files = '''$files'''
 | 
			
		||||
sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n')
 | 
			
		||||
for file in sys.argv[1:]:
 | 
			
		||||
for file in files.split():
 | 
			
		||||
    $pathtrans
 | 
			
		||||
    $filetrans
 | 
			
		||||
    if (
 | 
			
		||||
            not os.path.exists(filepath)
 | 
			
		||||
            or not (len(filepath) >= 3 and filepath[-3:] == '.py')
 | 
			
		||||
    ):
 | 
			
		||||
        continue
 | 
			
		||||
    sys.stdout.write(file + ' ')
 | 
			
		||||
    if not os.path.exists(filepath) or not (len(filepath) >= 3
 | 
			
		||||
                                            and filepath[-3:] == '.py'):
 | 
			
		||||
	    continue
 | 
			
		||||
    sys.stdout.write(file)
 | 
			
		||||
    sys.stdout.flush()
 | 
			
		||||
    py_compile.compile(filepath, destpath(filepath), path)
 | 
			
		||||
sys.stdout.write('\n')" "$@" 2>/dev/null || exit $?
 | 
			
		||||
 | 
			
		||||
# Then byte compile w/more optimization.
 | 
			
		||||
# Only do this for Python 3.5+, see https://bugs.gnu.org/38043 for background.
 | 
			
		||||
case $python_major.$python_minor in
 | 
			
		||||
2.*|3.[0-4])
 | 
			
		||||
  ;;
 | 
			
		||||
*)
 | 
			
		||||
  $PYTHON -OO -c "
 | 
			
		||||
import sys, os, py_compile, importlib
 | 
			
		||||
 | 
			
		||||
sys.stdout.write('Byte-compiling python modules (more optimized versions)'
 | 
			
		||||
                 ' ...\n')
 | 
			
		||||
for file in sys.argv[1:]:
 | 
			
		||||
    $pathtrans
 | 
			
		||||
    $filetrans
 | 
			
		||||
    if (
 | 
			
		||||
            not os.path.exists(filepath)
 | 
			
		||||
            or not (len(filepath) >= 3 and filepath[-3:] == '.py')
 | 
			
		||||
    ):
 | 
			
		||||
        continue
 | 
			
		||||
    sys.stdout.write(file + ' ')
 | 
			
		||||
    sys.stdout.flush()
 | 
			
		||||
    py_compile.compile(filepath, importlib.util.cache_from_source(filepath), path)
 | 
			
		||||
sys.stdout.write('\n')" "$@" 2>/dev/null || exit $?
 | 
			
		||||
  ;;
 | 
			
		||||
esac
 | 
			
		||||
    if hasattr(imp, 'get_tag'):
 | 
			
		||||
        py_compile.compile(filepath, imp.cache_from_source(filepath, False), path)
 | 
			
		||||
    else:
 | 
			
		||||
        py_compile.compile(filepath, filepath + 'o', path)
 | 
			
		||||
sys.stdout.write('\n')" 2>/dev/null || :
 | 
			
		||||
 | 
			
		||||
# Local Variables:
 | 
			
		||||
# mode: shell-script
 | 
			
		||||
# sh-indentation: 2
 | 
			
		||||
# eval: (add-hook 'before-save-hook 'time-stamp)
 | 
			
		||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
 | 
			
		||||
# time-stamp-start: "scriptversion="
 | 
			
		||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
 | 
			
		||||
# time-stamp-time-zone: "UTC0"
 | 
			
		||||
# time-stamp-time-zone: "UTC"
 | 
			
		||||
# time-stamp-end: "; # UTC"
 | 
			
		||||
# End:
 | 
			
		||||
 
 | 
			
		||||
@@ -31,10 +31,10 @@ CLEAN_TARGETS += $(BASE_DEPENDS) $(BASE_OBJECTS) \
 | 
			
		||||
	$(BASE_TARGET)
 | 
			
		||||
 | 
			
		||||
$(BASE_TARGET): $(BASE_OBJECTS)
 | 
			
		||||
	$(SHOW) "    [AR] $@"
 | 
			
		||||
	@echo "    [AR] $@"
 | 
			
		||||
	$(Q) $(RM) $@
 | 
			
		||||
	$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null
 | 
			
		||||
 | 
			
		||||
ifeq ("$(USE_TRACKING)","yes")
 | 
			
		||||
ifeq ("$(DEPENDS)","yes")
 | 
			
		||||
-include $(BASE_DEPENDS)
 | 
			
		||||
endif
 | 
			
		||||
 
 | 
			
		||||
@@ -30,10 +30,10 @@ struct dm_hash_table {
 | 
			
		||||
	unsigned num_nodes;
 | 
			
		||||
	unsigned num_hint;
 | 
			
		||||
	unsigned mask_slots;    /* (slots - 1) -> used as hash mask */
 | 
			
		||||
	unsigned collisions;    /* Collisions of hash keys */
 | 
			
		||||
	unsigned collisions;    /* Collissions of hash keys */
 | 
			
		||||
	unsigned search;        /* How many keys were searched */
 | 
			
		||||
	unsigned found;         /* How many nodes were found */
 | 
			
		||||
	unsigned same_hash;     /* Was there a collision with same masked hash and len ? */
 | 
			
		||||
	unsigned same_hash;     /* Was there a colision with same masked hash and len ? */
 | 
			
		||||
	struct dm_hash_node **slots;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -41,7 +41,7 @@ struct dm_hash_table {
 | 
			
		||||
static unsigned _hash(const void *key, unsigned len)
 | 
			
		||||
{
 | 
			
		||||
	/* Permutation of the Integers 0 through 255 */
 | 
			
		||||
	static const unsigned char _nums[] = {
 | 
			
		||||
	static unsigned char _nums[] = {
 | 
			
		||||
	1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
 | 
			
		||||
	87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
 | 
			
		||||
	49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
 | 
			
		||||
@@ -348,7 +348,7 @@ int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key,
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Look through multiple entries with the same key for one that has a
 | 
			
		||||
 * 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,
 | 
			
		||||
			      const void *val, uint32_t val_len)
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,6 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
@@ -70,7 +69,7 @@ struct node48 {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct node256 {
 | 
			
		||||
	uint32_t nr_entries;
 | 
			
		||||
        uint32_t nr_entries;
 | 
			
		||||
	struct value values[256];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -100,7 +99,7 @@ struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context)
 | 
			
		||||
static inline void _dtr(struct radix_tree *rt, union radix_value v)
 | 
			
		||||
{
 | 
			
		||||
	if (rt->dtr)
 | 
			
		||||
		rt->dtr(rt->dtr_context, v);
 | 
			
		||||
        	rt->dtr(rt->dtr_context, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns the number of values removed
 | 
			
		||||
@@ -119,8 +118,8 @@ static unsigned _free_node(struct radix_tree *rt, struct value v)
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case VALUE:
 | 
			
		||||
		_dtr(rt, v.value);
 | 
			
		||||
		nr = 1;
 | 
			
		||||
        	_dtr(rt, v.value);
 | 
			
		||||
        	nr = 1;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case VALUE_CHAIN:
 | 
			
		||||
@@ -179,9 +178,9 @@ unsigned radix_tree_size(struct radix_tree *rt)
 | 
			
		||||
	return rt->nr_entries;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv);
 | 
			
		||||
static bool _insert(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv);
 | 
			
		||||
 | 
			
		||||
static bool _insert_unset(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
 | 
			
		||||
static bool _insert_unset(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	unsigned len = ke - kb;
 | 
			
		||||
 | 
			
		||||
@@ -191,8 +190,8 @@ static bool _insert_unset(struct radix_tree *rt, struct value *v, const uint8_t
 | 
			
		||||
		v->value = rv;
 | 
			
		||||
		rt->nr_entries++;
 | 
			
		||||
	} else {
 | 
			
		||||
		// prefix -> value (all fields explicitly initialized)
 | 
			
		||||
		struct prefix_chain *pc = malloc(sizeof(*pc) + len);
 | 
			
		||||
		// prefix -> value
 | 
			
		||||
		struct prefix_chain *pc = zalloc(sizeof(*pc) + len);
 | 
			
		||||
		if (!pc)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
@@ -208,7 +207,7 @@ static bool _insert_unset(struct radix_tree *rt, struct value *v, const uint8_t
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _insert_value(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
 | 
			
		||||
static bool _insert_value(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	unsigned len = ke - kb;
 | 
			
		||||
 | 
			
		||||
@@ -235,7 +234,7 @@ static bool _insert_value(struct radix_tree *rt, struct value *v, const uint8_t
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _insert_value_chain(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
 | 
			
		||||
static bool _insert_value_chain(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	struct value_chain *vc = v->value.ptr;
 | 
			
		||||
	return _insert(rt, &vc->child, kb, ke, rv);
 | 
			
		||||
@@ -249,7 +248,7 @@ static unsigned min(unsigned lhs, unsigned rhs)
 | 
			
		||||
		return rhs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
 | 
			
		||||
static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	struct prefix_chain *pc = v->value.ptr;
 | 
			
		||||
 | 
			
		||||
@@ -267,8 +266,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
 | 
			
		||||
			if (kb[i] != pc->prefix[i])
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
		// All fields of pc2 are explicitly initialized
 | 
			
		||||
		if (!(pc2 = malloc(sizeof(*pc2) + pc->len - i)))
 | 
			
		||||
		if (!(pc2 = zalloc(sizeof(*pc2) + pc->len - i)))
 | 
			
		||||
			return false;
 | 
			
		||||
		pc2->len = pc->len - i;
 | 
			
		||||
		memmove(pc2->prefix, pc->prefix + i, pc2->len);
 | 
			
		||||
@@ -280,7 +278,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
 | 
			
		||||
		pc->len = i;
 | 
			
		||||
 | 
			
		||||
		if (!_insert(rt, &pc->child, kb + i, ke, rv)) {
 | 
			
		||||
			free(pc->child.value.ptr);
 | 
			
		||||
			free(pc2);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -294,7 +292,6 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
 | 
			
		||||
		if (pc->len == 1) {
 | 
			
		||||
			n4->values[0] = pc->child;
 | 
			
		||||
			free(pc);
 | 
			
		||||
			v->value.ptr = NULL;
 | 
			
		||||
		} else {
 | 
			
		||||
			memmove(pc->prefix, pc->prefix + 1, pc->len - 1);
 | 
			
		||||
			pc->len--;
 | 
			
		||||
@@ -316,7 +313,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _insert_node4(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
 | 
			
		||||
static bool _insert_node4(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	struct node4 *n4 = v->value.ptr;
 | 
			
		||||
	if (n4->nr_entries == 4) {
 | 
			
		||||
@@ -346,7 +343,7 @@ static bool _insert_node4(struct radix_tree *rt, struct value *v, const uint8_t
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _insert_node16(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
 | 
			
		||||
static bool _insert_node16(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	struct node16 *n16 = v->value.ptr;
 | 
			
		||||
 | 
			
		||||
@@ -385,7 +382,7 @@ static bool _insert_node16(struct radix_tree *rt, struct value *v, const uint8_t
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _insert_node48(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
 | 
			
		||||
static bool _insert_node48(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	struct node48 *n48 = v->value.ptr;
 | 
			
		||||
	if (n48->nr_entries == 48) {
 | 
			
		||||
@@ -420,20 +417,20 @@ static bool _insert_node48(struct radix_tree *rt, struct value *v, const uint8_t
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _insert_node256(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
 | 
			
		||||
static bool _insert_node256(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	struct node256 *n256 = v->value.ptr;
 | 
			
		||||
	bool r, was_unset = n256->values[*kb].type == UNSET;
 | 
			
		||||
 | 
			
		||||
	r = _insert(rt, n256->values + *kb, kb + 1, ke, rv);
 | 
			
		||||
	if (r && was_unset)
 | 
			
		||||
		n256->nr_entries++;
 | 
			
		||||
        	n256->nr_entries++;
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FIXME: the tree should not be touched if insert fails (eg, OOM)
 | 
			
		||||
static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, const uint8_t *ke, union radix_value rv)
 | 
			
		||||
static bool _insert(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	if (kb == ke) {
 | 
			
		||||
		if (v->type == UNSET) {
 | 
			
		||||
@@ -445,8 +442,7 @@ static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, c
 | 
			
		||||
			v->value = rv;
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
			// All fields explicitly initialized
 | 
			
		||||
			struct value_chain *vc = malloc(sizeof(*vc));
 | 
			
		||||
			struct value_chain *vc = zalloc(sizeof(*vc));
 | 
			
		||||
			if (!vc)
 | 
			
		||||
				return false;
 | 
			
		||||
 | 
			
		||||
@@ -491,10 +487,10 @@ static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, c
 | 
			
		||||
 | 
			
		||||
struct lookup_result {
 | 
			
		||||
	struct value *v;
 | 
			
		||||
	const uint8_t *kb;
 | 
			
		||||
	uint8_t *kb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, const uint8_t *ke)
 | 
			
		||||
static struct lookup_result _lookup_prefix(struct value *v, uint8_t *kb, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i;
 | 
			
		||||
	struct value_chain *vc;
 | 
			
		||||
@@ -504,7 +500,7 @@ static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, c
 | 
			
		||||
	struct node48 *n48;
 | 
			
		||||
	struct node256 *n256;
 | 
			
		||||
 | 
			
		||||
	if (kb == ke || !kb) /* extra check for !kb for coverity */
 | 
			
		||||
	if (kb == ke)
 | 
			
		||||
		return (struct lookup_result) {.v = v, .kb = kb};
 | 
			
		||||
 | 
			
		||||
	switch (v->type) {
 | 
			
		||||
@@ -559,38 +555,45 @@ static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, c
 | 
			
		||||
	return (struct lookup_result) {.v = v, .kb = kb};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value rv)
 | 
			
		||||
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	const uint8_t *kb = key;
 | 
			
		||||
	const uint8_t *ke = kb + keylen;
 | 
			
		||||
	struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
 | 
			
		||||
	return _insert(rt, lr.v, lr.kb, ke, rv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
	return radix_tree_insert(rt, key, keylen, rv) ?
 | 
			
		||||
		((entries != rt->nr_entries) ? 1 : -1) : 0;
 | 
			
		||||
        struct node4 *n4 = zalloc(sizeof(*n4));
 | 
			
		||||
 | 
			
		||||
	assert(n4 != NULL);
 | 
			
		||||
 | 
			
		||||
        n4->nr_entries = n16->nr_entries;
 | 
			
		||||
        memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys));
 | 
			
		||||
        memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values));
 | 
			
		||||
        free(n16);
 | 
			
		||||
 | 
			
		||||
	result->type = NODE4;
 | 
			
		||||
	result->value.ptr = n4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _degrade_to_n16(struct node48 *n48, struct value *result)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i, count = 0;
 | 
			
		||||
	struct node16 *n16 = zalloc(sizeof(*n16));
 | 
			
		||||
        struct node16 *n16 = zalloc(sizeof(*n16));
 | 
			
		||||
 | 
			
		||||
	assert(n16 != NULL);
 | 
			
		||||
 | 
			
		||||
	n16->nr_entries = n48->nr_entries;
 | 
			
		||||
	for (i = 0; i < 256; i++) {
 | 
			
		||||
		if (n48->keys[i] < 48) {
 | 
			
		||||
			n16->keys[count] = i;
 | 
			
		||||
			n16->values[count] = n48->values[n48->keys[i]];
 | 
			
		||||
			count++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
        n16->nr_entries = n48->nr_entries;
 | 
			
		||||
        for (i = 0; i < 256; i++) {
 | 
			
		||||
	        if (n48->keys[i] < 48) {
 | 
			
		||||
		        n16->keys[count] = i;
 | 
			
		||||
		        n16->values[count] = n48->values[n48->keys[i]];
 | 
			
		||||
		        count++;
 | 
			
		||||
	        }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	free(n48);
 | 
			
		||||
        free(n48);
 | 
			
		||||
 | 
			
		||||
	result->type = NODE16;
 | 
			
		||||
	result->value.ptr = n16;
 | 
			
		||||
@@ -598,13 +601,13 @@ static void _degrade_to_n16(struct node48 *n48, struct value *result)
 | 
			
		||||
 | 
			
		||||
static void _degrade_to_n48(struct node256 *n256, struct value *result)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i, count = 0;
 | 
			
		||||
	struct node48 *n48 = zalloc(sizeof(*n48));
 | 
			
		||||
        unsigned i, count = 0;
 | 
			
		||||
        struct node48 *n48 = zalloc(sizeof(*n48));
 | 
			
		||||
 | 
			
		||||
	assert(n48 != NULL);
 | 
			
		||||
 | 
			
		||||
	n48->nr_entries = n256->nr_entries;
 | 
			
		||||
	for (i = 0; i < 256; i++) {
 | 
			
		||||
        n48->nr_entries = n256->nr_entries;
 | 
			
		||||
        for (i = 0; i < 256; i++) {
 | 
			
		||||
		if (n256->values[i].type == UNSET)
 | 
			
		||||
			n48->keys[i] = 48;
 | 
			
		||||
 | 
			
		||||
@@ -613,9 +616,9 @@ static void _degrade_to_n48(struct node256 *n256, struct value *result)
 | 
			
		||||
			n48->values[count] = n256->values[i];
 | 
			
		||||
			count++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	free(n256);
 | 
			
		||||
        free(n256);
 | 
			
		||||
 | 
			
		||||
	result->type = NODE48;
 | 
			
		||||
	result->value.ptr = n48;
 | 
			
		||||
@@ -629,14 +632,14 @@ static void _erase_elt(void *array, size_t obj_size, unsigned count, unsigned id
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	memmove(((uint8_t *) array) + (obj_size * idx),
 | 
			
		||||
		((uint8_t *) array) + (obj_size * (idx + 1)),
 | 
			
		||||
		obj_size * (count - idx - 1));
 | 
			
		||||
                ((uint8_t *) array) + (obj_size * (idx + 1)),
 | 
			
		||||
                obj_size * (count - idx - 1));
 | 
			
		||||
 | 
			
		||||
	// Zero the now unused last elt (set's v.type to UNSET)
 | 
			
		||||
	memset(((uint8_t *) array) + (count - 1) * obj_size, 0, obj_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb, const uint8_t *ke)
 | 
			
		||||
static bool _remove(struct radix_tree *rt, struct value *root, uint8_t *kb, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
	bool r;
 | 
			
		||||
	unsigned i, j;
 | 
			
		||||
@@ -648,28 +651,27 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
 | 
			
		||||
	struct node256 *n256;
 | 
			
		||||
 | 
			
		||||
	if (kb == ke) {
 | 
			
		||||
		if (root->type == VALUE) {
 | 
			
		||||
			root->type = UNSET;
 | 
			
		||||
			_dtr(rt, root->value);
 | 
			
		||||
			return true;
 | 
			
		||||
        	if (root->type == VALUE) {
 | 
			
		||||
                	root->type = UNSET;
 | 
			
		||||
                	_dtr(rt, root->value);
 | 
			
		||||
                	return true;
 | 
			
		||||
 | 
			
		||||
		} else if (root->type == VALUE_CHAIN) {
 | 
			
		||||
			// Free value_chain after copying child out
 | 
			
		||||
                } else if (root->type == VALUE_CHAIN) {
 | 
			
		||||
			vc = root->value.ptr;
 | 
			
		||||
			_dtr(rt, vc->value);
 | 
			
		||||
			*root = vc->child;
 | 
			
		||||
			memcpy(root, &vc->child, sizeof(*root));
 | 
			
		||||
			free(vc);
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
		} else
 | 
			
		||||
                } else
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (root->type) {
 | 
			
		||||
	case UNSET:
 | 
			
		||||
	case VALUE:
 | 
			
		||||
		// this is a value for a prefix of the key
 | 
			
		||||
		return false;
 | 
			
		||||
        	// this is a value for a prefix of the key
 | 
			
		||||
        	return false;
 | 
			
		||||
 | 
			
		||||
	case VALUE_CHAIN:
 | 
			
		||||
		vc = root->value.ptr;
 | 
			
		||||
@@ -684,11 +686,11 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
 | 
			
		||||
	case PREFIX_CHAIN:
 | 
			
		||||
		pc = root->value.ptr;
 | 
			
		||||
		if (ke - kb < pc->len)
 | 
			
		||||
			return false;
 | 
			
		||||
        		return false;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < pc->len; i++)
 | 
			
		||||
			if (kb[i] != pc->prefix[i])
 | 
			
		||||
				return false;
 | 
			
		||||
        			return false;
 | 
			
		||||
 | 
			
		||||
		r = _remove(rt, &pc->child, kb + pc->len, ke);
 | 
			
		||||
		if (r && pc->child.type == UNSET) {
 | 
			
		||||
@@ -703,12 +705,12 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
 | 
			
		||||
			if (n4->keys[i] == *kb) {
 | 
			
		||||
				r = _remove(rt, n4->values + i, kb + 1, ke);
 | 
			
		||||
				if (r && n4->values[i].type == UNSET) {
 | 
			
		||||
					if (i < n4->nr_entries) {
 | 
			
		||||
						_erase_elt(n4->keys, sizeof(*n4->keys), n4->nr_entries, i);
 | 
			
		||||
						_erase_elt(n4->values, sizeof(*n4->values), n4->nr_entries, i);
 | 
			
		||||
					}
 | 
			
		||||
        				if (i < n4->nr_entries) {
 | 
			
		||||
	        				_erase_elt(n4->keys, sizeof(*n4->keys), n4->nr_entries, i);
 | 
			
		||||
	        				_erase_elt(n4->values, sizeof(*n4->values), n4->nr_entries, i);
 | 
			
		||||
        				}
 | 
			
		||||
 | 
			
		||||
					n4->nr_entries--;
 | 
			
		||||
        				n4->nr_entries--;
 | 
			
		||||
					if (!n4->nr_entries) {
 | 
			
		||||
						free(n4);
 | 
			
		||||
						root->type = UNSET;
 | 
			
		||||
@@ -720,20 +722,19 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	case NODE16:
 | 
			
		||||
		n16 = root->value.ptr;
 | 
			
		||||
        	n16 = root->value.ptr;
 | 
			
		||||
		for (i = 0; i < n16->nr_entries; i++) {
 | 
			
		||||
			if (n16->keys[i] == *kb) {
 | 
			
		||||
				r = _remove(rt, n16->values + i, kb + 1, ke);
 | 
			
		||||
				if (r && n16->values[i].type == UNSET) {
 | 
			
		||||
					if (i < n16->nr_entries) {
 | 
			
		||||
						_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i);
 | 
			
		||||
						_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i);
 | 
			
		||||
					}
 | 
			
		||||
        				if (i < n16->nr_entries) {
 | 
			
		||||
	        				_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i);
 | 
			
		||||
	        				_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i);
 | 
			
		||||
        				}
 | 
			
		||||
 | 
			
		||||
					n16->nr_entries--;
 | 
			
		||||
					if (!n16->nr_entries) {
 | 
			
		||||
						free(n16);
 | 
			
		||||
						root->type = UNSET;
 | 
			
		||||
        				n16->nr_entries--;
 | 
			
		||||
					if (n16->nr_entries <= 4) {
 | 
			
		||||
        					_degrade_to_n4(n16, root);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				return r;
 | 
			
		||||
@@ -745,18 +746,18 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
 | 
			
		||||
		n48 = root->value.ptr;
 | 
			
		||||
		i = n48->keys[*kb];
 | 
			
		||||
		if (i < 48) {
 | 
			
		||||
			r = _remove(rt, n48->values + i, kb + 1, ke);
 | 
			
		||||
			if (r && n48->values[i].type == UNSET) {
 | 
			
		||||
				n48->keys[*kb] = 48;
 | 
			
		||||
				for (j = 0; j < 256; j++)
 | 
			
		||||
					if (n48->keys[j] < 48 && n48->keys[j] > i)
 | 
			
		||||
						n48->keys[j]--;
 | 
			
		||||
        		r = _remove(rt, n48->values + i, kb + 1, ke);
 | 
			
		||||
        		if (r && n48->values[i].type == UNSET) {
 | 
			
		||||
                		n48->keys[*kb] = 48;
 | 
			
		||||
                		for (j = 0; j < 256; j++)
 | 
			
		||||
	                		if (n48->keys[j] < 48 && n48->keys[j] > i)
 | 
			
		||||
		                		n48->keys[j]--;
 | 
			
		||||
				_erase_elt(n48->values, sizeof(*n48->values), n48->nr_entries, i);
 | 
			
		||||
				n48->nr_entries--;
 | 
			
		||||
				if (n48->nr_entries <= 16)
 | 
			
		||||
					_degrade_to_n16(n48, root);
 | 
			
		||||
			}
 | 
			
		||||
			return r;
 | 
			
		||||
        				_degrade_to_n16(n48, root);
 | 
			
		||||
        		}
 | 
			
		||||
        		return r;
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
@@ -766,7 +767,7 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
 | 
			
		||||
		if (r && n256->values[*kb].type == UNSET) {
 | 
			
		||||
			n256->nr_entries--;
 | 
			
		||||
			if (n256->nr_entries <= 48)
 | 
			
		||||
				_degrade_to_n48(n256, root);
 | 
			
		||||
        			_degrade_to_n48(n256, root);
 | 
			
		||||
		}
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
@@ -774,14 +775,11 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen)
 | 
			
		||||
bool radix_tree_remove(struct radix_tree *rt, uint8_t *key_begin, uint8_t *key_end)
 | 
			
		||||
{
 | 
			
		||||
	const uint8_t *kb = key;
 | 
			
		||||
	const uint8_t *ke = kb + keylen;
 | 
			
		||||
 | 
			
		||||
	if (_remove(rt, &rt->root, kb, ke)) {
 | 
			
		||||
		rt->nr_entries--;
 | 
			
		||||
		return true;
 | 
			
		||||
	if (_remove(rt, &rt->root, key_begin, key_end)) {
 | 
			
		||||
        	rt->nr_entries--;
 | 
			
		||||
        	return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
@@ -789,25 +787,25 @@ bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen)
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
static bool _prefix_chain_matches(const struct lookup_result *lr, const uint8_t *ke)
 | 
			
		||||
static bool _prefix_chain_matches(struct lookup_result *lr, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
	// It's possible the top node is a prefix chain, and
 | 
			
		||||
	// the remaining key matches part of it.
 | 
			
		||||
	if (lr->v->type == PREFIX_CHAIN) {
 | 
			
		||||
		unsigned i, rlen = ke - lr->kb;
 | 
			
		||||
		const struct prefix_chain *pc = lr->v->value.ptr;
 | 
			
		||||
		if (rlen < pc->len) {
 | 
			
		||||
			for (i = 0; i < rlen; i++)
 | 
			
		||||
				if (pc->prefix[i] != lr->kb[i])
 | 
			
		||||
					return false;
 | 
			
		||||
			return true;
 | 
			
		||||
        // It's possible the top node is a prefix chain, and
 | 
			
		||||
        // the remaining key matches part of it.
 | 
			
		||||
        if (lr->v->type == PREFIX_CHAIN) {
 | 
			
		||||
                unsigned i, rlen = ke - lr->kb;
 | 
			
		||||
                struct prefix_chain *pc = lr->v->value.ptr;
 | 
			
		||||
                if (rlen < pc->len) {
 | 
			
		||||
                        for (i = 0; i < rlen; i++)
 | 
			
		||||
                                if (pc->prefix[i] != lr->kb[i])
 | 
			
		||||
                                        return false;
 | 
			
		||||
                        return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
        return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uint8_t *kb, const uint8_t *ke, unsigned *count)
 | 
			
		||||
static bool _remove_subtree(struct radix_tree *rt, struct value *root, uint8_t *kb, uint8_t *ke, unsigned *count)
 | 
			
		||||
{
 | 
			
		||||
	bool r;
 | 
			
		||||
	unsigned i, j, len;
 | 
			
		||||
@@ -828,7 +826,7 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
 | 
			
		||||
	case UNSET:
 | 
			
		||||
	case VALUE:
 | 
			
		||||
		// No entries with the given prefix
 | 
			
		||||
		return true;
 | 
			
		||||
        	return true;
 | 
			
		||||
 | 
			
		||||
	case VALUE_CHAIN:
 | 
			
		||||
		vc = root->value.ptr;
 | 
			
		||||
@@ -845,7 +843,7 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
 | 
			
		||||
		len = min(pc->len, ke - kb);
 | 
			
		||||
		for (i = 0; i < len; i++)
 | 
			
		||||
			if (kb[i] != pc->prefix[i])
 | 
			
		||||
				return true;
 | 
			
		||||
        			return true;
 | 
			
		||||
 | 
			
		||||
		r = _remove_subtree(rt, &pc->child, len < pc->len ? ke : (kb + pc->len), ke, count);
 | 
			
		||||
		if (r && pc->child.type == UNSET) {
 | 
			
		||||
@@ -860,12 +858,12 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
 | 
			
		||||
			if (n4->keys[i] == *kb) {
 | 
			
		||||
				r = _remove_subtree(rt, n4->values + i, kb + 1, ke, count);
 | 
			
		||||
				if (r && n4->values[i].type == UNSET) {
 | 
			
		||||
					if (i < n4->nr_entries) {
 | 
			
		||||
						_erase_elt(n4->keys, sizeof(*n4->keys), n4->nr_entries, i);
 | 
			
		||||
						_erase_elt(n4->values, sizeof(*n4->values), n4->nr_entries, i);
 | 
			
		||||
					}
 | 
			
		||||
        				if (i < n4->nr_entries) {
 | 
			
		||||
	        				_erase_elt(n4->keys, sizeof(*n4->keys), n4->nr_entries, i);
 | 
			
		||||
	        				_erase_elt(n4->values, sizeof(*n4->values), n4->nr_entries, i);
 | 
			
		||||
        				}
 | 
			
		||||
 | 
			
		||||
					n4->nr_entries--;
 | 
			
		||||
        				n4->nr_entries--;
 | 
			
		||||
					if (!n4->nr_entries) {
 | 
			
		||||
						free(n4);
 | 
			
		||||
						root->type = UNSET;
 | 
			
		||||
@@ -877,21 +875,19 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	case NODE16:
 | 
			
		||||
		n16 = root->value.ptr;
 | 
			
		||||
        	n16 = root->value.ptr;
 | 
			
		||||
		for (i = 0; i < n16->nr_entries; i++) {
 | 
			
		||||
			if (n16->keys[i] == *kb) {
 | 
			
		||||
				r = _remove_subtree(rt, n16->values + i, kb + 1, ke, count);
 | 
			
		||||
				if (r && n16->values[i].type == UNSET) {
 | 
			
		||||
					if (i < n16->nr_entries) {
 | 
			
		||||
						_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i);
 | 
			
		||||
						_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i);
 | 
			
		||||
					}
 | 
			
		||||
        				if (i < n16->nr_entries) {
 | 
			
		||||
	        				_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i);
 | 
			
		||||
	        				_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i);
 | 
			
		||||
        				}
 | 
			
		||||
 | 
			
		||||
					n16->nr_entries--;
 | 
			
		||||
					if (!n16->nr_entries) {
 | 
			
		||||
						free(n16);
 | 
			
		||||
						root->type = UNSET;
 | 
			
		||||
					}
 | 
			
		||||
        				n16->nr_entries--;
 | 
			
		||||
					if (n16->nr_entries <= 4)
 | 
			
		||||
        					_degrade_to_n4(n16, root);
 | 
			
		||||
				}
 | 
			
		||||
				return r;
 | 
			
		||||
			}
 | 
			
		||||
@@ -902,18 +898,18 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
 | 
			
		||||
		n48 = root->value.ptr;
 | 
			
		||||
		i = n48->keys[*kb];
 | 
			
		||||
		if (i < 48) {
 | 
			
		||||
			r = _remove_subtree(rt, n48->values + i, kb + 1, ke, count);
 | 
			
		||||
			if (r && n48->values[i].type == UNSET) {
 | 
			
		||||
				n48->keys[*kb] = 48;
 | 
			
		||||
				for (j = 0; j < 256; j++)
 | 
			
		||||
					if (n48->keys[j] < 48 && n48->keys[j] > i)
 | 
			
		||||
						n48->keys[j]--;
 | 
			
		||||
        		r = _remove_subtree(rt, n48->values + i, kb + 1, ke, count);
 | 
			
		||||
        		if (r && n48->values[i].type == UNSET) {
 | 
			
		||||
                		n48->keys[*kb] = 48;
 | 
			
		||||
                		for (j = 0; j < 256; j++)
 | 
			
		||||
	                		if (n48->keys[j] < 48 && n48->keys[j] > i)
 | 
			
		||||
		                		n48->keys[j]--;
 | 
			
		||||
				_erase_elt(n48->values, sizeof(*n48->values), n48->nr_entries, i);
 | 
			
		||||
				n48->nr_entries--;
 | 
			
		||||
				if (n48->nr_entries <= 16)
 | 
			
		||||
					_degrade_to_n16(n48, root);
 | 
			
		||||
			}
 | 
			
		||||
			return r;
 | 
			
		||||
        				_degrade_to_n16(n48, root);
 | 
			
		||||
        		}
 | 
			
		||||
        		return r;
 | 
			
		||||
		}
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
@@ -926,7 +922,7 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
 | 
			
		||||
		if (r && n256->values[*kb].type == UNSET) {
 | 
			
		||||
			n256->nr_entries--;
 | 
			
		||||
			if (n256->nr_entries <= 48)
 | 
			
		||||
				_degrade_to_n48(n256, root);
 | 
			
		||||
        			_degrade_to_n48(n256, root);
 | 
			
		||||
		}
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
@@ -935,13 +931,11 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, size_t prefix_len)
 | 
			
		||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
	const uint8_t *kb = prefix;
 | 
			
		||||
	const uint8_t *ke = kb + prefix_len;
 | 
			
		||||
	unsigned count = 0;
 | 
			
		||||
        unsigned count = 0;
 | 
			
		||||
 | 
			
		||||
	if (_remove_subtree(rt, &rt->root, kb, ke, &count))
 | 
			
		||||
        if (_remove_subtree(rt, &rt->root, kb, ke, &count))
 | 
			
		||||
		rt->nr_entries -= count;
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
@@ -949,11 +943,9 @@ unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, siz
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
 | 
			
		||||
		       union radix_value *result)
 | 
			
		||||
bool radix_tree_lookup(struct radix_tree *rt,
 | 
			
		||||
		       uint8_t *kb, uint8_t *ke, union radix_value *result)
 | 
			
		||||
{
 | 
			
		||||
	const uint8_t *kb = key;
 | 
			
		||||
	const uint8_t *ke = kb + keylen;
 | 
			
		||||
	struct value_chain *vc;
 | 
			
		||||
	struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
 | 
			
		||||
	if (lr.kb == ke) {
 | 
			
		||||
@@ -976,58 +968,58 @@ bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FIXME: build up the keys too
 | 
			
		||||
static bool _iterate(struct radix_tree_iterator *it, const struct value *v)
 | 
			
		||||
static bool _iterate(struct value *v, struct radix_tree_iterator *it)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i;
 | 
			
		||||
	const struct value_chain *vc;
 | 
			
		||||
	const struct prefix_chain *pc;
 | 
			
		||||
	const struct node4 *n4;
 | 
			
		||||
	const struct node16 *n16;
 | 
			
		||||
	const struct node48 *n48;
 | 
			
		||||
	const struct node256 *n256;
 | 
			
		||||
	struct value_chain *vc;
 | 
			
		||||
	struct prefix_chain *pc;
 | 
			
		||||
	struct node4 *n4;
 | 
			
		||||
	struct node16 *n16;
 | 
			
		||||
	struct node48 *n48;
 | 
			
		||||
	struct node256 *n256;
 | 
			
		||||
 | 
			
		||||
	switch (v->type) {
 | 
			
		||||
	case UNSET:
 | 
			
		||||
		// can't happen
 | 
			
		||||
        	// can't happen
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case VALUE:
 | 
			
		||||
		return it->visit(it, NULL, 0, v->value);
 | 
			
		||||
        	return it->visit(it, NULL, NULL, v->value);
 | 
			
		||||
 | 
			
		||||
	case VALUE_CHAIN:
 | 
			
		||||
		vc = v->value.ptr;
 | 
			
		||||
		return it->visit(it, NULL, 0, vc->value) && _iterate(it, &vc->child);
 | 
			
		||||
		return it->visit(it, NULL, NULL, vc->value) && _iterate(&vc->child, it);
 | 
			
		||||
 | 
			
		||||
	case PREFIX_CHAIN:
 | 
			
		||||
		pc = v->value.ptr;
 | 
			
		||||
		return _iterate(it, &pc->child);
 | 
			
		||||
		return _iterate(&pc->child, it);
 | 
			
		||||
 | 
			
		||||
	case NODE4:
 | 
			
		||||
		n4 = (const struct node4 *) v->value.ptr;
 | 
			
		||||
		n4 = (struct node4 *) v->value.ptr;
 | 
			
		||||
		for (i = 0; i < n4->nr_entries; i++)
 | 
			
		||||
			if (!_iterate(it, n4->values + i))
 | 
			
		||||
				return false;
 | 
			
		||||
		return true;
 | 
			
		||||
			if (!_iterate(n4->values + i, it))
 | 
			
		||||
        			return false;
 | 
			
		||||
        	return true;
 | 
			
		||||
 | 
			
		||||
	case NODE16:
 | 
			
		||||
		n16 = (const struct node16 *) v->value.ptr;
 | 
			
		||||
		n16 = (struct node16 *) v->value.ptr;
 | 
			
		||||
		for (i = 0; i < n16->nr_entries; i++)
 | 
			
		||||
			if (!_iterate(it, n16->values + i))
 | 
			
		||||
				return false;
 | 
			
		||||
        		if (!_iterate(n16->values + i, it))
 | 
			
		||||
        			return false;
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	case NODE48:
 | 
			
		||||
		n48 = (const struct node48 *) v->value.ptr;
 | 
			
		||||
		n48 = (struct node48 *) v->value.ptr;
 | 
			
		||||
		for (i = 0; i < n48->nr_entries; i++)
 | 
			
		||||
			if (!_iterate(it, n48->values + i))
 | 
			
		||||
				return false;
 | 
			
		||||
        		if (!_iterate(n48->values + i, it))
 | 
			
		||||
        			return false;
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	case NODE256:
 | 
			
		||||
		n256 = (const struct node256 *) v->value.ptr;
 | 
			
		||||
		n256 = (struct node256 *) v->value.ptr;
 | 
			
		||||
		for (i = 0; i < 256; i++)
 | 
			
		||||
			if (n256->values[i].type != UNSET && !_iterate(it, n256->values + i))
 | 
			
		||||
				return false;
 | 
			
		||||
        		if (n256->values[i].type != UNSET && !_iterate(n256->values + i, it))
 | 
			
		||||
        			return false;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1035,14 +1027,12 @@ static bool _iterate(struct radix_tree_iterator *it, const struct value *v)
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
 | 
			
		||||
			struct radix_tree_iterator *it)
 | 
			
		||||
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
 | 
			
		||||
                        struct radix_tree_iterator *it)
 | 
			
		||||
{
 | 
			
		||||
	const uint8_t *kb = key;
 | 
			
		||||
	const uint8_t *ke = kb + keylen;
 | 
			
		||||
	struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
 | 
			
		||||
	if (lr.kb == ke || _prefix_chain_matches(&lr, ke))
 | 
			
		||||
		(void) _iterate(it, lr.v);
 | 
			
		||||
		(void) _iterate(lr.v, it);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
@@ -1140,7 +1130,7 @@ static bool _check_nodes(struct value *v, unsigned *count)
 | 
			
		||||
 | 
			
		||||
		if (ncount != n48->nr_entries) {
 | 
			
		||||
			fprintf(stderr, "incorrect number of entries in n48, n48->nr_entries = %u, actual = %u\n",
 | 
			
		||||
				n48->nr_entries, ncount);
 | 
			
		||||
                                n48->nr_entries, ncount);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -1176,7 +1166,7 @@ static bool _check_nodes(struct value *v, unsigned *count)
 | 
			
		||||
 | 
			
		||||
		if (ncount != n256->nr_entries) {
 | 
			
		||||
			fprintf(stderr, "incorrect number of entries in n256, n256->nr_entries = %u, actual = %u\n",
 | 
			
		||||
				n256->nr_entries, ncount);
 | 
			
		||||
                                n256->nr_entries, ncount);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -1199,7 +1189,7 @@ bool radix_tree_is_well_formed(struct radix_tree *rt)
 | 
			
		||||
 | 
			
		||||
	if (rt->nr_entries != count) {
 | 
			
		||||
		fprintf(stderr, "incorrect entry count: rt->nr_entries = %u, actual = %u\n",
 | 
			
		||||
			rt->nr_entries, count);
 | 
			
		||||
                        rt->nr_entries, count);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1217,7 +1207,6 @@ static void _dump(FILE *out, struct value v, unsigned indent)
 | 
			
		||||
	struct node16 *n16;
 | 
			
		||||
	struct node48 *n48;
 | 
			
		||||
	struct node256 *n256;
 | 
			
		||||
	unsigned printable;
 | 
			
		||||
 | 
			
		||||
	if (v.type == UNSET)
 | 
			
		||||
		return;
 | 
			
		||||
@@ -1242,22 +1231,9 @@ static void _dump(FILE *out, struct value v, unsigned indent)
 | 
			
		||||
 | 
			
		||||
	case PREFIX_CHAIN:
 | 
			
		||||
		pc = v.value.ptr;
 | 
			
		||||
		fprintf(out, "<prefix(%u): ", pc->len);
 | 
			
		||||
		printable = 1;
 | 
			
		||||
		fprintf(out, "<prefix: ");
 | 
			
		||||
		for (i = 0; i < pc->len; i++)
 | 
			
		||||
			if (!isprint(pc->prefix[i])) {
 | 
			
		||||
				printable = 0;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		if (printable)
 | 
			
		||||
			fputc('"', out);
 | 
			
		||||
		for (i = 0; i < pc->len; i++)
 | 
			
		||||
			if (printable)
 | 
			
		||||
				fprintf(out, "%c", pc->prefix[i]);
 | 
			
		||||
			else
 | 
			
		||||
				fprintf(out, "%02x.", (unsigned) *(pc->prefix + i));
 | 
			
		||||
		if (printable)
 | 
			
		||||
			fputc('"', out);
 | 
			
		||||
			fprintf(out, "%x.", (unsigned) *(pc->prefix + i));
 | 
			
		||||
		fprintf(out, ">\n");
 | 
			
		||||
		_dump(out, pc->child, indent + 1);
 | 
			
		||||
		break;
 | 
			
		||||
@@ -1266,7 +1242,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
 | 
			
		||||
		n4 = v.value.ptr;
 | 
			
		||||
		fprintf(out, "<n4: ");
 | 
			
		||||
		for (i = 0; i < n4->nr_entries; i++)
 | 
			
		||||
			fprintf(out, "%02x ", (unsigned) n4->keys[i]);
 | 
			
		||||
			fprintf(out, "%x ", (unsigned) n4->keys[i]);
 | 
			
		||||
		fprintf(out, ">\n");
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < n4->nr_entries; i++)
 | 
			
		||||
@@ -1277,7 +1253,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
 | 
			
		||||
		n16 = v.value.ptr;
 | 
			
		||||
		fprintf(out, "<n16: ");
 | 
			
		||||
		for (i = 0; i < n16->nr_entries; i++)
 | 
			
		||||
			fprintf(out, "%02x ", (unsigned) n16->keys[i]);
 | 
			
		||||
			fprintf(out, "%x ", (unsigned) n16->keys[i]);
 | 
			
		||||
		fprintf(out, ">\n");
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < n16->nr_entries; i++)
 | 
			
		||||
@@ -1289,7 +1265,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
 | 
			
		||||
		fprintf(out, "<n48: ");
 | 
			
		||||
		for (i = 0; i < 256; i++)
 | 
			
		||||
			if (n48->keys[i] < 48)
 | 
			
		||||
				fprintf(out, "%02x ", i);
 | 
			
		||||
				fprintf(out, "%x ", i);
 | 
			
		||||
		fprintf(out, ">\n");
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < n48->nr_entries; i++) {
 | 
			
		||||
@@ -1303,7 +1279,7 @@ static void _dump(FILE *out, struct value v, unsigned indent)
 | 
			
		||||
		fprintf(out, "<n256: ");
 | 
			
		||||
		for (i = 0; i < 256; i++)
 | 
			
		||||
			if (n256->values[i].type != UNSET)
 | 
			
		||||
				fprintf(out, "%02x ", i);
 | 
			
		||||
				fprintf(out, "%x ", i);
 | 
			
		||||
		fprintf(out, ">\n");
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < 256; i++)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// 
 | 
			
		||||
// This file is part of LVM2.
 | 
			
		||||
//
 | 
			
		||||
// This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
@@ -18,7 +18,6 @@
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
// This implementation is based around nested binary trees.  Very
 | 
			
		||||
@@ -38,12 +37,12 @@ struct node {
 | 
			
		||||
struct radix_tree {
 | 
			
		||||
	radix_value_dtr dtr;
 | 
			
		||||
	void *dtr_context;
 | 
			
		||||
	unsigned nr_entries;
 | 
			
		||||
 | 
			
		||||
	struct node *root;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context)
 | 
			
		||||
struct radix_tree *
 | 
			
		||||
radix_tree_create(radix_value_dtr dtr, void *dtr_context)
 | 
			
		||||
{
 | 
			
		||||
	struct radix_tree *rt = zalloc(sizeof(*rt));
 | 
			
		||||
 | 
			
		||||
@@ -106,7 +105,7 @@ unsigned radix_tree_size(struct radix_tree *rt)
 | 
			
		||||
	return _count(rt->root);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct node **_lookup(struct node **pn, const uint8_t *kb, const uint8_t *ke)
 | 
			
		||||
static struct node **_lookup(struct node **pn, uint8_t *kb, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
	struct node *n = *pn;
 | 
			
		||||
 | 
			
		||||
@@ -123,7 +122,7 @@ static struct node **_lookup(struct node **pn, const uint8_t *kb, const uint8_t
 | 
			
		||||
		return _lookup(&n->center, kb + 1, ke);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _insert(struct node **pn, const uint8_t *kb, const uint8_t *ke, union radix_value v)
 | 
			
		||||
static bool _insert(struct node **pn, uint8_t *kb, uint8_t *ke, union radix_value v)
 | 
			
		||||
{
 | 
			
		||||
	struct node *n = *pn;
 | 
			
		||||
 | 
			
		||||
@@ -152,53 +151,41 @@ static bool _insert(struct node **pn, const uint8_t *kb, const uint8_t *ke, unio
 | 
			
		||||
		return _insert(&n->center, kb + 1, ke, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen,
 | 
			
		||||
		       union radix_value v)
 | 
			
		||||
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v)
 | 
			
		||||
{
 | 
			
		||||
	const uint8_t *kb = key;
 | 
			
		||||
	const uint8_t *ke = kb + keylen;
 | 
			
		||||
 | 
			
		||||
	if (!_insert(&rt->root, kb, ke, v))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	rt->nr_entries++;
 | 
			
		||||
	return true;
 | 
			
		||||
	return _insert(&rt->root, kb, ke, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen)
 | 
			
		||||
bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
	const uint8_t *kb = key;
 | 
			
		||||
	const uint8_t *ke = kb + keylen;
 | 
			
		||||
	struct node **pn = _lookup(&rt->root, kb, ke);
 | 
			
		||||
	struct node *n = *pn;
 | 
			
		||||
 | 
			
		||||
	if (!n || !n->has_value)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	rt->nr_entries--;
 | 
			
		||||
	else {
 | 
			
		||||
		if (rt->dtr)
 | 
			
		||||
			rt->dtr(rt->dtr_context, n->value);
 | 
			
		||||
 | 
			
		||||
	if (rt->dtr)
 | 
			
		||||
	    rt->dtr(rt->dtr_context, n->value);
 | 
			
		||||
		if (n->left || n->center || n->right) {
 | 
			
		||||
			n->has_value = false;
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
	if (n->left || n->center || n->right) {
 | 
			
		||||
	    n->has_value = false;
 | 
			
		||||
	    return true;
 | 
			
		||||
		} else {
 | 
			
		||||
			// FIXME: delete parent if this was the last entry
 | 
			
		||||
			free(n);
 | 
			
		||||
			*pn = NULL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// FIXME: delete parent if this was the last entry
 | 
			
		||||
	free(n);
 | 
			
		||||
	*pn = NULL;
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *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;
 | 
			
		||||
	unsigned count = 0;
 | 
			
		||||
	unsigned count;
 | 
			
		||||
 | 
			
		||||
	pn = _lookup(&rt->root, kb, ke);
 | 
			
		||||
 | 
			
		||||
@@ -210,20 +197,17 @@ unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, siz
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
 | 
			
		||||
		       union radix_value *result)
 | 
			
		||||
bool
 | 
			
		||||
radix_tree_lookup(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value *result)
 | 
			
		||||
{
 | 
			
		||||
	const uint8_t *kb = key;
 | 
			
		||||
	const uint8_t *ke = kb + keylen;
 | 
			
		||||
	struct node **pn = _lookup(&rt->root, kb, ke);
 | 
			
		||||
	struct node *n = *pn;
 | 
			
		||||
 | 
			
		||||
	if (n && n->has_value) {
 | 
			
		||||
		*result = n->value;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
	} else
 | 
			
		||||
		return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _iterate(struct node *n, struct radix_tree_iterator *it)
 | 
			
		||||
@@ -235,18 +219,15 @@ static void _iterate(struct node *n, struct radix_tree_iterator *it)
 | 
			
		||||
 | 
			
		||||
	if (n->has_value)
 | 
			
		||||
		// FIXME: fill out the key
 | 
			
		||||
		it->visit(it, NULL, 0, n->value);
 | 
			
		||||
		it->visit(it, NULL, NULL, n->value);
 | 
			
		||||
 | 
			
		||||
	_iterate(n->center, it);
 | 
			
		||||
	_iterate(n->right, it);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
 | 
			
		||||
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
 | 
			
		||||
                        struct radix_tree_iterator *it)
 | 
			
		||||
{
 | 
			
		||||
	const uint8_t *kb = key;
 | 
			
		||||
	const uint8_t *ke = kb + keylen;
 | 
			
		||||
 | 
			
		||||
	if (kb == ke)
 | 
			
		||||
		_iterate(rt->root, it);
 | 
			
		||||
 | 
			
		||||
@@ -256,7 +237,7 @@ void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
 | 
			
		||||
 | 
			
		||||
		if (n) {
 | 
			
		||||
			if (n->has_value)
 | 
			
		||||
				it->visit(it, NULL, 0, n->value);
 | 
			
		||||
				it->visit(it, NULL, NULL, n->value);
 | 
			
		||||
			_iterate(n->center, it);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -267,32 +248,8 @@ bool radix_tree_is_well_formed(struct radix_tree *rt)
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _dump(FILE *out, struct node *n, unsigned indent)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i;
 | 
			
		||||
 | 
			
		||||
	if (!n)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	_dump(out, n->left, indent + 1);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 2 * indent; i++)
 | 
			
		||||
		fprintf(out, " ");
 | 
			
		||||
 | 
			
		||||
	if (n->has_value) {
 | 
			
		||||
		fprintf(out, "value: %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)
 | 
			
		||||
{
 | 
			
		||||
	_dump(out, rt->root, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -19,45 +19,3 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
struct visitor {
 | 
			
		||||
	struct radix_tree_iterator it;
 | 
			
		||||
	unsigned pos, nr_entries;
 | 
			
		||||
	union radix_value *values;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static bool _visitor(struct radix_tree_iterator *it,
 | 
			
		||||
		     const void *key, size_t keylen,
 | 
			
		||||
		     union radix_value v)
 | 
			
		||||
{
 | 
			
		||||
	struct visitor *vt = container_of(it, struct visitor, it);
 | 
			
		||||
 | 
			
		||||
	if (vt->pos >= vt->nr_entries)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	vt->values[vt->pos++] = v;
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_values(struct radix_tree *rt, const void *key, size_t keylen,
 | 
			
		||||
		       union radix_value **values, unsigned *nr_values)
 | 
			
		||||
{
 | 
			
		||||
	struct visitor vt = {
 | 
			
		||||
		.it.visit = _visitor,
 | 
			
		||||
		.nr_entries = rt->nr_entries,
 | 
			
		||||
		.values = calloc(rt->nr_entries + 1, sizeof(union radix_value)),
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	if (vt.values) {
 | 
			
		||||
		// build set of all values in current radix tree
 | 
			
		||||
		radix_tree_iterate(rt, key, keylen, &vt.it);
 | 
			
		||||
		*nr_values = vt.pos;
 | 
			
		||||
		*values = vt.values;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -33,61 +33,32 @@ struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context);
 | 
			
		||||
void radix_tree_destroy(struct radix_tree *rt);
 | 
			
		||||
 | 
			
		||||
unsigned radix_tree_size(struct radix_tree *rt);
 | 
			
		||||
bool radix_tree_insert(struct radix_tree *rt, const void *key, size_t keylen, union radix_value v);
 | 
			
		||||
bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen);
 | 
			
		||||
// 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);
 | 
			
		||||
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v);
 | 
			
		||||
bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke);
 | 
			
		||||
 | 
			
		||||
// Returns the number of values removed
 | 
			
		||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, size_t prefix_len);
 | 
			
		||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *prefix_b, uint8_t *prefix_e);
 | 
			
		||||
 | 
			
		||||
bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen,
 | 
			
		||||
		       union radix_value *result);
 | 
			
		||||
bool radix_tree_lookup(struct radix_tree *rt,
 | 
			
		||||
		       uint8_t *kb, uint8_t *ke, union radix_value *result);
 | 
			
		||||
 | 
			
		||||
// The radix tree stores entries in lexicographical order.  Which means
 | 
			
		||||
// we can iterate entries, in order.  Or iterate entries with a particular
 | 
			
		||||
// prefix.
 | 
			
		||||
struct radix_tree_iterator {
 | 
			
		||||
	// Returns false if the iteration should end.
 | 
			
		||||
        // Returns false if the iteration should end.
 | 
			
		||||
	bool (*visit)(struct radix_tree_iterator *it,
 | 
			
		||||
		      const void *key, size_t keylen, union radix_value v);
 | 
			
		||||
                      uint8_t *kb, uint8_t *ke, union radix_value v);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void radix_tree_iterate(struct radix_tree *rt, const void *key, size_t keylen,
 | 
			
		||||
			struct radix_tree_iterator *it);
 | 
			
		||||
 | 
			
		||||
// Alternative traversing radix_tree.
 | 
			
		||||
// Builds whole set all radix_tree  nr_values values.
 | 
			
		||||
// After use, free(values).
 | 
			
		||||
bool radix_tree_values(struct radix_tree *rt, const void *key, size_t keylen,
 | 
			
		||||
		       union radix_value **values, unsigned *nr_values);
 | 
			
		||||
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
 | 
			
		||||
                        struct radix_tree_iterator *it);
 | 
			
		||||
 | 
			
		||||
// Checks that some constraints on the shape of the tree are
 | 
			
		||||
// being held.  For debug only.
 | 
			
		||||
bool radix_tree_is_well_formed(struct radix_tree *rt);
 | 
			
		||||
void radix_tree_dump(struct radix_tree *rt, FILE *out);
 | 
			
		||||
 | 
			
		||||
// Shortcut for ptr value return
 | 
			
		||||
// Note: if value would be NULL, it's same result for not/found case.
 | 
			
		||||
static inline void *radix_tree_lookup_ptr(struct radix_tree *rt, const void *key, size_t keylen)
 | 
			
		||||
{
 | 
			
		||||
	union radix_value v;
 | 
			
		||||
	return radix_tree_lookup(rt, key, keylen, &v) ? v.ptr : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool radix_tree_insert_ptr(struct radix_tree *rt, const void *key, size_t keylen, void *ptr)
 | 
			
		||||
{
 | 
			
		||||
	union radix_value v = { .ptr = ptr };
 | 
			
		||||
	return radix_tree_insert(rt, key, keylen, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ install_localconf: $(CONFLOCAL)
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
install_profiles: $(PROFILES)
 | 
			
		||||
	$(SHOW) "    [INSTALL] $<"
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_DIR) $(profiledir)
 | 
			
		||||
	$(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -36,19 +36,6 @@ config {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# checks = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option config/validate_metadata.
 | 
			
		||||
	# Allows selecting the level of validation after metadata transformation.
 | 
			
		||||
	# Validation takes extra CPU time to verify internal consistency.
 | 
			
		||||
	# Accepted values:
 | 
			
		||||
	#   full
 | 
			
		||||
	#     Do a full metadata validation before disk write.
 | 
			
		||||
	#   none
 | 
			
		||||
	#     Skip any checks (unrecommended, slightly faster).
 | 
			
		||||
	#
 | 
			
		||||
	# This configuration option is advanced.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# validate_metadata = "full"
 | 
			
		||||
 | 
			
		||||
	# Configuration option config/abort_on_errors.
 | 
			
		||||
	# Abort the LVM process if a configuration mismatch is found.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
@@ -135,11 +122,11 @@ devices {
 | 
			
		||||
	# Configuration option devices/use_devicesfile.
 | 
			
		||||
	# Enable or disable the use of a devices file.
 | 
			
		||||
	# When enabled, lvm will only use devices that
 | 
			
		||||
	# are listed in the devices file. A devices file will
 | 
			
		||||
	# are lised in the devices file. A devices file will
 | 
			
		||||
	# be used, regardless of this setting, when the --devicesfile
 | 
			
		||||
	# option is set to a specific file name.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# use_devicesfile = @DEFAULT_USE_DEVICES_FILE@
 | 
			
		||||
	# use_devicesfile = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/devicesfile.
 | 
			
		||||
	# The name of the system devices file, listing devices that LVM should use.
 | 
			
		||||
@@ -148,16 +135,6 @@ devices {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# devicesfile = "system.devices"
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/devicesfile_backup_limit.
 | 
			
		||||
	# The max number of backup files to keep in /etc/lvm/devices/backup.
 | 
			
		||||
	# LVM creates a backup of the devices file each time a new
 | 
			
		||||
	# version is created, or each time a modification is detected.
 | 
			
		||||
	# When the max number of backups is reached, the oldest are
 | 
			
		||||
	# removed to remain at the limit. Set to 0 to disable backups.
 | 
			
		||||
	# Only the system devices file is backed up.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# devicesfile_backup_limit = 50
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/search_for_devnames.
 | 
			
		||||
	# Look outside of the devices file for missing devname entries.
 | 
			
		||||
	# A devname entry is used for a device that does not have a stable
 | 
			
		||||
@@ -172,27 +149,7 @@ devices {
 | 
			
		||||
	# at other devices, but only those that are likely to have the PV.
 | 
			
		||||
	# If "all", lvm will look at all devices on the system.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# search_for_devnames = "all"
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/device_ids_refresh.
 | 
			
		||||
	# Find PVs on new devices and update the device IDs in the devices file.
 | 
			
		||||
	# If PVs are restored or moved to a new system with new devices, but
 | 
			
		||||
	# an old system.devices remains with old device IDs, then search for
 | 
			
		||||
	# the PVIDs on new devices and update the device IDs in system.devices.
 | 
			
		||||
	# The original device IDs must also not be found on the new system.
 | 
			
		||||
	# See device_ids_refresh_check for conditions that trigger the refresh.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# device_ids_refresh = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/device_ids_refresh_checks.
 | 
			
		||||
	# Conditions that trigger device_ids_refresh to locate PVIDs on new devices.
 | 
			
		||||
	# product_uuid: refresh if /sys/devices/virtual/dmi/id/product_uuid does not
 | 
			
		||||
	# match the value saved in system.devices.
 | 
			
		||||
	# hostname: refresh if hostname does not match the value saved in system.devices.
 | 
			
		||||
	# (hostname is used if product_uuid is not available.)
 | 
			
		||||
	# Remove values from this list to prevent lvm from using them.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# device_ids_refresh_checks = [ "product_uuid", "hostname" ]
 | 
			
		||||
	# search_for_devnames = "auto"
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/filter.
 | 
			
		||||
	# Limit the block devices that are used by LVM commands.
 | 
			
		||||
@@ -207,7 +164,7 @@ devices {
 | 
			
		||||
	# device is rejected. Unmatching path names do not affect the accept
 | 
			
		||||
	# or reject decision. If no path names for a device match a pattern,
 | 
			
		||||
	# then the device is accepted. Be careful mixing 'a' and 'r' patterns,
 | 
			
		||||
	# as the combination might produce unexpected results (test changes).
 | 
			
		||||
	# as the combination might produce unexpected results (test changes.)
 | 
			
		||||
	# Run vgscan after changing the filter to regenerate the cache.
 | 
			
		||||
	#
 | 
			
		||||
	# Example
 | 
			
		||||
@@ -249,17 +206,22 @@ devices {
 | 
			
		||||
	# Configuration option devices/sysfs_scan.
 | 
			
		||||
	# Restrict device scanning to block devices appearing in sysfs.
 | 
			
		||||
	# This is a quick way of filtering out block devices that are not
 | 
			
		||||
	# present on the system. sysfs must be part of the kernel and mounted.
 | 
			
		||||
	# present on the system. sysfs must be part of the kernel and mounted.)
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# sysfs_scan = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/scan_lvs.
 | 
			
		||||
	# Allow LVM LVs to be used as PVs. When enabled, LVM commands will
 | 
			
		||||
	# scan active LVs to look for other PVs. Caution is required to
 | 
			
		||||
	# avoid using PVs that belong to guest images stored on LVs.
 | 
			
		||||
	# When enabled, the LVs scanned should be restricted using the
 | 
			
		||||
	# devices file or the filter. This option does not enable autoactivation
 | 
			
		||||
	# of layered VGs, which requires editing LVM udev rules (see LVM_PVSCAN_ON_LVS).
 | 
			
		||||
	# Scan LVM LVs for layered PVs, allowing LVs to be used as PVs.
 | 
			
		||||
	# When 1, LVM will detect PVs layered on LVs, and caution must be
 | 
			
		||||
	# taken to avoid a host accessing a layered VG that may not belong
 | 
			
		||||
	# to it, e.g. from a guest image. This generally requires excluding
 | 
			
		||||
	# the LVs with device filters. Also, when this setting is enabled,
 | 
			
		||||
	# every LVM command will scan every active LV on the system (unless
 | 
			
		||||
	# filtered), which can cause performance problems on systems with
 | 
			
		||||
	# many active LVs. When this setting is 0, LVM will not detect or
 | 
			
		||||
	# use PVs that exist on LVs, and will not allow a PV to be created on
 | 
			
		||||
	# an LV. The LVs are ignored using a built in device filter that
 | 
			
		||||
	# identifies and excludes LVs.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# scan_lvs = 0
 | 
			
		||||
 | 
			
		||||
@@ -337,7 +299,7 @@ devices {
 | 
			
		||||
	# penalty, e.g. MD chunk size. optimal_io_size is the device's
 | 
			
		||||
	# preferred unit of receiving I/O, e.g. MD stripe width.
 | 
			
		||||
	# minimum_io_size is used if optimal_io_size is undefined (0).
 | 
			
		||||
	# If md_chunk_alignment is enabled, it will detect the optimal_io_size.
 | 
			
		||||
	# If md_chunk_alignment is enabled, that detects the optimal_io_size.
 | 
			
		||||
	# default_data_alignment and md_chunk_alignment will be overridden
 | 
			
		||||
	# if they are not aligned with the value detected for this setting.
 | 
			
		||||
	# This setting is overridden by data_alignment and the --dataalignment
 | 
			
		||||
@@ -497,7 +459,7 @@ allocation {
 | 
			
		||||
	# is not claimed incorrectly by other tools because of old signatures
 | 
			
		||||
	# from previous use. The number of signatures that LVM can detect
 | 
			
		||||
	# depends on the detection code that is selected (see
 | 
			
		||||
	# use_blkid_wiping). Wiping each detected signature must be confirmed.
 | 
			
		||||
	# use_blkid_wiping.) Wiping each detected signature must be confirmed.
 | 
			
		||||
	# When this setting is disabled, signatures on new LVs are not detected
 | 
			
		||||
	# or erased unless the --wipesignatures option is used directly.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
@@ -529,7 +491,7 @@ allocation {
 | 
			
		||||
	# Accepted values:
 | 
			
		||||
	#   0  Automatically detected best available format
 | 
			
		||||
	#   1  Original format
 | 
			
		||||
	#   2  Improved second-generation format
 | 
			
		||||
	#   2  Improved 2nd. generation format
 | 
			
		||||
	#
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# cache_metadata_format = 0
 | 
			
		||||
@@ -575,30 +537,19 @@ allocation {
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/cache_pool_max_chunks.
 | 
			
		||||
	# The maximum number of chunks in a cache pool.
 | 
			
		||||
	# For cache target v1.9 the recommended maximum is 1000000 chunks.
 | 
			
		||||
	# For cache target v1.9 the recommended maximumm is 1000000 chunks.
 | 
			
		||||
	# Using cache pool with more chunks may degrade cache performance.
 | 
			
		||||
	# This configuration option does not have a default value defined.
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/pvmove_max_segment_size_mb.
 | 
			
		||||
	# Maximum size in MiB of segments to mirror at once during pvmove.
 | 
			
		||||
	# When pvmove needs to move large segments, it will split them into
 | 
			
		||||
	# smaller chunks of this size, mirror each chunk, and update metadata
 | 
			
		||||
	# between chunks. This prevents mirroring excessively large amounts
 | 
			
		||||
	# of data at once. A value of 0 (default) means no limit - the entire
 | 
			
		||||
	# segment will be mirrored at once. Setting this to e.g. 10240 will
 | 
			
		||||
	# limit each mirroring operation to 10GiB chunks.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# pvmove_max_segment_size_mb = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
 | 
			
		||||
	# Thin pool metadata and data will always use different PVs.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# thin_pool_metadata_require_separate_pvs = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/thin_pool_crop_metadata.
 | 
			
		||||
	# Older versions of lvm2 cropped pool's metadata size to 15.81 GiB.
 | 
			
		||||
	# This is slightly less than the actual maximum 15.88 GiB.
 | 
			
		||||
	# For compatibility with older versions and to use the cropped size, set to 1.
 | 
			
		||||
	# Older version of lvm2 cropped pool's metadata size to 15.81 GiB.
 | 
			
		||||
	# This is slightly less then the actual maximum 15.88 GiB.
 | 
			
		||||
	# For compatibility with older version and use of cropped size set to 1.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# thin_pool_crop_metadata = 0
 | 
			
		||||
 | 
			
		||||
@@ -670,9 +621,17 @@ allocation {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_use_deduplication = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_use_metadata_hints.
 | 
			
		||||
	# Enables or disables whether VDO volume should tag its latency-critical
 | 
			
		||||
	# writes with the REQ_SYNC flag. Some device mapper targets such as dm-raid5
 | 
			
		||||
	# process writes with this flag at a higher priority.
 | 
			
		||||
	# Default is enabled.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_use_metadata_hints = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_minimum_io_size.
 | 
			
		||||
	# The minimum IO size for VDO volume to accept, in bytes.
 | 
			
		||||
	# Valid values are 512 or 4096. The recommended value is 4096.
 | 
			
		||||
	# Valid values are 512 or 4096. The recommended and default value is 4096.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_minimum_io_size = 4096
 | 
			
		||||
 | 
			
		||||
@@ -692,6 +651,11 @@ allocation {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_block_map_period = 16380
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_check_point_frequency.
 | 
			
		||||
	# The default check point frequency for VDO volume.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_check_point_frequency = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_use_sparse_index.
 | 
			
		||||
	# Enables sparse indexing for VDO volume.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
@@ -720,7 +684,7 @@ allocation {
 | 
			
		||||
	# Configuration option allocation/vdo_bio_threads.
 | 
			
		||||
	# Specifies the number of threads to use for submitting I/O
 | 
			
		||||
	# operations to the storage device of VDO volume.
 | 
			
		||||
	# The value must be in range [1..100].
 | 
			
		||||
	# The value must be in range [1..100]
 | 
			
		||||
	# Each additional thread after the first will use an additional 18MiB of RAM,
 | 
			
		||||
	# plus 1.12 MiB of RAM per megabyte of configured read cache size.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
@@ -734,7 +698,7 @@ allocation {
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_cpu_threads.
 | 
			
		||||
	# Specifies the number of threads to use for CPU-intensive work such as
 | 
			
		||||
	# hashing or compression for VDO volume. The value must be in range [1..100].
 | 
			
		||||
	# hashing or compression for VDO volume. The value must be in range [1..100]
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_cpu_threads = 2
 | 
			
		||||
 | 
			
		||||
@@ -752,7 +716,7 @@ allocation {
 | 
			
		||||
	# processing based on the hash value computed from the block data.
 | 
			
		||||
	# A logical thread count of 9 or more will require explicitly specifying
 | 
			
		||||
	# a sufficiently large block map cache size, as well.
 | 
			
		||||
	# The value must be in range [0..60].
 | 
			
		||||
	# The value must be in range [0..100].
 | 
			
		||||
	# vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
 | 
			
		||||
	# either all zero or all non-zero.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
@@ -768,6 +732,19 @@ allocation {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_physical_threads = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_write_policy.
 | 
			
		||||
	# Specifies the write policy:
 | 
			
		||||
	# auto  - VDO will check the storage device and determine whether it supports flushes.
 | 
			
		||||
	#         If it does, VDO will run in async mode, otherwise it will run in sync mode.
 | 
			
		||||
	# sync  - Writes are acknowledged only after data is stably written.
 | 
			
		||||
	#         This policy is not supported if the underlying storage is not also synchronous.
 | 
			
		||||
	# async - Writes are acknowledged after data has been cached for writing to stable storage.
 | 
			
		||||
	#         Data which has not been flushed is not guaranteed to persist in this mode.
 | 
			
		||||
	# async-unsafe - Writes are handled like 'async' but there is no guarantee of the atomicity async provides.
 | 
			
		||||
	#         This mode should only be used for better performance when atomicity is not required.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_write_policy = "auto"
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_max_discard.
 | 
			
		||||
	# Specified the maximum size of discard bio accepted, in 4096 byte blocks.
 | 
			
		||||
	# I/O requests to a VDO volume are normally split into 4096-byte blocks,
 | 
			
		||||
@@ -781,7 +758,7 @@ allocation {
 | 
			
		||||
	# vdo_max_discard = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_pool_header_size.
 | 
			
		||||
	# Specified the empty header size in KiB at the front and end of vdo pool device.
 | 
			
		||||
	# Specified the emptry header size in KiB at the front and end of vdo pool device.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_pool_header_size = 512
 | 
			
		||||
}
 | 
			
		||||
@@ -805,9 +782,6 @@ log {
 | 
			
		||||
	# to define fields to display and sort fields for the log report.
 | 
			
		||||
	# You can also use log/command_log_selection to define selection
 | 
			
		||||
	# criteria used each time the log is reported.
 | 
			
		||||
	# Note that if report/output_format (or --reportformat command line
 | 
			
		||||
	# option) is set to json or json_std, then log/report_command_log=1
 | 
			
		||||
	# is default.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# report_command_log = 0
 | 
			
		||||
 | 
			
		||||
@@ -837,9 +811,8 @@ log {
 | 
			
		||||
	# define selection criteria for log report on command line directly
 | 
			
		||||
	# using <lvm command> --configreport log -S <selection criteria>
 | 
			
		||||
	# which has precedence over log/command_log_selection setting.
 | 
			
		||||
	# To make all the command log lines visible, use "all" value
 | 
			
		||||
	# for the command log selection. For more information about selection
 | 
			
		||||
	# criteria in general, see lvmreport(7) man page.
 | 
			
		||||
	# For more information about selection criteria in general, see
 | 
			
		||||
	# lvm(8) man page.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# command_log_selection = "!(log_type=status && message=success)"
 | 
			
		||||
 | 
			
		||||
@@ -910,7 +883,7 @@ log {
 | 
			
		||||
 | 
			
		||||
	# Configuration option log/activation.
 | 
			
		||||
	# Log messages during activation.
 | 
			
		||||
	# Do not use this in low memory situations (can deadlock).
 | 
			
		||||
	# Don't use this in low memory situations (can deadlock).
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# activation = 0
 | 
			
		||||
 | 
			
		||||
@@ -964,7 +937,7 @@ backup {
 | 
			
		||||
	# archive = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option backup/archive_dir.
 | 
			
		||||
	# Location of the metadata archive files.
 | 
			
		||||
	# Location of the metdata archive files.
 | 
			
		||||
	# Remember to back up this directory regularly!
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# archive_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@"
 | 
			
		||||
@@ -1040,7 +1013,7 @@ global {
 | 
			
		||||
	# Location of proc filesystem.
 | 
			
		||||
	# This configuration option is advanced.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# proc = "@DEFAULT_PROC_DIR@"
 | 
			
		||||
	# proc = "/proc"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/etc.
 | 
			
		||||
	# Location of /etc system configuration directory.
 | 
			
		||||
@@ -1085,7 +1058,7 @@ global {
 | 
			
		||||
	# Additionally, read-only commands that encounter metadata in need of
 | 
			
		||||
	# repair will still be allowed to proceed exactly as if the repair had
 | 
			
		||||
	# been performed (except for the unchanged vg_seqno). Inappropriate
 | 
			
		||||
	# use could corrupt your system, so seek advice first!
 | 
			
		||||
	# use could mess up your system, so seek advice first!
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# metadata_read_only = 0
 | 
			
		||||
 | 
			
		||||
@@ -1119,7 +1092,7 @@ global {
 | 
			
		||||
	# Configuration option global/support_mirrored_mirror_log.
 | 
			
		||||
	# Enable mirrored 'mirror' log type for testing.
 | 
			
		||||
	#
 | 
			
		||||
	# This type is deprecated for creation or conversion but can
 | 
			
		||||
	# This type is deprecated to create or convert to but can
 | 
			
		||||
	# be enabled to test that activation of existing mirrored
 | 
			
		||||
	# logs and conversion to disk/core works.
 | 
			
		||||
	#
 | 
			
		||||
@@ -1178,13 +1151,18 @@ global {
 | 
			
		||||
	# lvdisplay_shows_full_device_path = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/event_activation.
 | 
			
		||||
	# Disable event based autoactivation commands.
 | 
			
		||||
	# WARNING: setting this to zero may cause machine startup to fail.
 | 
			
		||||
	# Previously, setting this to zero would enable static autoactivation
 | 
			
		||||
	# services (via the lvm2-activation-generator), but the autoactivation
 | 
			
		||||
	# services and generator have been removed.
 | 
			
		||||
	# Activate LVs based on system-generated device events.
 | 
			
		||||
	# When a PV appears on the system, a system-generated uevent triggers
 | 
			
		||||
	# the lvm2-pvscan service which runs the pvscan --cache -aay command.
 | 
			
		||||
	# If the new PV completes a VG, pvscan autoactivates LVs in the VG.
 | 
			
		||||
	# When event_activation is disabled, the lvm2-activation services are
 | 
			
		||||
	# generated and run at fixed points during system startup.  These
 | 
			
		||||
	# services run vgchange -aay to autoactivate LVs in VGs that happen
 | 
			
		||||
	# to be present at that point in time.
 | 
			
		||||
	# See the --setautoactivation option or the auto_activation_volume_list
 | 
			
		||||
	# setting to configure autoactivation for specific VGs or LVs.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# event_activation = @DEFAULT_EVENT_ACTIVATION@
 | 
			
		||||
	# event_activation = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/use_aio.
 | 
			
		||||
	# Use async I/O when reading and writing devices.
 | 
			
		||||
@@ -1216,20 +1194,10 @@ global {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# sanlock_lv_extend = 256
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/sanlock_align_size.
 | 
			
		||||
	# The sanlock lease size in MiB to use on disks with a 4K sector size.
 | 
			
		||||
	# Possible values are 1,2,4,8.  The default is 8, which supports up to
 | 
			
		||||
	# 2000 hosts (and max host_id 2000).  Smaller values support smaller
 | 
			
		||||
	# numbers of max hosts (and max host_ids): 250, 500, 1000, 2000 for
 | 
			
		||||
	# lease sizes 1,2,4,8.  Disks with 512 byte sectors always use 1MiB
 | 
			
		||||
	# leases and support 2000 hosts, and are not affected by this setting.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# sanlock_align_size = 8
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/lvmlockctl_kill_command.
 | 
			
		||||
	# The command that lvmlockctl --kill should use to force LVs offline.
 | 
			
		||||
	# The lvmlockctl --kill command is run when a shared VG has lost
 | 
			
		||||
	# access to locks (e.g. when sanlock has lost access to storage).
 | 
			
		||||
	# access to locks (e.g. when sanlock has lost access to storage.)
 | 
			
		||||
	# An empty string means that there will be no automatic attempt by
 | 
			
		||||
	# lvmlockctl --kill to forcibly shut down LVs in the VG, and the user
 | 
			
		||||
	# can manually intervene as described in lvmlockd(8).
 | 
			
		||||
@@ -1239,7 +1207,7 @@ global {
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/thin_check_executable.
 | 
			
		||||
	# The full path to the thin_check command.
 | 
			
		||||
	# LVM uses this command to check that a thin pool metadata device is in a
 | 
			
		||||
	# LVM uses this command to check that a thin metadata device is in a
 | 
			
		||||
	# usable state. When a thin pool is activated and after it is
 | 
			
		||||
	# deactivated, this command is run. Activation will only proceed if
 | 
			
		||||
	# the command has an exit status of 0. Set to "" to skip this check.
 | 
			
		||||
@@ -1263,14 +1231,6 @@ global {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# thin_repair_executable = "@THIN_REPAIR_CMD@"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/thin_restore_executable.
 | 
			
		||||
	# The full path to the thin_restore command.
 | 
			
		||||
	# LVM uses this command to restore generated data for a thin pool metadata device.
 | 
			
		||||
	# Also see thin_restore_options.
 | 
			
		||||
	# (See package device-mapper-persistent-data or thin-provisioning-tools)
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# thin_restore_executable = "@THIN_RESTORE_CMD@"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/thin_check_options.
 | 
			
		||||
	# List of options passed to the thin_check command.
 | 
			
		||||
	# With thin_check version 2.1 or newer you can add the option
 | 
			
		||||
@@ -1285,11 +1245,6 @@ global {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# thin_repair_options = [ "" ]
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/thin_restore_options.
 | 
			
		||||
	# List of options passed to the thin_restore command.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# thin_restore_options = [ "" ]
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/thin_disabled_features.
 | 
			
		||||
	# Features to not use in the thin driver.
 | 
			
		||||
	# This can be helpful for testing, or to avoid using a feature that is
 | 
			
		||||
@@ -1338,14 +1293,6 @@ global {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# cache_repair_executable = "@CACHE_REPAIR_CMD@"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/cache_restore_executable.
 | 
			
		||||
	# The full path to the cache_restore command.
 | 
			
		||||
	# LVM uses this command to restore generated data for a cache metadata device.
 | 
			
		||||
	# Also see cache_restore_options.
 | 
			
		||||
	# (See package device-mapper-persistent-data or thin-provisioning-tools)
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# cache_restore_executable = "@CACHE_RESTORE_CMD@"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/cache_check_options.
 | 
			
		||||
	# List of options passed to the cache_check command.
 | 
			
		||||
	# With cache_check version 5.0 or newer you should include the option
 | 
			
		||||
@@ -1358,11 +1305,6 @@ global {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# cache_repair_options = [ "" ]
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/cache_restore_options.
 | 
			
		||||
	# List of options passed to the cache_restore command.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# cache_restore_options = [ "" ]
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/vdo_format_executable.
 | 
			
		||||
	# The full path to the vdoformat command.
 | 
			
		||||
	# LVM uses this command to initial data volume for VDO type logical volume
 | 
			
		||||
@@ -1377,10 +1319,10 @@ global {
 | 
			
		||||
	# Configuration option global/vdo_disabled_features.
 | 
			
		||||
	# Features to not use in the vdo driver.
 | 
			
		||||
	# This can be helpful for testing, or to avoid using a feature that is
 | 
			
		||||
	# causing problems. Features include: online_rename, version4
 | 
			
		||||
	# causing problems. Features include: online_rename
 | 
			
		||||
	#
 | 
			
		||||
	# Example
 | 
			
		||||
	# vdo_disabled_features = [ "online_rename", "version4" ]
 | 
			
		||||
	# vdo_disabled_features = [ "online_rename" ]
 | 
			
		||||
	#
 | 
			
		||||
	# This configuration option does not have a default value defined.
 | 
			
		||||
 | 
			
		||||
@@ -1390,16 +1332,10 @@ global {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# fsadm_executable = "@FSADM_PATH@"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/lvresize_fs_helper_executable.
 | 
			
		||||
	# The full path to the lvresize_fs_helper command.
 | 
			
		||||
	# LVM uses this command to help with filesystem operations during lvresize.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# lvresize_fs_helper_executable = "@LVRESIZE_FS_HELPER_PATH@"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/system_id_source.
 | 
			
		||||
	# The method LVM uses to set the local system ID.
 | 
			
		||||
	# Volume Groups can also be given a system ID (by vgcreate, vgchange,
 | 
			
		||||
	# or vgimport). A VG on shared storage devices is accessible only to
 | 
			
		||||
	# or vgimport.) A VG on shared storage devices is accessible only to
 | 
			
		||||
	# the host with a matching system ID. See 'man lvmsystemid' for
 | 
			
		||||
	# information on limitations and correct usage.
 | 
			
		||||
	#
 | 
			
		||||
@@ -1416,9 +1352,8 @@ global {
 | 
			
		||||
	#     Use an LVM-specific derivation of the local machine-id as the
 | 
			
		||||
	#     system ID. See 'man machine-id'.
 | 
			
		||||
	#   machineid
 | 
			
		||||
	#     Use the contents of the machine-id file to set the system ID.
 | 
			
		||||
	#     (appmachineid is recommended to avoid exposing the confidential
 | 
			
		||||
	#     machine-id.)
 | 
			
		||||
	#     Use the contents of the machine-id file to set the system ID
 | 
			
		||||
	#     (appmachineid is recommended.)
 | 
			
		||||
	#   file
 | 
			
		||||
	#     Use the contents of another file (system_id_file) to set the
 | 
			
		||||
	#     system ID.
 | 
			
		||||
@@ -1534,15 +1469,13 @@ activation {
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/reserved_stack.
 | 
			
		||||
	# Stack size in KiB to reserve for use while devices are suspended.
 | 
			
		||||
	# Insufficient reserve risks I/O deadlock during device suspension.
 | 
			
		||||
	# Value 0 disables memory locking.
 | 
			
		||||
	# Insufficent reserve risks I/O deadlock during device suspension.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# reserved_stack = 64
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/reserved_memory.
 | 
			
		||||
	# Memory size in KiB to reserve for use while devices are suspended.
 | 
			
		||||
	# Insufficient reserve risks I/O deadlock during device suspension.
 | 
			
		||||
	# Value 0 disables memory locking.
 | 
			
		||||
	# Insufficent reserve risks I/O deadlock during device suspension.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# reserved_memory = 8192
 | 
			
		||||
 | 
			
		||||
@@ -1677,7 +1610,7 @@ activation {
 | 
			
		||||
	# This includes LVs that have the following segment types:
 | 
			
		||||
	# raid1, raid4, raid5*, and raid6*.
 | 
			
		||||
	# If a device in the LV fails, the policy determines the steps
 | 
			
		||||
	# performed by dmeventd automatically, and the steps performed by the
 | 
			
		||||
	# performed by dmeventd automatically, and the steps perfomed by the
 | 
			
		||||
	# manual command lvconvert --repair --use-policies.
 | 
			
		||||
	# Automatic handling requires dmeventd to be monitoring the LV.
 | 
			
		||||
	#
 | 
			
		||||
@@ -1701,7 +1634,7 @@ activation {
 | 
			
		||||
	# (copies) and a mirror log. A disk log ensures that a mirror LV does
 | 
			
		||||
	# not need to be re-synced (all copies made the same) every time a
 | 
			
		||||
	# machine reboots or crashes. If a device in the LV fails, this policy
 | 
			
		||||
	# determines the steps performed by dmeventd automatically, and the steps
 | 
			
		||||
	# determines the steps perfomed by dmeventd automatically, and the steps
 | 
			
		||||
	# performed by the manual command lvconvert --repair --use-policies.
 | 
			
		||||
	# Automatic handling requires dmeventd to be monitoring the LV.
 | 
			
		||||
	#
 | 
			
		||||
@@ -1743,7 +1676,7 @@ activation {
 | 
			
		||||
	# Configuration option activation/snapshot_autoextend_threshold.
 | 
			
		||||
	# Auto-extend a snapshot when its usage exceeds this percent.
 | 
			
		||||
	# Setting this to 100 disables automatic extension.
 | 
			
		||||
	# The minimum value is 50 (a smaller value is treated as 50).
 | 
			
		||||
	# The minimum value is 50 (a smaller value is treated as 50.)
 | 
			
		||||
	# Also see snapshot_autoextend_percent.
 | 
			
		||||
	# Automatic extension requires dmeventd to be monitoring the LV.
 | 
			
		||||
	#
 | 
			
		||||
@@ -1773,7 +1706,7 @@ activation {
 | 
			
		||||
	# Configuration option activation/thin_pool_autoextend_threshold.
 | 
			
		||||
	# Auto-extend a thin pool when its usage exceeds this percent.
 | 
			
		||||
	# Setting this to 100 disables automatic extension.
 | 
			
		||||
	# The minimum value is 50 (a smaller value is treated as 50).
 | 
			
		||||
	# The minimum value is 50 (a smaller value is treated as 50.)
 | 
			
		||||
	# Also see thin_pool_autoextend_percent.
 | 
			
		||||
	# Automatic extension requires dmeventd to be monitoring the LV.
 | 
			
		||||
	#
 | 
			
		||||
@@ -1803,7 +1736,7 @@ activation {
 | 
			
		||||
	# Configuration option activation/vdo_pool_autoextend_threshold.
 | 
			
		||||
	# Auto-extend a VDO pool when its usage exceeds this percent.
 | 
			
		||||
	# Setting this to 100 disables automatic extension.
 | 
			
		||||
	# The minimum value is 50 (a smaller value is treated as 50).
 | 
			
		||||
	# The minimum value is 50 (a smaller value is treated as 50.)
 | 
			
		||||
	# Also see vdo_pool_autoextend_percent.
 | 
			
		||||
	# Automatic extension requires dmeventd to be monitoring the LV.
 | 
			
		||||
	#
 | 
			
		||||
@@ -1863,7 +1796,7 @@ activation {
 | 
			
		||||
	# Configuration option activation/polling_interval.
 | 
			
		||||
	# Check pvmove or lvconvert progress at this interval (seconds).
 | 
			
		||||
	# When pvmove or lvconvert must wait for the kernel to finish
 | 
			
		||||
	# synchronizing or merging data, they check and report progress at
 | 
			
		||||
	# synchronising or merging data, they check and report progress at
 | 
			
		||||
	# intervals of this number of seconds. If this is set to 0 and there
 | 
			
		||||
	# is only one thing to wait for, there are no progress reports, but
 | 
			
		||||
	# the process is awoken immediately once the operation is complete.
 | 
			
		||||
@@ -1891,7 +1824,7 @@ activation {
 | 
			
		||||
	#     uses are present. Other PVs in the Volume Group may be missing.
 | 
			
		||||
	#   degraded
 | 
			
		||||
	#     Like complete, but additionally RAID LVs of segment type raid1,
 | 
			
		||||
	#     raid4, raid5, raid6 and raid10 will be activated if there is no
 | 
			
		||||
	#     raid4, raid5, radid6 and raid10 will be activated if there is no
 | 
			
		||||
	#     data loss, i.e. they have sufficient redundancy to present the
 | 
			
		||||
	#     entire addressable range of the Logical Volume.
 | 
			
		||||
	#   partial
 | 
			
		||||
@@ -2008,14 +1941,15 @@ activation {
 | 
			
		||||
 | 
			
		||||
# Configuration section report.
 | 
			
		||||
# LVM report command output formatting.
 | 
			
		||||
report {
 | 
			
		||||
# This configuration section has an automatic default value.
 | 
			
		||||
# report {
 | 
			
		||||
 | 
			
		||||
	# Configuration option report/output_format.
 | 
			
		||||
	# Format of LVM command's report output.
 | 
			
		||||
	# If there is more than one report per command, then the format
 | 
			
		||||
	# is applied for all reports. You can also change output format
 | 
			
		||||
	# directly on command line using --reportformat option which
 | 
			
		||||
	# has precedence over report/output_format setting.
 | 
			
		||||
	# has precedence over log/output_format setting.
 | 
			
		||||
	# Accepted values:
 | 
			
		||||
	#   basic
 | 
			
		||||
	#     Original format with columns and rows. If there is more than
 | 
			
		||||
@@ -2023,19 +1957,12 @@ report {
 | 
			
		||||
	#     name for identification.
 | 
			
		||||
	#   json
 | 
			
		||||
	#     JSON format.
 | 
			
		||||
	#   json_std
 | 
			
		||||
	#     JSON format that is more compliant with JSON standard.
 | 
			
		||||
	#     Compared to original "json" format:
 | 
			
		||||
	#       - it does not use double quotes around numeric values,
 | 
			
		||||
	#       - it uses 'null' for undefined numeric values,
 | 
			
		||||
	#       - it prints string list as proper JSON array of strings instead of a single string.
 | 
			
		||||
	# Note that if json or json_std output format is used, then log/command_log_report=1 is default.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# output_format = "basic"
 | 
			
		||||
 | 
			
		||||
	# Configuration option report/compact_output.
 | 
			
		||||
	# Do not print empty values for all report fields.
 | 
			
		||||
	# If enabled, all fields that do not have a value set for any of the
 | 
			
		||||
	# If enabled, all fields that don't have a value set for any of the
 | 
			
		||||
	# rows reported are skipped and not printed. Compact output is
 | 
			
		||||
	# applicable only if report/buffered is enabled. If you need to
 | 
			
		||||
	# compact only specified fields, use compact_output=0 and define
 | 
			
		||||
@@ -2045,7 +1972,7 @@ report {
 | 
			
		||||
 | 
			
		||||
	# Configuration option report/compact_output_cols.
 | 
			
		||||
	# Do not print empty values for specified report fields.
 | 
			
		||||
	# If defined, specified fields that do not have a value set for any
 | 
			
		||||
	# If defined, specified fields that don't have a value set for any
 | 
			
		||||
	# of the rows reported are skipped and not printed. Compact output
 | 
			
		||||
	# is applicable only if report/buffered is enabled. If you need to
 | 
			
		||||
	# compact all fields, use compact_output=1 instead in which case
 | 
			
		||||
@@ -2069,11 +1996,7 @@ report {
 | 
			
		||||
	# buffered = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option report/headings.
 | 
			
		||||
	# Format of LVM command's report output headings.
 | 
			
		||||
	# Accepted values:
 | 
			
		||||
	#   0 no headings,
 | 
			
		||||
	#   1 headings with column abbreviations,
 | 
			
		||||
	#   2 headings with full column names.
 | 
			
		||||
	# Show headings for columns on report.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# headings = 1
 | 
			
		||||
 | 
			
		||||
@@ -2152,7 +2075,7 @@ report {
 | 
			
		||||
	#   %F
 | 
			
		||||
	#     Equivalent to %Y-%m-%d (the ISO 8601 date format).
 | 
			
		||||
	#   %G
 | 
			
		||||
	#     The ISO 8601 week-based year with century as a decimal number.
 | 
			
		||||
	#     The ISO 8601 week-based year with century as adecimal number.
 | 
			
		||||
	#     The 4-digit year corresponding to the ISO week number (see %V).
 | 
			
		||||
	#     This has the same format and value as %Y, except that if the
 | 
			
		||||
	#     ISO week number belongs to the previous or next year, that year
 | 
			
		||||
@@ -2423,7 +2346,7 @@ report {
 | 
			
		||||
	# This is displayed when the device for a PV is not known.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# two_word_unknown_device = 0
 | 
			
		||||
}
 | 
			
		||||
# }
 | 
			
		||||
 | 
			
		||||
# Configuration section dmeventd.
 | 
			
		||||
# Settings for the LVM event daemon.
 | 
			
		||||
 
 | 
			
		||||
@@ -38,14 +38,6 @@ local {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# 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.
 | 
			
		||||
	# 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
 | 
			
		||||
@@ -57,12 +49,9 @@ local {
 | 
			
		||||
	# This configuration option does not have a default value defined.
 | 
			
		||||
 | 
			
		||||
	# Configuration option local/host_id.
 | 
			
		||||
	# The sanlock host_id used by lvmlockd. This must be unique among all the hosts
 | 
			
		||||
	# using shared VGs with sanlock. Accepted values are 1-2000, except when sanlock_align_size
 | 
			
		||||
	# is configured to 1, 2 or 4, which correspond to max host_id values of 250, 500, or 1000.
 | 
			
		||||
	# 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.)
 | 
			
		||||
	# The lvmlockd sanlock host_id.
 | 
			
		||||
	# This must be unique among all hosts, and must be between 1 and 2000.
 | 
			
		||||
	# Applicable only if LVM is compiled with lockd support
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# host_id = 0
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,11 @@
 | 
			
		||||
allocation {
 | 
			
		||||
	vdo_use_compression=1
 | 
			
		||||
	vdo_use_deduplication=1
 | 
			
		||||
	vdo_use_metadata_hints=1
 | 
			
		||||
	vdo_minimum_io_size=4096
 | 
			
		||||
	vdo_block_map_cache_size_mb=128
 | 
			
		||||
	vdo_block_map_period=16380
 | 
			
		||||
	vdo_check_point_frequency=0
 | 
			
		||||
	vdo_use_sparse_index=0
 | 
			
		||||
	vdo_index_memory_size_mb=256
 | 
			
		||||
	vdo_slab_size_mb=2048
 | 
			
		||||
@@ -17,5 +19,6 @@ allocation {
 | 
			
		||||
	vdo_hash_zone_threads=1
 | 
			
		||||
	vdo_logical_threads=1
 | 
			
		||||
	vdo_physical_threads=1
 | 
			
		||||
	vdo_write_policy="auto"
 | 
			
		||||
	vdo_max_discard=1
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1605
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										1605
									
								
								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.
 | 
			
		||||
 *
 | 
			
		||||
@@ -21,295 +21,128 @@
 | 
			
		||||
 * compile (using outdir 'cov'):
 | 
			
		||||
 * 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
 | 
			
		||||
 *
 | 
			
		||||
 * generate html output (to 'html' from 'cov'):
 | 
			
		||||
 * cov-format-errors --dir cov  --html-output html
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Define NULL for Coverity modeling */
 | 
			
		||||
#define NULL ((void *)0)
 | 
			
		||||
 | 
			
		||||
/* Forward declarations */
 | 
			
		||||
struct lv_segment;
 | 
			
		||||
struct logical_volume;
 | 
			
		||||
struct segment_type;
 | 
			
		||||
struct cmd_context;
 | 
			
		||||
struct profile;
 | 
			
		||||
struct dm_pool;
 | 
			
		||||
struct dm_list;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * These functions never return NULL for valid LVs with segments
 | 
			
		||||
 */
 | 
			
		||||
struct lv_segment *first_seg(const struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
 | 
			
		||||
	/* 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 */
 | 
			
		||||
	return ((struct lv_segment **)lv)[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct lv_segment *last_seg(const struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
 | 
			
		||||
	if (lv) {
 | 
			
		||||
		__coverity_read_pointee__(lv);
 | 
			
		||||
		return seg;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	__coverity_panic__();
 | 
			
		||||
	return ((struct lv_segment **)lv)[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
/*
 | 
			
		||||
struct logical_volume *origin_from_cow(const struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	if (lv)
 | 
			
		||||
		return lv;
 | 
			
		||||
 | 
			
		||||
	__coverity_panic__();
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/* simple_memccpy() from glibc */
 | 
			
		||||
void *memccpy(void *dest, const void *src, int c, size_t n)
 | 
			
		||||
{
 | 
			
		||||
	const char *s = src;
 | 
			
		||||
	char *d = dest;
 | 
			
		||||
 | 
			
		||||
	while (n-- > 0)
 | 
			
		||||
		if ((*d++ = *s++) == (char) c)
 | 
			
		||||
			return d;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 2 lines bellow needs to be placed in coverity/config/user_nodefs.h
 | 
			
		||||
 * 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)
 | 
			
		||||
{
 | 
			
		||||
	char *str;
 | 
			
		||||
 | 
			
		||||
	__coverity_read_pointee__(cmd);
 | 
			
		||||
 | 
			
		||||
	if (str)
 | 
			
		||||
		return str;
 | 
			
		||||
 | 
			
		||||
	__coverity_panic__();
 | 
			
		||||
        return "text";
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
struct segment_type *init_unknown_segtype(struct cmd_context *cmd, const char *name)
 | 
			
		||||
/*
 | 
			
		||||
 * 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)
 | 
			
		||||
{
 | 
			
		||||
	struct segment_type *seg_type;
 | 
			
		||||
	const struct dm_config_node *cn;
 | 
			
		||||
 | 
			
		||||
	__coverity_read_pointee__(cmd);
 | 
			
		||||
	__coverity_read_pointee__(name);
 | 
			
		||||
 | 
			
		||||
	if (seg_type)
 | 
			
		||||
		return seg_type;
 | 
			
		||||
 | 
			
		||||
	__coverity_panic__();
 | 
			
		||||
	return cn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* simple_memccpy() from glibc */
 | 
			
		||||
void *memccpy(void *dest, const void *src, int c, unsigned long n)
 | 
			
		||||
const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, int id, struct profile *profile)
 | 
			
		||||
{
 | 
			
		||||
	int success;
 | 
			
		||||
	const struct dm_config_node *cn;
 | 
			
		||||
 | 
			
		||||
	__coverity_negative_sink__(n);
 | 
			
		||||
	__coverity_negative_sink__(c);
 | 
			
		||||
	__coverity_tainted_data_transitive__(dest, src);
 | 
			
		||||
	__coverity_write_buffer_bytes__(dest, n);
 | 
			
		||||
 | 
			
		||||
	if (!success)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return dest;
 | 
			
		||||
	return cn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* dm_pool_alloc - can return NULL on allocation failure */
 | 
			
		||||
void *dm_pool_alloc(struct dm_pool *p, unsigned long s)
 | 
			
		||||
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile)
 | 
			
		||||
{
 | 
			
		||||
	void *ptr;
 | 
			
		||||
	int success;
 | 
			
		||||
	int b;
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
	return b;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 
 | 
			
		||||
@@ -32,12 +32,12 @@ CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
 | 
			
		||||
 | 
			
		||||
cmirrord: $(OBJECTS)
 | 
			
		||||
	$(SHOW) "    [CC] $@"
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
 | 
			
		||||
		$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS)
 | 
			
		||||
 | 
			
		||||
install_cluster: $(TARGETS)
 | 
			
		||||
	$(SHOW) "    [INSTALL] $<"
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(usrsbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install: install_cluster
 | 
			
		||||
 
 | 
			
		||||
@@ -43,14 +43,14 @@ static void usage (FILE *dest)
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	int foreground_mode = 0;
 | 
			
		||||
	static const struct option _long_options[] = {
 | 
			
		||||
	struct option longopts[] = {
 | 
			
		||||
		{ "foreground", no_argument, NULL, 'f' },
 | 
			
		||||
		{ "help"      , no_argument, NULL, 'h' },
 | 
			
		||||
		{ 0, 0, 0, 0 }
 | 
			
		||||
	};
 | 
			
		||||
	int opt;
 | 
			
		||||
 | 
			
		||||
	while ((opt = getopt_long (argc, argv, "fh", _long_options, NULL)) != -1) {
 | 
			
		||||
	while ((opt = getopt_long (argc, argv, "fh", longopts, NULL)) != -1) {
 | 
			
		||||
		switch (opt) {
 | 
			
		||||
		case 'f':
 | 
			
		||||
			foreground_mode = 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ static SaVersionT version = { 'B', 1, 1 };
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEBUGGING_HISTORY 100
 | 
			
		||||
#define DEBUGGING_BUFLEN 270
 | 
			
		||||
#define DEBUGGING_BUFLEN 128
 | 
			
		||||
#define LOG_SPRINT(cc, f, arg...) do {				\
 | 
			
		||||
		cc->idx++;					\
 | 
			
		||||
		cc->idx = cc->idx % DEBUGGING_HISTORY;		\
 | 
			
		||||
@@ -197,7 +197,7 @@ int cluster_send(struct clog_request *rq)
 | 
			
		||||
	iov.iov_base = rq;
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
	r = clog_request_to_network(rq);
 | 
			
		||||
@@ -279,7 +279,7 @@ static int handle_cluster_request(struct clog_cpg *entry __attribute__((unused))
 | 
			
		||||
	 * With resumes, we only handle our own.
 | 
			
		||||
	 * Resume is a special case that requires
 | 
			
		||||
	 * 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
 | 
			
		||||
	 */
 | 
			
		||||
	if (tmp->u_rq.request_type == DM_ULOG_RESUME) {
 | 
			
		||||
@@ -1091,7 +1091,6 @@ static void cpg_message_callback(cpg_handle_t handle, const struct cpg_name *gna
 | 
			
		||||
	    (rq->u_rq.request_type != DM_ULOG_RESUME) &&
 | 
			
		||||
	    (rq->u_rq.request_type != DM_ULOG_CLEAR_REGION) &&
 | 
			
		||||
	    (rq->u_rq.request_type != DM_ULOG_CHECKPOINT_READY)) {
 | 
			
		||||
		/* coverity[suspicious_sizeof] allocation is using varargs data @end */
 | 
			
		||||
		tmp_rq = malloc(DM_ULOG_REQUEST_SIZE);
 | 
			
		||||
		if (!tmp_rq) {
 | 
			
		||||
			/*
 | 
			
		||||
@@ -1341,7 +1340,6 @@ static void cpg_join_callback(struct clog_cpg *match,
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* coverity[suspicious_sizeof] allocation is using varargs data @end */
 | 
			
		||||
	rq = malloc(DM_ULOG_REQUEST_SIZE);
 | 
			
		||||
	if (!rq) {
 | 
			
		||||
		LOG_ERROR("cpg_config_callback: "
 | 
			
		||||
@@ -1634,7 +1632,7 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
 | 
			
		||||
 | 
			
		||||
	size = ((strlen(uuid) + 1) > CPG_MAX_NAME_LENGTH) ?
 | 
			
		||||
		CPG_MAX_NAME_LENGTH : (strlen(uuid) + 1);
 | 
			
		||||
	dm_strncpy(new->name.value, uuid, size);
 | 
			
		||||
	(void) dm_strncpy(new->name.value, uuid, size);
 | 
			
		||||
	new->name.length = (uint32_t)size;
 | 
			
		||||
	new->luid = luid;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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_SYNC_COUNT:
 | 
			
		||||
			pu64 = (uint64_t *)rq->u_rq.data;
 | 
			
		||||
			*pu64 = htole64(*pu64);
 | 
			
		||||
			*pu64 = xlate64(*pu64);
 | 
			
		||||
			break;
 | 
			
		||||
		case DM_ULOG_IS_CLEAN:
 | 
			
		||||
		case DM_ULOG_IN_SYNC:
 | 
			
		||||
			pi64 = (int64_t *)rq->u_rq.data;
 | 
			
		||||
			*pi64 = htole64(*pi64);
 | 
			
		||||
			*pi64 = xlate64(*pi64);
 | 
			
		||||
			break;
 | 
			
		||||
		case DM_ULOG_GET_RESYNC_WORK:
 | 
			
		||||
		case DM_ULOG_IS_REMOTE_RECOVERING:
 | 
			
		||||
			pi64 = (int64_t *)rq->u_rq.data;
 | 
			
		||||
			pu64 = ((uint64_t *)rq->u_rq.data) + 1;
 | 
			
		||||
			*pi64 = htole64(*pi64);
 | 
			
		||||
			*pu64 = htole64(*pu64);
 | 
			
		||||
			*pi64 = xlate64(*pi64);
 | 
			
		||||
			*pu64 = xlate64(*pu64);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			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_IS_REMOTE_RECOVERING:
 | 
			
		||||
			pu64 = (uint64_t *)rq->u_rq.data;
 | 
			
		||||
			*pu64 = htole64(*pu64);
 | 
			
		||||
			*pu64 = xlate64(*pu64);
 | 
			
		||||
			break;
 | 
			
		||||
		case DM_ULOG_MARK_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;
 | 
			
		||||
			for (i = 0; i < end; i++)
 | 
			
		||||
				pu64[i] = htole64(pu64[i]);
 | 
			
		||||
				pu64[i] = xlate64(pu64[i]);
 | 
			
		||||
			break;
 | 
			
		||||
		case DM_ULOG_SET_REGION_SYNC:
 | 
			
		||||
			pu64 = (uint64_t *)rq->u_rq.data;
 | 
			
		||||
			pi64 = ((int64_t *)rq->u_rq.data) + 1;
 | 
			
		||||
			*pu64 = htole64(*pu64);
 | 
			
		||||
			*pi64 = htole64(*pi64);
 | 
			
		||||
			*pu64 = xlate64(*pu64);
 | 
			
		||||
			*pi64 = xlate64(*pi64);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			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;
 | 
			
		||||
 | 
			
		||||
	u_rq->error = htole32(u_rq->error);
 | 
			
		||||
	u_rq->seq = htole32(u_rq->seq);
 | 
			
		||||
	u_rq->error = xlate32(u_rq->error);
 | 
			
		||||
	u_rq->seq = xlate32(u_rq->seq);
 | 
			
		||||
 | 
			
		||||
	rq->originator = htole32(rq->originator);
 | 
			
		||||
	rq->originator = xlate32(rq->originator);
 | 
			
		||||
 | 
			
		||||
	v5_data_endian_switch(rq, 1);
 | 
			
		||||
 | 
			
		||||
	u_rq->request_type = htole32(u_rq->request_type);
 | 
			
		||||
	u_rq->data_size = htole32(u_rq->data_size);
 | 
			
		||||
	u_rq->request_type = xlate32(u_rq->request_type);
 | 
			
		||||
	u_rq->data_size = xlate32(u_rq->data_size);
 | 
			
		||||
 | 
			
		||||
	return size;
 | 
			
		||||
}
 | 
			
		||||
@@ -142,7 +142,7 @@ int clog_request_to_network(struct clog_request *rq)
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	/* 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");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
@@ -165,12 +165,12 @@ static int v5_endian_from_network(struct clog_request *rq)
 | 
			
		||||
	int size;
 | 
			
		||||
	struct dm_ulog_request *u_rq = &rq->u_rq;
 | 
			
		||||
 | 
			
		||||
	u_rq->error = htole32(u_rq->error);
 | 
			
		||||
	u_rq->seq = htole32(u_rq->seq);
 | 
			
		||||
	u_rq->request_type = htole32(u_rq->request_type);
 | 
			
		||||
	u_rq->data_size = htole32(u_rq->data_size);
 | 
			
		||||
	u_rq->error = xlate32(u_rq->error);
 | 
			
		||||
	u_rq->seq = xlate32(u_rq->seq);
 | 
			
		||||
	u_rq->request_type = xlate32(u_rq->request_type);
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
@@ -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)
 | 
			
		||||
{
 | 
			
		||||
	uint64_t *vp = data;
 | 
			
		||||
	uint64_t version = htole64(vp[0]);
 | 
			
		||||
	uint64_t version = xlate64(vp[0]);
 | 
			
		||||
	struct clog_request *rq = data;
 | 
			
		||||
 | 
			
		||||
	switch (version) {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,6 @@
 | 
			
		||||
#ifndef _LVM_CLOG_COMPAT_H
 | 
			
		||||
#define _LVM_CLOG_COMPAT_H
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The intermachine communication structure version are:
 | 
			
		||||
 *	0: Unused
 | 
			
		||||
@@ -21,8 +19,6 @@
 | 
			
		||||
 */
 | 
			
		||||
#define CLOG_TFR_VERSION 5
 | 
			
		||||
 | 
			
		||||
struct clog_request;
 | 
			
		||||
 | 
			
		||||
int clog_request_to_network(struct clog_request *rq);
 | 
			
		||||
int clog_request_from_network(void *data, size_t data_len);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@
 | 
			
		||||
#define LOG_OFFSET 2
 | 
			
		||||
 | 
			
		||||
#define RESYNC_HISTORY 50
 | 
			
		||||
#define RESYNC_BUFLEN 270
 | 
			
		||||
#define RESYNC_BUFLEN 128
 | 
			
		||||
//static char resync_history[RESYNC_HISTORY][128];
 | 
			
		||||
//static int idx = 0;
 | 
			
		||||
#define LOG_SPRINT(_lc, f, arg...) do {					\
 | 
			
		||||
@@ -67,7 +67,7 @@ struct log_c {
 | 
			
		||||
	uint32_t recoverer;
 | 
			
		||||
	uint64_t recovering_region; /* -1 means not recovering */
 | 
			
		||||
	uint64_t skip_bit_warning; /* used to warn if region skipped */
 | 
			
		||||
	unsigned sync_search;
 | 
			
		||||
	int sync_search;
 | 
			
		||||
 | 
			
		||||
	int resume_override;
 | 
			
		||||
 | 
			
		||||
@@ -220,7 +220,7 @@ static int rw_log(struct log_c *lc, int do_write)
 | 
			
		||||
	if (r < 0)
 | 
			
		||||
		LOG_ERROR("[%s] rw_log:  read failure: %s",
 | 
			
		||||
			  SHORT_UUID(lc->uuid), strerror(errno));
 | 
			
		||||
	if ((unsigned) r != lc->disk_size)
 | 
			
		||||
	if (r != lc->disk_size)
 | 
			
		||||
		return -EIO; /* Failed disk read */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -254,7 +254,7 @@ static int read_log(struct log_c *lc)
 | 
			
		||||
	bitset_size = lc->region_count / 8;
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	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) ? 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);
 | 
			
		||||
 | 
			
		||||
	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! */
 | 
			
		||||
static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int *unlink_path __attribute__((unused)))
 | 
			
		||||
static int find_disk_path(char *major_minor_str, char *path_rtn, int *unlink_path __attribute__((unused)))
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
	DIR *dp;
 | 
			
		||||
	struct dirent *dep;
 | 
			
		||||
	struct stat statbuf;
 | 
			
		||||
	unsigned major, minor;
 | 
			
		||||
	int major, minor;
 | 
			
		||||
 | 
			
		||||
	if (!strstr(major_minor_str, ":")) {
 | 
			
		||||
		r = stat(major_minor_str, &statbuf);
 | 
			
		||||
@@ -306,7 +306,7 @@ static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int
 | 
			
		||||
			return -errno;
 | 
			
		||||
		if (!S_ISBLK(statbuf.st_mode))
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		dm_strncpy(path_rtn, major_minor_str, sz);
 | 
			
		||||
		sprintf(path_rtn, "%s", major_minor_str);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -329,7 +329,7 @@ static int find_disk_path(char *major_minor_str, char *path_rtn, size_t sz, int
 | 
			
		||||
		 * wanted.
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		snprintf(path_rtn, sz, "/dev/mapper/%s", dep->d_name);
 | 
			
		||||
		sprintf(path_rtn, "/dev/mapper/%s", dep->d_name);
 | 
			
		||||
		if (stat(path_rtn, &statbuf) < 0) {
 | 
			
		||||
			LOG_DBG("Unable to stat %s", path_rtn);
 | 
			
		||||
			continue;
 | 
			
		||||
@@ -380,8 +380,8 @@ static int _clog_ctr(char *uuid, uint64_t luid,
 | 
			
		||||
	int disk_log;
 | 
			
		||||
	char disk_path[PATH_MAX] = { 0 };
 | 
			
		||||
	int unlink_path = 0;
 | 
			
		||||
	long ps;
 | 
			
		||||
	size_t pages, page_size;
 | 
			
		||||
	long page_size;
 | 
			
		||||
	int pages;
 | 
			
		||||
 | 
			
		||||
	/* If core log request, then argv[0] will be region_size */
 | 
			
		||||
	if (!strtoll(argv[0], &p, 0) || *p) {
 | 
			
		||||
@@ -394,7 +394,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		r = find_disk_path(argv[0], disk_path, sizeof(disk_path), &unlink_path);
 | 
			
		||||
		r = find_disk_path(argv[0], disk_path, &unlink_path);
 | 
			
		||||
		if (r) {
 | 
			
		||||
			LOG_ERROR("Unable to find path to device %s", argv[0]);
 | 
			
		||||
			goto fail;
 | 
			
		||||
@@ -452,7 +452,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
 | 
			
		||||
	lc->skip_bit_warning = region_count;
 | 
			
		||||
	lc->disk_fd = -1;
 | 
			
		||||
	lc->log_dev_failed = 0;
 | 
			
		||||
	if (!_dm_strncpy(lc->uuid, uuid, DM_UUID_LEN)) {
 | 
			
		||||
	if (!dm_strncpy(lc->uuid, uuid, DM_UUID_LEN)) {
 | 
			
		||||
		LOG_ERROR("Cannot use too long UUID %s.", uuid);
 | 
			
		||||
		r = -EINVAL;
 | 
			
		||||
		goto fail;
 | 
			
		||||
@@ -488,15 +488,14 @@ static int _clog_ctr(char *uuid, uint64_t luid,
 | 
			
		||||
	lc->sync_count = (log_sync == NOSYNC) ? region_count : 0;
 | 
			
		||||
 | 
			
		||||
	if (disk_log) {
 | 
			
		||||
		if (((ps = sysconf(_SC_PAGESIZE)) <= 0) ||
 | 
			
		||||
		    (ps > (1 << 24))) {
 | 
			
		||||
		if ((page_size = sysconf(_SC_PAGESIZE)) < 0) {
 | 
			
		||||
			LOG_ERROR("Unable to read pagesize: %s",
 | 
			
		||||
				  strerror(errno));
 | 
			
		||||
			r = errno;
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
		page_size = (size_t)ps;
 | 
			
		||||
		pages = (*(lc->clean_bits) + page_size - 1) / page_size;
 | 
			
		||||
		pages = *(lc->clean_bits) / page_size;
 | 
			
		||||
		pages += *(lc->clean_bits) % page_size ? 1 : 0;
 | 
			
		||||
		pages += 1; /* for header */
 | 
			
		||||
 | 
			
		||||
		r = open(disk_path, O_RDWR | O_DIRECT);
 | 
			
		||||
@@ -928,7 +927,7 @@ int local_resume(struct dm_ulog_request *rq)
 | 
			
		||||
 *
 | 
			
		||||
 * Since this value doesn't change, the kernel
 | 
			
		||||
 * 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
 | 
			
		||||
 */
 | 
			
		||||
@@ -1019,7 +1018,7 @@ static int clog_in_sync(struct dm_ulog_request *rq)
 | 
			
		||||
	 * happen for reads is that additional read attempts may be
 | 
			
		||||
	 * 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
 | 
			
		||||
	 * recovering.  In that case, lc->in_sync would not have been set
 | 
			
		||||
	 * yet.
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,6 @@
 | 
			
		||||
#define _LVM_CLOG_FUNCTIONS_H
 | 
			
		||||
 | 
			
		||||
#include "libdm/libdevmapper.h"
 | 
			
		||||
#include "libdm/dm-tools/util.h"
 | 
			
		||||
#include "libdm/misc/dm-log-userspace.h"
 | 
			
		||||
#include "cluster.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -266,7 +266,7 @@ static int do_local_work(void *data __attribute__((unused)))
 | 
			
		||||
					  RQ_TYPE(u_rq->request_type));
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		/* ELSE */ /* fall through */
 | 
			
		||||
		/* ELSE, fall through */
 | 
			
		||||
	case DM_ULOG_IS_CLEAN:
 | 
			
		||||
	case DM_ULOG_FLUSH:
 | 
			
		||||
	case DM_ULOG_MARK_REGION:
 | 
			
		||||
@@ -326,11 +326,10 @@ static int do_local_work(void *data __attribute__((unused)))
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: 0 on success, -EXXX on failure
 | 
			
		||||
 */
 | 
			
		||||
int kernel_send(void *data)
 | 
			
		||||
int kernel_send(struct dm_ulog_request *u_rq)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
	uint16_t size;
 | 
			
		||||
	struct dm_ulog_request *u_rq = data;
 | 
			
		||||
 | 
			
		||||
	if (!u_rq)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
@@ -354,7 +353,7 @@ int kernel_send(void *data)
 | 
			
		||||
		size = sizeof(struct dm_ulog_request);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = kernel_send_helper(data, size);
 | 
			
		||||
	r = kernel_send_helper(u_rq, size);
 | 
			
		||||
	if (r)
 | 
			
		||||
		LOG_ERROR("Failed to send msg to kernel.");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,11 +12,9 @@
 | 
			
		||||
#ifndef _LVM_CLOG_LOCAL_H
 | 
			
		||||
#define _LVM_CLOG_LOCAL_H
 | 
			
		||||
 | 
			
		||||
struct dm_ulog_request;
 | 
			
		||||
 | 
			
		||||
int init_local(void);
 | 
			
		||||
void cleanup_local(void);
 | 
			
		||||
 | 
			
		||||
int kernel_send(void *data);
 | 
			
		||||
int kernel_send(struct dm_ulog_request *rq);
 | 
			
		||||
 | 
			
		||||
#endif /* _LVM_CLOG_LOCAL_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 */
 | 
			
		||||
#include "logging.h"
 | 
			
		||||
 | 
			
		||||
const char * const __rq_types_off_by_one[] = {
 | 
			
		||||
const char *__rq_types_off_by_one[] = {
 | 
			
		||||
	"DM_ULOG_CTR",
 | 
			
		||||
	"DM_ULOG_DTR",
 | 
			
		||||
	"DM_ULOG_PRESUSPEND",
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
/* SHORT_UUID - print last 8 chars of a string */
 | 
			
		||||
#define SHORT_UUID(x) (strlen(x) > 8) ? ((x) + (strlen(x) - 8)) : (x)
 | 
			
		||||
 | 
			
		||||
extern const char * const __rq_types_off_by_one[];
 | 
			
		||||
extern const char *__rq_types_off_by_one[];
 | 
			
		||||
#define RQ_TYPE(x) __rq_types_off_by_one[(x) - 1]
 | 
			
		||||
 | 
			
		||||
extern int log_tabbing;
 | 
			
		||||
 
 | 
			
		||||
@@ -70,13 +70,13 @@ plugins.device-mapper: $(LIB_SHARED)
 | 
			
		||||
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
 | 
			
		||||
dmeventd: $(LIB_SHARED) dmeventd.o
 | 
			
		||||
	$(SHOW) "    [CC] $@"
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
 | 
			
		||||
		-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
 | 
			
		||||
 | 
			
		||||
dmeventd.static: $(LIB_STATIC) dmeventd.o
 | 
			
		||||
	$(SHOW) "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(STATIC_LDFLAGS) -static dmeventd.o \
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static dmeventd.o \
 | 
			
		||||
		-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
 | 
			
		||||
 | 
			
		||||
ifeq ("@PKGCONFIG@", "yes")
 | 
			
		||||
@@ -84,27 +84,27 @@ ifeq ("@PKGCONFIG@", "yes")
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
install_include: $(srcdir)/libdevmapper-event.h
 | 
			
		||||
	$(SHOW) "    [INSTALL] $(<F)"
 | 
			
		||||
	@echo "    [INSTALL] $(<F)"
 | 
			
		||||
	$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_pkgconfig: libdevmapper-event.pc
 | 
			
		||||
	$(SHOW) "    [INSTALL] $<"
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
 | 
			
		||||
 | 
			
		||||
install_lib_dynamic: install_lib_shared
 | 
			
		||||
 | 
			
		||||
install_lib_static: $(LIB_STATIC)
 | 
			
		||||
	$(SHOW) "    [INSTALL] $<"
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_lib: $(INSTALL_LIB_TARGETS)
 | 
			
		||||
 | 
			
		||||
install_dmeventd_dynamic: dmeventd
 | 
			
		||||
	$(SHOW) "    [INSTALL] $<"
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_dmeventd_static: dmeventd.static
 | 
			
		||||
	$(SHOW) "    [INSTALL] $<"
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -15,8 +15,6 @@
 | 
			
		||||
#ifndef __DMEVENTD_DOT_H__
 | 
			
		||||
#define __DMEVENTD_DOT_H__
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
/* FIXME This stuff must be configurable. */
 | 
			
		||||
 | 
			
		||||
#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,
 | 
			
		||||
		struct dm_event_daemon_message *msg, int cmd,
 | 
			
		||||
		const char *dso_name, const char *dev_name,
 | 
			
		||||
		unsigned evmask, uint32_t timeout);
 | 
			
		||||
		enum dm_event_mask evmask, uint32_t timeout);
 | 
			
		||||
int init_fifos(struct dm_event_fifos *fifos);
 | 
			
		||||
void fini_fifos(struct dm_event_fifos *fifos);
 | 
			
		||||
int dm_event_get_version(struct dm_event_fifos *fifos, int *version);
 | 
			
		||||
 
 | 
			
		||||
@@ -352,7 +352,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
 | 
			
		||||
int daemon_talk(struct dm_event_fifos *fifos,
 | 
			
		||||
		struct dm_event_daemon_message *msg, int cmd,
 | 
			
		||||
		const char *dso_name, const char *dev_name,
 | 
			
		||||
		unsigned evmask, uint32_t timeout)
 | 
			
		||||
		enum dm_event_mask evmask, uint32_t timeout)
 | 
			
		||||
{
 | 
			
		||||
	int msg_size;
 | 
			
		||||
	memset(msg, 0, sizeof(*msg));
 | 
			
		||||
@@ -400,16 +400,25 @@ int daemon_talk(struct dm_event_fifos *fifos,
 | 
			
		||||
	return (int32_t) msg->cmd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Check for usable client fifo file
 | 
			
		||||
 * start_daemon
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: 2 client path does not exists, dmeventd should be restarted
 | 
			
		||||
 *          1 on success, 0 otherwise
 | 
			
		||||
 * This function forks off a process (dmeventd) that will handle
 | 
			
		||||
 * the events.  I am currently test opening one of the fifos to
 | 
			
		||||
 * ensure that the daemon is running and listening...  I thought
 | 
			
		||||
 * this would be less expensive than fork/exec'ing every time.
 | 
			
		||||
 * Perhaps there is an even quicker/better way (no, checking the
 | 
			
		||||
 * lock file is _not_ a better way).
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: 1 on success, 0 otherwise
 | 
			
		||||
 */
 | 
			
		||||
static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *fifos)
 | 
			
		||||
static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
 | 
			
		||||
{
 | 
			
		||||
	int pid, ret = 0;
 | 
			
		||||
	int status;
 | 
			
		||||
	struct stat statbuf;
 | 
			
		||||
	char default_dmeventd_path[] = DMEVENTD_PATH;
 | 
			
		||||
	char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * FIXME Explicitly verify the code's requirement that client_path is secure:
 | 
			
		||||
@@ -420,7 +429,7 @@ static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *f
 | 
			
		||||
	if ((lstat(fifos->client_path, &statbuf) < 0)) {
 | 
			
		||||
		if (errno == ENOENT)
 | 
			
		||||
			/* Jump ahead if fifo does not already exist. */
 | 
			
		||||
			return 2;
 | 
			
		||||
			goto start_server;
 | 
			
		||||
		else {
 | 
			
		||||
			log_sys_error("stat", fifos->client_path);
 | 
			
		||||
			return 0;
 | 
			
		||||
@@ -446,14 +455,12 @@ static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *f
 | 
			
		||||
			log_error("%s is no longer a secure root-owned fifo with mode 0600.", fifos->client_path);
 | 
			
		||||
			if (close(fifos->client))
 | 
			
		||||
				log_sys_debug("close", fifos->client_path);
 | 
			
		||||
			fifos->client = -1;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* server is running and listening */
 | 
			
		||||
		if (close(fifos->client))
 | 
			
		||||
			log_sys_debug("close", fifos->client_path);
 | 
			
		||||
		fifos->client = -1;
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	if (errno != ENXIO && errno != ENOENT)  {
 | 
			
		||||
@@ -462,36 +469,9 @@ static int _check_for_usable_fifos(char *dmeventd_path, struct dm_event_fifos *f
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * start_daemon
 | 
			
		||||
 *
 | 
			
		||||
 * This function forks off a process (dmeventd) that will handle
 | 
			
		||||
 * the events.  I am currently test opening one of the fifos to
 | 
			
		||||
 * ensure that the daemon is running and listening...  I thought
 | 
			
		||||
 * this would be less expensive than fork/exec'ing every time.
 | 
			
		||||
 * Perhaps there is an even quicker/better way (no, checking the
 | 
			
		||||
 * lock file is _not_ a better way).
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: 1 on success, 0 otherwise
 | 
			
		||||
 */
 | 
			
		||||
static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
 | 
			
		||||
{
 | 
			
		||||
	struct stat statbuf;
 | 
			
		||||
	char default_dmeventd_path[] = DMEVENTD_PATH;
 | 
			
		||||
	char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
 | 
			
		||||
	int pid, ret = 0;
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	switch (_check_for_usable_fifos(dmeventd_path, fifos)) {
 | 
			
		||||
	case 0: return_0;
 | 
			
		||||
	case 1: return 1; /* Already running dmeventd */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
start_server:
 | 
			
		||||
	/* server is not running */
 | 
			
		||||
 | 
			
		||||
	if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
 | 
			
		||||
		log_sys_error("stat", args[0]);
 | 
			
		||||
		return 0;
 | 
			
		||||
@@ -512,17 +492,8 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
 | 
			
		||||
				  strerror(errno));
 | 
			
		||||
		else if (WEXITSTATUS(status))
 | 
			
		||||
			log_error("Unable to start dmeventd.");
 | 
			
		||||
		else {
 | 
			
		||||
			/* Loop here till forked dmeventd is serving fifos */
 | 
			
		||||
			for (ret = 100; ret > 0; --ret)
 | 
			
		||||
				switch (_check_for_usable_fifos(dmeventd_path, fifos)) {
 | 
			
		||||
				case 0: return_0;
 | 
			
		||||
				case 1: return 1;
 | 
			
		||||
				case 2: usleep(1000); break;
 | 
			
		||||
				}
 | 
			
		||||
			/* ret == 0 */
 | 
			
		||||
			log_error("Dmeventd is not serving fifos.");
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
			ret = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
@@ -542,7 +513,7 @@ int init_fifos(struct dm_event_fifos *fifos)
 | 
			
		||||
	/* Lock out anyone else trying to do communication with the daemon. */
 | 
			
		||||
	if (flock(fifos->server, LOCK_EX) < 0) {
 | 
			
		||||
		log_sys_error("flock", fifos->server_path);
 | 
			
		||||
		goto bad_no_unlock;
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
/*	if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/
 | 
			
		||||
@@ -553,9 +524,6 @@ int init_fifos(struct dm_event_fifos *fifos)
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
bad:
 | 
			
		||||
	if (flock(fifos->server, LOCK_UN))
 | 
			
		||||
		log_sys_debug("flock unlock", fifos->server_path);
 | 
			
		||||
bad_no_unlock:
 | 
			
		||||
	if (close(fifos->server))
 | 
			
		||||
		log_sys_debug("close", fifos->server_path);
 | 
			
		||||
	fifos->server = -1;
 | 
			
		||||
@@ -584,8 +552,6 @@ void fini_fifos(struct dm_event_fifos *fifos)
 | 
			
		||||
		if (close(fifos->server))
 | 
			
		||||
			log_sys_debug("close", fifos->server_path);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fifos->client = fifos->server = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Get uuid of a device */
 | 
			
		||||
@@ -754,7 +720,7 @@ static char *_fetch_string(char **src, const int delimiter)
 | 
			
		||||
 | 
			
		||||
/* Parse a device message from the daemon. */
 | 
			
		||||
static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
 | 
			
		||||
			 char **uuid, unsigned *evmask)
 | 
			
		||||
			 char **uuid, enum dm_event_mask *evmask)
 | 
			
		||||
{
 | 
			
		||||
	char *id;
 | 
			
		||||
	char *p = msg->data;
 | 
			
		||||
@@ -779,7 +745,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	const char *uuid = NULL;
 | 
			
		||||
	char *reply_dso = NULL, *reply_uuid = NULL;
 | 
			
		||||
	unsigned reply_mask = 0;
 | 
			
		||||
	enum dm_event_mask reply_mask = 0;
 | 
			
		||||
	struct dm_task *dmt = NULL;
 | 
			
		||||
	struct dm_event_daemon_message msg = { 0 };
 | 
			
		||||
	struct dm_info info;
 | 
			
		||||
@@ -829,7 +795,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_event_handler_set_dso(dmevh, reply_dso);
 | 
			
		||||
	dm_event_handler_set_event_mask(dmevh, (enum dm_event_mask) reply_mask);
 | 
			
		||||
	dm_event_handler_set_event_mask(dmevh, reply_mask);
 | 
			
		||||
 | 
			
		||||
	free(reply_dso);
 | 
			
		||||
	reply_dso = NULL;
 | 
			
		||||
@@ -878,7 +844,6 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 | 
			
		||||
int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
 | 
			
		||||
	char *p;
 | 
			
		||||
	struct dm_event_daemon_message msg = { 0 };
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0))
 | 
			
		||||
		return 0;
 | 
			
		||||
@@ -886,17 +851,13 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
 | 
			
		||||
	*version = 0;
 | 
			
		||||
 | 
			
		||||
	if (!p || !(p = strchr(p, ' '))) /* Message ID */
 | 
			
		||||
		goto out;
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (!(p = strchr(p + 1, ' '))) /* HELLO */
 | 
			
		||||
		goto out;
 | 
			
		||||
		return 0;
 | 
			
		||||
	if ((p = strchr(p + 1, ' '))) /* HELLO, once more */
 | 
			
		||||
		*version = atoi(p);
 | 
			
		||||
 | 
			
		||||
	ret = 1;
 | 
			
		||||
out:
 | 
			
		||||
	free(msg.data);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_event_log_set(int debug_log_level, int use_syslog)
 | 
			
		||||
@@ -911,11 +872,11 @@ void dm_event_log(const char *subsys, int level, const char *file,
 | 
			
		||||
{
 | 
			
		||||
	static int _abort_on_internal_errors = -1;
 | 
			
		||||
	static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
 | 
			
		||||
	static long long _start = 0;
 | 
			
		||||
	static time_t start = 0;
 | 
			
		||||
	const char *indent = "";
 | 
			
		||||
	FILE *stream = log_stderr(level) ? stderr : stdout;
 | 
			
		||||
	int prio;
 | 
			
		||||
	long long now, now_nsec;
 | 
			
		||||
	time_t now;
 | 
			
		||||
	int log_with_debug = 0;
 | 
			
		||||
 | 
			
		||||
	if (subsys[0] == '#') {
 | 
			
		||||
@@ -962,33 +923,22 @@ void dm_event_log(const char *subsys, int level, const char *file,
 | 
			
		||||
	if (_use_syslog) {
 | 
			
		||||
		vsyslog(prio, format, ap);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (_debug_level) {
 | 
			
		||||
#define _NSEC_PER_SEC (1000000000LL)
 | 
			
		||||
#ifdef HAVE_REALTIME
 | 
			
		||||
			struct timespec mono_time = { 0 };
 | 
			
		||||
			if (clock_gettime(CLOCK_MONOTONIC, &mono_time) == 0)
 | 
			
		||||
				now = mono_time.tv_sec * _NSEC_PER_SEC + mono_time.tv_nsec;
 | 
			
		||||
			else
 | 
			
		||||
#endif
 | 
			
		||||
				now = time(NULL) * _NSEC_PER_SEC;
 | 
			
		||||
 | 
			
		||||
			if (!_start)
 | 
			
		||||
				_start = now;
 | 
			
		||||
			now -= _start;
 | 
			
		||||
			now_nsec = now %_NSEC_PER_SEC;
 | 
			
		||||
			now /= _NSEC_PER_SEC;
 | 
			
		||||
			fprintf(stream, "[%2lld:%02lld.%06lld] %8x:%-6s%s",
 | 
			
		||||
				now / 60, now % 60, now_nsec / 1000,
 | 
			
		||||
		now = time(NULL);
 | 
			
		||||
		if (!start)
 | 
			
		||||
			start = now;
 | 
			
		||||
		now -= start;
 | 
			
		||||
		if (_debug_level)
 | 
			
		||||
			fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
 | 
			
		||||
				(int)now / 60, (int)now % 60,
 | 
			
		||||
				// TODO: Maybe use shorter ID
 | 
			
		||||
				// ((int)(pthread_self()) >> 6) & 0xffff,
 | 
			
		||||
				(int)pthread_self(), subsys,
 | 
			
		||||
				(_debug_level > 3) ? "" : indent);
 | 
			
		||||
		}
 | 
			
		||||
		if (_debug_level > 3)
 | 
			
		||||
			fprintf(stream, "%28s:%4d %s", file, line, indent);
 | 
			
		||||
		vfprintf(stream, _(format), ap);
 | 
			
		||||
		fputc('\n', stream);
 | 
			
		||||
		(void) fflush(stream);
 | 
			
		||||
		fflush(stream);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&_log_mutex);
 | 
			
		||||
@@ -1007,7 +957,7 @@ void dm_event_log(const char *subsys, int level, const char *file,
 | 
			
		||||
 | 
			
		||||
static char *_skip_string(char *src, const int delimiter)
 | 
			
		||||
{
 | 
			
		||||
	src = strchr(src, delimiter);
 | 
			
		||||
	src = srtchr(src, delimiter);
 | 
			
		||||
	if (src && *(src + 1))
 | 
			
		||||
		return src + 1;
 | 
			
		||||
	return NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -29,22 +29,19 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
enum dm_event_mask {
 | 
			
		||||
	DM_EVENT_SETTINGS_MASK  = 0x0000FF,
 | 
			
		||||
	DM_EVENT_SINGLE		= 0x000001, /* Report multiple errors just once. */
 | 
			
		||||
	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_DEVICE_ERROR	= 0x000200, /* Device failure. */
 | 
			
		||||
	DM_EVENT_PATH_ERROR	= 0x000400, /* Failure on an io path. */
 | 
			
		||||
	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_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 */
 | 
			
		||||
};
 | 
			
		||||
@@ -73,10 +70,10 @@ int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path);
 | 
			
		||||
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
@@ -112,7 +109,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
 | 
			
		||||
/* Set debug level for logging, and whether to log on stdout/stderr or syslog */
 | 
			
		||||
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)))
 | 
			
		||||
void dm_event_log(const char *subsys, int level, const char *file,
 | 
			
		||||
		  int line, int dm_errno_or_class,
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,6 @@
 | 
			
		||||
#include "lib/misc/lib.h"
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
			
		||||
#include "lib/metadata/metadata-exported.h" /* MIRROR_SYNC_LAYER */
 | 
			
		||||
#include "tools/lvm2cmd.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
@@ -88,7 +87,7 @@ int dmeventd_lvm2_init(void)
 | 
			
		||||
		lvm2_disable_dmeventd_monitoring(_lvm_handle);
 | 
			
		||||
		/* FIXME Temporary: move to dmeventd core */
 | 
			
		||||
		lvm2_run(_lvm_handle, "_memlock_inc");
 | 
			
		||||
		log_debug("lvm plugin initialized.");
 | 
			
		||||
		log_debug("lvm plugin initilized.");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_register_count++;
 | 
			
		||||
@@ -104,7 +103,7 @@ void dmeventd_lvm2_exit(void)
 | 
			
		||||
	pthread_mutex_lock(&_register_mutex);
 | 
			
		||||
 | 
			
		||||
	if (!--_register_count) {
 | 
			
		||||
		log_debug("lvm plugin shutting down.");
 | 
			
		||||
		log_debug("lvm plugin shuting down.");
 | 
			
		||||
		lvm2_run(_lvm_handle, "_memlock_dec");
 | 
			
		||||
		dm_pool_destroy(_mem_pool);
 | 
			
		||||
		_mem_pool = NULL;
 | 
			
		||||
@@ -124,7 +123,6 @@ struct dm_pool *dmeventd_lvm2_pool(void)
 | 
			
		||||
 | 
			
		||||
int dmeventd_lvm2_run(const char *cmdline)
 | 
			
		||||
{
 | 
			
		||||
	/* coverity[missing_lock] no locking for run part */
 | 
			
		||||
	return (lvm2_run(_lvm_handle, cmdline) == LVM2_COMMAND_SUCCEEDED);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -144,7 +142,7 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* strip off the mirror component designations */
 | 
			
		||||
	if ((layer = strstr(lv, MIRROR_SYNC_LAYER)) ||
 | 
			
		||||
	if ((layer = strstr(lv, "_mimagetmp")) ||
 | 
			
		||||
	    (layer = strstr(lv, "_mlog")))
 | 
			
		||||
		*layer = '\0';
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,8 +25,6 @@
 | 
			
		||||
#ifndef _DMEVENTD_LVMWRAP_H
 | 
			
		||||
#define _DMEVENTD_LVMWRAP_H
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
struct dm_pool;
 | 
			
		||||
 | 
			
		||||
int dmeventd_lvm2_init(void);
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ static void _process_status_code(dm_status_mirror_health_t health,
 | 
			
		||||
	 *    A => Alive - No failures
 | 
			
		||||
	 *    D => Dead - A write failure occurred leaving mirror out-of-sync
 | 
			
		||||
	 *    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
 | 
			
		||||
	 *    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,
 | 
			
		||||
		   enum dm_event_mask evmask __attribute__((unused)),
 | 
			
		||||
		   enum dm_event_mask event __attribute__((unused)),
 | 
			
		||||
		   void **user)
 | 
			
		||||
{
 | 
			
		||||
	struct dso_state *state = *user;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
			
		||||
#include "lib/config/defaults.h"
 | 
			
		||||
 | 
			
		||||
/* Hold enough elements for the maximum number of RAID images */
 | 
			
		||||
/* Hold enough elements for the mximum number of RAID images */
 | 
			
		||||
#define	RAID_DEVS_ELEMS	((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
 | 
			
		||||
 | 
			
		||||
struct dso_state {
 | 
			
		||||
@@ -84,7 +84,7 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
 | 
			
		||||
		 */
 | 
			
		||||
		if (!state->warned && status->insync_regions < status->total_regions) {
 | 
			
		||||
			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);
 | 
			
		||||
			/* Fall through to allow lvconvert to run. */
 | 
			
		||||
		}
 | 
			
		||||
@@ -114,7 +114,7 @@ out:
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void process_event(struct dm_task *dmt,
 | 
			
		||||
		   enum dm_event_mask evmask __attribute__((unused)),
 | 
			
		||||
		   enum dm_event_mask event __attribute__((unused)),
 | 
			
		||||
		   void **user)
 | 
			
		||||
{
 | 
			
		||||
	struct dso_state *state = *user;
 | 
			
		||||
 
 | 
			
		||||
@@ -163,7 +163,7 @@ static void _umount(const char *device, int major, int minor)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void process_event(struct dm_task *dmt,
 | 
			
		||||
		   enum dm_event_mask evmask __attribute__((unused)),
 | 
			
		||||
		   enum dm_event_mask event __attribute__((unused)),
 | 
			
		||||
		   void **user)
 | 
			
		||||
{
 | 
			
		||||
	struct dso_state *state = *user;
 | 
			
		||||
 
 | 
			
		||||
@@ -45,10 +45,10 @@
 | 
			
		||||
 | 
			
		||||
struct dso_state {
 | 
			
		||||
	struct dm_pool *mem;
 | 
			
		||||
	dm_percent_t metadata_percent_check;
 | 
			
		||||
	dm_percent_t metadata_percent;
 | 
			
		||||
	dm_percent_t data_percent_check;
 | 
			
		||||
	dm_percent_t data_percent;
 | 
			
		||||
	int metadata_percent_check;
 | 
			
		||||
	int metadata_percent;
 | 
			
		||||
	int data_percent_check;
 | 
			
		||||
	int data_percent;
 | 
			
		||||
	uint64_t known_metadata_size;
 | 
			
		||||
	uint64_t known_data_size;
 | 
			
		||||
	unsigned fails;
 | 
			
		||||
@@ -87,7 +87,7 @@ static int _run_command(struct dso_state *state)
 | 
			
		||||
	log_verbose("Executing command: %s", state->cmd_str);
 | 
			
		||||
 | 
			
		||||
	/* 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
 | 
			
		||||
	 *   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,
 | 
			
		||||
		   enum dm_event_mask evmask,
 | 
			
		||||
		   enum dm_event_mask event __attribute__((unused)),
 | 
			
		||||
		   void **user)
 | 
			
		||||
{
 | 
			
		||||
	const char *device = dm_task_get_name(dmt);
 | 
			
		||||
@@ -179,7 +179,7 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (evmask & DM_EVENT_DEVICE_ERROR) {
 | 
			
		||||
	if (event & DM_EVENT_DEVICE_ERROR) {
 | 
			
		||||
		/* Error -> no need to check and do instant resize */
 | 
			
		||||
		state->data_percent = state->metadata_percent = 0;
 | 
			
		||||
		if (_use_policy(dmt, state))
 | 
			
		||||
@@ -223,12 +223,10 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if THIN_DEBUG
 | 
			
		||||
	log_debug("Thin pool status " FMTu64 "/" FMTu64 " (" FMTu64 ") "
 | 
			
		||||
		  FMTu64 "/" FMTu64 " (" FMTu64").",
 | 
			
		||||
		  tps->used_data_blocks, tps->total_data_blocks,
 | 
			
		||||
		  state->known_data_size,
 | 
			
		||||
	log_debug("Thin pool status " FMTu64 "/" FMTu64 "  "
 | 
			
		||||
		  FMTu64 "/" FMTu64 ".",
 | 
			
		||||
		  tps->used_metadata_blocks, tps->total_metadata_blocks,
 | 
			
		||||
		  state->known_metadata_size);
 | 
			
		||||
		  tps->used_data_blocks, tps->total_data_blocks);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* 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.
 | 
			
		||||
	 * 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%
 | 
			
		||||
	 */
 | 
			
		||||
	state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
 | 
			
		||||
@@ -381,13 +379,14 @@ int register_device(const char *device,
 | 
			
		||||
 | 
			
		||||
		state->argv[1] = str + 1;  /* 1 argument - vg/lv */
 | 
			
		||||
		_init_thread_signals(state);
 | 
			
		||||
	} else /* Unsupported command format */
 | 
			
		||||
	} else /* Unuspported command format */
 | 
			
		||||
		goto inval;
 | 
			
		||||
 | 
			
		||||
	state->max_fails = 1;
 | 
			
		||||
	state->pid = -1;
 | 
			
		||||
	*user = state;
 | 
			
		||||
 | 
			
		||||
	log_info("Monitoring thin pool %s.", device);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
inval:
 | 
			
		||||
	log_error("Invalid command for monitoring: %s.", cmd_str);
 | 
			
		||||
@@ -431,6 +430,7 @@ int unregister_device(const char *device,
 | 
			
		||||
	_restore_thread_signals(state);
 | 
			
		||||
 | 
			
		||||
	dmeventd_lvm2_exit_with_pool(state);
 | 
			
		||||
	log_info("No longer monitoring thin pool %s.", device);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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
 | 
			
		||||
 * in runtime we are linked agains systems libdm 'older' library
 | 
			
		||||
 * which does not provide this symbol and plugin fails to load
 | 
			
		||||
 */
 | 
			
		||||
/* coverity[unnecessary_header] used for parsing */
 | 
			
		||||
@@ -78,7 +78,7 @@ static int _run_command(struct dso_state *state)
 | 
			
		||||
	log_verbose("Executing command: %s", state->cmd_str);
 | 
			
		||||
 | 
			
		||||
	/* 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
 | 
			
		||||
	 *   as signalling is not allowed while 'process_event()' is running
 | 
			
		||||
	 */
 | 
			
		||||
@@ -146,7 +146,7 @@ static int _wait_for_pid(struct dso_state *state)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void process_event(struct dm_task *dmt,
 | 
			
		||||
		   enum dm_event_mask evmask __attribute__((unused)),
 | 
			
		||||
		   enum dm_event_mask event __attribute__((unused)),
 | 
			
		||||
		   void **user)
 | 
			
		||||
{
 | 
			
		||||
	const char *device = dm_task_get_name(dmt);
 | 
			
		||||
@@ -169,7 +169,7 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (evmask & DM_EVENT_DEVICE_ERROR) {
 | 
			
		||||
	if (event & DM_EVENT_DEVICE_ERROR) {
 | 
			
		||||
#if VDO_DEBUG
 | 
			
		||||
		log_debug("VDO event error.");
 | 
			
		||||
#endif
 | 
			
		||||
@@ -227,7 +227,7 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
	/*
 | 
			
		||||
	 * Trigger action when threshold boundary is exceeded.
 | 
			
		||||
	 * 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%
 | 
			
		||||
	 */
 | 
			
		||||
	if ((state->percent > WARNING_THRESH) &&
 | 
			
		||||
@@ -354,7 +354,7 @@ int register_device(const char *device,
 | 
			
		||||
		_init_thread_signals(state);
 | 
			
		||||
	} else if (cmd[0] == 0) {
 | 
			
		||||
		state->name = "volume"; /* What to use with 'others?' */
 | 
			
		||||
	} else/* Unsupported command format */
 | 
			
		||||
	} else/* Unuspported command format */
 | 
			
		||||
		goto inval;
 | 
			
		||||
 | 
			
		||||
	state->pid = -1;
 | 
			
		||||
 
 | 
			
		||||
@@ -51,14 +51,18 @@ include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
.PHONY: install_lvmdbusd
 | 
			
		||||
 | 
			
		||||
all:
 | 
			
		||||
	$(Q) test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
 | 
			
		||||
 | 
			
		||||
install_lvmdbusd: $(LVMDBUSD)
 | 
			
		||||
	$(SHOW) "    [INSTALL] $<"
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_DIR) $(sbindir)
 | 
			
		||||
	$(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
 | 
			
		||||
	$(Q) $(INSTALL_DIR) $(lvmdbusdir) $(lvmdbusdir)/__pycache__
 | 
			
		||||
	$(Q) $(INSTALL_DIR) $(lvmdbusdir)
 | 
			
		||||
	$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(lvmdbusdir))
 | 
			
		||||
	$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir)
 | 
			
		||||
	$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbuspydir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
 | 
			
		||||
	$(Q) $(CHMOD) 755 $(lvmdbusdir)/__pycache__
 | 
			
		||||
	$(Q) $(CHMOD) 444 $(lvmdbusdir)/__pycache__/*.py[co]
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_lvmdbusd
 | 
			
		||||
 
 | 
			
		||||
@@ -44,10 +44,10 @@ class AutomatedProperties(dbus.service.Object):
 | 
			
		||||
 | 
			
		||||
	def set_interface(self, interface):
 | 
			
		||||
		"""
 | 
			
		||||
		With inheritance, we can't easily tell what interfaces a class provides,
 | 
			
		||||
		With inheritance we can't easily tell what interfaces a class provides
 | 
			
		||||
		so we will have each class that implements an interface tell the
 | 
			
		||||
		base AutomatedProperties what it is they do provide.  This is kind of
 | 
			
		||||
		clunky, and perhaps we can figure out a better way to do this later.
 | 
			
		||||
		clunky and perhaps we can figure out a better way to do this later.
 | 
			
		||||
		:param interface:       An interface the object supports
 | 
			
		||||
		:return:
 | 
			
		||||
		"""
 | 
			
		||||
@@ -88,6 +88,7 @@ class AutomatedProperties(dbus.service.Object):
 | 
			
		||||
			cb, cbe, False)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _get_all_prop(obj, interface_name):
 | 
			
		||||
		if interface_name in obj.interface(True):
 | 
			
		||||
 
 | 
			
		||||
@@ -7,13 +7,16 @@
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import subprocess
 | 
			
		||||
from . import cfg
 | 
			
		||||
from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm
 | 
			
		||||
import dbus
 | 
			
		||||
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
 | 
			
		||||
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
 | 
			
		||||
					mt_async_call
 | 
			
		||||
from .request import RequestEntry
 | 
			
		||||
import threading
 | 
			
		||||
import time
 | 
			
		||||
import traceback
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def pv_move_lv_cmd(move_options, lv_full_name,
 | 
			
		||||
@@ -62,15 +65,18 @@ def _move_callback(job_state, line_str):
 | 
			
		||||
def _move_merge(interface_name, command, job_state):
 | 
			
		||||
	# We need to execute these command stand alone by forking & exec'ing
 | 
			
		||||
	# the command always as we will be getting periodic output from them on
 | 
			
		||||
	# the status of the long-running operation.
 | 
			
		||||
	# the status of the long running operation.
 | 
			
		||||
 | 
			
		||||
	meta = LvmExecutionMeta(time.time(), 0, command)
 | 
			
		||||
	cfg.flightrecorder.add(meta)
 | 
			
		||||
	meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
 | 
			
		||||
	cfg.blackbox.add(meta)
 | 
			
		||||
 | 
			
		||||
	ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
 | 
			
		||||
									cb_data=job_state)
 | 
			
		||||
	ended = time.time()
 | 
			
		||||
	meta.completed(ended, ec, stdout, stderr)
 | 
			
		||||
 | 
			
		||||
	with meta.lock:
 | 
			
		||||
		meta.ended = time.time()
 | 
			
		||||
		meta.ec = ec
 | 
			
		||||
		meta.stderr_txt = stderr
 | 
			
		||||
 | 
			
		||||
	if ec == 0:
 | 
			
		||||
		job_state.Percent = 100
 | 
			
		||||
 
 | 
			
		||||
@@ -11,18 +11,11 @@ import os
 | 
			
		||||
import multiprocessing
 | 
			
		||||
import queue
 | 
			
		||||
import itertools
 | 
			
		||||
from lvmdbusd.utils import LvmDebugData
 | 
			
		||||
 | 
			
		||||
from lvmdbusd import path
 | 
			
		||||
 | 
			
		||||
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
 | 
			
		||||
 | 
			
		||||
LOCK_FILE = os.getenv("LVM_DBUSD_LOCKFILE", "/var/lock/lvm/lvmdbusd")
 | 
			
		||||
 | 
			
		||||
# Save off the debug data needed for lvm team to debug issues
 | 
			
		||||
# only used for 'fullreport' at this time.
 | 
			
		||||
lvmdebug = LvmDebugData(os.getenv('LVM_DBUSD_COLLECT_LVM_DEBUG', False))
 | 
			
		||||
 | 
			
		||||
# This is the global object manager
 | 
			
		||||
om = None
 | 
			
		||||
 | 
			
		||||
@@ -32,13 +25,13 @@ bus = None
 | 
			
		||||
# Command line args
 | 
			
		||||
args = None
 | 
			
		||||
 | 
			
		||||
# Set to true if we depend on external events for updates
 | 
			
		||||
# Set to true if we are depending on external events for updates
 | 
			
		||||
got_external_event = False
 | 
			
		||||
 | 
			
		||||
# Shared state variable across all processes
 | 
			
		||||
run = multiprocessing.Value('i', 1)
 | 
			
		||||
 | 
			
		||||
# If this is set to true, the current setup support lvm shell, and we are
 | 
			
		||||
# If this is set to true, the current setup support lvm shell and we are
 | 
			
		||||
# running in that mode of operation
 | 
			
		||||
SHELL_IN_USE = None
 | 
			
		||||
 | 
			
		||||
@@ -50,11 +43,6 @@ worker_q = queue.Queue()
 | 
			
		||||
# Main event loop
 | 
			
		||||
loop = None
 | 
			
		||||
 | 
			
		||||
G_LOOP_TMO = 0.5
 | 
			
		||||
 | 
			
		||||
# Used to instruct the daemon if we should ignore SIGTERM
 | 
			
		||||
ignore_sigterm = False
 | 
			
		||||
 | 
			
		||||
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
 | 
			
		||||
BASE_INTERFACE = 'com.redhat.lvmdbus1'
 | 
			
		||||
PV_INTERFACE = BASE_INTERFACE + '.Pv'
 | 
			
		||||
@@ -102,14 +90,11 @@ vdo_support = False
 | 
			
		||||
db = None
 | 
			
		||||
 | 
			
		||||
# lvm flight recorder
 | 
			
		||||
flightrecorder = None
 | 
			
		||||
blackbox = None
 | 
			
		||||
 | 
			
		||||
# RequestEntry ctor
 | 
			
		||||
create_request_entry = None
 | 
			
		||||
 | 
			
		||||
# Circular debug log
 | 
			
		||||
debug = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def exit_daemon():
 | 
			
		||||
    """
 | 
			
		||||
@@ -119,6 +104,3 @@ def exit_daemon():
 | 
			
		||||
    if run and loop:
 | 
			
		||||
        run.value = 0
 | 
			
		||||
        loop.quit()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
systemd = False
 | 
			
		||||
 
 | 
			
		||||
@@ -6,18 +6,19 @@
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
import errno
 | 
			
		||||
 | 
			
		||||
from subprocess import Popen, PIPE
 | 
			
		||||
import select
 | 
			
		||||
import time
 | 
			
		||||
import threading
 | 
			
		||||
from itertools import chain
 | 
			
		||||
import collections
 | 
			
		||||
import traceback
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
from lvmdbusd import cfg
 | 
			
		||||
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
 | 
			
		||||
			make_non_block, read_decoded, extract_stack_trace, LvmBug, add_config_option, get_error_msg
 | 
			
		||||
							make_non_block, read_decoded
 | 
			
		||||
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
@@ -25,6 +26,7 @@ try:
 | 
			
		||||
except ImportError:
 | 
			
		||||
	import json
 | 
			
		||||
 | 
			
		||||
SEP = '{|}'
 | 
			
		||||
 | 
			
		||||
total_time = 0.0
 | 
			
		||||
total_count = 0
 | 
			
		||||
@@ -36,7 +38,7 @@ cmd_lock = threading.RLock()
 | 
			
		||||
 | 
			
		||||
class LvmExecutionMeta(object):
 | 
			
		||||
 | 
			
		||||
	def __init__(self, start, ended, cmd, ec=-1000, stdout_txt=None, stderr_txt=None):
 | 
			
		||||
	def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
 | 
			
		||||
		self.lock = threading.RLock()
 | 
			
		||||
		self.start = start
 | 
			
		||||
		self.ended = ended
 | 
			
		||||
@@ -47,49 +49,32 @@ class LvmExecutionMeta(object):
 | 
			
		||||
 | 
			
		||||
	def __str__(self):
 | 
			
		||||
		with self.lock:
 | 
			
		||||
			if self.ended == 0:
 | 
			
		||||
				ended_txt = "still running"
 | 
			
		||||
				self.ended = time.time()
 | 
			
		||||
			else:
 | 
			
		||||
				ended_txt = str(time.ctime(self.ended))
 | 
			
		||||
 | 
			
		||||
			return 'EC= %d for "%s"\n' \
 | 
			
		||||
				"STARTED: %s, ENDED: %s, DURATION: %f\n" \
 | 
			
		||||
			return "EC= %d for %s\n" \
 | 
			
		||||
				"STARTED: %f, ENDED: %f\n" \
 | 
			
		||||
				"STDOUT=%s\n" \
 | 
			
		||||
				"STDERR=%s\n" % \
 | 
			
		||||
				(self.ec, " ".join(self.cmd), time.ctime(self.start), ended_txt, float(self.ended) - self.start,
 | 
			
		||||
					self.stdout_txt,
 | 
			
		||||
					self.stderr_txt)
 | 
			
		||||
 | 
			
		||||
	def completed(self, end_time, ec, stdout_txt, stderr_txt):
 | 
			
		||||
		with self.lock:
 | 
			
		||||
			self.ended = end_time
 | 
			
		||||
			self.ec = ec
 | 
			
		||||
			self.stdout_txt = stdout_txt
 | 
			
		||||
			self.stderr_txt = stderr_txt
 | 
			
		||||
				(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
 | 
			
		||||
				self.stderr_txt)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LvmFlightRecorder(object):
 | 
			
		||||
 | 
			
		||||
	def __init__(self, size=16):
 | 
			
		||||
		self.queue = collections.deque(maxlen=size)
 | 
			
		||||
		self.lock = threading.RLock()
 | 
			
		||||
 | 
			
		||||
	def add(self, lvm_exec_meta):
 | 
			
		||||
		with self.lock:
 | 
			
		||||
			self.queue.append(lvm_exec_meta)
 | 
			
		||||
		self.queue.append(lvm_exec_meta)
 | 
			
		||||
 | 
			
		||||
	def dump(self):
 | 
			
		||||
		with self.lock:
 | 
			
		||||
		with cmd_lock:
 | 
			
		||||
			if len(self.queue):
 | 
			
		||||
				log_error("LVM dbus flight recorder START (in order of newest to oldest)")
 | 
			
		||||
				log_error("LVM dbus flight recorder START")
 | 
			
		||||
				for c in reversed(self.queue):
 | 
			
		||||
					log_error(str(c))
 | 
			
		||||
				log_error("LVM dbus flight recorder END")
 | 
			
		||||
				self.queue.clear()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
cfg.flightrecorder = LvmFlightRecorder()
 | 
			
		||||
cfg.blackbox = LvmFlightRecorder()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _debug_c(cmd, exit_code, out):
 | 
			
		||||
@@ -109,7 +94,7 @@ def call_lvm(command, debug=False, line_cb=None,
 | 
			
		||||
					stdin, CALL MUST EXECUTE QUICKLY and not *block*
 | 
			
		||||
					otherwise call_lvm function will fail to read
 | 
			
		||||
					stdin/stdout.  Return value of call back is ignored
 | 
			
		||||
	:param cb_data: Supplied to call back to allow caller access to
 | 
			
		||||
	:param cb_data: Supplied to callback to allow caller access to
 | 
			
		||||
								its own data
 | 
			
		||||
 | 
			
		||||
	# Callback signature
 | 
			
		||||
@@ -121,9 +106,6 @@ def call_lvm(command, debug=False, line_cb=None,
 | 
			
		||||
	command.insert(0, cfg.LVM_CMD)
 | 
			
		||||
	command = add_no_notify(command)
 | 
			
		||||
 | 
			
		||||
	# Ensure we get an error message when we fork & exec the lvm command line
 | 
			
		||||
	command = add_config_option(command, "--config", 'log/command_log_selection="log_context!=''"')
 | 
			
		||||
 | 
			
		||||
	process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
 | 
			
		||||
					env=os.environ)
 | 
			
		||||
 | 
			
		||||
@@ -133,10 +115,10 @@ def call_lvm(command, debug=False, line_cb=None,
 | 
			
		||||
	make_non_block(process.stdout)
 | 
			
		||||
	make_non_block(process.stderr)
 | 
			
		||||
 | 
			
		||||
	while True and cfg.run.value != 0:
 | 
			
		||||
	while True:
 | 
			
		||||
		try:
 | 
			
		||||
			rd_fd = [process.stdout.fileno(), process.stderr.fileno()]
 | 
			
		||||
			ready = select.select(rd_fd, [], [], cfg.G_LOOP_TMO)
 | 
			
		||||
			ready = select.select(rd_fd, [], [], 2)
 | 
			
		||||
 | 
			
		||||
			for r in ready[0]:
 | 
			
		||||
				if r == process.stdout.fileno():
 | 
			
		||||
@@ -151,8 +133,8 @@ def call_lvm(command, debug=False, line_cb=None,
 | 
			
		||||
					if i != -1:
 | 
			
		||||
						try:
 | 
			
		||||
							line_cb(cb_data, stdout_text[stdout_index:i])
 | 
			
		||||
						except BaseException as be:
 | 
			
		||||
							st = extract_stack_trace(be)
 | 
			
		||||
						except:
 | 
			
		||||
							st = traceback.format_exc()
 | 
			
		||||
							log_error("call_lvm: line_cb exception: \n %s" % st)
 | 
			
		||||
						stdout_index = i + 1
 | 
			
		||||
					else:
 | 
			
		||||
@@ -160,36 +142,15 @@ def call_lvm(command, debug=False, line_cb=None,
 | 
			
		||||
 | 
			
		||||
			# 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
 | 
			
		||||
			pass
 | 
			
		||||
 | 
			
		||||
	if process.returncode is not None:
 | 
			
		||||
		cfg.lvmdebug.lvm_complete()
 | 
			
		||||
		if debug or (process.returncode != 0 and (process.returncode != 5 and "fullreport" in command)):
 | 
			
		||||
			_debug_c(command, process.returncode, (stdout_text, stderr_text))
 | 
			
		||||
 | 
			
		||||
		try:
 | 
			
		||||
			report_json = json.loads(stdout_text)
 | 
			
		||||
		except json.decoder.JSONDecodeError:
 | 
			
		||||
			# Some lvm commands don't return json even though we are asking for it to do so.
 | 
			
		||||
			return process.returncode, stdout_text, stderr_text
 | 
			
		||||
 | 
			
		||||
		error_msg = get_error_msg(report_json)
 | 
			
		||||
		if error_msg:
 | 
			
		||||
			stderr_text += error_msg
 | 
			
		||||
 | 
			
		||||
		return process.returncode, report_json, stderr_text
 | 
			
		||||
	else:
 | 
			
		||||
		if cfg.run.value == 0:
 | 
			
		||||
			raise SystemExit
 | 
			
		||||
		# We can bail out before the lvm command finished when we get a signal
 | 
			
		||||
		# which is requesting we exit
 | 
			
		||||
		return -errno.EINTR, "", "operation interrupted"
 | 
			
		||||
	if debug or process.returncode != 0:
 | 
			
		||||
		_debug_c(command, process.returncode, (stdout_text, stderr_text))
 | 
			
		||||
 | 
			
		||||
	return process.returncode, stdout_text, stderr_text
 | 
			
		||||
 | 
			
		||||
# The actual method which gets called to invoke the lvm command, can vary
 | 
			
		||||
# from forking a new process to using lvm shell
 | 
			
		||||
@@ -204,18 +165,18 @@ def _shell_cfg():
 | 
			
		||||
		_t_call = lvm_shell.call_lvm
 | 
			
		||||
		cfg.SHELL_IN_USE = lvm_shell
 | 
			
		||||
		return True
 | 
			
		||||
	except Exception as e:
 | 
			
		||||
	except Exception:
 | 
			
		||||
		_t_call = call_lvm
 | 
			
		||||
		cfg.SHELL_IN_USE = None
 | 
			
		||||
		log_error("Unable to utilize lvm shell, dropping "
 | 
			
		||||
				  "back to fork & exec\n%s" % extract_stack_trace(e))
 | 
			
		||||
		log_error(traceback.format_exc())
 | 
			
		||||
		log_error("Unable to utilize lvm shell, dropping back to fork & exec")
 | 
			
		||||
		return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_execution(shell):
 | 
			
		||||
	global _t_call
 | 
			
		||||
	with cmd_lock:
 | 
			
		||||
		# If the user requested lvm shell, and we are currently setup that
 | 
			
		||||
		# If the user requested lvm shell and we are currently setup that
 | 
			
		||||
		# way, just return
 | 
			
		||||
		if cfg.SHELL_IN_USE and shell:
 | 
			
		||||
			return True
 | 
			
		||||
@@ -239,15 +200,11 @@ def time_wrapper(command, debug=False):
 | 
			
		||||
 | 
			
		||||
	with cmd_lock:
 | 
			
		||||
		start = time.time()
 | 
			
		||||
		meta = LvmExecutionMeta(start, 0, command)
 | 
			
		||||
		# Add the partial metadata to flight recorder, so if the command hangs
 | 
			
		||||
		# we will see what it was.
 | 
			
		||||
		cfg.flightrecorder.add(meta)
 | 
			
		||||
		results = _t_call(command, debug)
 | 
			
		||||
		ended = time.time()
 | 
			
		||||
		total_time += (ended - start)
 | 
			
		||||
		total_count += 1
 | 
			
		||||
		meta.completed(ended, *results)
 | 
			
		||||
		cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
 | 
			
		||||
	return results
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -257,11 +214,44 @@ call = time_wrapper
 | 
			
		||||
# Default cmd
 | 
			
		||||
# Place default arguments for every command here.
 | 
			
		||||
def _dc(cmd, args):
 | 
			
		||||
	c = [cmd, '--nosuffix', '--unbuffered', '--units', 'b']
 | 
			
		||||
	c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
 | 
			
		||||
		'--unbuffered', '--units', 'b']
 | 
			
		||||
	c.extend(args)
 | 
			
		||||
	return c
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def parse(out):
 | 
			
		||||
	rc = []
 | 
			
		||||
 | 
			
		||||
	for line in out.split('\n'):
 | 
			
		||||
		# This line includes separators, so process them
 | 
			
		||||
		if SEP in line:
 | 
			
		||||
			elem = line.split(SEP)
 | 
			
		||||
			cleaned_elem = []
 | 
			
		||||
			for e in elem:
 | 
			
		||||
				e = e.strip()
 | 
			
		||||
				cleaned_elem.append(e)
 | 
			
		||||
 | 
			
		||||
			if len(cleaned_elem) > 1:
 | 
			
		||||
				rc.append(cleaned_elem)
 | 
			
		||||
		else:
 | 
			
		||||
			t = line.strip()
 | 
			
		||||
			if len(t) > 0:
 | 
			
		||||
				rc.append(t)
 | 
			
		||||
	return rc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def parse_column_names(out, column_names):
 | 
			
		||||
	lines = parse(out)
 | 
			
		||||
	rc = []
 | 
			
		||||
 | 
			
		||||
	for i in range(0, len(lines)):
 | 
			
		||||
		d = dict(list(zip(column_names, lines[i])))
 | 
			
		||||
		rc.append(d)
 | 
			
		||||
 | 
			
		||||
	return rc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def options_to_cli_args(options):
 | 
			
		||||
	rc = []
 | 
			
		||||
	for k, v in list(dict(options).items()):
 | 
			
		||||
@@ -326,12 +316,10 @@ def vg_rename(vg_uuid, new_name, rename_options):
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def vg_remove(vg_id, remove_options):
 | 
			
		||||
def vg_remove(vg_name, remove_options):
 | 
			
		||||
	cmd = ['vgremove']
 | 
			
		||||
	cmd.extend(options_to_cli_args(remove_options))
 | 
			
		||||
	cmd.extend(['-f', vg_id])
 | 
			
		||||
	# https://bugzilla.redhat.com/show_bug.cgi?id=2175220 is preventing us from doing the following
 | 
			
		||||
	# cmd.extend(['-f', "--select", "vg_uuid=%s" % vg_id])
 | 
			
		||||
	cmd.extend(['-f', vg_name])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -554,14 +542,6 @@ def lv_vdo_deduplication(lv_path, enable, dedup_options):
 | 
			
		||||
	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():
 | 
			
		||||
	cmd = ['help']
 | 
			
		||||
	rc, out, err = call(cmd)
 | 
			
		||||
@@ -633,25 +613,68 @@ def lvm_full_report_json():
 | 
			
		||||
		'--configreport', 'vg', '-o', ','.join(vg_columns),
 | 
			
		||||
		'--configreport', 'lv', '-o', ','.join(lv_columns),
 | 
			
		||||
		'--configreport', 'seg', '-o', ','.join(lv_seg_columns),
 | 
			
		||||
		'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns)
 | 
			
		||||
		'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns),
 | 
			
		||||
		'--reportformat', 'json'
 | 
			
		||||
	])
 | 
			
		||||
 | 
			
		||||
	# We are running the fullreport command, we will ask lvm to output the debug
 | 
			
		||||
	# data, so we can have the required information for lvm to debug the fullreport failures.
 | 
			
		||||
	# Note: this is disabled by default and can be enabled with env. var.
 | 
			
		||||
	# LVM_DBUSD_COLLECT_LVM_DEBUG=True
 | 
			
		||||
	fn = cfg.lvmdebug.setup()
 | 
			
		||||
	if fn is not None:
 | 
			
		||||
		add_config_option(cmd, "--config", "log {level=7 file=%s syslog=0}" % fn)
 | 
			
		||||
 | 
			
		||||
	rc, out, err = call(cmd)
 | 
			
		||||
	# When we have an exported vg the exit code of lvs or fullreport will be 5
 | 
			
		||||
	if rc == 0 or rc == 5:
 | 
			
		||||
		if type(out) != dict:
 | 
			
		||||
			raise LvmBug("lvm likely returned invalid JSON, lvm exit code = %d, output = %s, err= %s" %
 | 
			
		||||
						 (rc, str(out), str(err)))
 | 
			
		||||
		return out
 | 
			
		||||
	raise LvmBug("'fullreport' exited with code '%d'" % rc)
 | 
			
		||||
		# With the current implementation, if we are using the shell then we
 | 
			
		||||
		# are using JSON and JSON is returned back to us as it was parsed to
 | 
			
		||||
		# figure out if we completed OK or not
 | 
			
		||||
		if cfg.SHELL_IN_USE:
 | 
			
		||||
			assert(type(out) == dict)
 | 
			
		||||
			return out
 | 
			
		||||
		else:
 | 
			
		||||
			try:
 | 
			
		||||
				return json.loads(out)
 | 
			
		||||
			except json.decoder.JSONDecodeError as joe:
 | 
			
		||||
				log_error("JSONDecodeError %s, \n JSON=\n%s\n" %
 | 
			
		||||
							(str(joe), out))
 | 
			
		||||
				raise joe
 | 
			
		||||
 | 
			
		||||
	return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def pv_retrieve_with_segs(device=None):
 | 
			
		||||
	d = []
 | 
			
		||||
	err = ""
 | 
			
		||||
	out = ""
 | 
			
		||||
	rc = 0
 | 
			
		||||
 | 
			
		||||
	columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
 | 
			
		||||
				'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
 | 
			
		||||
				'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
 | 
			
		||||
				'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
 | 
			
		||||
				'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing']
 | 
			
		||||
 | 
			
		||||
	# Lvm has some issues where it returns failure when querying pvs when other
 | 
			
		||||
	# operations are in process, see:
 | 
			
		||||
	# https://bugzilla.redhat.com/show_bug.cgi?id=1274085
 | 
			
		||||
	for i in range(0, 10):
 | 
			
		||||
		cmd = _dc('pvs', ['-o', ','.join(columns)])
 | 
			
		||||
 | 
			
		||||
		if device:
 | 
			
		||||
			cmd.extend(device)
 | 
			
		||||
 | 
			
		||||
		rc, out, err = call(cmd)
 | 
			
		||||
 | 
			
		||||
		if rc == 0:
 | 
			
		||||
			d = parse_column_names(out, columns)
 | 
			
		||||
			break
 | 
			
		||||
		else:
 | 
			
		||||
			time.sleep(0.2)
 | 
			
		||||
			log_debug("LVM Bug workaround, retrying pvs command...")
 | 
			
		||||
 | 
			
		||||
	if rc != 0:
 | 
			
		||||
		msg = "We were unable to get pvs to return without error after " \
 | 
			
		||||
			"trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \
 | 
			
		||||
			(rc, err, out)
 | 
			
		||||
		log_error(msg)
 | 
			
		||||
		raise RuntimeError(msg)
 | 
			
		||||
 | 
			
		||||
	return d
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def pv_resize(device, size_bytes, create_options):
 | 
			
		||||
@@ -797,10 +820,6 @@ def activate_deactivate(op, name, activate, control_flags, options):
 | 
			
		||||
		if (1 << 5) & control_flags:
 | 
			
		||||
			cmd.append('--ignoreactivationskip')
 | 
			
		||||
 | 
			
		||||
		# Shared locking (Cluster)
 | 
			
		||||
		if (1 << 6) & control_flags:
 | 
			
		||||
			op += 's'
 | 
			
		||||
 | 
			
		||||
	if activate:
 | 
			
		||||
		op += 'y'
 | 
			
		||||
	else:
 | 
			
		||||
@@ -812,6 +831,53 @@ def activate_deactivate(op, name, activate, control_flags, options):
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def vg_retrieve(vg_specific):
 | 
			
		||||
	if vg_specific:
 | 
			
		||||
		assert isinstance(vg_specific, list)
 | 
			
		||||
 | 
			
		||||
	columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free',
 | 
			
		||||
				'vg_sysid', 'vg_extent_size', 'vg_extent_count',
 | 
			
		||||
				'vg_free_count', 'vg_profile', 'max_lv', 'max_pv',
 | 
			
		||||
				'pv_count', 'lv_count', 'snap_count', 'vg_seqno',
 | 
			
		||||
				'vg_mda_count', 'vg_mda_free', 'vg_mda_size',
 | 
			
		||||
				'vg_mda_used_count', 'vg_attr', 'vg_tags']
 | 
			
		||||
 | 
			
		||||
	cmd = _dc('vgs', ['-o', ','.join(columns)])
 | 
			
		||||
 | 
			
		||||
	if vg_specific:
 | 
			
		||||
		cmd.extend(vg_specific)
 | 
			
		||||
 | 
			
		||||
	d = []
 | 
			
		||||
	rc, out, err = call(cmd)
 | 
			
		||||
	if rc == 0:
 | 
			
		||||
		d = parse_column_names(out, columns)
 | 
			
		||||
 | 
			
		||||
	return d
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def lv_retrieve_with_segments():
 | 
			
		||||
	columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size',
 | 
			
		||||
				'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid',
 | 
			
		||||
				'origin', 'data_percent',
 | 
			
		||||
				'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
 | 
			
		||||
				'metadata_lv', 'seg_pe_ranges', 'segtype', 'lv_parent',
 | 
			
		||||
				'lv_role', 'lv_layout',
 | 
			
		||||
				'snap_percent', 'metadata_percent', 'copy_percent',
 | 
			
		||||
				'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
 | 
			
		||||
 | 
			
		||||
	cmd = _dc('lvs', ['-a', '-o', ','.join(columns)])
 | 
			
		||||
	rc, out, err = call(cmd)
 | 
			
		||||
 | 
			
		||||
	d = []
 | 
			
		||||
 | 
			
		||||
	if rc == 0:
 | 
			
		||||
		d = parse_column_names(out, columns)
 | 
			
		||||
 | 
			
		||||
	return d
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
	# Leave this for future debug as needed
 | 
			
		||||
	pass
 | 
			
		||||
	pv_data = pv_retrieve_with_segs()
 | 
			
		||||
 | 
			
		||||
	for p in pv_data:
 | 
			
		||||
		print(str(p))
 | 
			
		||||
 
 | 
			
		||||
@@ -6,16 +6,16 @@
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
import errno
 | 
			
		||||
 | 
			
		||||
from .pv import load_pvs
 | 
			
		||||
from .vg import load_vgs
 | 
			
		||||
from .lv import load_lvs
 | 
			
		||||
from . import cfg
 | 
			
		||||
from .utils import MThreadRunner, log_debug, log_error, LvmBug, extract_stack_trace
 | 
			
		||||
from .utils import MThreadRunner, log_debug, log_error
 | 
			
		||||
import threading
 | 
			
		||||
import queue
 | 
			
		||||
import time
 | 
			
		||||
import traceback
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _main_thread_load(refresh=True, emit_signal=True):
 | 
			
		||||
@@ -120,125 +120,89 @@ class StateUpdate(object):
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def update_thread(obj):
 | 
			
		||||
		exception_count = 0
 | 
			
		||||
 | 
			
		||||
		queued_requests = []
 | 
			
		||||
 | 
			
		||||
		def set_results(val):
 | 
			
		||||
			nonlocal queued_requests
 | 
			
		||||
			for idx in queued_requests:
 | 
			
		||||
				idx.set_result(val)
 | 
			
		||||
				# Only clear out the requests after we have given them a result
 | 
			
		||||
				# otherwise we can orphan the waiting threads, and they never
 | 
			
		||||
				# wake up if we get an exception
 | 
			
		||||
				queued_requests = []
 | 
			
		||||
 | 
			
		||||
		def bailing(rv):
 | 
			
		||||
			set_results(rv)
 | 
			
		||||
			try:
 | 
			
		||||
				while True:
 | 
			
		||||
					item = obj.queue.get(False)
 | 
			
		||||
					item.set_result(rv)
 | 
			
		||||
			except queue.Empty:
 | 
			
		||||
				pass
 | 
			
		||||
 | 
			
		||||
		def _load_args(requests):
 | 
			
		||||
			"""
 | 
			
		||||
			If we have multiple requests in the queue, they might not all have the same options.  If any of the requests
 | 
			
		||||
			have an option set we need to honor it.
 | 
			
		||||
			"""
 | 
			
		||||
			refresh = any([r.refresh for r in requests])
 | 
			
		||||
			emit_signal = any([r.emit_signal for r in requests])
 | 
			
		||||
			cache_refresh = any([r.cache_refresh for r in requests])
 | 
			
		||||
			log = any([r.log for r in requests])
 | 
			
		||||
			need_main_thread = any([r.need_main_thread for r in requests])
 | 
			
		||||
 | 
			
		||||
			return refresh, emit_signal, cache_refresh, log, need_main_thread
 | 
			
		||||
 | 
			
		||||
		def _drain_queue(queued, incoming):
 | 
			
		||||
			try:
 | 
			
		||||
				while True:
 | 
			
		||||
					queued.append(incoming.get(block=False))
 | 
			
		||||
			except queue.Empty:
 | 
			
		||||
				pass
 | 
			
		||||
 | 
			
		||||
		def _handle_error():
 | 
			
		||||
			nonlocal exception_count
 | 
			
		||||
			exception_count += 1
 | 
			
		||||
 | 
			
		||||
			if exception_count >= 5:
 | 
			
		||||
				log_error("Too many errors in update_thread, exiting daemon")
 | 
			
		||||
				cfg.debug.dump()
 | 
			
		||||
				cfg.flightrecorder.dump()
 | 
			
		||||
				bailing(errno.EFAULT)
 | 
			
		||||
				cfg.exit_daemon()
 | 
			
		||||
			else:
 | 
			
		||||
				# Slow things down when encountering errors
 | 
			
		||||
				cfg.lvmdebug.complete()
 | 
			
		||||
				time.sleep(1)
 | 
			
		||||
 | 
			
		||||
		while cfg.run.value != 0:
 | 
			
		||||
			# noinspection PyBroadException
 | 
			
		||||
			try:
 | 
			
		||||
				refresh = True
 | 
			
		||||
				emit_signal = True
 | 
			
		||||
				cache_refresh = True
 | 
			
		||||
				log = True
 | 
			
		||||
				need_main_thread = True
 | 
			
		||||
 | 
			
		||||
				with obj.lock:
 | 
			
		||||
					wait = not obj.deferred
 | 
			
		||||
					obj.deferred = False
 | 
			
		||||
 | 
			
		||||
				if len(queued_requests) == 0 and wait:
 | 
			
		||||
					# Note: If we don't have anything for N seconds we will
 | 
			
		||||
					# get a queue.Empty exception raised here
 | 
			
		||||
					queued_requests.append(obj.queue.get(block=True, timeout=cfg.G_LOOP_TMO))
 | 
			
		||||
					queued_requests.append(obj.queue.get(True, 2))
 | 
			
		||||
 | 
			
		||||
				# Ok we have one or the deferred queue has some,
 | 
			
		||||
				# check if any others and grab them too
 | 
			
		||||
				_drain_queue(queued_requests, obj.queue)
 | 
			
		||||
				# check if any others
 | 
			
		||||
				try:
 | 
			
		||||
					while True:
 | 
			
		||||
						queued_requests.append(obj.queue.get(False))
 | 
			
		||||
 | 
			
		||||
				except queue.Empty:
 | 
			
		||||
					pass
 | 
			
		||||
 | 
			
		||||
				if len(queued_requests) > 1:
 | 
			
		||||
					log_debug("Processing %d updates!" % len(queued_requests),
 | 
			
		||||
							'bg_black', 'fg_light_green')
 | 
			
		||||
 | 
			
		||||
				num_changes = load(*_load_args(queued_requests))
 | 
			
		||||
				# We have what we can, run the update with the needed options
 | 
			
		||||
				for i in queued_requests:
 | 
			
		||||
					if not i.refresh:
 | 
			
		||||
						refresh = False
 | 
			
		||||
					if not i.emit_signal:
 | 
			
		||||
						emit_signal = False
 | 
			
		||||
					if not i.cache_refresh:
 | 
			
		||||
						cache_refresh = False
 | 
			
		||||
					if not i.log:
 | 
			
		||||
						log = False
 | 
			
		||||
					if not i.need_main_thread:
 | 
			
		||||
						need_main_thread = False
 | 
			
		||||
 | 
			
		||||
				num_changes = load(refresh, emit_signal, cache_refresh, log,
 | 
			
		||||
									need_main_thread)
 | 
			
		||||
				# Update is done, let everyone know!
 | 
			
		||||
				set_results(num_changes)
 | 
			
		||||
				for i in queued_requests:
 | 
			
		||||
					i.set_result(num_changes)
 | 
			
		||||
 | 
			
		||||
				# Only clear out the requests after we have given them a result
 | 
			
		||||
				# otherwise we can orphan the waiting threads and they never
 | 
			
		||||
				# wake up if we get an exception
 | 
			
		||||
				queued_requests = []
 | 
			
		||||
 | 
			
		||||
				# We retrieved OK, clear exception count
 | 
			
		||||
				exception_count = 0
 | 
			
		||||
 | 
			
		||||
			except queue.Empty:
 | 
			
		||||
				pass
 | 
			
		||||
			except SystemExit:
 | 
			
		||||
				break
 | 
			
		||||
			except LvmBug as bug:
 | 
			
		||||
				# If a lvm bug occurred, we will dump the lvm debug data if
 | 
			
		||||
				# we have it.
 | 
			
		||||
				cfg.lvmdebug.dump()
 | 
			
		||||
				log_error(str(bug))
 | 
			
		||||
				_handle_error()
 | 
			
		||||
			except Exception as e:
 | 
			
		||||
				log_error("update_thread: \n%s" % extract_stack_trace(e))
 | 
			
		||||
				_handle_error()
 | 
			
		||||
			finally:
 | 
			
		||||
				cfg.lvmdebug.complete()
 | 
			
		||||
				st = traceback.format_exc()
 | 
			
		||||
				log_error("update_thread exception: \n%s" % st)
 | 
			
		||||
				cfg.blackbox.dump()
 | 
			
		||||
				exception_count += 1
 | 
			
		||||
				if exception_count >= 5:
 | 
			
		||||
					for i in queued_requests:
 | 
			
		||||
						i.set_result(e)
 | 
			
		||||
 | 
			
		||||
		# Make sure to unblock any that may be waiting before we exit this thread
 | 
			
		||||
		# otherwise they hang forever ...
 | 
			
		||||
		bailing(Exception("update thread exiting"))
 | 
			
		||||
		log_debug("update thread exiting!")
 | 
			
		||||
					log_error("Too many errors in update_thread, exiting daemon")
 | 
			
		||||
					cfg.exit_daemon()
 | 
			
		||||
 | 
			
		||||
				else:
 | 
			
		||||
					# Slow things down when encountering errors
 | 
			
		||||
					time.sleep(1)
 | 
			
		||||
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		self.lock = threading.RLock()
 | 
			
		||||
		self.queue = queue.Queue()
 | 
			
		||||
		self.deferred = False
 | 
			
		||||
 | 
			
		||||
		# Do initial load, with retries.  During error injection testing we can and do fail here.
 | 
			
		||||
		count = 0
 | 
			
		||||
		need_refresh = False  # First attempt we are building from new, any subsequent will be true
 | 
			
		||||
		while count < 5:
 | 
			
		||||
			try:
 | 
			
		||||
				load(refresh=need_refresh, emit_signal=False, need_main_thread=False)
 | 
			
		||||
				break
 | 
			
		||||
			except LvmBug as bug:
 | 
			
		||||
				count += 1
 | 
			
		||||
				need_refresh = True
 | 
			
		||||
				log_error("We encountered an lvm bug on initial load, trying again %s" % str(bug))
 | 
			
		||||
		# Do initial load
 | 
			
		||||
		load(refresh=False, emit_signal=False, need_main_thread=False)
 | 
			
		||||
 | 
			
		||||
		self.thread = threading.Thread(target=StateUpdate.update_thread,
 | 
			
		||||
										args=(self,),
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ class WaitingClient(object):
 | 
			
		||||
			self.timer_id = GLib.timeout_add_seconds(
 | 
			
		||||
				tmo, WaitingClient._timeout, self)
 | 
			
		||||
 | 
			
		||||
	# The job finished before the timer popped, and we are being notified that
 | 
			
		||||
	# The job finished before the timer popped and we are being notified that
 | 
			
		||||
	# it's done
 | 
			
		||||
	def notify(self):
 | 
			
		||||
		with self.rlock:
 | 
			
		||||
@@ -71,7 +71,7 @@ class JobState(object):
 | 
			
		||||
		self._stderr = ''
 | 
			
		||||
		self._waiting_clients = []
 | 
			
		||||
 | 
			
		||||
		# This is a lvm command that is just taking too long and doesn't
 | 
			
		||||
		# This is an lvm command that is just taking too long and doesn't
 | 
			
		||||
		# support background operation
 | 
			
		||||
		if self._request:
 | 
			
		||||
			# Faking the percentage when we don't have one
 | 
			
		||||
@@ -138,7 +138,7 @@ class JobState(object):
 | 
			
		||||
		# If a waiting client timer pops before the job is done we will allow
 | 
			
		||||
		# the client to remove themselves from the list.  As we have a lock
 | 
			
		||||
		# here and a lock in the waiting client too, and they can be obtained
 | 
			
		||||
		# in different orders, a deadlock can occur.
 | 
			
		||||
		# in different orders, a dead lock can occur.
 | 
			
		||||
		# As this remove is really optional, we will try to acquire the lock
 | 
			
		||||
		# and remove.  If we are unsuccessful it's not fatal, we just delay
 | 
			
		||||
		# the time when the objects can be garbage collected by python
 | 
			
		||||
@@ -226,21 +226,3 @@ class Job(AutomatedProperties):
 | 
			
		||||
	def Uuid(self):
 | 
			
		||||
		import uuid
 | 
			
		||||
		return uuid.uuid1()
 | 
			
		||||
 | 
			
		||||
	# Override the property "getters" implementation for the job interface, so a user can query a job while the queue
 | 
			
		||||
	# is processing items.  Originally all the property get methods were this way, but we changed this in
 | 
			
		||||
	# e53454d6de07de56736303dd2157c3859f6fa848
 | 
			
		||||
 | 
			
		||||
	# Properties
 | 
			
		||||
	# noinspection PyUnusedLocal
 | 
			
		||||
	@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
 | 
			
		||||
						 in_signature='ss', out_signature='v')
 | 
			
		||||
	def Get(self, interface_name, property_name):
 | 
			
		||||
		# Note: If we get an exception in this handler we won't know about it,
 | 
			
		||||
		# only the side effect of no returned value!
 | 
			
		||||
		return AutomatedProperties._get_prop(self, interface_name, property_name)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
 | 
			
		||||
						 in_signature='s', out_signature='a{sv}')
 | 
			
		||||
	def GetAll(self, interface_name):
 | 
			
		||||
		return AutomatedProperties._get_all_prop(self, interface_name)
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ def common(retrieve, o_type, search_keys,
 | 
			
		||||
		existing_paths = cfg.om.object_paths_by_type(o_type)
 | 
			
		||||
 | 
			
		||||
	for o in objects:
 | 
			
		||||
		# Assume we need to add this one to dbus, unless we are refreshing,
 | 
			
		||||
		# Assume we need to add this one to dbus, unless we are refreshing
 | 
			
		||||
		# and it's already present
 | 
			
		||||
		return_object = True
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
from .automatedproperties import AutomatedProperties
 | 
			
		||||
 | 
			
		||||
from . import utils
 | 
			
		||||
from .utils import vg_obj_path_generate, log_error, _handle_execute, LvmBug
 | 
			
		||||
from .utils import vg_obj_path_generate, log_error, _handle_execute
 | 
			
		||||
import dbus
 | 
			
		||||
from . import cmdhandler
 | 
			
		||||
from . import cfg
 | 
			
		||||
@@ -21,12 +21,14 @@ from .utils import n, n32, d
 | 
			
		||||
from .loader import common
 | 
			
		||||
from .state import State
 | 
			
		||||
from . import background
 | 
			
		||||
from .utils import round_size, mt_remove_dbus_objects, lvm_column_key
 | 
			
		||||
from .utils import round_size, mt_remove_dbus_objects
 | 
			
		||||
from .job import JobState
 | 
			
		||||
 | 
			
		||||
import traceback
 | 
			
		||||
 | 
			
		||||
# Try and build a key for a LV, so that we sort the LVs with the least dependencies
 | 
			
		||||
# first.  This may be error-prone because of the flexibility LVM
 | 
			
		||||
 | 
			
		||||
# Try and build a key for a LV, so that we sort the LVs with least dependencies
 | 
			
		||||
# first.  This may be error prone because of the flexibility LVM
 | 
			
		||||
# provides and what you can stack.
 | 
			
		||||
def get_key(i):
 | 
			
		||||
 | 
			
		||||
@@ -65,80 +67,73 @@ def lvs_state_retrieve(selection, cache_refresh=True):
 | 
			
		||||
	if cache_refresh:
 | 
			
		||||
		cfg.db.refresh()
 | 
			
		||||
 | 
			
		||||
	try:
 | 
			
		||||
		# When building up the model, it's best to process LVs with the least
 | 
			
		||||
		# dependencies to those that are dependent upon other LVs.  Otherwise, when
 | 
			
		||||
		# we are trying to gather information we could be in a position where we
 | 
			
		||||
		# don't have information available yet.
 | 
			
		||||
		lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
 | 
			
		||||
	# When building up the model, it's best to process LVs with the least
 | 
			
		||||
	# dependencies to those that are dependant upon other LVs.  Otherwise, when
 | 
			
		||||
	# we are trying to gather information we could be in a position where we
 | 
			
		||||
	# don't have information available yet.
 | 
			
		||||
	lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
 | 
			
		||||
 | 
			
		||||
		for l in lvs:
 | 
			
		||||
			if cfg.vdo_support:
 | 
			
		||||
				rc.append(LvStateVdo(
 | 
			
		||||
					l['lv_uuid'], l['lv_name'],
 | 
			
		||||
					l['lv_path'], n(l['lv_size']),
 | 
			
		||||
					l['vg_name'],
 | 
			
		||||
					l['vg_uuid'], l['pool_lv_uuid'],
 | 
			
		||||
					l['pool_lv'], l['origin_uuid'], l['origin'],
 | 
			
		||||
					n32(l['data_percent']), l['lv_attr'],
 | 
			
		||||
					l['lv_tags'], l['lv_active'], l['data_lv'],
 | 
			
		||||
					l['metadata_lv'], l['segtype'], l['lv_role'],
 | 
			
		||||
					l['lv_layout'],
 | 
			
		||||
					n32(l['snap_percent']),
 | 
			
		||||
					n32(l['metadata_percent']),
 | 
			
		||||
					n32(l['copy_percent']),
 | 
			
		||||
					n32(l['sync_percent']),
 | 
			
		||||
					n(l['lv_metadata_size']),
 | 
			
		||||
					l['move_pv'],
 | 
			
		||||
					l['move_pv_uuid'],
 | 
			
		||||
					l['vdo_operating_mode'],
 | 
			
		||||
					l['vdo_compression_state'],
 | 
			
		||||
					l['vdo_index_state'],
 | 
			
		||||
					n(l['vdo_used_size']),
 | 
			
		||||
					d(l['vdo_saving_percent']),
 | 
			
		||||
					l['vdo_compression'],
 | 
			
		||||
					l['vdo_deduplication'],
 | 
			
		||||
					l['vdo_use_metadata_hints'],
 | 
			
		||||
					n32(l['vdo_minimum_io_size']),
 | 
			
		||||
					n(l['vdo_block_map_cache_size']),
 | 
			
		||||
					n32(l['vdo_block_map_era_length']),
 | 
			
		||||
					l['vdo_use_sparse_index'],
 | 
			
		||||
					n(l['vdo_index_memory_size']),
 | 
			
		||||
					n(l['vdo_slab_size']),
 | 
			
		||||
					n32(l['vdo_ack_threads']),
 | 
			
		||||
					n32(l['vdo_bio_threads']),
 | 
			
		||||
					n32(l['vdo_bio_rotation']),
 | 
			
		||||
					n32(l['vdo_cpu_threads']),
 | 
			
		||||
					n32(l['vdo_hash_zone_threads']),
 | 
			
		||||
					n32(l['vdo_logical_threads']),
 | 
			
		||||
					n32(l['vdo_physical_threads']),
 | 
			
		||||
					n32(l['vdo_max_discard']),
 | 
			
		||||
					l['vdo_write_policy'],
 | 
			
		||||
					n32(l['vdo_header_size'])))
 | 
			
		||||
			else:
 | 
			
		||||
				rc.append(LvState(
 | 
			
		||||
					l['lv_uuid'], l['lv_name'],
 | 
			
		||||
					l['lv_path'], n(l['lv_size']),
 | 
			
		||||
					l['vg_name'],
 | 
			
		||||
					l['vg_uuid'], l['pool_lv_uuid'],
 | 
			
		||||
					l['pool_lv'], l['origin_uuid'], l['origin'],
 | 
			
		||||
					n32(l['data_percent']), l['lv_attr'],
 | 
			
		||||
					l['lv_tags'], l['lv_active'], l['data_lv'],
 | 
			
		||||
					l['metadata_lv'], l['segtype'], l['lv_role'],
 | 
			
		||||
					l['lv_layout'],
 | 
			
		||||
					n32(l['snap_percent']),
 | 
			
		||||
					n32(l['metadata_percent']),
 | 
			
		||||
					n32(l['copy_percent']),
 | 
			
		||||
					n32(l['sync_percent']),
 | 
			
		||||
					n(l['lv_metadata_size']),
 | 
			
		||||
					l['move_pv'],
 | 
			
		||||
					l['move_pv_uuid']))
 | 
			
		||||
	except KeyError as ke:
 | 
			
		||||
		# Sometimes lvm omits returning one of the keys we requested.
 | 
			
		||||
		key = ke.args[0]
 | 
			
		||||
		if lvm_column_key(key):
 | 
			
		||||
			raise LvmBug("missing JSON key: '%s'" % key)
 | 
			
		||||
		raise ke
 | 
			
		||||
	for l in lvs:
 | 
			
		||||
		if cfg.vdo_support:
 | 
			
		||||
			rc.append(LvStateVdo(
 | 
			
		||||
				l['lv_uuid'], l['lv_name'],
 | 
			
		||||
				l['lv_path'], n(l['lv_size']),
 | 
			
		||||
				l['vg_name'],
 | 
			
		||||
				l['vg_uuid'], l['pool_lv_uuid'],
 | 
			
		||||
				l['pool_lv'], l['origin_uuid'], l['origin'],
 | 
			
		||||
				n32(l['data_percent']), l['lv_attr'],
 | 
			
		||||
				l['lv_tags'], l['lv_active'], l['data_lv'],
 | 
			
		||||
				l['metadata_lv'], l['segtype'], l['lv_role'],
 | 
			
		||||
				l['lv_layout'],
 | 
			
		||||
				n32(l['snap_percent']),
 | 
			
		||||
				n32(l['metadata_percent']),
 | 
			
		||||
				n32(l['copy_percent']),
 | 
			
		||||
				n32(l['sync_percent']),
 | 
			
		||||
				n(l['lv_metadata_size']),
 | 
			
		||||
				l['move_pv'],
 | 
			
		||||
				l['move_pv_uuid'],
 | 
			
		||||
				l['vdo_operating_mode'],
 | 
			
		||||
				l['vdo_compression_state'],
 | 
			
		||||
				l['vdo_index_state'],
 | 
			
		||||
				n(l['vdo_used_size']),
 | 
			
		||||
				d(l['vdo_saving_percent']),
 | 
			
		||||
				l['vdo_compression'],
 | 
			
		||||
				l['vdo_deduplication'],
 | 
			
		||||
				l['vdo_use_metadata_hints'],
 | 
			
		||||
				n32(l['vdo_minimum_io_size']),
 | 
			
		||||
				n(l['vdo_block_map_cache_size']),
 | 
			
		||||
				n32(l['vdo_block_map_era_length']),
 | 
			
		||||
				l['vdo_use_sparse_index'],
 | 
			
		||||
				n(l['vdo_index_memory_size']),
 | 
			
		||||
				n(l['vdo_slab_size']),
 | 
			
		||||
				n32(l['vdo_ack_threads']),
 | 
			
		||||
				n32(l['vdo_bio_threads']),
 | 
			
		||||
				n32(l['vdo_bio_rotation']),
 | 
			
		||||
				n32(l['vdo_cpu_threads']),
 | 
			
		||||
				n32(l['vdo_hash_zone_threads']),
 | 
			
		||||
				n32(l['vdo_logical_threads']),
 | 
			
		||||
				n32(l['vdo_physical_threads']),
 | 
			
		||||
				n32(l['vdo_max_discard']),
 | 
			
		||||
				l['vdo_write_policy'],
 | 
			
		||||
				n32(l['vdo_header_size'])))
 | 
			
		||||
		else:
 | 
			
		||||
			rc.append(LvState(
 | 
			
		||||
				l['lv_uuid'], l['lv_name'],
 | 
			
		||||
				l['lv_path'], n(l['lv_size']),
 | 
			
		||||
				l['vg_name'],
 | 
			
		||||
				l['vg_uuid'], l['pool_lv_uuid'],
 | 
			
		||||
				l['pool_lv'], l['origin_uuid'], l['origin'],
 | 
			
		||||
				n32(l['data_percent']), l['lv_attr'],
 | 
			
		||||
				l['lv_tags'], l['lv_active'], l['data_lv'],
 | 
			
		||||
				l['metadata_lv'], l['segtype'], l['lv_role'],
 | 
			
		||||
				l['lv_layout'],
 | 
			
		||||
				n32(l['snap_percent']),
 | 
			
		||||
				n32(l['metadata_percent']),
 | 
			
		||||
				n32(l['copy_percent']),
 | 
			
		||||
				n32(l['sync_percent']),
 | 
			
		||||
				n(l['lv_metadata_size']),
 | 
			
		||||
				l['move_pv'],
 | 
			
		||||
				l['move_pv_uuid']))
 | 
			
		||||
	return rc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -279,15 +274,15 @@ class LvStateVdo(LvState):
 | 
			
		||||
					MetaDataPercent, CopyPercent, SyncPercent,
 | 
			
		||||
					MetaDataSizeBytes, move_pv, move_pv_uuid,
 | 
			
		||||
					vdo_operating_mode, vdo_compression_state, vdo_index_state,
 | 
			
		||||
					vdo_used_size, vdo_saving_percent, vdo_compression,
 | 
			
		||||
					vdo_deduplication, vdo_use_metadata_hints,
 | 
			
		||||
					vdo_minimum_io_size, vdo_block_map_cache_size,
 | 
			
		||||
					vdo_block_map_era_length, vdo_use_sparse_index,
 | 
			
		||||
					vdo_index_memory_size, vdo_slab_size, vdo_ack_threads,
 | 
			
		||||
					vdo_bio_threads, vdo_bio_rotation, vdo_cpu_threads,
 | 
			
		||||
					vdo_hash_zone_threads, vdo_logical_threads,
 | 
			
		||||
					vdo_physical_threads, vdo_max_discard,
 | 
			
		||||
					vdo_write_policy, vdo_header_size):
 | 
			
		||||
					vdo_used_size,vdo_saving_percent,vdo_compression,
 | 
			
		||||
					vdo_deduplication,vdo_use_metadata_hints,
 | 
			
		||||
					vdo_minimum_io_size,vdo_block_map_cache_size,
 | 
			
		||||
					vdo_block_map_era_length,vdo_use_sparse_index,
 | 
			
		||||
					vdo_index_memory_size,vdo_slab_size,vdo_ack_threads,
 | 
			
		||||
					vdo_bio_threads,vdo_bio_rotation,vdo_cpu_threads,
 | 
			
		||||
					vdo_hash_zone_threads,vdo_logical_threads,
 | 
			
		||||
					vdo_physical_threads,vdo_max_discard,
 | 
			
		||||
					vdo_write_policy,vdo_header_size):
 | 
			
		||||
		super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
 | 
			
		||||
					vg_name, vg_uuid, pool_lv_uuid, PoolLv,
 | 
			
		||||
					origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
 | 
			
		||||
@@ -376,8 +371,8 @@ class LvCommon(AutomatedProperties):
 | 
			
		||||
			return dbus.Struct((self.state.Attr[index],
 | 
			
		||||
				type_map.get(self.state.Attr[index], default)),
 | 
			
		||||
								signature="(ss)")
 | 
			
		||||
		except BaseException as b:
 | 
			
		||||
			st = utils.extract_stack_trace(b)
 | 
			
		||||
		except BaseException:
 | 
			
		||||
			st = traceback.format_exc()
 | 
			
		||||
			log_error("attr_struct: \n%s" % st)
 | 
			
		||||
			return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
 | 
			
		||||
 | 
			
		||||
@@ -600,7 +595,7 @@ class Lv(LvCommon):
 | 
			
		||||
				optional_size = space + 512 - remainder
 | 
			
		||||
 | 
			
		||||
		LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
 | 
			
		||||
			lv_name, snapshot_options, name, optional_size))
 | 
			
		||||
			lv_name, snapshot_options,name, optional_size))
 | 
			
		||||
		full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
 | 
			
		||||
		return cfg.om.get_object_path_by_lvm_id(full_name)
 | 
			
		||||
 | 
			
		||||
@@ -640,7 +635,7 @@ class Lv(LvCommon):
 | 
			
		||||
 | 
			
		||||
		size_change = new_size_bytes - dbo.SizeBytes
 | 
			
		||||
		LvCommon.handle_execute(*cmdhandler.lv_resize(
 | 
			
		||||
			dbo.lvm_id, size_change, pv_dests, resize_options))
 | 
			
		||||
			dbo.lvm_id, size_change,pv_dests, resize_options))
 | 
			
		||||
		return "/"
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -749,7 +744,7 @@ class Lv(LvCommon):
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _caching_common(method, lv_uuid, lv_name, lv_object_path, cache_options):
 | 
			
		||||
	def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
 | 
			
		||||
 | 
			
		||||
@@ -758,7 +753,7 @@ class Lv(LvCommon):
 | 
			
		||||
 | 
			
		||||
		if lv_to_cache:
 | 
			
		||||
			fcn = lv_to_cache.lv_full_name()
 | 
			
		||||
			rc, out, err = method(
 | 
			
		||||
			rc, out, err = cmdhandler.lv_writecache_lv(
 | 
			
		||||
				dbo.lv_full_name(), fcn, cache_options)
 | 
			
		||||
			if rc == 0:
 | 
			
		||||
				# When we cache an LV, the cache pool and the lv that is getting
 | 
			
		||||
@@ -775,14 +770,9 @@ class Lv(LvCommon):
 | 
			
		||||
		else:
 | 
			
		||||
			raise dbus.exceptions.DBusException(
 | 
			
		||||
				LV_INTERFACE, 'LV to cache with object path %s not present!' %
 | 
			
		||||
							  lv_object_path)
 | 
			
		||||
				lv_object_path)
 | 
			
		||||
		return lv_converted
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
 | 
			
		||||
		return Lv._caching_common(cmdhandler.lv_writecache_lv, lv_uuid,
 | 
			
		||||
									lv_name, lv_object_path, cache_options)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
		dbus_interface=LV_INTERFACE,
 | 
			
		||||
		in_signature='oia{sv}',
 | 
			
		||||
@@ -795,39 +785,6 @@ class Lv(LvCommon):
 | 
			
		||||
			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')
 | 
			
		||||
@@ -888,10 +845,10 @@ class LvVdoPool(Lv):
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
		dbus_interface=VDO_POOL_INTERFACE,
 | 
			
		||||
		in_signature='ia{sv}',
 | 
			
		||||
		out_signature='o',
 | 
			
		||||
		async_callbacks=('cb', 'cbe'))
 | 
			
		||||
	dbus_interface=VDO_POOL_INTERFACE,
 | 
			
		||||
	in_signature='ia{sv}',
 | 
			
		||||
	out_signature='o',
 | 
			
		||||
	async_callbacks=('cb', 'cbe'))
 | 
			
		||||
	def DisableCompression(self, tmo, comp_options, cb, cbe):
 | 
			
		||||
		r = RequestEntry(
 | 
			
		||||
			tmo, LvVdoPool._enable_disable_compression,
 | 
			
		||||
@@ -921,10 +878,10 @@ class LvVdoPool(Lv):
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
		dbus_interface=VDO_POOL_INTERFACE,
 | 
			
		||||
		in_signature='ia{sv}',
 | 
			
		||||
		out_signature='o',
 | 
			
		||||
		async_callbacks=('cb', 'cbe'))
 | 
			
		||||
	dbus_interface=VDO_POOL_INTERFACE,
 | 
			
		||||
	in_signature='ia{sv}',
 | 
			
		||||
	out_signature='o',
 | 
			
		||||
	async_callbacks=('cb', 'cbe'))
 | 
			
		||||
	def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
 | 
			
		||||
		r = RequestEntry(
 | 
			
		||||
			tmo, LvVdoPool._enable_disable_deduplication,
 | 
			
		||||
@@ -995,8 +952,33 @@ class LvCachePool(Lv):
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
 | 
			
		||||
		return Lv._caching_common(cmdhandler.lv_cache_lv, lv_uuid, lv_name,
 | 
			
		||||
									lv_object_path, cache_options)
 | 
			
		||||
		# Make sure we have a dbus object representing cache pool
 | 
			
		||||
		dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
 | 
			
		||||
 | 
			
		||||
		# Make sure we have dbus object representing lv to cache
 | 
			
		||||
		lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
 | 
			
		||||
 | 
			
		||||
		if lv_to_cache:
 | 
			
		||||
			fcn = lv_to_cache.lv_full_name()
 | 
			
		||||
			rc, out, err = cmdhandler.lv_cache_lv(
 | 
			
		||||
				dbo.lv_full_name(), fcn, cache_options)
 | 
			
		||||
			if rc == 0:
 | 
			
		||||
				# When we cache an LV, the cache pool and the lv that is getting
 | 
			
		||||
				# cached need to be removed from the object manager and
 | 
			
		||||
				# re-created as their interfaces have changed!
 | 
			
		||||
				mt_remove_dbus_objects((dbo, lv_to_cache))
 | 
			
		||||
				cfg.load()
 | 
			
		||||
 | 
			
		||||
				lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
 | 
			
		||||
			else:
 | 
			
		||||
				raise dbus.exceptions.DBusException(
 | 
			
		||||
					LV_INTERFACE,
 | 
			
		||||
					'Exit code %s, stderr = %s' % (str(rc), err))
 | 
			
		||||
		else:
 | 
			
		||||
			raise dbus.exceptions.DBusException(
 | 
			
		||||
				LV_INTERFACE, 'LV to cache with object path %s not present!' %
 | 
			
		||||
				lv_object_path)
 | 
			
		||||
		return lv_converted
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
		dbus_interface=CACHE_POOL_INTERFACE,
 | 
			
		||||
 
 | 
			
		||||
@@ -14,12 +14,12 @@
 | 
			
		||||
import subprocess
 | 
			
		||||
import shlex
 | 
			
		||||
import os
 | 
			
		||||
import pty
 | 
			
		||||
import traceback
 | 
			
		||||
import sys
 | 
			
		||||
import tempfile
 | 
			
		||||
import time
 | 
			
		||||
import threading
 | 
			
		||||
import select
 | 
			
		||||
import copy
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
	import simplejson as json
 | 
			
		||||
@@ -27,9 +27,9 @@ except ImportError:
 | 
			
		||||
	import json
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import lvmdbusd.cfg as cfg
 | 
			
		||||
from lvmdbusd.cfg import LVM_CMD
 | 
			
		||||
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
 | 
			
		||||
			read_decoded, extract_stack_trace, LvmBug, get_error_msg
 | 
			
		||||
							read_decoded
 | 
			
		||||
 | 
			
		||||
SHELL_PROMPT = "lvm> "
 | 
			
		||||
 | 
			
		||||
@@ -43,11 +43,10 @@ def _quote_arg(arg):
 | 
			
		||||
 | 
			
		||||
class LVMShellProxy(object):
 | 
			
		||||
 | 
			
		||||
	# Read REPORT FD until we have a complete and valid JSON record or give
 | 
			
		||||
	# up trying to get one.
 | 
			
		||||
	#
 | 
			
		||||
	# Returns stdout, report (JSON), stderr
 | 
			
		||||
	def _read_response(self, no_output=False):
 | 
			
		||||
	# Read until we get prompt back and a result
 | 
			
		||||
	# @param: no_output	Caller expects no output to report FD
 | 
			
		||||
	# Returns stdout, report, stderr (report is JSON!)
 | 
			
		||||
	def _read_until_prompt(self, no_output=False):
 | 
			
		||||
		stdout = ""
 | 
			
		||||
		report = ""
 | 
			
		||||
		stderr = ""
 | 
			
		||||
@@ -59,27 +58,24 @@ class LVMShellProxy(object):
 | 
			
		||||
		# Try reading from all FDs to prevent one from filling up and causing
 | 
			
		||||
		# a hang.  Keep reading until we get the prompt back and the report
 | 
			
		||||
		# FD does not contain valid JSON
 | 
			
		||||
 | 
			
		||||
		while keep_reading and cfg.run.value != 0:
 | 
			
		||||
		while keep_reading:
 | 
			
		||||
			try:
 | 
			
		||||
				rd_fd = [
 | 
			
		||||
					self.parent_stdout_fd,
 | 
			
		||||
					self.lvm_shell.stdout.fileno(),
 | 
			
		||||
					self.report_stream.fileno(),
 | 
			
		||||
					self.parent_stderr_fd]
 | 
			
		||||
				ready = select.select(rd_fd, [], [], cfg.G_LOOP_TMO)
 | 
			
		||||
					self.lvm_shell.stderr.fileno()]
 | 
			
		||||
				ready = select.select(rd_fd, [], [], 2)
 | 
			
		||||
 | 
			
		||||
				for r in ready[0]:
 | 
			
		||||
					if r == self.parent_stdout_fd:
 | 
			
		||||
						for line in self.parent_stdout.readlines():
 | 
			
		||||
							stdout += line
 | 
			
		||||
					if r == self.lvm_shell.stdout.fileno():
 | 
			
		||||
						stdout += read_decoded(self.lvm_shell.stdout)
 | 
			
		||||
					elif r == self.report_stream.fileno():
 | 
			
		||||
						report += read_decoded(self.report_stream)
 | 
			
		||||
					elif r == self.parent_stderr_fd:
 | 
			
		||||
						for line in self.parent_stderr.readlines():
 | 
			
		||||
							stderr += line
 | 
			
		||||
					elif r == self.lvm_shell.stderr.fileno():
 | 
			
		||||
						stderr += read_decoded(self.lvm_shell.stderr)
 | 
			
		||||
 | 
			
		||||
				# Check to see if the lvm process died on us
 | 
			
		||||
				if self.lvm_shell.poll() is not None:
 | 
			
		||||
				if self.lvm_shell.poll():
 | 
			
		||||
					raise Exception(self.lvm_shell.returncode, "%s" % stderr)
 | 
			
		||||
 | 
			
		||||
				if stdout.endswith(SHELL_PROMPT):
 | 
			
		||||
@@ -103,106 +99,91 @@ class LVMShellProxy(object):
 | 
			
		||||
							extra_passes -= 1
 | 
			
		||||
							if extra_passes <= 0:
 | 
			
		||||
								if len(report):
 | 
			
		||||
									raise LvmBug("Invalid json: %s" %
 | 
			
		||||
									raise ValueError("Invalid json: %s" %
 | 
			
		||||
														report)
 | 
			
		||||
								else:
 | 
			
		||||
									raise LvmBug(
 | 
			
		||||
									raise ValueError(
 | 
			
		||||
										"lvm returned no JSON output!")
 | 
			
		||||
			except Exception as e:
 | 
			
		||||
				log_error("While reading from lvm shell we encountered an error %s" % str(e))
 | 
			
		||||
				log_error("stdout= %s\nstderr= %s\n" % (stdout, stderr))
 | 
			
		||||
				if self.lvm_shell.poll() is not None:
 | 
			
		||||
					log_error("Underlying lvm shell process unexpectedly exited: %d" % self.lvm_shell.returncode)
 | 
			
		||||
				else:
 | 
			
		||||
					log_error("Underlying lvm shell process is still present!")
 | 
			
		||||
				raise e
 | 
			
		||||
 | 
			
		||||
		if keep_reading and cfg.run.value == 0:
 | 
			
		||||
			# We didn't complete as we are shutting down
 | 
			
		||||
			# Try to clean up lvm shell process
 | 
			
		||||
			log_debug("exiting lvm shell as we are shutting down")
 | 
			
		||||
			self.exit_shell()
 | 
			
		||||
			raise SystemExit
 | 
			
		||||
			except IOError as ioe:
 | 
			
		||||
				log_debug(str(ioe))
 | 
			
		||||
				pass
 | 
			
		||||
 | 
			
		||||
		return stdout, report_json, stderr
 | 
			
		||||
 | 
			
		||||
	def _write_cmd(self, cmd):
 | 
			
		||||
		self.parent_stdin.write(cmd)
 | 
			
		||||
		self.parent_stdin.flush()
 | 
			
		||||
		cmd_bytes = bytes(cmd, "utf-8")
 | 
			
		||||
		num_written = self.lvm_shell.stdin.write(cmd_bytes)
 | 
			
		||||
		assert (num_written == len(cmd_bytes))
 | 
			
		||||
		self.lvm_shell.stdin.flush()
 | 
			
		||||
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
 | 
			
		||||
		# Create a temp directory
 | 
			
		||||
		tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
 | 
			
		||||
		tmp_file = "%s/lvmdbus_report" % (tmp_dir)
 | 
			
		||||
 | 
			
		||||
		# Create a lock so that we don't step on each other when we are waiting for a command
 | 
			
		||||
		# to finish and some other request comes in concurrently, like to exit the shell.
 | 
			
		||||
		self.shell_lock = threading.RLock()
 | 
			
		||||
		try:
 | 
			
		||||
			# Lets create fifo for the report output
 | 
			
		||||
			os.mkfifo(tmp_file, 0o600)
 | 
			
		||||
		except FileExistsError:
 | 
			
		||||
			pass
 | 
			
		||||
 | 
			
		||||
		# Create a fifo for the report output
 | 
			
		||||
		os.mkfifo(tmp_file, 0o600)
 | 
			
		||||
 | 
			
		||||
		# Open the fifo for use to read and for lvm child process to write to.
 | 
			
		||||
		# We have to open non-blocking as the other side isn't open until
 | 
			
		||||
		# we actually fork the process.
 | 
			
		||||
		self.report_fd = os.open(tmp_file, os.O_NONBLOCK)
 | 
			
		||||
		self.report_stream = os.fdopen(self.report_fd, 'rb', 0)
 | 
			
		||||
		lvm_fd = os.open(tmp_file, os.O_WRONLY)
 | 
			
		||||
 | 
			
		||||
		# Set up the environment for using our own socket for reporting and disable the abort
 | 
			
		||||
		# logic if lvm logs too much, which easily happens when utilizing the lvm shell.
 | 
			
		||||
		local_env = {"LC_ALL": "C", "LVM_REPORT_FD": "%s" % lvm_fd, "LVM_COMMAND_PROFILE": "lvmdbusd",
 | 
			
		||||
					 "LVM_LOG_FILE_MAX_LINES": "0"}
 | 
			
		||||
		# Setup the environment for using our own socket for reporting
 | 
			
		||||
		local_env = copy.deepcopy(os.environ)
 | 
			
		||||
		local_env["LVM_REPORT_FD"] = "32"
 | 
			
		||||
		local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd"
 | 
			
		||||
 | 
			
		||||
		# If any env variables contain LVM we will propagate them too
 | 
			
		||||
		for k, v in os.environ.items():
 | 
			
		||||
			if "PATH" in k:
 | 
			
		||||
				local_env[k] = v
 | 
			
		||||
			if "LVM" in k:
 | 
			
		||||
				local_env[k] = v
 | 
			
		||||
 | 
			
		||||
		self.parent_stdin_fd, child_stdin_fd = pty.openpty()
 | 
			
		||||
		self.parent_stdout_fd, child_stdout_fd = pty.openpty()
 | 
			
		||||
		self.parent_stderr_fd, child_stderr_fd = pty.openpty()
 | 
			
		||||
		self.parent_stdin = os.fdopen(self.parent_stdin_fd, "w")
 | 
			
		||||
		self.parent_stdout = os.fdopen(self.parent_stdout_fd, "r")
 | 
			
		||||
		self.parent_stderr = os.fdopen(self.parent_stderr_fd, "r")
 | 
			
		||||
		# Disable the abort logic if lvm logs too much, which easily happens
 | 
			
		||||
		# when utilizing the lvm shell.
 | 
			
		||||
		local_env["LVM_LOG_FILE_MAX_LINES"] = "0"
 | 
			
		||||
 | 
			
		||||
		# run the lvm shell
 | 
			
		||||
		self.lvm_shell = subprocess.Popen(
 | 
			
		||||
			[cfg.LVM_CMD],
 | 
			
		||||
			stdin=child_stdin_fd,
 | 
			
		||||
			stdout=child_stdout_fd, env=local_env,
 | 
			
		||||
			stderr=child_stderr_fd, close_fds=True,
 | 
			
		||||
			pass_fds=(lvm_fd,), shell=False)
 | 
			
		||||
			[LVM_CMD + " 32>%s" % tmp_file],
 | 
			
		||||
			stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env,
 | 
			
		||||
			stderr=subprocess.PIPE, close_fds=True, shell=True)
 | 
			
		||||
 | 
			
		||||
		try:
 | 
			
		||||
			make_non_block(self.parent_stdout_fd)
 | 
			
		||||
			make_non_block(self.parent_stderr_fd)
 | 
			
		||||
 | 
			
		||||
			# Close our copies of the child FDs there were created with the fork, we don't need them open.
 | 
			
		||||
			os.close(lvm_fd)
 | 
			
		||||
			os.close(child_stdin_fd)
 | 
			
		||||
			os.close(child_stdout_fd)
 | 
			
		||||
			os.close(child_stderr_fd)
 | 
			
		||||
			make_non_block(self.lvm_shell.stdout)
 | 
			
		||||
			make_non_block(self.lvm_shell.stderr)
 | 
			
		||||
 | 
			
		||||
			# wait for the first prompt
 | 
			
		||||
			log_debug("waiting for first prompt...")
 | 
			
		||||
			errors = self._read_response(no_output=True)[2]
 | 
			
		||||
			errors = self._read_until_prompt(no_output=True)[2]
 | 
			
		||||
			if errors and len(errors):
 | 
			
		||||
				raise LvmBug(errors)
 | 
			
		||||
			log_debug("lvm prompt read!!!")
 | 
			
		||||
				raise RuntimeError(errors)
 | 
			
		||||
		except:
 | 
			
		||||
			raise
 | 
			
		||||
		finally:
 | 
			
		||||
			# These will get deleted when the FD count goes to zero, so we
 | 
			
		||||
			# These will get deleted when the FD count goes to zero so we
 | 
			
		||||
			# can be sure to clean up correctly no matter how we finish
 | 
			
		||||
			os.unlink(tmp_file)
 | 
			
		||||
			os.rmdir(tmp_dir)
 | 
			
		||||
 | 
			
		||||
	def _get_last_log(self):
 | 
			
		||||
		# Precondition, lock is held
 | 
			
		||||
	def get_error_msg(self):
 | 
			
		||||
		# We got an error, lets go fetch the error message
 | 
			
		||||
		self._write_cmd('lastlog\n')
 | 
			
		||||
		report_json = self._read_response()[1]
 | 
			
		||||
		return get_error_msg(report_json)
 | 
			
		||||
 | 
			
		||||
		# read everything from the STDOUT to the next prompt
 | 
			
		||||
		stdout, report_json, stderr = self._read_until_prompt()
 | 
			
		||||
		if 'log' in report_json:
 | 
			
		||||
			error_msg = ""
 | 
			
		||||
			# Walk the entire log array and build an error string
 | 
			
		||||
			for log_entry in report_json['log']:
 | 
			
		||||
				if log_entry['log_type'] == "error":
 | 
			
		||||
					if error_msg:
 | 
			
		||||
						error_msg += ', ' + log_entry['log_message']
 | 
			
		||||
					else:
 | 
			
		||||
						error_msg = log_entry['log_message']
 | 
			
		||||
 | 
			
		||||
			return error_msg
 | 
			
		||||
 | 
			
		||||
		return 'No error reason provided! (missing "log" section)'
 | 
			
		||||
 | 
			
		||||
	def call_lvm(self, argv, debug=False):
 | 
			
		||||
		rc = 1
 | 
			
		||||
@@ -220,94 +201,60 @@ class LVMShellProxy(object):
 | 
			
		||||
		cmd += "\n"
 | 
			
		||||
 | 
			
		||||
		# run the command by writing it to the shell's STDIN
 | 
			
		||||
		with self.shell_lock:
 | 
			
		||||
			self._write_cmd(cmd)
 | 
			
		||||
		self._write_cmd(cmd)
 | 
			
		||||
 | 
			
		||||
			# read everything from the STDOUT to the next prompt
 | 
			
		||||
			stdout, report_json, stderr = self._read_response()
 | 
			
		||||
		# read everything from the STDOUT to the next prompt
 | 
			
		||||
		stdout, report_json, stderr = self._read_until_prompt()
 | 
			
		||||
 | 
			
		||||
			# Parse the report to see what happened
 | 
			
		||||
			if 'log' in report_json:
 | 
			
		||||
				ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
 | 
			
		||||
				# If we have an exported vg we get a log_ret_code == 5 when
 | 
			
		||||
				# we do a 'fullreport'
 | 
			
		||||
				# Note: 0 == error
 | 
			
		||||
				if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
 | 
			
		||||
					rc = 0
 | 
			
		||||
				else:
 | 
			
		||||
					# Depending on where lvm fails the command, it may not have anything
 | 
			
		||||
					# to report for "lastlog", so we need to check for a message in the
 | 
			
		||||
					# report json too.
 | 
			
		||||
					error_msg = self._get_last_log()
 | 
			
		||||
					if error_msg is None:
 | 
			
		||||
						error_msg = get_error_msg(report_json)
 | 
			
		||||
						if error_msg is None:
 | 
			
		||||
							error_msg = 'No error reason provided! (missing "log" section)'
 | 
			
		||||
		# Parse the report to see what happened
 | 
			
		||||
		if 'log' in report_json:
 | 
			
		||||
			ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
 | 
			
		||||
			# If we have an exported vg we get a log_ret_code == 5 when
 | 
			
		||||
			# we do a 'fullreport'
 | 
			
		||||
			if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
 | 
			
		||||
				rc = 0
 | 
			
		||||
			else:
 | 
			
		||||
				error_msg = self.get_error_msg()
 | 
			
		||||
 | 
			
		||||
		if debug or rc != 0:
 | 
			
		||||
			log_error(("CMD= %s" % cmd))
 | 
			
		||||
			log_error(("EC= %d" % rc))
 | 
			
		||||
			log_error(('CMD: %s' % cmd))
 | 
			
		||||
			log_error(("EC = %d" % rc))
 | 
			
		||||
			log_error(("ERROR_MSG=\n %s\n" % error_msg))
 | 
			
		||||
 | 
			
		||||
		return rc, report_json, error_msg
 | 
			
		||||
 | 
			
		||||
	def exit_shell(self):
 | 
			
		||||
		with self.shell_lock:
 | 
			
		||||
			try:
 | 
			
		||||
				if self.lvm_shell is not None:
 | 
			
		||||
					self._write_cmd('exit\n')
 | 
			
		||||
					self.lvm_shell.wait(1)
 | 
			
		||||
					self.lvm_shell = None
 | 
			
		||||
			except Exception as _e:
 | 
			
		||||
				log_error("exit_shell: %s" % (str(_e)))
 | 
			
		||||
		try:
 | 
			
		||||
			self._write_cmd('exit\n')
 | 
			
		||||
		except Exception as e:
 | 
			
		||||
			log_error(str(e))
 | 
			
		||||
 | 
			
		||||
	def __del__(self):
 | 
			
		||||
		# Note: When we are shutting down the daemon and the main process has already exited
 | 
			
		||||
		# and this gets called we have a limited set of things we can do, like we cannot call
 | 
			
		||||
		# log_error as _common_log is None!!!
 | 
			
		||||
		if self.lvm_shell is not None:
 | 
			
		||||
			try:
 | 
			
		||||
				self.lvm_shell.wait(1)
 | 
			
		||||
			except subprocess.TimeoutExpired:
 | 
			
		||||
				print("lvm shell child process did not exit as instructed, sending SIGTERM")
 | 
			
		||||
				cfg.ignore_sigterm = True
 | 
			
		||||
				self.lvm_shell.terminate()
 | 
			
		||||
				child_exit_code = self.lvm_shell.wait(1)
 | 
			
		||||
				print("lvm shell process exited with %d" % child_exit_code)
 | 
			
		||||
		try:
 | 
			
		||||
			self.lvm_shell.terminate()
 | 
			
		||||
		except:
 | 
			
		||||
			pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
	print("USING LVM BINARY: %s " % cfg.LVM_CMD)
 | 
			
		||||
 | 
			
		||||
	shell = LVMShellProxy()
 | 
			
		||||
	in_line = "start"
 | 
			
		||||
	try:
 | 
			
		||||
		if len(sys.argv) > 1 and sys.argv[1] == "bisect":
 | 
			
		||||
			shell = LVMShellProxy()
 | 
			
		||||
			shell.exit_shell()
 | 
			
		||||
		else:
 | 
			
		||||
			shell = LVMShellProxy()
 | 
			
		||||
			in_line = "start"
 | 
			
		||||
			try:
 | 
			
		||||
				while in_line:
 | 
			
		||||
					in_line = input("lvm> ")
 | 
			
		||||
					if in_line:
 | 
			
		||||
						if in_line == "exit":
 | 
			
		||||
							shell.exit_shell()
 | 
			
		||||
							sys.exit(0)
 | 
			
		||||
						start = time.time()
 | 
			
		||||
						ret, out, err = shell.call_lvm(in_line.split())
 | 
			
		||||
						end = time.time()
 | 
			
		||||
		while in_line:
 | 
			
		||||
			in_line = input("lvm> ")
 | 
			
		||||
			if in_line:
 | 
			
		||||
				start = time.time()
 | 
			
		||||
				ret, out, err = shell.call_lvm(in_line.split())
 | 
			
		||||
				end = time.time()
 | 
			
		||||
 | 
			
		||||
						print(("RC: %d" % ret))
 | 
			
		||||
						print(("OUT:\n%s" % out))
 | 
			
		||||
						print(("ERR:\n%s" % err))
 | 
			
		||||
				print(("RC: %d" % ret))
 | 
			
		||||
				print(("OUT:\n%s" % out))
 | 
			
		||||
				print(("ERR:\n%s" % err))
 | 
			
		||||
 | 
			
		||||
						print("Command     = %f seconds" % (end - start))
 | 
			
		||||
			except KeyboardInterrupt:
 | 
			
		||||
				pass
 | 
			
		||||
			except EOFError:
 | 
			
		||||
				pass
 | 
			
		||||
	except Exception as e:
 | 
			
		||||
		log_error("main process exiting on exception!\n%s" % extract_stack_trace(e))
 | 
			
		||||
		sys.exit(1)
 | 
			
		||||
 | 
			
		||||
	sys.exit(0)
 | 
			
		||||
				print("Command     = %f seconds" % (end - start))
 | 
			
		||||
	except KeyboardInterrupt:
 | 
			
		||||
		pass
 | 
			
		||||
	except EOFError:
 | 
			
		||||
		pass
 | 
			
		||||
	except Exception:
 | 
			
		||||
		traceback.print_exc(file=sys.stdout)
 | 
			
		||||
 
 | 
			
		||||
@@ -13,13 +13,14 @@ from collections import OrderedDict
 | 
			
		||||
 | 
			
		||||
import pprint as prettyprint
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
from lvmdbusd import cmdhandler
 | 
			
		||||
from lvmdbusd.utils import log_debug, log_error, lvm_column_key, LvmBug
 | 
			
		||||
from lvmdbusd.utils import log_debug, log_error
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DataStore(object):
 | 
			
		||||
	def __init__(self, vdo_support=False):
 | 
			
		||||
	def __init__(self, usejson=True, vdo_support=False):
 | 
			
		||||
		self.pvs = {}
 | 
			
		||||
		self.vgs = {}
 | 
			
		||||
		self.lvs = {}
 | 
			
		||||
@@ -34,9 +35,41 @@ class DataStore(object):
 | 
			
		||||
		self.lvs_in_vgs = {}
 | 
			
		||||
		self.pvs_in_vgs = {}
 | 
			
		||||
 | 
			
		||||
		# self.refresh()
 | 
			
		||||
		self.num_refreshes = 0
 | 
			
		||||
 | 
			
		||||
		if usejson:
 | 
			
		||||
			self.json = cmdhandler.supports_json()
 | 
			
		||||
		else:
 | 
			
		||||
			self.json = usejson
 | 
			
		||||
 | 
			
		||||
		self.vdo_support = vdo_support
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _insert_record(table, key, record, allowed_multiple):
 | 
			
		||||
		if key in table:
 | 
			
		||||
			existing = table[key]
 | 
			
		||||
 | 
			
		||||
			for rec_k, rec_v in record.items():
 | 
			
		||||
				if rec_k in allowed_multiple:
 | 
			
		||||
					# This column name allows us to store multiple value for
 | 
			
		||||
					# each type
 | 
			
		||||
					if not isinstance(existing[rec_k], list):
 | 
			
		||||
						existing_value = existing[rec_k]
 | 
			
		||||
						existing[rec_k] = [existing_value, rec_v]
 | 
			
		||||
					else:
 | 
			
		||||
						existing[rec_k].append(rec_v)
 | 
			
		||||
				else:
 | 
			
		||||
					# If something is not expected to have changing values
 | 
			
		||||
					# lets ensure that
 | 
			
		||||
					if existing[rec_k] != rec_v:
 | 
			
		||||
						raise RuntimeError(
 | 
			
		||||
							"existing[%s]=%s != %s" %
 | 
			
		||||
							(rec_k, str(existing[rec_k]),
 | 
			
		||||
							str(rec_v)))
 | 
			
		||||
		else:
 | 
			
		||||
			table[key] = record
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup):
 | 
			
		||||
		for p in c_pvs.values():
 | 
			
		||||
@@ -51,6 +84,22 @@ class DataStore(object):
 | 
			
		||||
			# Lookup for translating between /dev/<name> and pv uuid
 | 
			
		||||
			c_lookup[p['pv_name']] = p['pv_uuid']
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _parse_pvs(_pvs):
 | 
			
		||||
		pvs = sorted(_pvs, key=lambda pk: pk['pv_name'])
 | 
			
		||||
 | 
			
		||||
		c_pvs = OrderedDict()
 | 
			
		||||
		c_lookup = {}
 | 
			
		||||
		c_pvs_in_vgs = {}
 | 
			
		||||
 | 
			
		||||
		for p in pvs:
 | 
			
		||||
			DataStore._insert_record(
 | 
			
		||||
				c_pvs, p['pv_uuid'], p,
 | 
			
		||||
				['pvseg_start', 'pvseg_size', 'segtype'])
 | 
			
		||||
 | 
			
		||||
		DataStore._pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup)
 | 
			
		||||
		return c_pvs, c_lookup, c_pvs_in_vgs
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _parse_pvs_json(_all):
 | 
			
		||||
 | 
			
		||||
@@ -58,7 +107,7 @@ class DataStore(object):
 | 
			
		||||
		c_lookup = {}
 | 
			
		||||
		c_pvs_in_vgs = {}
 | 
			
		||||
 | 
			
		||||
		# Each item in the report is a collection of information pertaining
 | 
			
		||||
		# Each item item in the report is a collection of information pertaining
 | 
			
		||||
		# to the vg
 | 
			
		||||
		for r in _all['report']:
 | 
			
		||||
			tmp_pv = []
 | 
			
		||||
@@ -92,6 +141,28 @@ class DataStore(object):
 | 
			
		||||
 | 
			
		||||
		return c_pvs, c_lookup, c_pvs_in_vgs
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _parse_vgs(_vgs):
 | 
			
		||||
		vgs = sorted(_vgs, key=lambda vk: vk['vg_uuid'])
 | 
			
		||||
 | 
			
		||||
		c_vgs = OrderedDict()
 | 
			
		||||
		c_lookup = {}
 | 
			
		||||
 | 
			
		||||
		for i in vgs:
 | 
			
		||||
			vg_name = i['vg_name']
 | 
			
		||||
 | 
			
		||||
			# Lvm allows duplicate vg names.  When this occurs, each subsequent
 | 
			
		||||
			# matching VG name will be called vg_name:vg_uuid.  Note: ':' is an
 | 
			
		||||
			# invalid character for lvm VG names
 | 
			
		||||
			if vg_name in c_lookup:
 | 
			
		||||
				vg_name = "%s:%s" % (vg_name, i['vg_uuid'])
 | 
			
		||||
				i['vg_name'] = vg_name
 | 
			
		||||
 | 
			
		||||
			c_lookup[vg_name] = i['vg_uuid']
 | 
			
		||||
			DataStore._insert_record(c_vgs, i['vg_uuid'], i, [])
 | 
			
		||||
 | 
			
		||||
		return c_vgs, c_lookup
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _parse_vgs_json(_all):
 | 
			
		||||
 | 
			
		||||
@@ -156,12 +227,28 @@ class DataStore(object):
 | 
			
		||||
 | 
			
		||||
		return c_lvs, c_lvs_in_vgs, c_lvs_hidden, c_lv_full_lookup
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _parse_lvs(_lvs):
 | 
			
		||||
		lvs = sorted(_lvs, key=lambda vk: vk['lv_name'])
 | 
			
		||||
 | 
			
		||||
		c_lvs = OrderedDict()
 | 
			
		||||
		c_lv_full_lookup = OrderedDict()
 | 
			
		||||
 | 
			
		||||
		for i in lvs:
 | 
			
		||||
			full_name = "%s/%s" % (i['vg_name'], i['lv_name'])
 | 
			
		||||
			c_lv_full_lookup[full_name] = i['lv_uuid']
 | 
			
		||||
			DataStore._insert_record(
 | 
			
		||||
				c_lvs, i['lv_uuid'], i,
 | 
			
		||||
				['seg_pe_ranges', 'segtype'])
 | 
			
		||||
 | 
			
		||||
		return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
 | 
			
		||||
 | 
			
		||||
	def _parse_lvs_json(self, _all):
 | 
			
		||||
 | 
			
		||||
		c_lvs = OrderedDict()
 | 
			
		||||
		c_lv_full_lookup = {}
 | 
			
		||||
 | 
			
		||||
		# Each item in the report is a collection of information pertaining
 | 
			
		||||
		# Each item item in the report is a collection of information pertaining
 | 
			
		||||
		# to the vg
 | 
			
		||||
		for r in _all['report']:
 | 
			
		||||
			# Get the lv data for this VG.
 | 
			
		||||
@@ -309,12 +396,12 @@ class DataStore(object):
 | 
			
		||||
		:param log  Add debug log entry/exit messages
 | 
			
		||||
		:return: None
 | 
			
		||||
		"""
 | 
			
		||||
		try:
 | 
			
		||||
			self.num_refreshes += 1
 | 
			
		||||
			if log:
 | 
			
		||||
				log_debug("lvmdb - refresh entry")
 | 
			
		||||
		self.num_refreshes += 1
 | 
			
		||||
		if log:
 | 
			
		||||
			log_debug("lvmdb - refresh entry")
 | 
			
		||||
 | 
			
		||||
			# Grab everything first then parse it
 | 
			
		||||
		# Grab everything first then parse it
 | 
			
		||||
		if self.json:
 | 
			
		||||
			# Do a single lvm retrieve for everything in json
 | 
			
		||||
			a = cmdhandler.lvm_full_report_json()
 | 
			
		||||
 | 
			
		||||
@@ -322,25 +409,29 @@ class DataStore(object):
 | 
			
		||||
			_vgs, _vgs_lookup = self._parse_vgs_json(a)
 | 
			
		||||
			_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs_json(a)
 | 
			
		||||
 | 
			
		||||
			# Set all
 | 
			
		||||
			self.pvs = _pvs
 | 
			
		||||
			self.pv_path_to_uuid = _pvs_lookup
 | 
			
		||||
			self.vg_name_to_uuid = _vgs_lookup
 | 
			
		||||
			self.lv_full_name_to_uuid = _lvs_lookup
 | 
			
		||||
		else:
 | 
			
		||||
			_raw_pvs = cmdhandler.pv_retrieve_with_segs()
 | 
			
		||||
			_raw_vgs = cmdhandler.vg_retrieve(None)
 | 
			
		||||
			_raw_lvs = cmdhandler.lv_retrieve_with_segments()
 | 
			
		||||
 | 
			
		||||
			self.vgs = _vgs
 | 
			
		||||
			self.lvs = _lvs
 | 
			
		||||
			self.lvs_in_vgs = _lvs_in_vgs
 | 
			
		||||
			self.pvs_in_vgs = _pvs_in_vgs
 | 
			
		||||
			self.lvs_hidden = _lvs_hidden
 | 
			
		||||
			_pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs(_raw_pvs)
 | 
			
		||||
			_vgs, _vgs_lookup = self._parse_vgs(_raw_vgs)
 | 
			
		||||
			_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs(_raw_lvs)
 | 
			
		||||
 | 
			
		||||
			# Create lookup table for which LV and segments are on each PV
 | 
			
		||||
			self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
 | 
			
		||||
		except KeyError as ke:
 | 
			
		||||
			key = ke.args[0]
 | 
			
		||||
			if lvm_column_key(key):
 | 
			
		||||
				raise LvmBug("missing JSON key: '%s'" % key)
 | 
			
		||||
			raise ke
 | 
			
		||||
		# Set all
 | 
			
		||||
		self.pvs = _pvs
 | 
			
		||||
		self.pv_path_to_uuid = _pvs_lookup
 | 
			
		||||
		self.vg_name_to_uuid = _vgs_lookup
 | 
			
		||||
		self.lv_full_name_to_uuid = _lvs_lookup
 | 
			
		||||
 | 
			
		||||
		self.vgs = _vgs
 | 
			
		||||
		self.lvs = _lvs
 | 
			
		||||
		self.lvs_in_vgs = _lvs_in_vgs
 | 
			
		||||
		self.pvs_in_vgs = _pvs_in_vgs
 | 
			
		||||
		self.lvs_hidden = _lvs_hidden
 | 
			
		||||
 | 
			
		||||
		# Create lookup table for which LV and segments are on each PV
 | 
			
		||||
		self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
 | 
			
		||||
 | 
			
		||||
		if log:
 | 
			
		||||
			log_debug("lvmdb - refresh exit")
 | 
			
		||||
@@ -351,7 +442,7 @@ class DataStore(object):
 | 
			
		||||
		else:
 | 
			
		||||
			rc = []
 | 
			
		||||
			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
 | 
			
		||||
				# if the pv name isn't in the lookup
 | 
			
		||||
				if s not in self.pv_path_to_uuid:
 | 
			
		||||
@@ -360,13 +451,10 @@ class DataStore(object):
 | 
			
		||||
			return rc
 | 
			
		||||
 | 
			
		||||
	def pv_missing(self, pv_uuid):
 | 
			
		||||
		# The uuid might not be a PV, default to false
 | 
			
		||||
		if pv_uuid in self.pvs:
 | 
			
		||||
			if self.pvs[pv_uuid]['pv_missing'] == '':
 | 
			
		||||
				return False
 | 
			
		||||
			else:
 | 
			
		||||
				return True
 | 
			
		||||
		return False
 | 
			
		||||
		return True
 | 
			
		||||
 | 
			
		||||
	def fetch_vgs(self, vg_name):
 | 
			
		||||
		if not vg_name:
 | 
			
		||||
@@ -437,11 +525,15 @@ class DataStore(object):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
	os.environ["LC_ALL"] = "C"
 | 
			
		||||
	os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
 | 
			
		||||
	pp = prettyprint.PrettyPrinter(indent=4)
 | 
			
		||||
 | 
			
		||||
	ds = DataStore()
 | 
			
		||||
	use_json = False
 | 
			
		||||
 | 
			
		||||
	if len(sys.argv) != 1:
 | 
			
		||||
		print(len(sys.argv))
 | 
			
		||||
		use_json = True
 | 
			
		||||
 | 
			
		||||
	ds = DataStore(use_json)
 | 
			
		||||
	ds.refresh()
 | 
			
		||||
 | 
			
		||||
	print("PVS")
 | 
			
		||||
 
 | 
			
		||||
@@ -22,13 +22,14 @@ from . import lvmdb
 | 
			
		||||
from gi.repository import GLib
 | 
			
		||||
from .fetch import StateUpdate
 | 
			
		||||
from .manager import Manager
 | 
			
		||||
import traceback
 | 
			
		||||
import queue
 | 
			
		||||
from . import udevwatch
 | 
			
		||||
from .utils import log_debug, log_error, log_msg, DebugMessages
 | 
			
		||||
from .utils import log_debug, log_error
 | 
			
		||||
import argparse
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
from .cmdhandler import LvmFlightRecorder, supports_vdo, supports_json
 | 
			
		||||
from .cmdhandler import LvmFlightRecorder, supports_vdo
 | 
			
		||||
from .request import RequestEntry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -41,7 +42,7 @@ def process_request():
 | 
			
		||||
	while cfg.run.value != 0:
 | 
			
		||||
		# noinspection PyBroadException
 | 
			
		||||
		try:
 | 
			
		||||
			req = cfg.worker_q.get(True, cfg.G_LOOP_TMO)
 | 
			
		||||
			req = cfg.worker_q.get(True, 5)
 | 
			
		||||
			log_debug(
 | 
			
		||||
				"Method start: %s with args %s (callback = %s)" %
 | 
			
		||||
				(str(req.method), str(req.arguments), str(req.cb)))
 | 
			
		||||
@@ -49,15 +50,12 @@ def process_request():
 | 
			
		||||
			log_debug("Method complete: %s" % str(req.method))
 | 
			
		||||
		except queue.Empty:
 | 
			
		||||
			pass
 | 
			
		||||
		except SystemExit:
 | 
			
		||||
			break
 | 
			
		||||
		except Exception as e:
 | 
			
		||||
			st = utils.extract_stack_trace(e)
 | 
			
		||||
		except Exception:
 | 
			
		||||
			st = traceback.format_exc()
 | 
			
		||||
			utils.log_error("process_request exception: \n%s" % st)
 | 
			
		||||
	log_debug("process_request thread exiting!")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def check_fr_size(value):
 | 
			
		||||
def check_bb_size(value):
 | 
			
		||||
	v = int(value)
 | 
			
		||||
	if v < 0:
 | 
			
		||||
		raise argparse.ArgumentTypeError(
 | 
			
		||||
@@ -67,7 +65,7 @@ def check_fr_size(value):
 | 
			
		||||
 | 
			
		||||
def install_signal_handlers():
 | 
			
		||||
	# Because of the glib main loop stuff the python signal handler code is
 | 
			
		||||
	# apparently not usable, and we need to use the glib calls instead
 | 
			
		||||
	# apparently not usable and we need to use the glib calls instead
 | 
			
		||||
	signal_add = None
 | 
			
		||||
 | 
			
		||||
	if hasattr(GLib, 'unix_signal_add'):
 | 
			
		||||
@@ -79,13 +77,13 @@ def install_signal_handlers():
 | 
			
		||||
		signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP, utils.handler, signal.SIGHUP)
 | 
			
		||||
		signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, utils.handler, signal.SIGINT)
 | 
			
		||||
		signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR1, utils.handler, signal.SIGUSR1)
 | 
			
		||||
		signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR2, utils.handler, signal.SIGUSR2)
 | 
			
		||||
		signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, utils.handler, signal.SIGTERM)
 | 
			
		||||
	else:
 | 
			
		||||
		log_error("GLib.unix_signal_[add|add_full] are NOT available!")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def process_args():
 | 
			
		||||
def main():
 | 
			
		||||
	start = time.time()
 | 
			
		||||
	# Add simple command line handling
 | 
			
		||||
	parser = argparse.ArgumentParser()
 | 
			
		||||
	parser.add_argument(
 | 
			
		||||
		"--udev", action='store_true',
 | 
			
		||||
@@ -106,137 +104,101 @@ def process_args():
 | 
			
		||||
		default=False,
 | 
			
		||||
		dest='use_lvm_shell')
 | 
			
		||||
	parser.add_argument(
 | 
			
		||||
		"--frsize",
 | 
			
		||||
		help="Size of the flight recorder (num. entries), 0 to disable (signal 12 to dump)",
 | 
			
		||||
		"--blackboxsize",
 | 
			
		||||
		help="Size of the black box flight recorder, 0 to disable",
 | 
			
		||||
		default=10,
 | 
			
		||||
		type=check_fr_size,
 | 
			
		||||
		dest='fr_size')
 | 
			
		||||
		type=check_bb_size,
 | 
			
		||||
		dest='bb_size')
 | 
			
		||||
 | 
			
		||||
	args = parser.parse_args()
 | 
			
		||||
	use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
 | 
			
		||||
 | 
			
		||||
	if not args.use_json:
 | 
			
		||||
		log_error("Daemon no longer supports lvm without JSON support, exiting!")
 | 
			
		||||
		sys.exit(1)
 | 
			
		||||
	else:
 | 
			
		||||
		if not supports_json():
 | 
			
		||||
			log_error("Un-supported version of LVM, daemon requires JSON output, exiting!")
 | 
			
		||||
			sys.exit(1)
 | 
			
		||||
 | 
			
		||||
	# Add udev watching
 | 
			
		||||
	if args.use_udev:
 | 
			
		||||
		# Make sure this msg ends up in the journal, so we know
 | 
			
		||||
		log_msg('The --udev option is no longer supported,'
 | 
			
		||||
				'the daemon always uses a combination of dbus notify from lvm tools and udev')
 | 
			
		||||
 | 
			
		||||
	return args
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def running_under_systemd():
 | 
			
		||||
	""""
 | 
			
		||||
	Checks to see if we are running under systemd, by checking 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.
 | 
			
		||||
	# Ensure that we get consistent output for parsing stdout/stderr
 | 
			
		||||
	os.environ["LC_ALL"] = "C"
 | 
			
		||||
	os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
 | 
			
		||||
 | 
			
		||||
	# Indicator if we are running under systemd
 | 
			
		||||
	cfg.systemd = running_under_systemd()
 | 
			
		||||
 | 
			
		||||
	# Add simple command line handling
 | 
			
		||||
	cfg.args = process_args()
 | 
			
		||||
 | 
			
		||||
	cfg.args = parser.parse_args()
 | 
			
		||||
	cfg.create_request_entry = RequestEntry
 | 
			
		||||
 | 
			
		||||
	# We create a flight recorder in cmdhandler too, but we replace it here
 | 
			
		||||
	# as the user may be specifying a different size.  The default one in
 | 
			
		||||
	# cmdhandler is for when we are running other code with a different main.
 | 
			
		||||
	cfg.flightrecorder = LvmFlightRecorder(cfg.args.fr_size)
 | 
			
		||||
	cfg.blackbox = LvmFlightRecorder(cfg.args.bb_size)
 | 
			
		||||
 | 
			
		||||
	# Create a circular buffer for debug logs
 | 
			
		||||
	cfg.debug = DebugMessages()
 | 
			
		||||
 | 
			
		||||
	log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
 | 
			
		||||
	if cfg.args.use_lvm_shell and not cfg.args.use_json:
 | 
			
		||||
		log_error("You cannot specify --lvmshell and --nojson")
 | 
			
		||||
		sys.exit(1)
 | 
			
		||||
 | 
			
		||||
	# We will dynamically add interfaces which support vdo if it
 | 
			
		||||
	# exists.
 | 
			
		||||
	cfg.vdo_support = supports_vdo()
 | 
			
		||||
 | 
			
		||||
	if cfg.vdo_support and not cfg.args.use_json:
 | 
			
		||||
		log_error("You cannot specify --nojson when lvm has VDO support")
 | 
			
		||||
		sys.exit(1)
 | 
			
		||||
 | 
			
		||||
	# List of threads that we start up
 | 
			
		||||
	thread_list = []
 | 
			
		||||
 | 
			
		||||
	install_signal_handlers()
 | 
			
		||||
 | 
			
		||||
	with utils.LockFile(cfg.LOCK_FILE):
 | 
			
		||||
		dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 | 
			
		||||
		dbus.mainloop.glib.threads_init()
 | 
			
		||||
	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 | 
			
		||||
	dbus.mainloop.glib.threads_init()
 | 
			
		||||
 | 
			
		||||
		cmdhandler.set_execution(cfg.args.use_lvm_shell)
 | 
			
		||||
	cmdhandler.set_execution(cfg.args.use_lvm_shell)
 | 
			
		||||
 | 
			
		||||
		if use_session:
 | 
			
		||||
			cfg.bus = dbus.SessionBus()
 | 
			
		||||
		else:
 | 
			
		||||
			cfg.bus = dbus.SystemBus()
 | 
			
		||||
		# The base name variable needs to exist for things to work.
 | 
			
		||||
		# noinspection PyUnusedLocal
 | 
			
		||||
		base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
 | 
			
		||||
		cfg.om = Lvm(BASE_OBJ_PATH)
 | 
			
		||||
		cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
 | 
			
		||||
	if use_session:
 | 
			
		||||
		cfg.bus = dbus.SessionBus()
 | 
			
		||||
	else:
 | 
			
		||||
		cfg.bus = dbus.SystemBus()
 | 
			
		||||
	# The base name variable needs to exist for things to work.
 | 
			
		||||
	# noinspection PyUnusedLocal
 | 
			
		||||
	base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
 | 
			
		||||
	cfg.om = Lvm(BASE_OBJ_PATH)
 | 
			
		||||
	cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
 | 
			
		||||
 | 
			
		||||
		cfg.db = lvmdb.DataStore(vdo_support=cfg.vdo_support)
 | 
			
		||||
	cfg.db = lvmdb.DataStore(cfg.args.use_json, cfg.vdo_support)
 | 
			
		||||
 | 
			
		||||
		# Using a thread to process requests, we cannot hang the dbus library
 | 
			
		||||
		# thread that is handling the dbus interface
 | 
			
		||||
		thread_list.append(
 | 
			
		||||
			threading.Thread(target=process_request, name='process_request'))
 | 
			
		||||
	# Using a thread to process requests, we cannot hang the dbus library
 | 
			
		||||
	# thread that is handling the dbus interface
 | 
			
		||||
	thread_list.append(
 | 
			
		||||
		threading.Thread(target=process_request, name='process_request'))
 | 
			
		||||
 | 
			
		||||
		# Have a single thread handling updating lvm and the dbus model, so we
 | 
			
		||||
		# don't have multiple threads doing this as the same time
 | 
			
		||||
		updater = StateUpdate()
 | 
			
		||||
		thread_list.append(updater.thread)
 | 
			
		||||
	# Have a single thread handling updating lvm and the dbus model so we
 | 
			
		||||
	# don't have multiple threads doing this as the same time
 | 
			
		||||
	updater = StateUpdate()
 | 
			
		||||
	thread_list.append(updater.thread)
 | 
			
		||||
 | 
			
		||||
		cfg.load = updater.load
 | 
			
		||||
	cfg.load = updater.load
 | 
			
		||||
 | 
			
		||||
		cfg.loop = GLib.MainLoop()
 | 
			
		||||
	cfg.loop = GLib.MainLoop()
 | 
			
		||||
 | 
			
		||||
		for thread in thread_list:
 | 
			
		||||
			thread.daemon = True
 | 
			
		||||
			thread.start()
 | 
			
		||||
	for thread in thread_list:
 | 
			
		||||
		thread.damon = True
 | 
			
		||||
		thread.start()
 | 
			
		||||
 | 
			
		||||
		# In all cases we are going to monitor for udev until we get an
 | 
			
		||||
		# ExternalEvent.  In the case where we get an external event and the user
 | 
			
		||||
		# didn't specify --udev we will stop monitoring udev
 | 
			
		||||
		udevwatch.add()
 | 
			
		||||
	# Add udev watching
 | 
			
		||||
	if cfg.args.use_udev:
 | 
			
		||||
		log_debug('Utilizing udev to trigger updates')
 | 
			
		||||
 | 
			
		||||
		end = time.time()
 | 
			
		||||
		log_debug(
 | 
			
		||||
			'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
 | 
			
		||||
			(end - start, cmdhandler.total_time, cmdhandler.total_count),
 | 
			
		||||
			'bg_black', 'fg_light_green')
 | 
			
		||||
	# In all cases we are going to monitor for udev until we get an
 | 
			
		||||
	# ExternalEvent.  In the case where we get an external event and the user
 | 
			
		||||
	# didn't specify --udev we will stop monitoring udev
 | 
			
		||||
	udevwatch.add()
 | 
			
		||||
 | 
			
		||||
		try:
 | 
			
		||||
			if cfg.run.value != 0:
 | 
			
		||||
				cfg.loop.run()
 | 
			
		||||
				udevwatch.remove()
 | 
			
		||||
	end = time.time()
 | 
			
		||||
	log_debug(
 | 
			
		||||
		'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
 | 
			
		||||
		(end - start, cmdhandler.total_time, cmdhandler.total_count),
 | 
			
		||||
		'bg_black', 'fg_light_green')
 | 
			
		||||
 | 
			
		||||
				for thread in thread_list:
 | 
			
		||||
					thread.join()
 | 
			
		||||
		except KeyboardInterrupt:
 | 
			
		||||
			# If we are unable to register signal handler, we will end up here when
 | 
			
		||||
			# the service gets a ^C or a kill -2 <parent pid>
 | 
			
		||||
			utils.handler(signal.SIGINT)
 | 
			
		||||
	try:
 | 
			
		||||
		if cfg.run.value != 0:
 | 
			
		||||
			cfg.loop.run()
 | 
			
		||||
			udevwatch.remove()
 | 
			
		||||
 | 
			
		||||
			for thread in thread_list:
 | 
			
		||||
				thread.join()
 | 
			
		||||
	except KeyboardInterrupt:
 | 
			
		||||
		# If we are unable to register signal handler, we will end up here when
 | 
			
		||||
		# the service gets a ^C or a kill -2 <parent pid>
 | 
			
		||||
		utils.handler(signal.SIGINT)
 | 
			
		||||
	return 0
 | 
			
		||||
 
 | 
			
		||||
@@ -137,8 +137,7 @@ class Manager(AutomatedProperties):
 | 
			
		||||
		"""
 | 
			
		||||
		Dump the flight recorder to syslog
 | 
			
		||||
		"""
 | 
			
		||||
		cfg.debug.dump()
 | 
			
		||||
		cfg.flightrecorder.dump()
 | 
			
		||||
		cfg.blackbox.dump()
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _lookup_by_lvm_id(key):
 | 
			
		||||
@@ -195,7 +194,6 @@ class Manager(AutomatedProperties):
 | 
			
		||||
	def _external_event(command):
 | 
			
		||||
		utils.log_debug("Processing _external_event= %s" % command,
 | 
			
		||||
							'bg_black', 'fg_orange')
 | 
			
		||||
		cfg.got_external_event = True
 | 
			
		||||
		cfg.load()
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -203,6 +201,14 @@ class Manager(AutomatedProperties):
 | 
			
		||||
		in_signature='s', out_signature='i')
 | 
			
		||||
	def ExternalEvent(self, command):
 | 
			
		||||
		utils.log_debug("ExternalEvent %s" % command)
 | 
			
		||||
		# If a user didn't explicitly specify udev, we will turn it off now.
 | 
			
		||||
		if not cfg.args.use_udev:
 | 
			
		||||
			if udevwatch.remove():
 | 
			
		||||
				utils.log_debug("ExternalEvent received, disabling "
 | 
			
		||||
								"udev monitoring")
 | 
			
		||||
				# We are dependent on external events now to stay current!
 | 
			
		||||
				cfg.got_external_event = True
 | 
			
		||||
 | 
			
		||||
		r = RequestEntry(
 | 
			
		||||
			-1, Manager._external_event, (command,), None, None, False)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,11 +9,12 @@
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import threading
 | 
			
		||||
import traceback
 | 
			
		||||
import dbus
 | 
			
		||||
import os
 | 
			
		||||
import copy
 | 
			
		||||
from . import cfg
 | 
			
		||||
from .utils import log_debug, log_error, extract_stack_trace
 | 
			
		||||
from .utils import log_debug, pv_obj_path_generate, log_error
 | 
			
		||||
from .automatedproperties import AutomatedProperties
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -39,8 +40,8 @@ class ObjectManager(AutomatedProperties):
 | 
			
		||||
				for k, v in list(obj._objects.items()):
 | 
			
		||||
					path, props = v[0].emit_data()
 | 
			
		||||
					rc[path] = props
 | 
			
		||||
			except Exception as e:
 | 
			
		||||
				log_error("_get_managed_objects exception, bailing: \n%s" % extract_stack_trace(e))
 | 
			
		||||
			except Exception:
 | 
			
		||||
				traceback.print_exc(file=sys.stdout)
 | 
			
		||||
				sys.exit(1)
 | 
			
		||||
			return rc
 | 
			
		||||
 | 
			
		||||
@@ -52,6 +53,15 @@ class ObjectManager(AutomatedProperties):
 | 
			
		||||
									(self, ), cb, cbe, False)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
	def locked(self):
 | 
			
		||||
		"""
 | 
			
		||||
		If some external code need to run across a number of different
 | 
			
		||||
		calls into ObjectManager while blocking others they can use this method
 | 
			
		||||
		to lock others out.
 | 
			
		||||
		:return:
 | 
			
		||||
		"""
 | 
			
		||||
		return ObjectManagerLock(self.rlock)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.signal(
 | 
			
		||||
		dbus_interface="org.freedesktop.DBus.ObjectManager",
 | 
			
		||||
		signature='oa{sa{sv}}')
 | 
			
		||||
@@ -159,8 +169,8 @@ class ObjectManager(AutomatedProperties):
 | 
			
		||||
			# print('Registering object path %s for %s' %
 | 
			
		||||
			# (path, dbus_object.lvm_id))
 | 
			
		||||
 | 
			
		||||
			# We want fast access to the object by a number of different ways,
 | 
			
		||||
			# so we use multiple hashes with different keys
 | 
			
		||||
			# We want fast access to the object by a number of different ways
 | 
			
		||||
			# so we use multiple hashs with different keys
 | 
			
		||||
			self._lookup_add(dbus_object, path, dbus_object.lvm_id,
 | 
			
		||||
				dbus_object.Uuid)
 | 
			
		||||
 | 
			
		||||
@@ -209,7 +219,7 @@ class ObjectManager(AutomatedProperties):
 | 
			
		||||
 | 
			
		||||
	def get_object_by_lvm_id(self, lvm_id):
 | 
			
		||||
		"""
 | 
			
		||||
		Given a lvm identifier, return the object registered for it
 | 
			
		||||
		Given an lvm identifier, return the object registered for it
 | 
			
		||||
		:param lvm_id: The lvm identifier
 | 
			
		||||
		"""
 | 
			
		||||
		with self.rlock:
 | 
			
		||||
@@ -220,7 +230,7 @@ class ObjectManager(AutomatedProperties):
 | 
			
		||||
 | 
			
		||||
	def get_object_path_by_lvm_id(self, lvm_id):
 | 
			
		||||
		"""
 | 
			
		||||
		Given a lvm identifier, return the object path for it
 | 
			
		||||
		Given an lvm identifier, return the object path for it
 | 
			
		||||
		:param lvm_id: The lvm identifier
 | 
			
		||||
		:return: Object path or '/' if not found
 | 
			
		||||
		"""
 | 
			
		||||
@@ -272,12 +282,12 @@ class ObjectManager(AutomatedProperties):
 | 
			
		||||
		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
 | 
			
		||||
		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
 | 
			
		||||
		register it with the object manager for the specified uuid & lvm_id.
 | 
			
		||||
		Note: If path create is not None, uuid and lvm_id cannot be equal
 | 
			
		||||
		:param uuid: The uuid for the lvm object we are searching for
 | 
			
		||||
		:param lvm_id: The lvm name (e.g. pv device path, vg name, lv full name)
 | 
			
		||||
		:param lvm_id: The lvm name (eg. pv device path, vg name, lv full name)
 | 
			
		||||
		:param path_create: If not None, create the path using this function if
 | 
			
		||||
				we fail to find the object by uuid or lvm_id.
 | 
			
		||||
		:returns None if lvm asset not found and path_create == None otherwise
 | 
			
		||||
@@ -295,17 +305,18 @@ class ObjectManager(AutomatedProperties):
 | 
			
		||||
			if uuid == lvm_id:
 | 
			
		||||
				path = self._id_lookup(lvm_id)
 | 
			
		||||
			else:
 | 
			
		||||
				# We have 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
 | 
			
		||||
 | 
			
		||||
				# If a PV is missing its device path is '[unknown]' or some
 | 
			
		||||
				# If a PV is missing it's device path is '[unknown]' or some
 | 
			
		||||
				# other text derivation of unknown.  When we find that a PV is
 | 
			
		||||
				# missing we will clear out the lvm_id as it's not unique
 | 
			
		||||
				# and thus not useful and harmful for lookups.
 | 
			
		||||
				if cfg.db.pv_missing(uuid):
 | 
			
		||||
				# missing we will clear out the lvm_id as it's likely not unique
 | 
			
		||||
				# and thus not useful and potentially harmful for lookups.
 | 
			
		||||
				if path_create == pv_obj_path_generate and \
 | 
			
		||||
						cfg.db.pv_missing(uuid):
 | 
			
		||||
					lvm_id = None
 | 
			
		||||
 | 
			
		||||
				# Let's check for the uuid first
 | 
			
		||||
				# Lets check for the uuid first
 | 
			
		||||
				path = self._id_lookup(uuid)
 | 
			
		||||
				if path:
 | 
			
		||||
					# Ensure table lookups are correct
 | 
			
		||||
@@ -326,3 +337,29 @@ class ObjectManager(AutomatedProperties):
 | 
			
		||||
			#	(uuid, lvm_id, str(path_create), path))
 | 
			
		||||
 | 
			
		||||
			return path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ObjectManagerLock(object):
 | 
			
		||||
	"""
 | 
			
		||||
	The sole purpose of this class is to allow other code the ability to
 | 
			
		||||
	lock the object manager using a `with` statement, eg.
 | 
			
		||||
 | 
			
		||||
	with cfg.om.locked():
 | 
			
		||||
		# Do stuff with object manager
 | 
			
		||||
 | 
			
		||||
	This will ensure that the lock is always released (assuming this is done
 | 
			
		||||
	correctly)
 | 
			
		||||
	"""
 | 
			
		||||
 | 
			
		||||
	def __init__(self, recursive_lock):
 | 
			
		||||
		self._lock = recursive_lock
 | 
			
		||||
 | 
			
		||||
	def __enter__(self):
 | 
			
		||||
		# Acquire lock
 | 
			
		||||
		self._lock.acquire()
 | 
			
		||||
 | 
			
		||||
	# noinspection PyUnusedLocal
 | 
			
		||||
	def __exit__(self, e_type, e_value, e_traceback):
 | 
			
		||||
		# Release lock
 | 
			
		||||
		self._lock.release()
 | 
			
		||||
		self._lock = None
 | 
			
		||||
 
 | 
			
		||||
@@ -14,11 +14,11 @@ import dbus
 | 
			
		||||
from .cfg import PV_INTERFACE
 | 
			
		||||
from . import cmdhandler
 | 
			
		||||
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
 | 
			
		||||
	lv_object_path_method, _handle_execute, lvm_column_key
 | 
			
		||||
	lv_object_path_method, _handle_execute
 | 
			
		||||
from .loader import common
 | 
			
		||||
from .request import RequestEntry
 | 
			
		||||
from .state import State
 | 
			
		||||
from .utils import round_size, LvmBug
 | 
			
		||||
from .utils import round_size
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# noinspection PyUnusedLocal
 | 
			
		||||
@@ -28,23 +28,16 @@ def pvs_state_retrieve(selection, cache_refresh=True):
 | 
			
		||||
	if cache_refresh:
 | 
			
		||||
		cfg.db.refresh()
 | 
			
		||||
 | 
			
		||||
	try:
 | 
			
		||||
		for p in cfg.db.fetch_pvs(selection):
 | 
			
		||||
			rc.append(
 | 
			
		||||
				PvState(
 | 
			
		||||
					p["pv_name"], p["pv_uuid"], p["pv_name"],
 | 
			
		||||
					p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]),
 | 
			
		||||
					n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]),
 | 
			
		||||
					n(p["pv_mda_free"]), int(p["pv_ba_start"]),
 | 
			
		||||
					n(p["pv_ba_size"]), n(p["pe_start"]),
 | 
			
		||||
					int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
 | 
			
		||||
					p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
 | 
			
		||||
	except KeyError as ke:
 | 
			
		||||
		# Sometimes lvm omits returning one of the keys we requested.
 | 
			
		||||
		key = ke.args[0]
 | 
			
		||||
		if lvm_column_key(key):
 | 
			
		||||
			raise LvmBug("missing JSON key: '%s'" % key)
 | 
			
		||||
		raise ke
 | 
			
		||||
	for p in cfg.db.fetch_pvs(selection):
 | 
			
		||||
		rc.append(
 | 
			
		||||
			PvState(
 | 
			
		||||
				p["pv_name"], p["pv_uuid"], p["pv_name"],
 | 
			
		||||
				p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]),
 | 
			
		||||
				n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]),
 | 
			
		||||
				n(p["pv_mda_free"]), int(p["pv_ba_start"]),
 | 
			
		||||
				n(p["pv_ba_size"]), n(p["pe_start"]),
 | 
			
		||||
				int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
 | 
			
		||||
				p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
 | 
			
		||||
	return rc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,13 +7,13 @@
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import dbus
 | 
			
		||||
import threading
 | 
			
		||||
# noinspection PyUnresolvedReferences
 | 
			
		||||
from gi.repository import GLib
 | 
			
		||||
from .job import Job
 | 
			
		||||
from . import cfg
 | 
			
		||||
from .utils import log_error, mt_async_call, extract_stack_trace
 | 
			
		||||
import traceback
 | 
			
		||||
from .utils import log_error, mt_async_call
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RequestEntry(object):
 | 
			
		||||
@@ -71,23 +71,13 @@ class RequestEntry(object):
 | 
			
		||||
		try:
 | 
			
		||||
			result = self.method(*self.arguments)
 | 
			
		||||
			self.register_result(result)
 | 
			
		||||
		except SystemExit as se:
 | 
			
		||||
			self.register_error(-1, str(se), se)
 | 
			
		||||
			raise se
 | 
			
		||||
		except dbus.exceptions.DBusException as dbe:
 | 
			
		||||
			# This is an expected error path when something goes awry that
 | 
			
		||||
			# we handled
 | 
			
		||||
			self.register_error(-1, str(dbe), dbe)
 | 
			
		||||
		except Exception as e:
 | 
			
		||||
			# Use the request entry to return the result as the client may
 | 
			
		||||
			# have gotten a job by the time we hit an error
 | 
			
		||||
			# Lets set the exception text as the error message and log the
 | 
			
		||||
			# exception in the journal for figuring out what went wrong.
 | 
			
		||||
			cfg.debug.dump()
 | 
			
		||||
			cfg.flightrecorder.dump()
 | 
			
		||||
			tb = extract_stack_trace(e)
 | 
			
		||||
			log_error("While processing %s: we encountered\n%s" % (str(self.method), tb))
 | 
			
		||||
			log_error("Error returned to client: %s" % str(e))
 | 
			
		||||
			# Lets get the stacktrace and set that to the error message
 | 
			
		||||
			st = traceback.format_exc()
 | 
			
		||||
			cfg.blackbox.dump()
 | 
			
		||||
			log_error("Exception returned to client: \n%s" % st)
 | 
			
		||||
			self.register_error(-1, str(e), e)
 | 
			
		||||
 | 
			
		||||
	def is_done(self):
 | 
			
		||||
@@ -141,7 +131,7 @@ class RequestEntry(object):
 | 
			
		||||
 | 
			
		||||
						mt_async_call(self.cb_error, error_exception)
 | 
			
		||||
			else:
 | 
			
		||||
				# We have a job, and it's complete, indicate that it's done.
 | 
			
		||||
				# We have a job and it's complete, indicate that it's done.
 | 
			
		||||
				self._job.Complete = True
 | 
			
		||||
				self._job = None
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
@@ -9,7 +9,6 @@
 | 
			
		||||
 | 
			
		||||
import pyudev
 | 
			
		||||
import threading
 | 
			
		||||
import os
 | 
			
		||||
from . import cfg
 | 
			
		||||
from .request import RequestEntry
 | 
			
		||||
from . import utils
 | 
			
		||||
@@ -53,79 +52,20 @@ def filter_event(action, device):
 | 
			
		||||
	# when appropriate.
 | 
			
		||||
	refresh = False
 | 
			
		||||
 | 
			
		||||
	# Debug: Uncomment to log all udev events
 | 
			
		||||
	#devlinks_str = device.get('DEVLINKS', '')
 | 
			
		||||
	#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 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 == '':
 | 
			
		||||
			# Check to see if the device was one we knew about
 | 
			
		||||
			if 'DEVNAME' in device:
 | 
			
		||||
				if lookup_with_translation(device):
 | 
			
		||||
				found = cfg.om.get_object_by_lvm_id(device['DEVNAME'])
 | 
			
		||||
				if found:
 | 
			
		||||
					refresh = True
 | 
			
		||||
	else:
 | 
			
		||||
		# This handles the wipefs -a path
 | 
			
		||||
		if not refresh and 'DEVNAME' in device:
 | 
			
		||||
			found_obj = lookup_with_translation(device)
 | 
			
		||||
 | 
			
		||||
			# Also check device symlinks - udev might report /dev/dm-X but
 | 
			
		||||
			# 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
 | 
			
		||||
	if 'DM_LV_NAME' in device:
 | 
			
		||||
		refresh = True
 | 
			
		||||
 | 
			
		||||
	if refresh:
 | 
			
		||||
		udev_add()
 | 
			
		||||
@@ -135,8 +75,7 @@ def add():
 | 
			
		||||
	with observer_lock:
 | 
			
		||||
		global observer
 | 
			
		||||
		context = pyudev.Context()
 | 
			
		||||
		# Use source='udev' to get processed udev events, not raw kernel events
 | 
			
		||||
		monitor = pyudev.Monitor.from_netlink(context, source='udev')
 | 
			
		||||
		monitor = pyudev.Monitor.from_netlink(context)
 | 
			
		||||
		monitor.filter_by('block')
 | 
			
		||||
		observer = pyudev.MonitorObserver(monitor, filter_event)
 | 
			
		||||
		observer.start()
 | 
			
		||||
 
 | 
			
		||||
@@ -10,14 +10,11 @@
 | 
			
		||||
import xml.etree.ElementTree as Et
 | 
			
		||||
import sys
 | 
			
		||||
import inspect
 | 
			
		||||
import collections
 | 
			
		||||
import errno
 | 
			
		||||
import fcntl
 | 
			
		||||
import ctypes
 | 
			
		||||
import os
 | 
			
		||||
import stat
 | 
			
		||||
import string
 | 
			
		||||
import datetime
 | 
			
		||||
import tempfile
 | 
			
		||||
from fcntl import fcntl, F_GETFL, F_SETFL
 | 
			
		||||
 | 
			
		||||
import dbus
 | 
			
		||||
from lvmdbusd import cfg
 | 
			
		||||
@@ -89,7 +86,7 @@ def init_class_from_arguments(
 | 
			
		||||
			nt = k
 | 
			
		||||
 | 
			
		||||
			# If the current attribute has a value, but the incoming does
 | 
			
		||||
			# not, don't overwrite it.  Otherwise, the default values on the
 | 
			
		||||
			# not, don't overwrite it.  Otherwise the default values on the
 | 
			
		||||
			# property decorator don't work as expected.
 | 
			
		||||
			cur = getattr(obj_instance, nt, v)
 | 
			
		||||
 | 
			
		||||
@@ -109,7 +106,7 @@ def init_class_from_arguments(
 | 
			
		||||
 | 
			
		||||
def get_properties(f):
 | 
			
		||||
	"""
 | 
			
		||||
	Walks through an object instance, or it's parent class(es) and determines
 | 
			
		||||
	Walks through an object instance or it's parent class(es) and determines
 | 
			
		||||
	which attributes are properties and if they were created to be used for
 | 
			
		||||
	dbus.
 | 
			
		||||
	:param f:   Object to inspect
 | 
			
		||||
@@ -193,7 +190,7 @@ def add_properties(xml, interface, props):
 | 
			
		||||
				interface_element = c
 | 
			
		||||
				break
 | 
			
		||||
 | 
			
		||||
		# Interface is not present, lets create it, so we have something to
 | 
			
		||||
		# Interface is not present, lets create it so we have something to
 | 
			
		||||
		# attach the properties too
 | 
			
		||||
		if interface_element is None:
 | 
			
		||||
			interface_element = Et.Element("interface", name=interface)
 | 
			
		||||
@@ -283,64 +280,25 @@ def parse_tags(tags):
 | 
			
		||||
	return dbus.Array([], signature='s')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DebugMessages(object):
 | 
			
		||||
def _common_log(msg, *attributes):
 | 
			
		||||
	cfg.stdout_lock.acquire()
 | 
			
		||||
	tid = ctypes.CDLL('libc.so.6').syscall(186)
 | 
			
		||||
 | 
			
		||||
	def __init__(self, size=5000):
 | 
			
		||||
		self.queue = collections.deque(maxlen=size)
 | 
			
		||||
		self.lock = threading.RLock()
 | 
			
		||||
 | 
			
		||||
	def add(self, message):
 | 
			
		||||
		with self.lock:
 | 
			
		||||
			self.queue.append(message)
 | 
			
		||||
 | 
			
		||||
	def dump(self):
 | 
			
		||||
		if cfg.args and not cfg.args.debug:
 | 
			
		||||
			with self.lock:
 | 
			
		||||
				if len(self.queue):
 | 
			
		||||
					log_error("LVM dbus debug messages START last (%d max) messages" % self.queue.maxlen)
 | 
			
		||||
					for m in self.queue:
 | 
			
		||||
						print(m)
 | 
			
		||||
					log_error("LVM dbus debug messages END")
 | 
			
		||||
					self.queue.clear()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _get_tid():
 | 
			
		||||
	try:
 | 
			
		||||
		# Only 3.8 and later have this
 | 
			
		||||
		return threading.get_native_id()
 | 
			
		||||
	except:
 | 
			
		||||
		return -1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _format_log_entry(msg):
 | 
			
		||||
	tid = _get_tid()
 | 
			
		||||
 | 
			
		||||
	if not cfg.systemd and STDOUT_TTY:
 | 
			
		||||
	if STDOUT_TTY:
 | 
			
		||||
		msg = "%s: %d:%d - %s" % \
 | 
			
		||||
			(datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"),
 | 
			
		||||
			os.getpid(), tid, msg)
 | 
			
		||||
 | 
			
		||||
	else:
 | 
			
		||||
		if cfg.systemd:
 | 
			
		||||
			# Systemd already puts the daemon pid in the log, we'll just add the tid
 | 
			
		||||
			msg = "[%d]: %s" % (tid, msg)
 | 
			
		||||
		else:
 | 
			
		||||
			msg = "[%d:%d]: %s" % (os.getpid(), tid, msg)
 | 
			
		||||
	return msg
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _common_log(msg, *attributes):
 | 
			
		||||
	msg = _format_log_entry(msg)
 | 
			
		||||
 | 
			
		||||
	cfg.stdout_lock.acquire()
 | 
			
		||||
		msg = "%d:%d - %s" % (os.getpid(), tid, msg)
 | 
			
		||||
 | 
			
		||||
	if STDOUT_TTY and attributes:
 | 
			
		||||
		print(color(msg, *attributes))
 | 
			
		||||
	else:
 | 
			
		||||
		print(msg)
 | 
			
		||||
 | 
			
		||||
	sys.stdout.flush()
 | 
			
		||||
	cfg.stdout_lock.release()
 | 
			
		||||
	sys.stdout.flush()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Serializes access to stdout to prevent interleaved output
 | 
			
		||||
@@ -349,19 +307,12 @@ def _common_log(msg, *attributes):
 | 
			
		||||
def log_debug(msg, *attributes):
 | 
			
		||||
	if cfg.args and cfg.args.debug:
 | 
			
		||||
		_common_log(msg, *attributes)
 | 
			
		||||
	else:
 | 
			
		||||
		if cfg.debug:
 | 
			
		||||
			cfg.debug.add(_format_log_entry(msg))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def log_error(msg, *attributes):
 | 
			
		||||
	_common_log(msg, *attributes)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def log_msg(msg, *attributes):
 | 
			
		||||
	_common_log(msg, *attributes)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def dump_threads_stackframe():
 | 
			
		||||
	ident_to_name = {}
 | 
			
		||||
 | 
			
		||||
@@ -389,32 +340,15 @@ def dump_threads_stackframe():
 | 
			
		||||
# noinspection PyUnusedLocal
 | 
			
		||||
def handler(signum):
 | 
			
		||||
	try:
 | 
			
		||||
		# signal 10
 | 
			
		||||
		if signum == signal.SIGUSR1:
 | 
			
		||||
			cfg.debug.dump()
 | 
			
		||||
			dump_threads_stackframe()
 | 
			
		||||
		# signal 12
 | 
			
		||||
		elif signum == signal.SIGUSR2:
 | 
			
		||||
			cfg.debug.dump()
 | 
			
		||||
			cfg.flightrecorder.dump()
 | 
			
		||||
		else:
 | 
			
		||||
			# If we are getting a SIGTERM, and we sent one to the lvm shell we
 | 
			
		||||
			# will ignore this and keep running.
 | 
			
		||||
			if signum == signal.SIGTERM and cfg.ignore_sigterm:
 | 
			
		||||
				# Clear the flag, so we will exit on SIGTERM if we didn't
 | 
			
		||||
				# send it.
 | 
			
		||||
				cfg.ignore_sigterm = False
 | 
			
		||||
				return True
 | 
			
		||||
 | 
			
		||||
			# If lvm shell is in use, tell it to exit
 | 
			
		||||
			if cfg.SHELL_IN_USE is not None:
 | 
			
		||||
				cfg.SHELL_IN_USE.exit_shell()
 | 
			
		||||
			cfg.run.value = 0
 | 
			
		||||
			log_error('Exiting daemon with signal %d' % signum)
 | 
			
		||||
			log_debug('Exiting daemon with signal %d' % signum)
 | 
			
		||||
			if cfg.loop is not None:
 | 
			
		||||
				cfg.loop.quit()
 | 
			
		||||
	except BaseException as be:
 | 
			
		||||
		st = extract_stack_trace(be)
 | 
			
		||||
	except:
 | 
			
		||||
		st = traceback.format_exc()
 | 
			
		||||
		log_error("signal handler: exception (logged, not reported!) \n %s" % st)
 | 
			
		||||
 | 
			
		||||
	# It's important we report that we handled the exception for the exception
 | 
			
		||||
@@ -543,7 +477,7 @@ def round_size(size_bytes):
 | 
			
		||||
	return size_bytes + bs - remainder
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_/%'
 | 
			
		||||
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_\/%'
 | 
			
		||||
_ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
 | 
			
		||||
 | 
			
		||||
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
 | 
			
		||||
@@ -638,23 +572,6 @@ def validate_tag(interface, tag):
 | 
			
		||||
			% (tag, _ALLOWABLE_TAG_CH))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def add_config_option(cmdline, key, value):
 | 
			
		||||
	if 'help' in cmdline:
 | 
			
		||||
		return cmdline
 | 
			
		||||
 | 
			
		||||
	if key in cmdline:
 | 
			
		||||
		for i, arg in enumerate(cmdline):
 | 
			
		||||
			if arg == key:
 | 
			
		||||
				if len(cmdline) <= i + 1:
 | 
			
		||||
					raise dbus.exceptions.DBusException("Missing value for --config option.")
 | 
			
		||||
				cmdline[i + 1] += " %s" % value
 | 
			
		||||
				break
 | 
			
		||||
	else:
 | 
			
		||||
		cmdline.extend([key, value])
 | 
			
		||||
 | 
			
		||||
	return cmdline
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def add_no_notify(cmdline):
 | 
			
		||||
	"""
 | 
			
		||||
	Given a command line to execute we will see if `--config` is present, if it
 | 
			
		||||
@@ -666,18 +583,27 @@ def add_no_notify(cmdline):
 | 
			
		||||
	:rtype: list
 | 
			
		||||
	"""
 | 
			
		||||
 | 
			
		||||
	# Only after we have seen an external event will we disable lvm from sending
 | 
			
		||||
	# Only after we have seen an external event will be disable lvm from sending
 | 
			
		||||
	# us one when we call lvm
 | 
			
		||||
	rv = cmdline
 | 
			
		||||
	if cfg.got_external_event:
 | 
			
		||||
		rv = add_config_option(rv, "--config", "global/notify_dbus=0")
 | 
			
		||||
		if 'help' in cmdline:
 | 
			
		||||
			return cmdline
 | 
			
		||||
 | 
			
		||||
	return rv
 | 
			
		||||
		if '--config' in cmdline:
 | 
			
		||||
			for i, arg in enumerate(cmdline):
 | 
			
		||||
				if arg == '--config':
 | 
			
		||||
					if len(cmdline) <= i+1:
 | 
			
		||||
						raise dbus.exceptions.DBusException("Missing value for --config option.")
 | 
			
		||||
					cmdline[i+1] += " global/notify_dbus=0"
 | 
			
		||||
					break
 | 
			
		||||
		else:
 | 
			
		||||
			cmdline.extend(['--config', 'global/notify_dbus=0'])
 | 
			
		||||
	return cmdline
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# The methods below which start with mt_* are used to execute the desired code
 | 
			
		||||
# on the main thread of execution to alleviate any issues the dbus-python
 | 
			
		||||
# library with regard to multithreaded access.  Essentially, we are trying to
 | 
			
		||||
# on the the main thread of execution to alleviate any issues the dbus-python
 | 
			
		||||
# library with regards to multi-threaded access.  Essentially, we are trying to
 | 
			
		||||
# ensure all dbus library interaction is done from the same thread!
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -691,8 +617,9 @@ def _async_handler(call_back, parameters):
 | 
			
		||||
			call_back(*parameters)
 | 
			
		||||
		else:
 | 
			
		||||
			call_back()
 | 
			
		||||
	except BaseException as be:
 | 
			
		||||
		log_error("mt_async_call: exception (logged, not reported!) \n %s" % extract_stack_trace(be))
 | 
			
		||||
	except:
 | 
			
		||||
		st = traceback.format_exc()
 | 
			
		||||
		log_error("mt_async_call: exception (logged, not reported!) \n %s" % st)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Execute the function on the main thread with the provided parameters, do
 | 
			
		||||
@@ -742,6 +669,9 @@ class MThreadRunner(object):
 | 
			
		||||
				self.rc = self.f()
 | 
			
		||||
		except BaseException as be:
 | 
			
		||||
			self.exception = be
 | 
			
		||||
			st = traceback.format_exc()
 | 
			
		||||
			log_error("MThreadRunner: exception \n %s" % st)
 | 
			
		||||
			log_error("Exception will be raised in calling thread!")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _remove_objects(dbus_objects_rm):
 | 
			
		||||
@@ -756,8 +686,8 @@ def mt_remove_dbus_objects(objs):
 | 
			
		||||
 | 
			
		||||
# Make stream non-blocking
 | 
			
		||||
def make_non_block(stream):
 | 
			
		||||
	flags = fcntl.fcntl(stream, fcntl.F_GETFL)
 | 
			
		||||
	fcntl.fcntl(stream, fcntl.F_SETFL, flags | os.O_NONBLOCK)
 | 
			
		||||
	flags = fcntl(stream, F_GETFL)
 | 
			
		||||
	fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def read_decoded(stream):
 | 
			
		||||
@@ -765,128 +695,3 @@ def read_decoded(stream):
 | 
			
		||||
	if tmp:
 | 
			
		||||
		return tmp.decode("utf-8")
 | 
			
		||||
	return ''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LockFile(object):
 | 
			
		||||
	"""
 | 
			
		||||
	Simple lock file class
 | 
			
		||||
	Based on Pg.1144 "The Linux Programming Interface" by Michael Kerrisk
 | 
			
		||||
	"""
 | 
			
		||||
	def __init__(self, lock_file):
 | 
			
		||||
		self.fd = 0
 | 
			
		||||
		self.lock_file = lock_file
 | 
			
		||||
 | 
			
		||||
	def __enter__(self):
 | 
			
		||||
		try:
 | 
			
		||||
			os.makedirs(os.path.dirname(self.lock_file), exist_ok=True)
 | 
			
		||||
			self.fd = os.open(self.lock_file, os.O_CREAT | os.O_RDWR, stat.S_IRUSR | stat.S_IWUSR)
 | 
			
		||||
 | 
			
		||||
			# Get and set the close on exec and lock the file
 | 
			
		||||
			flags = fcntl.fcntl(self.fd, fcntl.F_GETFD)
 | 
			
		||||
			flags |= fcntl.FD_CLOEXEC
 | 
			
		||||
			fcntl.fcntl(self.fd, fcntl.F_SETFL, flags)
 | 
			
		||||
			fcntl.lockf(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
 | 
			
		||||
		except OSError as e:
 | 
			
		||||
			if e.errno == errno.EAGAIN:
 | 
			
		||||
				log_error("Daemon already running, exiting!")
 | 
			
		||||
			else:
 | 
			
		||||
				log_error("Error during creation of lock file(%s): errno(%d), exiting!" % (self.lock_file, e.errno))
 | 
			
		||||
			sys.exit(114)
 | 
			
		||||
 | 
			
		||||
	def __exit__(self, _type, _value, _traceback):
 | 
			
		||||
		os.close(self.fd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def extract_stack_trace(exception):
 | 
			
		||||
	return ''.join(traceback.format_exception(None, exception, exception.__traceback__))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def lvm_column_key(key):
 | 
			
		||||
	# Check LV
 | 
			
		||||
	if key.startswith("lv_") or key.startswith("vg_") or key.startswith("pool_") or \
 | 
			
		||||
			key.endswith("_percent") or key.startswith("move_") or key.startswith("vdo_") or \
 | 
			
		||||
			key in ["origin_uuid", "segtype", "origin", "data_lv", "metadata_lv"]:
 | 
			
		||||
		return True
 | 
			
		||||
	# Check VG
 | 
			
		||||
	if key.startswith("vg_") or key.startswith("lv_") or key.startswith("pv_") or \
 | 
			
		||||
			key in ["max_lv", "max_pv", "snap_count"]:
 | 
			
		||||
		return True
 | 
			
		||||
	# Check PV
 | 
			
		||||
	if key.startswith("pv") or key.startswith("vg") or (key in ['dev_size', 'pe_start']):
 | 
			
		||||
		return True
 | 
			
		||||
	return False
 | 
			
		||||
 | 
			
		||||
class LvmBug(RuntimeError):
 | 
			
		||||
	"""
 | 
			
		||||
	Things that are clearly a bug with lvm itself.
 | 
			
		||||
	"""
 | 
			
		||||
	def __init__(self, msg):
 | 
			
		||||
		super().__init__(msg)
 | 
			
		||||
 | 
			
		||||
	def __str__(self):
 | 
			
		||||
		return "lvm bug encountered: %s" % ' '.join(self.args)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LvmDebugData:
 | 
			
		||||
	def __init__(self, do_collection):
 | 
			
		||||
		self.fd = -1
 | 
			
		||||
		self.fn = None
 | 
			
		||||
		self.collect = do_collection
 | 
			
		||||
		if self.collect:
 | 
			
		||||
			log_msg("Collecting lvm debug data!")
 | 
			
		||||
 | 
			
		||||
	def _remove_file(self):
 | 
			
		||||
		if self.fn is not None:
 | 
			
		||||
			os.unlink(self.fn)
 | 
			
		||||
			self.fn = None
 | 
			
		||||
 | 
			
		||||
	def _close_fd(self):
 | 
			
		||||
		if self.fd != -1:
 | 
			
		||||
			os.close(self.fd)
 | 
			
		||||
			self.fd = -1
 | 
			
		||||
 | 
			
		||||
	def setup(self):
 | 
			
		||||
		# Create a secure filename
 | 
			
		||||
		if self.collect:
 | 
			
		||||
			self.fd, self.fn = tempfile.mkstemp(suffix=".log", prefix="lvmdbusd.lvm.debug.")
 | 
			
		||||
			return self.fn
 | 
			
		||||
		return None
 | 
			
		||||
 | 
			
		||||
	def lvm_complete(self):
 | 
			
		||||
		# Remove the file ASAP, so we decrease our odds of leaving it
 | 
			
		||||
		# around if the daemon gets killed by a signal -9
 | 
			
		||||
		self._remove_file()
 | 
			
		||||
 | 
			
		||||
	def dump(self):
 | 
			
		||||
		# Read the file and log it to log_err
 | 
			
		||||
		if self.fd != -1:
 | 
			
		||||
			# How big could the verbose debug get?
 | 
			
		||||
			debug = os.read(self.fd, 1024*1024*5)
 | 
			
		||||
			debug_txt = debug.decode("utf-8")
 | 
			
		||||
			for line in debug_txt.split("\n"):
 | 
			
		||||
				log_error("lvm debug >>> %s" % line)
 | 
			
		||||
			self._close_fd()
 | 
			
		||||
		# In case lvm_complete doesn't get called.
 | 
			
		||||
		self._remove_file()
 | 
			
		||||
 | 
			
		||||
	def complete(self):
 | 
			
		||||
		self._close_fd()
 | 
			
		||||
		# In case lvm_complete doesn't get called.
 | 
			
		||||
		self._remove_file()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_error_msg(report_json):
 | 
			
		||||
	# Get the error message from the returned JSON
 | 
			
		||||
	if 'log' in report_json:
 | 
			
		||||
		error_msg = ""
 | 
			
		||||
		# Walk the entire log array and build an error string
 | 
			
		||||
		for log_entry in report_json['log']:
 | 
			
		||||
			if log_entry['log_type'] == "error":
 | 
			
		||||
				if error_msg:
 | 
			
		||||
					error_msg += ', ' + log_entry['log_message']
 | 
			
		||||
				else:
 | 
			
		||||
					error_msg = log_entry['log_message']
 | 
			
		||||
 | 
			
		||||
		return error_msg
 | 
			
		||||
 | 
			
		||||
	return None
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ from .request import RequestEntry
 | 
			
		||||
from .loader import common
 | 
			
		||||
from .state import State
 | 
			
		||||
from . import background
 | 
			
		||||
from .utils import round_size, mt_remove_dbus_objects, LvmBug, lvm_column_key
 | 
			
		||||
from .utils import round_size, mt_remove_dbus_objects
 | 
			
		||||
from .job import JobState
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -31,24 +31,17 @@ def vgs_state_retrieve(selection, cache_refresh=True):
 | 
			
		||||
	if cache_refresh:
 | 
			
		||||
		cfg.db.refresh()
 | 
			
		||||
 | 
			
		||||
	try:
 | 
			
		||||
		for v in cfg.db.fetch_vgs(selection):
 | 
			
		||||
			rc.append(
 | 
			
		||||
				VgState(
 | 
			
		||||
					v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
 | 
			
		||||
					n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
 | 
			
		||||
					n(v['vg_extent_count']), n(v['vg_free_count']),
 | 
			
		||||
					v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
 | 
			
		||||
					n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
 | 
			
		||||
					n(v['vg_seqno']), n(v['vg_mda_count']),
 | 
			
		||||
					n(v['vg_mda_free']), n(v['vg_mda_size']),
 | 
			
		||||
					n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
 | 
			
		||||
	except KeyError as ke:
 | 
			
		||||
		# Sometimes lvm omits returning one of the keys we requested.
 | 
			
		||||
		key = ke.args[0]
 | 
			
		||||
		if lvm_column_key(key):
 | 
			
		||||
			raise LvmBug("missing JSON key: '%s'" % key)
 | 
			
		||||
		raise ke
 | 
			
		||||
	for v in cfg.db.fetch_vgs(selection):
 | 
			
		||||
		rc.append(
 | 
			
		||||
			VgState(
 | 
			
		||||
				v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
 | 
			
		||||
				n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
 | 
			
		||||
				n(v['vg_extent_count']), n(v['vg_free_count']),
 | 
			
		||||
				v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
 | 
			
		||||
				n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
 | 
			
		||||
				n(v['vg_seqno']), n(v['vg_mda_count']),
 | 
			
		||||
				n(v['vg_mda_free']), n(v['vg_mda_size']),
 | 
			
		||||
				n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
 | 
			
		||||
	return rc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -151,7 +144,6 @@ class Vg(AutomatedProperties):
 | 
			
		||||
	_AllocNormal_meta = ('b', VG_INTERFACE)
 | 
			
		||||
	_AllocAnywhere_meta = ('b', VG_INTERFACE)
 | 
			
		||||
	_Clustered_meta = ('b', VG_INTERFACE)
 | 
			
		||||
	_Shared_meta = ('b', VG_INTERFACE)
 | 
			
		||||
	_Name_meta = ('s', VG_INTERFACE)
 | 
			
		||||
 | 
			
		||||
	# noinspection PyUnusedLocal,PyPep8Naming
 | 
			
		||||
@@ -786,10 +778,6 @@ class Vg(AutomatedProperties):
 | 
			
		||||
	def Clustered(self):
 | 
			
		||||
		return self._attribute(5, 'c')
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def Shared(self):
 | 
			
		||||
		return self._attribute(5, 's')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VgVdo(Vg):
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,60 +15,61 @@ srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
USE_SD_NOTIFY=yes
 | 
			
		||||
 | 
			
		||||
SOURCES = lvmlockd-core.c
 | 
			
		||||
SOURCES2 = lvmlockctl.c
 | 
			
		||||
 | 
			
		||||
TARGETS = lvmlockd lvmlockctl
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
 | 
			
		||||
  SOURCES += lvmlockd-sanlock.c
 | 
			
		||||
  CFLAGS += $(LIBSANLOCKCLIENT_CFLAGS)
 | 
			
		||||
  LOCK_LIBS += $(LIBSANLOCKCLIENT_LIBS)
 | 
			
		||||
  LOCK_LIBS += -lsanlock_client
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_LOCKDDLM@", "yes")
 | 
			
		||||
  SOURCES += lvmlockd-dlm.c
 | 
			
		||||
  CFLAGS += $(LIBDLM) $(LIBDLMCONTROL_CFLAGS)
 | 
			
		||||
#  LOCK_LIBS += $(LIBDLM_LIBS) $(LIBDLMCONTROL_LIBS)
 | 
			
		||||
  LOCK_LIBS += -ldlm_lt $(LIBDLMCONTROL_LIBS)
 | 
			
		||||
  LOCK_LIBS += -ldlm_lt
 | 
			
		||||
  LOCK_LIBS += -ldlmcontrol
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_LOCKDIDM@", "yes")
 | 
			
		||||
  SOURCES += lvmlockd-idm.c
 | 
			
		||||
  LOCK_LIBS += $(LIBSEAGATEILM_LIBS) $(BLKID_LIBS)
 | 
			
		||||
  LOCK_LIBS += -lseagate_ilm -lblkid
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
SOURCES2 = lvmlockctl.c
 | 
			
		||||
 | 
			
		||||
TARGETS = lvmlockd lvmlockctl
 | 
			
		||||
 | 
			
		||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
 | 
			
		||||
CFLOW_TARGET = lvmlockd
 | 
			
		||||
 | 
			
		||||
.PHONY: install_lvmlockd install_lvmlockctl
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
 | 
			
		||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
 | 
			
		||||
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
ifeq ("@SD_NOTIFY_SUPPORT@", "yes")
 | 
			
		||||
	CFLAGS += $(LIBSYSTEMD_CFLAGS)
 | 
			
		||||
	LIBS += $(LIBSYSTEMD_LIBS)
 | 
			
		||||
ifeq ($(USE_SD_NOTIFY),yes)
 | 
			
		||||
	CFLAGS += $(shell pkg-config --cflags libsystemd) -DUSE_SD_NOTIFY
 | 
			
		||||
	LIBS += $(shell pkg-config --libs libsystemd)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
 | 
			
		||||
	$(SHOW) "    [CC] $@"
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LOCK_LIBS) $(LIBS)
 | 
			
		||||
 | 
			
		||||
lvmlockctl: lvmlockctl.o $(INTERNAL_LIBS)
 | 
			
		||||
	$(SHOW) "    [CC] $@"
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
 | 
			
		||||
 | 
			
		||||
install_lvmlockd: lvmlockd
 | 
			
		||||
	$(SHOW) "    [INSTALL] $<"
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_lvmlockctl: lvmlockctl
 | 
			
		||||
	$(SHOW) "    [INSTALL] $<"
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_lvmlockd install_lvmlockctl
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ static int stop_lockspaces = 0;
 | 
			
		||||
static char *arg_vg_name = NULL;
 | 
			
		||||
 | 
			
		||||
#define DUMP_SOCKET_NAME "lvmlockd-dump.sock"
 | 
			
		||||
#define DUMP_BUF_SIZE (4 * 1024 * 1024)
 | 
			
		||||
#define DUMP_BUF_SIZE (1024 * 1024)
 | 
			
		||||
static char dump_buf[DUMP_BUF_SIZE+1];
 | 
			
		||||
static int dump_len;
 | 
			
		||||
static struct sockaddr_un dump_addr;
 | 
			
		||||
@@ -67,160 +67,6 @@ do { \
 | 
			
		||||
		syslog(LOG_WARNING, fmt, ##args); \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Like sscanf, but requires buffer size to be specified
 | 
			
		||||
 * for storing scanned strings, e.g.
 | 
			
		||||
 *
 | 
			
		||||
 * szscanf("%s", sizeof(buf), buf);
 | 
			
		||||
 *
 | 
			
		||||
 * Up to size-1 input bytes will be copied into buf.
 | 
			
		||||
 * A null byte will be written to buf following the
 | 
			
		||||
 * last copied byte.  When nothing is copied to buf,
 | 
			
		||||
 * no terminating null byte is written.
 | 
			
		||||
 *
 | 
			
		||||
 * If an input string matching %s is too long for the
 | 
			
		||||
 * specified buffer size, the characters that would have
 | 
			
		||||
 * been copied are ignored.
 | 
			
		||||
 *
 | 
			
		||||
 * Only recognizes: %d, %u, %s.
 | 
			
		||||
 */
 | 
			
		||||
static int szscanf(const char *input, const char *format, ...)
 | 
			
		||||
{
 | 
			
		||||
	va_list args;
 | 
			
		||||
	const char *fm;
 | 
			
		||||
	const char *in;
 | 
			
		||||
	int matched = 0;
 | 
			
		||||
	int n;
 | 
			
		||||
 | 
			
		||||
	va_start(args, format);
 | 
			
		||||
	fm = format;
 | 
			
		||||
	in = input;
 | 
			
		||||
 | 
			
		||||
	while (*fm != '\0') {
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * format is a string containing:
 | 
			
		||||
		 * 1. %d matching int from input
 | 
			
		||||
		 *    %u matching unsigned int from input
 | 
			
		||||
		 *    %s matching non-whitespace characters from input
 | 
			
		||||
		 * 2. whitespace chars matching zero or more whitespace
 | 
			
		||||
		 *    characters from input
 | 
			
		||||
		 * 3. non-whitespace chars matching the same input chars
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		if (*fm == '%') {
 | 
			
		||||
			/*
 | 
			
		||||
			 * case 1: %u, %d, or %s
 | 
			
		||||
			 */
 | 
			
		||||
 | 
			
		||||
			/* advance past '%' character, to look for 'u', 'd' or 's' */
 | 
			
		||||
			fm++;
 | 
			
		||||
 | 
			
		||||
			if (*fm == 'd') {
 | 
			
		||||
				/*
 | 
			
		||||
				 * read an int (%d)
 | 
			
		||||
				 */
 | 
			
		||||
				int *dest = va_arg(args, int *);
 | 
			
		||||
 | 
			
		||||
				if (sscanf(in, "%d%n", dest, &n) == 1) {
 | 
			
		||||
					in += n;
 | 
			
		||||
					matched++;
 | 
			
		||||
				} else {
 | 
			
		||||
					/* matching failure: no input int */
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			} else if (*fm == 'u') {
 | 
			
		||||
				/*
 | 
			
		||||
				 * read an unsigned int (%u)
 | 
			
		||||
				 */
 | 
			
		||||
				unsigned int *dest = va_arg(args, unsigned int *);
 | 
			
		||||
 | 
			
		||||
				if (sscanf(in, "%u%n", dest, &n) == 1) {
 | 
			
		||||
					in += n;
 | 
			
		||||
					matched++;
 | 
			
		||||
				} else {
 | 
			
		||||
					/* matching failure: no input unsigned int */
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			} else if (*fm == 's') {
 | 
			
		||||
				/*
 | 
			
		||||
				 * read a string (%s) into dest buffer with dest_size
 | 
			
		||||
				 * copy up to dest_size-1 characters into dest buffer
 | 
			
		||||
				 * write null byte into dest buffer following the last
 | 
			
		||||
				 * character copied.  When dest_size-1 bytes are copied,
 | 
			
		||||
				 * the null byte is written into the final byte of the
 | 
			
		||||
				 * dest buffer.  input bytes that would have been copied
 | 
			
		||||
				 * but did not fit in the dest buffer are skipped.
 | 
			
		||||
				 */
 | 
			
		||||
				size_t dest_size = va_arg(args, size_t);
 | 
			
		||||
				char *dest = va_arg(args, char *);
 | 
			
		||||
				char *out = dest;
 | 
			
		||||
 | 
			
		||||
				/* don't copy leading input whitespace to dest */
 | 
			
		||||
				while (isspace((unsigned char)*in))
 | 
			
		||||
					in++;
 | 
			
		||||
 | 
			
		||||
				/* copy non-whitespace characters from input to dest */
 | 
			
		||||
				n = 0;
 | 
			
		||||
				while (*in != '\0' && !isspace((unsigned char)*in) && (n < (int)dest_size-1)) {
 | 
			
		||||
					*out = *in;
 | 
			
		||||
					out++;
 | 
			
		||||
					in++;
 | 
			
		||||
					n++;
 | 
			
		||||
				}
 | 
			
		||||
				if (n) {
 | 
			
		||||
					dest[n] = '\0';
 | 
			
		||||
					matched++;
 | 
			
		||||
				} else {
 | 
			
		||||
					/* matching failure: no input string chars */
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				/* ignore input bytes that would have been copied but didn't fit */
 | 
			
		||||
				while (*in != '\0' && !isspace((unsigned char)*in))
 | 
			
		||||
					in++;
 | 
			
		||||
 | 
			
		||||
			} else {
 | 
			
		||||
				/* unsupported format specifier */
 | 
			
		||||
				matched = -1;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* advance past 'd', 'u', or 's' character */
 | 
			
		||||
			fm++;
 | 
			
		||||
 | 
			
		||||
		} else if (isspace((unsigned char)*fm)) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * case 2: format whitespace skips zero or more input
 | 
			
		||||
			 * whitespace characters
 | 
			
		||||
			 */
 | 
			
		||||
			while (isspace((unsigned char)*in))
 | 
			
		||||
				in++;
 | 
			
		||||
 | 
			
		||||
			/* advance past whitespace character */
 | 
			
		||||
			fm++;
 | 
			
		||||
 | 
			
		||||
		} else if (*fm == *in) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * case 3: literal character match between format and input
 | 
			
		||||
			 */
 | 
			
		||||
			fm++;
 | 
			
		||||
			in++;
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
			/*
 | 
			
		||||
			 * matching failure: format and input don't match
 | 
			
		||||
			 */
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	va_end(args);
 | 
			
		||||
	return matched;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define MAX_LINE 512
 | 
			
		||||
 | 
			
		||||
/* copied from lvmlockd-internal.h */
 | 
			
		||||
@@ -251,11 +97,8 @@ static void save_client_info(char *line)
 | 
			
		||||
	uint32_t client_id = 0;
 | 
			
		||||
	char name[MAX_NAME+1] = { 0 };
 | 
			
		||||
 | 
			
		||||
	/* info=client pid=%u fd=%d pi=%d id=%u name=%s */
 | 
			
		||||
 | 
			
		||||
	if (szscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
 | 
			
		||||
		    &pid, &fd, &pi, &client_id, sizeof(name), name) < 0)
 | 
			
		||||
		return;
 | 
			
		||||
	(void) sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
 | 
			
		||||
	       &pid, &fd, &pi, &client_id, name);
 | 
			
		||||
 | 
			
		||||
	clients[num_clients].client_id = client_id;
 | 
			
		||||
	clients[num_clients].pid = pid;
 | 
			
		||||
@@ -283,26 +126,20 @@ static void format_info_ls(char *line)
 | 
			
		||||
	char ls_name[MAX_NAME+1] = { 0 };
 | 
			
		||||
	char vg_name[MAX_NAME+1] = { 0 };
 | 
			
		||||
	char vg_uuid[MAX_NAME+1] = { 0 };
 | 
			
		||||
	char vg_args[MAX_ARGS+1] = { 0 };
 | 
			
		||||
	char lm_type[MAX_NAME+1] = { 0 };
 | 
			
		||||
	char vg_sysid[MAX_NAME+1] = { 0 };
 | 
			
		||||
	char lock_args[MAX_ARGS+1] = { 0 };
 | 
			
		||||
	char lock_type[MAX_NAME+1] = { 0 };
 | 
			
		||||
 | 
			
		||||
	/* info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_args=%s lm_type=%s */
 | 
			
		||||
 | 
			
		||||
	if (szscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_args=%s lm_type=%s",
 | 
			
		||||
		    sizeof(ls_name), ls_name,
 | 
			
		||||
		    sizeof(vg_name), vg_name,
 | 
			
		||||
		    sizeof(vg_uuid), vg_uuid,
 | 
			
		||||
		    sizeof(vg_args), vg_args,
 | 
			
		||||
		    sizeof(lm_type), lm_type) < 0)
 | 
			
		||||
		return;
 | 
			
		||||
	(void) sscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_sysid=%s vg_args=%s lm_type=%s",
 | 
			
		||||
	       ls_name, vg_name, vg_uuid, vg_sysid, lock_args, lock_type);
 | 
			
		||||
 | 
			
		||||
	if (!first_ls)
 | 
			
		||||
		printf("\n");
 | 
			
		||||
	first_ls = 0;
 | 
			
		||||
 | 
			
		||||
	printf("VG %s lock_type=%s %s\n", vg_name, lm_type, vg_uuid);
 | 
			
		||||
	printf("VG %s lock_type=%s %s\n", vg_name, lock_type, vg_uuid);
 | 
			
		||||
 | 
			
		||||
	printf("LS %s %s\n", lm_type, ls_name);
 | 
			
		||||
	printf("LS %s %s\n", lock_type, ls_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void format_info_ls_action(char *line)
 | 
			
		||||
@@ -314,14 +151,8 @@ static void format_info_ls_action(char *line)
 | 
			
		||||
	uint32_t pid = 0;
 | 
			
		||||
	char cl_name[MAX_NAME+1] = { 0 };
 | 
			
		||||
 | 
			
		||||
	/* info=ls_action client_id=%u flags=%s version=%u op=%s rt=%s mode=%s lm_type=%s result=%d lm_rv=%d */
 | 
			
		||||
 | 
			
		||||
	if (szscanf(line, "info=ls_action client_id=%u flags=%s version=%s op=%s",
 | 
			
		||||
		    &client_id,
 | 
			
		||||
		    sizeof(flags), flags,
 | 
			
		||||
		    sizeof(version), version,
 | 
			
		||||
		    sizeof(op), op) < 0)
 | 
			
		||||
		return;
 | 
			
		||||
	(void) sscanf(line, "info=ls_action client_id=%u %s %s op=%s",
 | 
			
		||||
	       &client_id, flags, version, op);
 | 
			
		||||
 | 
			
		||||
	find_client_info(client_id, &pid, cl_name);
 | 
			
		||||
 | 
			
		||||
@@ -333,18 +164,11 @@ static void format_info_r(char *line, char *r_name_out, char *r_type_out)
 | 
			
		||||
	char r_name[MAX_NAME+1] = { 0 };
 | 
			
		||||
	char r_type[4] = { 0 };
 | 
			
		||||
	char mode[4] = { 0 };
 | 
			
		||||
	int sh_count = 0;
 | 
			
		||||
	unsigned int ver = 0;
 | 
			
		||||
	char sh_count[MAX_NAME+1] = { 0 };
 | 
			
		||||
	uint32_t ver = 0;
 | 
			
		||||
 | 
			
		||||
	/* info=r name=%s type=%s mode=%s sh_count=%d version=%s */
 | 
			
		||||
 | 
			
		||||
	if (szscanf(line, "info=r name=%s type=%s mode=%s sh_count=%d version=%u",
 | 
			
		||||
		    sizeof(r_name), r_name,
 | 
			
		||||
		    sizeof(r_type), r_type,
 | 
			
		||||
		    sizeof(mode), mode,
 | 
			
		||||
		    &sh_count,
 | 
			
		||||
		    &ver) < 0)
 | 
			
		||||
		return;
 | 
			
		||||
	(void) sscanf(line, "info=r name=%s type=%s mode=%s %s version=%u",
 | 
			
		||||
	       r_name, r_type, mode, sh_count, &ver);
 | 
			
		||||
 | 
			
		||||
	strcpy(r_name_out, r_name);
 | 
			
		||||
	strcpy(r_type_out, r_type);
 | 
			
		||||
@@ -369,8 +193,8 @@ static void format_info_r(char *line, char *r_name_out, char *r_type_out)
 | 
			
		||||
static void format_info_lk(char *line, char *r_name, char *r_type)
 | 
			
		||||
{
 | 
			
		||||
	char mode[4] = { 0 };
 | 
			
		||||
	char flags[MAX_NAME+1] = { 0 };
 | 
			
		||||
	uint32_t ver = 0;
 | 
			
		||||
	char flags[MAX_NAME+1] = { 0 };
 | 
			
		||||
	uint32_t client_id = 0;
 | 
			
		||||
	uint32_t pid = 0;
 | 
			
		||||
	char cl_name[MAX_NAME+1] = { 0 };
 | 
			
		||||
@@ -381,14 +205,8 @@ static void format_info_lk(char *line, char *r_name, char *r_type)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* info=lk mode=%s version=%s flags=%s client_id=%u */
 | 
			
		||||
 | 
			
		||||
	if (szscanf(line, "info=lk mode=%s version=%u flags=%s client_id=%u",
 | 
			
		||||
		    sizeof(mode), mode,
 | 
			
		||||
		    &ver,
 | 
			
		||||
		    sizeof(flags), flags,
 | 
			
		||||
		    &client_id) < 0)
 | 
			
		||||
		return;
 | 
			
		||||
	(void) sscanf(line, "info=lk mode=%s version=%u %s client_id=%u",
 | 
			
		||||
	       mode, &ver, flags, &client_id);
 | 
			
		||||
 | 
			
		||||
	find_client_info(client_id, &pid, cl_name);
 | 
			
		||||
 | 
			
		||||
@@ -411,9 +229,9 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
 | 
			
		||||
	char op[MAX_NAME+1] = { 0 };
 | 
			
		||||
	char rt[4] = { 0 };
 | 
			
		||||
	char mode[4] = { 0 };
 | 
			
		||||
	char lm_type[MAX_NAME+1] = { 0 };
 | 
			
		||||
	int result = 0;
 | 
			
		||||
	int lm_rv = 0;
 | 
			
		||||
	char lm[MAX_NAME+1] = { 0 };
 | 
			
		||||
	char result[MAX_NAME+1] = { 0 };
 | 
			
		||||
	char lm_rv[MAX_NAME+1] = { 0 };
 | 
			
		||||
	uint32_t pid = 0;
 | 
			
		||||
	char cl_name[MAX_NAME+1] = { 0 };
 | 
			
		||||
 | 
			
		||||
@@ -423,19 +241,8 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* info=r_action client_id=%u flags=%s version=%s op=%s rt=%s mode=%s lm_type=%s result=%d lm_rv=%d */
 | 
			
		||||
 | 
			
		||||
	if (szscanf(line, "info=r_action client_id=%u flags=%s version=%s op=%s rt=%s mode=%s lm_type=%s result=%d lm_rv=%d",
 | 
			
		||||
		     &client_id,
 | 
			
		||||
		     sizeof(flags), flags,
 | 
			
		||||
		     sizeof(version), version,
 | 
			
		||||
		     sizeof(op), op,
 | 
			
		||||
		     sizeof(rt), rt,
 | 
			
		||||
		     sizeof(mode), mode,
 | 
			
		||||
		     sizeof(lm_type), lm_type,
 | 
			
		||||
		     &result,
 | 
			
		||||
		     &lm_rv) < 0)
 | 
			
		||||
		return;
 | 
			
		||||
	(void) sscanf(line, "info=r_action client_id=%u %s %s op=%s rt=%s mode=%s %s %s %s",
 | 
			
		||||
	       &client_id, flags, version, op, rt, mode, lm, result, lm_rv);
 | 
			
		||||
 | 
			
		||||
	find_client_info(client_id, &pid, cl_name);
 | 
			
		||||
 | 
			
		||||
@@ -457,19 +264,19 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
 | 
			
		||||
 | 
			
		||||
static void format_info_line(char *line, char *r_name, char *r_type)
 | 
			
		||||
{
 | 
			
		||||
	if (!strncmp(line, "info=structs ", sizeof("info=structs ") - 1)) {
 | 
			
		||||
	if (!strncmp(line, "info=structs ", strlen("info=structs "))) {
 | 
			
		||||
		/* only print this in the raw info dump */
 | 
			
		||||
 | 
			
		||||
	} else if (!strncmp(line, "info=client ", sizeof("info=client ") - 1)) {
 | 
			
		||||
	} else if (!strncmp(line, "info=client ", strlen("info=client "))) {
 | 
			
		||||
		save_client_info(line);
 | 
			
		||||
 | 
			
		||||
	} else if (!strncmp(line, "info=ls ", sizeof("info=ls ") - 1)) {
 | 
			
		||||
	} else if (!strncmp(line, "info=ls ", strlen("info=ls "))) {
 | 
			
		||||
		format_info_ls(line);
 | 
			
		||||
 | 
			
		||||
	} else if (!strncmp(line, "info=ls_action ", sizeof("info=ls_action ") - 1)) {
 | 
			
		||||
	} else if (!strncmp(line, "info=ls_action ", strlen("info=ls_action "))) {
 | 
			
		||||
		format_info_ls_action(line);
 | 
			
		||||
 | 
			
		||||
	} else if (!strncmp(line, "info=r ", sizeof("info=r ") - 1)) {
 | 
			
		||||
	} else if (!strncmp(line, "info=r ", strlen("info=r "))) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * r_name/r_type are reset when a new resource is found.
 | 
			
		||||
		 * They are reused for the lock and action lines that
 | 
			
		||||
@@ -479,11 +286,11 @@ static void format_info_line(char *line, char *r_name, char *r_type)
 | 
			
		||||
		memset(r_type, 0, MAX_NAME+1);
 | 
			
		||||
		format_info_r(line, r_name, r_type);
 | 
			
		||||
 | 
			
		||||
	} else if (!strncmp(line, "info=lk ", sizeof("info=lk ") - 1)) {
 | 
			
		||||
	} else if (!strncmp(line, "info=lk ", strlen("info=lk "))) {
 | 
			
		||||
		/* will use info from previous r */
 | 
			
		||||
		format_info_lk(line, r_name, r_type);
 | 
			
		||||
 | 
			
		||||
	} else if (!strncmp(line, "info=r_action ", sizeof("info=r_action ") - 1)) {
 | 
			
		||||
	} else if (!strncmp(line, "info=r_action ", strlen("info=r_action "))) {
 | 
			
		||||
		/* will use info from previous r */
 | 
			
		||||
		format_info_r_action(line, r_name, r_type);
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -1133,7 +940,7 @@ static int read_options(int argc, char *argv[])
 | 
			
		||||
	int option_index = 0;
 | 
			
		||||
	int c;
 | 
			
		||||
 | 
			
		||||
	static const struct option _long_options[] = {
 | 
			
		||||
	static struct option long_options[] = {
 | 
			
		||||
		{"help",            no_argument,       0,  'h' },
 | 
			
		||||
		{"quit",            no_argument,       0,  'q' },
 | 
			
		||||
		{"info",            no_argument,       0,  'i' },
 | 
			
		||||
@@ -1155,7 +962,7 @@ static int read_options(int argc, char *argv[])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		c = getopt_long(argc, argv, "hqidE:D:w:k:r:Se", _long_options, &option_index);
 | 
			
		||||
		c = getopt_long(argc, argv, "hqidE:D:w:k:r:Se", long_options, &option_index);
 | 
			
		||||
		if (c == -1)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,12 +16,9 @@
 | 
			
		||||
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
 | 
			
		||||
#define LVMLOCKD_ADOPT_FILE DEFAULT_RUN_DIR "/lvmlockd.adopt"
 | 
			
		||||
 | 
			
		||||
#define LVMLOCKD_USE_SANLOCK_LVB 0
 | 
			
		||||
 | 
			
		||||
/* Wrappers to open/close connection */
 | 
			
		||||
 | 
			
		||||
static inline __attribute__((always_inline))
 | 
			
		||||
	daemon_handle lvmlockd_open(const char *sock)
 | 
			
		||||
static inline daemon_handle lvmlockd_open(const char *sock)
 | 
			
		||||
{
 | 
			
		||||
	daemon_info lvmlockd_info = {
 | 
			
		||||
		.path = "lvmlockd",
 | 
			
		||||
@@ -54,10 +51,5 @@ static inline void lvmlockd_close(daemon_handle h)
 | 
			
		||||
#define EREMOVED  219
 | 
			
		||||
#define EDEVOPEN  220 /* sanlock failed to open lvmlock LV */
 | 
			
		||||
#define ELMERR    221
 | 
			
		||||
#define EORPHAN   222
 | 
			
		||||
#define EADOPT_NONE  223
 | 
			
		||||
#define EADOPT_RETRY 224
 | 
			
		||||
#define EIOTIMEOUT   225
 | 
			
		||||
#define ELOCKREPAIR  226
 | 
			
		||||
 | 
			
		||||
#endif	/* _LVM_LVMLOCKD_CLIENT_H */
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -13,7 +13,7 @@
 | 
			
		||||
 | 
			
		||||
#include "tools/tool.h"
 | 
			
		||||
 | 
			
		||||
#include "libdaemon/server/daemon-server.h"
 | 
			
		||||
#include "daemon-server.h"
 | 
			
		||||
#include "lib/mm/xlate.h"
 | 
			
		||||
 | 
			
		||||
#include "lvmlockd-internal.h"
 | 
			
		||||
@@ -31,6 +31,7 @@
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <endian.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <byteswap.h>
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
 | 
			
		||||
@@ -95,6 +96,7 @@ static int check_args_version(char *vg_args)
 | 
			
		||||
 | 
			
		||||
static int read_cluster_name(char *clustername)
 | 
			
		||||
{
 | 
			
		||||
	static const char close_error_msg[] = "read_cluster_name: close_error %d";
 | 
			
		||||
	char *n;
 | 
			
		||||
	int fd;
 | 
			
		||||
	int rv;
 | 
			
		||||
@@ -113,19 +115,18 @@ static int read_cluster_name(char *clustername)
 | 
			
		||||
	rv = read(fd, clustername, MAX_ARGS);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_error("read_cluster_name: cluster name read error %d, check dlm_controld", fd);
 | 
			
		||||
		goto out;
 | 
			
		||||
		if (close(fd))
 | 
			
		||||
			log_error(close_error_msg, fd);
 | 
			
		||||
		return rv;
 | 
			
		||||
	}
 | 
			
		||||
	clustername[rv] = 0;
 | 
			
		||||
 | 
			
		||||
	n = strstr(clustername, "\n");
 | 
			
		||||
	if (n)
 | 
			
		||||
		*n = '\0';
 | 
			
		||||
	rv = 0;
 | 
			
		||||
out:
 | 
			
		||||
	if (close(fd))
 | 
			
		||||
		log_error("read_cluster_name: close_error %d", fd);
 | 
			
		||||
 | 
			
		||||
	return rv;
 | 
			
		||||
		log_error(close_error_msg, fd);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define MAX_VERSION 16
 | 
			
		||||
@@ -168,10 +169,8 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
 | 
			
		||||
	struct lm_dlm *lmd;
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	if (daemon_test) {
 | 
			
		||||
		log_debug("lm_prepare_lockspace_dlm test");
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		goto skip_args;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memset(sys_clustername, 0, sizeof(sys_clustername));
 | 
			
		||||
	memset(arg_clustername, 0, sizeof(arg_clustername));
 | 
			
		||||
@@ -221,112 +220,20 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define DLM_COMMS_PATH "/sys/kernel/config/dlm/cluster/comms"
 | 
			
		||||
#define LOCK_LINE_MAX 1024
 | 
			
		||||
static int get_local_nodeid(void)
 | 
			
		||||
{
 | 
			
		||||
	struct dirent *de;
 | 
			
		||||
	DIR *ls_dir;
 | 
			
		||||
	char ls_comms_path[PATH_MAX] = { 0 };
 | 
			
		||||
	char path[PATH_MAX] = { 0 };
 | 
			
		||||
	FILE *file;
 | 
			
		||||
	char line[LOCK_LINE_MAX];
 | 
			
		||||
	char *str1, *str2;
 | 
			
		||||
	int rv = -1, val;
 | 
			
		||||
 | 
			
		||||
	snprintf(ls_comms_path, sizeof(ls_comms_path), "%s", DLM_COMMS_PATH);
 | 
			
		||||
 | 
			
		||||
	if (!(ls_dir = opendir(ls_comms_path)))
 | 
			
		||||
		return -ECONNREFUSED;
 | 
			
		||||
 | 
			
		||||
	while ((de = readdir(ls_dir))) {
 | 
			
		||||
		if (de->d_name[0] == '.')
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		snprintf(path, sizeof(path), "%s/%s/local",
 | 
			
		||||
			 DLM_COMMS_PATH, de->d_name);
 | 
			
		||||
 | 
			
		||||
		if (!(file = fopen(ls_comms_path, "r")))
 | 
			
		||||
			continue;
 | 
			
		||||
		str1 = fgets(line, sizeof(line), file);
 | 
			
		||||
		if (fclose(file))
 | 
			
		||||
			log_sys_debug("fclose", path);
 | 
			
		||||
		if (str1) {
 | 
			
		||||
			rv = sscanf(line, "%d", &val);
 | 
			
		||||
			if ((rv == 1) && (val == 1 )) {
 | 
			
		||||
				snprintf(path, sizeof(path), "%s/%s/nodeid",
 | 
			
		||||
					 DLM_COMMS_PATH, de->d_name);
 | 
			
		||||
 | 
			
		||||
				if (!(file = fopen(path, "r")))
 | 
			
		||||
					continue;
 | 
			
		||||
				str2 = fgets(line, sizeof(line), file);
 | 
			
		||||
				if (fclose(file))
 | 
			
		||||
					log_sys_debug("fclose", path);
 | 
			
		||||
				if (str2) {
 | 
			
		||||
					rv = sscanf(line, "%d", &val);
 | 
			
		||||
					if (rv == 1) {
 | 
			
		||||
						if (closedir(ls_dir))
 | 
			
		||||
							log_sys_debug("closedir", ls_comms_path);
 | 
			
		||||
						return val;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (closedir(ls_dir))
 | 
			
		||||
		log_sys_debug("closedir", ls_comms_path);
 | 
			
		||||
 | 
			
		||||
	return rv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lm_purge_locks_dlm(struct lockspace *ls)
 | 
			
		||||
{
 | 
			
		||||
	struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
 | 
			
		||||
	int nodeid;
 | 
			
		||||
	int rv = -1;
 | 
			
		||||
 | 
			
		||||
	if (!lmd || !lmd->dh) {
 | 
			
		||||
		log_error("purge_locks_dlm %s no dlm_handle_t error", ls->name);
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nodeid = get_local_nodeid();
 | 
			
		||||
	if (nodeid < 0) {
 | 
			
		||||
		log_error("failed to get local nodeid");
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
	if (dlm_ls_purge(lmd->dh, nodeid, 0)) {
 | 
			
		||||
		log_error("purge_locks_dlm %s error", ls->name);
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rv = 0;
 | 
			
		||||
fail:
 | 
			
		||||
	return rv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok)
 | 
			
		||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
 | 
			
		||||
{
 | 
			
		||||
	struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
 | 
			
		||||
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (adopt_only || adopt_ok) {
 | 
			
		||||
	if (adopt)
 | 
			
		||||
		lmd->dh = dlm_open_lockspace(ls->name);
 | 
			
		||||
		if (!lmd->dh && adopt_ok)
 | 
			
		||||
			lmd->dh = dlm_new_lockspace(ls->name, 0600, DLM_LSFL_NEWEXCL);
 | 
			
		||||
		if (!lmd->dh)
 | 
			
		||||
			log_error("add_lockspace_dlm adopt_only %d adopt_ok %d %s error",
 | 
			
		||||
				  adopt_only, adopt_ok, ls->name);
 | 
			
		||||
	} else {
 | 
			
		||||
	else
 | 
			
		||||
		lmd->dh = dlm_new_lockspace(ls->name, 0600, DLM_LSFL_NEWEXCL);
 | 
			
		||||
		if (!lmd->dh)
 | 
			
		||||
			log_error("add_lockspace_dlm %s error", ls->name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lmd->dh) {
 | 
			
		||||
		log_error("add_lockspace_dlm %s adopt %d error", ls->name, adopt);
 | 
			
		||||
		free(lmd);
 | 
			
		||||
		ls->lm_data = NULL;
 | 
			
		||||
		return -1;
 | 
			
		||||
@@ -362,7 +269,7 @@ int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
 | 
			
		||||
	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 rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
 | 
			
		||||
@@ -394,7 +301,7 @@ int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_
 | 
			
		||||
			      r->name, strlen(r->name),
 | 
			
		||||
			      0, NULL, NULL, NULL);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_error("%s:%s add_resource_dlm lock error %d", ls->name, r->name, rv);
 | 
			
		||||
		log_error("S %s R %s add_resource_dlm lock error %d", ls->name, r->name, rv);
 | 
			
		||||
		return rv;
 | 
			
		||||
	}
 | 
			
		||||
 out:
 | 
			
		||||
@@ -418,7 +325,7 @@ int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
 | 
			
		||||
 | 
			
		||||
	rv = dlm_ls_unlock_wait(lmd->dh, lksb->sb_lkid, 0, lksb);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_error("%s:%s rem_resource_dlm unlock error %d", ls->name, r->name, rv);
 | 
			
		||||
		log_error("S %s R %s rem_resource_dlm unlock error %d", ls->name, r->name, rv);
 | 
			
		||||
	}
 | 
			
		||||
 out:
 | 
			
		||||
	free(rdd->vb);
 | 
			
		||||
@@ -473,7 +380,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_debug("%s:%s adopt_dlm", ls->name, r->name);
 | 
			
		||||
	log_debug("S %s R %s adopt_dlm", ls->name, r->name);
 | 
			
		||||
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 0;
 | 
			
		||||
@@ -482,29 +389,29 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
 | 
			
		||||
	 * dlm returns 0 for success, -EAGAIN if an orphan is
 | 
			
		||||
	 * found with another mode, and -ENOENT if no orphan.
 | 
			
		||||
	 *
 | 
			
		||||
	 * cast/bast/param are (void (*)(void*))1 because the kernel
 | 
			
		||||
	 * cast/bast/param are (void *)1 because the kernel
 | 
			
		||||
	 * returns errors if some are null.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	rv = dlm_ls_lockx(lmd->dh, mode, lksb, flags,
 | 
			
		||||
			  r->name, strlen(r->name), 0,
 | 
			
		||||
			  (void (*)(void*))1, (void (*)(void*))1, (void (*)(void*))1,
 | 
			
		||||
			  (void *)1, (void *)1, (void *)1,
 | 
			
		||||
			  NULL, NULL);
 | 
			
		||||
 | 
			
		||||
	if (rv == -1 && (errno == EAGAIN)) {
 | 
			
		||||
		log_debug("%s:%s adopt_dlm adopt mode %d try other mode",
 | 
			
		||||
		log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
 | 
			
		||||
			  ls->name, r->name, ld_mode);
 | 
			
		||||
		rv = -EADOPT_RETRY;
 | 
			
		||||
		rv = -EUCLEAN;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
	if (rv == -1 && (errno == ENOENT)) {
 | 
			
		||||
		log_debug("%s:%s adopt_dlm adopt mode %d no lock",
 | 
			
		||||
		log_debug("S %s R %s adopt_dlm adopt mode %d no lock",
 | 
			
		||||
			  ls->name, r->name, ld_mode);
 | 
			
		||||
		rv = -EADOPT_NONE;
 | 
			
		||||
		rv = -ENOENT;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_debug("%s:%s adopt_dlm mode %d flags %x error %d errno %d",
 | 
			
		||||
		log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
 | 
			
		||||
			  ls->name, r->name, mode, flags, rv, errno);
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
@@ -534,7 +441,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
 | 
			
		||||
		struct val_blk *vb_out, int adopt_only, int adopt_ok)
 | 
			
		||||
		struct val_blk *vb_out, int adopt)
 | 
			
		||||
{
 | 
			
		||||
	struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
 | 
			
		||||
	struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
 | 
			
		||||
@@ -544,13 +451,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
 | 
			
		||||
	int mode;
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	if (adopt_ok) {
 | 
			
		||||
		log_debug("%s:%s lock_dlm adopt_ok not supported", ls->name, r->name);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (adopt_only) {
 | 
			
		||||
		log_debug("%s:%s lock_dlm adopt_only", ls->name, r->name);
 | 
			
		||||
	if (adopt) {
 | 
			
		||||
		/* When adopting, we don't follow the normal method
 | 
			
		||||
		   of acquiring a NL lock then converting it to the
 | 
			
		||||
		   desired mode. */
 | 
			
		||||
@@ -579,13 +480,13 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_debug("%s:%s lock_dlm", ls->name, r->name);
 | 
			
		||||
	log_debug("S %s R %s lock_dlm", ls->name, r->name);
 | 
			
		||||
 | 
			
		||||
	if (daemon_test) {
 | 
			
		||||
		if (rdd->vb) {
 | 
			
		||||
			vb_out->version = le16toh(rdd->vb->version);
 | 
			
		||||
			vb_out->flags = le16toh(rdd->vb->flags);
 | 
			
		||||
			vb_out->r_version = le32toh(rdd->vb->r_version);
 | 
			
		||||
			vb_out->version = le16_to_cpu(rdd->vb->version);
 | 
			
		||||
			vb_out->flags = le16_to_cpu(rdd->vb->flags);
 | 
			
		||||
			vb_out->r_version = le32_to_cpu(rdd->vb->r_version);
 | 
			
		||||
		}
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -599,7 +500,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
 | 
			
		||||
				      r->name, strlen(r->name),
 | 
			
		||||
				      0, NULL, NULL, NULL);
 | 
			
		||||
		if (rv == -1) {
 | 
			
		||||
			log_debug("%s:%s lock_dlm acquire mode PR for %d rv %d",
 | 
			
		||||
			log_debug("S %s R %s lock_dlm acquire mode PR for %d rv %d",
 | 
			
		||||
				  ls->name, r->name, mode, rv);
 | 
			
		||||
			goto lockrv;
 | 
			
		||||
		}
 | 
			
		||||
@@ -612,17 +513,17 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
 | 
			
		||||
			      0, NULL, NULL, NULL);
 | 
			
		||||
lockrv:
 | 
			
		||||
	if (rv == -1 && errno == EAGAIN) {
 | 
			
		||||
		log_debug("%s:%s lock_dlm acquire mode %d rv EAGAIN", ls->name, r->name, mode);
 | 
			
		||||
		log_debug("S %s R %s lock_dlm acquire mode %d rv EAGAIN", ls->name, r->name, mode);
 | 
			
		||||
		return -EAGAIN;
 | 
			
		||||
	}
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_error("%s:%s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
 | 
			
		||||
		log_error("S %s R %s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
 | 
			
		||||
		return -ELMERR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rdd->vb) {
 | 
			
		||||
		if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
 | 
			
		||||
			log_debug("%s:%s lock_dlm VALNOTVALID", ls->name, r->name);
 | 
			
		||||
			log_debug("S %s R %s lock_dlm VALNOTVALID", ls->name, r->name);
 | 
			
		||||
			memset(rdd->vb, 0, sizeof(struct val_blk));
 | 
			
		||||
			memset(vb_out, 0, sizeof(struct val_blk));
 | 
			
		||||
			goto out;
 | 
			
		||||
@@ -637,9 +538,9 @@ lockrv:
 | 
			
		||||
		memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk));
 | 
			
		||||
		memcpy(rdd->vb, &vb, sizeof(vb));
 | 
			
		||||
 | 
			
		||||
		vb_out->version = le16toh(vb.version);
 | 
			
		||||
		vb_out->flags = le16toh(vb.flags);
 | 
			
		||||
		vb_out->r_version = le32toh(vb.r_version);
 | 
			
		||||
		vb_out->version = le16_to_cpu(vb.version);
 | 
			
		||||
		vb_out->flags = le16_to_cpu(vb.flags);
 | 
			
		||||
		vb_out->r_version = le32_to_cpu(vb.r_version);
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	return 0;
 | 
			
		||||
@@ -651,11 +552,11 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
	struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
 | 
			
		||||
	struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
 | 
			
		||||
	struct dlm_lksb *lksb = &rdd->lksb;
 | 
			
		||||
	int mode;
 | 
			
		||||
	uint32_t mode;
 | 
			
		||||
	uint32_t flags = 0;
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	log_debug("%s:%s convert_dlm", ls->name, r->name);
 | 
			
		||||
	log_debug("S %s R %s convert_dlm", ls->name, r->name);
 | 
			
		||||
 | 
			
		||||
	flags |= LKF_CONVERT;
 | 
			
		||||
	flags |= LKF_NOQUEUE;
 | 
			
		||||
@@ -664,21 +565,19 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
	if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
 | 
			
		||||
		if (!rdd->vb->version) {
 | 
			
		||||
			/* 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));
 | 
			
		||||
 | 
			
		||||
		log_debug("%s:%s convert_dlm set r_version %u",
 | 
			
		||||
		log_debug("S %s R %s convert_dlm set r_version %u",
 | 
			
		||||
			  ls->name, r->name, r_version);
 | 
			
		||||
 | 
			
		||||
		flags |= LKF_VALBLK;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((mode = to_dlm_mode(ld_mode)) < 0) {
 | 
			
		||||
		log_error("lm_convert_dlm invalid mode %d", ld_mode);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	mode = to_dlm_mode(ld_mode);
 | 
			
		||||
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
@@ -687,11 +586,11 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
			      0, NULL, NULL, NULL);
 | 
			
		||||
	if (rv == -1 && errno == EAGAIN) {
 | 
			
		||||
		/* FIXME: When does this happen?  Should something different be done? */
 | 
			
		||||
		log_error("%s:%s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
 | 
			
		||||
		log_error("S %s R %s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
 | 
			
		||||
		return -EAGAIN;
 | 
			
		||||
	}
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_error("%s:%s convert_dlm error %d", ls->name, r->name, rv);
 | 
			
		||||
		log_error("S %s R %s convert_dlm error %d", ls->name, r->name, rv);
 | 
			
		||||
		rv = -ELMERR;
 | 
			
		||||
	}
 | 
			
		||||
	return rv;
 | 
			
		||||
@@ -723,17 +622,17 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
		memcpy(&vb_next, rdd->vb, sizeof(struct val_blk));
 | 
			
		||||
 | 
			
		||||
		if (!vb_prev.version) {
 | 
			
		||||
			vb_next.version = htole16(VAL_BLK_VERSION);
 | 
			
		||||
			vb_next.version = cpu_to_le16(VAL_BLK_VERSION);
 | 
			
		||||
			new_vb = 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (r_version) {
 | 
			
		||||
			vb_next.r_version = htole32(r_version);
 | 
			
		||||
			vb_next.r_version = cpu_to_le32(r_version);
 | 
			
		||||
			new_vb = 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -741,21 +640,21 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
			memcpy(rdd->vb, &vb_next, sizeof(struct val_blk));
 | 
			
		||||
			memcpy(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,
 | 
			
		||||
				  le16toh(vb_prev.version),
 | 
			
		||||
				  le16toh(vb_prev.flags),
 | 
			
		||||
				  le32toh(vb_prev.r_version),
 | 
			
		||||
				  le16toh(vb_next.version),
 | 
			
		||||
				  le16toh(vb_next.flags),
 | 
			
		||||
				  le32toh(vb_next.r_version));
 | 
			
		||||
				  le16_to_cpu(vb_prev.version),
 | 
			
		||||
				  le16_to_cpu(vb_prev.flags),
 | 
			
		||||
				  le32_to_cpu(vb_prev.r_version),
 | 
			
		||||
				  le16_to_cpu(vb_next.version),
 | 
			
		||||
				  le16_to_cpu(vb_next.flags),
 | 
			
		||||
				  le32_to_cpu(vb_next.r_version));
 | 
			
		||||
		} else {
 | 
			
		||||
			log_debug("%s:%s unlock_dlm vb unchanged", ls->name, r->name);
 | 
			
		||||
			log_debug("S %s R %s unlock_dlm vb unchanged", ls->name, r->name);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		flags |= LKF_VALBLK;
 | 
			
		||||
	} else {
 | 
			
		||||
		log_debug("%s:%s unlock_dlm", ls->name, r->name);
 | 
			
		||||
		log_debug("S %s R %s unlock_dlm", ls->name, r->name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
@@ -765,7 +664,7 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
			      r->name, strlen(r->name),
 | 
			
		||||
			      0, NULL, NULL, NULL);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_error("%s:%s unlock_dlm error %d", ls->name, r->name, rv);
 | 
			
		||||
		log_error("S %s R %s unlock_dlm error %d", ls->name, r->name, rv);
 | 
			
		||||
		rv = -ELMERR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -798,16 +697,9 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
 * 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)
 | 
			
		||||
{
 | 
			
		||||
	static const char closedir_err_msg[] = "lm_hosts_dlm: closedir failed";
 | 
			
		||||
	char ls_nodes_path[PATH_MAX];
 | 
			
		||||
	struct dirent *de;
 | 
			
		||||
	DIR *ls_dir;
 | 
			
		||||
@@ -830,7 +722,7 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (closedir(ls_dir))
 | 
			
		||||
		log_error("lm_hosts_dlm: closedir failed");
 | 
			
		||||
		log_error(closedir_err_msg);
 | 
			
		||||
 | 
			
		||||
	if (!count) {
 | 
			
		||||
		log_error("lm_hosts_dlm found no nodes in %s", ls_nodes_path);
 | 
			
		||||
@@ -847,10 +739,10 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
 | 
			
		||||
 | 
			
		||||
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
 | 
			
		||||
{
 | 
			
		||||
	static const char closedir_err_msg[] = "lm_get_lockspace_dlm: closedir failed";
 | 
			
		||||
	struct lockspace *ls;
 | 
			
		||||
	struct dirent *de;
 | 
			
		||||
	DIR *ls_dir;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	if (!(ls_dir = opendir(DLM_LOCKSPACES_PATH)))
 | 
			
		||||
		return -ECONNREFUSED;
 | 
			
		||||
@@ -863,20 +755,20 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(ls = alloc_lockspace())) {
 | 
			
		||||
			ret = -ENOMEM;
 | 
			
		||||
			goto out;
 | 
			
		||||
			if (closedir(ls_dir))
 | 
			
		||||
				log_error(closedir_err_msg);
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ls->lm_type = LD_LM_DLM;
 | 
			
		||||
		dm_strncpy(ls->name, de->d_name, sizeof(ls->name));
 | 
			
		||||
		dm_strncpy(ls->vg_name, ls->name + strlen(LVM_LS_PREFIX), sizeof(ls->vg_name));
 | 
			
		||||
		strncpy(ls->name, de->d_name, MAX_NAME);
 | 
			
		||||
		strncpy(ls->vg_name, ls->name + strlen(LVM_LS_PREFIX), MAX_NAME);
 | 
			
		||||
		list_add_tail(&ls->list, ls_rejoin);
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	if (closedir(ls_dir))
 | 
			
		||||
		log_error("lm_get_lockspace_dlm: closedir failed");
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
	if (closedir(ls_dir))
 | 
			
		||||
		log_error(closedir_err_msg);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lm_is_running_dlm(void)
 | 
			
		||||
@@ -906,7 +798,7 @@ int lm_refresh_lv_start_dlm(struct action *act)
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	/* split /dev/vgname/lvname into vgname and lvname strings */
 | 
			
		||||
	dm_strncpy(path, act->path, sizeof(path));
 | 
			
		||||
	strncpy(path, act->path, PATH_MAX-1);
 | 
			
		||||
 | 
			
		||||
	/* skip past dev */
 | 
			
		||||
	if (!(p = strchr(path + 1, '/')))
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@
 | 
			
		||||
 | 
			
		||||
#include "tools/tool.h"
 | 
			
		||||
 | 
			
		||||
#include "libdaemon/server/daemon-server.h"
 | 
			
		||||
#include "daemon-server.h"
 | 
			
		||||
#include "lib/mm/xlate.h"
 | 
			
		||||
 | 
			
		||||
#include "lvmlockd-internal.h"
 | 
			
		||||
@@ -136,7 +136,7 @@ static int lm_idm_scsi_directory_select(const struct dirent *s)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int lm_idm_scsi_find_block_directory(const char *block_path)
 | 
			
		||||
static int lm_idm_scsi_find_block_dirctory(const char *block_path)
 | 
			
		||||
{
 | 
			
		||||
	struct stat stats;
 | 
			
		||||
 | 
			
		||||
@@ -252,7 +252,7 @@ static char *lm_idm_scsi_get_block_device_node(const char *scsi_path)
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = lm_idm_scsi_find_block_directory(blk_path);
 | 
			
		||||
	ret = lm_idm_scsi_find_block_dirctory(blk_path);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		log_error("Fail to find block path %s", blk_path);
 | 
			
		||||
		goto fail;
 | 
			
		||||
@@ -364,7 +364,7 @@ static void lm_idm_update_vb_timestamp(uint64_t *vb_timestamp)
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * It's possible that the multiple nodes have no clock
 | 
			
		||||
	 * synchronization with microsecond precision and the time
 | 
			
		||||
	 * synchronization with microsecond prcision and the time
 | 
			
		||||
	 * is going backward.  For this case, simply increment the
 | 
			
		||||
	 * existing timestamp and write out to drive.
 | 
			
		||||
	 */
 | 
			
		||||
@@ -391,7 +391,7 @@ int lm_prepare_lockspace_idm(struct lockspace *ls)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok)
 | 
			
		||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt)
 | 
			
		||||
{
 | 
			
		||||
	char killpath[IDM_FAILURE_PATH_LEN];
 | 
			
		||||
	char killargs[IDM_FAILURE_ARGS_LEN];
 | 
			
		||||
@@ -490,7 +490,7 @@ out:
 | 
			
		||||
	return rv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lm_add_resource_idm(struct lockspace *ls, struct resource *r)
 | 
			
		||||
static int lm_add_resource_idm(struct lockspace *ls, struct resource *r)
 | 
			
		||||
{
 | 
			
		||||
	struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
 | 
			
		||||
 | 
			
		||||
@@ -530,7 +530,7 @@ static int to_idm_mode(int ld_mode)
 | 
			
		||||
 | 
			
		||||
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
 | 
			
		||||
		struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
 | 
			
		||||
		int adopt_only, int adopt_ok)
 | 
			
		||||
		int adopt)
 | 
			
		||||
{
 | 
			
		||||
	struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
 | 
			
		||||
	struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
 | 
			
		||||
@@ -556,9 +556,9 @@ int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
			vb_out->version = le16_to_cpu(rdi->vb->version);
 | 
			
		||||
			vb_out->flags = le16_to_cpu(rdi->vb->flags);
 | 
			
		||||
			vb_out->r_version = le32_to_cpu(rdi->vb->r_version);
 | 
			
		||||
		}
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,9 +13,6 @@
 | 
			
		||||
 | 
			
		||||
#include "base/memory/container_of.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
#define MAX_NAME 64
 | 
			
		||||
#define MAX_ARGS 64
 | 
			
		||||
 | 
			
		||||
@@ -62,7 +59,6 @@ enum {
 | 
			
		||||
	LD_OP_BUSY,
 | 
			
		||||
	LD_OP_QUERY_LOCK,
 | 
			
		||||
	LD_OP_REFRESH_LV,
 | 
			
		||||
	LD_OP_VG_STATUS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* resource types */
 | 
			
		||||
@@ -111,14 +107,11 @@ struct client {
 | 
			
		||||
#define LD_AF_SEARCH_LS            0x00000200
 | 
			
		||||
#define LD_AF_WAIT_STARTING        0x00001000
 | 
			
		||||
#define LD_AF_DUP_GL_LS            0x00002000
 | 
			
		||||
#define LD_AF_ADOPT                0x00010000 /* adopt ok but not required */
 | 
			
		||||
#define LD_AF_ADOPT                0x00010000
 | 
			
		||||
#define LD_AF_WARN_GL_REMOVED	   0x00020000
 | 
			
		||||
#define LD_AF_LV_LOCK              0x00040000
 | 
			
		||||
#define LD_AF_LV_UNLOCK            0x00080000
 | 
			
		||||
#define LD_AF_SH_EXISTS            0x00100000
 | 
			
		||||
#define LD_AF_ADOPT_ONLY           0x00200000 /* adopt orphan or fail */
 | 
			
		||||
#define LD_AF_NODELAY              0x00400000
 | 
			
		||||
#define LD_AF_REPAIR		   0x00800000
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Number of times to repeat a lock request after
 | 
			
		||||
@@ -132,24 +125,12 @@ struct pvs {
 | 
			
		||||
	int num;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define OWNER_NAME_SIZE 64
 | 
			
		||||
#define OWNER_STATE_SIZE 32
 | 
			
		||||
 | 
			
		||||
struct owner {
 | 
			
		||||
	uint32_t host_id;
 | 
			
		||||
	uint32_t generation;
 | 
			
		||||
	uint32_t timestamp;
 | 
			
		||||
	char state[OWNER_STATE_SIZE];
 | 
			
		||||
	char name[OWNER_NAME_SIZE];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct action {
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
	uint32_t client_id;
 | 
			
		||||
	uint32_t flags;			/* LD_AF_ */
 | 
			
		||||
	uint32_t version;
 | 
			
		||||
	uint32_t host_id;
 | 
			
		||||
	uint64_t lv_size_bytes;
 | 
			
		||||
	uint64_t host_id;
 | 
			
		||||
	int8_t op;			/* operation type LD_OP_ */
 | 
			
		||||
	int8_t rt;			/* resource type LD_RT_ */
 | 
			
		||||
	int8_t mode;			/* lock mode LD_LK_ */
 | 
			
		||||
@@ -158,7 +139,6 @@ struct action {
 | 
			
		||||
	int max_retries;
 | 
			
		||||
	int result;
 | 
			
		||||
	int lm_rv;			/* return value from lm_ function */
 | 
			
		||||
	int align_mb;
 | 
			
		||||
	char *path;
 | 
			
		||||
	char vg_uuid[64];
 | 
			
		||||
	char vg_name[MAX_NAME+1];
 | 
			
		||||
@@ -166,8 +146,7 @@ struct action {
 | 
			
		||||
	char lv_uuid[MAX_NAME+1];
 | 
			
		||||
	char vg_args[MAX_ARGS+1];
 | 
			
		||||
	char lv_args[MAX_ARGS+1];
 | 
			
		||||
	char prev_lv_args[MAX_ARGS+1];
 | 
			
		||||
	struct owner owner;
 | 
			
		||||
	char vg_sysid[MAX_NAME+1];
 | 
			
		||||
	struct pvs pvs;			/* PV list for idm */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -180,7 +159,6 @@ struct resource {
 | 
			
		||||
	unsigned int sh_count;		/* number of sh locks on locks list */
 | 
			
		||||
	uint32_t version;
 | 
			
		||||
	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 adopt : 1;		/* temp flag in remove_inactive_lvs */
 | 
			
		||||
	unsigned int version_zero_valid : 1;
 | 
			
		||||
@@ -207,11 +185,13 @@ struct lockspace {
 | 
			
		||||
	char vg_name[MAX_NAME+1];
 | 
			
		||||
	char vg_uuid[64];
 | 
			
		||||
	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 */
 | 
			
		||||
	void *lm_data;
 | 
			
		||||
	uint32_t host_id;
 | 
			
		||||
	uint64_t generation;
 | 
			
		||||
	uint64_t host_id;
 | 
			
		||||
	uint64_t free_lock_offset;	/* for sanlock, start search for free lock here */
 | 
			
		||||
	int free_lock_sector_size;	/* for sanlock */
 | 
			
		||||
	int free_lock_align_size;	/* for sanlock */
 | 
			
		||||
	struct pvs pvs;			/* for idm: PV list */
 | 
			
		||||
 | 
			
		||||
	uint32_t start_client_id;	/* client_id that started the lockspace */
 | 
			
		||||
@@ -231,7 +211,6 @@ struct lockspace {
 | 
			
		||||
 | 
			
		||||
	struct list_head actions;	/* new client actions */
 | 
			
		||||
	struct list_head resources;	/* resource/lock state for gl/vg/lv */
 | 
			
		||||
	struct list_head dispose;	/* resources to free */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* val_blk version */
 | 
			
		||||
@@ -298,15 +277,15 @@ static inline int list_empty(const struct list_head *head)
 | 
			
		||||
	list_entry((ptr)->next, type, 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 = 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)                  \
 | 
			
		||||
	for (pos = list_entry((head)->next, __typeof__(*pos), member),      \
 | 
			
		||||
	     n = list_entry(pos->member.next, __typeof__(*pos), member); \
 | 
			
		||||
	for (pos = list_entry((head)->next, typeof(*pos), member),      \
 | 
			
		||||
	     n = list_entry(pos->member.next, typeof(*pos), member); \
 | 
			
		||||
	     &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 */
 | 
			
		||||
@@ -384,8 +363,6 @@ void log_level(int level, const char *fmt, ...)  __attribute__((format(printf, 2
 | 
			
		||||
#define log_debug(fmt, args...) log_level(LOG_DEBUG, fmt, ##args)
 | 
			
		||||
#define log_error(fmt, args...) log_level(LOG_ERR, fmt, ##args)
 | 
			
		||||
#define log_warn(fmt, args...) log_level(LOG_WARNING, fmt, ##args)
 | 
			
		||||
#define log_sys_debug(x, y) \
 | 
			
		||||
		log_debug("%s: %s failed: %s", y, x, strerror(errno))
 | 
			
		||||
 | 
			
		||||
struct lockspace *alloc_lockspace(void);
 | 
			
		||||
int lockspaces_empty(void);
 | 
			
		||||
@@ -414,12 +391,10 @@ static inline const char *mode_str(int x)
 | 
			
		||||
 | 
			
		||||
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
 | 
			
		||||
int lm_prepare_lockspace_dlm(struct lockspace *ls);
 | 
			
		||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok);
 | 
			
		||||
int lm_purge_locks_dlm(struct lockspace *ls);
 | 
			
		||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
 | 
			
		||||
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
 | 
			
		||||
int lm_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,
 | 
			
		||||
		struct val_blk *vb_out, int adopt_only, int adopt_ok);
 | 
			
		||||
		struct val_blk *vb_out, int adopt);
 | 
			
		||||
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
		   int ld_mode, uint32_t r_version);
 | 
			
		||||
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
@@ -441,102 +416,64 @@ static inline int lm_support_dlm(void)
 | 
			
		||||
 | 
			
		||||
static inline int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
 | 
			
		||||
{
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 0;
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_prepare_lockspace_dlm(struct lockspace *ls)
 | 
			
		||||
{
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 0;
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_convert_dlm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
		   int ld_mode, uint32_t r_version)
 | 
			
		||||
{
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 0;
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
		  uint32_t r_version, uint32_t lmu_flags)
 | 
			
		||||
{
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 0;
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
 | 
			
		||||
{
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 0;
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
 | 
			
		||||
{
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 0;
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_data_size_dlm(void)
 | 
			
		||||
{
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 0;
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_is_running_dlm(void)
 | 
			
		||||
{
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_support_dlm(void)
 | 
			
		||||
{
 | 
			
		||||
	if (daemon_test)
 | 
			
		||||
		return 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -559,17 +496,15 @@ static inline int lm_refresh_lv_check_dlm(struct action *act)
 | 
			
		||||
 | 
			
		||||
#ifdef LOCKDSANLOCK_SUPPORT
 | 
			
		||||
 | 
			
		||||
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb);
 | 
			
		||||
int lm_init_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_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
 | 
			
		||||
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, int sector_size, int align_size, uint64_t free_offset);
 | 
			
		||||
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
 | 
			
		||||
int lm_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_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok, int nodelay);
 | 
			
		||||
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
 | 
			
		||||
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt);
 | 
			
		||||
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,
 | 
			
		||||
		    struct val_blk *vb_out, int *retry, struct owner *owner,
 | 
			
		||||
		    int adopt_only, int adopt_ok, int repair);
 | 
			
		||||
		    struct val_blk *vb_out, int *retry, int adopt);
 | 
			
		||||
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
 | 
			
		||||
		       int ld_mode, uint32_t r_version);
 | 
			
		||||
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
 | 
			
		||||
@@ -582,8 +517,7 @@ int lm_gl_is_enabled(struct lockspace *ls);
 | 
			
		||||
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
 | 
			
		||||
int lm_data_size_sanlock(void);
 | 
			
		||||
int lm_is_running_sanlock(void);
 | 
			
		||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes);
 | 
			
		||||
int lm_vg_status_sanlock(struct lockspace *ls, struct action *act);
 | 
			
		||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size);
 | 
			
		||||
 | 
			
		||||
static inline int lm_support_sanlock(void)
 | 
			
		||||
{
 | 
			
		||||
@@ -592,12 +526,12 @@ static inline int lm_support_sanlock(void)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb)
 | 
			
		||||
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
 | 
			
		||||
{
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args)
 | 
			
		||||
static inline int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, int sector_size, int align_size, uint64_t free_offset)
 | 
			
		||||
{
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
@@ -612,12 +546,12 @@ static inline int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t fl
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
@@ -627,14 +561,8 @@ static inline int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
 | 
			
		||||
	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,
 | 
			
		||||
		    struct val_blk *vb_out, int *retry, struct owner *owner,
 | 
			
		||||
		    int adopt_only, int adopt_ok, int repair)
 | 
			
		||||
		    struct val_blk *vb_out, int *retry, int adopt)
 | 
			
		||||
{
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
@@ -691,12 +619,7 @@ static inline int lm_is_running_sanlock(void)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes)
 | 
			
		||||
{
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_vg_status_sanlock(struct lockspace *ls, struct action *act)
 | 
			
		||||
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size)
 | 
			
		||||
{
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
@@ -713,12 +636,11 @@ static inline int lm_support_sanlock(void)
 | 
			
		||||
int lm_data_size_idm(void);
 | 
			
		||||
int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
 | 
			
		||||
int lm_prepare_lockspace_idm(struct lockspace *ls);
 | 
			
		||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok);
 | 
			
		||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt);
 | 
			
		||||
int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg);
 | 
			
		||||
int lm_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 adopt);
 | 
			
		||||
int lm_convert_idm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
		   int ld_mode, uint32_t r_version);
 | 
			
		||||
int lm_unlock_idm(struct lockspace *ls, struct resource *r,
 | 
			
		||||
@@ -751,7 +673,7 @@ static inline int lm_prepare_lockspace_idm(struct lockspace *ls)
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok)
 | 
			
		||||
static inline int lm_add_lockspace_idm(struct lockspace *ls, int adopt)
 | 
			
		||||
{
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
@@ -761,14 +683,9 @@ 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)
 | 
			
		||||
		       int adopt)
 | 
			
		||||
{
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -32,11 +32,11 @@ LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
 | 
			
		||||
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
 | 
			
		||||
	$(SHOW) "    [CC] $@"
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
 | 
			
		||||
 | 
			
		||||
install_lvmpolld: lvmpolld
 | 
			
		||||
	$(SHOW) "    [INSTALL] $<"
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_lvmpolld
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
 | 
			
		||||
#define MIN_ARGV_SIZE  8
 | 
			
		||||
 | 
			
		||||
static const char *const _polling_ops[] = {
 | 
			
		||||
static const char *const polling_ops[] = {
 | 
			
		||||
	[PVMOVE] = LVMPD_REQ_PVMOVE,
 | 
			
		||||
	[CONVERT] = LVMPD_REQ_CONVERT,
 | 
			
		||||
	[MERGE] = LVMPD_REQ_MERGE,
 | 
			
		||||
@@ -28,7 +28,7 @@ static const char *const _polling_ops[] = {
 | 
			
		||||
 | 
			
		||||
const char *polling_op(enum poll_type type)
 | 
			
		||||
{
 | 
			
		||||
	return type < POLL_TYPE_MAX ? _polling_ops[type] : "<undefined>";
 | 
			
		||||
	return type < POLL_TYPE_MAX ? polling_ops[type] : "<undefined>";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
 | 
			
		||||
@@ -81,7 +81,7 @@ const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary,
 | 
			
		||||
 | 
			
		||||
	/* one of: "convert", "pvmove", "merge", "merge_thin" */
 | 
			
		||||
	if (!add_to_cmd_arr(&cmd_argv, "--polloperation", &i) ||
 | 
			
		||||
	    !add_to_cmd_arr(&cmd_argv, _polling_ops[pdlv->type], &i))
 | 
			
		||||
	    !add_to_cmd_arr(&cmd_argv, polling_ops[pdlv->type], &i))
 | 
			
		||||
		goto err;
 | 
			
		||||
 | 
			
		||||
	/* vg/lv name */
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,8 @@
 | 
			
		||||
#include "lvmpolld-common.h"
 | 
			
		||||
 | 
			
		||||
#include "lvm-version.h"
 | 
			
		||||
#include "libdaemon/server/daemon-server.h"
 | 
			
		||||
#include "libdaemon/server/daemon-log.h"
 | 
			
		||||
#include "daemon-server.h"
 | 
			
		||||
#include "daemon-log.h"
 | 
			
		||||
 | 
			
		||||
#include <getopt.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)
 | 
			
		||||
{
 | 
			
		||||
#if defined(_GNU_SOURCE) && defined(STRERROR_R_CHAR_P)
 | 
			
		||||
#ifdef _GNU_SOURCE
 | 
			
		||||
	return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
 | 
			
		||||
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
 | 
			
		||||
	return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
 | 
			
		||||
@@ -75,7 +75,7 @@ static void _usage(const char *prog, FILE *file)
 | 
			
		||||
		"   -p|--pidfile     Set path to the pidfile\n"
 | 
			
		||||
		"   -s|--socket      Set path to the communication socket\n"
 | 
			
		||||
		"   -B|--binary      Path to lvm2 binary\n"
 | 
			
		||||
		"   -t|--timeout     Time to wait in seconds before shutdown on idle (missing or 0 = 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)
 | 
			
		||||
@@ -390,11 +390,6 @@ static void *fork_and_poll(void *args)
 | 
			
		||||
		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:");
 | 
			
		||||
	debug_print(ls, pdlv->cmdargv);
 | 
			
		||||
	DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
 | 
			
		||||
@@ -786,7 +781,7 @@ struct log_line_baton {
 | 
			
		||||
	const char *prefix;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static daemon_handle _lvmpolld = { .error = 0 };
 | 
			
		||||
daemon_handle _lvmpolld = { .error = 0 };
 | 
			
		||||
 | 
			
		||||
static daemon_handle _lvmpolld_open(const char *socket)
 | 
			
		||||
{
 | 
			
		||||
@@ -872,14 +867,14 @@ enum action_index {
 | 
			
		||||
	ACTION_MAX /* keep at the end */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const action_fn_t actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump };
 | 
			
		||||
 | 
			
		||||
static int _make_action(enum action_index idx, void *args)
 | 
			
		||||
{
 | 
			
		||||
	static const action_fn_t _actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump };
 | 
			
		||||
 | 
			
		||||
	return idx < ACTION_MAX ? _actions[idx](args) : 0;
 | 
			
		||||
	return idx < ACTION_MAX ? actions[idx](args) : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lvmpolld_client(const char *socket, enum action_index action)
 | 
			
		||||
static int _lvmpolld_client(const char *socket, unsigned action)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
@@ -897,9 +892,10 @@ static int _lvmpolld_client(const char *socket, enum action_index action)
 | 
			
		||||
	return r ? EXIT_SUCCESS : EXIT_FAILURE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct option _long_options[] = {
 | 
			
		||||
static int action_idx = ACTION_MAX;
 | 
			
		||||
static struct option long_options[] = {
 | 
			
		||||
	/* Have actions always at the beginning of the array. */
 | 
			
		||||
	{"dump",	no_argument,		0,		ACTION_DUMP }, /* or an option_index ? */
 | 
			
		||||
	{"dump",	no_argument,		&action_idx,	ACTION_DUMP }, /* or an option_index ? */
 | 
			
		||||
 | 
			
		||||
	/* other options */
 | 
			
		||||
	{"binary",	required_argument,	0,		'B' },
 | 
			
		||||
@@ -918,7 +914,7 @@ int main(int argc, char *argv[])
 | 
			
		||||
	int opt;
 | 
			
		||||
	int option_index = 0;
 | 
			
		||||
	int client = 0, server = 0;
 | 
			
		||||
	enum action_index action = ACTION_MAX;
 | 
			
		||||
	unsigned action = ACTION_MAX;
 | 
			
		||||
	struct timespec timeout;
 | 
			
		||||
	daemon_idle di = { .ptimeout = &timeout };
 | 
			
		||||
	struct lvmpolld_state ls = { .log_config = "" };
 | 
			
		||||
@@ -934,16 +930,16 @@ int main(int argc, char *argv[])
 | 
			
		||||
		.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	while ((opt = getopt_long(argc, argv, "fhVl:p:s:B:t:", _long_options, &option_index)) != -1) {
 | 
			
		||||
	while ((opt = getopt_long(argc, argv, "fhVl:p:s:B:t:", long_options, &option_index)) != -1) {
 | 
			
		||||
		switch (opt) {
 | 
			
		||||
		case 0 :
 | 
			
		||||
			if (action != ACTION_MAX) {
 | 
			
		||||
			if (action < ACTION_MAX) {
 | 
			
		||||
				fprintf(stderr, "Can't perform more actions. Action already requested: %s\n",
 | 
			
		||||
					_long_options[action].name);
 | 
			
		||||
					long_options[action].name);
 | 
			
		||||
				_usage(argv[0], stderr);
 | 
			
		||||
				exit(EXIT_FAILURE);
 | 
			
		||||
			}
 | 
			
		||||
			action = ACTION_DUMP;
 | 
			
		||||
			action = action_idx;
 | 
			
		||||
			client = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case '?':
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ static char *_construct_lvm_system_dir_env(const char *sysdir)
 | 
			
		||||
	 *		    - or -
 | 
			
		||||
	 *  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));
 | 
			
		||||
 | 
			
		||||
	if (!env)
 | 
			
		||||
@@ -89,17 +89,6 @@ char *construct_id(const char *sysdir, const char *uuid)
 | 
			
		||||
	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,
 | 
			
		||||
			   const char *vgname, const char *lvname,
 | 
			
		||||
			   const char *sysdir, enum poll_type type,
 | 
			
		||||
@@ -107,26 +96,30 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
 | 
			
		||||
			   struct lvmpolld_store *pdst,
 | 
			
		||||
			   const char *devicesfile)
 | 
			
		||||
{
 | 
			
		||||
	char *lvmpolld_id = strdup(id), /* copy */
 | 
			
		||||
	     *full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
 | 
			
		||||
	     *lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
 | 
			
		||||
	char *devicesfile_dup = devicesfile ? strdup(devicesfile) : NULL;
 | 
			
		||||
 | 
			
		||||
	struct lvmpolld_lv tmp = {
 | 
			
		||||
		.ls = ls,
 | 
			
		||||
		.type = type,
 | 
			
		||||
		.lvmpolld_id = strdup(id),
 | 
			
		||||
		.lvname = _construct_full_lvname(vgname, lvname),
 | 
			
		||||
		.devicesfile = devicesfile ? strdup(devicesfile) : NULL,
 | 
			
		||||
		.lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir),
 | 
			
		||||
		.sinterval = strdup(sinterval),
 | 
			
		||||
		.lvmpolld_id = lvmpolld_id,
 | 
			
		||||
		.lvid = _get_lvid(lvmpolld_id, sysdir),
 | 
			
		||||
		.lvname = full_lvname,
 | 
			
		||||
		.devicesfile = devicesfile_dup,
 | 
			
		||||
		.lvm_system_dir_env = lvm_system_dir_env,
 | 
			
		||||
		.sinterval = strdup(sinterval), /* copy */
 | 
			
		||||
		.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
 | 
			
		||||
		.cmd_state = { .retcode = -1, .signal = 0 },
 | 
			
		||||
		.pdst = pdst,
 | 
			
		||||
		.init_rq_count = 1
 | 
			
		||||
	}, *pdlv = (struct lvmpolld_lv *) 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;
 | 
			
		||||
 | 
			
		||||
	tmp.lvid = _get_lvid(tmp.lvmpolld_id, sysdir),
 | 
			
		||||
 | 
			
		||||
	*pdlv = tmp;
 | 
			
		||||
	memcpy(pdlv, &tmp, sizeof(*pdlv));
 | 
			
		||||
 | 
			
		||||
	if (pthread_mutex_init(&pdlv->lock, NULL))
 | 
			
		||||
		goto err;
 | 
			
		||||
@@ -134,20 +127,29 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
 | 
			
		||||
	return pdlv;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
	_free_lvmpolld_lv(&tmp);
 | 
			
		||||
 | 
			
		||||
	free(pdlv);
 | 
			
		||||
	free((void *)devicesfile_dup);
 | 
			
		||||
	free((void *)full_lvname);
 | 
			
		||||
	free((void *)lvmpolld_id);
 | 
			
		||||
	free((void *)lvm_system_dir_env);
 | 
			
		||||
	free((void *)tmp.sinterval);
 | 
			
		||||
	free((void *)pdlv);
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pdlv_destroy(struct lvmpolld_lv *pdlv)
 | 
			
		||||
{
 | 
			
		||||
	_free_lvmpolld_lv(pdlv);
 | 
			
		||||
	free((void *)pdlv->lvmpolld_id);
 | 
			
		||||
	free((void *)pdlv->devicesfile);
 | 
			
		||||
	free((void *)pdlv->lvname);
 | 
			
		||||
	free((void *)pdlv->sinterval);
 | 
			
		||||
	free((void *)pdlv->lvm_system_dir_env);
 | 
			
		||||
	free((void *)pdlv->cmdargv);
 | 
			
		||||
	free((void *)pdlv->cmdenvp);
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_destroy(&pdlv->lock);
 | 
			
		||||
 | 
			
		||||
	free(pdlv);
 | 
			
		||||
	free((void *)pdlv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)
 | 
			
		||||
@@ -271,12 +273,12 @@ static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdl
 | 
			
		||||
		buffer_append(buff, tmp);
 | 
			
		||||
	if (dm_snprintf(tmp, sizeof(tmp), "\t\tpolling_finished=%d\n", pdlv->polling_finished) > 0)
 | 
			
		||||
		buffer_append(buff, tmp);
 | 
			
		||||
	if (dm_snprintf(tmp, sizeof(tmp), "\t\terror_occurred=%d\n", pdlv->error) > 0)
 | 
			
		||||
	if (dm_snprintf(tmp, sizeof(tmp), "\t\terror_occured=%d\n", pdlv->error) > 0)
 | 
			
		||||
		buffer_append(buff, tmp);
 | 
			
		||||
	if (dm_snprintf(tmp, sizeof(tmp), "\t\tinit_requests_count=%d\n", pdlv->init_rq_count) > 0)
 | 
			
		||||
		buffer_append(buff, tmp);
 | 
			
		||||
 | 
			
		||||
	/* lvm_command-section { */
 | 
			
		||||
	/* lvm_commmand-section { */
 | 
			
		||||
	buffer_append(buff, "\t\tlvm_command {\n");
 | 
			
		||||
	if (cmd_state->retcode == -1 && !cmd_state->signal)
 | 
			
		||||
		buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_IN_PROGRESS "\"\n");
 | 
			
		||||
@@ -288,7 +290,7 @@ static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdl
 | 
			
		||||
			buffer_append(buff, tmp);
 | 
			
		||||
	}
 | 
			
		||||
	buffer_append(buff, "\t\t}\n");
 | 
			
		||||
	/* } lvm_command-section */
 | 
			
		||||
	/* } lvm_commmand-section */
 | 
			
		||||
 | 
			
		||||
	buffer_append(buff, "\t}\n");
 | 
			
		||||
	/* } pdlv-section */
 | 
			
		||||
 
 | 
			
		||||
@@ -15,10 +15,7 @@
 | 
			
		||||
#ifndef _LVM_LVMPOLLD_DATA_UTILS_H
 | 
			
		||||
#define _LVM_LVMPOLLD_DATA_UTILS_H
 | 
			
		||||
 | 
			
		||||
#include "base/data-struct/hash.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
struct buffer;
 | 
			
		||||
struct lvmpolld_state;
 | 
			
		||||
@@ -48,18 +45,18 @@ struct lvmpolld_lv {
 | 
			
		||||
	 * accessing following vars doesn't
 | 
			
		||||
	 * require struct lvmpolld_lv lock
 | 
			
		||||
	 */
 | 
			
		||||
	struct lvmpolld_state *ls;
 | 
			
		||||
	enum poll_type type;
 | 
			
		||||
	const char *lvid;
 | 
			
		||||
	const char *lvmpolld_id;
 | 
			
		||||
	const char *devicesfile;
 | 
			
		||||
	const char *lvname; /* full vg/lv name */
 | 
			
		||||
	unsigned pdtimeout; /* in seconds */
 | 
			
		||||
	const char *sinterval;
 | 
			
		||||
	const char *lvm_system_dir_env;
 | 
			
		||||
	struct lvmpolld_store *pdst;
 | 
			
		||||
	const char **cmdargv;
 | 
			
		||||
	const char **cmdenvp;
 | 
			
		||||
	struct lvmpolld_state *const ls;
 | 
			
		||||
	const enum poll_type type;
 | 
			
		||||
	const char *const lvid;
 | 
			
		||||
	const char *const lvmpolld_id;
 | 
			
		||||
	const char *const devicesfile;
 | 
			
		||||
	const char *const lvname; /* full vg/lv name */
 | 
			
		||||
	const unsigned pdtimeout; /* in seconds */
 | 
			
		||||
	const char *const sinterval;
 | 
			
		||||
	const char *const lvm_system_dir_env;
 | 
			
		||||
	struct lvmpolld_store *const pdst;
 | 
			
		||||
	const char *const *cmdargv;
 | 
			
		||||
	const char *const *cmdenvp;
 | 
			
		||||
 | 
			
		||||
	/* only used by write */
 | 
			
		||||
	pid_t cmd_pid;
 | 
			
		||||
@@ -69,9 +66,9 @@ struct lvmpolld_lv {
 | 
			
		||||
 | 
			
		||||
	/* block of shared variables protected by lock */
 | 
			
		||||
	struct lvmpolld_cmd_stat cmd_state;
 | 
			
		||||
	unsigned init_rq_count; /* for debugging purposes only */
 | 
			
		||||
	unsigned init_rq_count; /* for debuging purposes only */
 | 
			
		||||
	unsigned polling_finished:1; /* no more updates */
 | 
			
		||||
	unsigned error:1; /* unrecoverable error 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);
 | 
			
		||||
@@ -96,7 +93,7 @@ struct lvmpolld_thread_data {
 | 
			
		||||
	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 */
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@
 | 
			
		||||
#define LVMPD_RESP_OK		"OK"
 | 
			
		||||
 | 
			
		||||
#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_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.
 | 
			
		||||
#
 | 
			
		||||
@@ -25,12 +25,10 @@ DEVICE_MAPPER_SOURCE=\
 | 
			
		||||
	device_mapper/libdm-targets.c \
 | 
			
		||||
	device_mapper/libdm-timestamp.c \
 | 
			
		||||
	device_mapper/mm/pool.c \
 | 
			
		||||
	device_mapper/raid/raid_parser.c \
 | 
			
		||||
	device_mapper/regex/matcher.c \
 | 
			
		||||
	device_mapper/regex/parse_rx.c \
 | 
			
		||||
	device_mapper/regex/ttree.c \
 | 
			
		||||
	device_mapper/vdo/status.c \
 | 
			
		||||
	device_mapper/vdo/vdo_reader.c \
 | 
			
		||||
	device_mapper/vdo/vdo_target.c
 | 
			
		||||
 | 
			
		||||
DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a
 | 
			
		||||
@@ -45,10 +43,10 @@ CLEAN_TARGETS += $(DEVICE_MAPPER_DEPENDS) $(DEVICE_MAPPER_OBJECTS) \
 | 
			
		||||
#$(DEVICE_MAPPER_OBJECTS): INCLUDES+=$(VDO_INCLUDES)
 | 
			
		||||
 | 
			
		||||
$(DEVICE_MAPPER_TARGET): $(DEVICE_MAPPER_OBJECTS)
 | 
			
		||||
	$(SHOW) "    [AR] $@"
 | 
			
		||||
	@echo "    [AR] $@"
 | 
			
		||||
	$(Q) $(RM) $@
 | 
			
		||||
	$(Q) $(AR) rsv $@ $(DEVICE_MAPPER_OBJECTS) > /dev/null
 | 
			
		||||
 | 
			
		||||
ifeq ("$(USE_TRACKING)","yes")
 | 
			
		||||
ifeq ("$(DEPENDS)","yes")
 | 
			
		||||
-include $(DEVICE_MAPPER_DEPENDS)
 | 
			
		||||
endif
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,6 @@
 | 
			
		||||
 | 
			
		||||
#include "base/data-struct/list.h"
 | 
			
		||||
#include "base/data-struct/hash.h"
 | 
			
		||||
#include "raid/target.h"
 | 
			
		||||
#include "vdo/target.h"
 | 
			
		||||
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
@@ -176,11 +175,12 @@ struct dm_names {
 | 
			
		||||
 | 
			
		||||
struct dm_active_device {
 | 
			
		||||
	struct dm_list list;
 | 
			
		||||
	dev_t devno;
 | 
			
		||||
	const char *name;	/* device name */
 | 
			
		||||
	int major;
 | 
			
		||||
	int minor;
 | 
			
		||||
	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 */
 | 
			
		||||
	char *uuid;	/* valid uuid when DM_DEVICE_LIST_HAS_UUID is set */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct dm_versions {
 | 
			
		||||
@@ -192,7 +192,7 @@ struct dm_versions {
 | 
			
		||||
 | 
			
		||||
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_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
 | 
			
		||||
@@ -230,6 +230,13 @@ struct dm_names *dm_task_get_names(struct dm_task *dmt);
 | 
			
		||||
#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);
 | 
			
		||||
/*
 | 
			
		||||
 * -1: no idea about uuid (not provided by DM_DEVICE_LIST ioctl)
 | 
			
		||||
 *  0: uuid not present
 | 
			
		||||
 *  1: listed and dm_active_device will be set for not NULL pointer
 | 
			
		||||
 */
 | 
			
		||||
int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
 | 
			
		||||
				const struct dm_active_device **dev);
 | 
			
		||||
/* Release all associated memory with list of active DM devices */
 | 
			
		||||
void dm_device_list_destroy(struct dm_list **devs_list);
 | 
			
		||||
 | 
			
		||||
@@ -305,15 +312,15 @@ int dm_task_add_target(struct dm_task *dmt,
 | 
			
		||||
#define DM_FORMAT_DEV_BUFSIZE	13	/* Minimum bufsize to handle worst case. */
 | 
			
		||||
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 *next, uint64_t *start, uint64_t *length,
 | 
			
		||||
			 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.
 | 
			
		||||
 * Destroying the mempool will release all associated allocation.
 | 
			
		||||
 * Destroying the mempool will release all asociated allocation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Parse params from STATUS call for mirror target */
 | 
			
		||||
@@ -542,7 +549,7 @@ const char *dm_sysfs_dir(void);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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-".
 | 
			
		||||
 * To support stacks of devices from different subsystems, recursive functions
 | 
			
		||||
 * stop recursing if they reach a device with a different prefix.
 | 
			
		||||
@@ -585,7 +592,7 @@ int dm_device_has_mounted_fs(uint32_t major, uint32_t minor);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Callback is invoked for individual mountinfo lines,
 | 
			
		||||
 * Callback is invoked for individal mountinfo lines,
 | 
			
		||||
 * minor, major and mount target are parsed and unmangled.
 | 
			
		||||
 */
 | 
			
		||||
typedef int (*dm_mountinfo_line_callback_fn) (char *line, unsigned maj, unsigned min,
 | 
			
		||||
@@ -699,7 +706,7 @@ void *dm_tree_node_get_context(const struct dm_tree_node *node);
 | 
			
		||||
/*
 | 
			
		||||
 * Returns  0 when node size and its children is unchanged.
 | 
			
		||||
 * Returns  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);
 | 
			
		||||
 | 
			
		||||
@@ -886,7 +893,7 @@ struct dm_tree_node_raid_params {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Version 2 of above node raid params struct to keep API compatibility.
 | 
			
		||||
 * Version 2 of above node raid params struct to keeep API compatibility.
 | 
			
		||||
 *
 | 
			
		||||
 * Extended for more than 64 legs (max 253 in the MD kernel runtime!),
 | 
			
		||||
 * delta_disks for disk add/remove reshaping,
 | 
			
		||||
@@ -909,7 +916,7 @@ struct dm_tree_node_raid_params_v2 {
 | 
			
		||||
	 * 'rebuilds' and 'writemostly' are bitfields that signify
 | 
			
		||||
	 * which devices in the array are to be rebuilt or marked
 | 
			
		||||
	 * 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.
 | 
			
		||||
	 */
 | 
			
		||||
	uint64_t rebuilds[RAID_BITMAP_SIZE];
 | 
			
		||||
@@ -946,7 +953,7 @@ struct dm_config_node;
 | 
			
		||||
 *
 | 
			
		||||
 * policy_settings {
 | 
			
		||||
 *    migration_threshold=2048
 | 
			
		||||
 *    sequential_threshold=100
 | 
			
		||||
 *    sequention_threashold=100
 | 
			
		||||
 *    ...
 | 
			
		||||
 * }
 | 
			
		||||
 *
 | 
			
		||||
@@ -975,9 +982,7 @@ struct writecache_settings {
 | 
			
		||||
	uint32_t fua;
 | 
			
		||||
	uint32_t nofua;
 | 
			
		||||
	uint32_t cleaner;
 | 
			
		||||
	uint32_t max_age;         /* in milliseconds */
 | 
			
		||||
	uint32_t metadata_only;
 | 
			
		||||
	uint32_t pause_writeback; /* in milliseconds */
 | 
			
		||||
	uint32_t max_age;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Allow an unrecognized key and its val to be passed to the kernel for
 | 
			
		||||
@@ -999,8 +1004,6 @@ struct writecache_settings {
 | 
			
		||||
	unsigned nofua_set:1;
 | 
			
		||||
	unsigned cleaner_set:1;
 | 
			
		||||
	unsigned max_age_set:1;
 | 
			
		||||
	unsigned metadata_only_set:1;
 | 
			
		||||
	unsigned pause_writeback_set:1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
 | 
			
		||||
@@ -1024,7 +1027,6 @@ struct integrity_settings {
 | 
			
		||||
	uint32_t commit_time;
 | 
			
		||||
	uint32_t bitmap_flush_interval;
 | 
			
		||||
	uint64_t sectors_per_bit;
 | 
			
		||||
	uint32_t allow_discards;
 | 
			
		||||
 | 
			
		||||
	unsigned journal_sectors_set:1;
 | 
			
		||||
	unsigned interleave_sectors_set:1;
 | 
			
		||||
@@ -1033,7 +1035,6 @@ struct integrity_settings {
 | 
			
		||||
	unsigned commit_time_set:1;
 | 
			
		||||
	unsigned bitmap_flush_interval_set:1;
 | 
			
		||||
	unsigned sectors_per_bit_set:1;
 | 
			
		||||
	unsigned allow_discards_set:1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
 | 
			
		||||
@@ -1048,11 +1049,10 @@ int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
 | 
			
		||||
 */
 | 
			
		||||
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
 | 
			
		||||
				uint64_t size,
 | 
			
		||||
				uint32_t vdo_version,
 | 
			
		||||
				const char *vdo_pool_name,
 | 
			
		||||
				const char *data_uuid,
 | 
			
		||||
				uint64_t data_size,
 | 
			
		||||
				const struct dm_vdo_target_params *vtp);
 | 
			
		||||
				const struct dm_vdo_target_params *param);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * FIXME Add individual cache policy pairs  <key> = value, like:
 | 
			
		||||
@@ -1095,7 +1095,7 @@ int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
 | 
			
		||||
/* 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_MAX_SECTORS (1024 * 1024 * 1024 >> SECTOR_SHIFT)
 | 
			
		||||
 */
 | 
			
		||||
@@ -1161,7 +1161,7 @@ int dm_tree_node_set_thin_pool_error_if_no_space(struct dm_tree_node *node,
 | 
			
		||||
int dm_tree_node_set_thin_pool_read_only(struct dm_tree_node *node,
 | 
			
		||||
					 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)
 | 
			
		||||
 */
 | 
			
		||||
#define DM_THIN_MAX_DEVICE_ID (UINT32_C((1 << 24) - 1))
 | 
			
		||||
@@ -1179,9 +1179,9 @@ void dm_tree_node_set_presuspend_node(struct dm_tree_node *node,
 | 
			
		||||
				      struct dm_tree_node *presuspend_node);
 | 
			
		||||
 | 
			
		||||
int dm_tree_node_add_target_area(struct dm_tree_node *node,
 | 
			
		||||
				 const char *dev_name,
 | 
			
		||||
				 const char *uuid,
 | 
			
		||||
				 uint64_t offset);
 | 
			
		||||
				    const char *dev_name,
 | 
			
		||||
				    const char *dlid,
 | 
			
		||||
				    uint64_t offset);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Only for temporarily-missing raid devices where changes are tracked.
 | 
			
		||||
@@ -1591,9 +1591,9 @@ int dm_fclose(FILE *stream);
 | 
			
		||||
 * Pointer to the buffer is stored in *buf.
 | 
			
		||||
 * 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)));
 | 
			
		||||
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)));
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -1870,7 +1870,6 @@ const void *dm_report_value_cache_get(struct dm_report *rh, const char *name);
 | 
			
		||||
#define DM_REPORT_OUTPUT_FIELD_UNQUOTED		0x00000010
 | 
			
		||||
#define DM_REPORT_OUTPUT_COLUMNS_AS_ROWS	0x00000020
 | 
			
		||||
#define DM_REPORT_OUTPUT_MULTIPLE_TIMES		0x00000040
 | 
			
		||||
#define DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS	0x00000080
 | 
			
		||||
 | 
			
		||||
struct dm_report *dm_report_init(uint32_t *report_types,
 | 
			
		||||
				 const struct dm_report_object_type *types,
 | 
			
		||||
@@ -1942,7 +1941,7 @@ void dm_report_free(struct dm_report *rh);
 | 
			
		||||
 * Prefix added to each field name with DM_REPORT_OUTPUT_FIELD_NAME_PREFIX
 | 
			
		||||
 */
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
@@ -1983,8 +1982,7 @@ struct dm_report_group;
 | 
			
		||||
typedef enum {
 | 
			
		||||
	DM_REPORT_GROUP_SINGLE,
 | 
			
		||||
	DM_REPORT_GROUP_BASIC,
 | 
			
		||||
	DM_REPORT_GROUP_JSON,
 | 
			
		||||
	DM_REPORT_GROUP_JSON_STD
 | 
			
		||||
	DM_REPORT_GROUP_JSON
 | 
			
		||||
} dm_report_group_type_t;
 | 
			
		||||
 | 
			
		||||
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data);
 | 
			
		||||
@@ -2035,7 +2033,6 @@ struct dm_config_tree *dm_config_create(void);
 | 
			
		||||
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_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_set_custom(struct dm_config_tree *cft, void *custom);
 | 
			
		||||
@@ -2060,7 +2057,7 @@ void dm_config_destroy(struct dm_config_tree *cft);
 | 
			
		||||
 | 
			
		||||
/* Simple output line by line. */
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -2082,7 +2079,7 @@ int dm_config_write_one_node_out(const struct dm_config_node *cn, const struct d
 | 
			
		||||
 | 
			
		||||
struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn, const char *path);
 | 
			
		||||
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_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);
 | 
			
		||||
@@ -2114,7 +2111,7 @@ unsigned dm_config_maybe_section(const char *str, unsigned len);
 | 
			
		||||
 | 
			
		||||
const char *dm_config_parent_name(const struct dm_config_node *n);
 | 
			
		||||
 | 
			
		||||
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_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);
 | 
			
		||||
@@ -2123,7 +2120,7 @@ struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const st
 | 
			
		||||
 * Common formatting flags applicable to all config node types (lower 16 bits).
 | 
			
		||||
 */
 | 
			
		||||
#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).
 | 
			
		||||
@@ -2169,7 +2166,7 @@ struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
 | 
			
		||||
 */
 | 
			
		||||
#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
 | 
			
		||||
 * be applied (to create the nodes and symlinks under /dev and /dev/disk).
 | 
			
		||||
 */
 | 
			
		||||
@@ -2240,7 +2237,7 @@ struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
 | 
			
		||||
int dm_cookie_supported(void);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Udev synchronization functions.
 | 
			
		||||
 * Udev synchronisation functions.
 | 
			
		||||
 */
 | 
			
		||||
void dm_udev_set_sync_support(int sync_with_udev);
 | 
			
		||||
int dm_udev_get_sync_support(void);
 | 
			
		||||
 
 | 
			
		||||
@@ -70,7 +70,6 @@ static unsigned _dm_version_minor = 0;
 | 
			
		||||
static unsigned _dm_version_patchlevel = 0;
 | 
			
		||||
static int _log_suppress = 0;
 | 
			
		||||
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
 | 
			
		||||
@@ -88,8 +87,10 @@ static int _version_checked = 0;
 | 
			
		||||
static int _version_ok = 1;
 | 
			
		||||
static unsigned _ioctl_buffer_double_factor = 0;
 | 
			
		||||
 | 
			
		||||
const int _dm_compat = 0;
 | 
			
		||||
 | 
			
		||||
/* *INDENT-OFF* */
 | 
			
		||||
static const struct cmd_data _cmd_data_v4[] = {
 | 
			
		||||
static struct cmd_data _cmd_data_v4[] = {
 | 
			
		||||
	{"create",	DM_DEV_CREATE,		{4, 0, 0}},
 | 
			
		||||
	{"reload",	DM_TABLE_LOAD,		{4, 0, 0}},
 | 
			
		||||
	{"remove",	DM_DEV_REMOVE,		{4, 0, 0}},
 | 
			
		||||
@@ -138,6 +139,7 @@ static char *_align(char *ptr, unsigned int a)
 | 
			
		||||
	return (char *) (((unsigned long) ptr + agn) & ~agn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef DM_IOCTLS
 | 
			
		||||
static unsigned _kernel_major = 0;
 | 
			
		||||
static unsigned _kernel_minor = 0;
 | 
			
		||||
static unsigned _kernel_release = 0;
 | 
			
		||||
@@ -180,9 +182,6 @@ int get_uname_version(unsigned *major, unsigned *minor, unsigned *release)
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef DM_IOCTLS
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set number to NULL to populate _dm_bitset - otherwise first
 | 
			
		||||
 * match is returned.
 | 
			
		||||
@@ -199,7 +198,6 @@ static int _get_proc_number(const char *file, const char *name,
 | 
			
		||||
	char *line = NULL;
 | 
			
		||||
	size_t len;
 | 
			
		||||
	uint32_t num;
 | 
			
		||||
	unsigned blocksection = (strcmp(file, PROC_DEVICES) == 0) ? 0 : 1;
 | 
			
		||||
 | 
			
		||||
	if (!(fl = fopen(file, "r"))) {
 | 
			
		||||
		log_sys_error("fopen", file);
 | 
			
		||||
@@ -207,9 +205,7 @@ static int _get_proc_number(const char *file, const char *name,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (getline(&line, &len, fl) != -1) {
 | 
			
		||||
		if (!blocksection && (line[0] == 'B'))
 | 
			
		||||
			blocksection = 1;
 | 
			
		||||
		else if (sscanf(line, "%u %255s\n", &num, &nm[0]) == 2) {
 | 
			
		||||
		if (sscanf(line, "%u %255s\n", &num, &nm[0]) == 2) {
 | 
			
		||||
			if (!strcmp(name, nm)) {
 | 
			
		||||
				if (number) {
 | 
			
		||||
					*number = num;
 | 
			
		||||
@@ -249,16 +245,6 @@ static int _control_device_number(uint32_t *major, uint32_t *minor)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _control_unlink(const char *control)
 | 
			
		||||
{
 | 
			
		||||
	if (unlink(control) && (errno != ENOENT)) {
 | 
			
		||||
		log_sys_error("unlink", control);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Returns 1 if it exists on returning; 0 if it doesn't; -1 if it's wrong.
 | 
			
		||||
 */
 | 
			
		||||
@@ -274,7 +260,10 @@ static int _control_exists(const char *control, uint32_t major, uint32_t minor)
 | 
			
		||||
 | 
			
		||||
	if (!S_ISCHR(buf.st_mode)) {
 | 
			
		||||
		log_verbose("%s: Wrong inode type", control);
 | 
			
		||||
		return _control_unlink(control);
 | 
			
		||||
		if (!unlink(control))
 | 
			
		||||
			return 0;
 | 
			
		||||
		log_sys_error("unlink", control);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (major && buf.st_rdev != MKDEV(major, minor)) {
 | 
			
		||||
@@ -282,7 +271,10 @@ static int _control_exists(const char *control, uint32_t major, uint32_t minor)
 | 
			
		||||
			    "(%u, %u)", control,
 | 
			
		||||
			    MAJOR(buf.st_mode), MINOR(buf.st_mode),
 | 
			
		||||
			    major, minor);
 | 
			
		||||
		return _control_unlink(control);
 | 
			
		||||
		if (!unlink(control))
 | 
			
		||||
			return 0;
 | 
			
		||||
		log_sys_error("unlink", control);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
@@ -318,13 +310,8 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
 | 
			
		||||
	old_umask = umask(DM_CONTROL_NODE_UMASK);
 | 
			
		||||
	if (mknod(control, S_IFCHR | S_IRUSR | S_IWUSR,
 | 
			
		||||
		  MKDEV(major, minor)) < 0)  {
 | 
			
		||||
		if (errno != EEXIST) {
 | 
			
		||||
			log_sys_error("mknod", control);
 | 
			
		||||
			ret = 0;
 | 
			
		||||
		} else if (_control_exists(control, major, minor) != 1) {
 | 
			
		||||
			stack; /* Invalid control node created by parallel command ? */
 | 
			
		||||
			ret = 0;
 | 
			
		||||
		}
 | 
			
		||||
		log_sys_error("mknod", control);
 | 
			
		||||
		ret = 0;
 | 
			
		||||
	}
 | 
			
		||||
	umask(old_umask);
 | 
			
		||||
	(void) dm_prepare_selinux_context(NULL, 0);
 | 
			
		||||
@@ -410,7 +397,7 @@ static void _close_control_fd(void)
 | 
			
		||||
{
 | 
			
		||||
	if (_control_fd != -1) {
 | 
			
		||||
		if (close(_control_fd) < 0)
 | 
			
		||||
			log_sys_debug("close", "_control_fd");
 | 
			
		||||
			log_sys_error("close", "_control_fd");
 | 
			
		||||
		_control_fd = -1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -486,7 +473,7 @@ static void _dm_zfree_string(char *string)
 | 
			
		||||
{
 | 
			
		||||
	if (string) {
 | 
			
		||||
		memset(string, 0, strlen(string));
 | 
			
		||||
		__asm__ volatile ("" ::: "memory"); /* Compiler barrier. */
 | 
			
		||||
		asm volatile ("" ::: "memory"); /* Compiler barrier. */
 | 
			
		||||
		free(string);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -495,7 +482,7 @@ static void _dm_zfree_dmi(struct dm_ioctl *dmi)
 | 
			
		||||
{
 | 
			
		||||
	if (dmi) {
 | 
			
		||||
		memset(dmi, 0, dmi->data_size);
 | 
			
		||||
		__asm__ volatile ("" ::: "memory"); /* Compiler barrier. */
 | 
			
		||||
		asm volatile ("" ::: "memory"); /* Compiler barrier. */
 | 
			
		||||
		free(dmi);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -599,9 +586,23 @@ int dm_check_version(void)
 | 
			
		||||
 | 
			
		||||
	_version_checked = 1;
 | 
			
		||||
 | 
			
		||||
	if (_check_version(dmversion, sizeof(dmversion), 0))
 | 
			
		||||
	if (_check_version(dmversion, sizeof(dmversion), _dm_compat))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (!_dm_compat)
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	log_verbose("device-mapper ioctl protocol version %u failed. "
 | 
			
		||||
		    "Trying protocol version 1.", _dm_version);
 | 
			
		||||
	_dm_version = 1;
 | 
			
		||||
	if (_check_version(dmversion, sizeof(dmversion), 0)) {
 | 
			
		||||
		log_verbose("Using device-mapper ioctl protocol version 1");
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	compat = "(compat)";
 | 
			
		||||
 | 
			
		||||
      bad:
 | 
			
		||||
	dm_get_library_version(libversion, sizeof(libversion));
 | 
			
		||||
 | 
			
		||||
	log_error("Incompatible libdevmapper %s%s and kernel driver %s.",
 | 
			
		||||
@@ -660,7 +661,7 @@ void *dm_get_next_target(struct dm_task *dmt, void *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)
 | 
			
		||||
{
 | 
			
		||||
	char *outbuf = (char *) dmi + dmi->data_start;
 | 
			
		||||
@@ -749,11 +750,6 @@ uint32_t dm_task_get_read_ahead(const struct dm_task *dmt, uint32_t *read_ahead)
 | 
			
		||||
 | 
			
		||||
struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
 | 
			
		||||
{
 | 
			
		||||
	if (!dmt) {
 | 
			
		||||
		log_error(INTERNAL_ERROR "Missing dm_task.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (struct dm_deps *) (((char *) dmt->dmi.v4) +
 | 
			
		||||
				   dmt->dmi.v4->data_start);
 | 
			
		||||
}
 | 
			
		||||
@@ -770,7 +766,7 @@ static size_t _align_val(size_t val)
 | 
			
		||||
}
 | 
			
		||||
static void *_align_ptr(void *ptr)
 | 
			
		||||
{
 | 
			
		||||
	return (void *)(uintptr_t)_align_val((size_t)ptr);
 | 
			
		||||
	return (void *)_align_val((size_t)ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _check_has_event_nr(void) {
 | 
			
		||||
@@ -783,12 +779,19 @@ static int _check_has_event_nr(void) {
 | 
			
		||||
	return _has_event_nr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_device_list {
 | 
			
		||||
	struct dm_list list;
 | 
			
		||||
	unsigned count;
 | 
			
		||||
	unsigned features;
 | 
			
		||||
	struct dm_hash_table *uuids;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
 | 
			
		||||
			    unsigned *devs_features)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_names *names, *names1;
 | 
			
		||||
	struct dm_active_device *dm_dev, *dm_new_dev;
 | 
			
		||||
	struct dm_list *devs;
 | 
			
		||||
	struct dm_device_list *devs;
 | 
			
		||||
	unsigned next = 0;
 | 
			
		||||
	uint32_t *event_nr;
 | 
			
		||||
	char *uuid_ptr;
 | 
			
		||||
@@ -809,12 +812,12 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
 | 
			
		||||
		} 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))))
 | 
			
		||||
	if (!(devs = malloc(sizeof(*devs) + (cnt ? cnt * sizeof(*dm_dev) + (char*)names1 - (char*)names + 256 : 0))))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	dm_list_init(devs);
 | 
			
		||||
	dm_list_init(&devs->list);
 | 
			
		||||
	devs->count = cnt;
 | 
			
		||||
	devs->uuids = NULL;
 | 
			
		||||
 | 
			
		||||
	if (!cnt) {
 | 
			
		||||
		/* nothing in the list -> mark all features present */
 | 
			
		||||
@@ -822,22 +825,27 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
 | 
			
		||||
		goto out; /* nothing else to do */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Shift position where to store individual dm_devs */
 | 
			
		||||
	dm_dev = (struct dm_active_device *) ((long*) (devs + 1) + cnt);
 | 
			
		||||
	dm_dev = (struct dm_active_device *) (devs + 1);
 | 
			
		||||
 | 
			
		||||
	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->major = MAJOR(names->dev);
 | 
			
		||||
		dm_dev->minor = MINOR(names->dev);
 | 
			
		||||
		dm_dev->name = (char*)(dm_dev + 1);
 | 
			
		||||
		dm_dev->event_nr = 0;
 | 
			
		||||
		dm_dev->uuid = "";
 | 
			
		||||
		dm_dev->uuid = NULL;
 | 
			
		||||
 | 
			
		||||
		strcpy(dm_dev->name, names->name);
 | 
			
		||||
		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()) {
 | 
			
		||||
			/* Hash for UUIDs with some more bits to reduce colision count */
 | 
			
		||||
			if (!devs->uuids && !(devs->uuids = dm_hash_create(cnt * 8))) {
 | 
			
		||||
				free(devs);
 | 
			
		||||
				return_0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			*devs_features |= DM_DEVICE_LIST_HAS_EVENT_NR;
 | 
			
		||||
			event_nr = _align_ptr(names->name + len);
 | 
			
		||||
@@ -846,29 +854,54 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
 | 
			
		||||
			if ((event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
 | 
			
		||||
				*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_dev->uuid = (char*) dm_new_dev;
 | 
			
		||||
				dm_new_dev = _align_ptr((char*)dm_new_dev + strlen(uuid_ptr) + 1);
 | 
			
		||||
				strcpy(dm_dev->uuid, uuid_ptr);
 | 
			
		||||
				if (!dm_hash_insert(devs->uuids, dm_dev->uuid, dm_dev))
 | 
			
		||||
					return_0; // FIXME
 | 
			
		||||
#if 0
 | 
			
		||||
				log_debug("Active %s (%s) %d:%d event:%u",
 | 
			
		||||
					  dm_dev->name, dm_dev->uuid,
 | 
			
		||||
					  dm_dev->major, dm_dev->minor, dm_dev->event_nr);
 | 
			
		||||
#endif
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dm_list_add(devs, &dm_dev->list);
 | 
			
		||||
		dm_list_add(&devs->list, &dm_dev->list);
 | 
			
		||||
		dm_dev = dm_new_dev;
 | 
			
		||||
		next = names->next;
 | 
			
		||||
	} while (next);
 | 
			
		||||
 | 
			
		||||
    out:
 | 
			
		||||
	*devs_list = devs;
 | 
			
		||||
	*devs_list = (struct dm_list *)devs;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
 | 
			
		||||
				const struct dm_active_device **dev)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_device_list *devs = (struct dm_device_list *) devs_list;
 | 
			
		||||
	struct dm_active_device *dm_dev;
 | 
			
		||||
 | 
			
		||||
	if (devs->uuids &&
 | 
			
		||||
	    (dm_dev = dm_hash_lookup(devs->uuids, uuid))) {
 | 
			
		||||
		if (dev)
 | 
			
		||||
			*dev = dm_dev;
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_device_list_destroy(struct dm_list **devs_list)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_device_list *devs = (struct dm_device_list *) *devs_list;
 | 
			
		||||
 | 
			
		||||
	if (devs) {
 | 
			
		||||
		if (devs->uuids)
 | 
			
		||||
			dm_hash_destroy(devs->uuids);
 | 
			
		||||
 | 
			
		||||
		free(devs);
 | 
			
		||||
		*devs_list = NULL;
 | 
			
		||||
	}
 | 
			
		||||
@@ -1161,10 +1194,9 @@ static char *_add_target(struct target *t, char *out, char *end)
 | 
			
		||||
	while (*pt)
 | 
			
		||||
		if (*pt++ == '\\')
 | 
			
		||||
			backslash_count++;
 | 
			
		||||
	len = strlen(t->params) + backslash_count;
 | 
			
		||||
 | 
			
		||||
	len = strlen(t->params) + 1;
 | 
			
		||||
 | 
			
		||||
	if ((out >= end) || (out + len + backslash_count) >= end) {
 | 
			
		||||
	if ((out >= end) || (out + len + 1) >= end) {
 | 
			
		||||
		log_error("Ran out of memory building ioctl parameter");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
@@ -1180,8 +1212,8 @@ static char *_add_target(struct target *t, char *out, char *end)
 | 
			
		||||
		*out++ = '\0';
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		memcpy(out, t->params, len);
 | 
			
		||||
		out += len + backslash_count;
 | 
			
		||||
		strcpy(out, t->params);
 | 
			
		||||
		out += len + 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* align next block */
 | 
			
		||||
@@ -1215,7 +1247,7 @@ static int _lookup_dev_name(uint64_t dev, char *buf, size_t len)
 | 
			
		||||
	do {
 | 
			
		||||
		names = (struct dm_names *)((char *) names + next);
 | 
			
		||||
		if (names->dev == dev) {
 | 
			
		||||
			memccpy(buf, names->name, 0, len);
 | 
			
		||||
			strncpy(buf, names->name, len);
 | 
			
		||||
			r = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
@@ -1252,7 +1284,6 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
 | 
			
		||||
	struct target *t;
 | 
			
		||||
	struct dm_target_msg *tmsg;
 | 
			
		||||
	size_t len = sizeof(struct dm_ioctl);
 | 
			
		||||
	size_t message_len = 0, newname_len = 0, geometry_len = 0;
 | 
			
		||||
	char *b, *e;
 | 
			
		||||
	int count = 0;
 | 
			
		||||
 | 
			
		||||
@@ -1313,20 +1344,14 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dmt->newname) {
 | 
			
		||||
		newname_len = strlen(dmt->newname) + 1;
 | 
			
		||||
		len += newname_len;
 | 
			
		||||
	}
 | 
			
		||||
	if (dmt->newname)
 | 
			
		||||
		len += strlen(dmt->newname) + 1;
 | 
			
		||||
 | 
			
		||||
	if (dmt->message) {
 | 
			
		||||
		message_len = strlen(dmt->message) + 1;
 | 
			
		||||
		len += sizeof(struct dm_target_msg) + message_len;
 | 
			
		||||
	}
 | 
			
		||||
	if (dmt->message)
 | 
			
		||||
		len += sizeof(struct dm_target_msg) + strlen(dmt->message) + 1;
 | 
			
		||||
 | 
			
		||||
	if (dmt->geometry) {
 | 
			
		||||
		geometry_len = strlen(dmt->geometry) + 1;
 | 
			
		||||
		len += geometry_len;
 | 
			
		||||
	}
 | 
			
		||||
	if (dmt->geometry)
 | 
			
		||||
		len += strlen(dmt->geometry) + 1;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Give len a minimum size so that we have space to store
 | 
			
		||||
@@ -1384,10 +1409,12 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
 | 
			
		||||
	/* FIXME Until resume ioctl supplies name, use dev_name for readahead */
 | 
			
		||||
	if (DEV_NAME(dmt) && (dmt->type != DM_DEVICE_RESUME || dmt->minor < 0 ||
 | 
			
		||||
			      dmt->major < 0))
 | 
			
		||||
		memccpy(dmi->name, DEV_NAME(dmt), 0, sizeof(dmi->name));
 | 
			
		||||
		/* coverity[buffer_size_warning] */
 | 
			
		||||
		strncpy(dmi->name, DEV_NAME(dmt), sizeof(dmi->name));
 | 
			
		||||
 | 
			
		||||
	if (DEV_UUID(dmt))
 | 
			
		||||
		memccpy(dmi->uuid, DEV_UUID(dmt), 0, sizeof(dmi->uuid));
 | 
			
		||||
		/* coverity[buffer_size_warning] */
 | 
			
		||||
		strncpy(dmi->uuid, DEV_UUID(dmt), sizeof(dmi->uuid));
 | 
			
		||||
 | 
			
		||||
	if (dmt->type == DM_DEVICE_SUSPEND)
 | 
			
		||||
		dmi->flags |= DM_SUSPEND_FLAG;
 | 
			
		||||
@@ -1413,23 +1440,22 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
 | 
			
		||||
	}
 | 
			
		||||
	if (dmt->query_inactive_table) {
 | 
			
		||||
		if (!_dm_inactive_supported())
 | 
			
		||||
			log_warn_suppress(_dm_warn_inactive_suppress++,
 | 
			
		||||
					  "WARNING: Inactive table query unsupported by kernel. "
 | 
			
		||||
					  "It will use live table.");
 | 
			
		||||
			log_warn("WARNING: Inactive table query unsupported "
 | 
			
		||||
				 "by kernel.  It will use live table.");
 | 
			
		||||
		dmi->flags |= DM_QUERY_INACTIVE_TABLE_FLAG;
 | 
			
		||||
	}
 | 
			
		||||
	if (dmt->new_uuid) {
 | 
			
		||||
		if (_dm_version_minor < 19) {
 | 
			
		||||
			log_error("Setting UUID unsupported by kernel. "
 | 
			
		||||
				  "Aborting operation.");
 | 
			
		||||
			log_error("WARNING: Setting UUID unsupported by "
 | 
			
		||||
				  "kernel.  Aborting operation.");
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
		dmi->flags |= DM_UUID_FLAG;
 | 
			
		||||
	}
 | 
			
		||||
	if (dmt->ima_measurement) {
 | 
			
		||||
		if (_dm_version_minor < 45) {
 | 
			
		||||
			log_error("IMA measurement unsupported by kernel. "
 | 
			
		||||
				  "Aborting operation.");
 | 
			
		||||
			log_error("WARNING: IMA measurement unsupported by "
 | 
			
		||||
				  "kernel.  Aborting operation.");
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
		dmi->flags |= DM_IMA_MEASUREMENT_FLAG;
 | 
			
		||||
@@ -1447,16 +1473,16 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
 | 
			
		||||
				goto_bad;
 | 
			
		||||
 | 
			
		||||
	if (dmt->newname)
 | 
			
		||||
		memcpy(b, dmt->newname, newname_len);
 | 
			
		||||
		strcpy(b, dmt->newname);
 | 
			
		||||
 | 
			
		||||
	if (dmt->message) {
 | 
			
		||||
		tmsg = (struct dm_target_msg *) b;
 | 
			
		||||
		tmsg->sector = dmt->sector;
 | 
			
		||||
		memcpy(tmsg->message, dmt->message, message_len);
 | 
			
		||||
		strcpy(tmsg->message, dmt->message);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dmt->geometry)
 | 
			
		||||
		memcpy(b, dmt->geometry, geometry_len);
 | 
			
		||||
		strcpy(b, dmt->geometry);
 | 
			
		||||
 | 
			
		||||
	return dmi;
 | 
			
		||||
 | 
			
		||||
@@ -1578,7 +1604,7 @@ static int _check_uevent_generated(struct dm_ioctl *dmi)
 | 
			
		||||
static int _create_and_load_v4(struct dm_task *dmt)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_task *task;
 | 
			
		||||
	int r, ioctl_errno = 0;
 | 
			
		||||
	int r;
 | 
			
		||||
	uint32_t cookie;
 | 
			
		||||
 | 
			
		||||
	/* Use new task struct to create the device */
 | 
			
		||||
@@ -1604,10 +1630,8 @@ static int _create_and_load_v4(struct dm_task *dmt)
 | 
			
		||||
	task->cookie_set = dmt->cookie_set;
 | 
			
		||||
	task->add_node = dmt->add_node;
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_run(task)) {
 | 
			
		||||
		ioctl_errno = task->ioctl_errno;
 | 
			
		||||
	if (!dm_task_run(task))
 | 
			
		||||
		goto_bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_task_destroy(task);
 | 
			
		||||
 | 
			
		||||
@@ -1633,8 +1657,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
 | 
			
		||||
	task->ima_measurement = dmt->ima_measurement;
 | 
			
		||||
 | 
			
		||||
	r = dm_task_run(task);
 | 
			
		||||
	if (!r)
 | 
			
		||||
		ioctl_errno = task->ioctl_errno;
 | 
			
		||||
 | 
			
		||||
	task->head = NULL;
 | 
			
		||||
	task->tail = NULL;
 | 
			
		||||
@@ -1652,7 +1674,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
 | 
			
		||||
	dmt->uuid = NULL;
 | 
			
		||||
	free(dmt->mangled_uuid);
 | 
			
		||||
	dmt->mangled_uuid = NULL;
 | 
			
		||||
	/* coverity[double_free] recursive function call */
 | 
			
		||||
	_dm_task_free_targets(dmt);
 | 
			
		||||
 | 
			
		||||
	if (dm_task_run(dmt))
 | 
			
		||||
@@ -1664,7 +1685,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
 | 
			
		||||
	dmt->uuid = NULL;
 | 
			
		||||
	free(dmt->mangled_uuid);
 | 
			
		||||
	dmt->mangled_uuid = NULL;
 | 
			
		||||
	/* coverity[double_free] recursive function call */
 | 
			
		||||
	_dm_task_free_targets(dmt);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@@ -1683,18 +1703,12 @@ static int _create_and_load_v4(struct dm_task *dmt)
 | 
			
		||||
	if (!dm_task_run(dmt))
 | 
			
		||||
		log_error("Failed to revert device creation.");
 | 
			
		||||
 | 
			
		||||
	if (ioctl_errno != 0)
 | 
			
		||||
		dmt->ioctl_errno =  ioctl_errno;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
      bad:
 | 
			
		||||
	dm_task_destroy(task);
 | 
			
		||||
	_udev_complete(dmt);
 | 
			
		||||
 | 
			
		||||
	if (ioctl_errno != 0)
 | 
			
		||||
		dmt->ioctl_errno =  ioctl_errno;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2036,7 +2050,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
 | 
			
		||||
		/*
 | 
			
		||||
		 * Prevent udev vs. libdevmapper race when processing nodes
 | 
			
		||||
		 * and symlinks. This can happen when the udev rules are
 | 
			
		||||
		 * installed and udev synchronization code is enabled in
 | 
			
		||||
		 * installed and udev synchronisation code is enabled in
 | 
			
		||||
		 * libdevmapper but the software using libdevmapper does not
 | 
			
		||||
		 * make use of it (by not calling dm_task_set_cookie before).
 | 
			
		||||
		 * We need to instruct the udev rules not to be applied at
 | 
			
		||||
@@ -2046,7 +2060,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
 | 
			
		||||
		if (!dmt->cookie_set && dm_udev_get_sync_support()) {
 | 
			
		||||
			log_debug_activation("Cookie value is not set while trying to call %s "
 | 
			
		||||
					     "ioctl. Please, consider using libdevmapper's udev "
 | 
			
		||||
					     "synchronization interface or disable it explicitly "
 | 
			
		||||
					     "synchronisation interface or disable it explicitly "
 | 
			
		||||
					     "by calling dm_udev_set_sync_support(0).",
 | 
			
		||||
					     dmt->type == DM_DEVICE_RESUME ? "DM_DEVICE_RESUME" :
 | 
			
		||||
					     dmt->type == DM_DEVICE_REMOVE ? "DM_DEVICE_REMOVE" :
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,6 @@
 | 
			
		||||
#ifndef LIB_DMTARGETS_H
 | 
			
		||||
#define LIB_DMTARGETS_H
 | 
			
		||||
 | 
			
		||||
#include "device_mapper/all.h"
 | 
			
		||||
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
 | 
			
		||||
@@ -81,7 +79,7 @@ struct dm_task {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cmd_data {
 | 
			
		||||
	const char name[16];
 | 
			
		||||
	const char *name;
 | 
			
		||||
	const unsigned cmd;
 | 
			
		||||
	const int version[3];
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2025 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of the device-mapper userspace tools.
 | 
			
		||||
 *
 | 
			
		||||
@@ -511,7 +511,7 @@ int unmangle_string(const char *str, const char *str_name, size_t len,
 | 
			
		||||
		    char *buf, size_t buf_len, dm_string_mangling_t mode)
 | 
			
		||||
{
 | 
			
		||||
	int strict = mode != DM_STRING_MANGLING_NONE;
 | 
			
		||||
	char str_rest[DM_NAME_LEN + 1];
 | 
			
		||||
	char str_rest[DM_NAME_LEN];
 | 
			
		||||
	size_t i, j;
 | 
			
		||||
	unsigned int code;
 | 
			
		||||
	int r = 0;
 | 
			
		||||
@@ -537,8 +537,7 @@ int unmangle_string(const char *str, const char *str_name, size_t len,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (str[i] == '\\' && str[i+1] == 'x') {
 | 
			
		||||
			if (!sscanf(&str[i+2], "%2x%" DM_TO_STRING(DM_NAME_LEN) "s",
 | 
			
		||||
				    &code, str_rest)) {
 | 
			
		||||
			if (!sscanf(&str[i+2], "%2x%s", &code, str_rest)) {
 | 
			
		||||
				log_debug_activation("Hex encoding mismatch detected in %s \"%s\" "
 | 
			
		||||
						     "while trying to unmangle it.", str_name, str);
 | 
			
		||||
				goto out;
 | 
			
		||||
@@ -1044,19 +1043,12 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
 | 
			
		||||
{
 | 
			
		||||
	char path[PATH_MAX];
 | 
			
		||||
	struct stat info;
 | 
			
		||||
	struct stat linfo;
 | 
			
		||||
	dev_t dev = MKDEV(major, minor);
 | 
			
		||||
	mode_t old_mask;
 | 
			
		||||
 | 
			
		||||
	if (!_build_dev_path(path, sizeof(path), dev_name))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Check if the device node already exists.
 | 
			
		||||
	 * Note: stat() follows symlinks, so this checks the target device,
 | 
			
		||||
	 * not the symlink itself. This works correctly for both real nodes
 | 
			
		||||
	 * and symlinks pointing to the right device.
 | 
			
		||||
	 */
 | 
			
		||||
	if (stat(path, &info) >= 0) {
 | 
			
		||||
		if (!S_ISBLK(info.st_mode)) {
 | 
			
		||||
			log_error("A non-block device file at '%s' "
 | 
			
		||||
@@ -1065,71 +1057,17 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* If right inode already exists we don't touch uid etc. */
 | 
			
		||||
		if (info.st_rdev == dev) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * Correct device exists (either as real node or symlink).
 | 
			
		||||
			 * Use lstat() to distinguish between them for logging.
 | 
			
		||||
			 */
 | 
			
		||||
			if (lstat(path, &linfo) >= 0 && S_ISLNK(linfo.st_mode))
 | 
			
		||||
				log_debug_activation("Symlink %s to correct device already exists", path);
 | 
			
		||||
		if (info.st_rdev == dev)
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (unlink(path) && (errno != ENOENT)) {
 | 
			
		||||
			log_sys_error("unlink", path);
 | 
			
		||||
		if (unlink(path) < 0) {
 | 
			
		||||
			log_error("Unable to unlink device node for '%s'",
 | 
			
		||||
				  dev_name);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		/*
 | 
			
		||||
		 * stat() failed. Check for dangling symlinks (where lstat succeeds
 | 
			
		||||
		 * but stat fails with ENOENT because the symlink target doesn't exist).
 | 
			
		||||
		 * Remove the dangling symlink before attempting to create a new node.
 | 
			
		||||
		 */
 | 
			
		||||
		if (errno == ENOENT && lstat(path, &linfo) >= 0 && S_ISLNK(linfo.st_mode)) {
 | 
			
		||||
			log_debug_activation("Removing dangling symlink %s", path);
 | 
			
		||||
			if (unlink(path) && (errno != ENOENT)) {
 | 
			
		||||
				log_sys_error("unlink", path);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (_warn_if_op_needed(warn_if_udev_failed))
 | 
			
		||||
			log_warn("%s not set up by udev: Falling back to direct "
 | 
			
		||||
				 "node creation.", path);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Test environment optimization: If using alternative dev dir (e.g., /tmp/LVMTEST/dev)
 | 
			
		||||
	 * and the real /dev node already exists, create a symlink instead of a duplicate node.
 | 
			
		||||
	 * This ensures operations trigger udev events which only monitors /dev.
 | 
			
		||||
	 */
 | 
			
		||||
	if (strcmp(_dm_dir, DEV_DIR) != 0) {
 | 
			
		||||
		char real_path[PATH_MAX];
 | 
			
		||||
		struct stat real_stat;
 | 
			
		||||
 | 
			
		||||
		/* Build path to real /dev node (kernel always creates /dev/dm-N) */
 | 
			
		||||
		if (dm_snprintf(real_path, sizeof(real_path), DEV_DIR "dm-%u", minor) >= 0) {
 | 
			
		||||
			/* Check if real node exists with matching dev */
 | 
			
		||||
			if (stat(real_path, &real_stat) >= 0 &&
 | 
			
		||||
			    S_ISBLK(real_stat.st_mode) &&
 | 
			
		||||
			    real_stat.st_rdev == dev) {
 | 
			
		||||
				/*
 | 
			
		||||
				 * Real /dev/dm-N exists. Create symlink from alternative location.
 | 
			
		||||
				 * This allows operations to work through the symlink and trigger
 | 
			
		||||
				 * udev events on the real device.
 | 
			
		||||
				 */
 | 
			
		||||
				log_debug_activation("Creating symlink %s -> %s", path, real_path);
 | 
			
		||||
				(void) dm_prepare_selinux_context(path, S_IFLNK);
 | 
			
		||||
				if (symlink(real_path, path) < 0) {
 | 
			
		||||
					log_sys_error("symlink", path);
 | 
			
		||||
					(void) dm_prepare_selinux_context(NULL, 0);
 | 
			
		||||
					return 0;
 | 
			
		||||
				}
 | 
			
		||||
				(void) dm_prepare_selinux_context(NULL, 0);
 | 
			
		||||
				log_debug_activation("Created symlink %s -> %s", path, real_path);
 | 
			
		||||
				return 1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	} else if (_warn_if_op_needed(warn_if_udev_failed))
 | 
			
		||||
		log_warn("%s not set up by udev: Falling back to direct "
 | 
			
		||||
			 "node creation.", path);
 | 
			
		||||
 | 
			
		||||
	(void) dm_prepare_selinux_context(path, S_IFBLK);
 | 
			
		||||
	old_mask = umask(0);
 | 
			
		||||
@@ -1168,8 +1106,8 @@ static int _rm_dev_node(const char *dev_name, int warn_if_udev_failed)
 | 
			
		||||
			 "Falling back to direct node removal.", path);
 | 
			
		||||
 | 
			
		||||
	/* udev may already have deleted the node. Ignore ENOENT. */
 | 
			
		||||
	if (unlink(path) && (errno != ENOENT)) {
 | 
			
		||||
		log_sys_error("unlink", path);
 | 
			
		||||
	if (unlink(path) < 0 && errno != ENOENT) {
 | 
			
		||||
		log_error("Unable to unlink device node for '%s'", dev_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1513,10 +1451,9 @@ struct node_op_parms {
 | 
			
		||||
 | 
			
		||||
static void _store_str(char **pos, char **ptr, const char *str)
 | 
			
		||||
{
 | 
			
		||||
	size_t len = strlen(str) + 1;
 | 
			
		||||
	memcpy(*pos, str, len);
 | 
			
		||||
	strcpy(*pos, str);
 | 
			
		||||
	*ptr = *pos;
 | 
			
		||||
	*pos += len;
 | 
			
		||||
	*pos += strlen(*ptr) + 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _del_node_op(struct node_op_parms *nop)
 | 
			
		||||
@@ -1766,17 +1703,15 @@ const char *dm_sysfs_dir(void)
 | 
			
		||||
 */
 | 
			
		||||
int dm_set_uuid_prefix(const char *uuid_prefix)
 | 
			
		||||
{
 | 
			
		||||
	size_t len;
 | 
			
		||||
 | 
			
		||||
	if (!uuid_prefix)
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	if ((len = strlen(uuid_prefix)) > DM_MAX_UUID_PREFIX_LEN) {
 | 
			
		||||
	if (strlen(uuid_prefix) > DM_MAX_UUID_PREFIX_LEN) {
 | 
			
		||||
		log_error("New uuid prefix %s too long.", uuid_prefix);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(_default_uuid_prefix, uuid_prefix, len + 1);
 | 
			
		||||
	strcpy(_default_uuid_prefix, uuid_prefix);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -1805,9 +1740,6 @@ static void _unmangle_mountinfo_string(const char *src, char *buf)
 | 
			
		||||
	*buf = '\0';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* coverity[+tainted_string_sanitize_content:arg-0] */
 | 
			
		||||
static int _sanitize_line(const char *line) { return 1; }
 | 
			
		||||
 | 
			
		||||
/* Parse one line of mountinfo and unmangled target line */
 | 
			
		||||
static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min, char *buf)
 | 
			
		||||
{
 | 
			
		||||
@@ -1858,7 +1790,7 @@ static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Function to operate on individual mountinfo line,
 | 
			
		||||
 * Function to operate on individal mountinfo line,
 | 
			
		||||
 * minor, major and mount target are parsed and unmangled
 | 
			
		||||
 */
 | 
			
		||||
int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data)
 | 
			
		||||
@@ -1878,8 +1810,7 @@ int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (!feof(minfo) && fgets(buffer, sizeof(buffer), minfo))
 | 
			
		||||
		if (!_sanitize_line(buffer) ||
 | 
			
		||||
		    !_mountinfo_parse_line(buffer, &maj, &min, target) ||
 | 
			
		||||
		if (!_mountinfo_parse_line(buffer, &maj, &min, target) ||
 | 
			
		||||
		    !read_fn(buffer, maj, min, target, cb_data)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			r = 0;
 | 
			
		||||
@@ -1894,27 +1825,32 @@ int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data)
 | 
			
		||||
 | 
			
		||||
static int _sysfs_get_dm_name(uint32_t major, uint32_t minor, char *buf, size_t buf_size)
 | 
			
		||||
{
 | 
			
		||||
	char sysfs_path[PATH_MAX], temp_buf[2 * DM_NAME_LEN];
 | 
			
		||||
	char *sysfs_path, *temp_buf = NULL;
 | 
			
		||||
	FILE *fp = NULL;
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	size_t len;
 | 
			
		||||
 | 
			
		||||
	if (dm_snprintf(sysfs_path, sizeof(sysfs_path),
 | 
			
		||||
			"%sdev/block/%" PRIu32 ":%" PRIu32
 | 
			
		||||
	if (!(sysfs_path = malloc(PATH_MAX)) ||
 | 
			
		||||
	    !(temp_buf = malloc(PATH_MAX))) {
 | 
			
		||||
		log_error("_sysfs_get_dm_name: failed to allocate temporary buffers");
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dm_snprintf(sysfs_path, PATH_MAX, "%sdev/block/%" PRIu32 ":%" PRIu32
 | 
			
		||||
			"/dm/name", _sysfs_dir, major, minor) < 0) {
 | 
			
		||||
		log_error("_sysfs_get_dm_name: dm_snprintf failed.");
 | 
			
		||||
		log_error("_sysfs_get_dm_name: dm_snprintf failed");
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(fp = fopen(sysfs_path, "r"))) {
 | 
			
		||||
		if (errno == ENOENT)
 | 
			
		||||
			log_sys_debug("fopen", sysfs_path);
 | 
			
		||||
                else
 | 
			
		||||
		if (errno != ENOENT)
 | 
			
		||||
			log_sys_error("fopen", sysfs_path);
 | 
			
		||||
		else
 | 
			
		||||
			log_sys_debug("fopen", sysfs_path);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!fgets(temp_buf, sizeof(temp_buf), fp)) {
 | 
			
		||||
	if (!fgets(temp_buf, PATH_MAX, fp)) {
 | 
			
		||||
		log_sys_error("fgets", sysfs_path);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
@@ -1922,21 +1858,20 @@ static int _sysfs_get_dm_name(uint32_t major, uint32_t minor, char *buf, size_t
 | 
			
		||||
	len = strlen(temp_buf);
 | 
			
		||||
 | 
			
		||||
	if (len > buf_size) {
 | 
			
		||||
		log_error("_sysfs_get_dm_name: supplied buffer too small.");
 | 
			
		||||
		log_error("_sysfs_get_dm_name: supplied buffer too small");
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (len)
 | 
			
		||||
		--len;  /* strip \n */
 | 
			
		||||
 | 
			
		||||
	memcpy(buf, temp_buf, len);
 | 
			
		||||
	buf[len] = '\0';
 | 
			
		||||
 | 
			
		||||
	temp_buf[len ? len - 1 : 0] = '\0'; /* \n */
 | 
			
		||||
	strcpy(buf, temp_buf);
 | 
			
		||||
	r = 1;
 | 
			
		||||
bad:
 | 
			
		||||
	if (fp && fclose(fp))
 | 
			
		||||
		log_sys_error("fclose", sysfs_path);
 | 
			
		||||
 | 
			
		||||
	free(temp_buf);
 | 
			
		||||
	free(sysfs_path);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2019,7 +1954,7 @@ static int _sysfs_find_kernel_name(uint32_t major, uint32_t minor, char *buf, si
 | 
			
		||||
				    !strcmp(name_dev, "holders") ||
 | 
			
		||||
				    !strcmp(name_dev, "integrity") ||
 | 
			
		||||
				    !strcmp(name_dev, "loop") ||
 | 
			
		||||
				    !strcmp(name_dev, "queue") ||
 | 
			
		||||
				    !strcmp(name_dev, "queueu") ||
 | 
			
		||||
				    !strcmp(name_dev, "md") ||
 | 
			
		||||
				    !strcmp(name_dev, "mq") ||
 | 
			
		||||
				    !strcmp(name_dev, "power") ||
 | 
			
		||||
@@ -2376,7 +2311,7 @@ static int _check_semaphore_is_supported(void)
 | 
			
		||||
 | 
			
		||||
	if (maxid < 0) {
 | 
			
		||||
		log_warn("Kernel not configured for semaphores (System V IPC). "
 | 
			
		||||
			 "Not using udev synchronization code.");
 | 
			
		||||
			 "Not using udev synchronisation code.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -2399,7 +2334,7 @@ static int _check_udev_is_running(void)
 | 
			
		||||
 | 
			
		||||
	if (!(r = udev_queue_get_udev_is_active(udev_queue)))
 | 
			
		||||
		log_debug_activation("Udev is not running. "
 | 
			
		||||
				     "Not using udev synchronization code.");
 | 
			
		||||
				     "Not using udev synchronisation code.");
 | 
			
		||||
 | 
			
		||||
	udev_queue_unref(udev_queue);
 | 
			
		||||
	udev_unref(udev);
 | 
			
		||||
@@ -2474,7 +2409,7 @@ static int _get_cookie_sem(uint32_t cookie, int *semid)
 | 
			
		||||
			break;
 | 
			
		||||
		case EACCES:
 | 
			
		||||
			log_error("No permission to access "
 | 
			
		||||
				  "notification semaphore identified "
 | 
			
		||||
				  "notificaton semaphore identified "
 | 
			
		||||
				  "by cookie value %" PRIu32 " (0x%x)",
 | 
			
		||||
				  cookie, cookie);
 | 
			
		||||
			break;
 | 
			
		||||
@@ -2495,20 +2430,20 @@ static int _udev_notify_sem_inc(uint32_t cookie, int semid)
 | 
			
		||||
	int val;
 | 
			
		||||
 | 
			
		||||
	if (semop(semid, &sb, 1) < 0) {
 | 
			
		||||
		log_error("cookie inc: semid %d: semop failed for cookie 0x%" PRIx32 ": %s",
 | 
			
		||||
		log_error("semid %d: semop failed for cookie 0x%" PRIx32 ": %s",
 | 
			
		||||
			  semid, cookie, strerror(errno));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 	if ((val = semctl(semid, 0, GETVAL)) < 0) {
 | 
			
		||||
		log_warn("cookie inc: semid %d: sem_ctl GETVAL failed for "
 | 
			
		||||
		log_error("semid %d: sem_ctl GETVAL failed for "
 | 
			
		||||
			  "cookie 0x%" PRIx32 ": %s",
 | 
			
		||||
			  semid, cookie, strerror(errno));
 | 
			
		||||
		log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) incremented.",
 | 
			
		||||
				      cookie, semid);
 | 
			
		||||
	} else
 | 
			
		||||
		log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) incremented to %d",
 | 
			
		||||
				     cookie, semid, val);
 | 
			
		||||
		return 0;		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) incremented to %d",
 | 
			
		||||
		  cookie, semid, val);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -2518,21 +2453,23 @@ static int _udev_notify_sem_dec(uint32_t cookie, int semid)
 | 
			
		||||
	struct sembuf sb = {0, -1, IPC_NOWAIT};
 | 
			
		||||
	int val;
 | 
			
		||||
 | 
			
		||||
 	if ((val = semctl(semid, 0, GETVAL)) < 0)
 | 
			
		||||
		log_warn("cookie dec: semid %d: sem_ctl GETVAL failed for "
 | 
			
		||||
			 "cookie 0x%" PRIx32 ": %s",
 | 
			
		||||
			 semid, cookie, strerror(errno));
 | 
			
		||||
 	if ((val = semctl(semid, 0, GETVAL)) < 0) {
 | 
			
		||||
		log_error("semid %d: sem_ctl GETVAL failed for "
 | 
			
		||||
			  "cookie 0x%" PRIx32 ": %s",
 | 
			
		||||
			  semid, cookie, strerror(errno));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (semop(semid, &sb, 1) < 0) {
 | 
			
		||||
		switch (errno) {
 | 
			
		||||
			case EAGAIN:
 | 
			
		||||
				log_error("cookie dec: semid %d: semop failed for cookie "
 | 
			
		||||
				log_error("semid %d: semop failed for cookie "
 | 
			
		||||
					  "0x%" PRIx32 ": "
 | 
			
		||||
					  "incorrect semaphore state",
 | 
			
		||||
					  semid, cookie);
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				log_error("cookie dec: semid %d: semop failed for cookie "
 | 
			
		||||
				log_error("semid %d: semop failed for cookie "
 | 
			
		||||
					  "0x%" PRIx32 ": %s",
 | 
			
		||||
					  semid, cookie, strerror(errno));
 | 
			
		||||
				break;
 | 
			
		||||
@@ -2540,12 +2477,9 @@ static int _udev_notify_sem_dec(uint32_t cookie, int semid)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (val < 0)
 | 
			
		||||
		log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) decremented.",
 | 
			
		||||
				     cookie, semid);
 | 
			
		||||
	else
 | 
			
		||||
		log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) decremented to %d",
 | 
			
		||||
				     cookie, semid, val - 1);
 | 
			
		||||
	log_debug_activation("Udev cookie 0x%" PRIx32 " (semid %d) decremented to %d",
 | 
			
		||||
			     cookie, semid, val - 1);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2622,7 +2556,7 @@ static int _udev_notify_sem_create(uint32_t *cookie, int *semid)
 | 
			
		||||
	sem_arg.val = 1;
 | 
			
		||||
 | 
			
		||||
	if (semctl(gen_semid, 0, SETVAL, sem_arg) < 0) {
 | 
			
		||||
		log_error("cookie create: semid %d: semctl failed: %s", gen_semid, strerror(errno));
 | 
			
		||||
		log_error("semid %d: semctl failed: %s", gen_semid, strerror(errno));
 | 
			
		||||
		/* We have to destroy just created semaphore
 | 
			
		||||
		 * so it won't stay in the system. */
 | 
			
		||||
		(void) _udev_notify_sem_destroy(gen_cookie, gen_semid);
 | 
			
		||||
@@ -2630,10 +2564,9 @@ static int _udev_notify_sem_create(uint32_t *cookie, int *semid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 	if ((val = semctl(gen_semid, 0, GETVAL)) < 0) {
 | 
			
		||||
		log_error("cookie create: semid %d: sem_ctl GETVAL failed for "
 | 
			
		||||
		log_error("semid %d: sem_ctl GETVAL failed for "
 | 
			
		||||
			  "cookie 0x%" PRIx32 ": %s",
 | 
			
		||||
			  gen_semid, gen_cookie, strerror(errno));
 | 
			
		||||
		(void) _udev_notify_sem_destroy(gen_cookie, gen_semid);
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ struct target *create_target(uint64_t start,
 | 
			
		||||
			     uint64_t len,
 | 
			
		||||
			     const char *type, const char *params);
 | 
			
		||||
 | 
			
		||||
int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
 | 
			
		||||
int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major,
 | 
			
		||||
		 uid_t uid, gid_t gid, mode_t mode, int check_udev, unsigned rely_on_udev);
 | 
			
		||||
int rm_dev_node(const char *dev_name, int check_udev, unsigned rely_on_udev);
 | 
			
		||||
int rename_dev_node(const char *old_name, const char *new_name,
 | 
			
		||||
 
 | 
			
		||||
@@ -53,8 +53,6 @@ struct parser {
 | 
			
		||||
	int no_dup_node_check;	/* whether to disable dup node checking */
 | 
			
		||||
	const char *key;        /* last obtained key */
 | 
			
		||||
	unsigned ignored_creation_time;
 | 
			
		||||
	unsigned section_indent;
 | 
			
		||||
	const char *stop_after_section;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct config_output {
 | 
			
		||||
@@ -72,11 +70,12 @@ static struct dm_config_value *_value(struct parser *p);
 | 
			
		||||
static struct dm_config_value *_type(struct parser *p);
 | 
			
		||||
static int _match_aux(struct parser *p, int t);
 | 
			
		||||
static struct dm_config_value *_create_value(struct dm_pool *mem);
 | 
			
		||||
static struct dm_config_value *_create_str_value(struct dm_pool *mem, const char *str, size_t str_len);
 | 
			
		||||
static struct dm_config_node *_create_node(struct dm_pool *mem, const char *key, size_t key_len);
 | 
			
		||||
static struct dm_config_node *_create_node(struct dm_pool *mem);
 | 
			
		||||
static char *_dup_tok(struct parser *p);
 | 
			
		||||
static char *_dup_token(struct dm_pool *mem, const char *b, const char *e);
 | 
			
		||||
 | 
			
		||||
static const int _sep = '/';
 | 
			
		||||
 | 
			
		||||
#define MAX_INDENT 32
 | 
			
		||||
 | 
			
		||||
#define match(t) do {\
 | 
			
		||||
@@ -87,24 +86,20 @@ static char *_dup_token(struct dm_pool *mem, const char *b, const char *e);
 | 
			
		||||
   } \
 | 
			
		||||
} while(0)
 | 
			
		||||
 | 
			
		||||
/* match token */
 | 
			
		||||
static int _tok_match(const char *str, const char *b, const char *e)
 | 
			
		||||
{
 | 
			
		||||
	while (b < e) {
 | 
			
		||||
		if (!*str ||
 | 
			
		||||
		    (*str != *b))
 | 
			
		||||
	while (*str && (b != e)) {
 | 
			
		||||
		if (*str++ != *b++)
 | 
			
		||||
			return 0;
 | 
			
		||||
		++str;
 | 
			
		||||
		++b;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return !*str; /* token is matching for \0 end */
 | 
			
		||||
	return !(*str || (b != e));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_config_tree *dm_config_create(void)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_config_tree *cft;
 | 
			
		||||
	struct dm_pool *mem = dm_pool_create("config", 63 * 1024);
 | 
			
		||||
	struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
 | 
			
		||||
 | 
			
		||||
	if (!mem) {
 | 
			
		||||
		log_error("Failed to allocate config pool.");
 | 
			
		||||
@@ -178,24 +173,23 @@ static struct dm_config_node *_config_reverse(struct dm_config_node *head)
 | 
			
		||||
	return middle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _do_dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end,
 | 
			
		||||
			       int no_dup_node_check, const char *section)
 | 
			
		||||
static int _do_dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end, int no_dup_node_check)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO? if (start == end) return 1; */
 | 
			
		||||
 | 
			
		||||
	struct parser p = {
 | 
			
		||||
		.mem = cft->mem,
 | 
			
		||||
		.tb = start,
 | 
			
		||||
		.te = start,
 | 
			
		||||
		.fb = start,
 | 
			
		||||
		.fe = end,
 | 
			
		||||
		.line = 1,
 | 
			
		||||
		.stop_after_section = section,
 | 
			
		||||
		.no_dup_node_check = no_dup_node_check
 | 
			
		||||
	};
 | 
			
		||||
	struct parser *p;
 | 
			
		||||
	if (!(p = dm_pool_zalloc(cft->mem, sizeof(*p))))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	_get_token(&p, TOK_SECTION_E);
 | 
			
		||||
	if (!(cft->root = _file(&p)))
 | 
			
		||||
	p->mem = cft->mem;
 | 
			
		||||
	p->fb = start;
 | 
			
		||||
	p->fe = end;
 | 
			
		||||
	p->tb = p->te = p->fb;
 | 
			
		||||
	p->line = 1;
 | 
			
		||||
	p->no_dup_node_check = no_dup_node_check;
 | 
			
		||||
 | 
			
		||||
	_get_token(p, TOK_SECTION_E);
 | 
			
		||||
	if (!(cft->root = _file(p)))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	cft->root = _config_reverse(cft->root);
 | 
			
		||||
@@ -205,23 +199,12 @@ static int _do_dm_config_parse(struct dm_config_tree *cft, const char *start, co
 | 
			
		||||
 | 
			
		||||
int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end)
 | 
			
		||||
{
 | 
			
		||||
	return _do_dm_config_parse(cft, start, end, 0, NULL);
 | 
			
		||||
	return _do_dm_config_parse(cft, start, end, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_config_parse_without_dup_node_check(struct dm_config_tree *cft, const char *start, const char *end)
 | 
			
		||||
{
 | 
			
		||||
	return _do_dm_config_parse(cft, start, end, 1, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Stop parsing more sections after given section is parsed.
 | 
			
		||||
 * Only non-section config nodes are then still parsed.
 | 
			
		||||
 * It can be useful, when parsing i.e. lvm2 metadata and only physical_volumes config node is needed.
 | 
			
		||||
 * This function is automatically running without_dup_node_check.
 | 
			
		||||
 */
 | 
			
		||||
int dm_config_parse_only_section(struct dm_config_tree *cft, const char *start, const char *end, const char *section)
 | 
			
		||||
{
 | 
			
		||||
	return _do_dm_config_parse(cft, start, end, 1, section);
 | 
			
		||||
	return _do_dm_config_parse(cft, start, end, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_config_tree *dm_config_from_string(const char *config_settings)
 | 
			
		||||
@@ -487,33 +470,23 @@ int dm_config_write_node_out(const struct dm_config_node *cn,
 | 
			
		||||
/*
 | 
			
		||||
 * parser
 | 
			
		||||
 */
 | 
			
		||||
static const char *_string_tok(struct parser *p, size_t *len)
 | 
			
		||||
static char *_dup_string_tok(struct parser *p)
 | 
			
		||||
{
 | 
			
		||||
	ptrdiff_t d = p->te - p->tb;
 | 
			
		||||
	char *str;
 | 
			
		||||
 | 
			
		||||
	if (d < 2) {
 | 
			
		||||
	p->tb++, p->te--;	/* strip "'s */
 | 
			
		||||
 | 
			
		||||
	if (p->te < p->tb) {
 | 
			
		||||
		log_error("Parse error at byte %" PRIptrdiff_t " (line %d): "
 | 
			
		||||
			  "expected a string token.",
 | 
			
		||||
			  p->tb - p->fb + 1, p->line);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*len = (size_t)(d - 2); /* strip "'s */
 | 
			
		||||
 | 
			
		||||
	return p->tb + 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *_dup_string_tok(struct parser *p)
 | 
			
		||||
{
 | 
			
		||||
	const char *tok;
 | 
			
		||||
	size_t len;
 | 
			
		||||
	char *str;
 | 
			
		||||
 | 
			
		||||
	if (!(tok = _string_tok(p, &len)))
 | 
			
		||||
	if (!(str = _dup_tok(p)))
 | 
			
		||||
		return_NULL;
 | 
			
		||||
 | 
			
		||||
	if (!(str = _dup_token(p->mem, tok, tok + len)))
 | 
			
		||||
		return_NULL;
 | 
			
		||||
	p->te++;
 | 
			
		||||
 | 
			
		||||
	return str;
 | 
			
		||||
}
 | 
			
		||||
@@ -535,9 +508,10 @@ static struct dm_config_node *_make_node(struct dm_pool *mem,
 | 
			
		||||
{
 | 
			
		||||
	struct dm_config_node *n;
 | 
			
		||||
 | 
			
		||||
	if (!(n = _create_node(mem, key_b, key_e - key_b)))
 | 
			
		||||
	if (!(n = _create_node(mem)))
 | 
			
		||||
		return_NULL;
 | 
			
		||||
 | 
			
		||||
	n->key = _dup_token(mem, key_b, key_e);
 | 
			
		||||
	if (parent) {
 | 
			
		||||
		n->parent = parent;
 | 
			
		||||
		n->sib = parent->child;
 | 
			
		||||
@@ -552,18 +526,17 @@ static struct dm_config_node *_find_or_make_node(struct dm_pool *mem,
 | 
			
		||||
						 const char *path,
 | 
			
		||||
						 int no_dup_node_check)
 | 
			
		||||
{
 | 
			
		||||
	const int sep = '/';
 | 
			
		||||
	const char *e;
 | 
			
		||||
	struct dm_config_node *cn = parent ? parent->child : NULL;
 | 
			
		||||
	struct dm_config_node *cn_found = NULL;
 | 
			
		||||
 | 
			
		||||
	while (cn || mem) {
 | 
			
		||||
		/* trim any leading slashes */
 | 
			
		||||
		while (*path && (*path == sep))
 | 
			
		||||
		while (*path && (*path == _sep))
 | 
			
		||||
			path++;
 | 
			
		||||
 | 
			
		||||
		/* find the end of this segment */
 | 
			
		||||
		for (e = path; *e && (*e != sep); e++) ;
 | 
			
		||||
		for (e = path; *e && (*e != _sep); e++) ;
 | 
			
		||||
 | 
			
		||||
		/* hunt for the node */
 | 
			
		||||
		cn_found = NULL;
 | 
			
		||||
@@ -607,8 +580,6 @@ static struct dm_config_node *_section(struct parser *p, struct dm_config_node *
 | 
			
		||||
	struct dm_config_node *root;
 | 
			
		||||
	struct dm_config_value *value;
 | 
			
		||||
	char *str;
 | 
			
		||||
	size_t len;
 | 
			
		||||
	char buf[8192];
 | 
			
		||||
 | 
			
		||||
	if (p->t == TOK_STRING_ESCAPED) {
 | 
			
		||||
		if (!(str = _dup_string_tok(p)))
 | 
			
		||||
@@ -622,16 +593,9 @@ static struct dm_config_node *_section(struct parser *p, struct dm_config_node *
 | 
			
		||||
 | 
			
		||||
		match(TOK_STRING);
 | 
			
		||||
	} else {
 | 
			
		||||
		len = p->te - p->tb;
 | 
			
		||||
		if (len < (sizeof(buf) - 1)) {
 | 
			
		||||
			/* Use stack for smaller string */
 | 
			
		||||
			str = buf;
 | 
			
		||||
			memcpy(str, p->tb, len);
 | 
			
		||||
			str[len] = '\0';
 | 
			
		||||
		} else {
 | 
			
		||||
			if (!(str = _dup_tok(p)))
 | 
			
		||||
				return_NULL;
 | 
			
		||||
		}
 | 
			
		||||
		if (!(str = _dup_tok(p)))
 | 
			
		||||
			return_NULL;
 | 
			
		||||
 | 
			
		||||
		match(TOK_IDENTIFIER);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -645,28 +609,12 @@ static struct dm_config_node *_section(struct parser *p, struct dm_config_node *
 | 
			
		||||
		return_NULL;
 | 
			
		||||
 | 
			
		||||
	if (p->t == TOK_SECTION_B) {
 | 
			
		||||
		if (p->stop_after_section)
 | 
			
		||||
			++p->section_indent;
 | 
			
		||||
		match(TOK_SECTION_B);
 | 
			
		||||
		while (p->t != TOK_SECTION_E) {
 | 
			
		||||
			if (!(_section(p, root)))
 | 
			
		||||
				return_NULL;
 | 
			
		||||
		}
 | 
			
		||||
		match(TOK_SECTION_E);
 | 
			
		||||
		if (p->stop_after_section && (--p->section_indent == 1)) {
 | 
			
		||||
			if (!strcmp(str, p->stop_after_section)) {
 | 
			
		||||
				/* Found stopping section name -> parsing is finished.
 | 
			
		||||
				 * Now try to find the sequence "\n}\n" from end of b
 | 
			
		||||
				 * parsed buffer to continue filling remaining nodes */
 | 
			
		||||
				for (p->te = p->fe - 1; p->te > p->tb; --p->te)
 | 
			
		||||
					if ((p->te[-2] == '\n') &&
 | 
			
		||||
					    (p->te[-1] == '}') &&
 | 
			
		||||
					    (p->te[ 0] == '\n')) {
 | 
			
		||||
						p->t = TOK_SECTION_E;
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		match(TOK_EQ);
 | 
			
		||||
		p->key = root->key;
 | 
			
		||||
@@ -723,14 +671,16 @@ static struct dm_config_value *_value(struct parser *p)
 | 
			
		||||
static struct dm_config_value *_type(struct parser *p)
 | 
			
		||||
{
 | 
			
		||||
	/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
 | 
			
		||||
	struct dm_config_value *v;
 | 
			
		||||
	const char *str;
 | 
			
		||||
	size_t len;
 | 
			
		||||
	struct dm_config_value *v = _create_value(p->mem);
 | 
			
		||||
	char *str;
 | 
			
		||||
 | 
			
		||||
	if (!v) {
 | 
			
		||||
		log_error("Failed to allocate type value");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (p->t) {
 | 
			
		||||
	case TOK_INT:
 | 
			
		||||
		if (!(v = _create_value(p->mem)))
 | 
			
		||||
			break;
 | 
			
		||||
		v->type = DM_CFG_INT;
 | 
			
		||||
		errno = 0;
 | 
			
		||||
		v->v.i = strtoll(p->tb, NULL, 0);	/* FIXME: check error */
 | 
			
		||||
@@ -751,8 +701,6 @@ static struct dm_config_value *_type(struct parser *p)
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case TOK_FLOAT:
 | 
			
		||||
		if (!(v = _create_value(p->mem)))
 | 
			
		||||
			break;
 | 
			
		||||
		v->type = DM_CFG_FLOAT;
 | 
			
		||||
		errno = 0;
 | 
			
		||||
		v->v.f = strtod(p->tb, NULL);	/* FIXME: check error */
 | 
			
		||||
@@ -764,31 +712,31 @@ static struct dm_config_value *_type(struct parser *p)
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case TOK_STRING:
 | 
			
		||||
		if (!(str = _string_tok(p, &len)))
 | 
			
		||||
		v->type = DM_CFG_STRING;
 | 
			
		||||
 | 
			
		||||
		if (!(v->v.str = _dup_string_tok(p)))
 | 
			
		||||
			return_NULL;
 | 
			
		||||
 | 
			
		||||
		if ((v = _create_str_value(p->mem, str, len))) {
 | 
			
		||||
			v->type = DM_CFG_STRING;
 | 
			
		||||
			match(TOK_STRING);
 | 
			
		||||
		}
 | 
			
		||||
		match(TOK_STRING);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case TOK_STRING_BARE:
 | 
			
		||||
		if ((v = _create_str_value(p->mem, p->tb, p->te - p->tb))) {
 | 
			
		||||
			v->type = DM_CFG_STRING;
 | 
			
		||||
			match(TOK_STRING_BARE);
 | 
			
		||||
		}
 | 
			
		||||
		v->type = DM_CFG_STRING;
 | 
			
		||||
 | 
			
		||||
		if (!(v->v.str = _dup_tok(p)))
 | 
			
		||||
			return_NULL;
 | 
			
		||||
 | 
			
		||||
		match(TOK_STRING_BARE);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case TOK_STRING_ESCAPED:
 | 
			
		||||
		if (!(str = _string_tok(p, &len)))
 | 
			
		||||
			return_NULL;
 | 
			
		||||
		v->type = DM_CFG_STRING;
 | 
			
		||||
 | 
			
		||||
		if ((v = _create_str_value(p->mem, str, len))) {
 | 
			
		||||
			v->type = DM_CFG_STRING;
 | 
			
		||||
			dm_unescape_double_quotes((char*)v->v.str);
 | 
			
		||||
			match(TOK_STRING_ESCAPED);
 | 
			
		||||
		}
 | 
			
		||||
		if (!(str = _dup_string_tok(p)))
 | 
			
		||||
			return_NULL;
 | 
			
		||||
		dm_unescape_double_quotes(str);
 | 
			
		||||
		v->v.str = str;
 | 
			
		||||
		match(TOK_STRING_ESCAPED);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
@@ -796,12 +744,6 @@ static struct dm_config_value *_type(struct parser *p)
 | 
			
		||||
			  p->tb - p->fb + 1, p->line);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!v) {
 | 
			
		||||
		log_error("Failed to allocate type value.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -819,52 +761,60 @@ static int _match_aux(struct parser *p, int t)
 | 
			
		||||
 */
 | 
			
		||||
static void _get_token(struct parser *p, int tok_prev)
 | 
			
		||||
{
 | 
			
		||||
	/* Should next token be interpreted as value instead of identifier? */
 | 
			
		||||
	const int values_allowed = (tok_prev == TOK_EQ ||
 | 
			
		||||
				    tok_prev == TOK_ARRAY_B ||
 | 
			
		||||
				    tok_prev == TOK_COMMA);
 | 
			
		||||
	int values_allowed = 0;
 | 
			
		||||
 | 
			
		||||
	const char *te;
 | 
			
		||||
	char c;
 | 
			
		||||
 | 
			
		||||
	p->tb = p->te;
 | 
			
		||||
	_eat_space(p);
 | 
			
		||||
	if (p->tb == p->fe ||
 | 
			
		||||
	    !((c = *p->tb))) {
 | 
			
		||||
	if (p->tb == p->fe || !*p->tb) {
 | 
			
		||||
		p->t = TOK_EOF;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Should next token be interpreted as value instead of identifier? */
 | 
			
		||||
	if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
 | 
			
		||||
	    tok_prev == TOK_COMMA)
 | 
			
		||||
		values_allowed = 1;
 | 
			
		||||
 | 
			
		||||
	p->t = TOK_INT;		/* fudge so the fall through for
 | 
			
		||||
				   floats works */
 | 
			
		||||
	te = p->te + 1;         /* next character */
 | 
			
		||||
 | 
			
		||||
	switch (c) {
 | 
			
		||||
	te = p->te;
 | 
			
		||||
	switch (*te) {
 | 
			
		||||
	case SECTION_B_CHAR:
 | 
			
		||||
		p->t = TOK_SECTION_B;
 | 
			
		||||
		te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case SECTION_E_CHAR:
 | 
			
		||||
		p->t = TOK_SECTION_E;
 | 
			
		||||
		te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case '[':
 | 
			
		||||
		p->t = TOK_ARRAY_B;
 | 
			
		||||
		te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case ']':
 | 
			
		||||
		p->t = TOK_ARRAY_E;
 | 
			
		||||
		te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case ',':
 | 
			
		||||
		p->t = TOK_COMMA;
 | 
			
		||||
		te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case '=':
 | 
			
		||||
		p->t = TOK_EQ;
 | 
			
		||||
		te++;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case '"':
 | 
			
		||||
		p->t = TOK_STRING_ESCAPED;
 | 
			
		||||
		te++;
 | 
			
		||||
		while ((te != p->fe) && (*te) && (*te != '"')) {
 | 
			
		||||
			if ((*te == '\\') && (te + 1 != p->fe) &&
 | 
			
		||||
			    *(te + 1))
 | 
			
		||||
@@ -878,6 +828,7 @@ static void _get_token(struct parser *p, int tok_prev)
 | 
			
		||||
 | 
			
		||||
	case '\'':
 | 
			
		||||
		p->t = TOK_STRING;
 | 
			
		||||
		te++;
 | 
			
		||||
		while ((te != p->fe) && (*te) && (*te != '\''))
 | 
			
		||||
			te++;
 | 
			
		||||
 | 
			
		||||
@@ -901,7 +852,7 @@ static void _get_token(struct parser *p, int tok_prev)
 | 
			
		||||
	case '+':
 | 
			
		||||
	case '-':
 | 
			
		||||
		if (values_allowed) {
 | 
			
		||||
			for (; te != p->fe; ++te) {
 | 
			
		||||
			while (++te != p->fe) {
 | 
			
		||||
				if (!isdigit((int) *te)) {
 | 
			
		||||
					if (*te == '.') {
 | 
			
		||||
						if (p->t != TOK_FLOAT) {
 | 
			
		||||
@@ -918,10 +869,10 @@ static void _get_token(struct parser *p, int tok_prev)
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		p->t = TOK_IDENTIFIER;
 | 
			
		||||
		while ((te != p->fe) && ((c = *te)) && !isspace(c) &&
 | 
			
		||||
		       (c != '#') && (c != '=') &&
 | 
			
		||||
		       (c != SECTION_B_CHAR) &&
 | 
			
		||||
		       (c != SECTION_E_CHAR))
 | 
			
		||||
		while ((te != p->fe) && (*te) && !isspace(*te) &&
 | 
			
		||||
		       (*te != '#') && (*te != '=') &&
 | 
			
		||||
		       (*te != SECTION_B_CHAR) &&
 | 
			
		||||
		       (*te != SECTION_E_CHAR))
 | 
			
		||||
			te++;
 | 
			
		||||
		if (values_allowed)
 | 
			
		||||
			p->t = TOK_STRING_BARE;
 | 
			
		||||
@@ -934,19 +885,16 @@ static void _get_token(struct parser *p, int tok_prev)
 | 
			
		||||
static void _eat_space(struct parser *p)
 | 
			
		||||
{
 | 
			
		||||
	while (p->tb != p->fe) {
 | 
			
		||||
		if (!isspace(*p->te)) {
 | 
			
		||||
			if (*p->te != '#')
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
		if (*p->te == '#')
 | 
			
		||||
			while ((p->te != p->fe) && (*p->te != '\n') && (*p->te))
 | 
			
		||||
				++p->te;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		while (p->te != p->fe) {
 | 
			
		||||
		else if (!isspace(*p->te))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		while ((p->te != p->fe) && isspace(*p->te)) {
 | 
			
		||||
			if (*p->te == '\n')
 | 
			
		||||
				++p->line;
 | 
			
		||||
			else if (!isspace(*p->te))
 | 
			
		||||
				break;
 | 
			
		||||
			++p->te;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -962,44 +910,9 @@ static struct dm_config_value *_create_value(struct dm_pool *mem)
 | 
			
		||||
	return dm_pool_zalloc(mem, sizeof(struct dm_config_value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dm_config_value *_create_str_value(struct dm_pool *mem, const char *str, size_t str_len)
 | 
			
		||||
static struct dm_config_node *_create_node(struct dm_pool *mem)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_config_value *cv;
 | 
			
		||||
	char *str_buf;
 | 
			
		||||
 | 
			
		||||
	if (!(cv = dm_pool_alloc(mem, sizeof(struct dm_config_value) + str_len + 1)))
 | 
			
		||||
		return_NULL;
 | 
			
		||||
 | 
			
		||||
	memset(cv, 0, sizeof(*cv));
 | 
			
		||||
 | 
			
		||||
	if (str) {
 | 
			
		||||
		str_buf = (char *)(cv + 1);
 | 
			
		||||
		memcpy(str_buf, str, str_len);
 | 
			
		||||
		str_buf[str_len] = '\0';
 | 
			
		||||
		cv->v.str = str_buf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dm_config_node *_create_node(struct dm_pool *mem, const char *key, size_t key_len)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_config_node *cn;
 | 
			
		||||
	char *key_buf;
 | 
			
		||||
 | 
			
		||||
	if (!(cn = dm_pool_alloc(mem, sizeof(struct dm_config_node) + key_len + 1)))
 | 
			
		||||
		return_NULL;
 | 
			
		||||
 | 
			
		||||
	memset(cn, 0, sizeof(*cn));
 | 
			
		||||
 | 
			
		||||
	if (key) {
 | 
			
		||||
		key_buf = (char *)(cn + 1);
 | 
			
		||||
		memcpy(key_buf, key, key_len);
 | 
			
		||||
		key_buf[key_len] = '\0';
 | 
			
		||||
		cn->key = key_buf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cn;
 | 
			
		||||
	return dm_pool_zalloc(mem, sizeof(struct dm_config_node));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *_dup_token(struct dm_pool *mem, const char *b, const char *e)
 | 
			
		||||
@@ -1416,20 +1329,19 @@ static struct dm_config_value *_clone_config_value(struct dm_pool *mem,
 | 
			
		||||
{
 | 
			
		||||
	struct dm_config_value *new_cv;
 | 
			
		||||
 | 
			
		||||
	if (v->type == DM_CFG_STRING) {
 | 
			
		||||
		if (!(new_cv = _create_str_value(mem, v->v.str, strlen(v->v.str)))) {
 | 
			
		||||
			log_error("Failed to clone string config value.");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!(new_cv = _create_value(mem))) {
 | 
			
		||||
			log_error("Failed to clone config value.");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		new_cv->v = v->v;
 | 
			
		||||
	if (!(new_cv = _create_value(mem))) {
 | 
			
		||||
		log_error("Failed to clone config value.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	new_cv->type = v->type;
 | 
			
		||||
	if (v->type == DM_CFG_STRING) {
 | 
			
		||||
		if (!(new_cv->v.str = dm_pool_strdup(mem, v->v.str))) {
 | 
			
		||||
			log_error("Failed to clone config string value.");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
	} else
 | 
			
		||||
		new_cv->v = v->v;
 | 
			
		||||
 | 
			
		||||
	if (v->next && !(new_cv->next = _clone_config_value(mem, v->next)))
 | 
			
		||||
		return_NULL;
 | 
			
		||||
@@ -1446,11 +1358,16 @@ struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(new_cn = _create_node(mem, cn->key, cn->key ? strlen(cn->key) : 0))) {
 | 
			
		||||
	if (!(new_cn = _create_node(mem))) {
 | 
			
		||||
		log_error("Failed to clone config node.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((cn->key && !(new_cn->key = dm_pool_strdup(mem, cn->key)))) {
 | 
			
		||||
		log_error("Failed to clone config node key.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	new_cn->id = cn->id;
 | 
			
		||||
 | 
			
		||||
	if ((cn->v && !(new_cn->v = _clone_config_value(mem, cn->v))) ||
 | 
			
		||||
@@ -1461,20 +1378,23 @@ struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const
 | 
			
		||||
	return new_cn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *cn, int sib)
 | 
			
		||||
struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *node, int sib)
 | 
			
		||||
{
 | 
			
		||||
	return dm_config_clone_node_with_mem(cft->mem, cn, sib);
 | 
			
		||||
	return dm_config_clone_node_with_mem(cft->mem, node, sib);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_config_node *cn;
 | 
			
		||||
 | 
			
		||||
	if (!(cn = _create_node(cft->mem, key, strlen(key)))) {
 | 
			
		||||
	if (!(cn = _create_node(cft->mem))) {
 | 
			
		||||
		log_error("Failed to create config node.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(cn->key = dm_pool_strdup(cft->mem, key))) {
 | 
			
		||||
		log_error("Failed to create config node's key.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	cn->parent = NULL;
 | 
			
		||||
	cn->v = NULL;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
#include "misc/dm-ioctl.h"
 | 
			
		||||
#include "vdo/target.h"
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
 | 
			
		||||
@@ -151,17 +152,15 @@ struct thin_message {
 | 
			
		||||
struct load_segment {
 | 
			
		||||
	struct dm_list list;
 | 
			
		||||
 | 
			
		||||
	uint64_t size;
 | 
			
		||||
 | 
			
		||||
	unsigned type;
 | 
			
		||||
 | 
			
		||||
	uint64_t size;
 | 
			
		||||
 | 
			
		||||
	unsigned area_count;		/* Linear + Striped + Mirrored + Crypt */
 | 
			
		||||
	struct dm_list areas;		/* Linear + Striped + Mirrored + Crypt */
 | 
			
		||||
 | 
			
		||||
	uint32_t stripe_size;		/* Striped + raid */
 | 
			
		||||
 | 
			
		||||
	uint32_t region_size;		/* Mirror + raid */
 | 
			
		||||
 | 
			
		||||
	int persistent;			/* Snapshot */
 | 
			
		||||
	uint32_t chunk_size;		/* Snapshot */
 | 
			
		||||
	struct dm_tree_node *cow;	/* Snapshot */
 | 
			
		||||
@@ -169,9 +168,10 @@ struct load_segment {
 | 
			
		||||
	struct dm_tree_node *merge;	/* Snapshot */
 | 
			
		||||
 | 
			
		||||
	struct dm_tree_node *log;	/* Mirror */
 | 
			
		||||
	uint32_t region_size;		/* Mirror + raid */
 | 
			
		||||
	unsigned clustered;		/* Mirror */
 | 
			
		||||
	unsigned mirror_area_count;	/* Mirror */
 | 
			
		||||
	uint64_t flags;			/* Mirror + Raid + Cache */
 | 
			
		||||
	uint32_t flags;			/* Mirror + raid + Cache */
 | 
			
		||||
	char *uuid;			/* Clustered mirror log */
 | 
			
		||||
 | 
			
		||||
	const char *policy_name;	/* Cache */
 | 
			
		||||
@@ -214,7 +214,6 @@ struct load_segment {
 | 
			
		||||
	uint32_t device_id;		/* Thin */
 | 
			
		||||
 | 
			
		||||
	// VDO params
 | 
			
		||||
	uint32_t vdo_version;		/* VDO - version of target table line */
 | 
			
		||||
	struct dm_tree_node *vdo_data;  /* VDO */
 | 
			
		||||
	struct dm_vdo_target_params vdo_params; /* VDO */
 | 
			
		||||
	const char *vdo_name;           /* VDO - device name is ALSO passed as table arg */
 | 
			
		||||
@@ -265,7 +264,7 @@ struct load_properties {
 | 
			
		||||
	/*
 | 
			
		||||
	 * Preload tree normally only loads and not resume, but there is
 | 
			
		||||
	 * automatic resume when target is extended, as it's believed
 | 
			
		||||
	 * there can be no i/o flying to this 'new' extended space
 | 
			
		||||
	 * there can be no i/o flying to this 'new' extedend space
 | 
			
		||||
	 * from any device above. Reason is that preloaded target above
 | 
			
		||||
	 * may actually need to see its bigger subdevice before it
 | 
			
		||||
	 * gets suspended. As long as devices are simple linears
 | 
			
		||||
@@ -277,7 +276,7 @@ struct load_properties {
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * When comparing table lines to decide if a reload is
 | 
			
		||||
	 * needed, ignore any differences between the lvm device
 | 
			
		||||
	 * needed, ignore any differences betwen the lvm device
 | 
			
		||||
	 * params and the kernel-reported device params.
 | 
			
		||||
	 * dm-integrity reports many internal parameters on the
 | 
			
		||||
	 * table line when lvm does not explicitly set them,
 | 
			
		||||
@@ -288,16 +287,12 @@ struct load_properties {
 | 
			
		||||
	/*
 | 
			
		||||
	 * Call node_send_messages(), set to 2 if there are messages
 | 
			
		||||
	 * When != 0, it validates matching transaction id, thus thin-pools
 | 
			
		||||
	 * where transaction_id is passed as 0 are never validated, this
 | 
			
		||||
	 * allows external management of thin-pool TID.
 | 
			
		||||
	 * where transation_id is passed as 0 are never validated, this
 | 
			
		||||
	 * allows external managment of thin-pool TID.
 | 
			
		||||
	 */
 | 
			
		||||
	unsigned send_messages;
 | 
			
		||||
	/* Skip suspending node's children, used when sending messages to thin-pool */
 | 
			
		||||
	int skip_suspend;
 | 
			
		||||
 | 
			
		||||
	/* Suspend and Resume siblings after node activation with udev flags*/
 | 
			
		||||
	unsigned reactivate_siblings;
 | 
			
		||||
	uint16_t reactivate_udev_flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Two of these used to join two nodes with uses and used_by. */
 | 
			
		||||
@@ -348,7 +343,7 @@ struct dm_tree {
 | 
			
		||||
	int retry_remove;		/* 1 retries remove if not successful */
 | 
			
		||||
	uint32_t cookie;
 | 
			
		||||
	char buf[DM_NAME_LEN + 32];	/* print buffer for device_name (major:minor) */
 | 
			
		||||
	const char * const *optional_uuid_suffixes;	/* uuid suffixes ignored when matching */
 | 
			
		||||
	const char **optional_uuid_suffixes;	/* uuid suffixes ignored when matching */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -540,8 +535,7 @@ static struct dm_tree_node *_create_dm_tree_node(struct dm_tree *dtree,
 | 
			
		||||
	struct dm_tree_node *node;
 | 
			
		||||
	dev_t dev;
 | 
			
		||||
 | 
			
		||||
	if (!dtree || !dtree->mem ||
 | 
			
		||||
	    !(node = dm_pool_zalloc(dtree->mem, sizeof(*node))) ||
 | 
			
		||||
	if (!(node = dm_pool_zalloc(dtree->mem, sizeof(*node))) ||
 | 
			
		||||
	    !(node->name = dm_pool_strdup(dtree->mem, name)) ||
 | 
			
		||||
	    !(node->uuid = dm_pool_strdup(dtree->mem, uuid))) {
 | 
			
		||||
		log_error("_create_dm_tree_node alloc failed.");
 | 
			
		||||
@@ -591,7 +585,6 @@ void dm_tree_set_optional_uuid_suffixes(struct dm_tree *dtree, const char **opti
 | 
			
		||||
	dtree->optional_uuid_suffixes = optional_uuid_suffixes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *_node_name(struct dm_tree_node *dnode);
 | 
			
		||||
static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
 | 
			
		||||
						       const char *uuid)
 | 
			
		||||
{
 | 
			
		||||
@@ -599,26 +592,28 @@ static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
 | 
			
		||||
	const char *default_uuid_prefix;
 | 
			
		||||
	size_t default_uuid_prefix_len;
 | 
			
		||||
	const char *suffix, *suffix_position;
 | 
			
		||||
	char uuid_without_suffix[DM_UUID_LEN + 1];
 | 
			
		||||
	char uuid_without_suffix[DM_UUID_LEN];
 | 
			
		||||
	unsigned i = 0;
 | 
			
		||||
	const char * const *suffix_list = dtree->optional_uuid_suffixes;
 | 
			
		||||
	const char **suffix_list = dtree->optional_uuid_suffixes;
 | 
			
		||||
 | 
			
		||||
	if ((node = dm_hash_lookup(dtree->uuids, uuid))) {
 | 
			
		||||
		log_debug_activation("Matched uuid %s %s in deptree.", uuid, _node_name(node));
 | 
			
		||||
		log_debug("Matched uuid %s in deptree.", uuid);
 | 
			
		||||
		return node;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	default_uuid_prefix = dm_uuid_prefix();
 | 
			
		||||
	default_uuid_prefix_len = strlen(default_uuid_prefix);
 | 
			
		||||
 | 
			
		||||
	if (suffix_list && (suffix_position = strrchr(uuid, '-'))) {
 | 
			
		||||
		while ((suffix = suffix_list[i++])) {
 | 
			
		||||
			if (strcmp(suffix_position + 1, suffix))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			dm_strncpy(uuid_without_suffix, uuid, sizeof(uuid_without_suffix));
 | 
			
		||||
			(void) strncpy(uuid_without_suffix, uuid, sizeof(uuid_without_suffix));
 | 
			
		||||
			uuid_without_suffix[suffix_position - uuid] = '\0';
 | 
			
		||||
 | 
			
		||||
			if ((node = dm_hash_lookup(dtree->uuids, uuid_without_suffix))) {
 | 
			
		||||
				log_debug_activation("Matched uuid %s %s (missing suffix -%s) in deptree.",
 | 
			
		||||
						     uuid_without_suffix, _node_name(node), suffix);
 | 
			
		||||
				log_debug("Matched uuid %s (missing suffix -%s) in deptree.", uuid_without_suffix, suffix);
 | 
			
		||||
				return node;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@@ -626,17 +621,15 @@ static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	default_uuid_prefix = dm_uuid_prefix();
 | 
			
		||||
	default_uuid_prefix_len = strlen(default_uuid_prefix);
 | 
			
		||||
	if (strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if ((strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len) == 0) &&
 | 
			
		||||
	    (node = dm_hash_lookup(dtree->uuids, uuid + default_uuid_prefix_len))) {
 | 
			
		||||
		log_debug_activation("Matched uuid %s %s (missing prefix) in deptree.",
 | 
			
		||||
				     uuid + default_uuid_prefix_len, _node_name(node));
 | 
			
		||||
	if ((node = dm_hash_lookup(dtree->uuids, uuid + default_uuid_prefix_len))) {
 | 
			
		||||
		log_debug("Matched uuid %s (missing prefix) in deptree.", uuid + default_uuid_prefix_len);
 | 
			
		||||
		return node;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_debug_activation("Not matched uuid %s in deptree.", uuid);
 | 
			
		||||
	log_debug("Not matched uuid %s in deptree.", uuid);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -969,7 +962,7 @@ static int _check_device_not_in_use(const char *name, struct dm_info *info)
 | 
			
		||||
	} else if (dm_device_has_holders(info->major, info->minor))
 | 
			
		||||
		reason = "is used by another device";
 | 
			
		||||
	else if (dm_device_has_mounted_fs(info->major, info->minor))
 | 
			
		||||
		reason = "contains a filesystem in use";
 | 
			
		||||
		reason = "constains a filesystem in use";
 | 
			
		||||
	else
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
@@ -1817,7 +1810,7 @@ static int _dm_tree_deactivate_children(struct dm_tree_node *dnode,
 | 
			
		||||
 | 
			
		||||
		if (info.open_count) {
 | 
			
		||||
			/* Skip internal non-toplevel opened nodes */
 | 
			
		||||
			/* On some old udev systems without correct udev rules
 | 
			
		||||
			/* On some old udev systems without corrrect udev rules
 | 
			
		||||
			 * this hack avoids 'leaking' active _mimageX legs after
 | 
			
		||||
			 * deactivation of mirror LV. Other suffixes are not added
 | 
			
		||||
			 * since it's expected newer systems with wider range of
 | 
			
		||||
@@ -2036,68 +2029,6 @@ static int _rename_conflict_exists(struct dm_tree_node *parent,
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Reactivation of sibling nodes
 | 
			
		||||
 *
 | 
			
		||||
 * Function is used when activating origin and its thick snapshots
 | 
			
		||||
 * to ensure udev is processing first the origin LV and all the
 | 
			
		||||
 * snapshot LVs are processed afterwards.
 | 
			
		||||
 */
 | 
			
		||||
static int _reactivate_siblings(struct dm_tree_node *dnode,
 | 
			
		||||
				const char *uuid_prefix,
 | 
			
		||||
				size_t uuid_prefix_len)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_tree_node *child;
 | 
			
		||||
	const char *uuid;
 | 
			
		||||
	void *handle = NULL;
 | 
			
		||||
	int r = 1;
 | 
			
		||||
 | 
			
		||||
	/* Wait for udev before reactivating siblings */
 | 
			
		||||
	if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	dm_tree_set_cookie(dnode, 0);
 | 
			
		||||
 | 
			
		||||
	while ((child = dm_tree_next_child(&handle, dnode, 0))) {
 | 
			
		||||
		if (child->props.reactivate_siblings) {
 | 
			
		||||
			/* Skip 'leading' device in this group, marked with flag */
 | 
			
		||||
			child->props.reactivate_siblings = 0;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!(uuid = dm_tree_node_get_uuid(child))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!_suspend_node(child->name, child->info.major, child->info.minor,
 | 
			
		||||
				   child->dtree->skip_lockfs,
 | 
			
		||||
				   child->dtree->no_flush, &child->info)) {
 | 
			
		||||
			log_error("Unable to suspend %s (" FMTu32
 | 
			
		||||
				  ":" FMTu32 ")", child->name,
 | 
			
		||||
				  child->info.major, child->info.minor);
 | 
			
		||||
			r = 0;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		if (!_resume_node(child->name, child->info.major, child->info.minor,
 | 
			
		||||
				  child->props.read_ahead, child->props.read_ahead_flags,
 | 
			
		||||
				  &child->info, &child->dtree->cookie,
 | 
			
		||||
				  child->props.reactivate_udev_flags, // use these flags
 | 
			
		||||
				  child->info.suspended)) {
 | 
			
		||||
			log_error("Failed to suspend %s (" FMTu32
 | 
			
		||||
				  ":" FMTu32 ")", child->name,
 | 
			
		||||
				  child->info.major, child->info.minor);
 | 
			
		||||
			r = 0;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_tree_activate_children(struct dm_tree_node *dnode,
 | 
			
		||||
				 const char *uuid_prefix,
 | 
			
		||||
				 size_t uuid_prefix_len)
 | 
			
		||||
@@ -2108,7 +2039,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
 | 
			
		||||
	struct dm_tree_node *child = dnode;
 | 
			
		||||
	const char *name;
 | 
			
		||||
	const char *uuid;
 | 
			
		||||
	int priority, next_priority;
 | 
			
		||||
	int priority;
 | 
			
		||||
 | 
			
		||||
	/* Activate children first */
 | 
			
		||||
	while ((child = dm_tree_next_child(&handle, dnode, 0))) {
 | 
			
		||||
@@ -2126,16 +2057,12 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	handle = NULL;
 | 
			
		||||
 | 
			
		||||
	for (priority = 0; priority < 3; priority++) {
 | 
			
		||||
		awaiting_peer_rename = 0;
 | 
			
		||||
		next_priority = 0;
 | 
			
		||||
		while ((child = dm_tree_next_child(&handle, dnode, 0))) {
 | 
			
		||||
			if (priority != child->activation_priority) {
 | 
			
		||||
				if ((next_priority < child->activation_priority) &&
 | 
			
		||||
				    (child->activation_priority > priority))
 | 
			
		||||
					next_priority = child->activation_priority;
 | 
			
		||||
			if (priority != child->activation_priority)
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!(uuid = dm_tree_node_get_uuid(child))) {
 | 
			
		||||
				stack;
 | 
			
		||||
@@ -2183,23 +2110,16 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
 | 
			
		||||
			/*
 | 
			
		||||
			 * FIXME: Implement delayed error reporting
 | 
			
		||||
			 * activation should be stopped only in the case,
 | 
			
		||||
			 * the submission of transaction_id message fails,
 | 
			
		||||
			 * the submission of transation_id message fails,
 | 
			
		||||
			 * resume should continue further, just whole command
 | 
			
		||||
			 * has to report failure.
 | 
			
		||||
			 */
 | 
			
		||||
			if (r && (child->props.send_messages > 1) &&
 | 
			
		||||
			    !(r = _node_send_messages(child, uuid_prefix, uuid_prefix_len, 1)))
 | 
			
		||||
				stack;
 | 
			
		||||
 | 
			
		||||
			/* Reactivate only for fresh activated origin */
 | 
			
		||||
			if (r && child->props.reactivate_siblings &&
 | 
			
		||||
			    (!(r = _reactivate_siblings(dnode, uuid_prefix, uuid_prefix_len))))
 | 
			
		||||
				stack;
 | 
			
		||||
		}
 | 
			
		||||
		if (awaiting_peer_rename)
 | 
			
		||||
			priority--; /* redo priority level */
 | 
			
		||||
		else if (!next_priority)
 | 
			
		||||
			break;  /* no more work, higher priority was not found in the chain */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
@@ -2275,7 +2195,7 @@ static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* simplify string emitting code */
 | 
			
		||||
/* simplify string emiting code */
 | 
			
		||||
#define EMIT_PARAMS(p, str...)\
 | 
			
		||||
do {\
 | 
			
		||||
	int w;\
 | 
			
		||||
@@ -2758,10 +2678,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
 | 
			
		||||
		count += 1;
 | 
			
		||||
	if (seg->writecache_settings.max_age_set)
 | 
			
		||||
		count += 2;
 | 
			
		||||
	if (seg->writecache_settings.metadata_only_set)
 | 
			
		||||
		count += 1;
 | 
			
		||||
	if (seg->writecache_settings.pause_writeback_set)
 | 
			
		||||
		count += 2;
 | 
			
		||||
	if (seg->writecache_settings.new_key)
 | 
			
		||||
		count += 2;
 | 
			
		||||
 | 
			
		||||
@@ -2813,14 +2729,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
 | 
			
		||||
		EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (seg->writecache_settings.metadata_only_set) {
 | 
			
		||||
		EMIT_PARAMS(pos, " metadata_only");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (seg->writecache_settings.pause_writeback_set) {
 | 
			
		||||
		EMIT_PARAMS(pos, " pause_writeback %u", seg->writecache_settings.pause_writeback);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (seg->writecache_settings.new_key) {
 | 
			
		||||
		EMIT_PARAMS(pos, " %s %s",
 | 
			
		||||
			seg->writecache_settings.new_key,
 | 
			
		||||
@@ -2869,8 +2777,6 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
 | 
			
		||||
		count++;
 | 
			
		||||
	if (set->sectors_per_bit_set)
 | 
			
		||||
		count++;
 | 
			
		||||
	if (set->allow_discards_set && set->allow_discards)
 | 
			
		||||
		count++;
 | 
			
		||||
 | 
			
		||||
	EMIT_PARAMS(pos, "%s 0 %u %s %d fix_padding block_size:%u internal_hash:%s",
 | 
			
		||||
		    origin_dev,
 | 
			
		||||
@@ -2890,7 +2796,7 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
 | 
			
		||||
		EMIT_PARAMS(pos, " journal_sectors:%u", set->journal_sectors);
 | 
			
		||||
 | 
			
		||||
	if (set->interleave_sectors_set)
 | 
			
		||||
		EMIT_PARAMS(pos, " interleave_sectors:%u", set->interleave_sectors);
 | 
			
		||||
		EMIT_PARAMS(pos, " ineterleave_sectors:%u", set->interleave_sectors);
 | 
			
		||||
 | 
			
		||||
	if (set->buffer_sectors_set)
 | 
			
		||||
		EMIT_PARAMS(pos, " buffer_sectors:%u", set->buffer_sectors);
 | 
			
		||||
@@ -2907,9 +2813,6 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
 | 
			
		||||
	if (set->sectors_per_bit_set)
 | 
			
		||||
		EMIT_PARAMS(pos, " sectors_per_bit:%llu", (unsigned long long)set->sectors_per_bit);
 | 
			
		||||
 | 
			
		||||
	if (set->allow_discards_set && set->allow_discards)
 | 
			
		||||
		EMIT_PARAMS(pos, " allow_discards");
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_secure_data(dmt))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
@@ -2946,18 +2849,13 @@ static int _thin_pool_emit_segment_line(struct dm_task *dmt,
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t minor,
 | 
			
		||||
static int _vdo_emit_segment_line(struct dm_task *dmt,
 | 
			
		||||
				  struct load_segment *seg,
 | 
			
		||||
				  char *params, size_t paramsize)
 | 
			
		||||
{
 | 
			
		||||
	int pos = 0;
 | 
			
		||||
	char data[DM_FORMAT_DEV_BUFSIZE];
 | 
			
		||||
	char data_dev[128]; // for /dev/dm-XXXX
 | 
			
		||||
	uint64_t logical_blocks;
 | 
			
		||||
	struct dm_task *vdo_dmt;
 | 
			
		||||
	uint64_t start, length = 0;
 | 
			
		||||
	char *type = NULL;
 | 
			
		||||
	char *vdo_params = NULL;
 | 
			
		||||
 | 
			
		||||
	if (!_build_dev_string(data, sizeof(data), seg->vdo_data))
 | 
			
		||||
		return_0;
 | 
			
		||||
@@ -2967,59 +2865,18 @@ static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If there is already running VDO target, read 'existing' virtual size out of table line
 | 
			
		||||
	 * and avoid reading it them from VDO metadata device
 | 
			
		||||
	 *
 | 
			
		||||
	 * NOTE: ATM VDO virtual size can be ONLY extended thus it's simple to recognize 'right' size.
 | 
			
		||||
	 * However if there would be supported also reduction, this check would need to check range.
 | 
			
		||||
	 */
 | 
			
		||||
	if ((vdo_dmt = dm_task_create(DM_DEVICE_TABLE))) {
 | 
			
		||||
		if (dm_task_set_major(vdo_dmt, major) &&
 | 
			
		||||
		    dm_task_set_minor(vdo_dmt, minor) &&
 | 
			
		||||
		    dm_task_run(vdo_dmt)) {
 | 
			
		||||
			(void) dm_get_next_target(vdo_dmt, NULL, &start, &length, &type, &vdo_params);
 | 
			
		||||
			if (!type || strcmp(type, "vdo"))
 | 
			
		||||
				length = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dm_task_destroy(vdo_dmt);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!length && dm_vdo_parse_logical_size(data_dev, &logical_blocks))
 | 
			
		||||
		length = logical_blocks * 8;
 | 
			
		||||
 | 
			
		||||
	if (seg->size < length) {
 | 
			
		||||
		log_debug_activation("Correcting VDO virtual volume size from " FMTu64  " to " FMTu64 ".",
 | 
			
		||||
				     seg->size, length);
 | 
			
		||||
		seg->size = length;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (seg->vdo_version < 4) {
 | 
			
		||||
		EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s ",
 | 
			
		||||
			    data_dev,
 | 
			
		||||
			    seg->vdo_data_size / 8, // this parameter is in 4K units
 | 
			
		||||
			    seg->vdo_params.minimum_io_size * UINT32_C(512), //  sector to byte units
 | 
			
		||||
			    seg->vdo_params.block_map_cache_size_mb * UINT64_C(256),	// 1MiB -> 4KiB units
 | 
			
		||||
			    seg->vdo_params.block_map_era_length,
 | 
			
		||||
			    seg->vdo_params.use_metadata_hints ? "on" : "off" ,
 | 
			
		||||
			    (seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_SYNC) ? "sync" :
 | 
			
		||||
			    (seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC) ? "async" :
 | 
			
		||||
			    (seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
 | 
			
		||||
			    seg->vdo_name);
 | 
			
		||||
	} else {
 | 
			
		||||
		EMIT_PARAMS(pos, "V4 %s " FMTu64 " %u " FMTu64 " %u "
 | 
			
		||||
			    "deduplication %s compression %s ",
 | 
			
		||||
			    data_dev,
 | 
			
		||||
			    seg->vdo_data_size / 8, // this parameter is in 4K units
 | 
			
		||||
			    seg->vdo_params.minimum_io_size * UINT32_C(512), //  sector to byte units
 | 
			
		||||
			    seg->vdo_params.block_map_cache_size_mb * UINT64_C(256),	// 1MiB -> 4KiB units
 | 
			
		||||
			    seg->vdo_params.block_map_era_length,
 | 
			
		||||
			    seg->vdo_params.use_deduplication ? "on" : "off",
 | 
			
		||||
			    seg->vdo_params.use_compression ? "on" : "off");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	EMIT_PARAMS(pos, "maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
 | 
			
		||||
	EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s "
 | 
			
		||||
		    "maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
 | 
			
		||||
		    data_dev,
 | 
			
		||||
		    seg->vdo_data_size / 8, // this parameter is in 4K units
 | 
			
		||||
		    seg->vdo_params.minimum_io_size * UINT32_C(512), //  sector to byte units
 | 
			
		||||
		    seg->vdo_params.block_map_cache_size_mb * UINT64_C(256),	// 1MiB -> 4KiB units
 | 
			
		||||
		    seg->vdo_params.block_map_era_length,
 | 
			
		||||
		    seg->vdo_params.use_metadata_hints ? "on" : "off" ,
 | 
			
		||||
		    (seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_SYNC) ? "sync" :
 | 
			
		||||
			(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC) ? "async" :
 | 
			
		||||
			(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
 | 
			
		||||
		    seg->vdo_name,
 | 
			
		||||
		    seg->vdo_params.max_discard,
 | 
			
		||||
		    seg->vdo_params.ack_threads,
 | 
			
		||||
		    seg->vdo_params.bio_threads,
 | 
			
		||||
@@ -3094,7 +2951,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
 | 
			
		||||
		EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size);
 | 
			
		||||
		break;
 | 
			
		||||
	case SEG_VDO:
 | 
			
		||||
		if (!_vdo_emit_segment_line(dmt, major, minor, seg, params, paramsize))
 | 
			
		||||
		if (!_vdo_emit_segment_line(dmt, seg, params, paramsize))
 | 
			
		||||
		      return_0;
 | 
			
		||||
		break;
 | 
			
		||||
	case SEG_CRYPT:
 | 
			
		||||
@@ -3362,26 +3219,9 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
 | 
			
		||||
 | 
			
		||||
	/* Preload children first */
 | 
			
		||||
	while ((child = dm_tree_next_child(&handle, dnode, 0))) {
 | 
			
		||||
		/* When a parent node (other than root) is inactive, we cannot delay
 | 
			
		||||
		 * the resume of a new device.
 | 
			
		||||
		 * For example, preloading a RAID table with a pvmoved leg requires the
 | 
			
		||||
		 * leg LV to be active before loading the RAID LV, so the pvmove device must
 | 
			
		||||
		 * be resumed immediately.
 | 
			
		||||
		 * This scenario only occurs when neither the RAID nor pvmove device has
 | 
			
		||||
		 * been instantiated yet. In this case, starting the pvmove device does
 | 
			
		||||
		 * not leak access to the PV device without going through the mirror target.
 | 
			
		||||
		 * However, if the RAID is already active and running, we can only preload
 | 
			
		||||
		 * the new pvmove device, and a full suspend must occur before resuming
 | 
			
		||||
		 * the new table with the running pvmove. So until the resume point
 | 
			
		||||
		 * any IO is going through the existing table line and not via pvmove target.
 | 
			
		||||
		 */
 | 
			
		||||
		if ((child->props.delay_resume_if_new > 1) &&
 | 
			
		||||
		    !dnode->info.exists &&
 | 
			
		||||
		    (dnode != &dnode->dtree->root)) { /* Ignore when parent is root node */
 | 
			
		||||
			log_debug("%s with inactive parent cancels delay_resume_if_new.",
 | 
			
		||||
				  _node_name(child));
 | 
			
		||||
			child->props.delay_resume_if_new = 0;
 | 
			
		||||
		}
 | 
			
		||||
		/* Propagate delay of resume from parent node */
 | 
			
		||||
		if (dnode->props.delay_resume_if_new > 1)
 | 
			
		||||
			child->props.delay_resume_if_new = dnode->props.delay_resume_if_new;
 | 
			
		||||
 | 
			
		||||
		/* Skip existing non-device-mapper devices */
 | 
			
		||||
		if (!child->info.exists && child->info.major)
 | 
			
		||||
@@ -3400,7 +3240,7 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
 | 
			
		||||
		if (!child->info.exists && !(node_created = _create_node(child, dnode)))
 | 
			
		||||
			return_0;
 | 
			
		||||
 | 
			
		||||
		/* Propagate delayed resume from extended child node */
 | 
			
		||||
		/* Propagate delayed resume from exteded child node */
 | 
			
		||||
		if (child->props.delay_resume_if_extended)
 | 
			
		||||
			dnode->props.delay_resume_if_extended = 1;
 | 
			
		||||
 | 
			
		||||
@@ -3550,10 +3390,6 @@ int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
 | 
			
		||||
	/* Resume snapshot origins after new snapshots */
 | 
			
		||||
	dnode->activation_priority = 1;
 | 
			
		||||
 | 
			
		||||
	if (!dnode->info.exists)
 | 
			
		||||
		/* Reactivate siblings for this origin after being resumed */
 | 
			
		||||
		dnode->props.reactivate_siblings = 1;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Don't resume the origin immediately in case it is a non-trivial 
 | 
			
		||||
	 * target that must not be active more than once concurrently!
 | 
			
		||||
@@ -3616,20 +3452,6 @@ static int _add_snapshot_target(struct dm_tree_node *node,
 | 
			
		||||
			/* Resume merging snapshot after snapshot-merge */
 | 
			
		||||
			seg->merge->activation_priority = 2;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (!origin_node->info.exists) {
 | 
			
		||||
		/* Keep original udev_flags for reactivation. */
 | 
			
		||||
		node->props.reactivate_udev_flags = node->udev_flags;
 | 
			
		||||
 | 
			
		||||
		/* Reactivation is needed if the origin's -real device is not in DM table.
 | 
			
		||||
		 * For this case after the resume of its origin LV we resume its snapshots
 | 
			
		||||
		 * with updated udev_flags to completely avoid udev scanning for the first resume.
 | 
			
		||||
		 * Reactivation then resumes snapshots with original udev_flags.
 | 
			
		||||
		 */
 | 
			
		||||
		node->udev_flags |= DM_SUBSYSTEM_UDEV_FLAG0 |
 | 
			
		||||
			DM_UDEV_DISABLE_DISK_RULES_FLAG |
 | 
			
		||||
			DM_UDEV_DISABLE_OTHER_RULES_FLAG;
 | 
			
		||||
		log_debug_activation("Using udev_flags 0x%x for activation of %s.",
 | 
			
		||||
				     node->udev_flags, node->name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
@@ -3836,7 +3658,7 @@ int dm_tree_node_add_raid_target(struct dm_tree_node *node,
 | 
			
		||||
 * - maximum 253 legs in a raid set (MD kernel limitation)
 | 
			
		||||
 * - delta_disks for disk add/remove reshaping
 | 
			
		||||
 * - data_offset for out-of-place reshaping
 | 
			
		||||
 * - data_copies to cope with odd numbers of raid10 disks
 | 
			
		||||
 * - data_copies to cope witth odd numbers of raid10 disks
 | 
			
		||||
 */
 | 
			
		||||
int dm_tree_node_add_raid_target_with_params_v2(struct dm_tree_node *node,
 | 
			
		||||
					        uint64_t size,
 | 
			
		||||
@@ -3887,7 +3709,7 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
 | 
			
		||||
{
 | 
			
		||||
	struct dm_config_node *cn;
 | 
			
		||||
	struct load_segment *seg;
 | 
			
		||||
	const uint64_t modemask =
 | 
			
		||||
	static const uint64_t _modemask =
 | 
			
		||||
		DM_CACHE_FEATURE_PASSTHROUGH |
 | 
			
		||||
		DM_CACHE_FEATURE_WRITETHROUGH |
 | 
			
		||||
		DM_CACHE_FEATURE_WRITEBACK;
 | 
			
		||||
@@ -3899,12 +3721,12 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (feature_flags & modemask) {
 | 
			
		||||
	switch (feature_flags & _modemask) {
 | 
			
		||||
	case DM_CACHE_FEATURE_PASSTHROUGH:
 | 
			
		||||
	case DM_CACHE_FEATURE_WRITEBACK:
 | 
			
		||||
		if (strcmp(policy_name, "cleaner") == 0) {
 | 
			
		||||
			/* Enforce writethrough mode for cleaner policy */
 | 
			
		||||
			feature_flags = ~modemask;
 | 
			
		||||
			feature_flags = ~_modemask;
 | 
			
		||||
			feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
 | 
			
		||||
		}
 | 
			
		||||
                /* Fall through */
 | 
			
		||||
@@ -4100,7 +3922,7 @@ int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
 | 
			
		||||
					   uint32_t slog_flags,
 | 
			
		||||
					   uint32_t slog_region_size)
 | 
			
		||||
{
 | 
			
		||||
	log_error("Replicator target is unsupported.");
 | 
			
		||||
	log_error("Replicator targer is unsupported.");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -4387,12 +4209,6 @@ int dm_tree_node_set_thin_external_origin(struct dm_tree_node *node,
 | 
			
		||||
 | 
			
		||||
	seg->external = external;
 | 
			
		||||
 | 
			
		||||
	if (!external->info.minor) {
 | 
			
		||||
		log_debug_activation("Delaying resume for new external origin %s.",
 | 
			
		||||
				     external->name);
 | 
			
		||||
		external->props.delay_resume_if_new = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -4507,7 +4323,6 @@ void dm_tree_node_set_callback(struct dm_tree_node *dnode,
 | 
			
		||||
 | 
			
		||||
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
 | 
			
		||||
				uint64_t size,
 | 
			
		||||
				uint32_t vdo_version,
 | 
			
		||||
				const char *vdo_pool_name,
 | 
			
		||||
				const char *data_uuid,
 | 
			
		||||
				uint64_t data_size,
 | 
			
		||||
@@ -4529,13 +4344,11 @@ int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
 | 
			
		||||
	if (!_link_tree_nodes(node, seg->vdo_data))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	seg->vdo_version = vdo_version;
 | 
			
		||||
	seg->vdo_params = *vtp;
 | 
			
		||||
	seg->vdo_name = vdo_pool_name;
 | 
			
		||||
	seg->vdo_data_size = data_size;
 | 
			
		||||
 | 
			
		||||
	if (seg->vdo_version < 4)
 | 
			
		||||
		node->props.send_messages = 2;
 | 
			
		||||
	node->props.send_messages = 2;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -223,6 +223,7 @@ retry_fcntl:
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* coverity[leaked_handle] intentional leak of fd handle here  */
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
 | 
			
		||||
fail_close_unlink:
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -169,7 +169,7 @@ int dm_vasprintf(char **result, const char *format, va_list aq)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (i > 1) {
 | 
			
		||||
		/* Reallocating more than once? */
 | 
			
		||||
		/* Reallocating more then once? */
 | 
			
		||||
		if (!(*result = strdup(buf))) {
 | 
			
		||||
			free(buf);
 | 
			
		||||
			return -1;
 | 
			
		||||
@@ -192,7 +192,7 @@ int dm_asprintf(char **result, const char *format, ...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Count occurrences of 'c' in 'str' until we reach a null char.
 | 
			
		||||
 * Count occurences of 'c' in 'str' until we reach a null char.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:
 | 
			
		||||
 *  len - incremented for each char we encounter.
 | 
			
		||||
@@ -385,7 +385,7 @@ char *dm_build_dm_uuid(struct dm_pool *mem, const char *uuid_prefix, const char
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	snprintf(dmuuid, len, "%s%s%s%s", uuid_prefix, lvid, (*layer) ? "-" : "", layer);
 | 
			
		||||
	sprintf(dmuuid, "%s%s%s%s", uuid_prefix, lvid, (*layer) ? "-" : "", layer);
 | 
			
		||||
 | 
			
		||||
	return dmuuid;
 | 
			
		||||
}
 | 
			
		||||
@@ -471,10 +471,10 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
 | 
			
		||||
	double d;
 | 
			
		||||
	uint64_t byte = UINT64_C(0);
 | 
			
		||||
	uint64_t units = UINT64_C(1024);
 | 
			
		||||
	char *size_buf;
 | 
			
		||||
	char *size_buf = NULL;
 | 
			
		||||
	char new_unit_type = '\0', unit_type_buf[2];
 | 
			
		||||
	const char *prefix = "";
 | 
			
		||||
	static const char _size_str[][3][12] = {
 | 
			
		||||
	const char * const size_str[][3] = {
 | 
			
		||||
		/* BASE_UNKNOWN */
 | 
			
		||||
		{"         ", "   ", " "},	/* [0] */
 | 
			
		||||
 | 
			
		||||
@@ -519,14 +519,14 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
 | 
			
		||||
		/* Case-independent match */
 | 
			
		||||
		for (s = 0; s < NUM_UNIT_PREFIXES; s++)
 | 
			
		||||
			if (toupper((int) unit_type) ==
 | 
			
		||||
			    *_size_str[BASE_SHARED + s][2]) {
 | 
			
		||||
			    *size_str[BASE_SHARED + s][2]) {
 | 
			
		||||
				base = BASE_SHARED;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Case-dependent match for powers of 1000 */
 | 
			
		||||
		for (s = 0; s < NUM_UNIT_PREFIXES; s++)
 | 
			
		||||
			if (unit_type == *_size_str[BASE_1000 + s][2]) {
 | 
			
		||||
			if (unit_type == *size_str[BASE_1000 + s][2]) {
 | 
			
		||||
				base = BASE_1000;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
@@ -534,7 +534,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
 | 
			
		||||
		/* Case-dependent match for powers of 1024 */
 | 
			
		||||
		if (base == BASE_UNKNOWN)
 | 
			
		||||
			for (s = 0; s < NUM_UNIT_PREFIXES; s++)
 | 
			
		||||
			if (unit_type == *_size_str[BASE_1024 + s][2]) {
 | 
			
		||||
			if (unit_type == *size_str[BASE_1024 + s][2]) {
 | 
			
		||||
				base = BASE_1024;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
@@ -544,7 +544,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
 | 
			
		||||
		/* Check for special units - s, b or u */
 | 
			
		||||
		for (s = 0; s < NUM_SPECIAL; s++)
 | 
			
		||||
			if (toupper((int) unit_type) ==
 | 
			
		||||
			    *_size_str[BASE_SPECIAL + s][2]) {
 | 
			
		||||
			    *size_str[BASE_SPECIAL + s][2]) {
 | 
			
		||||
				base = BASE_SPECIAL;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
@@ -552,7 +552,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
 | 
			
		||||
	if (size == UINT64_C(0)) {
 | 
			
		||||
		if (base == BASE_UNKNOWN)
 | 
			
		||||
			s = 0;
 | 
			
		||||
		snprintf(size_buf, SIZE_BUF, "0%s", include_suffix ? _size_str[base + s][suffix_type] : "");
 | 
			
		||||
		sprintf(size_buf, "0%s", include_suffix ? size_str[base + s][suffix_type] : "");
 | 
			
		||||
		return size_buf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -591,7 +591,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
 | 
			
		||||
		if ((s < NUM_UNIT_PREFIXES) &&
 | 
			
		||||
		    ((unit_type == 'R') || (unit_type == 'r'))) {
 | 
			
		||||
			/* When the rounding would cause difference, add '<' prefix
 | 
			
		||||
			 * i.e.  2043M is more than 1.9949G prints <2.00G
 | 
			
		||||
			 * i.e.  2043M is more then 1.9949G prints <2.00G
 | 
			
		||||
			 * This version is for 2 digits fixed precision */
 | 
			
		||||
			d = 100. * (double) size / byte;
 | 
			
		||||
			if (!_close_enough(floorl(d), nearbyintl(d)))
 | 
			
		||||
@@ -602,7 +602,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME Make precision configurable */
 | 
			
		||||
	switch (toupper(*_size_str[base + s][DM_SIZE_UNIT])) {
 | 
			
		||||
	switch (toupper(*size_str[base + s][DM_SIZE_UNIT])) {
 | 
			
		||||
	case 'B':
 | 
			
		||||
	case 'S':
 | 
			
		||||
		precision = 0;
 | 
			
		||||
@@ -612,7 +612,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	snprintf(size_buf, SIZE_BUF, "%s%.*f%s", prefix, precision,
 | 
			
		||||
		 (double) size / byte, include_suffix ? _size_str[base + s][suffix_type] : "");
 | 
			
		||||
		 (double) size / byte, include_suffix ? size_str[base + s][suffix_type] : "");
 | 
			
		||||
 | 
			
		||||
	return size_buf;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -106,31 +106,26 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
 | 
			
		||||
 | 
			
		||||
	/* Second field holds the device count */
 | 
			
		||||
	msg_fields = "<#devs> ";
 | 
			
		||||
	if (!(pp = _skip_fields(params, 1)) || (sscanf(pp, "%d", &i) != 1) || !(p = _skip_fields(pp, 1)))
 | 
			
		||||
	if (!(p = _skip_fields(params, 1)) || (sscanf(p, "%d", &i) != 1))
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	msg_fields = "";
 | 
			
		||||
	if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid))))
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> ";
 | 
			
		||||
	if (!(s->raid_type = dm_pool_strndup(mem, params, pp - params - 1)))
 | 
			
		||||
	if (!(s->raid_type = dm_pool_zalloc(mem, p - params)))
 | 
			
		||||
		goto_bad; /* memory is freed when pool is destroyed */
 | 
			
		||||
 | 
			
		||||
	if (!(pp = _skip_fields(p, 1)))
 | 
			
		||||
	if (!(s->dev_health = dm_pool_zalloc(mem, i + 1))) /* Space for health chars */
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	/* Raid target can actually report more than real number of legs in a case
 | 
			
		||||
	 * raid legs have been removed during initial raid array resynchronization */
 | 
			
		||||
	if (i > (pp - p - 1))
 | 
			
		||||
		i = pp - p - 1;
 | 
			
		||||
 | 
			
		||||
	if (!(s->dev_health = dm_pool_strndup(mem, p, i))) /* health chars */
 | 
			
		||||
		goto_bad;
 | 
			
		||||
	p = pp;
 | 
			
		||||
 | 
			
		||||
	s->dev_count = i;
 | 
			
		||||
	if (sscanf(p, FMTu64 "/" FMTu64, &s->insync_regions, &s->total_regions) != 2)
 | 
			
		||||
	msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> ";
 | 
			
		||||
	if (sscanf(params, "%s %u %s " FMTu64 "/" FMTu64,
 | 
			
		||||
		   s->raid_type,
 | 
			
		||||
		   &s->dev_count,
 | 
			
		||||
		   s->dev_health,
 | 
			
		||||
		   &s->insync_regions,
 | 
			
		||||
		   &s->total_regions) != 5)
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@@ -146,13 +141,13 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
 | 
			
		||||
	msg_fields = "<sync_action> and <mismatch_cnt> ";
 | 
			
		||||
 | 
			
		||||
	/* Skip pre-1.5.0 params */
 | 
			
		||||
	if (!(pp = _skip_fields(params, 4)) || !(p = _skip_fields(pp, 1)))
 | 
			
		||||
	if (!(p = _skip_fields(params, 4)) || !(pp = _skip_fields(p, 1)))
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	if (!(s->sync_action = dm_pool_strndup(mem, pp, p - pp - 1)))
 | 
			
		||||
	if (!(s->sync_action = dm_pool_zalloc(mem, pp - p)))
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	if (sscanf(p, FMTu64, &s->mismatch_count) != 1)
 | 
			
		||||
	if (sscanf(p, "%s " FMTu64, s->sync_action, &s->mismatch_count) != 2)
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	if (num_fields < 7)
 | 
			
		||||
@@ -171,35 +166,23 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
 | 
			
		||||
	if (sscanf(p, FMTu64, &s->data_offset) != 1)
 | 
			
		||||
		goto bad;
 | 
			
		||||
 | 
			
		||||
	/* <journal_char>  - 'A' - active write-through journal device.
 | 
			
		||||
	 *                 - 'a' - active write-back journal device.
 | 
			
		||||
	 *                 - 'D' - dead journal device.
 | 
			
		||||
	 *                 - '-' - no journal device.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	*status = s;
 | 
			
		||||
 | 
			
		||||
	while (i-- > 0)
 | 
			
		||||
		if (s->dev_health[i] == 'a')
 | 
			
		||||
			a++; /* Count number of 'a' */
 | 
			
		||||
	if (s->insync_regions == s->total_regions) {
 | 
			
		||||
		/* FIXME: kernel gives misleading info here
 | 
			
		||||
		 * Trying to recognize a true state */
 | 
			
		||||
		while (i-- > 0)
 | 
			
		||||
			if (s->dev_health[i] == 'a')
 | 
			
		||||
				a++; /* Count number of 'a' */
 | 
			
		||||
 | 
			
		||||
	if (a) {
 | 
			
		||||
		if ((a < s->dev_count) &&  /* SOME legs are in 'a' */
 | 
			
		||||
		    /* FIXME: kernel gives misleading info here
 | 
			
		||||
		     * Trying to recognize a true state */
 | 
			
		||||
		    (s->insync_regions == s->total_regions) &&
 | 
			
		||||
		    (!strcasecmp(s->sync_action, "recover") ||
 | 
			
		||||
		     !strcasecmp(s->sync_action, "idle"))) {
 | 
			
		||||
			/* Kernel may possibly start some action
 | 
			
		||||
			 * in near-by future, do not report 100% */
 | 
			
		||||
			s->insync_regions--;
 | 
			
		||||
		}
 | 
			
		||||
		if ((a == s->dev_count) && /* all legs are in 'a' */
 | 
			
		||||
		    (!strcasecmp(s->sync_action, "resync") ||
 | 
			
		||||
		     !strcasecmp(s->sync_action, "idle"))) {
 | 
			
		||||
			/* Mark 1st. leg in sync */
 | 
			
		||||
			s->dev_health[0] = 'A';
 | 
			
		||||
		if (a && a < s->dev_count) {
 | 
			
		||||
			/* SOME legs are in 'a' */
 | 
			
		||||
			if (!strcasecmp(s->sync_action, "recover")
 | 
			
		||||
			    || !strcasecmp(s->sync_action, "idle"))
 | 
			
		||||
				/* Kernel may possibly start some action
 | 
			
		||||
				 * in near-by future, do not report 100% */
 | 
			
		||||
				s->insync_regions--;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -335,19 +318,11 @@ int dm_get_status_cache(struct dm_pool *mem, const char *params,
 | 
			
		||||
 | 
			
		||||
	/* Read in policy args */
 | 
			
		||||
	pp = p;
 | 
			
		||||
	if (!(p = _skip_fields(p, 1)))
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	i = p - pp;
 | 
			
		||||
	if ((i < 1) ||
 | 
			
		||||
	    !(s->policy_name = dm_pool_zalloc(mem, i)))
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	dm_strncpy(s->policy_name, pp, i);
 | 
			
		||||
 | 
			
		||||
	if (sscanf(p, "%d", &s->policy_argc) != 1)
 | 
			
		||||
	if (!(p = _skip_fields(p, 1)) ||
 | 
			
		||||
	    !(s->policy_name = dm_pool_zalloc(mem, (p - pp))))
 | 
			
		||||
		goto bad;
 | 
			
		||||
	if (sscanf(pp, "%s %d", s->policy_name, &s->policy_argc) != 2)
 | 
			
		||||
		goto bad;
 | 
			
		||||
 | 
			
		||||
	if (s->policy_argc &&
 | 
			
		||||
	    (!(s->policy_argv = dm_pool_zalloc(mem, sizeof(char *) * s->policy_argc)) ||
 | 
			
		||||
	     !(p = _skip_fields(p, 1)) ||
 | 
			
		||||
@@ -409,12 +384,12 @@ int dm_get_status_integrity(struct dm_pool *mem, const char *params,
 | 
			
		||||
			     struct dm_status_integrity **status)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_status_integrity *s;
 | 
			
		||||
	char recalc_str[16] = { 0 };
 | 
			
		||||
	char recalc_str[16] = "\0";
 | 
			
		||||
 | 
			
		||||
	if (!(s = dm_pool_zalloc(mem, sizeof(*s))))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	if (sscanf(params, "%llu %llu %15s",
 | 
			
		||||
	if (sscanf(params, "%llu %llu %s",
 | 
			
		||||
		   (unsigned long long *)&s->number_of_mismatches,
 | 
			
		||||
		   (unsigned long long *)&s->provided_data_sectors,
 | 
			
		||||
		   recalc_str) != 3) {
 | 
			
		||||
@@ -536,21 +511,6 @@ int dm_get_status_thin(struct dm_pool *mem, const char *params,
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dm_status_mirror_health_t _get_health(char c)
 | 
			
		||||
{
 | 
			
		||||
	switch (c) {
 | 
			
		||||
	case 'A': return DM_STATUS_MIRROR_ALIVE;
 | 
			
		||||
	case 'F': return DM_STATUS_MIRROR_FLUSH_FAILED;
 | 
			
		||||
	case 'D': return DM_STATUS_MIRROR_WRITE_FAILED;
 | 
			
		||||
	case 'S': return DM_STATUS_MIRROR_SYNC_FAILED;
 | 
			
		||||
	case 'R': return DM_STATUS_MIRROR_READ_FAILED;
 | 
			
		||||
	default:
 | 
			
		||||
		log_warn("WARNING: Unknown mirror health status char: %c", c);
 | 
			
		||||
		/* fall through */
 | 
			
		||||
	case 'U': return DM_STATUS_MIRROR_UNCLASSIFIED;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * dm core parms:	     0 409600 mirror
 | 
			
		||||
 * Mirror core parms:	     2 253:4 253:5 400/400
 | 
			
		||||
@@ -579,7 +539,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
 | 
			
		||||
	pos += used;
 | 
			
		||||
 | 
			
		||||
	if (num_devs > DM_MIRROR_MAX_IMAGES) {
 | 
			
		||||
		log_error(INTERNAL_ERROR "More than " DM_TO_STRING(DM_MIRROR_MAX_IMAGES)
 | 
			
		||||
		log_error(INTERNAL_ERROR "More then " DM_TO_STRING(DM_MIRROR_MAX_IMAGES)
 | 
			
		||||
			  " reported in mirror status.");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
@@ -604,7 +564,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
 | 
			
		||||
	pos += used;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_devs ; ++i)
 | 
			
		||||
		s->devs[i].health = _get_health(pos[i]);
 | 
			
		||||
		s->devs[i].health = pos[i];
 | 
			
		||||
 | 
			
		||||
	if (!(pos = _skip_fields(pos, argc)))
 | 
			
		||||
		goto_out;
 | 
			
		||||
@@ -649,7 +609,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
 | 
			
		||||
					goto_out;
 | 
			
		||||
 | 
			
		||||
			for (i = 0; i < s->log_count; ++i)
 | 
			
		||||
				s->logs[i].health = _get_health(pos[i]);
 | 
			
		||||
				s->logs[i].health = pos[i];
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,6 @@
 | 
			
		||||
#  include <linux/types.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#define DM_DIR "mapper"		/* Slashes not supported */
 | 
			
		||||
#define DM_CONTROL_NODE "control"
 | 
			
		||||
#define DM_MAX_TYPE_NAME 16
 | 
			
		||||
@@ -211,7 +209,7 @@ struct dm_name_list {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define DM_NAME_LIST_FLAG_HAS_UUID		1
 | 
			
		||||
#define DM_NAME_LIST_FLAG_DOES_NOT_HAVE_UUID	2
 | 
			
		||||
#define DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID	2
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Used to retrieve the target versions
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 * The UUID contained in the dm_ulog_request structure is the reference that
 | 
			
		||||
 * will be used by all request types to a specific log.  The constructor must
 | 
			
		||||
 * record this association with the instance created.
 | 
			
		||||
 * record this assotiation with the instance created.
 | 
			
		||||
 *
 | 
			
		||||
 * When the request has been processed, user-space must return the
 | 
			
		||||
 * dm_ulog_request to the kernel - setting the 'error' field, filling the
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,7 @@
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "base/memory/zalloc.h"
 | 
			
		||||
#include "device_mapper/misc/dmlib.h"
 | 
			
		||||
#include "dmlib.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
struct block {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifdef VALGRIND_POOL
 | 
			
		||||
#include <memcheck.h>
 | 
			
		||||
#include "memcheck.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "base/memory/zalloc.h"
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user