mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-30 20:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			dev-dct-se
			...
			dev-dct-de
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 07338325e5 | 
							
								
								
									
										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 | ||||
|   | ||||
							
								
								
									
										104
									
								
								.gitlab-ci.yml
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								.gitlab-ci.yml
									
									
									
									
									
								
							| @@ -1,104 +0,0 @@ | ||||
| stages: | ||||
|   - approve | ||||
|   - test | ||||
|  | ||||
| approve1: | ||||
|   stage: approve | ||||
|   script: | ||||
|     - echo "Approved..." | ||||
|   rules: | ||||
|     # TODO: Filter only safe repositories, or user in developers | ||||
|     - if: $CI_PROJECT_PATH != "csonto/lvm2" && $CI_PROJECT_PATH != "lvmteam/lvm2" | ||||
|       when: manual | ||||
|     # TODO: for other branches than main/rhel: run pipeline only when requested: | ||||
|     - if: $CI_COMMIT_BRANCH != "main" && $CI_COMMIT_BRANCH !~ "^rhel.*" | ||||
|       when: manual | ||||
|     - when: on_success | ||||
|   allow_failure: false | ||||
|  | ||||
|  | ||||
| pages: | ||||
|   image: elecnix/ikiwiki | ||||
|   stage: test | ||||
|   script: | ||||
|     - ikiwiki --setup ikiwiki.setup --libdir themes/ikistrap/lib | ||||
|   artifacts: | ||||
|     paths: | ||||
|       - public | ||||
|   only: | ||||
|     refs: | ||||
|       - main | ||||
|     changes: | ||||
|       - doc/**/* | ||||
|       - ikiwiki.setup | ||||
|  | ||||
|  | ||||
| # TODO: | ||||
| # - check results of autoreconf and make generate - may need additional commit | ||||
| #     - we need a particular setup (rawhide OR latest supported fedora?) | ||||
| # - do make rpm and publish results as artifacts - we will use packit/COPR for this eventually | ||||
|  | ||||
| # Run on any commits to main (master), rhel8, rhel9 branches | ||||
| test-job: | ||||
|   stage: test | ||||
|   parallel: | ||||
|     matrix: | ||||
|       - TAG: rhel8 | ||||
|         CONFIGURE: > | ||||
|           --with-cluster=internal | ||||
|           --enable-cmirrord | ||||
|       - TAG: rhel9 | ||||
|         CONFIGURE: > | ||||
|           --with-default-use-devices-file=1 | ||||
|           --enable-app-machineid | ||||
|           --enable-editline | ||||
|           --disable-readline | ||||
|   artifacts: | ||||
|     paths: | ||||
|       - test/results/ | ||||
|     expire_in: 1 week | ||||
|   tags: | ||||
|       - ${TAG} | ||||
|   timeout: 2h | ||||
|   script: | ||||
|     # Common options go here, diffs to the above matrix | ||||
|     - > | ||||
|       ./configure ${CONFIGURE} | ||||
|       --enable-fsadm | ||||
|       --enable-write_install | ||||
|       --enable-pkgconfig | ||||
|       --enable-cmdlib | ||||
|       --enable-dmeventd | ||||
|       --enable-blkid_wiping | ||||
|       --enable-udev_sync | ||||
|       --with-thin=internal | ||||
|       --with-cache=internal | ||||
|       --enable-lvmpolld | ||||
|       --enable-lvmlockd-dlm --enable-lvmlockd-dlmcontrol | ||||
|       --enable-lvmlockd-sanlock | ||||
|       --enable-dbus-service --enable-notify-dbus | ||||
|       --enable-dmfilemapd | ||||
|       --with-writecache=internal | ||||
|       --with-vdo=internal --with-vdo-format=/usr/bin/vdoformat | ||||
|       --with-integrity=internal | ||||
|       --disable-silent-rules | ||||
|     - make | ||||
|     - rm -rf test/results | ||||
|     - mkdir -p /dev/shm/lvm2-test | ||||
|     - mount -o remount,dev /dev/shm | ||||
|     # TODO: Need to distinguish failed test from failed harness | ||||
|     # TODO: Also need a way to find if run is incomplete, e.g. full disk resulting in many skipped tests | ||||
|     - VERBOSE=0 BATCH=1 LVM_TEST_DIR=/dev/shm/lvm2-test make check || true | ||||
|     - rm -rf /dev/shm/lvm2-test | ||||
|     - cut -d' ' -f2 test/results/list | sort | uniq -c | ||||
|     # Filter artifacts - keep only logs from tests which are not pass | ||||
|     - cd test/results && rm $(grep 'passed$' list | cut -d' ' -f1 | sed -e 's|/|_|g' -e 's|.*|\0.txt|') | ||||
|     # TODO: Keep a list of known failures, and translate into regexp - or simply use python... | ||||
|     - if grep failed test/results/list | grep -v '\\\(dbustest\|lvconvert-mirror\)\.sh' | sort; then false; else true; fi | ||||
|   rules: | ||||
|     # Filter only safe repositories, or user in developers: | ||||
|     # NOTE: Already done in approve stage, may be more caution than necessary | ||||
|     - if: $CI_PROJECT_PATH != "csonto/lvm2" && $CI_PROJECT_PATH != "lvmteam/lvm2" | ||||
|       when: manual | ||||
|     - when: on_success | ||||
|  | ||||
							
								
								
									
										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.210-git (2025-09-09) | ||||
| 1.02.185-git (2022-02-07) | ||||
|   | ||||
							
								
								
									
										440
									
								
								WHATS_NEW
									
									
									
									
									
								
							
							
						
						
									
										440
									
								
								WHATS_NEW
									
									
									
									
									
								
							| @@ -1,287 +1,5 @@ | ||||
| Version 2.03.36 -  | ||||
| ================== | ||||
|   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 | ||||
| Version 2.03.16 -  | ||||
| ==================================== | ||||
|   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 | ||||
| ==================================== | ||||
| @@ -368,8 +86,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. | ||||
| @@ -399,7 +117,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. | ||||
| @@ -442,7 +160,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 | ||||
| @@ -526,7 +244,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. | ||||
| @@ -539,14 +257,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. | ||||
| @@ -608,7 +326,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. | ||||
| @@ -653,7 +371,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. | ||||
|  | ||||
| @@ -669,7 +387,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. | ||||
| @@ -691,7 +409,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. | ||||
| @@ -781,13 +499,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". | ||||
| @@ -855,7 +573,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. | ||||
| @@ -905,8 +623,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. | ||||
| @@ -969,7 +687,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. | ||||
| @@ -1009,7 +727,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. | ||||
| @@ -1162,11 +880,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 | ||||
| @@ -1191,7 +909,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). | ||||
| @@ -1268,7 +986,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. | ||||
| @@ -1297,7 +1015,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. | ||||
| @@ -1447,7 +1165,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. | ||||
| @@ -1604,7 +1322,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. | ||||
| @@ -1682,7 +1400,7 @@ Version 2.02.116 - 30th January 2015 | ||||
|   Scan pools in for_each_sub_lv() and add for_each_sub_lv_except_pools(). | ||||
|   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. | ||||
| @@ -1748,13 +1466,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. | ||||
| @@ -1807,7 +1525,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. | ||||
| @@ -1875,7 +1593,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. | ||||
| @@ -1894,7 +1612,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. | ||||
| @@ -1999,7 +1717,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. | ||||
| @@ -2026,7 +1744,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. | ||||
| @@ -2068,7 +1786,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. | ||||
|  | ||||
| @@ -2141,7 +1859,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. | ||||
| @@ -2304,11 +2022,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 | ||||
| @@ -2509,7 +2227,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. | ||||
| @@ -2559,7 +2277,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. | ||||
| @@ -2643,7 +2361,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. | ||||
| @@ -2656,7 +2374,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. | ||||
| @@ -2691,7 +2409,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(). | ||||
| @@ -2764,7 +2482,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. | ||||
| @@ -2783,7 +2501,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). | ||||
| @@ -2813,7 +2531,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) | ||||
| @@ -2884,11 +2602,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. | ||||
| @@ -2954,13 +2672,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(). | ||||
| @@ -3033,7 +2751,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. | ||||
| @@ -3059,7 +2777,7 @@ Version 2.02.85 - 29th April 2011 | ||||
|   Use only vg_set_fid and new pv_set_fid fn to assign the format instance. | ||||
|   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. | ||||
| @@ -3068,10 +2786,10 @@ Version 2.02.85 - 29th April 2011 | ||||
|   Avoid possible endless loop in _free_vginfo when 4 or more VGs have same name. | ||||
|   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. | ||||
| @@ -3085,7 +2803,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. | ||||
| @@ -3099,7 +2817,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. | ||||
| @@ -3154,7 +2872,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. | ||||
| @@ -3186,7 +2904,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. | ||||
| @@ -3455,7 +3173,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. | ||||
| @@ -3483,7 +3201,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. | ||||
| @@ -3534,7 +3252,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. | ||||
| @@ -3693,7 +3411,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 | ||||
| =================================== | ||||
| @@ -3709,7 +3427,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(). | ||||
| @@ -3785,7 +3503,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 | ||||
| @@ -3823,14 +3541,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. | ||||
| @@ -4010,7 +3728,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. | ||||
| @@ -4071,7 +3789,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. | ||||
| @@ -4144,7 +3862,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. | ||||
| @@ -4321,7 +4039,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. | ||||
| @@ -4368,7 +4086,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. | ||||
| @@ -4386,7 +4104,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. | ||||
| @@ -4394,7 +4112,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. | ||||
| @@ -4444,7 +4162,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. | ||||
| @@ -4816,7 +4534,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. | ||||
| @@ -5143,7 +4861,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. | ||||
| @@ -5374,7 +5092,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. | ||||
| @@ -5589,5 +5307,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! | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										143
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							| @@ -1,104 +1,5 @@ | ||||
| Version 1.02.210 -  | ||||
| =================== | ||||
|  | ||||
| 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 | ||||
| Version 1.02.185 -  | ||||
| ===================================== | ||||
|   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 | ||||
| ===================================== | ||||
| @@ -130,7 +31,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 | ||||
| @@ -161,7 +62,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. | ||||
|  | ||||
| @@ -190,7 +91,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. | ||||
| @@ -239,7 +140,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). | ||||
|  | ||||
| @@ -294,7 +195,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 | ||||
|  | ||||
| @@ -434,7 +335,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 | ||||
| ===================================== | ||||
| @@ -449,7 +350,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'. | ||||
| @@ -622,7 +523,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 | ||||
| @@ -641,7 +542,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. | ||||
| @@ -728,7 +629,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 | ||||
| ===================================== | ||||
| @@ -753,7 +654,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(). | ||||
| @@ -850,7 +751,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. | ||||
| @@ -944,7 +845,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 | ||||
| =============================== | ||||
| @@ -959,7 +860,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 | ||||
| ================================== | ||||
| @@ -973,7 +874,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. | ||||
| @@ -1142,7 +1043,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 | ||||
| @@ -1198,7 +1099,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 | ||||
| ================================ | ||||
| @@ -1266,7 +1167,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. | ||||
| @@ -1322,7 +1223,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. | ||||
| @@ -1353,7 +1254,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. | ||||
|  | ||||
| @@ -1601,5 +1502,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; | ||||
|  | ||||
| @@ -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; | ||||
|  | ||||
| @@ -279,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; | ||||
| 		} | ||||
|  | ||||
| @@ -293,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--; | ||||
| @@ -315,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) { | ||||
| @@ -345,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; | ||||
|  | ||||
| @@ -384,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) { | ||||
| @@ -419,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) { | ||||
| @@ -489,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; | ||||
| @@ -502,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) { | ||||
| @@ -557,32 +555,23 @@ static struct lookup_result _lookup_prefix(struct value *v, const uint8_t *kb, c | ||||
| 	return (struct lookup_result) {.v = v, .kb = kb}; | ||||
| } | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	unsigned entries = rt->nr_entries; | ||||
| 	return radix_tree_insert(rt, key, keylen, rv) ? | ||||
| 		((entries != rt->nr_entries) ? 1 : -1) : 0; | ||||
| } | ||||
|  | ||||
| // Note the degrade functions also free the original node. | ||||
| static void _degrade_to_n4(struct node16 *n16, struct value *result) | ||||
| { | ||||
| 	struct node4 *n4 = zalloc(sizeof(*n4)); | ||||
|         struct node4 *n4 = zalloc(sizeof(*n4)); | ||||
|  | ||||
| 	assert(n4 != NULL); | ||||
|  | ||||
| 	n4->nr_entries = n16->nr_entries; | ||||
| 	memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys)); | ||||
| 	memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values)); | ||||
| 	free(n16); | ||||
|         n4->nr_entries = n16->nr_entries; | ||||
|         memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys)); | ||||
|         memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values)); | ||||
|         free(n16); | ||||
|  | ||||
| 	result->type = NODE4; | ||||
| 	result->value.ptr = n4; | ||||
| @@ -591,20 +580,20 @@ static void _degrade_to_n4(struct node16 *n16, struct value *result) | ||||
| static void _degrade_to_n16(struct node48 *n48, struct value *result) | ||||
| { | ||||
| 	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; | ||||
| @@ -612,13 +601,13 @@ static void _degrade_to_n16(struct node48 *n48, struct value *result) | ||||
|  | ||||
| static void _degrade_to_n48(struct node256 *n256, struct value *result) | ||||
| { | ||||
| 	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; | ||||
|  | ||||
| @@ -627,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; | ||||
| @@ -643,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; | ||||
| @@ -662,27 +651,27 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb | ||||
| 	struct node256 *n256; | ||||
|  | ||||
| 	if (kb == ke) { | ||||
| 		if (root->type == VALUE) { | ||||
| 			root->type = UNSET; | ||||
| 			_dtr(rt, root->value); | ||||
| 			return true; | ||||
|         	if (root->type == VALUE) { | ||||
|                 	root->type = UNSET; | ||||
|                 	_dtr(rt, root->value); | ||||
|                 	return true; | ||||
|  | ||||
| 		} else if (root->type == VALUE_CHAIN) { | ||||
|                 } else if (root->type == VALUE_CHAIN) { | ||||
| 			vc = root->value.ptr; | ||||
| 			_dtr(rt, vc->value); | ||||
| 			memcpy(root, &vc->child, sizeof(*root)); | ||||
| 			free(vc); | ||||
| 			return true; | ||||
|  | ||||
| 		} else | ||||
|                 } else | ||||
| 			return false; | ||||
| 	} | ||||
|  | ||||
| 	switch (root->type) { | ||||
| 	case UNSET: | ||||
| 	case VALUE: | ||||
| 		// this is a value for a prefix of the key | ||||
| 		return false; | ||||
|         	// this is a value for a prefix of the key | ||||
|         	return false; | ||||
|  | ||||
| 	case VALUE_CHAIN: | ||||
| 		vc = root->value.ptr; | ||||
| @@ -697,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) { | ||||
| @@ -716,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; | ||||
| @@ -733,19 +722,19 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb | ||||
| 		return false; | ||||
|  | ||||
| 	case NODE16: | ||||
| 		n16 = root->value.ptr; | ||||
|         	n16 = root->value.ptr; | ||||
| 		for (i = 0; i < n16->nr_entries; i++) { | ||||
| 			if (n16->keys[i] == *kb) { | ||||
| 				r = _remove(rt, n16->values + i, kb + 1, ke); | ||||
| 				if (r && n16->values[i].type == UNSET) { | ||||
| 					if (i < n16->nr_entries) { | ||||
| 						_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i); | ||||
| 						_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i); | ||||
| 					} | ||||
|         				if (i < n16->nr_entries) { | ||||
| 	        				_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i); | ||||
| 	        				_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i); | ||||
|         				} | ||||
|  | ||||
| 					n16->nr_entries--; | ||||
|         				n16->nr_entries--; | ||||
| 					if (n16->nr_entries <= 4) { | ||||
| 						_degrade_to_n4(n16, root); | ||||
|         					_degrade_to_n4(n16, root); | ||||
| 					} | ||||
| 				} | ||||
| 				return r; | ||||
| @@ -757,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; | ||||
|  | ||||
| @@ -778,7 +767,7 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb | ||||
| 		if (r && n256->values[*kb].type == UNSET) { | ||||
| 			n256->nr_entries--; | ||||
| 			if (n256->nr_entries <= 48) | ||||
| 				_degrade_to_n48(n256, root); | ||||
|         			_degrade_to_n48(n256, root); | ||||
| 		} | ||||
| 		return r; | ||||
| 	} | ||||
| @@ -786,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; | ||||
| @@ -801,25 +787,25 @@ bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen) | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| static bool _prefix_chain_matches(const struct lookup_result *lr, const uint8_t *ke) | ||||
| static bool _prefix_chain_matches(struct lookup_result *lr, uint8_t *ke) | ||||
| { | ||||
| 	// It's possible the top node is a prefix chain, and | ||||
| 	// 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; | ||||
| @@ -840,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; | ||||
| @@ -857,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) { | ||||
| @@ -872,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; | ||||
| @@ -889,19 +875,19 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin | ||||
| 		return true; | ||||
|  | ||||
| 	case NODE16: | ||||
| 		n16 = root->value.ptr; | ||||
|         	n16 = root->value.ptr; | ||||
| 		for (i = 0; i < n16->nr_entries; i++) { | ||||
| 			if (n16->keys[i] == *kb) { | ||||
| 				r = _remove_subtree(rt, n16->values + i, kb + 1, ke, count); | ||||
| 				if (r && n16->values[i].type == UNSET) { | ||||
| 					if (i < n16->nr_entries) { | ||||
| 						_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i); | ||||
| 						_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i); | ||||
| 					} | ||||
|         				if (i < n16->nr_entries) { | ||||
| 	        				_erase_elt(n16->keys, sizeof(*n16->keys), n16->nr_entries, i); | ||||
| 	        				_erase_elt(n16->values, sizeof(*n16->values), n16->nr_entries, i); | ||||
|         				} | ||||
|  | ||||
| 					n16->nr_entries--; | ||||
|         				n16->nr_entries--; | ||||
| 					if (n16->nr_entries <= 4) | ||||
| 						_degrade_to_n4(n16, root); | ||||
|         					_degrade_to_n4(n16, root); | ||||
| 				} | ||||
| 				return r; | ||||
| 			} | ||||
| @@ -912,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; | ||||
|  | ||||
| @@ -936,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; | ||||
| 	} | ||||
| @@ -945,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; | ||||
| @@ -959,11 +943,9 @@ unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, siz | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| bool radix_tree_lookup(struct radix_tree *rt, const void *key, size_t keylen, | ||||
| 		       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) { | ||||
| @@ -986,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; | ||||
| 	} | ||||
|  | ||||
| @@ -1045,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); | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
| @@ -1150,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; | ||||
| 		} | ||||
|  | ||||
| @@ -1186,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; | ||||
| 		} | ||||
|  | ||||
| @@ -1209,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; | ||||
| 	} | ||||
|  | ||||
| @@ -1227,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; | ||||
| @@ -1252,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; | ||||
| @@ -1276,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++) | ||||
| @@ -1287,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++) | ||||
| @@ -1299,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++) { | ||||
| @@ -1313,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 to select the level of validation after metadata transformation. | ||||
| 	# Validation takes extra CPU time to verify internal consistency. | ||||
| 	# Accepted values: | ||||
| 	#   full | ||||
| 	#     Do a full metadata validation before disk write. | ||||
| 	#   none | ||||
| 	#     Skip any checks (unrecommended, slightly faster). | ||||
| 	# | ||||
| 	# This configuration option is advanced. | ||||
| 	# This configuration option has an automatic default value. | ||||
| 	# validate_metadata = "full" | ||||
|  | ||||
| 	# Configuration option config/abort_on_errors. | ||||
| 	# 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. | ||||
| @@ -254,12 +211,17 @@ devices { | ||||
| 	# sysfs_scan = 1 | ||||
|  | ||||
| 	# Configuration option devices/scan_lvs. | ||||
| 	# Allow LVM LVs to be used as PVs. When enabled, LVM commands will | ||||
| 	# scan active LVs to look for other PVs. Caution is required to | ||||
| 	# avoid using PVs that belong to guest images stored on LVs. | ||||
| 	# When enabled, the LVs scanned should be restricted using the | ||||
| 	# devices file or the filter. This option does not enable autoactivation | ||||
| 	# of layered VGs, which requires editing LVM udev rules (see LVM_PVSCAN_ON_LVS.) | ||||
| 	# Scan LVM LVs for layered PVs, allowing LVs to be used as PVs. | ||||
| 	# When 1, LVM will detect PVs layered on LVs, and caution must be | ||||
| 	# taken to avoid a host accessing a layered VG that may not belong | ||||
| 	# to it, e.g. from a guest image. This generally requires excluding | ||||
| 	# the LVs with device filters. Also, when this setting is enabled, | ||||
| 	# every LVM command will scan every active LV on the system (unless | ||||
| 	# filtered), which can cause performance problems on systems with | ||||
| 	# many active LVs. When this setting is 0, LVM will not detect or | ||||
| 	# use PVs that exist on LVs, and will not allow a PV to be created on | ||||
| 	# an LV. The LVs are ignored using a built in device filter that | ||||
| 	# identifies and excludes LVs. | ||||
| 	# This configuration option has an automatic default value. | ||||
| 	# scan_lvs = 0 | ||||
|  | ||||
| @@ -575,7 +537,7 @@ 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. | ||||
|  | ||||
| @@ -586,7 +548,7 @@ allocation { | ||||
|  | ||||
| 	# Configuration option allocation/thin_pool_crop_metadata. | ||||
| 	# Older version of lvm2 cropped pool's metadata size to 15.81 GiB. | ||||
| 	# This is slightly less than the actual maximum 15.88 GiB. | ||||
| 	# This is slightly less then the actual maximum 15.88 GiB. | ||||
| 	# For compatibility with older version and use of cropped size set to 1. | ||||
| 	# This configuration option has an automatic default value. | ||||
| 	# thin_pool_crop_metadata = 0 | ||||
| @@ -659,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 | ||||
|  | ||||
| @@ -681,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. | ||||
| @@ -709,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. | ||||
| @@ -723,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 | ||||
|  | ||||
| @@ -741,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. | ||||
| @@ -757,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, | ||||
| @@ -770,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 | ||||
| } | ||||
| @@ -794,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 | ||||
|  | ||||
| @@ -826,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)" | ||||
|  | ||||
| @@ -953,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@" | ||||
| @@ -1029,7 +1013,7 @@ global { | ||||
| 	# Location of proc filesystem. | ||||
| 	# This configuration option is advanced. | ||||
| 	# This configuration option has an automatic default value. | ||||
| 	# proc = "@DEFAULT_PROC_DIR@" | ||||
| 	# proc = "/proc" | ||||
|  | ||||
| 	# Configuration option global/etc. | ||||
| 	# Location of /etc system configuration directory. | ||||
| @@ -1173,7 +1157,7 @@ global { | ||||
| 	# services (via the lvm2-activation-generator), but the autoactivation | ||||
| 	# services and generator have been removed. | ||||
| 	# 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. | ||||
| @@ -1205,16 +1189,6 @@ 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 | ||||
| @@ -1228,7 +1202,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. | ||||
| @@ -1252,14 +1226,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 | ||||
| @@ -1274,11 +1240,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 | ||||
| @@ -1327,14 +1288,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 | ||||
| @@ -1347,11 +1300,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 | ||||
| @@ -1366,10 +1314,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. | ||||
|  | ||||
| @@ -1379,12 +1327,6 @@ 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, | ||||
| @@ -1405,9 +1347,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. | ||||
| @@ -1523,15 +1464,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 | ||||
|  | ||||
| @@ -1666,7 +1605,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. | ||||
| 	# | ||||
| @@ -1690,7 +1629,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. | ||||
| 	# | ||||
| @@ -1852,7 +1791,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. | ||||
| @@ -1880,7 +1819,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 | ||||
| @@ -1997,14 +1936,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 | ||||
| @@ -2012,13 +1952,6 @@ report { | ||||
| 	#     name for identification. | ||||
| 	#   json | ||||
| 	#     JSON format. | ||||
| 	#   json_std | ||||
| 	#     JSON format that is more compliant with JSON standard. | ||||
| 	#     Compared to original "json" format: | ||||
| 	#       - it does not use double quotes around numeric values, | ||||
| 	#       - it uses 'null' for undefined numeric values, | ||||
| 	#       - it prints string list as proper JSON array of strings instead of a single string. | ||||
| 	# Note that if json or json_std output format is used, then log/command_log_report=1 is default. | ||||
| 	# This configuration option has an automatic default value. | ||||
| 	# output_format = "basic" | ||||
|  | ||||
| @@ -2058,11 +1991,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 | ||||
|  | ||||
| @@ -2141,7 +2070,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 | ||||
| @@ -2412,7 +2341,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 | ||||
| } | ||||
|   | ||||
							
								
								
									
										1608
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										1608
									
								
								configure.ac
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -21,7 +21,7 @@ | ||||
|  * 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'): | ||||
| @@ -30,8 +30,6 @@ | ||||
|  | ||||
| struct lv_segment; | ||||
| struct logical_volume; | ||||
| struct cmd_context; | ||||
| struct profile; | ||||
|  | ||||
| struct lv_segment *first_seg(const struct logical_volume *lv) | ||||
| { | ||||
| @@ -59,7 +57,7 @@ struct logical_volume *origin_from_cow(const struct logical_volume *lv) | ||||
| */ | ||||
|  | ||||
| /* simple_memccpy() from glibc */ | ||||
| void *memccpy(void *dest, const void *src, int c, unsigned long n) | ||||
| void *memccpy(void *dest, const void *src, int c, size_t n) | ||||
| { | ||||
| 	const char *s = src; | ||||
| 	char *d = dest; | ||||
| @@ -72,7 +70,7 @@ void *memccpy(void *dest, const void *src, int c, unsigned long n) | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 2 lines below needs to be placed in coverity/config/user_nodefs.h | ||||
|  * 2 lines bellow needs to be placed in coverity/config/user_nodefs.h | ||||
|  * Not sure about any other way. | ||||
|  * Without them, coverity shows warning since x86 system header files | ||||
|  * are using inline assembly to reset fdset | ||||
| @@ -92,14 +90,9 @@ void model_FD_ZERO(void *fdset) | ||||
| /* Resent Coverity reports quite weird errors... */ | ||||
| int *__errno_location(void) | ||||
| { | ||||
| 	static int _i = 0; | ||||
| 	return &_i; | ||||
| } | ||||
|  | ||||
| const unsigned short **__ctype_b_loc (void) | ||||
| { | ||||
| 	static const unsigned short *_a[1] = { 0 }; | ||||
| 	return _a; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -52,30 +52,20 @@ def filter_event(action, device): | ||||
| 	# when appropriate. | ||||
| 	refresh = False | ||||
|  | ||||
| 	# Ignore everything but change | ||||
| 	if action != 'change': | ||||
| 		return | ||||
|  | ||||
| 	if 'ID_FS_TYPE' in device: | ||||
| 		fs_type_new = device['ID_FS_TYPE'] | ||||
|  | ||||
| 		if 'LVM' in fs_type_new: | ||||
| 			# If we get a lvm related udev event for a block device | ||||
| 			# we don't know about, it's either a pvcreate which we | ||||
| 			# would handle with the dbus notification or something | ||||
| 			# copied a pv signature onto a block device, this is | ||||
| 			# required to catch the latter. | ||||
| 			if not cfg.om.get_object_by_lvm_id(device['DEVNAME']): | ||||
| 				refresh = True | ||||
| 			refresh = True | ||||
| 		elif fs_type_new == '': | ||||
| 			# Check to see if the device was one we knew about | ||||
| 			if 'DEVNAME' in device: | ||||
| 				if cfg.om.get_object_by_lvm_id(device['DEVNAME']): | ||||
| 				found = cfg.om.get_object_by_lvm_id(device['DEVNAME']) | ||||
| 				if found: | ||||
| 					refresh = True | ||||
| 	else: | ||||
| 		# This handles the wipefs -a path | ||||
| 		if not refresh and 'DEVNAME' in device: | ||||
| 			if cfg.om.get_object_by_lvm_id(device['DEVNAME']): | ||||
| 				refresh = True | ||||
|  | ||||
| 	if 'DM_LV_NAME' in device: | ||||
| 		refresh = True | ||||
|  | ||||
| 	if refresh: | ||||
| 		udev_add() | ||||
|   | ||||
| @@ -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@ | ||||
|  | ||||
| SOURCES = lvmlockd-core.c lvmlockd-helper.c | ||||
| SOURCES2 = lvmlockctl.c | ||||
| USE_SD_NOTIFY=yes | ||||
|  | ||||
| TARGETS = lvmlockd lvmlockctl | ||||
|  | ||||
| include $(top_builddir)/make.tmpl | ||||
| SOURCES = lvmlockd-core.c | ||||
|  | ||||
| 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,17 +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 | ||||
|  | ||||
| #define LOCKARGS_VERSION	0x00000001 /* meta only */ | ||||
| #define LOCKARGS_LVMLOCK	0x00000002 /* meta only */ | ||||
| #define LOCKARGS_TIMEOUT        0x00000004 /* user only */ | ||||
| #define LOCKARGS_NOTIMEOUT      0x00000008 /* meta or user */ | ||||
| #define LOCKARGS_PERSIST        0x00000010 /* meta or user */ | ||||
| #define LOCKARGS_NOPERSIST      0x00000020 /* user only */ | ||||
|  | ||||
| #endif	/* _LVM_LVMLOCKD_CLIENT_H */ | ||||
|   | ||||
										
											
												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> | ||||
|  | ||||
| @@ -76,7 +77,7 @@ static int check_args_version(char *vg_args) | ||||
| 	unsigned int major = 0; | ||||
| 	int rv; | ||||
|  | ||||
| 	rv = lockd_lockargs_get_version(vg_args, &major, NULL, NULL); | ||||
| 	rv = version_from_args(vg_args, &major, NULL, NULL); | ||||
| 	if (rv < 0) { | ||||
| 		log_error("check_args_version %s error %d", vg_args, rv); | ||||
| 		return rv; | ||||
| @@ -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, '/'))) | ||||
|   | ||||
| @@ -1,264 +0,0 @@ | ||||
| /* | ||||
|  * Copyright 2025 Red Hat, Inc. | ||||
|  * | ||||
|  * This copyrighted material is made available to anyone wishing to use, | ||||
|  * modify, copy, or redistribute it subject to the terms and conditions | ||||
|  * of the GNU General Public License v2 or (at your option) any later version. | ||||
|  */ | ||||
|  | ||||
| #include <inttypes.h> | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <stddef.h> | ||||
| #include <poll.h> | ||||
| #include <fcntl.h> | ||||
| #include <string.h> | ||||
| #include <errno.h> | ||||
| #include <limits.h> | ||||
| #include <time.h> | ||||
| #include <stdarg.h> | ||||
| #include <signal.h> | ||||
| #include <ctype.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/wait.h> | ||||
| #include <sys/prctl.h> | ||||
| #include <grp.h> | ||||
| #include <syslog.h> | ||||
|  | ||||
| #include "lvmlockd-internal.h" | ||||
|  | ||||
| struct list_head commands; /* helper_msg_list entries */ | ||||
|  | ||||
| static int _log_stderr; | ||||
|  | ||||
| #define log_helper(fmt, args...) \ | ||||
| do { \ | ||||
| 	if (_log_stderr) \ | ||||
| 		fprintf(stderr, fmt "\n", ##args); \ | ||||
| } while (0) | ||||
|  | ||||
| static void _save_command(struct helper_msg *msg) | ||||
| { | ||||
| 	struct helper_msg_list *ml; | ||||
|  | ||||
| 	ml = malloc(sizeof(struct helper_msg_list)); | ||||
| 	if (!ml) | ||||
| 		return; | ||||
|  | ||||
| 	memcpy(&ml->msg, msg, sizeof(struct helper_msg)); | ||||
| 	list_add_tail(&ml->list, &commands); | ||||
| } | ||||
|  | ||||
| static struct helper_msg_list *_get_command(int pid) | ||||
| { | ||||
| 	struct helper_msg_list *ml; | ||||
|  | ||||
| 	list_for_each_entry(ml, &commands, list) { | ||||
| 		if (ml->msg.pid == pid) | ||||
| 			return ml; | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static int read_msg(int fd, struct helper_msg *msg) | ||||
| { | ||||
| 	int rv; | ||||
|  retry: | ||||
| 	rv = read(fd, msg, sizeof(struct helper_msg)); | ||||
| 	if (rv == -1 && errno == EINTR) | ||||
| 		goto retry; | ||||
|  | ||||
| 	if (rv != sizeof(struct helper_msg)) | ||||
| 		return -1; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void exec_command(char *cmd_str) | ||||
| { | ||||
| 	char arg[ONE_ARG_LEN]; | ||||
| 	char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */ | ||||
| 	int av_count = 0; | ||||
| 	int i, arg_len, cmd_len; | ||||
|  | ||||
| 	for (i = 0; i < MAX_AV_COUNT + 1; i++) | ||||
| 		av[i] = NULL; | ||||
|  | ||||
| 	if (!cmd_str[0]) | ||||
| 		return; | ||||
|  | ||||
| 	/* this should already be done, but make sure */ | ||||
| 	cmd_str[RUN_COMMAND_LEN - 1] = '\0'; | ||||
|  | ||||
| 	memset(&arg, 0, sizeof(arg)); | ||||
| 	arg_len = 0; | ||||
| 	cmd_len = strlen(cmd_str); | ||||
|  | ||||
| 	for (i = 0; i < cmd_len; i++) { | ||||
| 		if (!cmd_str[i]) | ||||
| 			break; | ||||
|  | ||||
| 		if (av_count == MAX_AV_COUNT) | ||||
| 			break; | ||||
|  | ||||
| 		if (cmd_str[i] == '\\') { | ||||
| 			if (i == (cmd_len - 1)) | ||||
| 				break; | ||||
| 			i++; | ||||
|  | ||||
| 			if (cmd_str[i] == '\\') { | ||||
| 				arg[arg_len++] = cmd_str[i]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (isspace(cmd_str[i])) { | ||||
| 				arg[arg_len++] = cmd_str[i]; | ||||
| 				continue; | ||||
| 			} else { | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (isalnum(cmd_str[i]) || ispunct(cmd_str[i])) { | ||||
| 			arg[arg_len++] = cmd_str[i]; | ||||
| 		} else if (isspace(cmd_str[i])) { | ||||
| 			if (arg_len) | ||||
| 				av[av_count++] = strdup(arg); | ||||
|  | ||||
| 			memset(arg, 0, sizeof(arg)); | ||||
| 			arg_len = 0; | ||||
| 		} else { | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if ((av_count < MAX_AV_COUNT) && arg_len) { | ||||
| 		av[av_count++] = strdup(arg); | ||||
| 	} | ||||
|  | ||||
| 	execvp(av[0], av); | ||||
| } | ||||
|  | ||||
| static int send_result(struct helper_msg *msg, int fd) | ||||
| { | ||||
| 	int rv; | ||||
|  | ||||
| 	rv = write(fd, msg, sizeof(struct helper_msg)); | ||||
|  | ||||
| 	if (rv == sizeof(struct helper_msg)) | ||||
| 		return 0; | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| #define IDLE_TIMEOUT_MS (30 * 1000) | ||||
| #define ACTIVE_TIMEOUT_MS 500 | ||||
|  | ||||
| __attribute__((noreturn)) void helper_main(int in_fd, int out_fd, int log_stderr) | ||||
| { | ||||
| 	struct pollfd pollfd; | ||||
| 	struct helper_msg msg; | ||||
| 	struct helper_msg_list *ml; | ||||
| 	siginfo_t info; | ||||
| 	unsigned int fork_count = 0; | ||||
| 	unsigned int done_count = 0; | ||||
| 	int timeout = IDLE_TIMEOUT_MS; | ||||
| 	int rv, pid; | ||||
|  | ||||
| 	INIT_LIST_HEAD(&commands); | ||||
|  | ||||
| 	_log_stderr = log_stderr; | ||||
|  | ||||
| 	rv = setgroups(0, NULL); | ||||
| 	if (rv < 0) | ||||
| 		log_helper("error clearing helper groups errno %i", errno); | ||||
|  | ||||
| 	memset(&pollfd, 0, sizeof(pollfd)); | ||||
| 	pollfd.fd = in_fd; | ||||
| 	pollfd.events = POLLIN; | ||||
|  | ||||
| 	openlog("lvmlockd-helper", LOG_CONS | LOG_PID, LOG_LOCAL4); | ||||
|  | ||||
| 	while (1) { | ||||
| 		rv = poll(&pollfd, 1, timeout); | ||||
| 		if (rv == -1 && errno == EINTR) | ||||
| 			continue; | ||||
|  | ||||
| 		if (rv < 0) | ||||
| 			exit(0); | ||||
|  | ||||
| 		if (pollfd.revents & POLLIN) { | ||||
| 			memset(&msg, 0, sizeof(msg)); | ||||
|  | ||||
| 			rv = read_msg(in_fd, &msg); | ||||
| 			if (rv) | ||||
| 				continue; | ||||
|  | ||||
| 			if (msg.type == HELPER_COMMAND) { | ||||
| 				pid = fork(); | ||||
| 				if (!pid) { | ||||
| 					exec_command(msg.command); | ||||
| 					exit(1); | ||||
| 				} | ||||
|  | ||||
| 				msg.pid = pid; | ||||
|  | ||||
| 				_save_command(&msg); | ||||
|  | ||||
| 				fork_count++; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL)) | ||||
| 			exit(0); | ||||
|  | ||||
| 		/* collect child exits until no more children exist (ECHILD) | ||||
| 		   or none are ready (WNOHANG) */ | ||||
|  | ||||
| 		while (1) { | ||||
| 			memset(&info, 0, sizeof(info)); | ||||
|  | ||||
| 			rv = waitid(P_ALL, 0, &info, WEXITED | WNOHANG); | ||||
|  | ||||
| 			if ((rv < 0) && (errno == ECHILD)) { | ||||
| 				/* | ||||
| 				log_helper("helper no children exist fork_count %d done_count %d", fork_count, done_count); | ||||
| 				*/ | ||||
| 				timeout = IDLE_TIMEOUT_MS; | ||||
| 			} | ||||
|  | ||||
| 			else if (!rv && !info.si_pid) { | ||||
| 				log_helper("helper no children ready fork_count %d done_count %d", fork_count, done_count); | ||||
| 				timeout = ACTIVE_TIMEOUT_MS; | ||||
| 			} | ||||
|  | ||||
| 			else if (!rv && info.si_pid) { | ||||
| 				done_count++; | ||||
|  | ||||
| 				if (!(ml = _get_command(info.si_pid))) { | ||||
| 					log_helper("command for pid %d result %d not found", | ||||
| 						  info.si_pid, info.si_status); | ||||
| 					continue; | ||||
| 				} | ||||
|  | ||||
| 				log_helper("command for pid %d result %d done", info.si_pid, info.si_status); | ||||
|  | ||||
| 				ml->msg.type = HELPER_COMMAND_RESULT; | ||||
| 				ml->msg.result = info.si_status; | ||||
|  | ||||
| 				send_result(&ml->msg, out_fd); | ||||
|  | ||||
| 				list_del(&ml->list); | ||||
| 				free(ml); | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			else { | ||||
| 				log_helper("helper waitid rv %d errno %d fork_count %d done_count %d", | ||||
| 					  rv, errno, fork_count, done_count); | ||||
| 			} | ||||
|  | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -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,11 +59,6 @@ enum { | ||||
| 	LD_OP_BUSY, | ||||
| 	LD_OP_QUERY_LOCK, | ||||
| 	LD_OP_REFRESH_LV, | ||||
| 	LD_OP_VG_STATUS, | ||||
| 	LD_OP_FENCE, | ||||
| 	LD_OP_FENCE_RESULT, | ||||
| 	LD_OP_SETLOCKARGS_BEFORE, | ||||
| 	LD_OP_SETLOCKARGS_FINAL, | ||||
| }; | ||||
|  | ||||
| /* resource types */ | ||||
| @@ -115,15 +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 | ||||
| #define LD_AF_NO_TIMEOUT	   0x01000000 | ||||
|  | ||||
| /* | ||||
|  * Number of times to repeat a lock request after | ||||
| @@ -137,54 +125,12 @@ struct pvs { | ||||
| 	int num; | ||||
| }; | ||||
|  | ||||
| #define RUN_COMMAND_LEN 1024 | ||||
| #define MAX_AV_COUNT 32 | ||||
| #define ONE_ARG_LEN 256 | ||||
|  | ||||
| /* helper_msg types */ | ||||
| #define HELPER_COMMAND 0x1 | ||||
| #define HELPER_COMMAND_RESULT 0x2 | ||||
|  | ||||
| struct helper_msg { | ||||
| 	uint8_t  type; | ||||
| 	uint8_t  act; | ||||
| 	uint16_t unused1; | ||||
| 	uint32_t msg_id; | ||||
| 	int pid; | ||||
| 	int result; | ||||
| 	char ls_name[MAX_NAME+1]; | ||||
| 	uint8_t unused2; | ||||
| 	uint16_t unused3; | ||||
| 	char command[RUN_COMMAND_LEN]; | ||||
| }; | ||||
|  | ||||
| struct helper_msg_list { | ||||
| 	struct helper_msg msg; | ||||
| 	struct list_head list; | ||||
| }; | ||||
|  | ||||
| #define OWNER_NAME_SIZE 64 | ||||
| #define OWNER_STATE_SIZE 32 | ||||
|  | ||||
| struct owner { | ||||
| 	uint32_t host_id; | ||||
| 	uint32_t generation; | ||||
| 	uint32_t timestamp; | ||||
| 	char state[OWNER_STATE_SIZE]; | ||||
| 	char name[OWNER_NAME_SIZE]; | ||||
| }; | ||||
|  | ||||
| struct action { | ||||
| 	struct list_head list; | ||||
| 	uint32_t client_id; | ||||
| 	uint32_t flags;			/* LD_AF_ */ | ||||
| 	uint32_t msg_id; | ||||
| 	uint32_t version; | ||||
| 	uint32_t host_id; | ||||
| 	uint64_t ourkey; | ||||
| 	uint64_t remkey; | ||||
| 	uint64_t lv_size_bytes; | ||||
| 	uint64_t ls_generation; | ||||
| 	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_ */ | ||||
| @@ -193,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]; | ||||
| @@ -201,8 +146,7 @@ struct action { | ||||
| 	char lv_uuid[MAX_NAME+1]; | ||||
| 	char vg_args[MAX_ARGS+1]; | ||||
| 	char lv_args[MAX_ARGS+1]; | ||||
| 	char other_args[MAX_ARGS+1]; | ||||
| 	struct owner owner; | ||||
| 	char vg_sysid[MAX_NAME+1]; | ||||
| 	struct pvs pvs;			/* PV list for idm */ | ||||
| }; | ||||
|  | ||||
| @@ -215,14 +159,12 @@ 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; | ||||
| 	unsigned int use_vb : 1; | ||||
| 	struct list_head locks; | ||||
| 	struct list_head actions; | ||||
| 	struct list_head fence_wait_actions; | ||||
| 	char lv_args[MAX_ARGS+1]; | ||||
| 	char lm_data[];			/* lock manager specific data */ | ||||
| }; | ||||
| @@ -243,13 +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 lock_args_flags; | ||||
| 	uint32_t host_id; | ||||
| 	uint64_t generation; | ||||
| 	uint64_t ourkey; | ||||
| 	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 */ | ||||
| @@ -263,14 +205,12 @@ struct lockspace { | ||||
| 	unsigned int thread_done : 1; | ||||
| 	unsigned int sanlock_gl_enabled: 1; | ||||
| 	unsigned int sanlock_gl_dup: 1; | ||||
| 	unsigned int free_vg: 1; | ||||
| 	unsigned int kill_vg: 1; | ||||
| 	unsigned int fence_pr: 1; | ||||
| 	unsigned int no_timeout: 1; | ||||
| 	unsigned int drop_vg: 1; | ||||
|  | ||||
| 	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 */ | ||||
| 	struct list_head fence_history;	/* internally created actions for fencing */ | ||||
| }; | ||||
|  | ||||
| /* val_blk version */ | ||||
| @@ -337,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 */ | ||||
| @@ -423,15 +363,11 @@ void log_level(int level, const char *fmt, ...)  __attribute__((format(printf, 2 | ||||
| #define log_debug(fmt, args...) log_level(LOG_DEBUG, fmt, ##args) | ||||
| #define log_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); | ||||
| int last_string_from_args(char *args_in, char *last); | ||||
| void helper_main(int in_fd, int out_fd, int log_stderr); | ||||
| int lockd_lockargs_get_user_flags(const char *str, uint32_t *flags); | ||||
| int lockd_lockargs_get_version(char *str, unsigned int *major, unsigned int *minor, unsigned int *patch); | ||||
| int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsigned int *patch); | ||||
|  | ||||
| static inline const char *mode_str(int x) | ||||
| { | ||||
| @@ -455,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, | ||||
| @@ -482,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; | ||||
| } | ||||
|  | ||||
| @@ -600,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, char *other_args); | ||||
| int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args); | ||||
| int lm_init_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, | ||||
| @@ -623,11 +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); | ||||
| void lm_set_host_dead_sanlock(struct lockspace *ls, struct owner *owner); | ||||
| int lm_setlockargs_supported_sanlock(struct lockspace *ls, struct action *act); | ||||
| int lm_setlockargs_vg_sanlock(char *ls_name, char *vg_name, struct action *act); | ||||
| 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) | ||||
| { | ||||
| @@ -636,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, char *other_args) | ||||
| 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; | ||||
| } | ||||
| @@ -656,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; | ||||
| } | ||||
| @@ -671,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; | ||||
| } | ||||
| @@ -735,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; | ||||
| } | ||||
| @@ -750,20 +629,6 @@ static inline int lm_support_sanlock(void) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static inline void lm_set_host_dead_sanlock(struct lockspace *ls, struct owner *owner) | ||||
| { | ||||
| } | ||||
|  | ||||
| static inline int lm_setlockargs_supported_sanlock(struct lockspace *ls, struct action *act) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static inline int lm_setlockargs_vg_sanlock(char *ls_name, char *vg_name, struct action *act) | ||||
| { | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| #endif /* sanlock support */ | ||||
|  | ||||
| #ifdef LOCKDIDM_SUPPORT | ||||
| @@ -771,12 +636,11 @@ static inline int lm_setlockargs_vg_sanlock(char *ls_name, char *vg_name, struct | ||||
| 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, | ||||
| @@ -809,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; | ||||
| } | ||||
| @@ -819,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]; | ||||
| }; | ||||
|   | ||||
| @@ -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; | ||||
| @@ -1061,8 +1060,9 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor, | ||||
| 		if (info.st_rdev == dev) | ||||
| 			return 1; | ||||
|  | ||||
| 		if (unlink(path) && (errno != ENOENT)) { | ||||
| 			log_sys_error("unlink", path); | ||||
| 		if (unlink(path) < 0) { | ||||
| 			log_error("Unable to unlink device node for '%s'", | ||||
| 				  dev_name); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} else if (_warn_if_op_needed(warn_if_udev_failed)) | ||||
| @@ -1106,8 +1106,8 @@ static int _rm_dev_node(const char *dev_name, int warn_if_udev_failed) | ||||
| 			 "Falling back to direct node removal.", path); | ||||
|  | ||||
| 	/* udev may already have deleted the node. Ignore ENOENT. */ | ||||
| 	if (unlink(path) && (errno != ENOENT)) { | ||||
| 		log_sys_error("unlink", path); | ||||
| 	if (unlink(path) < 0 && errno != ENOENT) { | ||||
| 		log_error("Unable to unlink device node for '%s'", dev_name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| @@ -1451,10 +1451,9 @@ struct node_op_parms { | ||||
|  | ||||
| static void _store_str(char **pos, char **ptr, const char *str) | ||||
| { | ||||
| 	size_t len = strlen(str) + 1; | ||||
| 	memcpy(*pos, str, len); | ||||
| 	strcpy(*pos, str); | ||||
| 	*ptr = *pos; | ||||
| 	*pos += len; | ||||
| 	*pos += strlen(*ptr) + 1; | ||||
| } | ||||
|  | ||||
| static void _del_node_op(struct node_op_parms *nop) | ||||
| @@ -1704,17 +1703,15 @@ const char *dm_sysfs_dir(void) | ||||
|  */ | ||||
| int dm_set_uuid_prefix(const char *uuid_prefix) | ||||
| { | ||||
| 	size_t len; | ||||
|  | ||||
| 	if (!uuid_prefix) | ||||
| 		return_0; | ||||
|  | ||||
| 	if ((len = strlen(uuid_prefix)) > DM_MAX_UUID_PREFIX_LEN) { | ||||
| 	if (strlen(uuid_prefix) > DM_MAX_UUID_PREFIX_LEN) { | ||||
| 		log_error("New uuid prefix %s too long.", uuid_prefix); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	memcpy(_default_uuid_prefix, uuid_prefix, len + 1); | ||||
| 	strcpy(_default_uuid_prefix, uuid_prefix); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| @@ -1743,9 +1740,6 @@ static void _unmangle_mountinfo_string(const char *src, char *buf) | ||||
| 	*buf = '\0'; | ||||
| } | ||||
|  | ||||
| /* coverity[+tainted_string_sanitize_content:arg-0] */ | ||||
| static int _sanitize_line(const char *line) { return 1; } | ||||
|  | ||||
| /* Parse one line of mountinfo and unmangled target line */ | ||||
| static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min, char *buf) | ||||
| { | ||||
| @@ -1796,7 +1790,7 @@ static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min, | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Function to operate on individual mountinfo line, | ||||
|  * Function to operate on individal mountinfo line, | ||||
|  * minor, major and mount target are parsed and unmangled | ||||
|  */ | ||||
| int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data) | ||||
| @@ -1816,8 +1810,7 @@ int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data) | ||||
| 	} | ||||
|  | ||||
| 	while (!feof(minfo) && fgets(buffer, sizeof(buffer), minfo)) | ||||
| 		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; | ||||
| @@ -1832,27 +1825,32 @@ int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data) | ||||
|  | ||||
| static int _sysfs_get_dm_name(uint32_t major, uint32_t minor, char *buf, size_t buf_size) | ||||
| { | ||||
| 	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; | ||||
| 	} | ||||
| @@ -1860,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; | ||||
| } | ||||
|  | ||||
| @@ -1957,7 +1954,7 @@ static int _sysfs_find_kernel_name(uint32_t major, uint32_t minor, char *buf, si | ||||
| 				    !strcmp(name_dev, "holders") || | ||||
| 				    !strcmp(name_dev, "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") || | ||||
| @@ -2314,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; | ||||
| 	} | ||||
|  | ||||
| @@ -2337,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); | ||||
| @@ -2412,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; | ||||
| @@ -2433,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; | ||||
| } | ||||
| @@ -2456,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; | ||||
| @@ -2478,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; | ||||
| } | ||||
|  | ||||
| @@ -2560,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); | ||||
| @@ -2568,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: | ||||
| @@ -3383,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; | ||||
|  | ||||
| @@ -3533,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! | ||||
| @@ -3599,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; | ||||
| @@ -3819,7 +3658,7 @@ int dm_tree_node_add_raid_target(struct dm_tree_node *node, | ||||
|  * - maximum 253 legs in a raid set (MD kernel limitation) | ||||
|  * - 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, | ||||
| @@ -3870,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; | ||||
| @@ -3882,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 */ | ||||
| @@ -4083,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; | ||||
| } | ||||
|  | ||||
| @@ -4370,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; | ||||
| } | ||||
|  | ||||
| @@ -4490,7 +4323,6 @@ void dm_tree_node_set_callback(struct dm_tree_node *dnode, | ||||
|  | ||||
| int dm_tree_node_add_vdo_target(struct dm_tree_node *node, | ||||
| 				uint64_t size, | ||||
| 				uint32_t vdo_version, | ||||
| 				const char *vdo_pool_name, | ||||
| 				const char *data_uuid, | ||||
| 				uint64_t data_size, | ||||
| @@ -4512,13 +4344,11 @@ int dm_tree_node_add_vdo_target(struct dm_tree_node *node, | ||||
| 	if (!_link_tree_nodes(node, seg->vdo_data)) | ||||
| 		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 { | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user