mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-11-03 08:23:48 +03:00 
			
		
		
		
	Compare commits
	
		
			233 Commits
		
	
	
		
			dev-dct-wr
			...
			dev-dct-st
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f15564d18e | ||
| 
						 | 
					4a3e1ac740 | ||
| 
						 | 
					f39141ebc1 | ||
| 
						 | 
					5ddd1ead2d | ||
| 
						 | 
					b387d026bd | ||
| 
						 | 
					a178ad0858 | ||
| 
						 | 
					7550665ba4 | ||
| 
						 | 
					3d980172b0 | ||
| 
						 | 
					e3c8cebd87 | ||
| 
						 | 
					2f846697fc | ||
| 
						 | 
					cff9bff0af | ||
| 
						 | 
					143aca25da | ||
| 
						 | 
					1e9c409a3e | ||
| 
						 | 
					e1cc409ae6 | ||
| 
						 | 
					721a172edf | ||
| 
						 | 
					23478d9d21 | ||
| 
						 | 
					b0e1019add | ||
| 
						 | 
					9aedf68c32 | ||
| 
						 | 
					ea036ecfd3 | ||
| 
						 | 
					1650c10438 | ||
| 
						 | 
					b13ebfa4c2 | ||
| 
						 | 
					b62c0787de | ||
| 
						 | 
					ff2bf11360 | ||
| 
						 | 
					7232458b6c | ||
| 
						 | 
					8bea252a63 | ||
| 
						 | 
					66665f5e42 | ||
| 
						 | 
					5cf1c61152 | ||
| 
						 | 
					2cd6cd3439 | ||
| 
						 | 
					82e7426028 | ||
| 
						 | 
					862899cc88 | ||
| 
						 | 
					09aafb61e3 | ||
| 
						 | 
					3b42cdad0c | ||
| 
						 | 
					49813abc00 | ||
| 
						 | 
					788d89c412 | ||
| 
						 | 
					e0a176f49a | ||
| 
						 | 
					24186cd9ce | ||
| 
						 | 
					2806e6265f | ||
| 
						 | 
					02a5921cdb | ||
| 
						 | 
					b61c89b52b | ||
| 
						 | 
					78c937552a | ||
| 
						 | 
					a311684c4a | ||
| 
						 | 
					f3a87a2c2e | ||
| 
						 | 
					1727df7c98 | ||
| 
						 | 
					29ae8b8ca5 | ||
| 
						 | 
					e80ca65d30 | ||
| 
						 | 
					d6bce03615 | ||
| 
						 | 
					8623e33651 | ||
| 
						 | 
					c31e6b0aca | ||
| 
						 | 
					cb7766bc14 | ||
| 
						 | 
					1308572a87 | ||
| 
						 | 
					adf9bf80a3 | ||
| 
						 | 
					f633d68c54 | ||
| 
						 | 
					c733e96445 | ||
| 
						 | 
					3669c33af4 | ||
| 
						 | 
					e2ae1f2d71 | ||
| 
						 | 
					3aeff09bd7 | ||
| 
						 | 
					d5a5792b30 | ||
| 
						 | 
					a397b69ce3 | ||
| 
						 | 
					a8921be641 | ||
| 
						 | 
					9d7afaaab8 | ||
| 
						 | 
					71b9cb8e0f | ||
| 
						 | 
					057d866889 | ||
| 
						 | 
					e79e092f8b | ||
| 
						 | 
					4729b4af0b | ||
| 
						 | 
					f3be66c002 | ||
| 
						 | 
					2047d405af | ||
| 
						 | 
					1370277ea7 | ||
| 
						 | 
					f38cfd09c4 | ||
| 
						 | 
					515867bbad | ||
| 
						 | 
					bcf1aa99e6 | ||
| 
						 | 
					b41b112a4b | ||
| 
						 | 
					559cf0cd1e | ||
| 
						 | 
					228e331e27 | ||
| 
						 | 
					3ead62e24b | ||
| 
						 | 
					fa025cdd9a | ||
| 
						 | 
					f5d1f4f086 | ||
| 
						 | 
					699bf86090 | ||
| 
						 | 
					03d6cfdd99 | ||
| 
						 | 
					6064b9f1b2 | ||
| 
						 | 
					6d4f36c2c7 | ||
| 
						 | 
					63289b54c7 | ||
| 
						 | 
					0a726a7e26 | ||
| 
						 | 
					b79f1e176f | ||
| 
						 | 
					81d954df4e | ||
| 
						 | 
					7cbee7e9cf | ||
| 
						 | 
					717957ddc5 | ||
| 
						 | 
					9b04851fc5 | ||
| 
						 | 
					dcf8f3111a | ||
| 
						 | 
					ece0b131e5 | ||
| 
						 | 
					519f4453a5 | ||
| 
						 | 
					bc6ae7030a | ||
| 
						 | 
					167aa34926 | ||
| 
						 | 
					8fc64c5ee6 | ||
| 
						 | 
					8d44cd3e47 | ||
| 
						 | 
					40f57155a3 | ||
| 
						 | 
					1bef4dfab3 | ||
| 
						 | 
					e974f6866a | ||
| 
						 | 
					a93699ece9 | ||
| 
						 | 
					e4bb94a93e | ||
| 
						 | 
					93ac80037a | ||
| 
						 | 
					c9e5e6800c | ||
| 
						 | 
					f0f68791f3 | ||
| 
						 | 
					b39c26ddc3 | ||
| 
						 | 
					d1ae1455b4 | ||
| 
						 | 
					c115d92287 | ||
| 
						 | 
					ece117ee10 | ||
| 
						 | 
					590a1ebcf7 | ||
| 
						 | 
					863a2e693e | ||
| 
						 | 
					8dbfdb5b73 | ||
| 
						 | 
					675b94a11b | ||
| 
						 | 
					850e95f24a | ||
| 
						 | 
					083f162e8e | ||
| 
						 | 
					7f56908c2b | ||
| 
						 | 
					427e8ba3e3 | ||
| 
						 | 
					6a5575e959 | ||
| 
						 | 
					57cde6063f | ||
| 
						 | 
					d0cb672466 | ||
| 
						 | 
					75886f59e4 | ||
| 
						 | 
					1d2de5dd13 | ||
| 
						 | 
					df0797db8c | ||
| 
						 | 
					2d077286b9 | ||
| 
						 | 
					f5ea02ffee | ||
| 
						 | 
					262a42025f | ||
| 
						 | 
					d5234e1b7e | ||
| 
						 | 
					a188b1e513 | ||
| 
						 | 
					9764ee0b3f | ||
| 
						 | 
					322d4ed05e | ||
| 
						 | 
					a01e1fec0f | ||
| 
						 | 
					0e42ebd6d4 | ||
| 
						 | 
					fe1cabfa34 | ||
| 
						 | 
					cb5405ded8 | ||
| 
						 | 
					f8ce9bf3bc | ||
| 
						 | 
					9fda169077 | ||
| 
						 | 
					9799c8da07 | ||
| 
						 | 
					613466aa8f | ||
| 
						 | 
					813a83b2d6 | ||
| 
						 | 
					fa8d5e4e81 | ||
| 
						 | 
					b93aded021 | ||
| 
						 | 
					efa281685a | ||
| 
						 | 
					ab27d5dc2a | ||
| 
						 | 
					bd872064a2 | ||
| 
						 | 
					d1b652143a | ||
| 
						 | 
					e7bb508809 | ||
| 
						 | 
					de2863739f | ||
| 
						 | 
					c26bde42af | ||
| 
						 | 
					0e03c68619 | ||
| 
						 | 
					3374a59250 | ||
| 
						 | 
					6afb911252 | ||
| 
						 | 
					a8d59404f7 | ||
| 
						 | 
					a1a89a453f | ||
| 
						 | 
					ed749cdb5b | ||
| 
						 | 
					5502f72e41 | ||
| 
						 | 
					c527a0cbfc | ||
| 
						 | 
					63d4983890 | ||
| 
						 | 
					a991664dec | ||
| 
						 | 
					ab1aa0a4fb | ||
| 
						 | 
					d910f75d89 | ||
| 
						 | 
					94362423c4 | ||
| 
						 | 
					acf40f5587 | ||
| 
						 | 
					227a0d7336 | ||
| 
						 | 
					a41968c4b4 | ||
| 
						 | 
					672b8c196b | ||
| 
						 | 
					cc96eea029 | ||
| 
						 | 
					5f648406b0 | ||
| 
						 | 
					3ebc745f53 | ||
| 
						 | 
					acd2c6f256 | ||
| 
						 | 
					b10b462fde | ||
| 
						 | 
					a75eb8d74c | ||
| 
						 | 
					0569add94c | ||
| 
						 | 
					12dfd0ed02 | ||
| 
						 | 
					ad10d42671 | ||
| 
						 | 
					f7645995da | ||
| 
						 | 
					4ed9b07380 | ||
| 
						 | 
					0174ba692c | ||
| 
						 | 
					48594d007a | ||
| 
						 | 
					50a603de6f | ||
| 
						 | 
					e4fe0d1b8f | ||
| 
						 | 
					951676a59e | ||
| 
						 | 
					4456d9aa77 | ||
| 
						 | 
					b394a9f63f | ||
| 
						 | 
					9e296c9c6f | ||
| 
						 | 
					5b87f5fb72 | ||
| 
						 | 
					bb384f8488 | ||
| 
						 | 
					82feb5f111 | ||
| 
						 | 
					66990bc7c8 | ||
| 
						 | 
					6fcb2ba440 | ||
| 
						 | 
					b8a7f6ba3d | ||
| 
						 | 
					0851ee5301 | ||
| 
						 | 
					df8eef7096 | ||
| 
						 | 
					c1dbb22ba4 | ||
| 
						 | 
					99cddd67a9 | ||
| 
						 | 
					814dd84e07 | ||
| 
						 | 
					d5bcc56eef | ||
| 
						 | 
					f7ffba204e | ||
| 
						 | 
					90e419c645 | ||
| 
						 | 
					49147cbaa7 | ||
| 
						 | 
					69907e0780 | ||
| 
						 | 
					b90d4b38e5 | ||
| 
						 | 
					befdfc245b | ||
| 
						 | 
					0d78e4c1e9 | ||
| 
						 | 
					763c65314e | ||
| 
						 | 
					24aee732a5 | ||
| 
						 | 
					ba6ed5c90c | ||
| 
						 | 
					e0c94d883a | ||
| 
						 | 
					39e3b5d8ac | ||
| 
						 | 
					39fc98d731 | ||
| 
						 | 
					5503699c37 | ||
| 
						 | 
					e0bfc946cb | ||
| 
						 | 
					9546edeef9 | ||
| 
						 | 
					716199334c | ||
| 
						 | 
					4479228d32 | ||
| 
						 | 
					4afb5971b9 | ||
| 
						 | 
					dd075e93c1 | ||
| 
						 | 
					d4fd39f64c | ||
| 
						 | 
					acb784e2a8 | ||
| 
						 | 
					8a0af1bec8 | ||
| 
						 | 
					8bd9a89c14 | ||
| 
						 | 
					a30e622279 | ||
| 
						 | 
					76075ff55d | ||
| 
						 | 
					bfb904af1c | ||
| 
						 | 
					d88376ca78 | ||
| 
						 | 
					6283f5ea3f | ||
| 
						 | 
					43ce357ebc | ||
| 
						 | 
					d136790bab | ||
| 
						 | 
					214de62b5d | ||
| 
						 | 
					e9c0a64fb5 | ||
| 
						 | 
					7ac8e21f3c | ||
| 
						 | 
					fdb362b998 | ||
| 
						 | 
					06accf1395 | ||
| 
						 | 
					d3dcca639c | ||
| 
						 | 
					98eb9e5754 | ||
| 
						 | 
					347c807f86 | ||
| 
						 | 
					1e5f6887b1 | 
							
								
								
									
										15
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -25,29 +25,17 @@ make.tmpl
 | 
			
		||||
 | 
			
		||||
/autom4te.cache/
 | 
			
		||||
/autoscan.log
 | 
			
		||||
/build/
 | 
			
		||||
/config.cache
 | 
			
		||||
/config.log
 | 
			
		||||
/config.status
 | 
			
		||||
/configure.scan
 | 
			
		||||
/cscope.*
 | 
			
		||||
/html/
 | 
			
		||||
/reports/
 | 
			
		||||
/cscope.out
 | 
			
		||||
/tags
 | 
			
		||||
/tmp/
 | 
			
		||||
 | 
			
		||||
coverity/coverity_model.xml
 | 
			
		||||
 | 
			
		||||
# gcov files:
 | 
			
		||||
*.gcda
 | 
			
		||||
*.gcno
 | 
			
		||||
 | 
			
		||||
tools/man-generator
 | 
			
		||||
tools/man-generator.c
 | 
			
		||||
 | 
			
		||||
test/.lib-dir-stamp
 | 
			
		||||
test/.tests-stamp
 | 
			
		||||
test/lib/dmsecuretest
 | 
			
		||||
test/lib/lvchange
 | 
			
		||||
test/lib/lvconvert
 | 
			
		||||
test/lib/lvcreate
 | 
			
		||||
@@ -72,7 +60,6 @@ test/lib/pvremove
 | 
			
		||||
test/lib/pvresize
 | 
			
		||||
test/lib/pvs
 | 
			
		||||
test/lib/pvscan
 | 
			
		||||
test/lib/securetest
 | 
			
		||||
test/lib/vgcfgbackup
 | 
			
		||||
test/lib/vgcfgrestore
 | 
			
		||||
test/lib/vgchange
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										78
									
								
								Makefile.in
									
									
									
									
									
								
							
							
						
						
									
										78
									
								
								Makefile.in
									
									
									
									
									
								
							@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
 | 
			
		||||
abs_top_builddir = @abs_top_builddir@
 | 
			
		||||
abs_top_srcdir = @abs_top_srcdir@
 | 
			
		||||
 | 
			
		||||
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
 | 
			
		||||
SUBDIRS = conf daemons include lib libdaemon libdm man scripts device_mapper tools
 | 
			
		||||
 | 
			
		||||
ifeq ("@UDEV_RULES@", "yes")
 | 
			
		||||
  SUBDIRS += udev
 | 
			
		||||
@@ -28,6 +28,14 @@ ifeq ("@INTL@", "yes")
 | 
			
		||||
  SUBDIRS += po
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@APPLIB@", "yes")
 | 
			
		||||
  SUBDIRS += liblvm
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@PYTHON_BINDINGS@", "yes")
 | 
			
		||||
  SUBDIRS += python
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ($(MAKECMDGOALS),clean)
 | 
			
		||||
  SUBDIRS += test
 | 
			
		||||
endif
 | 
			
		||||
@@ -35,7 +43,7 @@ endif
 | 
			
		||||
ifeq ($(MAKECMDGOALS),distclean)
 | 
			
		||||
  SUBDIRS = conf include man test scripts \
 | 
			
		||||
    libdaemon lib tools daemons libdm \
 | 
			
		||||
    udev po
 | 
			
		||||
    udev po liblvm python device_mapper
 | 
			
		||||
tools.distclean: test.distclean
 | 
			
		||||
endif
 | 
			
		||||
DISTCLEAN_DIRS += lcov_reports*
 | 
			
		||||
@@ -43,25 +51,23 @@ DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
 | 
			
		||||
 | 
			
		||||
include make.tmpl
 | 
			
		||||
 | 
			
		||||
include $(top_srcdir)/base/Makefile
 | 
			
		||||
include $(top_srcdir)/device_mapper/Makefile
 | 
			
		||||
include $(top_srcdir)/test/unit/Makefile
 | 
			
		||||
 | 
			
		||||
libdm: include
 | 
			
		||||
libdaemon: include
 | 
			
		||||
lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
 | 
			
		||||
lib: libdm libdaemon
 | 
			
		||||
liblvm: lib
 | 
			
		||||
daemons: lib libdaemon tools
 | 
			
		||||
scripts: lib
 | 
			
		||||
tools: lib libdaemon
 | 
			
		||||
tools: lib libdaemon device-mapper
 | 
			
		||||
po: tools daemons
 | 
			
		||||
man: tools
 | 
			
		||||
all_man: tools
 | 
			
		||||
scripts: libdm
 | 
			
		||||
scripts: liblvm libdm
 | 
			
		||||
test: tools daemons
 | 
			
		||||
unit-test  run-unit-test: test
 | 
			
		||||
unit-test: lib
 | 
			
		||||
run-unit-test: unit-test
 | 
			
		||||
 | 
			
		||||
lib.device-mapper: include.device-mapper
 | 
			
		||||
libdm.device-mapper: include.device-mapper
 | 
			
		||||
liblvm.device-mapper: include.device-mapper
 | 
			
		||||
daemons.device-mapper: libdm.device-mapper
 | 
			
		||||
tools.device-mapper: libdm.device-mapper
 | 
			
		||||
scripts.device-mapper: include.device-mapper
 | 
			
		||||
@@ -75,6 +81,10 @@ po.pofile: tools.pofile daemons.pofile
 | 
			
		||||
pofile: po.pofile
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@PYTHON_BINDINGS@", "yes")
 | 
			
		||||
python: liblvm
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq ("$(CFLOW_CMD)", "")
 | 
			
		||||
tools.cflow: libdm.cflow lib.cflow
 | 
			
		||||
daemons.cflow: tools.cflow
 | 
			
		||||
@@ -89,7 +99,7 @@ endif
 | 
			
		||||
DISTCLEAN_TARGETS += cscope.out
 | 
			
		||||
CLEAN_DIRS += autom4te.cache
 | 
			
		||||
 | 
			
		||||
check check_system check_cluster check_local check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock: test
 | 
			
		||||
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit-test run-unit-test: test
 | 
			
		||||
	$(MAKE) -C test $(@)
 | 
			
		||||
 | 
			
		||||
conf.generate man.generate: tools
 | 
			
		||||
@@ -151,11 +161,27 @@ install_systemd_units:
 | 
			
		||||
install_all_man:
 | 
			
		||||
	$(MAKE) -C man install_all_man
 | 
			
		||||
 | 
			
		||||
ifeq ("@PYTHON_BINDINGS@", "yes")
 | 
			
		||||
install_python_bindings:
 | 
			
		||||
	$(MAKE) -C liblvm/python install_python_bindings
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
install_tmpfiles_configuration:
 | 
			
		||||
	$(MAKE) -C scripts install_tmpfiles_configuration
 | 
			
		||||
 | 
			
		||||
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
 | 
			
		||||
	libdaemon/client.info libdaemon/server.info \
 | 
			
		||||
	test/unit.info \
 | 
			
		||||
	daemons/clvmd.info \
 | 
			
		||||
	daemons/dmeventd.info \
 | 
			
		||||
	daemons/lvmetad.info \
 | 
			
		||||
	daemons/lvmlockd.info \
 | 
			
		||||
	daemons/lvmpolld.info
 | 
			
		||||
 | 
			
		||||
CLEAN_TARGETS += $(LCOV_TRACES)
 | 
			
		||||
 | 
			
		||||
ifneq ("$(LCOV)", "")
 | 
			
		||||
.PHONY: lcov-reset lcov lcov-dated
 | 
			
		||||
.PHONY: lcov-reset lcov lcov-dated $(LCOV_TRACES)
 | 
			
		||||
 | 
			
		||||
ifeq ($(MAKECMDGOALS),lcov-dated)
 | 
			
		||||
LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S)
 | 
			
		||||
@@ -165,22 +191,30 @@ LCOV_REPORTS_DIR := lcov_reports
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
lcov-reset:
 | 
			
		||||
	$(LCOV) --zerocounters --directory $(top_builddir)
 | 
			
		||||
	$(LCOV) --zerocounters $(addprefix -d , $(basename $(LCOV_TRACES)))
 | 
			
		||||
 | 
			
		||||
# maybe use subdirs processing to create tracefiles...
 | 
			
		||||
$(LCOV_TRACES):
 | 
			
		||||
	$(LCOV) -b $(basename $@) -d $(basename $@) \
 | 
			
		||||
		--ignore-errors source -c -o - | $(SED) \
 | 
			
		||||
		-e "s/\(dmeventd_lvm.[ch]\)/plugins\/lvm2\/\1/" \
 | 
			
		||||
		-e "s/dmeventd_\(mirror\|snapshot\|thin\|raid\)\.c/plugins\/\1\/dmeventd_\1\.c/" \
 | 
			
		||||
		>$@
 | 
			
		||||
 | 
			
		||||
ifneq ("$(GENHTML)", "")
 | 
			
		||||
lcov:
 | 
			
		||||
	$(RM) -rf $(LCOV_REPORTS_DIR)
 | 
			
		||||
lcov: $(LCOV_TRACES)
 | 
			
		||||
	$(RM) -r $(LCOV_REPORTS_DIR)
 | 
			
		||||
	$(MKDIR_P) $(LCOV_REPORTS_DIR)
 | 
			
		||||
	$(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 \
 | 
			
		||||
		$(LCOV_REPORTS_DIR)/out.info
 | 
			
		||||
	for i in $(LCOV_TRACES); do \
 | 
			
		||||
		test -s $$i -a $$(wc -w <$$i) -ge 100 && lc="$$lc $$i"; \
 | 
			
		||||
	done; \
 | 
			
		||||
	test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \
 | 
			
		||||
		-o $(LCOV_REPORTS_DIR) $$lc
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq ($(shell which ctags 2>/dev/null),)
 | 
			
		||||
ifneq ($(shell which ctags),)
 | 
			
		||||
.PHONY: tags
 | 
			
		||||
tags:
 | 
			
		||||
	test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README
									
									
									
									
									
								
							@@ -1,7 +1,5 @@
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
@@ -9,6 +7,7 @@ There is no warranty - see COPYING and COPYING.LIB.
 | 
			
		||||
 | 
			
		||||
Tarballs are available from:
 | 
			
		||||
  ftp://sourceware.org/pub/lvm2/
 | 
			
		||||
  ftp://sources.redhat.com/pub/lvm2/
 | 
			
		||||
  https://github.com/lvmteam/lvm2/releases
 | 
			
		||||
 | 
			
		||||
The source code is stored in git:
 | 
			
		||||
@@ -43,9 +42,6 @@ Report upstream bugs at:
 | 
			
		||||
or open issues at:
 | 
			
		||||
  https://github.com/lvmteam/lvm2/issues
 | 
			
		||||
 | 
			
		||||
The source code repository used until 7th June 2012 is accessible using CVS:
 | 
			
		||||
The source code repository used until 7th June 2012 is accessible here:
 | 
			
		||||
  http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2.
 | 
			
		||||
 | 
			
		||||
  cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 login cvs
 | 
			
		||||
  cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 checkout LVM2
 | 
			
		||||
 | 
			
		||||
The password is cvs.
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
1.02.175-git (2020-08-09)
 | 
			
		||||
1.02.160-git (2019-05-13)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										239
									
								
								WHATS_NEW
									
									
									
									
									
								
							
							
						
						
									
										239
									
								
								WHATS_NEW
									
									
									
									
									
								
							@@ -1,199 +1,90 @@
 | 
			
		||||
Version 2.03.11 - 
 | 
			
		||||
==================================
 | 
			
		||||
  Enhance error handling for fsadm and hanled correct fsck result.
 | 
			
		||||
  Dmeventd lvm plugin ignores higher reserved_stack lvm.conf values.
 | 
			
		||||
  Support using BLKZEROOUT for clearing devices.
 | 
			
		||||
  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.
 | 
			
		||||
  Configure use own python path name order to prefer using python3.
 | 
			
		||||
  Add configure --enable-editline support as an alternative to readline.
 | 
			
		||||
  Enhance reporting and error handling when creating thin volumes.
 | 
			
		||||
  Enable vgsplit for VDO volumes.
 | 
			
		||||
  Lvextend of vdo pool volumes ensure at least 1 new VDO slab is added.
 | 
			
		||||
  Use revert_lv() on reload error path after vg_revert().
 | 
			
		||||
  Configure --with-integrity enabled.
 | 
			
		||||
  Restore lost signal blocking while VG lock is held.
 | 
			
		||||
  Improve estimation of needed extents when creating thin-pool.
 | 
			
		||||
  Use extra 1% when resizing thin-pool metadata LV with --use-policy.
 | 
			
		||||
  Enhance --use-policy percentage rounding.
 | 
			
		||||
  Configure --with-vdo and --with-writecache as internal segments.
 | 
			
		||||
  Improving VDO man page examples.
 | 
			
		||||
  Switch code base to use flexible array syntax.
 | 
			
		||||
  Fix 64bit math when calculation cachevol size.
 | 
			
		||||
  Preserve uint32_t for seqno handling.
 | 
			
		||||
  Switch from mmap to plain read when loading regular files.
 | 
			
		||||
  Update lvmvdo man page and better explain DISCARD usage.
 | 
			
		||||
 | 
			
		||||
Version 2.03.10 - 09th August 2020
 | 
			
		||||
==================================
 | 
			
		||||
  Add writecache and integrity support to lvmdbusd.
 | 
			
		||||
  Generate unique cachevol name when default required from lvcreate.
 | 
			
		||||
  Converting RAID1 volume to one with same number of legs now succeeds with a
 | 
			
		||||
  warning.
 | 
			
		||||
  Fix conversion to raid from striped lagging type.
 | 
			
		||||
  Fix conversion to 'mirrored' mirror log with larger regionsize.
 | 
			
		||||
  Zero pool metadata on allocation (disable with allocation/zero_metadata=0).
 | 
			
		||||
  Failure in zeroing or wiping will fail command (bypass with -Zn, -Wn).
 | 
			
		||||
  Add lvcreate of new cache or writecache lv with single command.
 | 
			
		||||
  Fix running out of free buffers for async writing for larger writes.
 | 
			
		||||
  Add integrity with raid capability.
 | 
			
		||||
  Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
 | 
			
		||||
 | 
			
		||||
Version 2.03.09 - 26th March 2020
 | 
			
		||||
=================================
 | 
			
		||||
  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
 | 
			
		||||
====================================
 | 
			
		||||
  Prevent problematic snapshots of writecache volumes.
 | 
			
		||||
  Add error handling for failing allocation in _reserve_area().
 | 
			
		||||
  Fix memleak in syncing of internal cache.
 | 
			
		||||
  Fix pvck dump_current_text memleak.
 | 
			
		||||
  Fix lvmlockd result code on error path for _query_lock_lv().
 | 
			
		||||
  Update pvck man page and help output.
 | 
			
		||||
  Reject invalid writecache high/low_watermark setting.
 | 
			
		||||
  Report writecache status.
 | 
			
		||||
  Accept more output lines from vdo_format.
 | 
			
		||||
  Prohibit reshaping of stacked raid LVs.
 | 
			
		||||
  Avoid running cache input arg validation when creating vdo pool.
 | 
			
		||||
  Prevent raid reshaping of stacked volumes.
 | 
			
		||||
  Added VDO lvmdbusd methods for enable/disable compression & dedupe.
 | 
			
		||||
  Added VDO lvmdbusd method for converting LV to VDO pool.
 | 
			
		||||
 | 
			
		||||
Version 2.03.07 - 30th November 2019
 | 
			
		||||
====================================
 | 
			
		||||
  Subcommand in vgck for repairing headers and metadata.
 | 
			
		||||
  Ensure minimum required region size on striped RaidLV creation.
 | 
			
		||||
  Fix resize of thin-pool with data and metadata of different segtype.
 | 
			
		||||
  Improve mirror type leg splitting.
 | 
			
		||||
  Improve error path handling in daemons on shutdown.
 | 
			
		||||
  Fix activation order when removing merged snapshot.
 | 
			
		||||
  Experimental VDO support for lvmdbusd.
 | 
			
		||||
 | 
			
		||||
Version 2.03.06 - 23rd October 2019
 | 
			
		||||
===================================
 | 
			
		||||
  Add _cpool suffix to cache-pool LV name when used by caching LV.
 | 
			
		||||
  No longer store extra UUID for cmeta and cdata cachevol layer.
 | 
			
		||||
  Enhance activation of cache devices with cachevols.
 | 
			
		||||
  Add _cvol in list of protected suffixes and start use it with DM UUID.
 | 
			
		||||
  Rename LV converted to cachevol to use _cvol suffix.
 | 
			
		||||
  Use normal LVs for wiping of cachevols.
 | 
			
		||||
  Reload cleanered cache DM only with cleaner policy.
 | 
			
		||||
  Fix cmd return when zeroing of cachevol fails.
 | 
			
		||||
  Extend lvs to show all VDO properties.
 | 
			
		||||
  Preserve VDO write policy with vdopool.
 | 
			
		||||
  Increase default vdo bio threads to 4.
 | 
			
		||||
  Continue report when cache_status fails.
 | 
			
		||||
  Add support for DM_DEVICE_GET_TARGET_VERSION into device_mapper.
 | 
			
		||||
  Fix cmirrord usage of header files from device_mapper subdir.
 | 
			
		||||
  Allow standalone activation of VDO pool just like for thin-pools.
 | 
			
		||||
  Activate thin-pool layered volume as 'read-only' device.
 | 
			
		||||
  Ignore crypto devices with UUID signature CRYPT-SUBDEV.
 | 
			
		||||
  Enhance validation for thin and cache pool conversion and swapping.
 | 
			
		||||
  Improve internal removal of cached devices.
 | 
			
		||||
  Synchronize with udev when dropping snapshot.
 | 
			
		||||
  Add missing device synchronization point before removing pvmove node.
 | 
			
		||||
  Correctly set read_ahead for LVs when pvmove is finished.
 | 
			
		||||
  Remove unsupported OPTIONS+="event_timeout" udev rule from 11-dm-lvm.rules.
 | 
			
		||||
  Prevent creating VGs with PVs with different logical block sizes.
 | 
			
		||||
Version 2.02.186 - 
 | 
			
		||||
================================
 | 
			
		||||
  Fix metadata writes from corrupting with large physical block size.
 | 
			
		||||
 | 
			
		||||
Version 2.03.05 - 15th June 2019
 | 
			
		||||
================================
 | 
			
		||||
  Fix command definition for pvchange -a.
 | 
			
		||||
  Add vgck --updatemetadata command that will repair metadata problems.
 | 
			
		||||
  Improve VG reading to work if one good copy of metadata is found.
 | 
			
		||||
  Report/display/scan commands that read VGs will no longer write/repair.
 | 
			
		||||
  Move metadata repairs from VG reading to VG writing.
 | 
			
		||||
  Add config setting md_component_checks to control MD component checks.
 | 
			
		||||
  Add end of device MD component checks when dev has no udev info.
 | 
			
		||||
 | 
			
		||||
Version 2.03.04 - 10th June 2019
 | 
			
		||||
================================
 | 
			
		||||
  Remove unused_duplicate_devs from cmd causing segfault in dmeventd.
 | 
			
		||||
 | 
			
		||||
Version 2.03.03 - 07th June 2019
 | 
			
		||||
================================
 | 
			
		||||
  Report no_discard_passdown for cache LVs with lvs -o+kernel_discards.
 | 
			
		||||
  Add pvck --dump option to extract metadata.
 | 
			
		||||
  Prevent shared active mirror LVs with lvmlockd.
 | 
			
		||||
 | 
			
		||||
Version 2.02.185 - 13th May 2019
 | 
			
		||||
================================
 | 
			
		||||
  Fix change of monitoring in clustered volumes.
 | 
			
		||||
  Improve -lXXX%VG modifier which improves cache segment estimation.
 | 
			
		||||
  Add synchronization with udev before removing cached devices.
 | 
			
		||||
  Fix missing growth of _pmspare volume when extending _tmeta volume.
 | 
			
		||||
  Automatically grow thin metadata, when thin data gets too big.
 | 
			
		||||
  Add support for vgsplit with cached devices.
 | 
			
		||||
  Fix signal delivery checking race in libdaemon (lvmetad).
 | 
			
		||||
  Add missing Before=shutdown.target to LVM2 services to fix shutdown ordering.
 | 
			
		||||
  Skip autoactivation for a PV when PV size does not match device size.
 | 
			
		||||
  Remove first-pvscan-initialization which should no longer be needed.
 | 
			
		||||
  Add remote refresh through lvmlockd/dlm for shared LVs after lvextend.
 | 
			
		||||
  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 _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.
 | 
			
		||||
  Add support for vgsplit with cached devices.
 | 
			
		||||
  Query mpath device only once per command for its state.
 | 
			
		||||
  Use device INFO instead of STATUS when checking for mpath device uuid.
 | 
			
		||||
  Change default io_memory_size from 4 to 8 MiB.
 | 
			
		||||
  Add config setting io_memory_size to set bcache size.
 | 
			
		||||
  Fix pvscan autoactivation for concurrent pvscans.
 | 
			
		||||
 | 
			
		||||
Version 2.02.184 - 22nd March 2019
 | 
			
		||||
==================================
 | 
			
		||||
  Fix (de)activation of RaidLVs with visible SubLVs
 | 
			
		||||
  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 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 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 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.
 | 
			
		||||
  Move VDO support towards V2 target (6.2) support.
 | 
			
		||||
 | 
			
		||||
Version 2.03.02 - 18th December 2018
 | 
			
		||||
====================================
 | 
			
		||||
  Add scan_lvs config setting to control if lvm scans LVs for PVs.
 | 
			
		||||
  Fix missing proper initialization of pv_list struct when adding pv.
 | 
			
		||||
  Fix (de)activation of RaidLVs with visible SubLVs.
 | 
			
		||||
  Prohibit mirrored 'mirror' log via lvcreate and lvconvert.
 | 
			
		||||
 | 
			
		||||
Version 2.02.183 - 07th December 2018
 | 
			
		||||
=====================================
 | 
			
		||||
  Avoid disabling lvmetad when repair does nothing.
 | 
			
		||||
  Fix component detection for md version 0.90.
 | 
			
		||||
  Use sync io if async io_setup fails, or use_aio=0 is set in config.
 | 
			
		||||
  Fix more issues reported by coverity scan.
 | 
			
		||||
  Avoid opening devices to get block size by using existing open fd.
 | 
			
		||||
 | 
			
		||||
Version 2.03.01 - 31st October 2018
 | 
			
		||||
===================================
 | 
			
		||||
 | 
			
		||||
Version 2.03.00 - 10th October 2018
 | 
			
		||||
===================================
 | 
			
		||||
  Add hot fix to avoiding locking collision when monitoring thin-pools.
 | 
			
		||||
  Allow raid4 -> linear conversion request.
 | 
			
		||||
Version 2.02.182 - 30th October 2018
 | 
			
		||||
====================================
 | 
			
		||||
  Fix possible write race between last metadata block and the first extent.
 | 
			
		||||
  Fix filtering of md 1.0 devices so they are not seen as duplicate PVs.
 | 
			
		||||
  Fix lvconvert striped/raid0/raid0_meta -> raid6 regression.
 | 
			
		||||
  Add 'lvm2-activation-generator:' prefix for kmsg messages logged by generator.
 | 
			
		||||
  Add After=rbdmap.service to {lvm2-activation-net,blk-availability}.service.
 | 
			
		||||
  Fix pvs with lvmetad to avoid too many open files from filter reads.
 | 
			
		||||
  Fix pvscan --cache to avoid too many open files from filter reads.
 | 
			
		||||
  Reduce max concurrent aios to avoid EMFILE with many devices.
 | 
			
		||||
  Fix lvconvert conversion attempts to linear.
 | 
			
		||||
  Fix lvconvert raid0/raid0_meta -> striped regression.
 | 
			
		||||
  Fix lvconvert --splitmirror for mirror type (2.02.178).
 | 
			
		||||
  Do not pair cache policy and cache metadata format.
 | 
			
		||||
  lvconvert: reject conversions on raid1 LVs with split tracked SubLVs
 | 
			
		||||
  lvconvert: reject conversions on raid1 split tracked SubLVs
 | 
			
		||||
  Add basic creation support for VDO target.
 | 
			
		||||
  Fix mirrors honoring read_only_volume_list.
 | 
			
		||||
 | 
			
		||||
Version 2.02.181 - 01 August 2018
 | 
			
		||||
=================================
 | 
			
		||||
  Reject conversions on raid1 LVs with split tracked SubLVs.
 | 
			
		||||
  Reject conversions on raid1 split tracked SubLVs.
 | 
			
		||||
  Fix dmstats list failing when no regions exist.
 | 
			
		||||
  Reject conversions of LVs under snapshot.
 | 
			
		||||
  Limit suggested options on incorrect option for lvconvert subcommand.
 | 
			
		||||
 | 
			
		||||
Version 2.02.180 - 19th July 2018
 | 
			
		||||
=================================
 | 
			
		||||
  Never send any discard ioctl with test mode.
 | 
			
		||||
  Fix thin-pool alloc which needs same PV for data and metadata.
 | 
			
		||||
  Extend list of non-memlocked areas with newly linked libs.
 | 
			
		||||
  Enhance vgcfgrestore to check for active LVs in restored VG.
 | 
			
		||||
  Configure supports --disable-silent-rules for verbose builds.
 | 
			
		||||
  Fix unmonitoring of merging snapshots.
 | 
			
		||||
  Cache can uses metadata format 2 with cleaner policy.
 | 
			
		||||
  Fix check if resized PV can also fit metadata area.
 | 
			
		||||
  Avoid showing internal error in lvs output or pvmoved LVs.
 | 
			
		||||
  Remove clvmd
 | 
			
		||||
  Remove lvmlib (api)
 | 
			
		||||
  Remove lvmetad
 | 
			
		||||
  lvconvert: provide possible layouts between linear and striped/raid
 | 
			
		||||
  Fix unmonitoring of merging snapshots.
 | 
			
		||||
  Add missing -l description in fsadm man page.
 | 
			
		||||
  Cache can uses metadata format 2 with cleaner policy.
 | 
			
		||||
  Avoid showing internal error in lvs output or pvmoved LVs.
 | 
			
		||||
  Fix check if resized PV can also fit metadata area.
 | 
			
		||||
  Reopen devices RDWR only before writing to avoid udev issues.
 | 
			
		||||
  Change pvresize output confusing when no resize took place.
 | 
			
		||||
  Fix lvmetad hanging on shutdown.
 | 
			
		||||
  Fix mem leak in clvmd and more coverity issues.
 | 
			
		||||
 | 
			
		||||
Version 2.02.179 - 18th June 2018
 | 
			
		||||
=================================
 | 
			
		||||
  Allow forced vgchange to lock type none on clustered VG.
 | 
			
		||||
  Add the report field "shared".
 | 
			
		||||
  Enable automatic metadata consistency repair on a shared VG.
 | 
			
		||||
  Fix pvremove force on a PV with a shared VG.
 | 
			
		||||
  Fixed vgimportclone of a PV with a shared VG.
 | 
			
		||||
  Enable previously disallowed thin/cache commands in shared VGs.
 | 
			
		||||
  Enable metadata-related changes on LVs active with shared lock.
 | 
			
		||||
  Do not continue trying to use a device that cannot be opened.
 | 
			
		||||
  Fix problems opening a device that fails and returns.
 | 
			
		||||
  Use versionsort to fix archive file expiry beyond 100000 files.
 | 
			
		||||
 | 
			
		||||
Version 2.02.178 - 13th June 2018
 | 
			
		||||
=================================
 | 
			
		||||
 | 
			
		||||
Version 2.02.178-rc1 - 24th May 2018
 | 
			
		||||
====================================
 | 
			
		||||
  Add libaio dependency for build.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							@@ -1,52 +1,23 @@
 | 
			
		||||
Version 1.02.175 - 
 | 
			
		||||
===================================
 | 
			
		||||
 | 
			
		||||
Version 1.02.173 - 09th August 2020
 | 
			
		||||
===================================
 | 
			
		||||
  Add support for VDO in blkdeactivate script.
 | 
			
		||||
 | 
			
		||||
Version 1.02.171 - 26th March 2020
 | 
			
		||||
==================================
 | 
			
		||||
  Try to remove all created devices on dm preload tree error path.
 | 
			
		||||
  Fix dm_list interators with gcc 10 optimization (-ftree-pta).
 | 
			
		||||
  Dmeventd handles timer without looping on short intervals.
 | 
			
		||||
 | 
			
		||||
Version 1.02.169 - 11th February 2020
 | 
			
		||||
=====================================
 | 
			
		||||
  Enhance error messages for device creation.
 | 
			
		||||
 | 
			
		||||
Version 1.02.167 - 30th November 2019
 | 
			
		||||
=====================================
 | 
			
		||||
 | 
			
		||||
Version 1.02.165 - 23rd October 2019
 | 
			
		||||
====================================
 | 
			
		||||
  Add support for DM_DEVICE_GET_TARGET_VERSION.
 | 
			
		||||
  Add debug of dmsetup udevcomplete with hexa print DM_COOKIE_COMPLETED.
 | 
			
		||||
Version 1.02.160 - 
 | 
			
		||||
================================
 | 
			
		||||
  Fix versioning of dm_stats_create_region and dm_stats_create_region.
 | 
			
		||||
 | 
			
		||||
Version 1.02.163 - 15th June 2019
 | 
			
		||||
=================================
 | 
			
		||||
 | 
			
		||||
Version 1.02.161 - 10th June 2019
 | 
			
		||||
=================================
 | 
			
		||||
 | 
			
		||||
Version 1.02.159 - 07th June 2019
 | 
			
		||||
=================================
 | 
			
		||||
  Parsing of cache status understand no_discard_passdown.
 | 
			
		||||
  Ensure migration_threshold for cache is at least 8 chunks.
 | 
			
		||||
 | 
			
		||||
Version 1.02.155 - 18th December 2018
 | 
			
		||||
=====================================
 | 
			
		||||
  Include correct internal header inside libdm list.c.
 | 
			
		||||
Version 1.02.158 - 13th May 2019
 | 
			
		||||
================================
 | 
			
		||||
 | 
			
		||||
Version 1.02.156 - 22nd March 2019
 | 
			
		||||
==================================
 | 
			
		||||
  Ensure migration_threshold for cache is at least 8 chunks.
 | 
			
		||||
  Enhance ioctl flattening and add parameters only when needed.
 | 
			
		||||
  Add DM_DEVICE_ARM_POLL for API completness matching kernel.
 | 
			
		||||
 | 
			
		||||
Version 1.02.154 - 07th December 2018
 | 
			
		||||
=====================================
 | 
			
		||||
  Do not add parameters for RESUME with DM_DEVICE_CREATE dm task.
 | 
			
		||||
  Fix dmstats report printing no output.
 | 
			
		||||
 | 
			
		||||
Version 1.02.153 - 31st October 2018
 | 
			
		||||
====================================
 | 
			
		||||
 | 
			
		||||
Version 1.02.151 - 10th October 2018
 | 
			
		||||
Version 1.02.152 - 30th October 2018
 | 
			
		||||
====================================
 | 
			
		||||
  Add hot fix to avoiding locking collision when monitoring thin-pools.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										95
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										95
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
# generated automatically by aclocal 1.16.2 -*- Autoconf -*-
 | 
			
		||||
# generated automatically by aclocal 1.15 -*- Autoconf -*-
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 1996-2020 Free Software Foundation, Inc.
 | 
			
		||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 | 
			
		||||
 | 
			
		||||
# This file is free software; the Free Software Foundation
 | 
			
		||||
# gives unlimited permission to copy and/or distribute it,
 | 
			
		||||
@@ -13,7 +13,7 @@
 | 
			
		||||
 | 
			
		||||
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
 | 
			
		||||
# ===========================================================================
 | 
			
		||||
#     https://www.gnu.org/software/autoconf-archive/ax_python_module.html
 | 
			
		||||
#     http://www.gnu.org/software/autoconf-archive/ax_python_module.html
 | 
			
		||||
# ===========================================================================
 | 
			
		||||
#
 | 
			
		||||
# SYNOPSIS
 | 
			
		||||
@@ -37,7 +37,7 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun
 | 
			
		||||
#   and this notice are preserved. This file is offered as-is, without any
 | 
			
		||||
#   warranty.
 | 
			
		||||
 | 
			
		||||
#serial 9
 | 
			
		||||
#serial 8
 | 
			
		||||
 | 
			
		||||
AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE])
 | 
			
		||||
AC_DEFUN([AX_PYTHON_MODULE],[
 | 
			
		||||
@@ -69,9 +69,9 @@ AC_DEFUN([AX_PYTHON_MODULE],[
 | 
			
		||||
    fi
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
# pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
 | 
			
		||||
# serial 11 (pkg-config-0.29.1)
 | 
			
		||||
 | 
			
		||||
dnl pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
 | 
			
		||||
dnl serial 11 (pkg-config-0.29)
 | 
			
		||||
dnl
 | 
			
		||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
 | 
			
		||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
 | 
			
		||||
dnl
 | 
			
		||||
@@ -112,7 +112,7 @@ dnl
 | 
			
		||||
dnl See the "Since" comment for each macro you use to see what version
 | 
			
		||||
dnl of the macros you require.
 | 
			
		||||
m4_defun([PKG_PREREQ],
 | 
			
		||||
[m4_define([PKG_MACROS_VERSION], [0.29.1])
 | 
			
		||||
[m4_define([PKG_MACROS_VERSION], [0.29])
 | 
			
		||||
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
 | 
			
		||||
@@ -345,75 +345,7 @@ AS_VAR_COPY([$1], [pkg_cv_][$1])
 | 
			
		||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
 | 
			
		||||
])dnl PKG_CHECK_VAR
 | 
			
		||||
 | 
			
		||||
dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES,
 | 
			
		||||
dnl   [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND],
 | 
			
		||||
dnl   [DESCRIPTION], [DEFAULT])
 | 
			
		||||
dnl ------------------------------------------
 | 
			
		||||
dnl
 | 
			
		||||
dnl Prepare a "--with-" configure option using the lowercase
 | 
			
		||||
dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and
 | 
			
		||||
dnl PKG_CHECK_MODULES in a single macro.
 | 
			
		||||
AC_DEFUN([PKG_WITH_MODULES],
 | 
			
		||||
[
 | 
			
		||||
m4_pushdef([with_arg], m4_tolower([$1]))
 | 
			
		||||
 | 
			
		||||
m4_pushdef([description],
 | 
			
		||||
           [m4_default([$5], [build with ]with_arg[ support])])
 | 
			
		||||
 | 
			
		||||
m4_pushdef([def_arg], [m4_default([$6], [auto])])
 | 
			
		||||
m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes])
 | 
			
		||||
m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no])
 | 
			
		||||
 | 
			
		||||
m4_case(def_arg,
 | 
			
		||||
            [yes],[m4_pushdef([with_without], [--without-]with_arg)],
 | 
			
		||||
            [m4_pushdef([with_without],[--with-]with_arg)])
 | 
			
		||||
 | 
			
		||||
AC_ARG_WITH(with_arg,
 | 
			
		||||
     AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),,
 | 
			
		||||
    [AS_TR_SH([with_]with_arg)=def_arg])
 | 
			
		||||
 | 
			
		||||
AS_CASE([$AS_TR_SH([with_]with_arg)],
 | 
			
		||||
            [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)],
 | 
			
		||||
            [auto],[PKG_CHECK_MODULES([$1],[$2],
 | 
			
		||||
                                        [m4_n([def_action_if_found]) $3],
 | 
			
		||||
                                        [m4_n([def_action_if_not_found]) $4])])
 | 
			
		||||
 | 
			
		||||
m4_popdef([with_arg])
 | 
			
		||||
m4_popdef([description])
 | 
			
		||||
m4_popdef([def_arg])
 | 
			
		||||
 | 
			
		||||
])dnl PKG_WITH_MODULES
 | 
			
		||||
 | 
			
		||||
dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
 | 
			
		||||
dnl   [DESCRIPTION], [DEFAULT])
 | 
			
		||||
dnl -----------------------------------------------
 | 
			
		||||
dnl
 | 
			
		||||
dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES
 | 
			
		||||
dnl check._[VARIABLE-PREFIX] is exported as make variable.
 | 
			
		||||
AC_DEFUN([PKG_HAVE_WITH_MODULES],
 | 
			
		||||
[
 | 
			
		||||
PKG_WITH_MODULES([$1],[$2],,,[$3],[$4])
 | 
			
		||||
 | 
			
		||||
AM_CONDITIONAL([HAVE_][$1],
 | 
			
		||||
               [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"])
 | 
			
		||||
])dnl PKG_HAVE_WITH_MODULES
 | 
			
		||||
 | 
			
		||||
dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
 | 
			
		||||
dnl   [DESCRIPTION], [DEFAULT])
 | 
			
		||||
dnl ------------------------------------------------------
 | 
			
		||||
dnl
 | 
			
		||||
dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after
 | 
			
		||||
dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make
 | 
			
		||||
dnl and preprocessor variable.
 | 
			
		||||
AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES],
 | 
			
		||||
[
 | 
			
		||||
PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4])
 | 
			
		||||
 | 
			
		||||
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-2020 Free Software Foundation, Inc.
 | 
			
		||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 | 
			
		||||
#
 | 
			
		||||
# This file is free software; the Free Software Foundation
 | 
			
		||||
# gives unlimited permission to copy and/or distribute it,
 | 
			
		||||
@@ -447,11 +379,8 @@ 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 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.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl
 | 
			
		||||
 python2.0])
 | 
			
		||||
[python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
 | 
			
		||||
 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0])
 | 
			
		||||
 | 
			
		||||
  AC_ARG_VAR([PYTHON], [the Python interpreter])
 | 
			
		||||
 | 
			
		||||
@@ -651,7 +580,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-2020 Free Software Foundation, Inc.
 | 
			
		||||
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 | 
			
		||||
#
 | 
			
		||||
# This file is free software; the Free Software Foundation
 | 
			
		||||
# gives unlimited permission to copy and/or distribute it,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,40 +0,0 @@
 | 
			
		||||
# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of the device-mapper userspace tools.
 | 
			
		||||
#
 | 
			
		||||
# This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
# of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 | 
			
		||||
# Uncomment this to build the simple radix tree.  You'll need to make clean too.
 | 
			
		||||
# Comment to build the advanced radix tree.
 | 
			
		||||
#base/data-struct/radix-tree.o: CFLAGS += -DSIMPLE_RADIX_TREE
 | 
			
		||||
 | 
			
		||||
# NOTE: this Makefile only works as 'include' for toplevel Makefile
 | 
			
		||||
#       which defined all top_* variables
 | 
			
		||||
 | 
			
		||||
BASE_SOURCE=\
 | 
			
		||||
	base/data-struct/hash.c \
 | 
			
		||||
	base/data-struct/list.c \
 | 
			
		||||
	base/data-struct/radix-tree.c
 | 
			
		||||
 | 
			
		||||
BASE_TARGET = base/libbase.a
 | 
			
		||||
BASE_DEPENDS = $(BASE_SOURCE:%.c=%.d)
 | 
			
		||||
BASE_OBJECTS = $(BASE_SOURCE:%.c=%.o)
 | 
			
		||||
CLEAN_TARGETS += $(BASE_DEPENDS) $(BASE_OBJECTS) \
 | 
			
		||||
	$(BASE_SOURCE:%.c=%.gcda) \
 | 
			
		||||
	$(BASE_SOURCE:%.c=%.gcno) \
 | 
			
		||||
	$(BASE_TARGET)
 | 
			
		||||
 | 
			
		||||
$(BASE_TARGET): $(BASE_OBJECTS)
 | 
			
		||||
	@echo "    [AR] $@"
 | 
			
		||||
	$(Q) $(RM) $@
 | 
			
		||||
	$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null
 | 
			
		||||
 | 
			
		||||
ifeq ("$(DEPENDS)","yes")
 | 
			
		||||
-include $(BASE_DEPENDS)
 | 
			
		||||
endif
 | 
			
		||||
@@ -1,395 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of the device-mapper userspace tools.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "device_mapper/misc/dmlib.h"
 | 
			
		||||
#include "base/memory/zalloc.h"
 | 
			
		||||
#include "hash.h"
 | 
			
		||||
 | 
			
		||||
struct dm_hash_node {
 | 
			
		||||
	struct dm_hash_node *next;
 | 
			
		||||
	void *data;
 | 
			
		||||
	unsigned data_len;
 | 
			
		||||
	unsigned keylen;
 | 
			
		||||
	char key[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct dm_hash_table {
 | 
			
		||||
	unsigned num_nodes;
 | 
			
		||||
	unsigned num_slots;
 | 
			
		||||
	struct dm_hash_node **slots;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Permutation of the Integers 0 through 255 */
 | 
			
		||||
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,
 | 
			
		||||
	12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
 | 
			
		||||
	144,
 | 
			
		||||
	176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
 | 
			
		||||
	178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
 | 
			
		||||
	221,
 | 
			
		||||
	102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
 | 
			
		||||
	166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
 | 
			
		||||
	121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
 | 
			
		||||
	194,
 | 
			
		||||
	193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
 | 
			
		||||
	139,
 | 
			
		||||
	6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
 | 
			
		||||
	84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
 | 
			
		||||
	43,
 | 
			
		||||
	249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
 | 
			
		||||
	71,
 | 
			
		||||
	230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
 | 
			
		||||
	109,
 | 
			
		||||
	44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
 | 
			
		||||
	163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
 | 
			
		||||
	209
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct dm_hash_node *_create_node(const void *key, unsigned len)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *n = malloc(sizeof(*n) + len);
 | 
			
		||||
 | 
			
		||||
	if (n) {
 | 
			
		||||
		memcpy(n->key, key, len);
 | 
			
		||||
		n->keylen = len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned long _hash(const void *key, unsigned len)
 | 
			
		||||
{
 | 
			
		||||
	const unsigned char *str = key;
 | 
			
		||||
	unsigned long h = 0, g;
 | 
			
		||||
	unsigned i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < len; i++) {
 | 
			
		||||
		h <<= 4;
 | 
			
		||||
		h += _nums[*str++];
 | 
			
		||||
		g = h & ((unsigned long) 0xf << 16u);
 | 
			
		||||
		if (g) {
 | 
			
		||||
			h ^= g >> 16u;
 | 
			
		||||
			h ^= g >> 5u;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_hash_table *dm_hash_create(unsigned size_hint)
 | 
			
		||||
{
 | 
			
		||||
	size_t len;
 | 
			
		||||
	unsigned new_size = 16u;
 | 
			
		||||
	struct dm_hash_table *hc = zalloc(sizeof(*hc));
 | 
			
		||||
 | 
			
		||||
	if (!hc)
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	/* round size hint up to a power of two */
 | 
			
		||||
	while (new_size < size_hint)
 | 
			
		||||
		new_size = new_size << 1;
 | 
			
		||||
 | 
			
		||||
	hc->num_slots = new_size;
 | 
			
		||||
	len = sizeof(*(hc->slots)) * new_size;
 | 
			
		||||
	if (!(hc->slots = zalloc(len)))
 | 
			
		||||
		goto_bad;
 | 
			
		||||
 | 
			
		||||
	return hc;
 | 
			
		||||
 | 
			
		||||
      bad:
 | 
			
		||||
	free(hc->slots);
 | 
			
		||||
	free(hc);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _free_nodes(struct dm_hash_table *t)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *c, *n;
 | 
			
		||||
	unsigned i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < t->num_slots; i++)
 | 
			
		||||
		for (c = t->slots[i]; c; c = n) {
 | 
			
		||||
			n = c->next;
 | 
			
		||||
			free(c);
 | 
			
		||||
		}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_hash_destroy(struct dm_hash_table *t)
 | 
			
		||||
{
 | 
			
		||||
	_free_nodes(t);
 | 
			
		||||
	free(t->slots);
 | 
			
		||||
	free(t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dm_hash_node **_find(struct dm_hash_table *t, const void *key,
 | 
			
		||||
				   uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
	unsigned h = _hash(key, len) & (t->num_slots - 1);
 | 
			
		||||
	struct dm_hash_node **c;
 | 
			
		||||
 | 
			
		||||
	for (c = &t->slots[h]; *c; c = &((*c)->next)) {
 | 
			
		||||
		if ((*c)->keylen != len)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!memcmp(key, (*c)->key, len))
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key,
 | 
			
		||||
			    uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node **c = _find(t, key, len);
 | 
			
		||||
 | 
			
		||||
	return *c ? (*c)->data : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_hash_insert_binary(struct dm_hash_table *t, const void *key,
 | 
			
		||||
			  uint32_t len, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node **c = _find(t, key, len);
 | 
			
		||||
 | 
			
		||||
	if (*c)
 | 
			
		||||
		(*c)->data = data;
 | 
			
		||||
	else {
 | 
			
		||||
		struct dm_hash_node *n = _create_node(key, len);
 | 
			
		||||
 | 
			
		||||
		if (!n)
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		n->data = data;
 | 
			
		||||
		n->next = 0;
 | 
			
		||||
		*c = n;
 | 
			
		||||
		t->num_nodes++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_hash_remove_binary(struct dm_hash_table *t, const void *key,
 | 
			
		||||
			uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node **c = _find(t, key, len);
 | 
			
		||||
 | 
			
		||||
	if (*c) {
 | 
			
		||||
		struct dm_hash_node *old = *c;
 | 
			
		||||
		*c = (*c)->next;
 | 
			
		||||
		free(old);
 | 
			
		||||
		t->num_nodes--;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *dm_hash_lookup(struct dm_hash_table *t, const char *key)
 | 
			
		||||
{
 | 
			
		||||
	return dm_hash_lookup_binary(t, key, strlen(key) + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data)
 | 
			
		||||
{
 | 
			
		||||
	return dm_hash_insert_binary(t, key, strlen(key) + 1, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_hash_remove(struct dm_hash_table *t, const char *key)
 | 
			
		||||
{
 | 
			
		||||
	dm_hash_remove_binary(t, key, strlen(key) + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dm_hash_node **_find_str_with_val(struct dm_hash_table *t,
 | 
			
		||||
					        const void *key, const void *val,
 | 
			
		||||
					        uint32_t len, uint32_t val_len)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node **c;
 | 
			
		||||
	unsigned h;
 | 
			
		||||
       
 | 
			
		||||
	h = _hash(key, len) & (t->num_slots - 1);
 | 
			
		||||
 | 
			
		||||
	for (c = &t->slots[h]; *c; c = &((*c)->next)) {
 | 
			
		||||
		if ((*c)->keylen != len)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!memcmp(key, (*c)->key, len) && (*c)->data) {
 | 
			
		||||
			if (((*c)->data_len == val_len) &&
 | 
			
		||||
			    !memcmp(val, (*c)->data, val_len))
 | 
			
		||||
				return c;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key,
 | 
			
		||||
				  const void *val, uint32_t val_len)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *n;
 | 
			
		||||
	struct dm_hash_node *first;
 | 
			
		||||
	int len = strlen(key) + 1;
 | 
			
		||||
	unsigned h;
 | 
			
		||||
 | 
			
		||||
	n = _create_node(key, len);
 | 
			
		||||
	if (!n)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	n->data = (void *)val;
 | 
			
		||||
	n->data_len = val_len;
 | 
			
		||||
 | 
			
		||||
	h = _hash(key, len) & (t->num_slots - 1);
 | 
			
		||||
 | 
			
		||||
	first = t->slots[h];
 | 
			
		||||
 | 
			
		||||
	if (first)
 | 
			
		||||
		n->next = first;
 | 
			
		||||
	else
 | 
			
		||||
		n->next = 0;
 | 
			
		||||
	t->slots[h] = n;
 | 
			
		||||
 | 
			
		||||
	t->num_nodes++;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Look through multiple entries with the same key for one that has a
 | 
			
		||||
 * 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)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node **c;
 | 
			
		||||
 | 
			
		||||
	c = _find_str_with_val(t, key, val, strlen(key) + 1, val_len);
 | 
			
		||||
 | 
			
		||||
	return (c && *c) ? (*c)->data : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Look through multiple entries with the same key for one that has a
 | 
			
		||||
 * matching val and remove that.
 | 
			
		||||
 */
 | 
			
		||||
void dm_hash_remove_with_val(struct dm_hash_table *t, const char *key,
 | 
			
		||||
			     const void *val, uint32_t val_len)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node **c;
 | 
			
		||||
 | 
			
		||||
	c = _find_str_with_val(t, key, val, strlen(key) + 1, val_len);
 | 
			
		||||
 | 
			
		||||
	if (c && *c) {
 | 
			
		||||
		struct dm_hash_node *old = *c;
 | 
			
		||||
		*c = (*c)->next;
 | 
			
		||||
		free(old);
 | 
			
		||||
		t->num_nodes--;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Look up the value for a key and count how many
 | 
			
		||||
 * entries have the same key.
 | 
			
		||||
 *
 | 
			
		||||
 * If no entries have key, return NULL and set count to 0.
 | 
			
		||||
 *
 | 
			
		||||
 * If one entry has the key, the function returns the val,
 | 
			
		||||
 * and sets count to 1.
 | 
			
		||||
 *
 | 
			
		||||
 * If N entries have the key, the function returns the val
 | 
			
		||||
 * from the first entry, and sets count to N.
 | 
			
		||||
 */
 | 
			
		||||
void *dm_hash_lookup_with_count(struct dm_hash_table *t, const char *key, int *count)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node **c;
 | 
			
		||||
	struct dm_hash_node **c1 = NULL;
 | 
			
		||||
	uint32_t len = strlen(key) + 1;
 | 
			
		||||
	unsigned h;
 | 
			
		||||
 | 
			
		||||
	*count = 0;
 | 
			
		||||
 | 
			
		||||
	h = _hash(key, len) & (t->num_slots - 1);
 | 
			
		||||
 | 
			
		||||
	for (c = &t->slots[h]; *c; c = &((*c)->next)) {
 | 
			
		||||
		if ((*c)->keylen != len)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!memcmp(key, (*c)->key, len)) {
 | 
			
		||||
			(*count)++;
 | 
			
		||||
			if (!c1)
 | 
			
		||||
				c1 = c;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!c1)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	else
 | 
			
		||||
		return *c1 ? (*c1)->data : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned dm_hash_get_num_entries(struct dm_hash_table *t)
 | 
			
		||||
{
 | 
			
		||||
	return t->num_nodes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *c, *n;
 | 
			
		||||
	unsigned i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < t->num_slots; i++)
 | 
			
		||||
		for (c = t->slots[i]; c; c = n) {
 | 
			
		||||
			n = c->next;
 | 
			
		||||
			f(c->data);
 | 
			
		||||
		}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_hash_wipe(struct dm_hash_table *t)
 | 
			
		||||
{
 | 
			
		||||
	_free_nodes(t);
 | 
			
		||||
	memset(t->slots, 0, sizeof(struct dm_hash_node *) * t->num_slots);
 | 
			
		||||
	t->num_nodes = 0u;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *dm_hash_get_key(struct dm_hash_table *t __attribute__((unused)),
 | 
			
		||||
		      struct dm_hash_node *n)
 | 
			
		||||
{
 | 
			
		||||
	return n->key;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *dm_hash_get_data(struct dm_hash_table *t __attribute__((unused)),
 | 
			
		||||
		       struct dm_hash_node *n)
 | 
			
		||||
{
 | 
			
		||||
	return n->data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *c = NULL;
 | 
			
		||||
	unsigned i;
 | 
			
		||||
 | 
			
		||||
	for (i = s; i < t->num_slots && !c; i++)
 | 
			
		||||
		c = t->slots[i];
 | 
			
		||||
 | 
			
		||||
	return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t)
 | 
			
		||||
{
 | 
			
		||||
	return _next_slot(t, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n)
 | 
			
		||||
{
 | 
			
		||||
	unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1);
 | 
			
		||||
 | 
			
		||||
	return n->next ? n->next : _next_slot(t, h + 1);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,94 +0,0 @@
 | 
			
		||||
#ifndef BASE_DATA_STRUCT_HASH_H
 | 
			
		||||
#define BASE_DATA_STRUCT_HASH_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
struct dm_hash_table;
 | 
			
		||||
struct dm_hash_node;
 | 
			
		||||
 | 
			
		||||
typedef void (*dm_hash_iterate_fn) (void *data);
 | 
			
		||||
 | 
			
		||||
struct dm_hash_table *dm_hash_create(unsigned size_hint)
 | 
			
		||||
	__attribute__((__warn_unused_result__));
 | 
			
		||||
void dm_hash_destroy(struct dm_hash_table *t);
 | 
			
		||||
void dm_hash_wipe(struct dm_hash_table *t);
 | 
			
		||||
 | 
			
		||||
void *dm_hash_lookup(struct dm_hash_table *t, const char *key);
 | 
			
		||||
int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data);
 | 
			
		||||
void dm_hash_remove(struct dm_hash_table *t, const char *key);
 | 
			
		||||
 | 
			
		||||
void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key, uint32_t len);
 | 
			
		||||
int dm_hash_insert_binary(struct dm_hash_table *t, const void *key, uint32_t len,
 | 
			
		||||
			  void *data);
 | 
			
		||||
void dm_hash_remove_binary(struct dm_hash_table *t, const void *key, uint32_t len);
 | 
			
		||||
 | 
			
		||||
unsigned dm_hash_get_num_entries(struct dm_hash_table *t);
 | 
			
		||||
void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f);
 | 
			
		||||
 | 
			
		||||
char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n);
 | 
			
		||||
void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n);
 | 
			
		||||
struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t);
 | 
			
		||||
struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * dm_hash_insert() replaces the value of an existing
 | 
			
		||||
 * entry with a matching key if one exists.  Otherwise
 | 
			
		||||
 * it adds a new entry.
 | 
			
		||||
 *
 | 
			
		||||
 * dm_hash_insert_with_val() inserts a new entry if
 | 
			
		||||
 * another entry with the same key already exists.
 | 
			
		||||
 * val_len is the size of the data being inserted.
 | 
			
		||||
 *
 | 
			
		||||
 * If two entries with the same key exist,
 | 
			
		||||
 * (added using dm_hash_insert_allow_multiple), then:
 | 
			
		||||
 * . dm_hash_lookup() returns the first one it finds, and
 | 
			
		||||
 *   dm_hash_lookup_with_val() returns the one with a matching
 | 
			
		||||
 *   val_len/val.
 | 
			
		||||
 * . dm_hash_remove() removes the first one it finds, and
 | 
			
		||||
 *   dm_hash_remove_with_val() removes the one with a matching
 | 
			
		||||
 *   val_len/val.
 | 
			
		||||
 *
 | 
			
		||||
 * If a single entry with a given key exists, and it has
 | 
			
		||||
 * zero val_len, then:
 | 
			
		||||
 * . dm_hash_lookup() returns it
 | 
			
		||||
 * . dm_hash_lookup_with_val(val_len=0) returns it
 | 
			
		||||
 * . dm_hash_remove() removes it
 | 
			
		||||
 * . dm_hash_remove_with_val(val_len=0) removes it
 | 
			
		||||
 *
 | 
			
		||||
 * dm_hash_lookup_with_count() is a single call that will
 | 
			
		||||
 * both lookup a key's value and check if there is more
 | 
			
		||||
 * than one entry with the given key.
 | 
			
		||||
 *
 | 
			
		||||
 * (It is not meant to retrieve all the entries with the
 | 
			
		||||
 * given key.  In the common case where a single entry exists
 | 
			
		||||
 * for the key, it is useful to have a single call that will
 | 
			
		||||
 * both look up the value and indicate if multiple values
 | 
			
		||||
 * exist for the key.)
 | 
			
		||||
 *
 | 
			
		||||
 * dm_hash_lookup_with_count:
 | 
			
		||||
 * . If no entries exist, the function returns NULL, and
 | 
			
		||||
 *   the count is set to 0.
 | 
			
		||||
 * . If only one entry exists, the value of that entry is
 | 
			
		||||
 *   returned and count is set to 1.
 | 
			
		||||
 * . If N entries exists, the value of the first entry is
 | 
			
		||||
 *   returned and count is set to N.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key,
 | 
			
		||||
                              const void *val, uint32_t val_len);
 | 
			
		||||
void dm_hash_remove_with_val(struct dm_hash_table *t, const char *key,
 | 
			
		||||
                             const void *val, uint32_t val_len);
 | 
			
		||||
int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key,
 | 
			
		||||
                                  const void *val, uint32_t val_len);
 | 
			
		||||
void *dm_hash_lookup_with_count(struct dm_hash_table *t, const char *key, int *count);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define dm_hash_iterate(v, h) \
 | 
			
		||||
	for (v = dm_hash_get_first((h)); v; \
 | 
			
		||||
	     v = dm_hash_get_next((h), v))
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,170 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "list.h"
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Initialise a list before use.
 | 
			
		||||
 * The list head's next and previous pointers point back to itself.
 | 
			
		||||
 */
 | 
			
		||||
void dm_list_init(struct dm_list *head)
 | 
			
		||||
{
 | 
			
		||||
	head->n = head->p = head;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Insert an element before 'head'.
 | 
			
		||||
 * If 'head' is the list head, this adds an element to the end of the list.
 | 
			
		||||
 */
 | 
			
		||||
void dm_list_add(struct dm_list *head, struct dm_list *elem)
 | 
			
		||||
{
 | 
			
		||||
	assert(head->n);
 | 
			
		||||
 | 
			
		||||
	elem->n = head;
 | 
			
		||||
	elem->p = head->p;
 | 
			
		||||
 | 
			
		||||
	head->p->n = elem;
 | 
			
		||||
	head->p = elem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Insert an element after 'head'.
 | 
			
		||||
 * If 'head' is the list head, this adds an element to the front of the list.
 | 
			
		||||
 */
 | 
			
		||||
void dm_list_add_h(struct dm_list *head, struct dm_list *elem)
 | 
			
		||||
{
 | 
			
		||||
	assert(head->n);
 | 
			
		||||
 | 
			
		||||
	elem->n = head->n;
 | 
			
		||||
	elem->p = head;
 | 
			
		||||
 | 
			
		||||
	head->n->p = elem;
 | 
			
		||||
	head->n = elem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Delete an element from its list.
 | 
			
		||||
 * Note that this doesn't change the element itself - it may still be safe
 | 
			
		||||
 * to follow its pointers.
 | 
			
		||||
 */
 | 
			
		||||
void dm_list_del(struct dm_list *elem)
 | 
			
		||||
{
 | 
			
		||||
	elem->n->p = elem->p;
 | 
			
		||||
	elem->p->n = elem->n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Remove an element from existing list and insert before 'head'.
 | 
			
		||||
 */
 | 
			
		||||
void dm_list_move(struct dm_list *head, struct dm_list *elem)
 | 
			
		||||
{
 | 
			
		||||
        dm_list_del(elem);
 | 
			
		||||
        dm_list_add(head, elem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Is the list empty?
 | 
			
		||||
 */
 | 
			
		||||
int dm_list_empty(const struct dm_list *head)
 | 
			
		||||
{
 | 
			
		||||
	return head->n == head;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Is this the first element of the list?
 | 
			
		||||
 */
 | 
			
		||||
int dm_list_start(const struct dm_list *head, const struct dm_list *elem)
 | 
			
		||||
{
 | 
			
		||||
	return elem->p == head;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Is this the last element of the list?
 | 
			
		||||
 */
 | 
			
		||||
int dm_list_end(const struct dm_list *head, const struct dm_list *elem)
 | 
			
		||||
{
 | 
			
		||||
	return elem->n == head;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return first element of the list or NULL if empty
 | 
			
		||||
 */
 | 
			
		||||
struct dm_list *dm_list_first(const struct dm_list *head)
 | 
			
		||||
{
 | 
			
		||||
	return (dm_list_empty(head) ? NULL : head->n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return last element of the list or NULL if empty
 | 
			
		||||
 */
 | 
			
		||||
struct dm_list *dm_list_last(const struct dm_list *head)
 | 
			
		||||
{
 | 
			
		||||
	return (dm_list_empty(head) ? NULL : head->p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the previous element of the list, or NULL if we've reached the start.
 | 
			
		||||
 */
 | 
			
		||||
struct dm_list *dm_list_prev(const struct dm_list *head, const struct dm_list *elem)
 | 
			
		||||
{
 | 
			
		||||
	return (dm_list_start(head, elem) ? NULL : elem->p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the next element of the list, or NULL if we've reached the end.
 | 
			
		||||
 */
 | 
			
		||||
struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *elem)
 | 
			
		||||
{
 | 
			
		||||
	return (dm_list_end(head, elem) ? NULL : elem->n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the number of elements in a list by walking it.
 | 
			
		||||
 */
 | 
			
		||||
unsigned int dm_list_size(const struct dm_list *head)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int s = 0;
 | 
			
		||||
	const struct dm_list *v;
 | 
			
		||||
 | 
			
		||||
	dm_list_iterate(v, head)
 | 
			
		||||
	    s++;
 | 
			
		||||
 | 
			
		||||
	return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Join two lists together.
 | 
			
		||||
 * This moves all the elements of the list 'head1' to the end of the list
 | 
			
		||||
 * 'head', leaving 'head1' empty.
 | 
			
		||||
 */
 | 
			
		||||
void dm_list_splice(struct dm_list *head, struct dm_list *head1)
 | 
			
		||||
{
 | 
			
		||||
	assert(head->n);
 | 
			
		||||
	assert(head1->n);
 | 
			
		||||
 | 
			
		||||
	if (dm_list_empty(head1))
 | 
			
		||||
	    return;
 | 
			
		||||
 | 
			
		||||
	head1->p->n = head;
 | 
			
		||||
	head1->n->p = head->p;
 | 
			
		||||
 | 
			
		||||
	head->p->n = head1->n;
 | 
			
		||||
	head->p = head1->p;
 | 
			
		||||
 | 
			
		||||
	dm_list_init(head1);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,211 +0,0 @@
 | 
			
		||||
#ifndef BASE_DATA_STRUCT_LIST_H
 | 
			
		||||
#define BASE_DATA_STRUCT_LIST_H
 | 
			
		||||
 | 
			
		||||
#include "base/memory/container_of.h"
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * A list consists of a list head plus elements.
 | 
			
		||||
 * Each element has 'next' and 'previous' pointers.
 | 
			
		||||
 * The list head's pointers point to the first and the last element.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct dm_list {
 | 
			
		||||
	struct dm_list *n, *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * String list.
 | 
			
		||||
 */
 | 
			
		||||
struct dm_str_list {
 | 
			
		||||
	struct dm_list list;
 | 
			
		||||
	const char *str;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Initialise a list before use.
 | 
			
		||||
 * The list head's next and previous pointers point back to itself.
 | 
			
		||||
 */
 | 
			
		||||
#define DM_LIST_HEAD_INIT(name)	 { &(name), &(name) }
 | 
			
		||||
#define DM_LIST_INIT(name)	struct dm_list name = DM_LIST_HEAD_INIT(name)
 | 
			
		||||
void dm_list_init(struct dm_list *head);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Insert an element before 'head'.
 | 
			
		||||
 * If 'head' is the list head, this adds an element to the end of the list.
 | 
			
		||||
 */
 | 
			
		||||
void dm_list_add(struct dm_list *head, struct dm_list *elem);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Insert an element after 'head'.
 | 
			
		||||
 * If 'head' is the list head, this adds an element to the front of the list.
 | 
			
		||||
 */
 | 
			
		||||
void dm_list_add_h(struct dm_list *head, struct dm_list *elem);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Delete an element from its list.
 | 
			
		||||
 * Note that this doesn't change the element itself - it may still be safe
 | 
			
		||||
 * to follow its pointers.
 | 
			
		||||
 */
 | 
			
		||||
void dm_list_del(struct dm_list *elem);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Remove an element from existing list and insert before 'head'.
 | 
			
		||||
 */
 | 
			
		||||
void dm_list_move(struct dm_list *head, struct dm_list *elem);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Join 'head1' to the end of 'head'.
 | 
			
		||||
 */
 | 
			
		||||
void dm_list_splice(struct dm_list *head, struct dm_list *head1);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Is the list empty?
 | 
			
		||||
 */
 | 
			
		||||
int dm_list_empty(const struct dm_list *head);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Is this the first element of the list?
 | 
			
		||||
 */
 | 
			
		||||
int dm_list_start(const struct dm_list *head, const struct dm_list *elem);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Is this the last element of the list?
 | 
			
		||||
 */
 | 
			
		||||
int dm_list_end(const struct dm_list *head, const struct dm_list *elem);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return first element of the list or NULL if empty
 | 
			
		||||
 */
 | 
			
		||||
struct dm_list *dm_list_first(const struct dm_list *head);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return last element of the list or NULL if empty
 | 
			
		||||
 */
 | 
			
		||||
struct dm_list *dm_list_last(const struct dm_list *head);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the previous element of the list, or NULL if we've reached the start.
 | 
			
		||||
 */
 | 
			
		||||
struct dm_list *dm_list_prev(const struct dm_list *head, const struct dm_list *elem);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the next element of the list, or NULL if we've reached the end.
 | 
			
		||||
 */
 | 
			
		||||
struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *elem);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Given the address v of an instance of 'struct dm_list' called 'head'
 | 
			
		||||
 * contained in a structure of type t, return the containing structure.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_struct_base(v, t, head) \
 | 
			
		||||
    container_of(v, t, head)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Given the address v of an instance of 'struct dm_list list' contained in
 | 
			
		||||
 * a structure of type t, return the containing structure.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_item(v, t) dm_list_struct_base((v), t, list)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Given the address v of one known element e in a known structure of type t,
 | 
			
		||||
 * return another element f.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_struct_field(v, t, e, f) \
 | 
			
		||||
    (((t *)((uintptr_t)(v) - offsetof(t, e)))->f)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Given the address v of a known element e in a known structure of type t,
 | 
			
		||||
 * return the list head 'list'
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_head(v, t, e) dm_struct_field(v, t, e, list)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set v to each element of a list in turn.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_iterate(v, head) \
 | 
			
		||||
	for (v = (head)->n; v != head; v = v->n)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set v to each element in a list in turn, starting from the element
 | 
			
		||||
 * in front of 'start'.
 | 
			
		||||
 * You can use this to 'unwind' a list_iterate and back out actions on
 | 
			
		||||
 * already-processed elements.
 | 
			
		||||
 * If 'start' is 'head' it walks the list backwards.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_uniterate(v, head, start) \
 | 
			
		||||
	for (v = (start)->p; v != head; v = v->p)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * A safe way to walk a list and delete and free some elements along
 | 
			
		||||
 * the way.
 | 
			
		||||
 * t must be defined as a temporary variable of the same type as v.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_iterate_safe(v, t, head) \
 | 
			
		||||
	for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Walk a list, setting 'v' in turn to the containing structure of each item.
 | 
			
		||||
 * The containing structure should be the same type as 'v'.
 | 
			
		||||
 * The 'struct dm_list' variable within the containing structure is 'field'.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_iterate_items_gen(v, head, field) \
 | 
			
		||||
	for (v = dm_list_struct_base((head)->n, __typeof__(*v), field); \
 | 
			
		||||
	     &v->field != (head); \
 | 
			
		||||
	     v = dm_list_struct_base(v->field.n, __typeof__(*v), field))
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Walk a list, setting 'v' in turn to the containing structure of each item.
 | 
			
		||||
 * The containing structure should be the same type as 'v'.
 | 
			
		||||
 * The list should be 'struct dm_list list' within the containing structure.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_iterate_items(v, head) dm_list_iterate_items_gen(v, (head), list)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Walk a list, setting 'v' in turn to the containing structure of each item.
 | 
			
		||||
 * The containing structure should be the same type as 'v'.
 | 
			
		||||
 * The 'struct dm_list' variable within the containing structure is 'field'.
 | 
			
		||||
 * t must be defined as a temporary variable of the same type as v.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_iterate_items_gen_safe(v, t, head, field) \
 | 
			
		||||
	for (v = dm_list_struct_base((head)->n, __typeof__(*v), field), \
 | 
			
		||||
	     t = dm_list_struct_base(v->field.n, __typeof__(*v), field); \
 | 
			
		||||
	     &v->field != (head); \
 | 
			
		||||
	     v = t, t = dm_list_struct_base(v->field.n, __typeof__(*v), field))
 | 
			
		||||
/*
 | 
			
		||||
 * Walk a list, setting 'v' in turn to the containing structure of each item.
 | 
			
		||||
 * The containing structure should be the same type as 'v'.
 | 
			
		||||
 * The list should be 'struct dm_list list' within the containing structure.
 | 
			
		||||
 * t must be defined as a temporary variable of the same type as v.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_iterate_items_safe(v, t, head) \
 | 
			
		||||
	dm_list_iterate_items_gen_safe(v, t, (head), list)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Walk a list backwards, setting 'v' in turn to the containing structure
 | 
			
		||||
 * of each item.
 | 
			
		||||
 * The containing structure should be the same type as 'v'.
 | 
			
		||||
 * The 'struct dm_list' variable within the containing structure is 'field'.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_iterate_back_items_gen(v, head, field) \
 | 
			
		||||
	for (v = dm_list_struct_base((head)->p, __typeof__(*v), field); \
 | 
			
		||||
	     &v->field != (head); \
 | 
			
		||||
	     v = dm_list_struct_base(v->field.p, __typeof__(*v), field))
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Walk a list backwards, setting 'v' in turn to the containing structure
 | 
			
		||||
 * of each item.
 | 
			
		||||
 * The containing structure should be the same type as 'v'.
 | 
			
		||||
 * The list should be 'struct dm_list list' within the containing structure.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_list_iterate_back_items(v, head) dm_list_iterate_back_items_gen(v, (head), list)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the number of elements in a list by walking it.
 | 
			
		||||
 */
 | 
			
		||||
unsigned int dm_list_size(const struct dm_list *head);
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,256 +0,0 @@
 | 
			
		||||
// 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,
 | 
			
		||||
// modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
// of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
// along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 | 
			
		||||
#include "radix-tree.h"
 | 
			
		||||
 | 
			
		||||
#include "base/memory/container_of.h"
 | 
			
		||||
#include "base/memory/zalloc.h"
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
// This implementation is based around nested binary trees.  Very
 | 
			
		||||
// simple (and hopefully correct).
 | 
			
		||||
 | 
			
		||||
struct node {
 | 
			
		||||
	struct node *left;
 | 
			
		||||
	struct node *right;
 | 
			
		||||
 | 
			
		||||
	uint8_t key;
 | 
			
		||||
	struct node *center;
 | 
			
		||||
 | 
			
		||||
	bool has_value;
 | 
			
		||||
	union radix_value value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct radix_tree {
 | 
			
		||||
	radix_value_dtr dtr;
 | 
			
		||||
	void *dtr_context;
 | 
			
		||||
 | 
			
		||||
	struct node *root;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct radix_tree *
 | 
			
		||||
radix_tree_create(radix_value_dtr dtr, void *dtr_context)
 | 
			
		||||
{
 | 
			
		||||
	struct radix_tree *rt = zalloc(sizeof(*rt));
 | 
			
		||||
 | 
			
		||||
	if (rt) {
 | 
			
		||||
		rt->dtr = dtr;
 | 
			
		||||
		rt->dtr_context = dtr_context;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns the number of entries in the tree
 | 
			
		||||
static unsigned _destroy_tree(struct node *n, radix_value_dtr dtr, void *context)
 | 
			
		||||
{
 | 
			
		||||
	unsigned r;
 | 
			
		||||
 | 
			
		||||
	if (!n)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	r = _destroy_tree(n->left, dtr, context);
 | 
			
		||||
	r += _destroy_tree(n->right, dtr, context);
 | 
			
		||||
	r += _destroy_tree(n->center, dtr, context);
 | 
			
		||||
 | 
			
		||||
	if (n->has_value) {
 | 
			
		||||
		if (dtr)
 | 
			
		||||
			dtr(context, n->value);
 | 
			
		||||
		r++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	free(n);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void radix_tree_destroy(struct radix_tree *rt)
 | 
			
		||||
{
 | 
			
		||||
	_destroy_tree(rt->root, rt->dtr, rt->dtr_context);
 | 
			
		||||
	free(rt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned _count(struct node *n)
 | 
			
		||||
{
 | 
			
		||||
	unsigned r;
 | 
			
		||||
 | 
			
		||||
	if (!n)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	r = _count(n->left);
 | 
			
		||||
	r += _count(n->right);
 | 
			
		||||
	r += _count(n->center);
 | 
			
		||||
 | 
			
		||||
	if (n->has_value)
 | 
			
		||||
		r++;
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned radix_tree_size(struct radix_tree *rt)
 | 
			
		||||
{
 | 
			
		||||
	return _count(rt->root);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct node **_lookup(struct node **pn, uint8_t *kb, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
	struct node *n = *pn;
 | 
			
		||||
 | 
			
		||||
	if (!n || (kb == ke))
 | 
			
		||||
		return pn;
 | 
			
		||||
 | 
			
		||||
	if (*kb < n->key)
 | 
			
		||||
		return _lookup(&n->left, kb, ke);
 | 
			
		||||
 | 
			
		||||
	else if (*kb > n->key)
 | 
			
		||||
		return _lookup(&n->right, kb, ke);
 | 
			
		||||
 | 
			
		||||
	else
 | 
			
		||||
		return _lookup(&n->center, kb + 1, ke);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _insert(struct node **pn, uint8_t *kb, uint8_t *ke, union radix_value v)
 | 
			
		||||
{
 | 
			
		||||
	struct node *n = *pn;
 | 
			
		||||
 | 
			
		||||
	if (!n) {
 | 
			
		||||
		n = zalloc(sizeof(*n));
 | 
			
		||||
		if (!n)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		n->key = *kb;
 | 
			
		||||
		*pn = n;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (kb == ke) {
 | 
			
		||||
		n->has_value = true;
 | 
			
		||||
		n->value = v;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (*kb < n->key)
 | 
			
		||||
		return _insert(&n->left, kb, ke, v);
 | 
			
		||||
 | 
			
		||||
	else if (*kb > n->key)
 | 
			
		||||
		return _insert(&n->right, kb, ke, v);
 | 
			
		||||
 | 
			
		||||
	else
 | 
			
		||||
		return _insert(&n->center, kb + 1, ke, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v)
 | 
			
		||||
{
 | 
			
		||||
	return _insert(&rt->root, kb, ke, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
	struct node **pn = _lookup(&rt->root, kb, ke);
 | 
			
		||||
	struct node *n = *pn;
 | 
			
		||||
 | 
			
		||||
	if (!n || !n->has_value)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	else {
 | 
			
		||||
		if (rt->dtr)
 | 
			
		||||
			rt->dtr(rt->dtr_context, n->value);
 | 
			
		||||
 | 
			
		||||
		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;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
	struct node **pn;
 | 
			
		||||
	unsigned count;
 | 
			
		||||
 | 
			
		||||
	pn = _lookup(&rt->root, kb, ke);
 | 
			
		||||
 | 
			
		||||
	if (*pn) {
 | 
			
		||||
		count = _destroy_tree(*pn, rt->dtr, rt->dtr_context);
 | 
			
		||||
		*pn = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
radix_tree_lookup(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value *result)
 | 
			
		||||
{
 | 
			
		||||
	struct node **pn = _lookup(&rt->root, kb, ke);
 | 
			
		||||
	struct node *n = *pn;
 | 
			
		||||
 | 
			
		||||
	if (n && n->has_value) {
 | 
			
		||||
		*result = n->value;
 | 
			
		||||
		return true;
 | 
			
		||||
	} else
 | 
			
		||||
		return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _iterate(struct node *n, struct radix_tree_iterator *it)
 | 
			
		||||
{
 | 
			
		||||
	if (!n)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	_iterate(n->left, it);
 | 
			
		||||
 | 
			
		||||
	if (n->has_value)
 | 
			
		||||
		// FIXME: fill out the key
 | 
			
		||||
		it->visit(it, NULL, NULL, n->value);
 | 
			
		||||
 | 
			
		||||
	_iterate(n->center, it);
 | 
			
		||||
	_iterate(n->right, it);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
 | 
			
		||||
                        struct radix_tree_iterator *it)
 | 
			
		||||
{
 | 
			
		||||
	if (kb == ke)
 | 
			
		||||
		_iterate(rt->root, it);
 | 
			
		||||
 | 
			
		||||
	else {
 | 
			
		||||
		struct node **pn = _lookup(&rt->root, kb, ke);
 | 
			
		||||
		struct node *n = *pn;
 | 
			
		||||
 | 
			
		||||
		if (n) {
 | 
			
		||||
			if (n->has_value)
 | 
			
		||||
				it->visit(it, NULL, NULL, n->value);
 | 
			
		||||
			_iterate(n->center, it);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_is_well_formed(struct radix_tree *rt)
 | 
			
		||||
{
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void radix_tree_dump(struct radix_tree *rt, FILE *out)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
@@ -10,12 +10,853 @@
 | 
			
		||||
// along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
#include "radix-tree.h"
 | 
			
		||||
 | 
			
		||||
#ifdef SIMPLE_RADIX_TREE
 | 
			
		||||
#include "base/data-struct/radix-tree-simple.c"
 | 
			
		||||
#else
 | 
			
		||||
#include "base/data-struct/radix-tree-adaptive.c"
 | 
			
		||||
#endif
 | 
			
		||||
#include "base/memory/container_of.h"
 | 
			
		||||
#include "base/memory/zalloc.h"
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
enum node_type {
 | 
			
		||||
	UNSET = 0,
 | 
			
		||||
	VALUE,
 | 
			
		||||
	VALUE_CHAIN,
 | 
			
		||||
	PREFIX_CHAIN,
 | 
			
		||||
	NODE4,
 | 
			
		||||
	NODE16,
 | 
			
		||||
	NODE48,
 | 
			
		||||
	NODE256
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct value {
 | 
			
		||||
	enum node_type type;
 | 
			
		||||
	union radix_value value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// This is used for entries that have a key which is a prefix of another key.
 | 
			
		||||
struct value_chain {
 | 
			
		||||
	union radix_value value;
 | 
			
		||||
	struct value child;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct prefix_chain {
 | 
			
		||||
	struct value child;
 | 
			
		||||
	unsigned len;
 | 
			
		||||
	uint8_t prefix[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct node4 {
 | 
			
		||||
	uint32_t nr_entries;
 | 
			
		||||
	uint8_t keys[4];
 | 
			
		||||
	struct value values[4];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct node16 {
 | 
			
		||||
	uint32_t nr_entries;
 | 
			
		||||
	uint8_t keys[16];
 | 
			
		||||
	struct value values[16];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct node48 {
 | 
			
		||||
	uint32_t nr_entries;
 | 
			
		||||
	uint8_t keys[256];
 | 
			
		||||
	struct value values[48];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct node256 {
 | 
			
		||||
        uint32_t nr_entries;
 | 
			
		||||
	struct value values[256];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct radix_tree {
 | 
			
		||||
	unsigned nr_entries;
 | 
			
		||||
	struct value root;
 | 
			
		||||
	radix_value_dtr dtr;
 | 
			
		||||
	void *dtr_context;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context)
 | 
			
		||||
{
 | 
			
		||||
	struct radix_tree *rt = malloc(sizeof(*rt));
 | 
			
		||||
 | 
			
		||||
	if (rt) {
 | 
			
		||||
		rt->nr_entries = 0;
 | 
			
		||||
		rt->root.type = UNSET;
 | 
			
		||||
		rt->dtr = dtr;
 | 
			
		||||
		rt->dtr_context = dtr_context;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void _dtr(struct radix_tree *rt, union radix_value v)
 | 
			
		||||
{
 | 
			
		||||
	if (rt->dtr)
 | 
			
		||||
        	rt->dtr(rt->dtr_context, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns the number of values removed
 | 
			
		||||
static unsigned _free_node(struct radix_tree *rt, struct value v)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i, nr = 0;
 | 
			
		||||
	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:
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case VALUE:
 | 
			
		||||
        	_dtr(rt, v.value);
 | 
			
		||||
        	nr = 1;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case VALUE_CHAIN:
 | 
			
		||||
		vc = v.value.ptr;
 | 
			
		||||
		_dtr(rt, vc->value);
 | 
			
		||||
		nr = 1 + _free_node(rt, vc->child);
 | 
			
		||||
		free(vc);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case PREFIX_CHAIN:
 | 
			
		||||
		pc = v.value.ptr;
 | 
			
		||||
		nr = _free_node(rt, pc->child);
 | 
			
		||||
		free(pc);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case NODE4:
 | 
			
		||||
		n4 = (struct node4 *) v.value.ptr;
 | 
			
		||||
		for (i = 0; i < n4->nr_entries; i++)
 | 
			
		||||
			nr += _free_node(rt, n4->values[i]);
 | 
			
		||||
		free(n4);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case NODE16:
 | 
			
		||||
		n16 = (struct node16 *) v.value.ptr;
 | 
			
		||||
		for (i = 0; i < n16->nr_entries; i++)
 | 
			
		||||
			nr += _free_node(rt, n16->values[i]);
 | 
			
		||||
		free(n16);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case NODE48:
 | 
			
		||||
		n48 = (struct node48 *) v.value.ptr;
 | 
			
		||||
		for (i = 0; i < n48->nr_entries; i++)
 | 
			
		||||
			nr += _free_node(rt, n48->values[i]);
 | 
			
		||||
		free(n48);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case NODE256:
 | 
			
		||||
		n256 = (struct node256 *) v.value.ptr;
 | 
			
		||||
		for (i = 0; i < 256; i++)
 | 
			
		||||
			nr += _free_node(rt, n256->values[i]);
 | 
			
		||||
		free(n256);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void radix_tree_destroy(struct radix_tree *rt)
 | 
			
		||||
{
 | 
			
		||||
	_free_node(rt, rt->root);
 | 
			
		||||
	free(rt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned radix_tree_size(struct radix_tree *rt)
 | 
			
		||||
{
 | 
			
		||||
	return rt->nr_entries;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	unsigned len = ke - kb;
 | 
			
		||||
 | 
			
		||||
	if (!len) {
 | 
			
		||||
		// value
 | 
			
		||||
		v->type = VALUE;
 | 
			
		||||
		v->value = rv;
 | 
			
		||||
		rt->nr_entries++;
 | 
			
		||||
	} else {
 | 
			
		||||
		// prefix -> value
 | 
			
		||||
		struct prefix_chain *pc = zalloc(sizeof(*pc) + len);
 | 
			
		||||
		if (!pc)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		pc->child.type = VALUE;
 | 
			
		||||
		pc->child.value = rv;
 | 
			
		||||
		pc->len = len;
 | 
			
		||||
		memcpy(pc->prefix, kb, len);
 | 
			
		||||
		v->type = PREFIX_CHAIN;
 | 
			
		||||
		v->value.ptr = pc;
 | 
			
		||||
		rt->nr_entries++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
	if (!len)
 | 
			
		||||
		// overwrite
 | 
			
		||||
		v->value = rv;
 | 
			
		||||
 | 
			
		||||
	else {
 | 
			
		||||
		// value_chain -> value
 | 
			
		||||
		struct value_chain *vc = zalloc(sizeof(*vc));
 | 
			
		||||
		if (!vc)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		vc->value = v->value;
 | 
			
		||||
		if (!_insert(rt, &vc->child, kb, ke, rv)) {
 | 
			
		||||
			free(vc);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		v->type = VALUE_CHAIN;
 | 
			
		||||
		v->value.ptr = vc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned min(unsigned lhs, unsigned rhs)
 | 
			
		||||
{
 | 
			
		||||
	if (lhs <= rhs)
 | 
			
		||||
		return lhs;
 | 
			
		||||
	else
 | 
			
		||||
		return rhs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
	if (*kb == pc->prefix[0]) {
 | 
			
		||||
		// There's a common prefix let's split the chain into two and
 | 
			
		||||
		// recurse.
 | 
			
		||||
		struct prefix_chain *pc2;
 | 
			
		||||
		unsigned i, len = min(pc->len, ke - kb);
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < len; i++)
 | 
			
		||||
			if (kb[i] != pc->prefix[i])
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
		pc2 = zalloc(sizeof(*pc2) + pc->len - i);
 | 
			
		||||
		pc2->len = pc->len - i;
 | 
			
		||||
		memmove(pc2->prefix, pc->prefix + i, pc2->len);
 | 
			
		||||
		pc2->child = pc->child;
 | 
			
		||||
 | 
			
		||||
		// FIXME: this trashes pc so we can't back out
 | 
			
		||||
		pc->child.type = PREFIX_CHAIN;
 | 
			
		||||
		pc->child.value.ptr = pc2;
 | 
			
		||||
		pc->len = i;
 | 
			
		||||
 | 
			
		||||
		if (!_insert(rt, &pc->child, kb + i, ke, rv)) {
 | 
			
		||||
			free(pc2);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		// Stick an n4 in front.
 | 
			
		||||
		struct node4 *n4 = zalloc(sizeof(*n4));
 | 
			
		||||
		if (!n4)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		n4->keys[0] = *kb;
 | 
			
		||||
		if (!_insert(rt, n4->values, kb + 1, ke, rv)) {
 | 
			
		||||
			free(n4);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (pc->len) {
 | 
			
		||||
			n4->keys[1] = pc->prefix[0];
 | 
			
		||||
			if (pc->len == 1) {
 | 
			
		||||
				n4->values[1] = pc->child;
 | 
			
		||||
				free(pc);
 | 
			
		||||
			} else {
 | 
			
		||||
				memmove(pc->prefix, pc->prefix + 1, pc->len - 1);
 | 
			
		||||
				pc->len--;
 | 
			
		||||
				n4->values[1] = *v;
 | 
			
		||||
			}
 | 
			
		||||
			n4->nr_entries = 2;
 | 
			
		||||
		} else
 | 
			
		||||
			n4->nr_entries = 1;
 | 
			
		||||
 | 
			
		||||
		v->type = NODE4;
 | 
			
		||||
		v->value.ptr = n4;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
		struct node16 *n16 = zalloc(sizeof(*n16));
 | 
			
		||||
		if (!n16)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		n16->nr_entries = 5;
 | 
			
		||||
		memcpy(n16->keys, n4->keys, sizeof(n4->keys));
 | 
			
		||||
		memcpy(n16->values, n4->values, sizeof(n4->values));
 | 
			
		||||
 | 
			
		||||
		n16->keys[4] = *kb;
 | 
			
		||||
		if (!_insert(rt, n16->values + 4, kb + 1, ke, rv)) {
 | 
			
		||||
			free(n16);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		free(n4);
 | 
			
		||||
		v->type = NODE16;
 | 
			
		||||
		v->value.ptr = n16;
 | 
			
		||||
	} else {
 | 
			
		||||
		n4 = v->value.ptr;
 | 
			
		||||
		if (!_insert(rt, n4->values + n4->nr_entries, kb + 1, ke, rv))
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		n4->keys[n4->nr_entries] = *kb;
 | 
			
		||||
		n4->nr_entries++;
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
	if (n16->nr_entries == 16) {
 | 
			
		||||
		unsigned i;
 | 
			
		||||
		struct node48 *n48 = zalloc(sizeof(*n48));
 | 
			
		||||
 | 
			
		||||
		if (!n48)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		n48->nr_entries = 17;
 | 
			
		||||
		memset(n48->keys, 48, sizeof(n48->keys));
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < 16; i++) {
 | 
			
		||||
			n48->keys[n16->keys[i]] = i;
 | 
			
		||||
			n48->values[i] = n16->values[i];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		n48->keys[*kb] = 16;
 | 
			
		||||
		if (!_insert(rt, n48->values + 16, kb + 1, ke, rv)) {
 | 
			
		||||
			free(n48);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		free(n16);
 | 
			
		||||
		v->type = NODE48;
 | 
			
		||||
		v->value.ptr = n48;
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!_insert(rt, n16->values + n16->nr_entries, kb + 1, ke, rv))
 | 
			
		||||
			return false;
 | 
			
		||||
		n16->keys[n16->nr_entries] = *kb;
 | 
			
		||||
		n16->nr_entries++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
		unsigned i;
 | 
			
		||||
		struct node256 *n256 = zalloc(sizeof(*n256));
 | 
			
		||||
		if (!n256)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < 256; i++) {
 | 
			
		||||
			if (n48->keys[i] >= 48)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			n256->values[i] = n48->values[n48->keys[i]];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!_insert(rt, n256->values + *kb, kb + 1, ke, rv)) {
 | 
			
		||||
			free(n256);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		free(n48);
 | 
			
		||||
		v->type = NODE256;
 | 
			
		||||
		v->value.ptr = n256;
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!_insert(rt, n48->values + n48->nr_entries, kb + 1, ke, rv))
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		n48->keys[*kb] = n48->nr_entries;
 | 
			
		||||
		n48->nr_entries++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 was_unset = n256->values[*kb].type == UNSET;
 | 
			
		||||
 | 
			
		||||
	if (!_insert(rt, n256->values + *kb, kb + 1, ke, rv))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (was_unset)
 | 
			
		||||
        	n256->nr_entries++;
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FIXME: the tree should not be touched if insert fails (eg, OOM)
 | 
			
		||||
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) {
 | 
			
		||||
			v->type = VALUE;
 | 
			
		||||
			v->value = rv;
 | 
			
		||||
			rt->nr_entries++;
 | 
			
		||||
 | 
			
		||||
		} else if (v->type == VALUE) {
 | 
			
		||||
			v->value = rv;
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
			struct value_chain *vc = zalloc(sizeof(*vc));
 | 
			
		||||
			if (!vc)
 | 
			
		||||
				return false;
 | 
			
		||||
 | 
			
		||||
			vc->value = rv;
 | 
			
		||||
			vc->child = *v;
 | 
			
		||||
			v->type = VALUE_CHAIN;
 | 
			
		||||
			v->value.ptr = vc;
 | 
			
		||||
			rt->nr_entries++;
 | 
			
		||||
		}
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (v->type) {
 | 
			
		||||
	case UNSET:
 | 
			
		||||
		return _insert_unset(rt, v, kb, ke, rv);
 | 
			
		||||
 | 
			
		||||
	case VALUE:
 | 
			
		||||
		return _insert_value(rt, v, kb, ke, rv);
 | 
			
		||||
 | 
			
		||||
	case VALUE_CHAIN:
 | 
			
		||||
		return _insert_value_chain(rt, v, kb, ke, rv);
 | 
			
		||||
 | 
			
		||||
	case PREFIX_CHAIN:
 | 
			
		||||
		return _insert_prefix_chain(rt, v, kb, ke, rv);
 | 
			
		||||
 | 
			
		||||
	case NODE4:
 | 
			
		||||
		return _insert_node4(rt, v, kb, ke, rv);
 | 
			
		||||
 | 
			
		||||
	case NODE16:
 | 
			
		||||
		return _insert_node16(rt, v, kb, ke, rv);
 | 
			
		||||
 | 
			
		||||
	case NODE48:
 | 
			
		||||
		return _insert_node48(rt, v, kb, ke, rv);
 | 
			
		||||
 | 
			
		||||
	case NODE256:
 | 
			
		||||
		return _insert_node256(rt, v, kb, ke, rv);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// can't get here
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct lookup_result {
 | 
			
		||||
	struct value *v;
 | 
			
		||||
	uint8_t *kb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct lookup_result _lookup_prefix(struct value *v, uint8_t *kb, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i;
 | 
			
		||||
	struct value_chain *vc;
 | 
			
		||||
	struct prefix_chain *pc;
 | 
			
		||||
	struct node4 *n4;
 | 
			
		||||
	struct node16 *n16;
 | 
			
		||||
	struct node48 *n48;
 | 
			
		||||
	struct node256 *n256;
 | 
			
		||||
 | 
			
		||||
	if (kb == ke)
 | 
			
		||||
		return (struct lookup_result) {.v = v, .kb = kb};
 | 
			
		||||
 | 
			
		||||
	switch (v->type) {
 | 
			
		||||
	case UNSET:
 | 
			
		||||
	case VALUE:
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case VALUE_CHAIN:
 | 
			
		||||
		vc = v->value.ptr;
 | 
			
		||||
		return _lookup_prefix(&vc->child, kb, ke);
 | 
			
		||||
 | 
			
		||||
	case PREFIX_CHAIN:
 | 
			
		||||
		pc = v->value.ptr;
 | 
			
		||||
		if (ke - kb < pc->len)
 | 
			
		||||
			return (struct lookup_result) {.v = v, .kb = kb};
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < pc->len; i++)
 | 
			
		||||
			if (kb[i] != pc->prefix[i])
 | 
			
		||||
				return (struct lookup_result) {.v = v, .kb = kb};
 | 
			
		||||
 | 
			
		||||
		return _lookup_prefix(&pc->child, kb + pc->len, ke);
 | 
			
		||||
 | 
			
		||||
	case NODE4:
 | 
			
		||||
		n4 = v->value.ptr;
 | 
			
		||||
		for (i = 0; i < n4->nr_entries; i++)
 | 
			
		||||
			if (n4->keys[i] == *kb)
 | 
			
		||||
				return _lookup_prefix(n4->values + i, kb + 1, ke);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case NODE16:
 | 
			
		||||
		// FIXME: use binary search or simd?
 | 
			
		||||
		n16 = v->value.ptr;
 | 
			
		||||
		for (i = 0; i < n16->nr_entries; i++)
 | 
			
		||||
			if (n16->keys[i] == *kb)
 | 
			
		||||
				return _lookup_prefix(n16->values + i, kb + 1, ke);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case NODE48:
 | 
			
		||||
		n48 = v->value.ptr;
 | 
			
		||||
		i = n48->keys[*kb];
 | 
			
		||||
		if (i < 48)
 | 
			
		||||
			return _lookup_prefix(n48->values + i, kb + 1, ke);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case NODE256:
 | 
			
		||||
		n256 = v->value.ptr;
 | 
			
		||||
		return _lookup_prefix(n256->values + *kb, kb + 1, ke);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (struct lookup_result) {.v = v, .kb = kb};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value rv)
 | 
			
		||||
{
 | 
			
		||||
	struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
 | 
			
		||||
	return _insert(rt, lr.v, lr.kb, ke, rv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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));
 | 
			
		||||
 | 
			
		||||
        n4->nr_entries = n16->nr_entries;
 | 
			
		||||
        memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys));
 | 
			
		||||
        memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values));
 | 
			
		||||
        free(n16);
 | 
			
		||||
 | 
			
		||||
	result->type = NODE4;
 | 
			
		||||
	result->value.ptr = n4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _degrade_to_n16(struct node48 *n48, struct value *result)
 | 
			
		||||
{
 | 
			
		||||
        struct node4 *n16 = zalloc(sizeof(*n16));
 | 
			
		||||
 | 
			
		||||
        n16->nr_entries = n48->nr_entries;
 | 
			
		||||
        memcpy(n16->keys, n48->keys, n48->nr_entries * sizeof(*n16->keys));
 | 
			
		||||
        memcpy(n16->values, n48->values, n48->nr_entries * sizeof(*n16->values));
 | 
			
		||||
        free(n48);
 | 
			
		||||
 | 
			
		||||
	result->type = NODE16;
 | 
			
		||||
	result->value.ptr = n16;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _degrade_to_n48(struct node256 *n256, struct value *result)
 | 
			
		||||
{
 | 
			
		||||
        unsigned i, count = 0;
 | 
			
		||||
        struct node4 *n48 = zalloc(sizeof(*n48));
 | 
			
		||||
 | 
			
		||||
        n48->nr_entries = n256->nr_entries;
 | 
			
		||||
        for (i = 0; i < 256; i++) {
 | 
			
		||||
		if (n256->values[i].type == UNSET)
 | 
			
		||||
        		continue;
 | 
			
		||||
 | 
			
		||||
		n48->keys[count] = i;
 | 
			
		||||
		n48->values[count] = n256->values[i];
 | 
			
		||||
		count++;
 | 
			
		||||
        }
 | 
			
		||||
        free(n256);
 | 
			
		||||
 | 
			
		||||
	result->type = NODE48;
 | 
			
		||||
	result->value.ptr = n48;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _remove(struct radix_tree *rt, struct value *root, uint8_t *kb, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
	bool r;
 | 
			
		||||
	unsigned i;
 | 
			
		||||
	struct value_chain *vc;
 | 
			
		||||
	struct prefix_chain *pc;
 | 
			
		||||
	struct node4 *n4;
 | 
			
		||||
	struct node16 *n16;
 | 
			
		||||
	struct node48 *n48;
 | 
			
		||||
	struct node256 *n256;
 | 
			
		||||
 | 
			
		||||
	if (kb == ke) {
 | 
			
		||||
        	if (root->type == VALUE) {
 | 
			
		||||
                	root->type = UNSET;
 | 
			
		||||
                	_dtr(rt, root->value);
 | 
			
		||||
                	return true;
 | 
			
		||||
 | 
			
		||||
                } 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
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (root->type) {
 | 
			
		||||
	case UNSET:
 | 
			
		||||
	case VALUE:
 | 
			
		||||
        	// this is a value for a prefix of the key
 | 
			
		||||
        	return false;
 | 
			
		||||
 | 
			
		||||
	case VALUE_CHAIN:
 | 
			
		||||
		vc = root->value.ptr;
 | 
			
		||||
		r = _remove(rt, &vc->child, kb, ke);
 | 
			
		||||
		if (r && (vc->child.type == UNSET)) {
 | 
			
		||||
			memcpy(root, &vc->child, sizeof(*root));
 | 
			
		||||
			free(vc);
 | 
			
		||||
		}
 | 
			
		||||
		return r;
 | 
			
		||||
 | 
			
		||||
	case PREFIX_CHAIN:
 | 
			
		||||
		pc = root->value.ptr;
 | 
			
		||||
		if (ke - kb < pc->len)
 | 
			
		||||
        		return false;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < pc->len; i++)
 | 
			
		||||
			if (kb[i] != pc->prefix[i])
 | 
			
		||||
        			return false;
 | 
			
		||||
 | 
			
		||||
		return _remove(rt, &pc->child, kb + pc->len, ke);
 | 
			
		||||
 | 
			
		||||
	case NODE4:
 | 
			
		||||
		n4 = root->value.ptr;
 | 
			
		||||
		for (i = 0; i < n4->nr_entries; i++) {
 | 
			
		||||
			if (n4->keys[i] == *kb) {
 | 
			
		||||
				r = _remove(rt, n4->values + i, kb + 1, ke);
 | 
			
		||||
				if (r && n4->values[i].type == UNSET) {
 | 
			
		||||
        				n4->nr_entries--;
 | 
			
		||||
        				if (i < n4->nr_entries)
 | 
			
		||||
                				// slide the entries down
 | 
			
		||||
        					memmove(n4->keys + i, n4->keys + i + 1,
 | 
			
		||||
                                                       sizeof(*n4->keys) * (n4->nr_entries - i));
 | 
			
		||||
					if (!n4->nr_entries)
 | 
			
		||||
						root->type = UNSET;
 | 
			
		||||
				}
 | 
			
		||||
				return r;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	case NODE16:
 | 
			
		||||
        	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) {
 | 
			
		||||
        				n16->nr_entries--;
 | 
			
		||||
        				if (i < n16->nr_entries)
 | 
			
		||||
                				// slide the entries down
 | 
			
		||||
        					memmove(n16->keys + i, n16->keys + i + 1,
 | 
			
		||||
                                                        sizeof(*n16->keys) * (n16->nr_entries - i));
 | 
			
		||||
					if (n16->nr_entries <= 4)
 | 
			
		||||
        					_degrade_to_n4(n16, root);
 | 
			
		||||
				}
 | 
			
		||||
				return r;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	case NODE48:
 | 
			
		||||
		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;
 | 
			
		||||
				n48->nr_entries--;
 | 
			
		||||
				if (n48->nr_entries <= 16)
 | 
			
		||||
        				_degrade_to_n16(n48, root);
 | 
			
		||||
        		}
 | 
			
		||||
        		return r;
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	case NODE256:
 | 
			
		||||
		n256 = root->value.ptr;
 | 
			
		||||
		r = _remove(rt, n256->values + (*kb), kb + 1, ke);
 | 
			
		||||
		if (r && n256->values[*kb].type == UNSET) {
 | 
			
		||||
			n256->nr_entries--;
 | 
			
		||||
			if (n256->nr_entries <= 48)
 | 
			
		||||
        			_degrade_to_n48(n256, root);
 | 
			
		||||
		}
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_remove(struct radix_tree *rt, uint8_t *key_begin, uint8_t *key_end)
 | 
			
		||||
{
 | 
			
		||||
	if (_remove(rt, &rt->root, key_begin, key_end)) {
 | 
			
		||||
        	rt->nr_entries--;
 | 
			
		||||
        	return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
                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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
 | 
			
		||||
{
 | 
			
		||||
        unsigned count = 0;
 | 
			
		||||
	struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
 | 
			
		||||
	if (lr.kb == ke || _prefix_chain_matches(&lr, ke)) {
 | 
			
		||||
        	count = _free_node(rt, *lr.v);
 | 
			
		||||
        	lr.v->type = UNSET;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rt->nr_entries -= count;
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool radix_tree_lookup(struct radix_tree *rt,
 | 
			
		||||
		       uint8_t *kb, uint8_t *ke, union radix_value *result)
 | 
			
		||||
{
 | 
			
		||||
	struct value_chain *vc;
 | 
			
		||||
	struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
 | 
			
		||||
	if (lr.kb == ke) {
 | 
			
		||||
		switch (lr.v->type) {
 | 
			
		||||
		case VALUE:
 | 
			
		||||
			*result = lr.v->value;
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
		case VALUE_CHAIN:
 | 
			
		||||
			vc = lr.v->value.ptr;
 | 
			
		||||
			*result = vc->value;
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FIXME: build up the keys too
 | 
			
		||||
static bool _iterate(struct value *v, struct radix_tree_iterator *it)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i;
 | 
			
		||||
	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
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case VALUE:
 | 
			
		||||
        	return it->visit(it, NULL, NULL, v->value);
 | 
			
		||||
 | 
			
		||||
	case VALUE_CHAIN:
 | 
			
		||||
		vc = v->value.ptr;
 | 
			
		||||
		return it->visit(it, NULL, NULL, vc->value) && _iterate(&vc->child, it);
 | 
			
		||||
 | 
			
		||||
	case PREFIX_CHAIN:
 | 
			
		||||
		pc = v->value.ptr;
 | 
			
		||||
		return _iterate(&pc->child, it);
 | 
			
		||||
 | 
			
		||||
	case NODE4:
 | 
			
		||||
		n4 = (struct node4 *) v->value.ptr;
 | 
			
		||||
		for (i = 0; i < n4->nr_entries; i++)
 | 
			
		||||
			if (!_iterate(n4->values + i, it))
 | 
			
		||||
        			return false;
 | 
			
		||||
        	return true;
 | 
			
		||||
 | 
			
		||||
	case NODE16:
 | 
			
		||||
		n16 = (struct node16 *) v->value.ptr;
 | 
			
		||||
		for (i = 0; i < n16->nr_entries; i++)
 | 
			
		||||
        		if (!_iterate(n16->values + i, it))
 | 
			
		||||
        			return false;
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	case NODE48:
 | 
			
		||||
		n48 = (struct node48 *) v->value.ptr;
 | 
			
		||||
		for (i = 0; i < n48->nr_entries; i++)
 | 
			
		||||
        		if (!_iterate(n48->values + i, it))
 | 
			
		||||
        			return false;
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	case NODE256:
 | 
			
		||||
		n256 = (struct node256 *) v->value.ptr;
 | 
			
		||||
		for (i = 0; i < 256; i++)
 | 
			
		||||
        		if (n256->values[i].type != UNSET && !_iterate(n256->values + i, it))
 | 
			
		||||
        			return false;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// can't get here
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
 | 
			
		||||
                        struct radix_tree_iterator *it)
 | 
			
		||||
{
 | 
			
		||||
	struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
 | 
			
		||||
	if (lr.kb == ke || _prefix_chain_matches(&lr, ke))
 | 
			
		||||
        	_iterate(lr.v, it);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,6 @@
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
@@ -54,11 +53,6 @@ struct radix_tree_iterator {
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
// Copyright (C) 2018 - 2020 Red Hat, Inc. All rights reserved.
 | 
			
		||||
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
 | 
			
		||||
// 
 | 
			
		||||
// This file is part of LVM2.
 | 
			
		||||
//
 | 
			
		||||
@@ -13,12 +13,10 @@
 | 
			
		||||
#ifndef BASE_MEMORY_CONTAINER_OF_H
 | 
			
		||||
#define BASE_MEMORY_CONTAINER_OF_H
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>  // offsetof
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#define container_of(v, t, head) \
 | 
			
		||||
    ((t *)((char *)(v) - offsetof(t, head)))
 | 
			
		||||
    ((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,12 +14,16 @@
 | 
			
		||||
#define BASE_MEMORY_ZALLOC_H
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
static inline void *zalloc(size_t len)
 | 
			
		||||
{
 | 
			
		||||
	return calloc(1, len);
 | 
			
		||||
	void *ptr = malloc(len);
 | 
			
		||||
	if (ptr)
 | 
			
		||||
		memset(ptr, 0, len);
 | 
			
		||||
	return ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//----------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
 | 
			
		||||
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of LVM2.
 | 
			
		||||
#
 | 
			
		||||
@@ -25,7 +25,6 @@ PROFILES=$(PROFILE_TEMPLATES) \
 | 
			
		||||
	$(srcdir)/cache-smq.profile \
 | 
			
		||||
	$(srcdir)/thin-generic.profile \
 | 
			
		||||
	$(srcdir)/thin-performance.profile \
 | 
			
		||||
	$(srcdir)/vdo-small.profile \
 | 
			
		||||
	$(srcdir)/lvmdbusd.profile
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
@@ -33,8 +32,8 @@ include $(top_builddir)/make.tmpl
 | 
			
		||||
.PHONY: install_conf install_localconf install_profiles
 | 
			
		||||
 | 
			
		||||
generate:
 | 
			
		||||
	$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in
 | 
			
		||||
	$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --withcomments --withspaces local > lvmlocal.conf.in
 | 
			
		||||
	LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in
 | 
			
		||||
	LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --withcomments --withspaces local > lvmlocal.conf.in
 | 
			
		||||
 | 
			
		||||
install_conf: $(CONFSRC)
 | 
			
		||||
	@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
 | 
			
		||||
@@ -49,9 +48,8 @@ install_localconf: $(CONFLOCAL)
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
install_profiles: $(PROFILES)
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_DIR) $(profiledir)
 | 
			
		||||
	$(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/
 | 
			
		||||
	$(INSTALL_DIR) $(profiledir)
 | 
			
		||||
	$(INSTALL_DATA) $(PROFILES) $(profiledir)/
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_conf install_localconf install_profiles
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -88,22 +88,6 @@ devices {
 | 
			
		||||
	# 
 | 
			
		||||
	external_device_info_source = "none"
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/hints.
 | 
			
		||||
	# Use a local file to remember which devices have PVs on them.
 | 
			
		||||
	# Some commands will use this as an optimization to reduce device
 | 
			
		||||
	# scanning, and will only scan the listed PVs. Removing the hint file
 | 
			
		||||
	# will cause lvm to generate a new one. Disable hints if PVs will
 | 
			
		||||
	# be copied onto devices using non-lvm commands, like dd.
 | 
			
		||||
	# 
 | 
			
		||||
	# Accepted values:
 | 
			
		||||
	#   all
 | 
			
		||||
	#     Use all hints.
 | 
			
		||||
	#   none
 | 
			
		||||
	#     Use no hints.
 | 
			
		||||
	# 
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# hints = "all"
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/preferred_names.
 | 
			
		||||
	# Select which path name to display for a block device.
 | 
			
		||||
	# If multiple path names exist for a block device, and LVM needs to
 | 
			
		||||
@@ -139,10 +123,11 @@ devices {
 | 
			
		||||
	# then the device is accepted. Be careful mixing 'a' and 'r' patterns,
 | 
			
		||||
	# as the combination might produce unexpected results (test changes.)
 | 
			
		||||
	# Run vgscan after changing the filter to regenerate the cache.
 | 
			
		||||
	# See the use_lvmetad comment for a special case regarding filters.
 | 
			
		||||
	# 
 | 
			
		||||
	# Example
 | 
			
		||||
	# Accept every block device:
 | 
			
		||||
	# filter = [ "a|.*|" ]
 | 
			
		||||
	# filter = [ "a|.*/|" ]
 | 
			
		||||
	# Reject the cdrom drive:
 | 
			
		||||
	# filter = [ "r|/dev/cdrom|" ]
 | 
			
		||||
	# Work with just loopback devices, e.g. for testing:
 | 
			
		||||
@@ -150,20 +135,38 @@ devices {
 | 
			
		||||
	# Accept all loop devices and ide drives except hdc:
 | 
			
		||||
	# filter = [ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
 | 
			
		||||
	# Use anchors to be very specific:
 | 
			
		||||
	# filter = [ "a|^/dev/hda8$|", "r|.*|" ]
 | 
			
		||||
	# filter = [ "a|^/dev/hda8$|", "r|.*/|" ]
 | 
			
		||||
	# 
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# filter = [ "a|.*|" ]
 | 
			
		||||
	# filter = [ "a|.*/|" ]
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/global_filter.
 | 
			
		||||
	# Limit the block devices that are used by LVM system components.
 | 
			
		||||
	# Because devices/filter may be overridden from the command line, it is
 | 
			
		||||
	# not suitable for system-wide device filtering, e.g. udev.
 | 
			
		||||
	# not suitable for system-wide device filtering, e.g. udev and lvmetad.
 | 
			
		||||
	# Use global_filter to hide devices from these LVM system components.
 | 
			
		||||
	# The syntax is the same as devices/filter. Devices rejected by
 | 
			
		||||
	# global_filter are not opened by LVM.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# global_filter = [ "a|.*|" ]
 | 
			
		||||
	# global_filter = [ "a|.*/|" ]
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/cache_dir.
 | 
			
		||||
	# Directory in which to store the device cache file.
 | 
			
		||||
	# The results of filtering are cached on disk to avoid rescanning dud
 | 
			
		||||
	# devices (which can take a very long time). By default this cache is
 | 
			
		||||
	# stored in a file named .cache. It is safe to delete this file; the
 | 
			
		||||
	# tools regenerate it. If obtain_device_list_from_udev is enabled, the
 | 
			
		||||
	# list of devices is obtained from udev and any existing .cache file
 | 
			
		||||
	# is removed.
 | 
			
		||||
	cache_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@"
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/cache_file_prefix.
 | 
			
		||||
	# A prefix used before the .cache file name. See devices/cache_dir.
 | 
			
		||||
	cache_file_prefix = ""
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/write_cache_state.
 | 
			
		||||
	# Enable/disable writing the cache file. See devices/cache_dir.
 | 
			
		||||
	write_cache_state = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/types.
 | 
			
		||||
	# List of additional acceptable block device types.
 | 
			
		||||
@@ -201,34 +204,9 @@ devices {
 | 
			
		||||
	multipath_component_detection = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/md_component_detection.
 | 
			
		||||
	# Enable detection and exclusion of MD component devices.
 | 
			
		||||
	# An MD component device is a block device that MD uses as part
 | 
			
		||||
	# of a software RAID virtual device. When an LVM PV is created
 | 
			
		||||
	# on an MD device, LVM must only use the top level MD device as
 | 
			
		||||
	# the PV, and should ignore the underlying component devices.
 | 
			
		||||
	# In cases where the MD superblock is located at the end of the
 | 
			
		||||
	# component devices, it is more difficult for LVM to consistently
 | 
			
		||||
	# identify an MD component, see the md_component_checks setting.
 | 
			
		||||
	# Ignore devices that are components of software RAID (md) devices.
 | 
			
		||||
	md_component_detection = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/md_component_checks.
 | 
			
		||||
	# The checks LVM should use to detect MD component devices.
 | 
			
		||||
	# MD component devices are block devices used by MD software RAID.
 | 
			
		||||
	# 
 | 
			
		||||
	# Accepted values:
 | 
			
		||||
	#   auto
 | 
			
		||||
	#     LVM will skip scanning the end of devices when it has other
 | 
			
		||||
	#     indications that the device is not an MD component.
 | 
			
		||||
	#   start
 | 
			
		||||
	#     LVM will only scan the start of devices for MD superblocks.
 | 
			
		||||
	#     This does not incur extra I/O by LVM.
 | 
			
		||||
	#   full
 | 
			
		||||
	#     LVM will scan the start and end of devices for MD superblocks.
 | 
			
		||||
	#     This requires an extra read at the end of devices.
 | 
			
		||||
	# 
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# md_component_checks = "auto"
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/fw_raid_component_detection.
 | 
			
		||||
	# Ignore devices that are components of firmware RAID devices.
 | 
			
		||||
	# LVM must use an external_device_info_source other than none for this
 | 
			
		||||
@@ -236,24 +214,19 @@ devices {
 | 
			
		||||
	fw_raid_component_detection = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/md_chunk_alignment.
 | 
			
		||||
	# Align the start of a PV data area with md device's stripe-width.
 | 
			
		||||
	# Align PV data blocks with md device's stripe-width.
 | 
			
		||||
	# This applies if a PV is placed directly on an md device.
 | 
			
		||||
	# default_data_alignment will be overriden if it is not aligned
 | 
			
		||||
	# with the value detected for this setting.
 | 
			
		||||
	# This setting is overriden by data_alignment_detection,
 | 
			
		||||
	# data_alignment, and the --dataalignment option.
 | 
			
		||||
	md_chunk_alignment = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/default_data_alignment.
 | 
			
		||||
	# Align the start of a PV data area with this number of MiB.
 | 
			
		||||
	# Set to 1 for 1MiB, 2 for 2MiB, etc. Set to 0 to disable.
 | 
			
		||||
	# This setting is overriden by data_alignment and the --dataalignment
 | 
			
		||||
	# option.
 | 
			
		||||
	# Default alignment of the start of a PV data area in MB.
 | 
			
		||||
	# If set to 0, a value of 64KiB will be used.
 | 
			
		||||
	# Set to 1 for 1MiB, 2 for 2MiB, etc.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# default_data_alignment = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/data_alignment_detection.
 | 
			
		||||
	# Align the start of a PV data area with sysfs io properties.
 | 
			
		||||
	# Detect PV data alignment based on sysfs device information.
 | 
			
		||||
	# The start of a PV data area will be a multiple of minimum_io_size or
 | 
			
		||||
	# optimal_io_size exposed in sysfs. minimum_io_size is the smallest
 | 
			
		||||
	# request the device can perform without incurring a read-modify-write
 | 
			
		||||
@@ -261,29 +234,27 @@ devices {
 | 
			
		||||
	# preferred unit of receiving I/O, e.g. MD stripe width.
 | 
			
		||||
	# minimum_io_size is used if optimal_io_size is undefined (0).
 | 
			
		||||
	# If md_chunk_alignment is enabled, that detects the optimal_io_size.
 | 
			
		||||
	# default_data_alignment and md_chunk_alignment will be overriden
 | 
			
		||||
	# if they are not aligned with the value detected for this setting.
 | 
			
		||||
	# This setting is overriden by data_alignment and the --dataalignment
 | 
			
		||||
	# option.
 | 
			
		||||
	# This setting takes precedence over md_chunk_alignment.
 | 
			
		||||
	data_alignment_detection = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/data_alignment.
 | 
			
		||||
	# Align the start of a PV data area with this number of KiB.
 | 
			
		||||
	# When non-zero, this setting overrides default_data_alignment.
 | 
			
		||||
	# Set to 0 to disable, in which case default_data_alignment
 | 
			
		||||
	# is used to align the first PE in units of MiB.
 | 
			
		||||
	# This setting is overriden by the --dataalignment option.
 | 
			
		||||
	# Alignment of the start of a PV data area in KiB.
 | 
			
		||||
	# If a PV is placed directly on an md device and md_chunk_alignment or
 | 
			
		||||
	# data_alignment_detection are enabled, then this setting is ignored.
 | 
			
		||||
	# Otherwise, md_chunk_alignment and data_alignment_detection are
 | 
			
		||||
	# disabled if this is set. Set to 0 to use the default alignment or the
 | 
			
		||||
	# page size, if larger.
 | 
			
		||||
	data_alignment = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/data_alignment_offset_detection.
 | 
			
		||||
	# Shift the start of an aligned PV data area based on sysfs information.
 | 
			
		||||
	# After a PV data area is aligned, it will be shifted by the
 | 
			
		||||
	# Detect PV data alignment offset based on sysfs device information.
 | 
			
		||||
	# The start of a PV aligned data area will be shifted by the
 | 
			
		||||
	# alignment_offset exposed in sysfs. This offset is often 0, but may
 | 
			
		||||
	# be non-zero. Certain 4KiB sector drives that compensate for windows
 | 
			
		||||
	# partitioning will have an alignment_offset of 3584 bytes (sector 7
 | 
			
		||||
	# is the lowest aligned logical block, the 4KiB sectors start at
 | 
			
		||||
	# LBA -1, and consequently sector 63 is aligned on a 4KiB boundary).
 | 
			
		||||
	# This setting is overriden by the --dataalignmentoffset option.
 | 
			
		||||
	# pvcreate --dataalignmentoffset will skip this detection.
 | 
			
		||||
	data_alignment_offset_detection = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/ignore_suspended_devices.
 | 
			
		||||
@@ -311,6 +282,14 @@ devices {
 | 
			
		||||
	# different way, making them a better choice for VG stacking.
 | 
			
		||||
	ignore_lvm_mirrors = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/disable_after_error_count.
 | 
			
		||||
	# Number of I/O errors after which a device is skipped.
 | 
			
		||||
	# During each LVM operation, errors received from each device are
 | 
			
		||||
	# counted. If the counter of a device exceeds the limit set here,
 | 
			
		||||
	# no further I/O is sent to that device for the remainder of the
 | 
			
		||||
	# operation. Setting this to 0 disables the counters altogether.
 | 
			
		||||
	disable_after_error_count = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/require_restorefile_with_uuid.
 | 
			
		||||
	# Allow use of pvcreate --uuid without requiring --restorefile.
 | 
			
		||||
	require_restorefile_with_uuid = 1
 | 
			
		||||
@@ -347,12 +326,6 @@ devices {
 | 
			
		||||
	# Enabling this setting allows the VG to be used as usual even with
 | 
			
		||||
	# uncertain devices.
 | 
			
		||||
	allow_changes_with_duplicate_pvs = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option devices/allow_mixed_block_sizes.
 | 
			
		||||
	# Allow PVs in the same VG with different logical block sizes.
 | 
			
		||||
	# When allowed, the user is responsible to ensure that an LV is
 | 
			
		||||
	# using PVs with matching block sizes when necessary.
 | 
			
		||||
	allow_mixed_block_sizes = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Configuration section allocation.
 | 
			
		||||
@@ -387,7 +360,7 @@ allocation {
 | 
			
		||||
	maximise_cling = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/use_blkid_wiping.
 | 
			
		||||
	# Use blkid to detect and erase existing signatures on new PVs and LVs.
 | 
			
		||||
	# Use blkid to detect existing signatures on new PVs and LVs.
 | 
			
		||||
	# The blkid library can detect more signatures than the native LVM
 | 
			
		||||
	# detection code, but may take longer. LVM needs to be compiled with
 | 
			
		||||
	# blkid wiping support for this setting to apply. LVM native detection
 | 
			
		||||
@@ -429,8 +402,7 @@ allocation {
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/cache_pool_metadata_require_separate_pvs.
 | 
			
		||||
	# Cache pool metadata and data will always use different PVs.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# cache_pool_metadata_require_separate_pvs = 0
 | 
			
		||||
	cache_pool_metadata_require_separate_pvs = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/cache_metadata_format.
 | 
			
		||||
	# Sets default metadata format for new cache.
 | 
			
		||||
@@ -489,9 +461,8 @@ allocation {
 | 
			
		||||
	# This configuration option does not have a default value defined.
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
 | 
			
		||||
	# Thin pool metadata and data will always use different PVs.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# thin_pool_metadata_require_separate_pvs = 0
 | 
			
		||||
	# Thin pool metdata and data will always use different PVs.
 | 
			
		||||
	thin_pool_metadata_require_separate_pvs = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/thin_pool_zero.
 | 
			
		||||
	# Thin pool data chunks are zeroed before they are first used.
 | 
			
		||||
@@ -528,11 +499,6 @@ allocation {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# thin_pool_chunk_size_policy = "generic"
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/zero_metadata.
 | 
			
		||||
	# Zero whole metadata area before use with thin or cache pool.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# zero_metadata = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/thin_pool_chunk_size.
 | 
			
		||||
	# The minimal chunk size in KiB for thin pool volumes.
 | 
			
		||||
	# Larger chunk sizes may improve performance for plain thin volumes,
 | 
			
		||||
@@ -546,154 +512,6 @@ allocation {
 | 
			
		||||
	# Default physical extent size in KiB to use for new VGs.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# physical_extent_size = 4096
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_use_compression.
 | 
			
		||||
	# Enables or disables compression when creating a VDO volume.
 | 
			
		||||
	# Compression may be disabled if necessary to maximize performance
 | 
			
		||||
	# or to speed processing of data that is unlikely to compress.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_use_compression = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_use_deduplication.
 | 
			
		||||
	# Enables or disables deduplication when creating a VDO volume.
 | 
			
		||||
	# Deduplication may be disabled in instances where data is not expected
 | 
			
		||||
	# to have good deduplication rates but compression is still desired.
 | 
			
		||||
	# 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 and default value is 4096.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_minimum_io_size = 4096
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_block_map_cache_size_mb.
 | 
			
		||||
	# Specifies the amount of memory in MiB allocated for caching block map
 | 
			
		||||
	# pages for VDO volume. The value must be a multiple of 4096 and must be
 | 
			
		||||
	# at least 128MiB and less than 16TiB. The cache must be at least 16MiB
 | 
			
		||||
	# per logical thread. Note that there is a memory overhead of 15%.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_block_map_cache_size_mb = 128
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_block_map_period.
 | 
			
		||||
	# The speed with which the block map cache writes out modified block map pages.
 | 
			
		||||
	# A smaller era length is likely to reduce the amount time spent rebuilding,
 | 
			
		||||
	# at the cost of increased block map writes during normal operation.
 | 
			
		||||
	# The maximum and recommended value is 16380; the minimum value is 1.
 | 
			
		||||
	# 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.
 | 
			
		||||
	# vdo_use_sparse_index = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_index_memory_size_mb.
 | 
			
		||||
	# Specifies the amount of index memory in MiB for VDO volume.
 | 
			
		||||
	# The value must be at least 256MiB and at most 1TiB.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_index_memory_size_mb = 256
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_slab_size_mb.
 | 
			
		||||
	# Specifies the size in MiB of the increment by which a VDO is grown.
 | 
			
		||||
	# Using a smaller size constrains the total maximum physical size
 | 
			
		||||
	# that can be accommodated. Must be a power of two between 128MiB and 32GiB.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_slab_size_mb = 2048
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_ack_threads.
 | 
			
		||||
	# Specifies the number of threads to use for acknowledging
 | 
			
		||||
	# completion of requested VDO I/O operations.
 | 
			
		||||
	# The value must be at in range [0..100].
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_ack_threads = 1
 | 
			
		||||
 | 
			
		||||
	# 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]
 | 
			
		||||
	# 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.
 | 
			
		||||
	# vdo_bio_threads = 4
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_bio_rotation.
 | 
			
		||||
	# Specifies the number of I/O operations to enqueue for each bio-submission
 | 
			
		||||
	# thread before directing work to the next. The value must be in range [1..1024].
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_bio_rotation = 64
 | 
			
		||||
 | 
			
		||||
	# 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]
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_cpu_threads = 2
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_hash_zone_threads.
 | 
			
		||||
	# Specifies the number of threads across which to subdivide parts of the VDO
 | 
			
		||||
	# processing based on the hash value computed from the block data.
 | 
			
		||||
	# The value must be at 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.
 | 
			
		||||
	# vdo_hash_zone_threads = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_logical_threads.
 | 
			
		||||
	# Specifies the number of threads across which to subdivide parts of the VDO
 | 
			
		||||
	# 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..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.
 | 
			
		||||
	# vdo_logical_threads = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_physical_threads.
 | 
			
		||||
	# Specifies the number of threads across which to subdivide parts of the VDO
 | 
			
		||||
	# processing based on physical block addresses.
 | 
			
		||||
	# Each additional thread after the first will use an additional 10MiB of RAM.
 | 
			
		||||
	# The value must be in range [0..16].
 | 
			
		||||
	# 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.
 | 
			
		||||
	# 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.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_write_policy = "auto"
 | 
			
		||||
 | 
			
		||||
	# Configuration option allocation/vdo_max_discard.
 | 
			
		||||
	# Specified te maximum size of discard bio accepted, in 4096 byte blocks.
 | 
			
		||||
	# I/O requests to a VDO volume are normally split into 4096-byte blocks,
 | 
			
		||||
	# and processed up to 2048 at a time. However, discard requests to a VDO volume
 | 
			
		||||
	# can be automatically split to a larger size, up to <max discard> 4096-byte blocks
 | 
			
		||||
	# in a single bio, and are limited to 1500 at a time.
 | 
			
		||||
	# Increasing this value may provide better overall performance, at the cost of
 | 
			
		||||
	# increased latency for the individual discard requests.
 | 
			
		||||
	# The default and minimum is 1. The maximum is UINT_MAX / 4096.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_max_discard = 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Configuration section log.
 | 
			
		||||
@@ -784,8 +602,7 @@ log {
 | 
			
		||||
 | 
			
		||||
	# Configuration option log/indent.
 | 
			
		||||
	# Indent messages according to their severity.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# indent = 0
 | 
			
		||||
	indent = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option log/command_names.
 | 
			
		||||
	# Display the command name on each line of output.
 | 
			
		||||
@@ -808,23 +625,9 @@ log {
 | 
			
		||||
	# Select log messages by class.
 | 
			
		||||
	# Some debugging messages are assigned to a class and only appear in
 | 
			
		||||
	# debug output if the class is listed here. Classes currently
 | 
			
		||||
	# available: memory, devices, io, activation, allocation,
 | 
			
		||||
	# available: memory, devices, io, activation, allocation, lvmetad,
 | 
			
		||||
	# metadata, cache, locking, lvmpolld. Use "all" to see everything.
 | 
			
		||||
	debug_classes = [ "memory", "devices", "io", "activation", "allocation", "metadata", "cache", "locking", "lvmpolld", "dbus" ]
 | 
			
		||||
 | 
			
		||||
	# Configuration option log/debug_file_fields.
 | 
			
		||||
	# The fields included in debug output written to log file.
 | 
			
		||||
	# Use "all" to include everything (the default).
 | 
			
		||||
	# This configuration option is advanced.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# debug_file_fields = [ "time", "command", "fileline", "message" ]
 | 
			
		||||
 | 
			
		||||
	# Configuration option log/debug_output_fields.
 | 
			
		||||
	# The fields included in debug output written to stderr.
 | 
			
		||||
	# Use "all" to include everything (the default).
 | 
			
		||||
	# This configuration option is advanced.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# debug_output_fields = [ "time", "command", "fileline", "message" ]
 | 
			
		||||
	debug_classes = [ "memory", "devices", "io", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld", "dbus" ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Configuration section backup.
 | 
			
		||||
@@ -912,6 +715,23 @@ global {
 | 
			
		||||
	# the error messages.
 | 
			
		||||
	activation = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/fallback_to_lvm1.
 | 
			
		||||
	# This setting is no longer used.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# fallback_to_lvm1 = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/format.
 | 
			
		||||
	# This setting is no longer used.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# format = "lvm2"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/format_libraries.
 | 
			
		||||
	# This setting is no longer used.
 | 
			
		||||
	# This configuration option does not have a default value defined.
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/segment_libraries.
 | 
			
		||||
	# This configuration option does not have a default value defined.
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/proc.
 | 
			
		||||
	# Location of proc filesystem.
 | 
			
		||||
	# This configuration option is advanced.
 | 
			
		||||
@@ -921,10 +741,57 @@ global {
 | 
			
		||||
	# Location of /etc system configuration directory.
 | 
			
		||||
	etc = "@CONFDIR@"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/locking_type.
 | 
			
		||||
	# Type of locking to use.
 | 
			
		||||
	# 
 | 
			
		||||
	# Accepted values:
 | 
			
		||||
	#   0
 | 
			
		||||
	#     Turns off locking. Warning: this risks metadata corruption if
 | 
			
		||||
	#     commands run concurrently.
 | 
			
		||||
	#   1
 | 
			
		||||
	#     LVM uses local file-based locking, the standard mode.
 | 
			
		||||
	#   2
 | 
			
		||||
	#     LVM uses the external shared library locking_library.
 | 
			
		||||
	#   3
 | 
			
		||||
	#     LVM uses built-in clustered locking with clvmd.
 | 
			
		||||
	#     This is incompatible with lvmetad. If use_lvmetad is enabled,
 | 
			
		||||
	#     LVM prints a warning and disables lvmetad use.
 | 
			
		||||
	#   4
 | 
			
		||||
	#     LVM uses read-only locking which forbids any operations that
 | 
			
		||||
	#     might change metadata.
 | 
			
		||||
	#   5
 | 
			
		||||
	#     Offers dummy locking for tools that do not need any locks.
 | 
			
		||||
	#     You should not need to set this directly; the tools will select
 | 
			
		||||
	#     when to use it instead of the configured locking_type.
 | 
			
		||||
	#     Do not use lvmetad or the kernel device-mapper driver with this
 | 
			
		||||
	#     locking type. It is used by the --readonly option that offers
 | 
			
		||||
	#     read-only access to Volume Group metadata that cannot be locked
 | 
			
		||||
	#     safely because it belongs to an inaccessible domain and might be
 | 
			
		||||
	#     in use, for example a virtual machine image or a disk that is
 | 
			
		||||
	#     shared by a clustered machine.
 | 
			
		||||
	# 
 | 
			
		||||
	locking_type = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/wait_for_locks.
 | 
			
		||||
	# When disabled, fail if a lock request would block.
 | 
			
		||||
	wait_for_locks = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/fallback_to_clustered_locking.
 | 
			
		||||
	# Attempt to use built-in cluster locking if locking_type 2 fails.
 | 
			
		||||
	# If using external locking (type 2) and initialisation fails, with
 | 
			
		||||
	# this enabled, an attempt will be made to use the built-in clustered
 | 
			
		||||
	# locking. Disable this if using a customised locking_library.
 | 
			
		||||
	fallback_to_clustered_locking = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/fallback_to_local_locking.
 | 
			
		||||
	# Use locking_type 1 (local) if locking_type 2 or 3 fail.
 | 
			
		||||
	# If an attempt to initialise type 2 or type 3 locking failed, perhaps
 | 
			
		||||
	# because cluster components such as clvmd are not running, with this
 | 
			
		||||
	# enabled, an attempt will be made to use local file-based locking
 | 
			
		||||
	# (type 1). If this succeeds, only commands against local VGs will
 | 
			
		||||
	# proceed. VGs marked as clustered will be ignored.
 | 
			
		||||
	fallback_to_local_locking = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/locking_dir.
 | 
			
		||||
	# Directory to use for LVM command file locks.
 | 
			
		||||
	# Local non-LV directory that holds file-based locks while commands are
 | 
			
		||||
@@ -945,6 +812,11 @@ global {
 | 
			
		||||
	# Search this directory first for shared libraries.
 | 
			
		||||
	# This configuration option does not have a default value defined.
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/locking_library.
 | 
			
		||||
	# The external locking library to use for locking_type 2.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# locking_library = "liblvm2clusterlock.so"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/abort_on_internal_errors.
 | 
			
		||||
	# Abort a command that encounters an internal error.
 | 
			
		||||
	# Treat any internal errors as fatal errors, aborting the process that
 | 
			
		||||
@@ -985,17 +857,6 @@ global {
 | 
			
		||||
	# 
 | 
			
		||||
	mirror_segtype_default = "@DEFAULT_MIRROR_SEGTYPE@"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/support_mirrored_mirror_log.
 | 
			
		||||
	# Enable mirrored 'mirror' log type for testing.
 | 
			
		||||
	# 
 | 
			
		||||
	# This type is deprecated to create or convert to but can
 | 
			
		||||
	# be enabled to test that activation of existing mirrored
 | 
			
		||||
	# logs and conversion to disk/core works.
 | 
			
		||||
	# 
 | 
			
		||||
	# Not supported for regular operation!
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# support_mirrored_mirror_log = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/raid10_segtype_default.
 | 
			
		||||
	# The segment type used by the -i -m combination.
 | 
			
		||||
	# The --type raid10|mirror option overrides this setting.
 | 
			
		||||
@@ -1044,22 +905,47 @@ global {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# lvdisplay_shows_full_device_path = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/event_activation.
 | 
			
		||||
	# Activate LVs based on system-generated device events.
 | 
			
		||||
	# When a device appears on the system, a system-generated event runs
 | 
			
		||||
	# the pvscan command to activate LVs if the new PV completes the VG.
 | 
			
		||||
	# Use auto_activation_volume_list to select which LVs should be
 | 
			
		||||
	# activated from these events (the default is all.)
 | 
			
		||||
	# When event_activation is disabled, the system will generally run
 | 
			
		||||
	# a direct activation command to activate LVs in complete VGs.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# event_activation = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/use_aio.
 | 
			
		||||
	# Use async I/O when reading and writing devices.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# use_aio = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/use_lvmetad.
 | 
			
		||||
	# Use lvmetad to cache metadata and reduce disk scanning.
 | 
			
		||||
	# When enabled (and running), lvmetad provides LVM commands with VG
 | 
			
		||||
	# metadata and PV state. LVM commands then avoid reading this
 | 
			
		||||
	# information from disks which can be slow. When disabled (or not
 | 
			
		||||
	# running), LVM commands fall back to scanning disks to obtain VG
 | 
			
		||||
	# metadata. lvmetad is kept updated via udev rules which must be set
 | 
			
		||||
	# up for LVM to work correctly. (The udev rules should be installed
 | 
			
		||||
	# by default.) Without a proper udev setup, changes in the system's
 | 
			
		||||
	# block device configuration will be unknown to LVM, and ignored
 | 
			
		||||
	# until a manual 'pvscan --cache' is run. If lvmetad was running
 | 
			
		||||
	# while use_lvmetad was disabled, it must be stopped, use_lvmetad
 | 
			
		||||
	# enabled, and then started. When using lvmetad, LV activation is
 | 
			
		||||
	# switched to an automatic, event-based mode. In this mode, LVs are
 | 
			
		||||
	# activated based on incoming udev events that inform lvmetad when
 | 
			
		||||
	# PVs appear on the system. When a VG is complete (all PVs present),
 | 
			
		||||
	# it is auto-activated. The auto_activation_volume_list setting
 | 
			
		||||
	# controls which LVs are auto-activated (all by default.)
 | 
			
		||||
	# When lvmetad is updated (automatically by udev events, or directly
 | 
			
		||||
	# by pvscan --cache), devices/filter is ignored and all devices are
 | 
			
		||||
	# scanned by default. lvmetad always keeps unfiltered information
 | 
			
		||||
	# which is provided to LVM commands. Each LVM command then filters
 | 
			
		||||
	# based on devices/filter. This does not apply to other, non-regexp,
 | 
			
		||||
	# filtering settings: component filters such as multipath and MD
 | 
			
		||||
	# are checked during pvscan --cache. To filter a device and prevent
 | 
			
		||||
	# scanning from the LVM system entirely, including lvmetad, use
 | 
			
		||||
	# devices/global_filter.
 | 
			
		||||
	use_lvmetad = @DEFAULT_USE_LVMETAD@
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/lvmetad_update_wait_time.
 | 
			
		||||
	# Number of seconds a command will wait for lvmetad update to finish.
 | 
			
		||||
	# After waiting for this period, a command will not use lvmetad, and
 | 
			
		||||
	# will revert to disk scanning.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# lvmetad_update_wait_time = 10
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/use_lvmlockd.
 | 
			
		||||
	# Use lvmlockd for locking among hosts using LVM on shared storage.
 | 
			
		||||
	# Applicable only if LVM is compiled with lockd support in which
 | 
			
		||||
@@ -1184,17 +1070,6 @@ global {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# cache_repair_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
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_format_executable = "@VDO_FORMAT_CMD@"
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/vdo_format_options.
 | 
			
		||||
	# List of options passed added to standard vdoformat command.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_format_options = [ "" ]
 | 
			
		||||
 | 
			
		||||
	# Configuration option global/fsadm_executable.
 | 
			
		||||
	# The full path to the fsadm command.
 | 
			
		||||
	# LVM uses this command to help with lvresize -r operations.
 | 
			
		||||
@@ -1297,8 +1172,7 @@ activation {
 | 
			
		||||
	# This enables additional checks (and if necessary, repairs) on entries
 | 
			
		||||
	# in the device directory after udev has completed processing its
 | 
			
		||||
	# events. Useful for diagnosing problems with LVM/udev interactions.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# verify_udev_operations = 0
 | 
			
		||||
	verify_udev_operations = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/retry_deactivation.
 | 
			
		||||
	# Retry failed LV deactivation.
 | 
			
		||||
@@ -1323,27 +1197,23 @@ activation {
 | 
			
		||||
	# When disabled, the striped target is used. The linear target is an
 | 
			
		||||
	# optimised version of the striped target that only handles a single
 | 
			
		||||
	# stripe.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# use_linear_target = 1
 | 
			
		||||
	use_linear_target = 1
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/reserved_stack.
 | 
			
		||||
	# Stack size in KiB to reserve for use while devices are suspended.
 | 
			
		||||
	# Insufficent reserve risks I/O deadlock during device suspension.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# reserved_stack = 64
 | 
			
		||||
	reserved_stack = 64
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/reserved_memory.
 | 
			
		||||
	# Memory size in KiB to reserve for use while devices are suspended.
 | 
			
		||||
	# Insufficent reserve risks I/O deadlock during device suspension.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# reserved_memory = 8192
 | 
			
		||||
	reserved_memory = 8192
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/process_priority.
 | 
			
		||||
	# Nice value used while devices are suspended.
 | 
			
		||||
	# Use a high priority so that LVs are suspended
 | 
			
		||||
	# for the shortest possible time.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# process_priority = -18
 | 
			
		||||
	process_priority = -18
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/volume_list.
 | 
			
		||||
	# Only LVs selected by this list are activated.
 | 
			
		||||
@@ -1460,8 +1330,7 @@ activation {
 | 
			
		||||
	#   auto
 | 
			
		||||
	#     Use default value chosen by kernel.
 | 
			
		||||
	# 
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# readahead = "auto"
 | 
			
		||||
	readahead = "auto"
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/raid_fault_policy.
 | 
			
		||||
	# Defines how a device failure in a RAID LV is handled.
 | 
			
		||||
@@ -1584,34 +1453,6 @@ activation {
 | 
			
		||||
	# 
 | 
			
		||||
	thin_pool_autoextend_percent = 20
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/vdo_pool_autoextend_threshold.
 | 
			
		||||
	# Auto-extend a VDO pool when its usage exceeds this percent.
 | 
			
		||||
	# Setting this to 100 disables automatic extension.
 | 
			
		||||
	# The minimum value is 50 (a smaller value is treated as 50.)
 | 
			
		||||
	# Also see vdo_pool_autoextend_percent.
 | 
			
		||||
	# Automatic extension requires dmeventd to be monitoring the LV.
 | 
			
		||||
	# 
 | 
			
		||||
	# Example
 | 
			
		||||
	# Using 70% autoextend threshold and 20% autoextend size, when a 10G
 | 
			
		||||
	# VDO pool exceeds 7G, it is extended to 12G, and when it exceeds
 | 
			
		||||
	# 8.4G, it is extended to 14.4G:
 | 
			
		||||
	# vdo_pool_autoextend_threshold = 70
 | 
			
		||||
	# 
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_pool_autoextend_threshold = 100
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/vdo_pool_autoextend_percent.
 | 
			
		||||
	# Auto-extending a VDO pool adds this percent extra space.
 | 
			
		||||
	# The amount of additional space added to a VDO pool is this
 | 
			
		||||
	# percent of its current size.
 | 
			
		||||
	# 
 | 
			
		||||
	# Example
 | 
			
		||||
	# Using 70% autoextend threshold and 20% autoextend size, when a 10G
 | 
			
		||||
	# VDO pool exceeds 7G, it is extended to 12G, and when it exceeds
 | 
			
		||||
	# 8.4G, it is extended to 14.4G:
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_pool_autoextend_percent = 20
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/mlock_filter.
 | 
			
		||||
	# Do not mlock these memory areas.
 | 
			
		||||
	# While activating devices, I/O to devices being (re)configured is
 | 
			
		||||
@@ -1634,8 +1475,7 @@ activation {
 | 
			
		||||
	# Use the old behavior of mlockall to pin all memory.
 | 
			
		||||
	# Prior to version 2.02.62, LVM used mlockall() to pin the whole
 | 
			
		||||
	# process's memory while activating devices.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# use_mlockall = 0
 | 
			
		||||
	use_mlockall = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/monitoring.
 | 
			
		||||
	# Monitor LVs that are activated.
 | 
			
		||||
@@ -1650,8 +1490,7 @@ activation {
 | 
			
		||||
	# 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.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# polling_interval = 15
 | 
			
		||||
	polling_interval = 15
 | 
			
		||||
 | 
			
		||||
	# Configuration option activation/auto_set_activation_skip.
 | 
			
		||||
	# Set the activation skip flag on new thin snapshot LVs.
 | 
			
		||||
@@ -1759,19 +1598,13 @@ activation {
 | 
			
		||||
	# vgmetadatacopies = 0
 | 
			
		||||
 | 
			
		||||
	# Configuration option metadata/pvmetadatasize.
 | 
			
		||||
	# The default size of the metadata area in units of 512 byte sectors.
 | 
			
		||||
	# The metadata area begins at an offset of the page size from the start
 | 
			
		||||
	# of the device. The first PE is by default at 1 MiB from the start of
 | 
			
		||||
	# the device. The space between these is the default metadata area size.
 | 
			
		||||
	# The actual size of the metadata area may be larger than what is set
 | 
			
		||||
	# here due to default_data_alignment making the first PE a MiB multiple.
 | 
			
		||||
	# The metadata area begins with a 512 byte header and is followed by a
 | 
			
		||||
	# circular buffer used for VG metadata text. The maximum size of the VG
 | 
			
		||||
	# metadata is about half the size of the metadata buffer. VGs with large
 | 
			
		||||
	# numbers of PVs or LVs, or VGs containing complex LV structures, may need
 | 
			
		||||
	# additional space for VG metadata. The --metadatasize option overrides
 | 
			
		||||
	# this setting.
 | 
			
		||||
	# This configuration option does not have a default value defined.
 | 
			
		||||
	# Approximate number of sectors to use for each metadata copy.
 | 
			
		||||
	# VGs with large numbers of PVs or LVs, or VGs containing complex LV
 | 
			
		||||
	# structures, may need additional space for VG metadata. The metadata
 | 
			
		||||
	# areas are treated as circular buffers, so unused space becomes filled
 | 
			
		||||
	# with an archive of the most recent previous versions of the metadata.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# pvmetadatasize = 255
 | 
			
		||||
 | 
			
		||||
	# Configuration option metadata/pvmetadataignore.
 | 
			
		||||
	# Ignore metadata areas on a new PV.
 | 
			
		||||
@@ -1786,6 +1619,24 @@ activation {
 | 
			
		||||
	# This configuration option is advanced.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# stripesize = 64
 | 
			
		||||
 | 
			
		||||
	# Configuration option metadata/dirs.
 | 
			
		||||
	# Directories holding live copies of text format metadata.
 | 
			
		||||
	# These directories must not be on logical volumes!
 | 
			
		||||
	# It's possible to use LVM with a couple of directories here,
 | 
			
		||||
	# preferably on different (non-LV) filesystems, and with no other
 | 
			
		||||
	# on-disk metadata (pvmetadatacopies = 0). Or this can be in addition
 | 
			
		||||
	# to on-disk metadata areas. The feature was originally added to
 | 
			
		||||
	# simplify testing and is not supported under low memory situations -
 | 
			
		||||
	# the machine could lock up. Never edit any files in these directories
 | 
			
		||||
	# by hand unless you are absolutely sure you know what you are doing!
 | 
			
		||||
	# Use the supplied toolset to make changes (e.g. vgcfgrestore).
 | 
			
		||||
	# 
 | 
			
		||||
	# Example
 | 
			
		||||
	# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
 | 
			
		||||
	# 
 | 
			
		||||
	# This configuration option is advanced.
 | 
			
		||||
	# This configuration option does not have a default value defined.
 | 
			
		||||
# }
 | 
			
		||||
 | 
			
		||||
# Configuration section report.
 | 
			
		||||
@@ -2207,8 +2058,7 @@ dmeventd {
 | 
			
		||||
	# failures. It removes failed devices from a volume group and
 | 
			
		||||
	# reconfigures a mirror as necessary. If no mirror library is
 | 
			
		||||
	# provided, mirrors are not monitored through dmeventd.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# mirror_library = "libdevmapper-event-lvm2mirror.so"
 | 
			
		||||
	mirror_library = "libdevmapper-event-lvm2mirror.so"
 | 
			
		||||
 | 
			
		||||
	# Configuration option dmeventd/raid_library.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
@@ -2219,16 +2069,14 @@ dmeventd {
 | 
			
		||||
	# libdevmapper-event-lvm2snapshot.so monitors the filling of snapshots
 | 
			
		||||
	# and emits a warning through syslog when the usage exceeds 80%. The
 | 
			
		||||
	# warning is repeated when 85%, 90% and 95% of the snapshot is filled.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# snapshot_library = "libdevmapper-event-lvm2snapshot.so"
 | 
			
		||||
	snapshot_library = "libdevmapper-event-lvm2snapshot.so"
 | 
			
		||||
 | 
			
		||||
	# Configuration option dmeventd/thin_library.
 | 
			
		||||
	# The library dmeventd uses when monitoring a thin device.
 | 
			
		||||
	# libdevmapper-event-lvm2thin.so monitors the filling of a pool
 | 
			
		||||
	# and emits a warning through syslog when the usage exceeds 80%. The
 | 
			
		||||
	# warning is repeated when 85%, 90% and 95% of the pool is filled.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# thin_library = "libdevmapper-event-lvm2thin.so"
 | 
			
		||||
	thin_library = "libdevmapper-event-lvm2thin.so"
 | 
			
		||||
 | 
			
		||||
	# Configuration option dmeventd/thin_command.
 | 
			
		||||
	# The plugin runs command with each 5% increment when thin-pool data volume
 | 
			
		||||
@@ -2239,23 +2087,6 @@ dmeventd {
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# thin_command = "lvm lvextend --use-policies"
 | 
			
		||||
 | 
			
		||||
	# Configuration option dmeventd/vdo_library.
 | 
			
		||||
	# The library dmeventd uses when monitoring a VDO pool device.
 | 
			
		||||
	# libdevmapper-event-lvm2vdo.so monitors the filling of a pool
 | 
			
		||||
	# and emits a warning through syslog when the usage exceeds 80%. The
 | 
			
		||||
	# warning is repeated when 85%, 90% and 95% of the pool is filled.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_library = "libdevmapper-event-lvm2vdo.so"
 | 
			
		||||
 | 
			
		||||
	# Configuration option dmeventd/vdo_command.
 | 
			
		||||
	# The plugin runs command with each 5% increment when VDO pool volume
 | 
			
		||||
	# gets above 50%.
 | 
			
		||||
	# Command which starts with 'lvm ' prefix is internal lvm command.
 | 
			
		||||
	# You can write your own handler to customise behaviour in more details.
 | 
			
		||||
	# User handler is specified with the full path starting with '/'.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
	# vdo_command = "lvm lvextend --use-policies"
 | 
			
		||||
 | 
			
		||||
	# Configuration option dmeventd/executable.
 | 
			
		||||
	# The full path to the dmeventd binary.
 | 
			
		||||
	# This configuration option has an automatic default value.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
# Demo configuration for 'VDO' using less memory.
 | 
			
		||||
# ~lvmconfig --type full | grep vdo
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
	vdo_ack_threads=1
 | 
			
		||||
	vdo_bio_threads=1
 | 
			
		||||
	vdo_bio_rotation=64
 | 
			
		||||
	vdo_cpu_threads=2
 | 
			
		||||
	vdo_hash_zone_threads=1
 | 
			
		||||
	vdo_logical_threads=1
 | 
			
		||||
	vdo_physical_threads=1
 | 
			
		||||
	vdo_write_policy="auto"
 | 
			
		||||
	vdo_max_discard=1
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										622
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										622
									
								
								configure.ac
									
									
									
									
									
								
							@@ -30,7 +30,7 @@ AC_CANONICAL_TARGET([])
 | 
			
		||||
AS_IF([test -z "$CFLAGS"], [COPTIMISE_FLAG="-O2"])
 | 
			
		||||
case "$host_os" in
 | 
			
		||||
	linux*)
 | 
			
		||||
		CLDFLAGS="${CLDFLAGS-"$LDFLAGS"} -Wl,--version-script,.export.sym"
 | 
			
		||||
		CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
 | 
			
		||||
		# equivalent to -rdynamic
 | 
			
		||||
		ELDFLAGS="-Wl,--export-dynamic"
 | 
			
		||||
		# FIXME Generate list and use --dynamic-list=.dlopen.sym
 | 
			
		||||
@@ -39,19 +39,20 @@ case "$host_os" in
 | 
			
		||||
		LDDEPS="$LDDEPS .export.sym"
 | 
			
		||||
		LIB_SUFFIX=so
 | 
			
		||||
		DEVMAPPER=yes
 | 
			
		||||
		BUILD_LVMETAD=no
 | 
			
		||||
		BUILD_LVMPOLLD=no
 | 
			
		||||
		LOCKDSANLOCK=no
 | 
			
		||||
		LOCKDDLM=no
 | 
			
		||||
		LOCKDDLM_CONTROL=no
 | 
			
		||||
		ODIRECT=yes
 | 
			
		||||
		DM_IOCTLS=yes
 | 
			
		||||
		SELINUX=yes
 | 
			
		||||
		CLUSTER=internal
 | 
			
		||||
		FSADM=yes
 | 
			
		||||
		BLKDEACTIVATE=yes
 | 
			
		||||
		;;
 | 
			
		||||
	darwin*)
 | 
			
		||||
		CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
 | 
			
		||||
		CLDFLAGS="${CLDFLAGS-"$LDFLAGS"}"
 | 
			
		||||
		CLDFLAGS="$CLDFLAGS"
 | 
			
		||||
		ELDFLAGS=
 | 
			
		||||
		CLDWHOLEARCHIVE="-all_load"
 | 
			
		||||
		CLDNOWHOLEARCHIVE=
 | 
			
		||||
@@ -60,12 +61,10 @@ case "$host_os" in
 | 
			
		||||
		ODIRECT=no
 | 
			
		||||
		DM_IOCTLS=no
 | 
			
		||||
		SELINUX=no
 | 
			
		||||
		CLUSTER=none
 | 
			
		||||
		FSADM=no
 | 
			
		||||
		BLKDEACTIVATE=no
 | 
			
		||||
		;;
 | 
			
		||||
	*)
 | 
			
		||||
		CLDFLAGS="${CLDFLAGS-"$LDFLAGS"}"
 | 
			
		||||
		;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
@@ -143,12 +142,6 @@ AC_TYPE_UINT16_T
 | 
			
		||||
AC_TYPE_UINT32_T
 | 
			
		||||
AC_TYPE_UINT64_T
 | 
			
		||||
AX_GCC_BUILTIN([__builtin_clz])
 | 
			
		||||
AX_GCC_BUILTIN([__builtin_clzll])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AC_DEFINE([_GNU_SOURCE], 1, [Define to get access to GNU/Linux extension])
 | 
			
		||||
AC_DEFINE([_REENTRANT], 1, [Define to use re-entrant thread safe versions])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Check for functions
 | 
			
		||||
@@ -156,7 +149,6 @@ AC_CHECK_FUNCS([ftruncate gethostname getpagesize gettimeofday localtime_r \
 | 
			
		||||
  memchr memset mkdir mkfifo munmap nl_langinfo pselect realpath rmdir setenv \
 | 
			
		||||
  setlocale strcasecmp strchr strcspn strdup strerror strncasecmp strndup \
 | 
			
		||||
  strrchr strspn strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
 | 
			
		||||
AC_CHECK_FUNCS([prlimit])
 | 
			
		||||
AC_FUNC_ALLOCA
 | 
			
		||||
AC_FUNC_CLOSEDIR_VOID
 | 
			
		||||
AC_FUNC_CHOWN
 | 
			
		||||
@@ -180,15 +172,6 @@ AC_ARG_ENABLE(dependency-tracking,
 | 
			
		||||
	      USE_TRACKING=$enableval, USE_TRACKING=yes)
 | 
			
		||||
AC_MSG_RESULT($USE_TRACKING)
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Disable silence rules
 | 
			
		||||
AC_MSG_CHECKING(whether to build silently)
 | 
			
		||||
AC_ARG_ENABLE(silent-rules,
 | 
			
		||||
	      AC_HELP_STRING([--disable-silent-rules], [disable silent building]),
 | 
			
		||||
	      SILENT_RULES=$enableval, SILENT_RULES=yes)
 | 
			
		||||
AC_MSG_RESULT($SILENT_RULES)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Enables statically-linked tools
 | 
			
		||||
AC_MSG_CHECKING(whether to use static linking)
 | 
			
		||||
@@ -299,6 +282,22 @@ esac
 | 
			
		||||
AC_MSG_RESULT($MANGLING)
 | 
			
		||||
AC_DEFINE_UNQUOTED([DEFAULT_DM_NAME_MANGLING], $mangling, [Define default name mangling behaviour])
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- cluster_locking inclusion type
 | 
			
		||||
AC_MSG_CHECKING(whether to include support for cluster locking)
 | 
			
		||||
AC_ARG_WITH(cluster,
 | 
			
		||||
	    AC_HELP_STRING([--with-cluster=TYPE],
 | 
			
		||||
			   [cluster LVM locking support: internal/shared/none [internal]]),
 | 
			
		||||
	    CLUSTER=$withval)
 | 
			
		||||
AC_MSG_RESULT($CLUSTER)
 | 
			
		||||
 | 
			
		||||
case "$CLUSTER" in
 | 
			
		||||
  none|shared) ;;
 | 
			
		||||
  internal) AC_DEFINE([CLUSTER_LOCKING_INTERNAL], 1,
 | 
			
		||||
		      [Define to 1 to include built-in support for clustered LVM locking.]) ;;
 | 
			
		||||
  *) AC_MSG_ERROR([--with-cluster parameter invalid]) ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- snapshots inclusion type
 | 
			
		||||
AC_MSG_CHECKING(whether to include snapshots)
 | 
			
		||||
@@ -601,89 +600,6 @@ AC_DEFINE_UNQUOTED([CACHE_REPAIR_CMD], ["$CACHE_REPAIR_CMD"],
 | 
			
		||||
AC_DEFINE_UNQUOTED([CACHE_RESTORE_CMD], ["$CACHE_RESTORE_CMD"],
 | 
			
		||||
		   [The path to 'cache_restore', if available.])
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- cache inclusion type
 | 
			
		||||
AC_MSG_CHECKING(whether to include vdo)
 | 
			
		||||
AC_ARG_WITH(vdo,
 | 
			
		||||
	    AC_HELP_STRING([--with-vdo=TYPE],
 | 
			
		||||
			   [vdo support: internal/none [internal]]),
 | 
			
		||||
			   VDO=$withval, VDO="internal")
 | 
			
		||||
 | 
			
		||||
AC_MSG_RESULT($VDO)
 | 
			
		||||
 | 
			
		||||
AC_ARG_WITH(vdo-format,
 | 
			
		||||
	    AC_HELP_STRING([--with-vdo-format=PATH],
 | 
			
		||||
			   [vdoformat tool: [autodetect]]),
 | 
			
		||||
			   VDO_FORMAT_CMD=$withval, VDO_FORMAT_CMD="autodetect")
 | 
			
		||||
case "$VDO" in
 | 
			
		||||
 none) ;;
 | 
			
		||||
 internal) 
 | 
			
		||||
	AC_DEFINE([VDO_INTERNAL], 1, [Define to 1 to include built-in support for vdo.])
 | 
			
		||||
	if test "$VDO_FORMAT_CMD" = "autodetect"; then
 | 
			
		||||
		AC_PATH_TOOL(VDO_FORMAT_CMD, vdoformat, [], [$PATH])
 | 
			
		||||
		if test -z "$VDO_FORMAT_CMD"; then
 | 
			
		||||
			AC_MSG_WARN([vdoformat not found in path $PATH])
 | 
			
		||||
			VDO_FORMAT_CMD=/usr/bin/vdoformat
 | 
			
		||||
			VDO_CONFIGURE_WARN=y
 | 
			
		||||
		fi
 | 
			
		||||
	fi
 | 
			
		||||
	;;
 | 
			
		||||
 *) AC_MSG_ERROR([--with-vdo parameter invalid]) ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
AC_DEFINE_UNQUOTED([VDO_FORMAT_CMD], ["$VDO_FORMAT_CMD"],
 | 
			
		||||
		   [The path to 'vdoformat', if available.])
 | 
			
		||||
#
 | 
			
		||||
# Do we need to use the API??
 | 
			
		||||
# Do we want to link lvm2 with a big library for vdoformating ?
 | 
			
		||||
#
 | 
			
		||||
#AC_ARG_WITH(vdo-include,
 | 
			
		||||
#	    AC_HELP_STRING([--with-vdo-include=PATH],
 | 
			
		||||
#			   [vdo support: Path to utils headers: [/usr/include/vdo/utils]]),
 | 
			
		||||
#			   VDO_INCLUDE=$withval, VDO_INCLUDE="/usr/include/vdo/utils")
 | 
			
		||||
#AC_MSG_RESULT($VDO_INCLUDE)
 | 
			
		||||
#
 | 
			
		||||
#AC_ARG_WITH(vdo-lib,
 | 
			
		||||
#            AC_HELP_STRING([--with-vdo-lib=PATH],
 | 
			
		||||
#                           [vdo support: Path to utils lib: [/usr/lib]]),
 | 
			
		||||
#                           VDO_LIB=$withval, VDO_LIB="/usr/lib") 
 | 
			
		||||
#AC_MSG_RESULT($VDO_LIB)
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- writecache inclusion type
 | 
			
		||||
AC_MSG_CHECKING(whether to include writecache)
 | 
			
		||||
AC_ARG_WITH(writecache,
 | 
			
		||||
	    AC_HELP_STRING([--with-writecache=TYPE],
 | 
			
		||||
			   [writecache support: internal/none [internal]]),
 | 
			
		||||
			   WRITECACHE=$withval, WRITECACHE="internal")
 | 
			
		||||
 | 
			
		||||
AC_MSG_RESULT($WRITECACHE)
 | 
			
		||||
 | 
			
		||||
case "$WRITECACHE" in
 | 
			
		||||
 none) ;;
 | 
			
		||||
 internal) 
 | 
			
		||||
	AC_DEFINE([WRITECACHE_INTERNAL], 1, [Define to 1 to include built-in support for writecache.])
 | 
			
		||||
	;;
 | 
			
		||||
 *) AC_MSG_ERROR([--with-writecache parameter invalid]) ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- integrity inclusion type
 | 
			
		||||
AC_MSG_CHECKING(whether to include integrity)
 | 
			
		||||
AC_ARG_WITH(integrity,
 | 
			
		||||
	    AC_HELP_STRING([--with-integrity=TYPE],
 | 
			
		||||
			   [integrity support: internal/none [internal]]),
 | 
			
		||||
			   INTEGRITY=$withval, INTEGRITY="internal")
 | 
			
		||||
 | 
			
		||||
AC_MSG_RESULT($INTEGRITY)
 | 
			
		||||
 | 
			
		||||
case "$INTEGRITY" in
 | 
			
		||||
 none) ;;
 | 
			
		||||
 internal)
 | 
			
		||||
	AC_DEFINE([INTEGRITY_INTERNAL], 1, [Define to 1 to include built-in support for integrity.])
 | 
			
		||||
	;;
 | 
			
		||||
 *) AC_MSG_ERROR([--with-integrity parameter invalid]) ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Disable readline
 | 
			
		||||
@@ -691,12 +607,6 @@ AC_ARG_ENABLE([readline],
 | 
			
		||||
	      AC_HELP_STRING([--disable-readline], [disable readline support]),
 | 
			
		||||
	      READLINE=$enableval, READLINE=maybe)
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Disable editline
 | 
			
		||||
AC_ARG_ENABLE([editline],
 | 
			
		||||
	      AC_HELP_STRING([--enable-editline], [enable editline support]),
 | 
			
		||||
	      EDITLINE=$enableval, EDITLINE=no)
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Disable realtime clock support
 | 
			
		||||
AC_MSG_CHECKING(whether to enable realtime support)
 | 
			
		||||
@@ -740,7 +650,7 @@ dnl -- Set up pidfile and run directory
 | 
			
		||||
AH_TEMPLATE(DEFAULT_PID_DIR)
 | 
			
		||||
AC_ARG_WITH(default-pid-dir,
 | 
			
		||||
	    AC_HELP_STRING([--with-default-pid-dir=PID_DIR],
 | 
			
		||||
			   [default directory to keep PID files in [autodetect]]),
 | 
			
		||||
			   [Default directory to keep PID files in. [autodetect]]),
 | 
			
		||||
	    DEFAULT_PID_DIR="$withval", DEFAULT_PID_DIR=$RUN_DIR)
 | 
			
		||||
AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"],
 | 
			
		||||
		   [Default directory to keep PID files in.])
 | 
			
		||||
@@ -748,7 +658,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"],
 | 
			
		||||
AH_TEMPLATE(DEFAULT_DM_RUN_DIR, [Name of default DM run directory.])
 | 
			
		||||
AC_ARG_WITH(default-dm-run-dir,
 | 
			
		||||
	    AC_HELP_STRING([--with-default-dm-run-dir=DM_RUN_DIR],
 | 
			
		||||
			   [default DM run directory [autodetect]]),
 | 
			
		||||
			   [ Default DM run directory. [autodetect]]),
 | 
			
		||||
	    DEFAULT_DM_RUN_DIR="$withval", DEFAULT_DM_RUN_DIR=$RUN_DIR)
 | 
			
		||||
AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"],
 | 
			
		||||
		   [Default DM run directory.])
 | 
			
		||||
@@ -756,11 +666,246 @@ AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"],
 | 
			
		||||
AH_TEMPLATE(DEFAULT_RUN_DIR, [Name of default LVM run directory.])
 | 
			
		||||
AC_ARG_WITH(default-run-dir,
 | 
			
		||||
	    AC_HELP_STRING([--with-default-run-dir=RUN_DIR],
 | 
			
		||||
			   [default LVM run directory [autodetect_run_dir/lvm]]),
 | 
			
		||||
			   [Default LVM run directory. [autodetect_run_dir/lvm]]),
 | 
			
		||||
	    DEFAULT_RUN_DIR="$withval", DEFAULT_RUN_DIR="$RUN_DIR/lvm")
 | 
			
		||||
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
 | 
			
		||||
		   [Default LVM run directory.])
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Build cluster LVM daemon
 | 
			
		||||
AC_MSG_CHECKING(whether to build cluster LVM daemon)
 | 
			
		||||
AC_ARG_WITH(clvmd,
 | 
			
		||||
  [  --with-clvmd=TYPE       build cluster LVM Daemon
 | 
			
		||||
                          The following cluster manager combinations are valid:
 | 
			
		||||
                           * cman                  (RHEL5 or equivalent)
 | 
			
		||||
                           * cman,corosync,openais (or selection of them)
 | 
			
		||||
                           * singlenode            (localhost only)
 | 
			
		||||
                           * all                   (autodetect)
 | 
			
		||||
                           * none                  (disable build)
 | 
			
		||||
                          [[none]]],
 | 
			
		||||
	    CLVMD=$withval, CLVMD=none)
 | 
			
		||||
test "$CLVMD" = yes && CLVMD=all
 | 
			
		||||
AC_MSG_RESULT($CLVMD)
 | 
			
		||||
 | 
			
		||||
dnl -- If clvmd enabled without cluster locking, automagically include it
 | 
			
		||||
test "$CLVMD" != none -a "$CLUSTER" = none && CLUSTER=internal
 | 
			
		||||
 | 
			
		||||
dnl -- init pkgconfig if required
 | 
			
		||||
test "$CLVMD" != none && pkg_config_init
 | 
			
		||||
 | 
			
		||||
dnl -- Express clvmd init script Required-Start / Required-Stop
 | 
			
		||||
CLVMD_CMANAGERS=""
 | 
			
		||||
dnl -- On RHEL4/RHEL5, qdiskd is started from a separate init script.
 | 
			
		||||
dnl -- Enable if we are build for cman.
 | 
			
		||||
CLVMD_NEEDS_QDISKD=no
 | 
			
		||||
 | 
			
		||||
dnl -- define build types
 | 
			
		||||
if [[ `expr x"$CLVMD" : '.*gulm.*'` != 0 ]]; then
 | 
			
		||||
	AC_MSG_ERROR([Since version 2.02.87 GULM locking is no longer supported.]);
 | 
			
		||||
fi
 | 
			
		||||
if [[ `expr x"$CLVMD" : '.*cman.*'` != 0 ]]; then
 | 
			
		||||
	BUILDCMAN=yes
 | 
			
		||||
	CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
 | 
			
		||||
	CLVMD_NEEDS_QDISKD=yes
 | 
			
		||||
fi
 | 
			
		||||
if [[ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]]; then
 | 
			
		||||
	BUILDCOROSYNC=yes
 | 
			
		||||
	CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
 | 
			
		||||
fi
 | 
			
		||||
if [[ `expr x"$CLVMD" : '.*openais.*'` != 0 ]]; then
 | 
			
		||||
	BUILDOPENAIS=yes
 | 
			
		||||
	CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
 | 
			
		||||
fi
 | 
			
		||||
test "$CLVMD_NEEDS_QDISKD" != no && CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
 | 
			
		||||
 | 
			
		||||
dnl -- define a soft bailout if we are autodetecting
 | 
			
		||||
soft_bailout() {
 | 
			
		||||
	NOTFOUND=1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
hard_bailout() {
 | 
			
		||||
	AC_MSG_ERROR([bailing out])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dnl -- if clvmd=all then set soft_bailout (we do not want to error)
 | 
			
		||||
dnl -- and set all builds to yes. We need to do this here
 | 
			
		||||
dnl -- to skip the openais|corosync sanity check above.
 | 
			
		||||
if test "$CLVMD" = all; then
 | 
			
		||||
	bailout=soft_bailout
 | 
			
		||||
	BUILDCMAN=yes
 | 
			
		||||
	BUILDCOROSYNC=yes
 | 
			
		||||
	BUILDOPENAIS=yes
 | 
			
		||||
else
 | 
			
		||||
	bailout=hard_bailout
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl -- helper macro to check libs without adding them to LIBS
 | 
			
		||||
check_lib_no_libs() {
 | 
			
		||||
	lib_no_libs_arg1=$1
 | 
			
		||||
	shift
 | 
			
		||||
	lib_no_libs_arg2=$1
 | 
			
		||||
	shift
 | 
			
		||||
	lib_no_libs_args=$@
 | 
			
		||||
	AC_CHECK_LIB([$lib_no_libs_arg1],
 | 
			
		||||
		     [$lib_no_libs_arg2],,
 | 
			
		||||
		     [$bailout],
 | 
			
		||||
		     [$lib_no_libs_args])
 | 
			
		||||
	LIBS=$ac_check_lib_save_LIBS
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dnl -- Look for cman libraries if required.
 | 
			
		||||
if test "$BUILDCMAN" = yes; then
 | 
			
		||||
	PKG_CHECK_MODULES(CMAN, libcman, [HAVE_CMAN=yes],
 | 
			
		||||
		[NOTFOUND=0
 | 
			
		||||
		AC_CHECK_HEADERS(libcman.h,,$bailout)
 | 
			
		||||
		check_lib_no_libs cman cman_init
 | 
			
		||||
		if test $NOTFOUND = 0; then
 | 
			
		||||
			AC_MSG_RESULT([no pkg for libcman, using -lcman])
 | 
			
		||||
			CMAN_LIBS="-lcman"
 | 
			
		||||
			HAVE_CMAN=yes
 | 
			
		||||
		fi])
 | 
			
		||||
	CHECKCONFDB=yes
 | 
			
		||||
	CHECKDLM=yes
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl -- Look for corosync that is required also for openais build
 | 
			
		||||
dnl -- only enough recent version of corosync ship pkg-config files.
 | 
			
		||||
dnl -- We can safely rely on that to detect the correct bits.
 | 
			
		||||
if test "$BUILDCOROSYNC" = yes -o "$BUILDOPENAIS" = yes; then
 | 
			
		||||
	PKG_CHECK_MODULES(COROSYNC, corosync, [HAVE_COROSYNC=yes], $bailout)
 | 
			
		||||
	CHECKCONFDB=yes
 | 
			
		||||
	CHECKCMAP=yes
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl -- Look for corosync libraries if required.
 | 
			
		||||
if test "$BUILDCOROSYNC" = yes; then
 | 
			
		||||
	PKG_CHECK_MODULES(QUORUM, libquorum, [HAVE_QUORUM=yes], $bailout)
 | 
			
		||||
	CHECKCPG=yes
 | 
			
		||||
	CHECKDLM=yes
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl -- Look for openais libraries if required.
 | 
			
		||||
if test "$BUILDOPENAIS" = yes; then
 | 
			
		||||
	PKG_CHECK_MODULES(SALCK, libSaLck, [HAVE_SALCK=yes], $bailout)
 | 
			
		||||
	CHECKCPG=yes
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl -- Below are checks for libraries common to more than one build.
 | 
			
		||||
 | 
			
		||||
dnl -- Check confdb library.
 | 
			
		||||
dnl -- mandatory for corosync < 2.0 build.
 | 
			
		||||
dnl -- optional for openais/cman build.
 | 
			
		||||
 | 
			
		||||
if test "$CHECKCONFDB" = yes; then
 | 
			
		||||
	PKG_CHECK_MODULES(CONFDB, libconfdb,
 | 
			
		||||
			  [HAVE_CONFDB=yes], [HAVE_CONFDB=no])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_HEADERS([corosync/confdb.h],
 | 
			
		||||
			 [HAVE_CONFDB_H=yes], [HAVE_CONFDB_H=no])
 | 
			
		||||
 | 
			
		||||
	if test "$HAVE_CONFDB" != yes -a "$HAVE_CONFDB_H" = yes; then
 | 
			
		||||
		check_lib_no_libs confdb confdb_initialize
 | 
			
		||||
		AC_MSG_RESULT([no pkg for confdb, using -lconfdb])
 | 
			
		||||
		CONFDB_LIBS="-lconfdb"
 | 
			
		||||
		HAVE_CONFDB=yes
 | 
			
		||||
	fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl -- Check cmap library
 | 
			
		||||
dnl -- mandatory for corosync >= 2.0 build.
 | 
			
		||||
 | 
			
		||||
if test "$CHECKCMAP" = yes; then
 | 
			
		||||
	PKG_CHECK_MODULES(CMAP, libcmap,
 | 
			
		||||
			  [HAVE_CMAP=yes], [HAVE_CMAP=no])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_HEADERS([corosync/cmap.h],
 | 
			
		||||
			 [HAVE_CMAP_H=yes], [HAVE_CMAP_H=no])
 | 
			
		||||
 | 
			
		||||
	if test "$HAVE_CMAP" != yes -a "$HAVE_CMAP_H" = yes; then
 | 
			
		||||
		check_lib_no_libs cmap cmap_initialize
 | 
			
		||||
		AC_MSG_RESULT([no pkg for cmap, using -lcmap])
 | 
			
		||||
		CMAP_LIBS="-lcmap"
 | 
			
		||||
		HAVE_CMAP=yes
 | 
			
		||||
	fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test "$BUILDCOROSYNC" = yes -a \
 | 
			
		||||
	"$HAVE_CMAP" != yes -a "$HAVE_CONFDB" != yes -a "$CLVMD" != all; then
 | 
			
		||||
	AC_MSG_ERROR([bailing out... cmap (corosync >= 2.0) or confdb (corosync < 2.0) library is required])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl -- Check cpg library.
 | 
			
		||||
if test "$CHECKCPG" = yes; then
 | 
			
		||||
	PKG_CHECK_MODULES(CPG, libcpg, [HAVE_CPG=yes], [$bailout])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl -- Check dlm library.
 | 
			
		||||
if test "$CHECKDLM" = yes; then
 | 
			
		||||
	PKG_CHECK_MODULES(DLM, libdlm, [HAVE_DLM=yes],
 | 
			
		||||
		[NOTFOUND=0
 | 
			
		||||
		AC_CHECK_HEADERS(libdlm.h,,[$bailout])
 | 
			
		||||
		check_lib_no_libs dlm dlm_lock -lpthread
 | 
			
		||||
		if test $NOTFOUND = 0; then
 | 
			
		||||
			AC_MSG_RESULT([no pkg for libdlm, using -ldlm])
 | 
			
		||||
			DLM_LIBS="-ldlm -lpthread"
 | 
			
		||||
			HAVE_DLM=yes
 | 
			
		||||
		fi])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl -- If we are autodetecting, we need to re-create
 | 
			
		||||
dnl -- the depedencies checks and set a proper CLVMD,
 | 
			
		||||
dnl -- together with init script Required-Start/Stop entries.
 | 
			
		||||
if test "$CLVMD" = all; then
 | 
			
		||||
	CLVMD=none
 | 
			
		||||
	CLVMD_CMANAGERS=""
 | 
			
		||||
	CLVMD_NEEDS_QDISKD=no
 | 
			
		||||
	if test "$HAVE_CMAN" = yes -a \
 | 
			
		||||
		"$HAVE_DLM" = yes; then
 | 
			
		||||
		AC_MSG_RESULT([Enabling clvmd cman cluster manager])
 | 
			
		||||
		CLVMD="$CLVMD,cman"
 | 
			
		||||
		CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
 | 
			
		||||
		CLVMD_NEEDS_QDISKD=yes
 | 
			
		||||
	fi
 | 
			
		||||
	if test "$HAVE_COROSYNC" = yes -a \
 | 
			
		||||
		"$HAVE_QUORUM" = yes -a \
 | 
			
		||||
		"$HAVE_CPG" = yes -a \
 | 
			
		||||
		"$HAVE_DLM" = yes; then
 | 
			
		||||
	   if test "$HAVE_CONFDB" = yes -o "$HAVE_CMAP" = yes; then
 | 
			
		||||
		AC_MSG_RESULT([Enabling clvmd corosync cluster manager])
 | 
			
		||||
		CLVMD="$CLVMD,corosync"
 | 
			
		||||
		CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
 | 
			
		||||
	   fi
 | 
			
		||||
	fi
 | 
			
		||||
	if test "$HAVE_COROSYNC" = yes -a \
 | 
			
		||||
		"$HAVE_CPG" = yes -a \
 | 
			
		||||
		"$HAVE_SALCK" = yes; then
 | 
			
		||||
		AC_MSG_RESULT([Enabling clvmd openais cluster manager])
 | 
			
		||||
		CLVMD="$CLVMD,openais"
 | 
			
		||||
		CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
 | 
			
		||||
	fi
 | 
			
		||||
	test "$CLVMD_NEEDS_QDISKD" != no && CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
 | 
			
		||||
	test "$CLVMD" = none && AC_MSG_RESULT([Disabling clvmd build. No cluster manager detected.])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl -- Fixup CLVMD_CMANAGERS with new corosync
 | 
			
		||||
dnl -- clvmd built with corosync >= 2.0 needs dlm (either init or systemd service)
 | 
			
		||||
dnl -- to be started.
 | 
			
		||||
if [[ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]]; then
 | 
			
		||||
   test "$HAVE_CMAP" = yes && CLVMD_CMANAGERS="$CLVMD_CMANAGERS dlm"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- clvmd pidfile
 | 
			
		||||
if test "$CLVMD" != none; then
 | 
			
		||||
	AC_ARG_WITH(clvmd-pidfile,
 | 
			
		||||
		    AC_HELP_STRING([--with-clvmd-pidfile=PATH],
 | 
			
		||||
				   [clvmd pidfile [PID_DIR/clvmd.pid]]),
 | 
			
		||||
		    CLVMD_PIDFILE=$withval,
 | 
			
		||||
		    CLVMD_PIDFILE="$DEFAULT_PID_DIR/clvmd.pid")
 | 
			
		||||
	AC_DEFINE_UNQUOTED(CLVMD_PIDFILE, ["$CLVMD_PIDFILE"],
 | 
			
		||||
			   [Path to clvmd pidfile.])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Build cluster mirror log daemon
 | 
			
		||||
AC_MSG_CHECKING(whether to build cluster mirror log daemon)
 | 
			
		||||
@@ -789,6 +934,11 @@ dnl -- Look for corosync libraries if required.
 | 
			
		||||
if [[ "$BUILD_CMIRRORD" = yes ]]; then
 | 
			
		||||
	pkg_config_init
 | 
			
		||||
 | 
			
		||||
	AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 1, [Define to 1 to include libSaCkpt.])
 | 
			
		||||
	PKG_CHECK_MODULES(SACKPT, libSaCkpt, [HAVE_SACKPT=yes],
 | 
			
		||||
		[AC_MSG_RESULT([no libSaCkpt, compiling without it])
 | 
			
		||||
		AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 0, [Define to 0 to exclude libSaCkpt.])])
 | 
			
		||||
 | 
			
		||||
	if test "$HAVE_CPG" != yes; then
 | 
			
		||||
		PKG_CHECK_MODULES(CPG, libcpg)
 | 
			
		||||
	fi
 | 
			
		||||
@@ -894,6 +1044,16 @@ if test "$DEVMAPPER" = yes; then
 | 
			
		||||
	AC_DEFINE([DEVMAPPER_SUPPORT], 1, [Define to 1 to enable LVM2 device-mapper interaction.])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Build lvmetad
 | 
			
		||||
AC_MSG_CHECKING(whether to build LVMetaD)
 | 
			
		||||
AC_ARG_ENABLE(lvmetad,
 | 
			
		||||
	      AC_HELP_STRING([--enable-lvmetad],
 | 
			
		||||
			     [enable the LVM Metadata Daemon]),
 | 
			
		||||
	      LVMETAD=$enableval)
 | 
			
		||||
test -n "$LVMETAD" && BUILD_LVMETAD=$LVMETAD
 | 
			
		||||
AC_MSG_RESULT($BUILD_LVMETAD)
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Build lvmpolld
 | 
			
		||||
AC_MSG_CHECKING(whether to build lvmpolld)
 | 
			
		||||
@@ -942,24 +1102,6 @@ if test "$BUILD_LOCKDDLM" = yes; then
 | 
			
		||||
	BUILD_LVMLOCKD=yes
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Build lvmlockddlmcontrol
 | 
			
		||||
AC_MSG_CHECKING(whether to build lvmlockddlmcontrol)
 | 
			
		||||
AC_ARG_ENABLE(lvmlockd-dlmcontrol,
 | 
			
		||||
	      AC_HELP_STRING([--enable-lvmlockd-dlmcontrol],
 | 
			
		||||
			     [enable lvmlockd remote refresh using libdlmcontrol]),
 | 
			
		||||
	      LOCKDDLM_CONTROL=$enableval)
 | 
			
		||||
AC_MSG_RESULT($LOCKDDLM_CONTROL)
 | 
			
		||||
 | 
			
		||||
BUILD_LOCKDDLM_CONTROL=$LOCKDDLM_CONTROL
 | 
			
		||||
 | 
			
		||||
dnl -- Look for libdlmcontrol libraries
 | 
			
		||||
if test "$BUILD_LOCKDDLM_CONTROL" = yes; then
 | 
			
		||||
	PKG_CHECK_MODULES(LOCKD_DLM_CONTROL, libdlmcontrol >= 3.2, [HAVE_LOCKD_DLM_CONTROL=yes], $bailout)
 | 
			
		||||
	AC_DEFINE([LOCKDDLM_CONTROL_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd dlm control option.])
 | 
			
		||||
	BUILD_LVMLOCKD=yes
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Build lvmlockd
 | 
			
		||||
AC_MSG_CHECKING(whether to build lvmlockd)
 | 
			
		||||
@@ -967,7 +1109,9 @@ AC_MSG_RESULT($BUILD_LVMLOCKD)
 | 
			
		||||
 | 
			
		||||
if test "$BUILD_LVMLOCKD" = yes; then
 | 
			
		||||
	AS_IF([test "$LVMPOLLD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmpolld.])])
 | 
			
		||||
	AS_IF([test "$LVMETAD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmetad.])])
 | 
			
		||||
	AS_IF([test "$BUILD_LVMPOLLD" = no], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
 | 
			
		||||
	AS_IF([test "$BUILD_LVMETAD" = no], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
 | 
			
		||||
	AC_MSG_CHECKING([defaults for use_lvmlockd])
 | 
			
		||||
	AC_ARG_ENABLE(use_lvmlockd,
 | 
			
		||||
		      AC_HELP_STRING([--disable-use-lvmlockd],
 | 
			
		||||
@@ -992,6 +1136,33 @@ fi
 | 
			
		||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMLOCKD, [$DEFAULT_USE_LVMLOCKD],
 | 
			
		||||
		   [Use lvmlockd by default.])
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Check lvmetad
 | 
			
		||||
if test "$BUILD_LVMETAD" = yes; then
 | 
			
		||||
	AC_MSG_CHECKING([defaults for use_lvmetad])
 | 
			
		||||
	AC_ARG_ENABLE(use_lvmetad,
 | 
			
		||||
		      AC_HELP_STRING([--disable-use-lvmetad],
 | 
			
		||||
				     [disable usage of LVM Metadata Daemon]),
 | 
			
		||||
		      [case ${enableval} in
 | 
			
		||||
		       yes) DEFAULT_USE_LVMETAD=1 ;;
 | 
			
		||||
		       *) DEFAULT_USE_LVMETAD=0 ;;
 | 
			
		||||
		       esac], DEFAULT_USE_LVMETAD=1)
 | 
			
		||||
	AC_MSG_RESULT($DEFAULT_USE_LVMETAD)
 | 
			
		||||
	AC_DEFINE([LVMETAD_SUPPORT], 1, [Define to 1 to include code that uses lvmetad.])
 | 
			
		||||
 | 
			
		||||
	AC_ARG_WITH(lvmetad-pidfile,
 | 
			
		||||
		    AC_HELP_STRING([--with-lvmetad-pidfile=PATH],
 | 
			
		||||
				   [lvmetad pidfile [PID_DIR/lvmetad.pid]]),
 | 
			
		||||
		    LVMETAD_PIDFILE=$withval,
 | 
			
		||||
		    LVMETAD_PIDFILE="$DEFAULT_PID_DIR/lvmetad.pid")
 | 
			
		||||
	AC_DEFINE_UNQUOTED(LVMETAD_PIDFILE, ["$LVMETAD_PIDFILE"],
 | 
			
		||||
			   [Path to lvmetad pidfile.])
 | 
			
		||||
else
 | 
			
		||||
	DEFAULT_USE_LVMETAD=0
 | 
			
		||||
fi
 | 
			
		||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMETAD, [$DEFAULT_USE_LVMETAD],
 | 
			
		||||
		   [Use lvmetad by default.])
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Check lvmpolld
 | 
			
		||||
if test "$BUILD_LVMPOLLD" = yes; then
 | 
			
		||||
@@ -1195,6 +1366,20 @@ if test "$ODIRECT" = yes; then
 | 
			
		||||
	AC_DEFINE([O_DIRECT_SUPPORT], 1, [Define to 1 to enable O_DIRECT support.])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Enable liblvm2app.so
 | 
			
		||||
AC_MSG_CHECKING(whether to build liblvm2app.so application library)
 | 
			
		||||
AC_ARG_ENABLE(applib,
 | 
			
		||||
	      AC_HELP_STRING([--enable-applib], [build application library]),
 | 
			
		||||
	      APPLIB=$enableval, APPLIB=no)
 | 
			
		||||
AC_MSG_RESULT($APPLIB)
 | 
			
		||||
AC_SUBST([LVM2APP_LIB])
 | 
			
		||||
test "$APPLIB" = yes \
 | 
			
		||||
  && LVM2APP_LIB=-llvm2app \
 | 
			
		||||
  || LVM2APP_LIB=
 | 
			
		||||
AS_IF([test "$APPLIB"],
 | 
			
		||||
      [AC_MSG_WARN([liblvm2app is deprecated. Use D-Bus API])])
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Enable cmdlib
 | 
			
		||||
AC_MSG_CHECKING(whether to compile liblvm2cmd.so)
 | 
			
		||||
@@ -1218,15 +1403,48 @@ AS_IF([test "$NOTIFYDBUS_SUPPORT" = yes && test "BUILD_LVMDBUSD" = yes],
 | 
			
		||||
      [AC_MSG_WARN([Building D-Bus support without D-Bus notifications.])])
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Enable Python dbus library
 | 
			
		||||
dnl -- Enable Python liblvm2app bindings
 | 
			
		||||
AC_MSG_CHECKING(whether to build Python wrapper for liblvm2app.so)
 | 
			
		||||
AC_ARG_ENABLE(python_bindings,
 | 
			
		||||
	      AC_HELP_STRING([--enable-python_bindings], [build default Python applib bindings]),
 | 
			
		||||
	      PYTHON_BINDINGS=$enableval, PYTHON_BINDINGS=no)
 | 
			
		||||
AC_MSG_RESULT($PYTHON_BINDINGS)
 | 
			
		||||
 | 
			
		||||
if test "$BUILD_LVMDBUSD" = yes; then
 | 
			
		||||
AC_MSG_CHECKING(whether to build Python2 wrapper for liblvm2app.so)
 | 
			
		||||
AC_ARG_ENABLE(python2_bindings,
 | 
			
		||||
	      AC_HELP_STRING([--enable-python2_bindings], [build Python2 applib bindings]),
 | 
			
		||||
	      PYTHON2_BINDINGS=$enableval, PYTHON2_BINDINGS=no)
 | 
			
		||||
AC_MSG_RESULT($PYTHON2_BINDINGS)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING(whether to build Python3 wrapper for liblvm2app.so)
 | 
			
		||||
AC_ARG_ENABLE(python3_bindings,
 | 
			
		||||
	      AC_HELP_STRING([--enable-python3_bindings], [build Python3 applib bindings]),
 | 
			
		||||
	      PYTHON3_BINDINGS=$enableval, PYTHON3_BINDINGS=no)
 | 
			
		||||
AC_MSG_RESULT($PYTHON3_BINDINGS)
 | 
			
		||||
 | 
			
		||||
if test "$PYTHON_BINDINGS" = yes; then
 | 
			
		||||
	AC_MSG_ERROR([--enable-python-bindings is replaced by --enable-python2-bindings and --enable-python3-bindings])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test "$PYTHON2_BINDINGS" = yes; then
 | 
			
		||||
	AM_PATH_PYTHON([2])
 | 
			
		||||
	AC_PATH_TOOL(PYTHON2, python2)
 | 
			
		||||
	test -z "$PYTHON2" && AC_MSG_ERROR([python2 is required for --enable-python2_bindings but cannot be found])
 | 
			
		||||
	AC_PATH_TOOL(PYTHON2_CONFIG, python2-config)
 | 
			
		||||
	test -z "$PYTHON2_CONFIG" && AC_PATH_TOOL(PYTHON2_CONFIG, python-config)
 | 
			
		||||
	test -z "$PYTHON2_CONFIG" && AC_MSG_ERROR([python headers are required for --enable-python2_bindings but cannot be found])
 | 
			
		||||
	PYTHON2_INCDIRS=`"$PYTHON2_CONFIG" --includes`
 | 
			
		||||
	PYTHON2_LIBDIRS=`"$PYTHON2_CONFIG" --libs`
 | 
			
		||||
	PYTHON2DIR=$pythondir
 | 
			
		||||
	PYTHON_BINDINGS=yes
 | 
			
		||||
fi
 | 
			
		||||
	
 | 
			
		||||
if test "$PYTHON3_BINDINGS" = yes -o "$BUILD_LVMDBUSD" = yes; then
 | 
			
		||||
	unset PYTHON PYTHON_CONFIG
 | 
			
		||||
	unset am_cv_pathless_PYTHON ac_cv_path_PYTHON am_cv_python_platform
 | 
			
		||||
	unset am_cv_python_pythondir am_cv_python_version am_cv_python_pyexecdir
 | 
			
		||||
	unset ac_cv_path_PYTHON_CONFIG ac_cv_path_ac_pt_PYTHON_CONFIG
 | 
			
		||||
	m4_define_default([_AM_PYTHON_INTERPRETER_LIST],[ python3 python2 python dnl
 | 
			
		||||
	python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 dnl
 | 
			
		||||
	python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 ])
 | 
			
		||||
	AM_PATH_PYTHON([3])
 | 
			
		||||
	PYTHON3=$PYTHON
 | 
			
		||||
	test -z "$PYTHON3" && AC_MSG_ERROR([python3 is required for --enable-python3_bindings or --enable-dbus-service but cannot be found])
 | 
			
		||||
@@ -1236,12 +1454,19 @@ if test "$BUILD_LVMDBUSD" = yes; then
 | 
			
		||||
	PYTHON3_LIBDIRS=`"$PYTHON3_CONFIG" --libs`
 | 
			
		||||
	PYTHON3DIR=$pythondir
 | 
			
		||||
	test "$PYTHON3_BINDINGS" = yes && PYTHON_BINDINGS=yes
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test "$BUILD_LVMDBUSD" = yes; then
 | 
			
		||||
	# To get this macro, install autoconf-archive package then run autoreconf
 | 
			
		||||
	AC_PYTHON_MODULE([pyudev], [Required], python3)
 | 
			
		||||
	AC_PYTHON_MODULE([dbus], [Required], python3)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test "$PYTHON_BINDINGS" = yes -o "$PYTHON2_BINDINGS" = yes -o "$PYTHON3_BINDINGS" = yes; then
 | 
			
		||||
	AC_MSG_WARN([Python bindings are deprecated. Use D-Bus API])
 | 
			
		||||
	test "$APPLIB" != yes && AC_MSG_ERROR([Python_bindings require --enable-applib])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Enable pkg-config
 | 
			
		||||
AC_ARG_ENABLE(pkgconfig,
 | 
			
		||||
@@ -1313,7 +1538,7 @@ AC_CHECK_LIB(dl, dlopen,
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Check for shared/static conflicts
 | 
			
		||||
if [[ \( "$LVM1" = shared -o "$POOL" = shared \
 | 
			
		||||
if [[ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
 | 
			
		||||
      \) -a "$STATIC_LINK" = yes ]]; then
 | 
			
		||||
	AC_MSG_ERROR([Features cannot be 'shared' when building statically])
 | 
			
		||||
fi
 | 
			
		||||
@@ -1354,33 +1579,6 @@ if test "$SELINUX" = yes; then
 | 
			
		||||
		HAVE_SELINUX=no ])
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Check BLKZEROOUT support
 | 
			
		||||
 | 
			
		||||
AC_CACHE_CHECK([for BLKZEROOUT in sys/ioctl.h.],
 | 
			
		||||
	[ac_cv_have_blkzeroout],
 | 
			
		||||
	[AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
 | 
			
		||||
[#include <sys/ioctl.h>
 | 
			
		||||
#include <linux/fs.h>
 | 
			
		||||
int bar(void) { return ioctl(0, BLKZEROOUT, 0); }]
 | 
			
		||||
	 )], [ac_cv_have_blkzeroout=yes], [ac_cv_have_blkzeroout=no])])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AC_ARG_ENABLE(blkzeroout,
 | 
			
		||||
	      AC_HELP_STRING([--disable-blkzeroout],
 | 
			
		||||
			     [do not use BLKZEROOUT for device zeroing]),
 | 
			
		||||
	      BLKZEROOUT=$enableval, BLKZEROOUT=yes)
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING(whether to use BLKZEROOUT for device zeroing)
 | 
			
		||||
if test "$BLKZEROOUT" = yes; then
 | 
			
		||||
	AC_IF_YES(ac_cv_have_blkzeroout,
 | 
			
		||||
		  AC_DEFINE(HAVE_BLKZEROOUT, 1,
 | 
			
		||||
			    [Define if ioctl BLKZEROOUT can be used for device zeroing.]),
 | 
			
		||||
		  BLKZEROOUT=no)
 | 
			
		||||
fi
 | 
			
		||||
AC_MSG_RESULT($BLKZEROOUT)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Check for realtime clock support
 | 
			
		||||
RT_LIBS=
 | 
			
		||||
@@ -1414,16 +1612,6 @@ AC_IF_YES(ac_cv_stat_st_ctim,
 | 
			
		||||
dnl -- Check for getopt
 | 
			
		||||
AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 if getopt_long is available.]))
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Check for editline
 | 
			
		||||
if test "$EDITLINE" == yes; then
 | 
			
		||||
	PKG_CHECK_MODULES([EDITLINE], [libedit], [
 | 
			
		||||
		AC_DEFINE([EDITLINE_SUPPORT], 1,
 | 
			
		||||
			[Define to 1 to include the LVM editline shell.])], AC_MSG_ERROR(
 | 
			
		||||
[libedit could not be found which is required for the --enable-readline option.])
 | 
			
		||||
	)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Check for readline (Shamelessly copied from parted 1.4.17)
 | 
			
		||||
if test "$READLINE" != no; then
 | 
			
		||||
@@ -1556,12 +1744,6 @@ fi
 | 
			
		||||
AC_MSG_CHECKING(whether to enable readline)
 | 
			
		||||
AC_MSG_RESULT($READLINE)
 | 
			
		||||
 | 
			
		||||
if test "$EDITLINE" = yes; then
 | 
			
		||||
	AC_CHECK_HEADERS(editline/readline.h editline/history.h,,hard_bailout)
 | 
			
		||||
fi
 | 
			
		||||
AC_MSG_CHECKING(whether to enable editline)
 | 
			
		||||
AC_MSG_RESULT($EDITLINE)
 | 
			
		||||
 | 
			
		||||
if test "$BUILD_CMIRRORD" = yes; then
 | 
			
		||||
	AC_CHECK_FUNCS(atexit,,hard_bailout)
 | 
			
		||||
fi
 | 
			
		||||
@@ -1576,6 +1758,18 @@ if test "$BUILD_LVMPOLLD" = yes; then
 | 
			
		||||
	AC_FUNC_STRERROR_R
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test "$CLVMD" != none; then
 | 
			
		||||
	AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
 | 
			
		||||
	AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,hard_bailout)
 | 
			
		||||
	AC_FUNC_GETMNTENT
 | 
			
		||||
	AC_FUNC_SELECT_ARGTYPES
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test "$CLUSTER" != none; then
 | 
			
		||||
	AC_CHECK_HEADERS(sys/socket.h sys/un.h,,hard_bailout)
 | 
			
		||||
	AC_CHECK_FUNCS(socket,,hard_bailout)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test "$BUILD_DMEVENTD" = yes; then
 | 
			
		||||
	AC_CHECK_HEADERS(arpa/inet.h,,hard_bailout)
 | 
			
		||||
fi
 | 
			
		||||
@@ -1609,10 +1803,9 @@ SBINDIR="$(eval echo $(eval echo $sbindir))"
 | 
			
		||||
LVM_PATH="$SBINDIR/lvm"
 | 
			
		||||
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
 | 
			
		||||
 | 
			
		||||
LVMCONFIG_PATH="$SBINDIR/lvmconfig"
 | 
			
		||||
AC_DEFINE_UNQUOTED(LVMCONFIG_PATH, ["$LVMCONFIG_PATH"], [Path to lvmconfig binary.])
 | 
			
		||||
 | 
			
		||||
USRSBINDIR="$(eval echo $(eval echo $usrsbindir))"
 | 
			
		||||
CLVMD_PATH="$USRSBINDIR/clvmd"
 | 
			
		||||
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
 | 
			
		||||
 | 
			
		||||
FSADM_PATH="$SBINDIR/fsadm"
 | 
			
		||||
AC_DEFINE_UNQUOTED(FSADM_PATH, ["$FSADM_PATH"], [Path to fsadm binary.])
 | 
			
		||||
@@ -1692,6 +1885,15 @@ AC_ARG_WITH(default-locking-dir,
 | 
			
		||||
AC_DEFINE_UNQUOTED(DEFAULT_LOCK_DIR, ["$DEFAULT_LOCK_DIR"],
 | 
			
		||||
		   [Name of default locking directory.])
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- Setup default data alignment
 | 
			
		||||
AC_ARG_WITH(default-data-alignment,
 | 
			
		||||
	    AC_HELP_STRING([--with-default-data-alignment=NUM],
 | 
			
		||||
			   [set the default data alignment in MiB [1]]),
 | 
			
		||||
	    DEFAULT_DATA_ALIGNMENT=$withval, DEFAULT_DATA_ALIGNMENT=1)
 | 
			
		||||
AC_DEFINE_UNQUOTED(DEFAULT_DATA_ALIGNMENT, [$DEFAULT_DATA_ALIGNMENT],
 | 
			
		||||
		   [Default data alignment.])
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
dnl -- which kernel interface to use (ioctl only)
 | 
			
		||||
AC_MSG_CHECKING(for kernel interface choice)
 | 
			
		||||
@@ -1723,16 +1925,17 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[[()]]' '{print $2}'`
 | 
			
		||||
AC_DEFINE_UNQUOTED(LVM_CONFIGURE_LINE, "$CONFIGURE_LINE", [configure command line used])
 | 
			
		||||
 | 
			
		||||
################################################################################
 | 
			
		||||
AC_SUBST(APPLIB)
 | 
			
		||||
AC_SUBST(AWK)
 | 
			
		||||
AC_SUBST(BLKID_PC)
 | 
			
		||||
AC_SUBST(BUILD_CMIRRORD)
 | 
			
		||||
AC_SUBST(BUILD_DMEVENTD)
 | 
			
		||||
AC_SUBST(BUILD_LVMDBUSD)
 | 
			
		||||
AC_SUBST(BUILD_LVMETAD)
 | 
			
		||||
AC_SUBST(BUILD_LVMPOLLD)
 | 
			
		||||
AC_SUBST(BUILD_LVMLOCKD)
 | 
			
		||||
AC_SUBST(BUILD_LOCKDSANLOCK)
 | 
			
		||||
AC_SUBST(BUILD_LOCKDDLM)
 | 
			
		||||
AC_SUBST(BUILD_LOCKDDLM_CONTROL)
 | 
			
		||||
AC_SUBST(BUILD_DMFILEMAPD)
 | 
			
		||||
AC_SUBST(CACHE)
 | 
			
		||||
AC_SUBST(CFLAGS)
 | 
			
		||||
@@ -1741,6 +1944,14 @@ AC_SUBST(CHMOD)
 | 
			
		||||
AC_SUBST(CLDFLAGS)
 | 
			
		||||
AC_SUBST(CLDNOWHOLEARCHIVE)
 | 
			
		||||
AC_SUBST(CLDWHOLEARCHIVE)
 | 
			
		||||
AC_SUBST(CLUSTER)
 | 
			
		||||
AC_SUBST(CLVMD)
 | 
			
		||||
AC_SUBST(CLVMD_CMANAGERS)
 | 
			
		||||
AC_SUBST(CLVMD_PATH)
 | 
			
		||||
AC_SUBST(CMAN_CFLAGS)
 | 
			
		||||
AC_SUBST(CMAN_LIBS)
 | 
			
		||||
AC_SUBST(CMAP_CFLAGS)
 | 
			
		||||
AC_SUBST(CMAP_LIBS)
 | 
			
		||||
AC_SUBST(CMDLIB)
 | 
			
		||||
AC_SUBST(CONFDB_CFLAGS)
 | 
			
		||||
AC_SUBST(CONFDB_LIBS)
 | 
			
		||||
@@ -1753,6 +1964,7 @@ AC_SUBST(DEBUG)
 | 
			
		||||
AC_SUBST(DEFAULT_ARCHIVE_SUBDIR)
 | 
			
		||||
AC_SUBST(DEFAULT_BACKUP_SUBDIR)
 | 
			
		||||
AC_SUBST(DEFAULT_CACHE_SUBDIR)
 | 
			
		||||
AC_SUBST(DEFAULT_DATA_ALIGNMENT)
 | 
			
		||||
AC_SUBST(DEFAULT_DM_RUN_DIR)
 | 
			
		||||
AC_SUBST(DEFAULT_LOCK_DIR)
 | 
			
		||||
AC_SUBST(DEFAULT_MIRROR_SEGTYPE)
 | 
			
		||||
@@ -1764,6 +1976,7 @@ AC_SUBST(DEFAULT_SPARSE_SEGTYPE)
 | 
			
		||||
AC_SUBST(DEFAULT_SYS_DIR)
 | 
			
		||||
AC_SUBST(DEFAULT_SYS_LOCK_DIR)
 | 
			
		||||
AC_SUBST(DEFAULT_USE_BLKID_WIPING)
 | 
			
		||||
AC_SUBST(DEFAULT_USE_LVMETAD)
 | 
			
		||||
AC_SUBST(DEFAULT_USE_LVMPOLLD)
 | 
			
		||||
AC_SUBST(DEFAULT_USE_LVMLOCKD)
 | 
			
		||||
AC_SUBST(DEVMAPPER)
 | 
			
		||||
@@ -1817,7 +2030,6 @@ AC_SUBST(QUORUM_CFLAGS)
 | 
			
		||||
AC_SUBST(QUORUM_LIBS)
 | 
			
		||||
AC_SUBST(RT_LIBS)
 | 
			
		||||
AC_SUBST(READLINE_LIBS)
 | 
			
		||||
AC_SUBST(EDITLINE_LIBS)
 | 
			
		||||
AC_SUBST(REPLICATORS)
 | 
			
		||||
AC_SUBST(SACKPT_CFLAGS)
 | 
			
		||||
AC_SUBST(SACKPT_LIBS)
 | 
			
		||||
@@ -1848,17 +2060,14 @@ AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
 | 
			
		||||
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
 | 
			
		||||
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
 | 
			
		||||
AC_SUBST(USE_TRACKING)
 | 
			
		||||
AC_SUBST(SILENT_RULES)
 | 
			
		||||
AC_SUBST(USRSBINDIR)
 | 
			
		||||
AC_SUBST(VALGRIND_POOL)
 | 
			
		||||
AC_SUBST(VDO)
 | 
			
		||||
AC_SUBST(VDO_FORMAT_CMD)
 | 
			
		||||
AC_SUBST(VDO_INCLUDE)
 | 
			
		||||
AC_SUBST(VDO_LIB)
 | 
			
		||||
AC_SUBST(WRITE_INSTALL)
 | 
			
		||||
AC_SUBST(DMEVENTD_PIDFILE)
 | 
			
		||||
AC_SUBST(LVMETAD_PIDFILE)
 | 
			
		||||
AC_SUBST(LVMPOLLD_PIDFILE)
 | 
			
		||||
AC_SUBST(LVMLOCKD_PIDFILE)
 | 
			
		||||
AC_SUBST(CLVMD_PIDFILE)
 | 
			
		||||
AC_SUBST(CMIRRORD_PIDFILE)
 | 
			
		||||
AC_SUBST(interface)
 | 
			
		||||
AC_SUBST(kerneldir)
 | 
			
		||||
@@ -1879,8 +2088,8 @@ dnl -- keep utility scripts running properly
 | 
			
		||||
AC_CONFIG_FILES([
 | 
			
		||||
Makefile
 | 
			
		||||
make.tmpl
 | 
			
		||||
libdm/make.tmpl
 | 
			
		||||
daemons/Makefile
 | 
			
		||||
daemons/clvmd/Makefile
 | 
			
		||||
daemons/cmirrord/Makefile
 | 
			
		||||
daemons/dmeventd/Makefile
 | 
			
		||||
daemons/dmeventd/libdevmapper-event.pc
 | 
			
		||||
@@ -1891,50 +2100,68 @@ daemons/dmeventd/plugins/mirror/Makefile
 | 
			
		||||
daemons/dmeventd/plugins/snapshot/Makefile
 | 
			
		||||
daemons/dmeventd/plugins/thin/Makefile
 | 
			
		||||
daemons/dmeventd/plugins/vdo/Makefile
 | 
			
		||||
daemons/dmfilemapd/Makefile
 | 
			
		||||
daemons/lvmdbusd/Makefile
 | 
			
		||||
daemons/lvmdbusd/lvmdbusd
 | 
			
		||||
daemons/lvmdbusd/lvmdb.py
 | 
			
		||||
daemons/lvmdbusd/lvm_shell_proxy.py
 | 
			
		||||
daemons/lvmdbusd/path.py
 | 
			
		||||
daemons/lvmetad/Makefile
 | 
			
		||||
daemons/lvmpolld/Makefile
 | 
			
		||||
daemons/lvmlockd/Makefile
 | 
			
		||||
device_mapper/Makefile
 | 
			
		||||
conf/Makefile
 | 
			
		||||
conf/example.conf
 | 
			
		||||
conf/lvmlocal.conf
 | 
			
		||||
conf/command_profile_template.profile
 | 
			
		||||
conf/metadata_profile_template.profile
 | 
			
		||||
include/.symlinks
 | 
			
		||||
include/Makefile
 | 
			
		||||
lib/Makefile
 | 
			
		||||
lib/locking/Makefile
 | 
			
		||||
include/lvm-version.h
 | 
			
		||||
libdaemon/Makefile
 | 
			
		||||
libdaemon/client/Makefile
 | 
			
		||||
libdaemon/server/Makefile
 | 
			
		||||
libdm/Makefile
 | 
			
		||||
libdm/dm-tools/Makefile
 | 
			
		||||
libdm/libdevmapper.pc
 | 
			
		||||
liblvm/Makefile
 | 
			
		||||
liblvm/liblvm2app.pc
 | 
			
		||||
man/Makefile
 | 
			
		||||
po/Makefile
 | 
			
		||||
scripts/lvm2-pvscan.service
 | 
			
		||||
python/Makefile
 | 
			
		||||
python/setup.py
 | 
			
		||||
scripts/blkdeactivate.sh
 | 
			
		||||
scripts/blk_availability_init_red_hat
 | 
			
		||||
scripts/blk_availability_systemd_red_hat.service
 | 
			
		||||
scripts/clvmd_init_red_hat
 | 
			
		||||
scripts/cmirrord_init_red_hat
 | 
			
		||||
scripts/com.redhat.lvmdbus1.service
 | 
			
		||||
scripts/dm_event_systemd_red_hat.service
 | 
			
		||||
scripts/dm_event_systemd_red_hat.socket
 | 
			
		||||
scripts/lvm2_cluster_activation_red_hat.sh
 | 
			
		||||
scripts/lvm2_cluster_activation_systemd_red_hat.service
 | 
			
		||||
scripts/lvm2_clvmd_systemd_red_hat.service
 | 
			
		||||
scripts/lvm2_cmirrord_systemd_red_hat.service
 | 
			
		||||
scripts/lvm2_lvmdbusd_systemd_red_hat.service
 | 
			
		||||
scripts/lvm2_lvmetad_init_red_hat
 | 
			
		||||
scripts/lvm2_lvmetad_systemd_red_hat.service
 | 
			
		||||
scripts/lvm2_lvmetad_systemd_red_hat.socket
 | 
			
		||||
scripts/lvm2_lvmpolld_init_red_hat
 | 
			
		||||
scripts/lvm2_lvmpolld_systemd_red_hat.service
 | 
			
		||||
scripts/lvm2_lvmpolld_systemd_red_hat.socket
 | 
			
		||||
scripts/lvmlockd.service
 | 
			
		||||
scripts/lvmlocks.service
 | 
			
		||||
scripts/lvm2_lvmlockd_systemd_red_hat.service
 | 
			
		||||
scripts/lvm2_lvmlocking_systemd_red_hat.service
 | 
			
		||||
scripts/lvm2_monitoring_init_red_hat
 | 
			
		||||
scripts/lvm2_monitoring_systemd_red_hat.service
 | 
			
		||||
scripts/lvm2_pvscan_systemd_red_hat@.service
 | 
			
		||||
scripts/lvm2_tmpfiles_red_hat.conf
 | 
			
		||||
scripts/lvmdump.sh
 | 
			
		||||
scripts/Makefile
 | 
			
		||||
test/Makefile
 | 
			
		||||
test/api/Makefile
 | 
			
		||||
test/api/python_lvm_unit.py
 | 
			
		||||
test/unit/Makefile
 | 
			
		||||
tools/Makefile
 | 
			
		||||
udev/Makefile
 | 
			
		||||
])
 | 
			
		||||
@@ -1952,9 +2179,6 @@ AS_IF([test -n "$CACHE_CONFIGURE_WARN"],
 | 
			
		||||
AS_IF([test -n "$CACHE_CHECK_VERSION_WARN"],
 | 
			
		||||
      [AC_MSG_WARN([You should install latest cache_check vsn 0.7.0 to use lvm2 cache metadata format 2])])
 | 
			
		||||
 | 
			
		||||
AS_IF([test -n "$VDO_CONFIGURE_WARN"],
 | 
			
		||||
      [AC_MSG_WARN([Unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!])])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AS_IF([test "$ODIRECT" != yes],
 | 
			
		||||
      [AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])])
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,6 @@ const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile
 | 
			
		||||
	return "STRING";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
struct logical_volume *origin_from_cow(const struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	if (lv)
 | 
			
		||||
@@ -54,7 +53,6 @@ struct logical_volume *origin_from_cow(const struct logical_volume *lv)
 | 
			
		||||
 | 
			
		||||
	__coverity_panic__();
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/* simple_memccpy() from glibc */
 | 
			
		||||
void *memccpy(void *dest, const void *src, int c, size_t n)
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,11 @@ srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
.PHONY: dmeventd cmirrord lvmpolld lvmlockd
 | 
			
		||||
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld lvmlockd
 | 
			
		||||
 | 
			
		||||
ifneq ("@CLVMD@", "none")
 | 
			
		||||
  SUBDIRS += clvmd
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_CMIRRORD@", "yes")
 | 
			
		||||
  SUBDIRS += cmirrord
 | 
			
		||||
@@ -28,6 +32,10 @@ daemons.cflow: dmeventd.cflow
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_LVMETAD@", "yes")
 | 
			
		||||
  SUBDIRS += lvmetad
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_LVMPOLLD@", "yes")
 | 
			
		||||
  SUBDIRS += lvmpolld
 | 
			
		||||
endif
 | 
			
		||||
@@ -40,8 +48,12 @@ ifeq ("@BUILD_LVMDBUSD@", "yes")
 | 
			
		||||
  SUBDIRS += lvmdbusd
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_DMFILEMAPD@", "yes")
 | 
			
		||||
  SUBDIRS += dmfilemapd
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ($(MAKECMDGOALS),distclean)
 | 
			
		||||
  SUBDIRS = cmirrord dmeventd lvmpolld lvmlockd lvmdbusd
 | 
			
		||||
  SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd dmfilemapd
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								daemons/clvmd/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								daemons/clvmd/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
clvmd
 | 
			
		||||
							
								
								
									
										94
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of LVM2.
 | 
			
		||||
#
 | 
			
		||||
# This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
# of the GNU General Public License v.2.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 | 
			
		||||
srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
CMAN_LIBS = @CMAN_LIBS@
 | 
			
		||||
CMAN_CFLAGS = @CMAN_CFLAGS@
 | 
			
		||||
CMAP_LIBS = @CMAP_LIBS@
 | 
			
		||||
CMAP_CFLAGS = @CMAP_CFLAGS@
 | 
			
		||||
CONFDB_LIBS = @CONFDB_LIBS@
 | 
			
		||||
CONFDB_CFLAGS = @CONFDB_CFLAGS@
 | 
			
		||||
CPG_LIBS = @CPG_LIBS@
 | 
			
		||||
CPG_CFLAGS = @CPG_CFLAGS@
 | 
			
		||||
DLM_LIBS = @DLM_LIBS@
 | 
			
		||||
DLM_CFLAGS = @DLM_CFLAGS@
 | 
			
		||||
QUORUM_LIBS = @QUORUM_LIBS@
 | 
			
		||||
QUORUM_CFLAGS = @QUORUM_CFLAGS@
 | 
			
		||||
SALCK_LIBS = @SALCK_LIBS@
 | 
			
		||||
SALCK_CFLAGS = @SALCK_CFLAGS@
 | 
			
		||||
 | 
			
		||||
SOURCES = \
 | 
			
		||||
	clvmd-command.c\
 | 
			
		||||
	clvmd.c\
 | 
			
		||||
	lvm-functions.c\
 | 
			
		||||
	refresh_clvmd.c
 | 
			
		||||
 | 
			
		||||
ifneq (,$(findstring cman,, "@CLVMD@,"))
 | 
			
		||||
	SOURCES += clvmd-cman.c
 | 
			
		||||
	LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS)
 | 
			
		||||
	CFLAGS += $(CMAN_CFLAGS) $(CONFDB_CFLAGS) $(DLM_CFLAGS)
 | 
			
		||||
	DEFS += -DUSE_CMAN
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq (,$(findstring openais,, "@CLVMD@,"))
 | 
			
		||||
	SOURCES += clvmd-openais.c
 | 
			
		||||
	LMLIBS += $(CONFDB_LIBS) $(CPG_LIBS) $(SALCK_LIBS)
 | 
			
		||||
	CFLAGS += $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(SALCK_CFLAGS)
 | 
			
		||||
	DEFS += -DUSE_OPENAIS
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq (,$(findstring corosync,, "@CLVMD@,"))
 | 
			
		||||
	SOURCES += clvmd-corosync.c
 | 
			
		||||
	LMLIBS += $(CMAP_LIBS) $(CONFDB_LIBS) $(CPG_LIBS) $(DLM_LIBS) $(QUORUM_LIBS)
 | 
			
		||||
	CFLAGS += $(CMAP_CFLAGS) $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(DLM_CFLAGS) $(QUORUM_CFLAGS)
 | 
			
		||||
	DEFS += -DUSE_COROSYNC
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifneq (,$(findstring singlenode,, "@CLVMD@,"))
 | 
			
		||||
	SOURCES += clvmd-singlenode.c
 | 
			
		||||
	DEFS += -DUSE_SINGLENODE
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ($(MAKECMDGOALS),distclean)
 | 
			
		||||
	SOURCES += clvmd-cman.c
 | 
			
		||||
	SOURCES += clvmd-openais.c
 | 
			
		||||
	SOURCES += clvmd-corosync.c
 | 
			
		||||
	SOURCES += clvmd-singlenode.c
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
TARGETS = \
 | 
			
		||||
	clvmd
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS) -laio
 | 
			
		||||
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
 | 
			
		||||
INSTALL_TARGETS = \
 | 
			
		||||
	install_clvmd
 | 
			
		||||
 | 
			
		||||
clvmd: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
 | 
			
		||||
	      -o clvmd $(OBJECTS) $(LMLIBS) $(LIBS)
 | 
			
		||||
 | 
			
		||||
.PHONY: install_clvmd
 | 
			
		||||
 | 
			
		||||
install_clvmd: $(TARGETS)
 | 
			
		||||
	$(INSTALL_PROGRAM) -D clvmd $(usrsbindir)/clvmd
 | 
			
		||||
 | 
			
		||||
install: $(INSTALL_TARGETS)
 | 
			
		||||
 | 
			
		||||
install_cluster: $(INSTALL_TARGETS)
 | 
			
		||||
							
								
								
									
										85
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Definitions for CLVMD server and clients */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The protocol spoken over the cluster and across the local socket.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _CLVM_H
 | 
			
		||||
#define _CLVM_H
 | 
			
		||||
 | 
			
		||||
#include "configure.h"
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
 | 
			
		||||
struct clvm_header {
 | 
			
		||||
	uint8_t  cmd;	        /* See below */
 | 
			
		||||
	uint8_t  flags;	        /* See below */
 | 
			
		||||
	uint16_t xid;	        /* Transaction ID */
 | 
			
		||||
	uint32_t clientid;	/* Only used in Daemon->Daemon comms */
 | 
			
		||||
	int32_t  status;	/* For replies, whether request succeeded */
 | 
			
		||||
	uint32_t arglen;	/* Length of argument below.
 | 
			
		||||
				   If >1500 then it will be passed
 | 
			
		||||
				   around the cluster in the system LV */
 | 
			
		||||
	char node[1];		/* Actually a NUL-terminated string, node name.
 | 
			
		||||
				   If this is empty then the command is
 | 
			
		||||
				   forwarded to all cluster nodes unless
 | 
			
		||||
				   FLAG_LOCAL or FLAG_REMOTE is also set. */
 | 
			
		||||
	char args[1];		/* Arguments for the command follow the
 | 
			
		||||
				   node name, This member is only
 | 
			
		||||
				   valid if the node name is empty */
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
/* Flags */
 | 
			
		||||
#define CLVMD_FLAG_LOCAL	1	/* Only do this on the local node */
 | 
			
		||||
#define CLVMD_FLAG_SYSTEMLV	2	/* Data in system LV under my node name */
 | 
			
		||||
#define CLVMD_FLAG_NODEERRS	4	/* Reply has errors in node-specific portion */
 | 
			
		||||
#define CLVMD_FLAG_REMOTE	8	/* Do this on all nodes except for the local node */
 | 
			
		||||
 | 
			
		||||
/* Name of the local socket to communicate between lvm and clvmd */
 | 
			
		||||
#define CLVMD_SOCKNAME		DEFAULT_RUN_DIR "/clvmd.sock"
 | 
			
		||||
 | 
			
		||||
/* Internal commands & replies */
 | 
			
		||||
#define CLVMD_CMD_REPLY    1
 | 
			
		||||
#define CLVMD_CMD_VERSION  2	/* Send version around cluster when we start */
 | 
			
		||||
#define CLVMD_CMD_GOAWAY   3	/* Die if received this - we are running
 | 
			
		||||
				   an incompatible version */
 | 
			
		||||
#define CLVMD_CMD_TEST     4	/* Just for mucking about */
 | 
			
		||||
 | 
			
		||||
#define CLVMD_CMD_LOCK              30
 | 
			
		||||
#define CLVMD_CMD_UNLOCK            31
 | 
			
		||||
 | 
			
		||||
/* Lock/Unlock commands */
 | 
			
		||||
#define CLVMD_CMD_LOCK_LV           50
 | 
			
		||||
#define CLVMD_CMD_LOCK_VG           51
 | 
			
		||||
#define CLVMD_CMD_LOCK_QUERY	    52
 | 
			
		||||
 | 
			
		||||
/* Misc functions */
 | 
			
		||||
#define CLVMD_CMD_REFRESH	    40
 | 
			
		||||
#define CLVMD_CMD_GET_CLUSTERNAME   41
 | 
			
		||||
#define CLVMD_CMD_SET_DEBUG	    42
 | 
			
		||||
#define CLVMD_CMD_VG_BACKUP	    43
 | 
			
		||||
#define CLVMD_CMD_RESTART	    44
 | 
			
		||||
#define CLVMD_CMD_SYNC_NAMES	    45
 | 
			
		||||
 | 
			
		||||
/* Used internally by some callers, but not part of the protocol.*/
 | 
			
		||||
#ifndef NODE_ALL
 | 
			
		||||
#  define NODE_ALL	"*"
 | 
			
		||||
#  define NODE_LOCAL	"."
 | 
			
		||||
#  define NODE_REMOTE	"^"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										505
									
								
								daemons/clvmd/clvmd-cman.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										505
									
								
								daemons/clvmd/clvmd-cman.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,505 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * CMAN communication layer for clvmd.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
#include "lvm-functions.h"
 | 
			
		||||
 | 
			
		||||
#include <libdlm.h>
 | 
			
		||||
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
#define LOCKSPACE_NAME "clvmd"
 | 
			
		||||
 | 
			
		||||
struct clvmd_node
 | 
			
		||||
{
 | 
			
		||||
	struct cman_node *node;
 | 
			
		||||
	int clvmd_up;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int num_nodes;
 | 
			
		||||
static struct cman_node *nodes = NULL;
 | 
			
		||||
static struct cman_node this_node;
 | 
			
		||||
static int count_nodes; /* size of allocated nodes array */
 | 
			
		||||
static struct dm_hash_table *node_updown_hash;
 | 
			
		||||
static dlm_lshandle_t *lockspace;
 | 
			
		||||
static cman_handle_t c_handle;
 | 
			
		||||
 | 
			
		||||
static void count_clvmds_running(void);
 | 
			
		||||
static void get_members(void);
 | 
			
		||||
static int nodeid_from_csid(const char *csid);
 | 
			
		||||
static int name_from_nodeid(int nodeid, char *name);
 | 
			
		||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg);
 | 
			
		||||
static void data_callback(cman_handle_t handle, void *private,
 | 
			
		||||
			  char *buf, int len, uint8_t port, int nodeid);
 | 
			
		||||
 | 
			
		||||
struct lock_wait {
 | 
			
		||||
	pthread_cond_t cond;
 | 
			
		||||
	pthread_mutex_t mutex;
 | 
			
		||||
	struct dlm_lksb lksb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int _init_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	node_updown_hash = dm_hash_create(100);
 | 
			
		||||
 | 
			
		||||
	/* Open the cluster communication socket */
 | 
			
		||||
	c_handle = cman_init(NULL);
 | 
			
		||||
	if (!c_handle) {
 | 
			
		||||
		syslog(LOG_ERR, "Can't open cluster manager socket: %m");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	DEBUGLOG("Connected to CMAN\n");
 | 
			
		||||
 | 
			
		||||
	if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
 | 
			
		||||
		syslog(LOG_ERR, "Can't bind cluster socket: %m");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cman_start_notification(c_handle, event_callback)) {
 | 
			
		||||
		syslog(LOG_ERR, "Can't start cluster event listening");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Get the cluster members list */
 | 
			
		||||
	get_members();
 | 
			
		||||
	count_clvmds_running();
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("CMAN initialisation complete\n");
 | 
			
		||||
 | 
			
		||||
	/* Create a lockspace for LV & VG locks to live in */
 | 
			
		||||
	lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
 | 
			
		||||
	if (!lockspace) {
 | 
			
		||||
		lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
 | 
			
		||||
		if (!lockspace) {
 | 
			
		||||
			syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		DEBUGLOG("Created DLM lockspace for CLVMD.\n");
 | 
			
		||||
	} else
 | 
			
		||||
		DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
 | 
			
		||||
 | 
			
		||||
	dlm_ls_pthread_init(lockspace);
 | 
			
		||||
	DEBUGLOG("DLM initialisation complete\n");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _cluster_init_completed(void)
 | 
			
		||||
{
 | 
			
		||||
	clvmd_cluster_init_completed();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_main_cluster_fd(void)
 | 
			
		||||
{
 | 
			
		||||
	return cman_get_fd(c_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_num_nodes(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int nnodes = 0;
 | 
			
		||||
 | 
			
		||||
	/* return number of ACTIVE nodes */
 | 
			
		||||
	for (i=0; i<num_nodes; i++) {
 | 
			
		||||
		if (nodes[i].cn_member && nodes[i].cn_nodeid)
 | 
			
		||||
			nnodes++;
 | 
			
		||||
	}
 | 
			
		||||
	return nnodes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* send_message with the fd check removed */
 | 
			
		||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
 | 
			
		||||
				 const char *errtext)
 | 
			
		||||
{
 | 
			
		||||
	int nodeid = 0;
 | 
			
		||||
 | 
			
		||||
	if (csid)
 | 
			
		||||
		memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
 | 
			
		||||
	{
 | 
			
		||||
		log_error("%s", errtext);
 | 
			
		||||
	}
 | 
			
		||||
	return msglen;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _get_our_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
	if (this_node.cn_nodeid == 0) {
 | 
			
		||||
		cman_get_node(c_handle, 0, &this_node);
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Call a callback routine for each node is that known (down means not running a clvmd) */
 | 
			
		||||
static int _cluster_do_node_callback(struct local_client *client,
 | 
			
		||||
				     void (*callback) (struct local_client *,
 | 
			
		||||
						       const char *,
 | 
			
		||||
						       int))
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int somedown = 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < _get_num_nodes(); i++) {
 | 
			
		||||
		if (nodes[i].cn_member && nodes[i].cn_nodeid) {
 | 
			
		||||
			int up = (int)(long)dm_hash_lookup_binary(node_updown_hash, (char *)&nodes[i].cn_nodeid, sizeof(int));
 | 
			
		||||
 | 
			
		||||
			callback(client, (char *)&nodes[i].cn_nodeid, up);
 | 
			
		||||
			if (!up)
 | 
			
		||||
				somedown = -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return somedown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Process OOB messages from the cluster socket */
 | 
			
		||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
 | 
			
		||||
{
 | 
			
		||||
	char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
 | 
			
		||||
	switch (reason) {
 | 
			
		||||
        case CMAN_REASON_PORTCLOSED:
 | 
			
		||||
		name_from_nodeid(arg, namebuf);
 | 
			
		||||
		log_notice("clvmd on node %s has died\n", namebuf);
 | 
			
		||||
		DEBUGLOG("Got port closed message, removing node %s\n", namebuf);
 | 
			
		||||
 | 
			
		||||
		dm_hash_insert_binary(node_updown_hash, (char *)&arg, sizeof(int), (void *)0);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CMAN_REASON_STATECHANGE:
 | 
			
		||||
		DEBUGLOG("Got state change message, re-reading members list\n");
 | 
			
		||||
		get_members();
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
#if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2
 | 
			
		||||
	case CMAN_REASON_PORTOPENED:
 | 
			
		||||
		/* Ignore this, wait for startup message from clvmd itself */
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CMAN_REASON_TRY_SHUTDOWN:
 | 
			
		||||
		DEBUGLOG("Got try shutdown, sending OK\n");
 | 
			
		||||
		cman_replyto_shutdown(c_handle, 1);
 | 
			
		||||
		break;
 | 
			
		||||
#endif
 | 
			
		||||
	default:
 | 
			
		||||
		/* ERROR */
 | 
			
		||||
		DEBUGLOG("Got unknown event callback message: %d\n", reason);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct local_client *cman_client;
 | 
			
		||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
 | 
			
		||||
				const char *csid,
 | 
			
		||||
				struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	/* Save this for data_callback */
 | 
			
		||||
	cman_client = fd;
 | 
			
		||||
 | 
			
		||||
	/* We never return a new client */
 | 
			
		||||
	*new_client = NULL;
 | 
			
		||||
 | 
			
		||||
	return cman_dispatch(c_handle, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void data_callback(cman_handle_t handle, void *private,
 | 
			
		||||
			  char *buf, int len, uint8_t port, int nodeid)
 | 
			
		||||
{
 | 
			
		||||
	/* Ignore looped back messages */
 | 
			
		||||
	if (nodeid == this_node.cn_nodeid)
 | 
			
		||||
		return;
 | 
			
		||||
	process_message(cman_client, buf, len, (char *)&nodeid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _add_up_node(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
	/* It's up ! */
 | 
			
		||||
	int nodeid = nodeid_from_csid(csid);
 | 
			
		||||
 | 
			
		||||
	dm_hash_insert_binary(node_updown_hash, (char *)&nodeid, sizeof(int), (void *)1);
 | 
			
		||||
	DEBUGLOG("Added new node %d to updown list\n", nodeid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _cluster_closedown(void)
 | 
			
		||||
{
 | 
			
		||||
	dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
 | 
			
		||||
	cman_finish(c_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int is_listening(int nodeid)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD);
 | 
			
		||||
		if (status < 0 && errno == EBUSY) {	/* Don't busywait */
 | 
			
		||||
			sleep(1);
 | 
			
		||||
			errno = EBUSY;	/* In case sleep trashes it */
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	while (status < 0 && errno == EBUSY);
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Populate the list of CLVMDs running.
 | 
			
		||||
   called only at startup time */
 | 
			
		||||
static void count_clvmds_running(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_nodes; i++) {
 | 
			
		||||
		int nodeid = nodes[i].cn_nodeid;
 | 
			
		||||
 | 
			
		||||
		if (is_listening(nodeid) == 1)
 | 
			
		||||
			dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)1);
 | 
			
		||||
		else
 | 
			
		||||
			dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)0);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Get a list of active cluster members */
 | 
			
		||||
static void get_members(void)
 | 
			
		||||
{
 | 
			
		||||
	int retnodes;
 | 
			
		||||
	int status;
 | 
			
		||||
	int i;
 | 
			
		||||
	int high_nodeid = 0;
 | 
			
		||||
 | 
			
		||||
	num_nodes = cman_get_node_count(c_handle);
 | 
			
		||||
	if (num_nodes == -1) {
 | 
			
		||||
		log_error("Unable to get node count");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Not enough room for new nodes list ? */
 | 
			
		||||
	if (num_nodes > count_nodes && nodes) {
 | 
			
		||||
		free(nodes);
 | 
			
		||||
		nodes = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (nodes == NULL) {
 | 
			
		||||
		count_nodes = num_nodes + 10; /* Overallocate a little */
 | 
			
		||||
		nodes = malloc(count_nodes * sizeof(struct cman_node));
 | 
			
		||||
		if (!nodes) {
 | 
			
		||||
			log_error("Unable to allocate nodes array\n");
 | 
			
		||||
			exit(5);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
 | 
			
		||||
	if (status < 0) {
 | 
			
		||||
		log_error("Unable to get node details");
 | 
			
		||||
		exit(6);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Get the highest nodeid */
 | 
			
		||||
	for (i=0; i<retnodes; i++) {
 | 
			
		||||
		if (nodes[i].cn_nodeid > high_nodeid)
 | 
			
		||||
			high_nodeid = nodes[i].cn_nodeid;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Convert a node name to a CSID */
 | 
			
		||||
static int _csid_from_name(char *csid, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_nodes; i++) {
 | 
			
		||||
		if (strcmp(name, nodes[i].cn_name) == 0) {
 | 
			
		||||
			memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Convert a CSID to a node name */
 | 
			
		||||
static int _name_from_csid(const char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_nodes; i++) {
 | 
			
		||||
		if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) {
 | 
			
		||||
			strcpy(name, nodes[i].cn_name);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Who?? */
 | 
			
		||||
	strcpy(name, "Unknown");
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Convert a node ID to a node name */
 | 
			
		||||
static int name_from_nodeid(int nodeid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_nodes; i++) {
 | 
			
		||||
		if (nodeid == nodes[i].cn_nodeid) {
 | 
			
		||||
			strcpy(name, nodes[i].cn_name);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Who?? */
 | 
			
		||||
	strcpy(name, "Unknown");
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Convert a CSID to a node ID */
 | 
			
		||||
static int nodeid_from_csid(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
        int nodeid;
 | 
			
		||||
 | 
			
		||||
	memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	return nodeid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _is_quorate(void)
 | 
			
		||||
{
 | 
			
		||||
	return cman_is_quorate(c_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sync_ast_routine(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct lock_wait *lwait = arg;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lwait->mutex);
 | 
			
		||||
	pthread_cond_signal(&lwait->cond);
 | 
			
		||||
	pthread_mutex_unlock(&lwait->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	struct lock_wait lwait;
 | 
			
		||||
 | 
			
		||||
	if (!lockid) {
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags);
 | 
			
		||||
	/* Conversions need the lockid in the LKSB */
 | 
			
		||||
	if (flags & LKF_CONVERT)
 | 
			
		||||
		lwait.lksb.sb_lkid = *lockid;
 | 
			
		||||
 | 
			
		||||
	pthread_cond_init(&lwait.cond, NULL);
 | 
			
		||||
	pthread_mutex_init(&lwait.mutex, NULL);
 | 
			
		||||
	pthread_mutex_lock(&lwait.mutex);
 | 
			
		||||
 | 
			
		||||
	status = dlm_ls_lock(lockspace,
 | 
			
		||||
			     mode,
 | 
			
		||||
			     &lwait.lksb,
 | 
			
		||||
			     flags,
 | 
			
		||||
			     resource,
 | 
			
		||||
			     strlen(resource),
 | 
			
		||||
			     0, sync_ast_routine, &lwait, NULL, NULL);
 | 
			
		||||
	if (status)
 | 
			
		||||
		return status;
 | 
			
		||||
 | 
			
		||||
	/* Wait for it to complete */
 | 
			
		||||
	pthread_cond_wait(&lwait.cond, &lwait.mutex);
 | 
			
		||||
	pthread_mutex_unlock(&lwait.mutex);
 | 
			
		||||
 | 
			
		||||
	*lockid = lwait.lksb.sb_lkid;
 | 
			
		||||
 | 
			
		||||
	errno = lwait.lksb.sb_status;
 | 
			
		||||
	DEBUGLOG("sync_lock: returning lkid %x\n", *lockid);
 | 
			
		||||
	if (lwait.lksb.sb_status)
 | 
			
		||||
		return -1;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	struct lock_wait lwait;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid);
 | 
			
		||||
 | 
			
		||||
	pthread_cond_init(&lwait.cond, NULL);
 | 
			
		||||
	pthread_mutex_init(&lwait.mutex, NULL);
 | 
			
		||||
	pthread_mutex_lock(&lwait.mutex);
 | 
			
		||||
 | 
			
		||||
	status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait);
 | 
			
		||||
 | 
			
		||||
	if (status)
 | 
			
		||||
		return status;
 | 
			
		||||
 | 
			
		||||
	/* Wait for it to complete */
 | 
			
		||||
	pthread_cond_wait(&lwait.cond, &lwait.mutex);
 | 
			
		||||
	pthread_mutex_unlock(&lwait.mutex);
 | 
			
		||||
 | 
			
		||||
	errno = lwait.lksb.sb_status;
 | 
			
		||||
	if (lwait.lksb.sb_status != EUNLOCK)
 | 
			
		||||
		return -1;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_cluster_name(char *buf, int buflen)
 | 
			
		||||
{
 | 
			
		||||
	cman_cluster_t cluster_info;
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	status = cman_get_cluster(c_handle, &cluster_info);
 | 
			
		||||
	if (!status) {
 | 
			
		||||
		strncpy(buf, cluster_info.ci_name, buflen);
 | 
			
		||||
	}
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct cluster_ops _cluster_cman_ops = {
 | 
			
		||||
	.name                     = "cman",
 | 
			
		||||
	.cluster_init_completed   = _cluster_init_completed,
 | 
			
		||||
	.cluster_send_message     = _cluster_send_message,
 | 
			
		||||
	.name_from_csid           = _name_from_csid,
 | 
			
		||||
	.csid_from_name           = _csid_from_name,
 | 
			
		||||
	.get_num_nodes            = _get_num_nodes,
 | 
			
		||||
	.cluster_fd_callback      = _cluster_fd_callback,
 | 
			
		||||
	.get_main_cluster_fd      = _get_main_cluster_fd,
 | 
			
		||||
	.cluster_do_node_callback = _cluster_do_node_callback,
 | 
			
		||||
	.is_quorate               = _is_quorate,
 | 
			
		||||
	.get_our_csid             = _get_our_csid,
 | 
			
		||||
	.add_up_node              = _add_up_node,
 | 
			
		||||
	.cluster_closedown        = _cluster_closedown,
 | 
			
		||||
	.get_cluster_name         = _get_cluster_name,
 | 
			
		||||
	.sync_lock                = _sync_lock,
 | 
			
		||||
	.sync_unlock              = _sync_unlock,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cluster_ops *init_cman_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!_init_cluster())
 | 
			
		||||
		return &_cluster_cman_ops;
 | 
			
		||||
	else
 | 
			
		||||
		return NULL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										415
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										415
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,415 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  CLVMD Cluster LVM daemon command processor.
 | 
			
		||||
 | 
			
		||||
  To add commands to the daemon simply add a processor in do_command and return
 | 
			
		||||
  and messages back in buf and the length in *retlen. The initial value of
 | 
			
		||||
  buflen is the maximum size of the buffer. if buf is not large enough then it
 | 
			
		||||
  may be reallocated by the functions in here to a suitable size bearing in
 | 
			
		||||
  mind that anything larger than the passed-in size will have to be returned
 | 
			
		||||
  using the system LV and so performance will suffer.
 | 
			
		||||
 | 
			
		||||
  The status return will be negated and passed back to the originating node.
 | 
			
		||||
 | 
			
		||||
  pre- and post- command routines are called only on the local node. The
 | 
			
		||||
  purpose is primarily to get and release locks, though the pre- routine should
 | 
			
		||||
  also do any other local setups required by the command (if any) and can
 | 
			
		||||
  return a failure code that prevents the command from being distributed around
 | 
			
		||||
  the cluster
 | 
			
		||||
 | 
			
		||||
  The pre- and post- routines are run in their own thread so can block as long
 | 
			
		||||
  they like, do_command is run in the main clvmd thread so should not block for
 | 
			
		||||
  too long. If the pre-command returns an error code (!=0) then the command
 | 
			
		||||
  will not be propogated around the cluster but the post-command WILL be called
 | 
			
		||||
 | 
			
		||||
  Also note that the pre and post routine are *always* called on the local
 | 
			
		||||
  node, even if the command to be executed was only requested to run on a
 | 
			
		||||
  remote node. It may peek inside the client structure to check the status of
 | 
			
		||||
  the command.
 | 
			
		||||
 | 
			
		||||
  The clients of the daemon must, naturally, understand the return messages and
 | 
			
		||||
  codes.
 | 
			
		||||
 | 
			
		||||
  Routines in here may only READ the values in the client structure passed in
 | 
			
		||||
  apart from client->private which they are free to do what they like with.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
#include "lvm-globals.h"
 | 
			
		||||
#include "lvm-functions.h"
 | 
			
		||||
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
 | 
			
		||||
extern struct cluster_ops *clops;
 | 
			
		||||
static int restart_clvmd(void);
 | 
			
		||||
 | 
			
		||||
/* This is where all the real work happens:
 | 
			
		||||
   NOTE: client will be NULL when this is executed on a remote node */
 | 
			
		||||
int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
 | 
			
		||||
	       char **buf, int buflen, int *retlen)
 | 
			
		||||
{
 | 
			
		||||
	char *args = msg->node + strlen(msg->node) + 1;
 | 
			
		||||
	int arglen = msglen - sizeof(struct clvm_header) - strlen(msg->node);
 | 
			
		||||
	int status = 0;
 | 
			
		||||
	char *lockname;
 | 
			
		||||
	const char *locktype;
 | 
			
		||||
	struct utsname nodeinfo;
 | 
			
		||||
	unsigned char lock_cmd;
 | 
			
		||||
	unsigned char lock_flags;
 | 
			
		||||
 | 
			
		||||
	/* Do the command */
 | 
			
		||||
	switch (msg->cmd) {
 | 
			
		||||
		/* Just a test message */
 | 
			
		||||
	case CLVMD_CMD_TEST:
 | 
			
		||||
		if (arglen > buflen) {
 | 
			
		||||
			char *new_buf;
 | 
			
		||||
			buflen = arglen + 200;
 | 
			
		||||
			new_buf = realloc(*buf, buflen);
 | 
			
		||||
			if (new_buf == NULL) {
 | 
			
		||||
				status = errno;
 | 
			
		||||
				free (*buf);
 | 
			
		||||
			}
 | 
			
		||||
			*buf = new_buf;
 | 
			
		||||
		}
 | 
			
		||||
		if (*buf) {
 | 
			
		||||
			if (uname(&nodeinfo))
 | 
			
		||||
				memset(&nodeinfo, 0, sizeof(nodeinfo));
 | 
			
		||||
 | 
			
		||||
			*retlen = 1 + dm_snprintf(*buf, buflen,
 | 
			
		||||
						  "TEST from %s: %s v%s",
 | 
			
		||||
						  nodeinfo.nodename, args,
 | 
			
		||||
						  nodeinfo.release);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_VG:
 | 
			
		||||
		lock_cmd = args[0];
 | 
			
		||||
		lock_flags = args[1];
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		/* Check to see if the VG is in use by LVM1 */
 | 
			
		||||
		do_lock_vg(lock_cmd, lock_flags, lockname);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_LV:
 | 
			
		||||
		/* This is the biggie */
 | 
			
		||||
		lock_cmd = args[0];
 | 
			
		||||
		lock_flags = args[1];
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		status = do_lock_lv(lock_cmd, lock_flags, lockname);
 | 
			
		||||
		/* Replace EIO with something less scary */
 | 
			
		||||
		if (status == EIO) {
 | 
			
		||||
			*retlen = 1 + dm_snprintf(*buf, buflen, "%s",
 | 
			
		||||
						  get_last_lvm_error());
 | 
			
		||||
			return EIO;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_QUERY:
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		if (buflen < 3)
 | 
			
		||||
			return EIO;
 | 
			
		||||
		if ((locktype = do_lock_query(lockname)))
 | 
			
		||||
			*retlen = 1 + dm_snprintf(*buf, buflen, "%s", locktype);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_REFRESH:
 | 
			
		||||
		do_refresh_cache();
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_SYNC_NAMES:
 | 
			
		||||
		lvm_do_fs_unlock();
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_SET_DEBUG:
 | 
			
		||||
		clvmd_set_debug((debug_t) args[0]);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_RESTART:
 | 
			
		||||
		status = restart_clvmd();
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_GET_CLUSTERNAME:
 | 
			
		||||
		status = clops->get_cluster_name(*buf, buflen);
 | 
			
		||||
		if (!status)
 | 
			
		||||
			*retlen = strlen(*buf)+1;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_VG_BACKUP:
 | 
			
		||||
		/*
 | 
			
		||||
		 * Do not run backup on local node, caller should do that.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!client)
 | 
			
		||||
			lvm_do_backup(&args[2]);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		/* Won't get here because command is validated in pre_command */
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check the status of the command and return the error text */
 | 
			
		||||
	if (status) {
 | 
			
		||||
		if (*buf)
 | 
			
		||||
			*retlen = dm_snprintf(*buf, buflen, "%s", strerror(status)) + 1;
 | 
			
		||||
		else
 | 
			
		||||
			*retlen = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int lock_vg(struct local_client *client)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_table *lock_hash;
 | 
			
		||||
	struct clvm_header *header =
 | 
			
		||||
		(struct clvm_header *) client->bits.localsock.cmd;
 | 
			
		||||
	unsigned char lock_cmd;
 | 
			
		||||
	int lock_mode;
 | 
			
		||||
	char *args = header->node + strlen(header->node) + 1;
 | 
			
		||||
	int lkid;
 | 
			
		||||
	int status;
 | 
			
		||||
	char *lockname;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Keep a track of VG locks in our own hash table. In current
 | 
			
		||||
	 * practice there should only ever be more than two VGs locked
 | 
			
		||||
	 * if a user tries to merge lots of them at once
 | 
			
		||||
	 */
 | 
			
		||||
	if (!client->bits.localsock.private) {
 | 
			
		||||
		if (!(lock_hash = dm_hash_create(3)))
 | 
			
		||||
			return ENOMEM;
 | 
			
		||||
		client->bits.localsock.private = (void *) lock_hash;
 | 
			
		||||
	} else
 | 
			
		||||
		lock_hash = (struct dm_hash_table *) client->bits.localsock.private;
 | 
			
		||||
 | 
			
		||||
	lock_cmd = args[0] & (LCK_NONBLOCK | LCK_HOLD | LCK_SCOPE_MASK | LCK_TYPE_MASK);
 | 
			
		||||
	lock_mode = ((int) lock_cmd & LCK_TYPE_MASK);
 | 
			
		||||
	/* lock_flags = args[1]; */
 | 
			
		||||
	lockname = &args[2];
 | 
			
		||||
	DEBUGLOG("(%p) doing PRE command LOCK_VG '%s' at %x\n", client, lockname, lock_cmd);
 | 
			
		||||
 | 
			
		||||
	if (lock_mode == LCK_UNLOCK) {
 | 
			
		||||
		if (!(lkid = (int) (long) dm_hash_lookup(lock_hash, lockname)))
 | 
			
		||||
			return EINVAL;
 | 
			
		||||
 | 
			
		||||
		if ((status = sync_unlock(lockname, lkid)))
 | 
			
		||||
			status = errno;
 | 
			
		||||
		else
 | 
			
		||||
			dm_hash_remove(lock_hash, lockname);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Read locks need to be PR; other modes get passed through */
 | 
			
		||||
		if (lock_mode == LCK_READ)
 | 
			
		||||
			lock_mode = LCK_PREAD;
 | 
			
		||||
 | 
			
		||||
		if ((status = sync_lock(lockname, lock_mode, (lock_cmd & LCK_NONBLOCK) ? LCKF_NOQUEUE : 0, &lkid)))
 | 
			
		||||
			status = errno;
 | 
			
		||||
		else if (!dm_hash_insert(lock_hash, lockname, (void *) (long) lkid))
 | 
			
		||||
			return ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Pre-command is a good place to get locks that are needed only for the duration
 | 
			
		||||
   of the commands around the cluster (don't forget to free them in post-command),
 | 
			
		||||
   and to sanity check the command arguments */
 | 
			
		||||
int do_pre_command(struct local_client *client)
 | 
			
		||||
{
 | 
			
		||||
	struct clvm_header *header =
 | 
			
		||||
	    (struct clvm_header *) client->bits.localsock.cmd;
 | 
			
		||||
	unsigned char lock_cmd;
 | 
			
		||||
	unsigned char lock_flags;
 | 
			
		||||
	char *args = header->node + strlen(header->node) + 1;
 | 
			
		||||
	int lockid = 0;
 | 
			
		||||
	int status = 0;
 | 
			
		||||
	char *lockname;
 | 
			
		||||
 | 
			
		||||
	switch (header->cmd) {
 | 
			
		||||
	case CLVMD_CMD_TEST:
 | 
			
		||||
		status = sync_lock("CLVMD_TEST", LCK_EXCL, 0, &lockid);
 | 
			
		||||
		client->bits.localsock.private = (void *)(long)lockid;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_VG:
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		/* We take out a real lock unless LCK_CACHE was set */
 | 
			
		||||
		if (!strncmp(lockname, "V_", 2) ||
 | 
			
		||||
		    !strncmp(lockname, "P_#", 3))
 | 
			
		||||
			status = lock_vg(client);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_LV:
 | 
			
		||||
		lock_cmd = args[0];
 | 
			
		||||
		lock_flags = args[1];
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		status = pre_lock_lv(lock_cmd, lock_flags, lockname);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_REFRESH:
 | 
			
		||||
	case CLVMD_CMD_GET_CLUSTERNAME:
 | 
			
		||||
	case CLVMD_CMD_SET_DEBUG:
 | 
			
		||||
	case CLVMD_CMD_VG_BACKUP:
 | 
			
		||||
	case CLVMD_CMD_SYNC_NAMES:
 | 
			
		||||
	case CLVMD_CMD_LOCK_QUERY:
 | 
			
		||||
	case CLVMD_CMD_RESTART:
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		log_error("Unknown command %d received\n", header->cmd);
 | 
			
		||||
		status = EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Note that the post-command routine is called even if the pre-command or the real command
 | 
			
		||||
   failed */
 | 
			
		||||
int do_post_command(struct local_client *client)
 | 
			
		||||
{
 | 
			
		||||
	struct clvm_header *header =
 | 
			
		||||
	    (struct clvm_header *) client->bits.localsock.cmd;
 | 
			
		||||
	int status = 0;
 | 
			
		||||
	unsigned char lock_cmd;
 | 
			
		||||
	unsigned char lock_flags;
 | 
			
		||||
	char *args = header->node + strlen(header->node) + 1;
 | 
			
		||||
	char *lockname;
 | 
			
		||||
 | 
			
		||||
	switch (header->cmd) {
 | 
			
		||||
	case CLVMD_CMD_TEST:
 | 
			
		||||
		status = sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private);
 | 
			
		||||
		client->bits.localsock.private = NULL;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case CLVMD_CMD_LOCK_LV:
 | 
			
		||||
		lock_cmd = args[0];
 | 
			
		||||
		lock_flags = args[1];
 | 
			
		||||
		lockname = &args[2];
 | 
			
		||||
		status = post_lock_lv(lock_cmd, lock_flags, lockname);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		/* Nothing to do here */
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Called when the client is about to be deleted */
 | 
			
		||||
void cmd_client_cleanup(struct local_client *client)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *v;
 | 
			
		||||
	struct dm_hash_table *lock_hash;
 | 
			
		||||
	int lkid;
 | 
			
		||||
	char *lockname;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("(%p) Client thread cleanup\n", client);
 | 
			
		||||
	if (!client->bits.localsock.private)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	lock_hash = (struct dm_hash_table *)client->bits.localsock.private;
 | 
			
		||||
 | 
			
		||||
	dm_hash_iterate(v, lock_hash) {
 | 
			
		||||
		lkid = (int)(long)dm_hash_get_data(lock_hash, v);
 | 
			
		||||
		lockname = dm_hash_get_key(lock_hash, v);
 | 
			
		||||
		DEBUGLOG("(%p) Cleanup: Unlocking lock %s %x\n", client, lockname, lkid);
 | 
			
		||||
		(void) sync_unlock(lockname, lkid);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_hash_destroy(lock_hash);
 | 
			
		||||
	client->bits.localsock.private = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int restart_clvmd(void)
 | 
			
		||||
{
 | 
			
		||||
	const char **argv;
 | 
			
		||||
	char *lv_name;
 | 
			
		||||
	int argc = 0, max_locks = 0;
 | 
			
		||||
	struct dm_hash_node *hn = NULL;
 | 
			
		||||
	char debug_arg[16];
 | 
			
		||||
	const char *clvmd = getenv("LVM_CLVMD_BINARY") ? : CLVMD_PATH;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("clvmd restart requested\n");
 | 
			
		||||
 | 
			
		||||
	/* Count exclusively-open LVs */
 | 
			
		||||
	do {
 | 
			
		||||
		hn = get_next_excl_lock(hn, &lv_name);
 | 
			
		||||
		if (lv_name) {
 | 
			
		||||
			max_locks++;
 | 
			
		||||
			if (!*lv_name)
 | 
			
		||||
				break; /* FIXME: Is this error ? */
 | 
			
		||||
		}
 | 
			
		||||
	} while (hn);
 | 
			
		||||
 | 
			
		||||
	/* clvmd + locks (-E uuid) + debug (-d X) + NULL */
 | 
			
		||||
	if (!(argv = malloc((max_locks * 2 + 6) * sizeof(*argv))))
 | 
			
		||||
		goto_out;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Build the command-line
 | 
			
		||||
	 */
 | 
			
		||||
	argv[argc++] = "clvmd";
 | 
			
		||||
 | 
			
		||||
	/* Propagate debug options */
 | 
			
		||||
	if (clvmd_get_debug()) {
 | 
			
		||||
		if (dm_snprintf(debug_arg, sizeof(debug_arg), "-d%u", clvmd_get_debug()) < 0)
 | 
			
		||||
			goto_out;
 | 
			
		||||
		argv[argc++] = debug_arg;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Propagate foreground options */
 | 
			
		||||
	if (clvmd_get_foreground())
 | 
			
		||||
		argv[argc++] = "-f";
 | 
			
		||||
 | 
			
		||||
	argv[argc++] = "-I";
 | 
			
		||||
	argv[argc++] = clops->name;
 | 
			
		||||
 | 
			
		||||
	/* Now add the exclusively-open LVs */
 | 
			
		||||
	hn = NULL;
 | 
			
		||||
	do {
 | 
			
		||||
		hn = get_next_excl_lock(hn, &lv_name);
 | 
			
		||||
		if (lv_name) {
 | 
			
		||||
			if (!*lv_name)
 | 
			
		||||
				break; /* FIXME: Is this error ? */
 | 
			
		||||
			argv[argc++] = "-E";
 | 
			
		||||
			argv[argc++] = lv_name;
 | 
			
		||||
			DEBUGLOG("excl lock: %s\n", lv_name);
 | 
			
		||||
		}
 | 
			
		||||
	} while (hn);
 | 
			
		||||
	argv[argc] = NULL;
 | 
			
		||||
 | 
			
		||||
	/* Exec new clvmd */
 | 
			
		||||
	DEBUGLOG("--- Restarting %s ---\n", clvmd);
 | 
			
		||||
	for (argc = 1; argv[argc]; argc++) DEBUGLOG("--- %d: %s\n", argc, argv[argc]);
 | 
			
		||||
 | 
			
		||||
	/* NOTE: This will fail when downgrading! */
 | 
			
		||||
	execvp(clvmd, (char **)argv);
 | 
			
		||||
out:
 | 
			
		||||
	/* We failed */
 | 
			
		||||
	DEBUGLOG("Restart of clvmd failed.\n");
 | 
			
		||||
 | 
			
		||||
	free(argv);
 | 
			
		||||
 | 
			
		||||
	return EIO;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
@@ -12,11 +12,16 @@
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LIBDM_KDEV_H
 | 
			
		||||
#define _LIBDM_KDEV_H
 | 
			
		||||
/*
 | 
			
		||||
 * This file must be included first by every clvmd source file.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef _LVM_CLVMD_COMMON_H
 | 
			
		||||
#define _LVM_CLVMD_COMMON_H
 | 
			
		||||
 | 
			
		||||
#define MAJOR(dev)      ((dev & 0xfff00) >> 8)
 | 
			
		||||
#define MINOR(dev)      ((dev & 0xff) | ((dev >> 12) & 0xfff00))
 | 
			
		||||
#define MKDEV(ma,mi)    (((dev_t)mi & 0xff) | ((dev_t)ma << 8) | (((dev_t)mi & ~0xff) << 12))
 | 
			
		||||
#define _REENTRANT
 | 
			
		||||
 | 
			
		||||
#include "tool.h"
 | 
			
		||||
 | 
			
		||||
#include "lvm-logging.h"
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										119
									
								
								daemons/clvmd/clvmd-comms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								daemons/clvmd/clvmd-comms.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Abstraction layer for clvmd cluster communications
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _CLVMD_COMMS_H
 | 
			
		||||
#define _CLVMD_COMMS_H
 | 
			
		||||
 | 
			
		||||
struct local_client;
 | 
			
		||||
 | 
			
		||||
struct cluster_ops {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	void (*cluster_init_completed) (void);
 | 
			
		||||
 | 
			
		||||
	int (*cluster_send_message) (const void *buf, int msglen,
 | 
			
		||||
				     const char *csid,
 | 
			
		||||
				     const char *errtext);
 | 
			
		||||
	int (*name_from_csid) (const char *csid, char *name);
 | 
			
		||||
	int (*csid_from_name) (char *csid, const char *name);
 | 
			
		||||
	int (*get_num_nodes) (void);
 | 
			
		||||
	int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len,
 | 
			
		||||
				    const char *csid,
 | 
			
		||||
				    struct local_client **new_client);
 | 
			
		||||
	int (*get_main_cluster_fd) (void);	/* gets accept FD or cman cluster socket */
 | 
			
		||||
	int (*cluster_do_node_callback) (struct local_client *client,
 | 
			
		||||
					 void (*callback) (struct local_client *,
 | 
			
		||||
							   const char *csid,
 | 
			
		||||
							   int node_up));
 | 
			
		||||
	int (*is_quorate) (void);
 | 
			
		||||
 | 
			
		||||
	void (*get_our_csid) (char *csid);
 | 
			
		||||
	void (*add_up_node) (const char *csid);
 | 
			
		||||
	void (*reread_config) (void);
 | 
			
		||||
	void (*cluster_closedown) (void);
 | 
			
		||||
 | 
			
		||||
	int (*get_cluster_name)(char *buf, int buflen);
 | 
			
		||||
 | 
			
		||||
	int (*sync_lock) (const char *resource, int mode,
 | 
			
		||||
			  int flags, int *lockid);
 | 
			
		||||
	int (*sync_unlock) (const char *resource, int lockid);
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef USE_CMAN
 | 
			
		||||
#  include <netinet/in.h>
 | 
			
		||||
#  include "libcman.h"
 | 
			
		||||
#  define CMAN_MAX_CSID_LEN 4
 | 
			
		||||
#  ifndef MAX_CSID_LEN
 | 
			
		||||
#    define MAX_CSID_LEN CMAN_MAX_CSID_LEN
 | 
			
		||||
#  endif
 | 
			
		||||
#  undef MAX_CLUSTER_MEMBER_NAME_LEN
 | 
			
		||||
#  define MAX_CLUSTER_MEMBER_NAME_LEN   CMAN_MAX_NODENAME_LEN
 | 
			
		||||
#  define CMAN_MAX_CLUSTER_MESSAGE 1500
 | 
			
		||||
#  define CLUSTER_PORT_CLVMD 11
 | 
			
		||||
struct cluster_ops *init_cman_cluster(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_OPENAIS
 | 
			
		||||
#  include <openais/saAis.h>
 | 
			
		||||
#  include <corosync/totem/totem.h>
 | 
			
		||||
#  define OPENAIS_CSID_LEN (sizeof(int))
 | 
			
		||||
#  define OPENAIS_MAX_CLUSTER_MESSAGE         MESSAGE_SIZE_MAX
 | 
			
		||||
#  define OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
 | 
			
		||||
#  ifndef MAX_CLUSTER_MEMBER_NAME_LEN
 | 
			
		||||
#    define MAX_CLUSTER_MEMBER_NAME_LEN       SA_MAX_NAME_LENGTH
 | 
			
		||||
#  endif
 | 
			
		||||
#  ifndef CMAN_MAX_CLUSTER_MESSAGE
 | 
			
		||||
#    define CMAN_MAX_CLUSTER_MESSAGE          MESSAGE_SIZE_MAX
 | 
			
		||||
#  endif
 | 
			
		||||
#  ifndef MAX_CSID_LEN
 | 
			
		||||
#    define MAX_CSID_LEN sizeof(int)
 | 
			
		||||
#  endif
 | 
			
		||||
struct cluster_ops *init_openais_cluster(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_COROSYNC
 | 
			
		||||
#  include <corosync/corotypes.h>
 | 
			
		||||
#  define COROSYNC_CSID_LEN (sizeof(int))
 | 
			
		||||
#  define COROSYNC_MAX_CLUSTER_MESSAGE         65535
 | 
			
		||||
#  define COROSYNC_MAX_CLUSTER_MEMBER_NAME_LEN CS_MAX_NAME_LENGTH
 | 
			
		||||
#  ifndef MAX_CLUSTER_MEMBER_NAME_LEN
 | 
			
		||||
#    define MAX_CLUSTER_MEMBER_NAME_LEN       CS_MAX_NAME_LENGTH
 | 
			
		||||
#  endif
 | 
			
		||||
#  ifndef CMAN_MAX_CLUSTER_MESSAGE
 | 
			
		||||
#    define CMAN_MAX_CLUSTER_MESSAGE          65535
 | 
			
		||||
#  endif
 | 
			
		||||
#  ifndef MAX_CSID_LEN
 | 
			
		||||
#    define MAX_CSID_LEN sizeof(int)
 | 
			
		||||
#  endif
 | 
			
		||||
struct cluster_ops *init_corosync_cluster(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_SINGLENODE
 | 
			
		||||
#  define SINGLENODE_CSID_LEN (sizeof(int))
 | 
			
		||||
#  ifndef MAX_CLUSTER_MEMBER_NAME_LEN
 | 
			
		||||
#    define MAX_CLUSTER_MEMBER_NAME_LEN       64
 | 
			
		||||
#  endif
 | 
			
		||||
#  define SINGLENODE_MAX_CLUSTER_MESSAGE          65535
 | 
			
		||||
#  ifndef MAX_CSID_LEN
 | 
			
		||||
#    define MAX_CSID_LEN sizeof(int)
 | 
			
		||||
#  endif
 | 
			
		||||
struct cluster_ops *init_singlenode_cluster(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										662
									
								
								daemons/clvmd/clvmd-corosync.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										662
									
								
								daemons/clvmd/clvmd-corosync.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,662 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2009-2012 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This provides the interface between clvmd and corosync/DLM as the cluster
 | 
			
		||||
 * and lock manager.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
#include "lvm-functions.h"
 | 
			
		||||
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
 | 
			
		||||
#include <corosync/cpg.h>
 | 
			
		||||
#include <corosync/quorum.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_COROSYNC_CONFDB_H
 | 
			
		||||
#  include <corosync/confdb.h>
 | 
			
		||||
#elif defined HAVE_COROSYNC_CMAP_H
 | 
			
		||||
#  include <corosync/cmap.h>
 | 
			
		||||
#else
 | 
			
		||||
#  error "Either HAVE_COROSYNC_CONFDB_H or HAVE_COROSYNC_CMAP_H must be defined."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <libdlm.h>
 | 
			
		||||
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
/* Timeout value for several corosync calls */
 | 
			
		||||
#define LOCKSPACE_NAME "clvmd"
 | 
			
		||||
 | 
			
		||||
static void corosync_cpg_deliver_callback (cpg_handle_t handle,
 | 
			
		||||
				  const struct cpg_name *groupName,
 | 
			
		||||
				  uint32_t nodeid,
 | 
			
		||||
				  uint32_t pid,
 | 
			
		||||
				  void *msg,
 | 
			
		||||
				  size_t msg_len);
 | 
			
		||||
static void corosync_cpg_confchg_callback(cpg_handle_t handle,
 | 
			
		||||
				 const struct cpg_name *groupName,
 | 
			
		||||
				 const struct cpg_address *member_list, size_t member_list_entries,
 | 
			
		||||
				 const struct cpg_address *left_list, size_t left_list_entries,
 | 
			
		||||
				 const struct cpg_address *joined_list, size_t joined_list_entries);
 | 
			
		||||
static void _cluster_closedown(void);
 | 
			
		||||
 | 
			
		||||
/* Hash list of nodes in the cluster */
 | 
			
		||||
static struct dm_hash_table *node_hash;
 | 
			
		||||
 | 
			
		||||
/* Number of active nodes */
 | 
			
		||||
static int num_nodes;
 | 
			
		||||
static unsigned int our_nodeid;
 | 
			
		||||
 | 
			
		||||
static struct local_client *cluster_client;
 | 
			
		||||
 | 
			
		||||
/* Corosync handles */
 | 
			
		||||
static cpg_handle_t cpg_handle;
 | 
			
		||||
static quorum_handle_t quorum_handle;
 | 
			
		||||
 | 
			
		||||
/* DLM Handle */
 | 
			
		||||
static dlm_lshandle_t *lockspace;
 | 
			
		||||
 | 
			
		||||
static struct cpg_name cpg_group_name;
 | 
			
		||||
 | 
			
		||||
/* Corosync callback structs */
 | 
			
		||||
cpg_callbacks_t corosync_cpg_callbacks = {
 | 
			
		||||
	.cpg_deliver_fn =            corosync_cpg_deliver_callback,
 | 
			
		||||
	.cpg_confchg_fn =            corosync_cpg_confchg_callback,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
quorum_callbacks_t quorum_callbacks = {
 | 
			
		||||
	.quorum_notify_fn = NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct node_info
 | 
			
		||||
{
 | 
			
		||||
	enum {NODE_DOWN, NODE_CLVMD} state;
 | 
			
		||||
	int nodeid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Set errno to something approximating the right value and return 0 or -1 */
 | 
			
		||||
static int cs_to_errno(cs_error_t err)
 | 
			
		||||
{
 | 
			
		||||
	switch(err)
 | 
			
		||||
	{
 | 
			
		||||
	case CS_OK:
 | 
			
		||||
		return 0;
 | 
			
		||||
        case CS_ERR_LIBRARY:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_VERSION:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_INIT:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_TIMEOUT:
 | 
			
		||||
		errno = ETIME;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_TRY_AGAIN:
 | 
			
		||||
		errno = EAGAIN;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_INVALID_PARAM:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NO_MEMORY:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_BAD_HANDLE:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_BUSY:
 | 
			
		||||
		errno = EBUSY;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_ACCESS:
 | 
			
		||||
		errno = EPERM;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NOT_EXIST:
 | 
			
		||||
		errno = ENOENT;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NAME_TOO_LONG:
 | 
			
		||||
		errno = ENAMETOOLONG;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_EXIST:
 | 
			
		||||
		errno = EEXIST;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NO_SPACE:
 | 
			
		||||
		errno = ENOSPC;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_INTERRUPT:
 | 
			
		||||
		errno = EINTR;
 | 
			
		||||
		break;
 | 
			
		||||
	case CS_ERR_NAME_NOT_FOUND:
 | 
			
		||||
		errno = ENOENT;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NO_RESOURCES:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NOT_SUPPORTED:
 | 
			
		||||
		errno = EOPNOTSUPP;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_BAD_OPERATION:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_FAILED_OPERATION:
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_MESSAGE_ERROR:
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_QUEUE_FULL:
 | 
			
		||||
		errno = EXFULL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_QUEUE_NOT_AVAILABLE:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_BAD_FLAGS:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_TOO_BIG:
 | 
			
		||||
		errno = E2BIG;
 | 
			
		||||
		break;
 | 
			
		||||
        case CS_ERR_NO_SECTIONS:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *print_corosync_csid(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[128];
 | 
			
		||||
	int id;
 | 
			
		||||
 | 
			
		||||
	memcpy(&id, csid, sizeof(int));
 | 
			
		||||
	sprintf(buf, "%d", id);
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void corosync_cpg_deliver_callback (cpg_handle_t handle,
 | 
			
		||||
				  const struct cpg_name *groupName,
 | 
			
		||||
				  uint32_t nodeid,
 | 
			
		||||
				  uint32_t pid,
 | 
			
		||||
				  void *msg,
 | 
			
		||||
				  size_t msg_len)
 | 
			
		||||
{
 | 
			
		||||
	int target_nodeid;
 | 
			
		||||
 | 
			
		||||
	memcpy(&target_nodeid, msg, COROSYNC_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("%u got message from nodeid %d for %d. len %zd\n",
 | 
			
		||||
		 our_nodeid, nodeid, target_nodeid, msg_len-4);
 | 
			
		||||
 | 
			
		||||
	if (nodeid != our_nodeid)
 | 
			
		||||
		if (target_nodeid == our_nodeid || target_nodeid == 0)
 | 
			
		||||
			process_message(cluster_client, (char *)msg+COROSYNC_CSID_LEN,
 | 
			
		||||
					msg_len-COROSYNC_CSID_LEN, (char*)&nodeid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void corosync_cpg_confchg_callback(cpg_handle_t handle,
 | 
			
		||||
				 const struct cpg_name *groupName,
 | 
			
		||||
				 const struct cpg_address *member_list, size_t member_list_entries,
 | 
			
		||||
				 const struct cpg_address *left_list, size_t left_list_entries,
 | 
			
		||||
				 const struct cpg_address *joined_list, size_t joined_list_entries)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("confchg callback. %zd joined, %zd left, %zd members\n",
 | 
			
		||||
		 joined_list_entries, left_list_entries, member_list_entries);
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<joined_list_entries; i++) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash,
 | 
			
		||||
					      (char *)&joined_list[i].nodeid,
 | 
			
		||||
					      COROSYNC_CSID_LEN);
 | 
			
		||||
		if (!ninfo) {
 | 
			
		||||
			ninfo = malloc(sizeof(struct node_info));
 | 
			
		||||
			if (!ninfo) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				ninfo->nodeid = joined_list[i].nodeid;
 | 
			
		||||
				dm_hash_insert_binary(node_hash,
 | 
			
		||||
						      (char *)&ninfo->nodeid,
 | 
			
		||||
						      COROSYNC_CSID_LEN, ninfo);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ninfo->state = NODE_CLVMD;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<left_list_entries; i++) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash,
 | 
			
		||||
					      (char *)&left_list[i].nodeid,
 | 
			
		||||
					      COROSYNC_CSID_LEN);
 | 
			
		||||
		if (ninfo)
 | 
			
		||||
			ninfo->state = NODE_DOWN;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	num_nodes = member_list_entries;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _init_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	cs_error_t err;
 | 
			
		||||
 | 
			
		||||
#ifdef QUORUM_SET	/* corosync/quorum.h */
 | 
			
		||||
	uint32_t quorum_type;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	node_hash = dm_hash_create(100);
 | 
			
		||||
 | 
			
		||||
	err = cpg_initialize(&cpg_handle,
 | 
			
		||||
			     &corosync_cpg_callbacks);
 | 
			
		||||
	if (err != CS_OK) {
 | 
			
		||||
		syslog(LOG_ERR, "Cannot initialise Corosync CPG service: %d",
 | 
			
		||||
		       err);
 | 
			
		||||
		DEBUGLOG("Cannot initialise Corosync CPG service: %d", err);
 | 
			
		||||
		return cs_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef QUORUM_SET
 | 
			
		||||
	err = quorum_initialize(&quorum_handle,
 | 
			
		||||
				&quorum_callbacks,
 | 
			
		||||
				&quorum_type);
 | 
			
		||||
 | 
			
		||||
	if (quorum_type != QUORUM_SET) {
 | 
			
		||||
		syslog(LOG_ERR, "Corosync quorum service is not configured");
 | 
			
		||||
		DEBUGLOG("Corosync quorum service is not configured");
 | 
			
		||||
		return EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
#else
 | 
			
		||||
	err = quorum_initialize(&quorum_handle,
 | 
			
		||||
				&quorum_callbacks);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (err != CS_OK) {
 | 
			
		||||
		syslog(LOG_ERR, "Cannot initialise Corosync quorum service: %d",
 | 
			
		||||
		       err);
 | 
			
		||||
		DEBUGLOG("Cannot initialise Corosync quorum service: %d", err);
 | 
			
		||||
		return cs_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Create a lockspace for LV & VG locks to live in */
 | 
			
		||||
	lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
 | 
			
		||||
	if (!lockspace) {
 | 
			
		||||
		lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
 | 
			
		||||
		if (!lockspace) {
 | 
			
		||||
			syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		DEBUGLOG("Created DLM lockspace for CLVMD.\n");
 | 
			
		||||
	} else
 | 
			
		||||
		DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
 | 
			
		||||
 | 
			
		||||
	dlm_ls_pthread_init(lockspace);
 | 
			
		||||
	DEBUGLOG("DLM initialisation complete\n");
 | 
			
		||||
 | 
			
		||||
	/* Connect to the clvmd group */
 | 
			
		||||
	strcpy((char *)cpg_group_name.value, "clvmd");
 | 
			
		||||
	cpg_group_name.length = strlen((char *)cpg_group_name.value);
 | 
			
		||||
	err = cpg_join(cpg_handle, &cpg_group_name);
 | 
			
		||||
	if (err != CS_OK) {
 | 
			
		||||
		cpg_finalize(cpg_handle);
 | 
			
		||||
		quorum_finalize(quorum_handle);
 | 
			
		||||
		dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
 | 
			
		||||
		syslog(LOG_ERR, "Cannot join clvmd process group");
 | 
			
		||||
		DEBUGLOG("Cannot join clvmd process group: %d\n", err);
 | 
			
		||||
		return cs_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = cpg_local_get(cpg_handle,
 | 
			
		||||
			    &our_nodeid);
 | 
			
		||||
	if (err != CS_OK) {
 | 
			
		||||
		cpg_finalize(cpg_handle);
 | 
			
		||||
		quorum_finalize(quorum_handle);
 | 
			
		||||
		dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
 | 
			
		||||
		syslog(LOG_ERR, "Cannot get local node id\n");
 | 
			
		||||
		return cs_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
	DEBUGLOG("Our local node id is %d\n", our_nodeid);
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Connected to Corosync\n");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _cluster_closedown(void)
 | 
			
		||||
{
 | 
			
		||||
	dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
 | 
			
		||||
	cpg_finalize(cpg_handle);
 | 
			
		||||
	quorum_finalize(quorum_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _get_our_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
	memcpy(csid, &our_nodeid, sizeof(int));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Corosync doesn't really have nmode names so we
 | 
			
		||||
   just use the node ID in hex instead */
 | 
			
		||||
static int _csid_from_name(char *csid, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	int nodeid;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	if (sscanf(name, "%x", &nodeid) == 1) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
 | 
			
		||||
		if (ninfo)
 | 
			
		||||
			return nodeid;
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _name_from_csid(const char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
 | 
			
		||||
	if (!ninfo)
 | 
			
		||||
	{
 | 
			
		||||
		sprintf(name, "UNKNOWN %s", print_corosync_csid(csid));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sprintf(name, "%x", ninfo->nodeid);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_num_nodes(void)
 | 
			
		||||
{
 | 
			
		||||
	DEBUGLOG("num_nodes = %d\n", num_nodes);
 | 
			
		||||
	return num_nodes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Node is now known to be running a clvmd */
 | 
			
		||||
static void _add_up_node(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
 | 
			
		||||
	if (!ninfo) {
 | 
			
		||||
		DEBUGLOG("corosync_add_up_node no node_hash entry for csid %s\n",
 | 
			
		||||
			 print_corosync_csid(csid));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("corosync_add_up_node %d\n", ninfo->nodeid);
 | 
			
		||||
 | 
			
		||||
	ninfo->state = NODE_CLVMD;
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Call a callback for each node, so the caller knows whether it's up or down */
 | 
			
		||||
static int _cluster_do_node_callback(struct local_client *master_client,
 | 
			
		||||
				     void (*callback)(struct local_client *,
 | 
			
		||||
						      const char *csid, int node_up))
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *hn;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	dm_hash_iterate(hn, node_hash)
 | 
			
		||||
	{
 | 
			
		||||
		char csid[COROSYNC_CSID_LEN];
 | 
			
		||||
 | 
			
		||||
		ninfo = dm_hash_get_data(node_hash, hn);
 | 
			
		||||
		memcpy(csid, dm_hash_get_key(node_hash, hn), COROSYNC_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
		DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
 | 
			
		||||
			 ninfo->state);
 | 
			
		||||
 | 
			
		||||
		if (ninfo->state == NODE_CLVMD)
 | 
			
		||||
			callback(master_client, csid, 1);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Real locking */
 | 
			
		||||
static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
	struct dlm_lksb lksb;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
 | 
			
		||||
 | 
			
		||||
	if (flags & LKF_CONVERT)
 | 
			
		||||
		lksb.sb_lkid = *lockid;
 | 
			
		||||
 | 
			
		||||
	err = dlm_ls_lock_wait(lockspace,
 | 
			
		||||
			       mode,
 | 
			
		||||
			       &lksb,
 | 
			
		||||
			       flags,
 | 
			
		||||
			       resource,
 | 
			
		||||
			       strlen(resource),
 | 
			
		||||
			       0,
 | 
			
		||||
			       NULL, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
	if (err != 0)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("dlm_ls_lock returned %d\n", errno);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
	if (lksb.sb_status != 0)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("dlm_ls_lock returns lksb.sb_status %d\n", lksb.sb_status);
 | 
			
		||||
		errno = lksb.sb_status;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("lock_resource returning %d, lock_id=%x\n", err, lksb.sb_lkid);
 | 
			
		||||
 | 
			
		||||
	*lockid = lksb.sb_lkid;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int _unlock_resource(const char *resource, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	struct dlm_lksb lksb;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("unlock_resource: %s lockid: %x\n", resource, lockid);
 | 
			
		||||
	lksb.sb_lkid = lockid;
 | 
			
		||||
 | 
			
		||||
	err = dlm_ls_unlock_wait(lockspace,
 | 
			
		||||
				 lockid,
 | 
			
		||||
				 0,
 | 
			
		||||
				 &lksb);
 | 
			
		||||
	if (err != 0)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("Unlock returned %d\n", err);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
	if (lksb.sb_status != EUNLOCK)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("dlm_ls_unlock_wait returns lksb.sb_status: %d\n", lksb.sb_status);
 | 
			
		||||
		errno = lksb.sb_status;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}   
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _is_quorate(void)
 | 
			
		||||
{
 | 
			
		||||
	int quorate;
 | 
			
		||||
	if (quorum_getquorate(quorum_handle, &quorate) == CS_OK)
 | 
			
		||||
		return quorate;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_main_cluster_fd(void)
 | 
			
		||||
{
 | 
			
		||||
	int select_fd;
 | 
			
		||||
 | 
			
		||||
	cpg_fd_get(cpg_handle, &select_fd);
 | 
			
		||||
	return select_fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
 | 
			
		||||
				const char *csid,
 | 
			
		||||
				struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
	cluster_client = fd;
 | 
			
		||||
	*new_client = NULL;
 | 
			
		||||
	cpg_dispatch(cpg_handle, CS_DISPATCH_ONE);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
 | 
			
		||||
				 const char *errtext)
 | 
			
		||||
{
 | 
			
		||||
	static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
 | 
			
		||||
	struct iovec iov[2];
 | 
			
		||||
	cs_error_t err;
 | 
			
		||||
	int target_node;
 | 
			
		||||
 | 
			
		||||
	if (csid)
 | 
			
		||||
		memcpy(&target_node, csid, COROSYNC_CSID_LEN);
 | 
			
		||||
	else
 | 
			
		||||
		target_node = 0;
 | 
			
		||||
 | 
			
		||||
	iov[0].iov_base = &target_node;
 | 
			
		||||
	iov[0].iov_len = sizeof(int);
 | 
			
		||||
	iov[1].iov_base = (char *)buf;
 | 
			
		||||
	iov[1].iov_len = msglen;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&_mutex);
 | 
			
		||||
	err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
 | 
			
		||||
	pthread_mutex_unlock(&_mutex);
 | 
			
		||||
 | 
			
		||||
	return cs_to_errno(err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_COROSYNC_CONFDB_H
 | 
			
		||||
/*
 | 
			
		||||
 * We are not necessarily connected to a Red Hat Cluster system,
 | 
			
		||||
 * but if we are, this returns the cluster name from cluster.conf.
 | 
			
		||||
 * I've used confdb rather than ccs to reduce the inter-package
 | 
			
		||||
 * dependancies as well as to allow people to set a cluster name
 | 
			
		||||
 * for themselves even if they are not running on RH cluster.
 | 
			
		||||
 */
 | 
			
		||||
static int _get_cluster_name(char *buf, int buflen)
 | 
			
		||||
{
 | 
			
		||||
	confdb_handle_t handle;
 | 
			
		||||
	int result;
 | 
			
		||||
	size_t namelen = buflen;
 | 
			
		||||
	hdb_handle_t cluster_handle;
 | 
			
		||||
	confdb_callbacks_t callbacks = {
 | 
			
		||||
		.confdb_key_change_notify_fn = NULL,
 | 
			
		||||
		.confdb_object_create_change_notify_fn = NULL,
 | 
			
		||||
		.confdb_object_delete_change_notify_fn = NULL
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/* This is a default in case everything else fails */
 | 
			
		||||
	strncpy(buf, "Corosync", buflen);
 | 
			
		||||
 | 
			
		||||
	/* Look for a cluster name in confdb */
 | 
			
		||||
	result = confdb_initialize (&handle, &callbacks);
 | 
			
		||||
        if (result != CS_OK)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
        result = confdb_object_find_start(handle, OBJECT_PARENT_HANDLE);
 | 
			
		||||
	if (result != CS_OK)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
        result = confdb_object_find(handle, OBJECT_PARENT_HANDLE, (void *)"cluster", strlen("cluster"), &cluster_handle);
 | 
			
		||||
        if (result != CS_OK)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
        result = confdb_key_get(handle, cluster_handle, (void *)"name", strlen("name"), buf, &namelen);
 | 
			
		||||
        if (result != CS_OK)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	buf[namelen] = '\0';
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	confdb_finalize(handle);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif defined HAVE_COROSYNC_CMAP_H
 | 
			
		||||
 | 
			
		||||
static int _get_cluster_name(char *buf, int buflen)
 | 
			
		||||
{
 | 
			
		||||
	cmap_handle_t cmap_handle = 0;
 | 
			
		||||
	int result;
 | 
			
		||||
	char *name = NULL;
 | 
			
		||||
 | 
			
		||||
	/* This is a default in case everything else fails */
 | 
			
		||||
	strncpy(buf, "Corosync", buflen);
 | 
			
		||||
 | 
			
		||||
	/* Look for a cluster name in cmap */
 | 
			
		||||
	result = cmap_initialize(&cmap_handle);
 | 
			
		||||
	if (result != CS_OK)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	result = cmap_get_string(cmap_handle, "totem.cluster_name", &name);
 | 
			
		||||
	if (result != CS_OK)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	memset(buf, 0, buflen);
 | 
			
		||||
	strncpy(buf, name, buflen - 1);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	if (name)
 | 
			
		||||
		free(name);
 | 
			
		||||
	cmap_finalize(cmap_handle);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static struct cluster_ops _cluster_corosync_ops = {
 | 
			
		||||
	.name                     = "corosync",
 | 
			
		||||
	.cluster_init_completed   = NULL,
 | 
			
		||||
	.cluster_send_message     = _cluster_send_message,
 | 
			
		||||
	.name_from_csid           = _name_from_csid,
 | 
			
		||||
	.csid_from_name           = _csid_from_name,
 | 
			
		||||
	.get_num_nodes            = _get_num_nodes,
 | 
			
		||||
	.cluster_fd_callback      = _cluster_fd_callback,
 | 
			
		||||
	.get_main_cluster_fd      = _get_main_cluster_fd,
 | 
			
		||||
	.cluster_do_node_callback = _cluster_do_node_callback,
 | 
			
		||||
	.is_quorate               = _is_quorate,
 | 
			
		||||
	.get_our_csid             = _get_our_csid,
 | 
			
		||||
	.add_up_node              = _add_up_node,
 | 
			
		||||
	.reread_config            = NULL,
 | 
			
		||||
	.cluster_closedown        = _cluster_closedown,
 | 
			
		||||
	.get_cluster_name         = _get_cluster_name,
 | 
			
		||||
	.sync_lock                = _lock_resource,
 | 
			
		||||
	.sync_unlock              = _unlock_resource,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cluster_ops *init_corosync_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!_init_cluster())
 | 
			
		||||
		return &_cluster_corosync_ops;
 | 
			
		||||
	else
 | 
			
		||||
		return NULL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										687
									
								
								daemons/clvmd/clvmd-openais.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										687
									
								
								daemons/clvmd/clvmd-openais.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,687 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2007-2009 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This provides the interface between clvmd and OpenAIS as the cluster
 | 
			
		||||
 * and lock manager.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
#include <openais/saAis.h>
 | 
			
		||||
#include <openais/saLck.h>
 | 
			
		||||
 | 
			
		||||
#include <corosync/corotypes.h>
 | 
			
		||||
#include <corosync/cpg.h>
 | 
			
		||||
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "lvm-functions.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
 | 
			
		||||
/* Timeout value for several openais calls */
 | 
			
		||||
#define TIMEOUT 10
 | 
			
		||||
 | 
			
		||||
static void openais_cpg_deliver_callback (cpg_handle_t handle,
 | 
			
		||||
				  const struct cpg_name *groupName,
 | 
			
		||||
				  uint32_t nodeid,
 | 
			
		||||
				  uint32_t pid,
 | 
			
		||||
				  void *msg,
 | 
			
		||||
				  size_t msg_len);
 | 
			
		||||
static void openais_cpg_confchg_callback(cpg_handle_t handle,
 | 
			
		||||
				 const struct cpg_name *groupName,
 | 
			
		||||
				 const struct cpg_address *member_list, size_t member_list_entries,
 | 
			
		||||
				 const struct cpg_address *left_list, size_t left_list_entries,
 | 
			
		||||
				 const struct cpg_address *joined_list, size_t joined_list_entries);
 | 
			
		||||
 | 
			
		||||
static void _cluster_closedown(void);
 | 
			
		||||
 | 
			
		||||
/* Hash list of nodes in the cluster */
 | 
			
		||||
static struct dm_hash_table *node_hash;
 | 
			
		||||
 | 
			
		||||
/* For associating lock IDs & resource handles */
 | 
			
		||||
static struct dm_hash_table *lock_hash;
 | 
			
		||||
 | 
			
		||||
/* Number of active nodes */
 | 
			
		||||
static int num_nodes;
 | 
			
		||||
static unsigned int our_nodeid;
 | 
			
		||||
 | 
			
		||||
static struct local_client *cluster_client;
 | 
			
		||||
 | 
			
		||||
/* OpenAIS handles */
 | 
			
		||||
static cpg_handle_t cpg_handle;
 | 
			
		||||
static SaLckHandleT lck_handle;
 | 
			
		||||
 | 
			
		||||
static struct cpg_name cpg_group_name;
 | 
			
		||||
 | 
			
		||||
/* Openais callback structs */
 | 
			
		||||
cpg_callbacks_t openais_cpg_callbacks = {
 | 
			
		||||
	.cpg_deliver_fn =            openais_cpg_deliver_callback,
 | 
			
		||||
	.cpg_confchg_fn =            openais_cpg_confchg_callback,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct node_info
 | 
			
		||||
{
 | 
			
		||||
	enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
 | 
			
		||||
	int nodeid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct lock_info
 | 
			
		||||
{
 | 
			
		||||
	SaLckResourceHandleT res_handle;
 | 
			
		||||
	SaLckLockIdT         lock_id;
 | 
			
		||||
	SaNameT              lock_name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Set errno to something approximating the right value and return 0 or -1 */
 | 
			
		||||
static int ais_to_errno(SaAisErrorT err)
 | 
			
		||||
{
 | 
			
		||||
	switch(err)
 | 
			
		||||
	{
 | 
			
		||||
	case SA_AIS_OK:
 | 
			
		||||
		return 0;
 | 
			
		||||
        case SA_AIS_ERR_LIBRARY:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_VERSION:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_INIT:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_TIMEOUT:
 | 
			
		||||
		errno = ETIME;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_TRY_AGAIN:
 | 
			
		||||
		errno = EAGAIN;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_INVALID_PARAM:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NO_MEMORY:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_BAD_HANDLE:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_BUSY:
 | 
			
		||||
		errno = EBUSY;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_ACCESS:
 | 
			
		||||
		errno = EPERM;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NOT_EXIST:
 | 
			
		||||
		errno = ENOENT;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NAME_TOO_LONG:
 | 
			
		||||
		errno = ENAMETOOLONG;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_EXIST:
 | 
			
		||||
		errno = EEXIST;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NO_SPACE:
 | 
			
		||||
		errno = ENOSPC;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_INTERRUPT:
 | 
			
		||||
		errno = EINTR;
 | 
			
		||||
		break;
 | 
			
		||||
	case SA_AIS_ERR_NAME_NOT_FOUND:
 | 
			
		||||
		errno = ENOENT;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NO_RESOURCES:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NOT_SUPPORTED:
 | 
			
		||||
		errno = EOPNOTSUPP;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_BAD_OPERATION:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_FAILED_OPERATION:
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_MESSAGE_ERROR:
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_QUEUE_FULL:
 | 
			
		||||
		errno = EXFULL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_QUEUE_NOT_AVAILABLE:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_BAD_FLAGS:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_TOO_BIG:
 | 
			
		||||
		errno = E2BIG;
 | 
			
		||||
		break;
 | 
			
		||||
        case SA_AIS_ERR_NO_SECTIONS:
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *print_openais_csid(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[128];
 | 
			
		||||
	int id;
 | 
			
		||||
 | 
			
		||||
	memcpy(&id, csid, sizeof(int));
 | 
			
		||||
	sprintf(buf, "%d", id);
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int add_internal_client(int fd, fd_callback_t callback)
 | 
			
		||||
{
 | 
			
		||||
	struct local_client *client;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Add_internal_client, fd = %d\n", fd);
 | 
			
		||||
 | 
			
		||||
	if (!(client = dm_zalloc(sizeof(*client)))) {
 | 
			
		||||
		DEBUGLOG("malloc failed\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	client->fd = fd;
 | 
			
		||||
	client->type = CLUSTER_INTERNAL;
 | 
			
		||||
	client->callback = callback;
 | 
			
		||||
	add_client(client);
 | 
			
		||||
 | 
			
		||||
	/* Set Close-on-exec */
 | 
			
		||||
	fcntl(fd, F_SETFD, 1);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void openais_cpg_deliver_callback (cpg_handle_t handle,
 | 
			
		||||
				  const struct cpg_name *groupName,
 | 
			
		||||
				  uint32_t nodeid,
 | 
			
		||||
				  uint32_t pid,
 | 
			
		||||
				  void *msg,
 | 
			
		||||
				  size_t msg_len)
 | 
			
		||||
{
 | 
			
		||||
	int target_nodeid;
 | 
			
		||||
 | 
			
		||||
	memcpy(&target_nodeid, msg, OPENAIS_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("%u got message from nodeid %d for %d. len %" PRIsize_t "\n",
 | 
			
		||||
		 our_nodeid, nodeid, target_nodeid, msg_len-4);
 | 
			
		||||
 | 
			
		||||
	if (nodeid != our_nodeid)
 | 
			
		||||
		if (target_nodeid == our_nodeid || target_nodeid == 0)
 | 
			
		||||
			process_message(cluster_client, (char *)msg+OPENAIS_CSID_LEN,
 | 
			
		||||
					msg_len-OPENAIS_CSID_LEN, (char*)&nodeid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void openais_cpg_confchg_callback(cpg_handle_t handle,
 | 
			
		||||
				 const struct cpg_name *groupName,
 | 
			
		||||
				 const struct cpg_address *member_list, size_t member_list_entries,
 | 
			
		||||
				 const struct cpg_address *left_list, size_t left_list_entries,
 | 
			
		||||
				 const struct cpg_address *joined_list, size_t joined_list_entries)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
 | 
			
		||||
		 FMTsize_t " left, %" PRIsize_t " members\n",
 | 
			
		||||
		 joined_list_entries, left_list_entries, member_list_entries);
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<joined_list_entries; i++) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash,
 | 
			
		||||
					      (char *)&joined_list[i].nodeid,
 | 
			
		||||
					      OPENAIS_CSID_LEN);
 | 
			
		||||
		if (!ninfo) {
 | 
			
		||||
			ninfo = malloc(sizeof(struct node_info));
 | 
			
		||||
			if (!ninfo) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				ninfo->nodeid = joined_list[i].nodeid;
 | 
			
		||||
				dm_hash_insert_binary(node_hash,
 | 
			
		||||
						      (char *)&ninfo->nodeid,
 | 
			
		||||
						      OPENAIS_CSID_LEN, ninfo);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ninfo->state = NODE_CLVMD;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<left_list_entries; i++) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash,
 | 
			
		||||
					      (char *)&left_list[i].nodeid,
 | 
			
		||||
					      OPENAIS_CSID_LEN);
 | 
			
		||||
		if (ninfo)
 | 
			
		||||
			ninfo->state = NODE_DOWN;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<member_list_entries; i++) {
 | 
			
		||||
		if (member_list[i].nodeid == 0) continue;
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash,
 | 
			
		||||
				(char *)&member_list[i].nodeid,
 | 
			
		||||
				OPENAIS_CSID_LEN);
 | 
			
		||||
		if (!ninfo) {
 | 
			
		||||
			ninfo = malloc(sizeof(struct node_info));
 | 
			
		||||
			if (!ninfo) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				ninfo->nodeid = member_list[i].nodeid;
 | 
			
		||||
				dm_hash_insert_binary(node_hash,
 | 
			
		||||
						(char *)&ninfo->nodeid,
 | 
			
		||||
						OPENAIS_CSID_LEN, ninfo);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ninfo->state = NODE_CLVMD;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	num_nodes = member_list_entries;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int lck_dispatch(struct local_client *client, char *buf, int len,
 | 
			
		||||
			const char *csid, struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
	*new_client = NULL;
 | 
			
		||||
	saLckDispatch(lck_handle, SA_DISPATCH_ONE);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _init_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	SaAisErrorT err;
 | 
			
		||||
	SaVersionT  ver = { 'B', 1, 1 };
 | 
			
		||||
	int select_fd;
 | 
			
		||||
 | 
			
		||||
	node_hash = dm_hash_create(100);
 | 
			
		||||
	lock_hash = dm_hash_create(10);
 | 
			
		||||
 | 
			
		||||
	err = cpg_initialize(&cpg_handle,
 | 
			
		||||
			     &openais_cpg_callbacks);
 | 
			
		||||
	if (err != SA_AIS_OK) {
 | 
			
		||||
		syslog(LOG_ERR, "Cannot initialise OpenAIS CPG service: %d",
 | 
			
		||||
		       err);
 | 
			
		||||
		DEBUGLOG("Cannot initialise OpenAIS CPG service: %d", err);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = saLckInitialize(&lck_handle,
 | 
			
		||||
					NULL,
 | 
			
		||||
			      &ver);
 | 
			
		||||
	if (err != SA_AIS_OK) {
 | 
			
		||||
		cpg_initialize(&cpg_handle, &openais_cpg_callbacks);
 | 
			
		||||
		syslog(LOG_ERR, "Cannot initialise OpenAIS lock service: %d",
 | 
			
		||||
		       err);
 | 
			
		||||
		DEBUGLOG("Cannot initialise OpenAIS lock service: %d\n\n", err);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Connect to the clvmd group */
 | 
			
		||||
	strcpy((char *)cpg_group_name.value, "clvmd");
 | 
			
		||||
	cpg_group_name.length = strlen((char *)cpg_group_name.value);
 | 
			
		||||
	err = cpg_join(cpg_handle, &cpg_group_name);
 | 
			
		||||
	if (err != SA_AIS_OK) {
 | 
			
		||||
		cpg_finalize(cpg_handle);
 | 
			
		||||
		saLckFinalize(lck_handle);
 | 
			
		||||
		syslog(LOG_ERR, "Cannot join clvmd process group");
 | 
			
		||||
		DEBUGLOG("Cannot join clvmd process group: %d\n", err);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = cpg_local_get(cpg_handle,
 | 
			
		||||
			    &our_nodeid);
 | 
			
		||||
	if (err != SA_AIS_OK) {
 | 
			
		||||
		cpg_finalize(cpg_handle);
 | 
			
		||||
		saLckFinalize(lck_handle);
 | 
			
		||||
		syslog(LOG_ERR, "Cannot get local node id\n");
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
	DEBUGLOG("Our local node id is %d\n", our_nodeid);
 | 
			
		||||
 | 
			
		||||
	saLckSelectionObjectGet(lck_handle, (SaSelectionObjectT *)&select_fd);
 | 
			
		||||
	add_internal_client(select_fd, lck_dispatch);
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Connected to OpenAIS\n");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _cluster_closedown(void)
 | 
			
		||||
{
 | 
			
		||||
	saLckFinalize(lck_handle);
 | 
			
		||||
	cpg_finalize(cpg_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _get_our_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
	memcpy(csid, &our_nodeid, sizeof(int));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* OpenAIS doesn't really have nmode names so we
 | 
			
		||||
   just use the node ID in hex instead */
 | 
			
		||||
static int _csid_from_name(char *csid, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	int nodeid;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	if (sscanf(name, "%x", &nodeid) == 1) {
 | 
			
		||||
		ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
 | 
			
		||||
		if (ninfo)
 | 
			
		||||
			return nodeid;
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _name_from_csid(const char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
 | 
			
		||||
	if (!ninfo)
 | 
			
		||||
	{
 | 
			
		||||
		sprintf(name, "UNKNOWN %s", print_openais_csid(csid));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sprintf(name, "%x", ninfo->nodeid);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_num_nodes()
 | 
			
		||||
{
 | 
			
		||||
	DEBUGLOG("num_nodes = %d\n", num_nodes);
 | 
			
		||||
	return num_nodes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Node is now known to be running a clvmd */
 | 
			
		||||
static void _add_up_node(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
 | 
			
		||||
	if (!ninfo) {
 | 
			
		||||
		DEBUGLOG("openais_add_up_node no node_hash entry for csid %s\n",
 | 
			
		||||
			 print_openais_csid(csid));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("openais_add_up_node %d\n", ninfo->nodeid);
 | 
			
		||||
 | 
			
		||||
	ninfo->state = NODE_CLVMD;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Call a callback for each node, so the caller knows whether it's up or down */
 | 
			
		||||
static int _cluster_do_node_callback(struct local_client *master_client,
 | 
			
		||||
				     void (*callback)(struct local_client *,
 | 
			
		||||
						      const char *csid, int node_up))
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *hn;
 | 
			
		||||
	struct node_info *ninfo;
 | 
			
		||||
	int somedown = 0;
 | 
			
		||||
 | 
			
		||||
	dm_hash_iterate(hn, node_hash)
 | 
			
		||||
	{
 | 
			
		||||
		char csid[OPENAIS_CSID_LEN];
 | 
			
		||||
 | 
			
		||||
		ninfo = dm_hash_get_data(node_hash, hn);
 | 
			
		||||
		memcpy(csid, dm_hash_get_key(node_hash, hn), OPENAIS_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
		DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
 | 
			
		||||
			 ninfo->state);
 | 
			
		||||
 | 
			
		||||
		if (ninfo->state != NODE_DOWN)
 | 
			
		||||
			callback(master_client, csid, ninfo->state == NODE_CLVMD);
 | 
			
		||||
		if (ninfo->state != NODE_CLVMD)
 | 
			
		||||
			somedown = -1;
 | 
			
		||||
	}
 | 
			
		||||
	return somedown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Real locking */
 | 
			
		||||
static int _lock_resource(char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
	struct lock_info *linfo;
 | 
			
		||||
	SaLckResourceHandleT res_handle;
 | 
			
		||||
	SaAisErrorT err;
 | 
			
		||||
	SaLckLockIdT lock_id;
 | 
			
		||||
	SaLckLockStatusT lockStatus;
 | 
			
		||||
 | 
			
		||||
	/* This needs to be converted from DLM/LVM2 value for OpenAIS LCK */
 | 
			
		||||
	if (flags & LCK_NONBLOCK) flags = SA_LCK_LOCK_NO_QUEUE;
 | 
			
		||||
 | 
			
		||||
	linfo = malloc(sizeof(struct lock_info));
 | 
			
		||||
	if (!linfo)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
 | 
			
		||||
 | 
			
		||||
	linfo->lock_name.length = strlen(resource)+1;
 | 
			
		||||
	strcpy((char *)linfo->lock_name.value, resource);
 | 
			
		||||
 | 
			
		||||
	err = saLckResourceOpen(lck_handle, &linfo->lock_name,
 | 
			
		||||
				SA_LCK_RESOURCE_CREATE, TIMEOUT, &res_handle);
 | 
			
		||||
	if (err != SA_AIS_OK)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("ResourceOpen returned %d\n", err);
 | 
			
		||||
		free(linfo);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = saLckResourceLock(
 | 
			
		||||
			res_handle,
 | 
			
		||||
			&lock_id,
 | 
			
		||||
			mode,
 | 
			
		||||
			flags,
 | 
			
		||||
			0,
 | 
			
		||||
			SA_TIME_END,
 | 
			
		||||
			&lockStatus);
 | 
			
		||||
	if (err != SA_AIS_OK && lockStatus != SA_LCK_LOCK_GRANTED)
 | 
			
		||||
	{
 | 
			
		||||
		free(linfo);
 | 
			
		||||
		saLckResourceClose(res_handle);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Wait for it to complete */
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("lock_resource returning %d, lock_id=%" PRIx64 "\n",
 | 
			
		||||
		 err, lock_id);
 | 
			
		||||
 | 
			
		||||
	linfo->lock_id = lock_id;
 | 
			
		||||
	linfo->res_handle = res_handle;
 | 
			
		||||
 | 
			
		||||
	dm_hash_insert(lock_hash, resource, linfo);
 | 
			
		||||
 | 
			
		||||
	return ais_to_errno(err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int _unlock_resource(char *resource, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	SaAisErrorT err;
 | 
			
		||||
	struct lock_info *linfo;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("unlock_resource %s\n", resource);
 | 
			
		||||
	linfo = dm_hash_lookup(lock_hash, resource);
 | 
			
		||||
	if (!linfo)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("unlock_resource: lockid: %" PRIx64 "\n", linfo->lock_id);
 | 
			
		||||
	err = saLckResourceUnlock(linfo->lock_id, SA_TIME_END);
 | 
			
		||||
	if (err != SA_AIS_OK)
 | 
			
		||||
	{
 | 
			
		||||
		DEBUGLOG("Unlock returned %d\n", err);
 | 
			
		||||
		return ais_to_errno(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Release the resource */
 | 
			
		||||
	dm_hash_remove(lock_hash, resource);
 | 
			
		||||
	saLckResourceClose(linfo->res_handle);
 | 
			
		||||
	free(linfo);
 | 
			
		||||
 | 
			
		||||
	return ais_to_errno(err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	char lock1[strlen(resource)+3];
 | 
			
		||||
	char lock2[strlen(resource)+3];
 | 
			
		||||
 | 
			
		||||
	snprintf(lock1, sizeof(lock1), "%s-1", resource);
 | 
			
		||||
	snprintf(lock2, sizeof(lock2), "%s-2", resource);
 | 
			
		||||
 | 
			
		||||
	switch (mode)
 | 
			
		||||
	{
 | 
			
		||||
	case LCK_EXCL:
 | 
			
		||||
		status = _lock_resource(lock1, SA_LCK_EX_LOCK_MODE, flags, lockid);
 | 
			
		||||
		if (status)
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
		/* If we can't get this lock too then bail out */
 | 
			
		||||
		status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, LCK_NONBLOCK,
 | 
			
		||||
					lockid);
 | 
			
		||||
		if (status == SA_LCK_LOCK_NOT_QUEUED)
 | 
			
		||||
		{
 | 
			
		||||
			_unlock_resource(lock1, *lockid);
 | 
			
		||||
			status = -1;
 | 
			
		||||
			errno = EAGAIN;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_PREAD:
 | 
			
		||||
	case LCK_READ:
 | 
			
		||||
		status = _lock_resource(lock1, SA_LCK_PR_LOCK_MODE, flags, lockid);
 | 
			
		||||
		if (status)
 | 
			
		||||
			goto out;
 | 
			
		||||
		_unlock_resource(lock2, *lockid);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_WRITE:
 | 
			
		||||
		status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, flags, lockid);
 | 
			
		||||
		if (status)
 | 
			
		||||
			goto out;
 | 
			
		||||
		_unlock_resource(lock1, *lockid);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		status = -1;
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	*lockid = mode;
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _sync_unlock(const char *resource, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	int status = 0;
 | 
			
		||||
	char lock1[strlen(resource)+3];
 | 
			
		||||
	char lock2[strlen(resource)+3];
 | 
			
		||||
 | 
			
		||||
	snprintf(lock1, sizeof(lock1), "%s-1", resource);
 | 
			
		||||
	snprintf(lock2, sizeof(lock2), "%s-2", resource);
 | 
			
		||||
 | 
			
		||||
	_unlock_resource(lock1, lockid);
 | 
			
		||||
	_unlock_resource(lock2, lockid);
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* We are always quorate ! */
 | 
			
		||||
static int _is_quorate()
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_main_cluster_fd(void)
 | 
			
		||||
{
 | 
			
		||||
	int select_fd;
 | 
			
		||||
 | 
			
		||||
	cpg_fd_get(cpg_handle, &select_fd);
 | 
			
		||||
	return select_fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
 | 
			
		||||
				const char *csid,
 | 
			
		||||
				struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
	cluster_client = fd;
 | 
			
		||||
	*new_client = NULL;
 | 
			
		||||
	cpg_dispatch(cpg_handle, SA_DISPATCH_ONE);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
 | 
			
		||||
				 const char *errtext)
 | 
			
		||||
{
 | 
			
		||||
	struct iovec iov[2];
 | 
			
		||||
	SaAisErrorT err;
 | 
			
		||||
	int target_node;
 | 
			
		||||
 | 
			
		||||
	if (csid)
 | 
			
		||||
		memcpy(&target_node, csid, OPENAIS_CSID_LEN);
 | 
			
		||||
	else
 | 
			
		||||
		target_node = 0;
 | 
			
		||||
 | 
			
		||||
	iov[0].iov_base = &target_node;
 | 
			
		||||
	iov[0].iov_len = sizeof(int);
 | 
			
		||||
	iov[1].iov_base = (char *)buf;
 | 
			
		||||
	iov[1].iov_len = msglen;
 | 
			
		||||
 | 
			
		||||
	err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
 | 
			
		||||
	return ais_to_errno(err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* We don't have a cluster name to report here */
 | 
			
		||||
static int _get_cluster_name(char *buf, int buflen)
 | 
			
		||||
{
 | 
			
		||||
	strncpy(buf, "OpenAIS", buflen);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct cluster_ops _cluster_openais_ops = {
 | 
			
		||||
	.name                     = "openais",
 | 
			
		||||
	.cluster_init_completed   = NULL,
 | 
			
		||||
	.cluster_send_message     = _cluster_send_message,
 | 
			
		||||
	.name_from_csid           = _name_from_csid,
 | 
			
		||||
	.csid_from_name           = _csid_from_name,
 | 
			
		||||
	.get_num_nodes            = _get_num_nodes,
 | 
			
		||||
	.cluster_fd_callback      = _cluster_fd_callback,
 | 
			
		||||
	.get_main_cluster_fd      = _get_main_cluster_fd,
 | 
			
		||||
	.cluster_do_node_callback = _cluster_do_node_callback,
 | 
			
		||||
	.is_quorate               = _is_quorate,
 | 
			
		||||
	.get_our_csid             = _get_our_csid,
 | 
			
		||||
	.add_up_node              = _add_up_node,
 | 
			
		||||
	.reread_config            = NULL,
 | 
			
		||||
	.cluster_closedown        = _cluster_closedown,
 | 
			
		||||
	.get_cluster_name         = _get_cluster_name,
 | 
			
		||||
	.sync_lock                = _sync_lock,
 | 
			
		||||
	.sync_unlock              = _sync_unlock,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cluster_ops *init_openais_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!_init_cluster())
 | 
			
		||||
		return &_cluster_openais_ops;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										382
									
								
								daemons/clvmd/clvmd-singlenode.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								daemons/clvmd/clvmd-singlenode.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,382 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2009-2013 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
static const char SINGLENODE_CLVMD_SOCKNAME[] = DEFAULT_RUN_DIR "/clvmd_singlenode.sock";
 | 
			
		||||
static int listen_fd = -1;
 | 
			
		||||
 | 
			
		||||
static struct dm_hash_table *_locks;
 | 
			
		||||
static int _lockid;
 | 
			
		||||
 | 
			
		||||
static pthread_mutex_t _lock_mutex = PTHREAD_MUTEX_INITIALIZER;
 | 
			
		||||
/* Using one common condition for all locks for simplicity */
 | 
			
		||||
static pthread_cond_t _lock_cond = PTHREAD_COND_INITIALIZER;
 | 
			
		||||
 | 
			
		||||
struct lock {
 | 
			
		||||
	struct dm_list list;
 | 
			
		||||
	int lockid;
 | 
			
		||||
	int mode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void close_comms(void)
 | 
			
		||||
{
 | 
			
		||||
	if (listen_fd != -1 && close(listen_fd))
 | 
			
		||||
		stack;
 | 
			
		||||
	(void)unlink(SINGLENODE_CLVMD_SOCKNAME);
 | 
			
		||||
	listen_fd = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int init_comms(void)
 | 
			
		||||
{
 | 
			
		||||
	mode_t old_mask;
 | 
			
		||||
	struct sockaddr_un addr = { .sun_family = AF_UNIX };
 | 
			
		||||
 | 
			
		||||
	if (!dm_strncpy(addr.sun_path, SINGLENODE_CLVMD_SOCKNAME,
 | 
			
		||||
			sizeof(addr.sun_path))) {
 | 
			
		||||
		DEBUGLOG("%s: singlenode socket name too long.",
 | 
			
		||||
			 SINGLENODE_CLVMD_SOCKNAME);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	close_comms();
 | 
			
		||||
 | 
			
		||||
	(void) dm_prepare_selinux_context(SINGLENODE_CLVMD_SOCKNAME, S_IFSOCK);
 | 
			
		||||
	old_mask = umask(0077);
 | 
			
		||||
 | 
			
		||||
	listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
 | 
			
		||||
	if (listen_fd < 0) {
 | 
			
		||||
		DEBUGLOG("Can't create local socket: %s\n", strerror(errno));
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
	/* Set Close-on-exec */
 | 
			
		||||
	if (fcntl(listen_fd, F_SETFD, 1)) {
 | 
			
		||||
		DEBUGLOG("Setting CLOEXEC on client fd failed: %s\n", strerror(errno));
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
 | 
			
		||||
		DEBUGLOG("Can't bind local socket: %s\n", strerror(errno));
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
	if (listen(listen_fd, 10) < 0) {
 | 
			
		||||
		DEBUGLOG("Can't listen local socket: %s\n", strerror(errno));
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	umask(old_mask);
 | 
			
		||||
	(void) dm_prepare_selinux_context(NULL, 0);
 | 
			
		||||
	return 0;
 | 
			
		||||
error:
 | 
			
		||||
	umask(old_mask);
 | 
			
		||||
	(void) dm_prepare_selinux_context(NULL, 0);
 | 
			
		||||
	close_comms();
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _init_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	if (!(_locks = dm_hash_create(128))) {
 | 
			
		||||
		DEBUGLOG("Failed to allocate single-node hash table.\n");
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = init_comms();
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dm_hash_destroy(_locks);
 | 
			
		||||
		_locks = NULL;
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Single-node cluster initialised.\n");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _cluster_closedown(void)
 | 
			
		||||
{
 | 
			
		||||
	close_comms();
 | 
			
		||||
 | 
			
		||||
	/* If there is any awaited resource, kill it softly */
 | 
			
		||||
	pthread_mutex_lock(&_lock_mutex);
 | 
			
		||||
	dm_hash_destroy(_locks);
 | 
			
		||||
	_locks = NULL;
 | 
			
		||||
	_lockid = 0;
 | 
			
		||||
	pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
 | 
			
		||||
	pthread_mutex_unlock(&_lock_mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _get_our_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
	int nodeid = 1;
 | 
			
		||||
	memcpy(csid, &nodeid, sizeof(int));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _csid_from_name(char *csid, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _name_from_csid(const char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	strcpy(name, "SINGLENODE");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_num_nodes(void)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Node is now known to be running a clvmd */
 | 
			
		||||
static void _add_up_node(const char *csid)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Call a callback for each node, so the caller knows whether it's up or down */
 | 
			
		||||
static int _cluster_do_node_callback(struct local_client *master_client,
 | 
			
		||||
				     void (*callback)(struct local_client *,
 | 
			
		||||
				     const char *csid, int node_up))
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _lock_file(const char *file, uint32_t flags);
 | 
			
		||||
 | 
			
		||||
static const char *_get_mode(int mode)
 | 
			
		||||
{
 | 
			
		||||
	switch (mode) {
 | 
			
		||||
	case LCK_NULL: return "NULL";
 | 
			
		||||
	case LCK_READ: return "READ";
 | 
			
		||||
	case LCK_PREAD: return "PREAD";
 | 
			
		||||
	case LCK_WRITE: return "WRITE";
 | 
			
		||||
	case LCK_EXCL: return "EXCLUSIVE";
 | 
			
		||||
	case LCK_UNLOCK: return "UNLOCK";
 | 
			
		||||
	default: return "????";
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Real locking */
 | 
			
		||||
static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
	/* DLM table of allowed transition states */
 | 
			
		||||
	static const int _dlm_table[6][6] = {
 | 
			
		||||
	/* Mode	   NL	CR	CW	PR	PW	EX */
 | 
			
		||||
	/* NL */ { 1,	 1,	 1,	 1,	 1,	 1},
 | 
			
		||||
	/* CR */ { 1,	 1,	 1,	 1,	 1,	 0},
 | 
			
		||||
	/* CW */ { 1,	 1,	 1,	 0,	 0,	 0},
 | 
			
		||||
	/* PR */ { 1,	 1,	 0,	 1,	 0,	 0},
 | 
			
		||||
	/* PW */ { 1,	 1,	 0,	 0,	 0,	 0},
 | 
			
		||||
	/* EX */ { 1,	 0,	 0,	 0,	 0,	 0}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct lock *lck = NULL, *lckt;
 | 
			
		||||
	struct dm_list *head;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Locking resource %s, flags=0x%02x (%s%s%s), mode=%s (%d)\n",
 | 
			
		||||
		 resource, flags,
 | 
			
		||||
		 (flags & LCKF_NOQUEUE) ? "NOQUEUE" : "",
 | 
			
		||||
		 ((flags & (LCKF_NOQUEUE | LCKF_CONVERT)) ==
 | 
			
		||||
		  (LCKF_NOQUEUE | LCKF_CONVERT)) ? "|" : "",
 | 
			
		||||
		 (flags & LCKF_CONVERT) ? "CONVERT" : "",
 | 
			
		||||
		 _get_mode(mode), mode);
 | 
			
		||||
 | 
			
		||||
	mode &= LCK_TYPE_MASK;
 | 
			
		||||
	pthread_mutex_lock(&_lock_mutex);
 | 
			
		||||
 | 
			
		||||
retry:
 | 
			
		||||
	if (!(head = dm_hash_lookup(_locks, resource))) {
 | 
			
		||||
		if (flags & LCKF_CONVERT) {
 | 
			
		||||
			/* In real DLM, lock is identified only by lockid, resource is not used */
 | 
			
		||||
			DEBUGLOG("Unlocked resource %s cannot be converted\n", resource);
 | 
			
		||||
			goto_bad;
 | 
			
		||||
		}
 | 
			
		||||
		/* Add new locked resource */
 | 
			
		||||
		if (!(head = dm_malloc(sizeof(struct dm_list))) ||
 | 
			
		||||
		    !dm_hash_insert(_locks, resource, head)) {
 | 
			
		||||
			dm_free(head);
 | 
			
		||||
			goto_bad;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dm_list_init(head);
 | 
			
		||||
	} else	/* Update/convert locked resource */
 | 
			
		||||
		dm_list_iterate_items(lck, head) {
 | 
			
		||||
			/* Check is all locks are compatible with requested lock */
 | 
			
		||||
			if (flags & LCKF_CONVERT) {
 | 
			
		||||
				if (lck->lockid != *lockid)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				DEBUGLOG("Converting resource %s lockid=%d mode:%s -> %s...\n",
 | 
			
		||||
					 resource, lck->lockid, _get_mode(lck->mode), _get_mode(mode));
 | 
			
		||||
				dm_list_iterate_items(lckt, head) {
 | 
			
		||||
					if ((lckt->lockid != *lockid) &&
 | 
			
		||||
					    !_dlm_table[mode][lckt->mode]) {
 | 
			
		||||
						if (!(flags & LCKF_NOQUEUE) &&
 | 
			
		||||
						    /* TODO: Real dlm uses here conversion queues */
 | 
			
		||||
						    !pthread_cond_wait(&_lock_cond, &_lock_mutex) &&
 | 
			
		||||
						    _locks) /* End of the game? */
 | 
			
		||||
							goto retry;
 | 
			
		||||
						goto bad;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				lck->mode = mode; /* Lock is now converted */
 | 
			
		||||
				goto out;
 | 
			
		||||
			} else if (!_dlm_table[mode][lck->mode]) {
 | 
			
		||||
				DEBUGLOG("Resource %s already locked lockid=%d, mode:%s\n",
 | 
			
		||||
					 resource, lck->lockid, _get_mode(lck->mode));
 | 
			
		||||
				if (!(flags & LCKF_NOQUEUE) &&
 | 
			
		||||
				    !pthread_cond_wait(&_lock_cond, &_lock_mutex) &&
 | 
			
		||||
				    _locks) { /* End of the game? */
 | 
			
		||||
					DEBUGLOG("Resource %s retrying lock in mode:%s...\n",
 | 
			
		||||
						 resource, _get_mode(mode));
 | 
			
		||||
					goto retry;
 | 
			
		||||
				}
 | 
			
		||||
				goto bad;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	if (!(flags & LCKF_CONVERT)) {
 | 
			
		||||
		if (!(lck = dm_malloc(sizeof(struct lock))))
 | 
			
		||||
			goto_bad;
 | 
			
		||||
 | 
			
		||||
		*lockid = lck->lockid = ++_lockid;
 | 
			
		||||
		lck->mode = mode;
 | 
			
		||||
		dm_list_add(head, &lck->list);
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
 | 
			
		||||
	pthread_mutex_unlock(&_lock_mutex);
 | 
			
		||||
	DEBUGLOG("Locked resource %s, lockid=%d, mode=%s\n",
 | 
			
		||||
		 resource, lck->lockid, _get_mode(lck->mode));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
bad:
 | 
			
		||||
	pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
 | 
			
		||||
	pthread_mutex_unlock(&_lock_mutex);
 | 
			
		||||
	DEBUGLOG("Failed to lock resource %s\n", resource);
 | 
			
		||||
 | 
			
		||||
	return 1; /* fail */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _unlock_resource(const char *resource, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	struct lock *lck;
 | 
			
		||||
	struct dm_list *head;
 | 
			
		||||
	int r = 1;
 | 
			
		||||
 | 
			
		||||
	if (lockid < 0) {
 | 
			
		||||
		DEBUGLOG("Not tracking unlock of lockid -1: %s, lockid=%d\n",
 | 
			
		||||
			 resource, lockid);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Unlocking resource %s, lockid=%d\n", resource, lockid);
 | 
			
		||||
	pthread_mutex_lock(&_lock_mutex);
 | 
			
		||||
	pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
 | 
			
		||||
 | 
			
		||||
	if (!(head = dm_hash_lookup(_locks, resource))) {
 | 
			
		||||
		pthread_mutex_unlock(&_lock_mutex);
 | 
			
		||||
		DEBUGLOG("Resource %s is not locked.\n", resource);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_list_iterate_items(lck, head)
 | 
			
		||||
		if (lck->lockid == lockid) {
 | 
			
		||||
			dm_list_del(&lck->list);
 | 
			
		||||
			dm_free(lck);
 | 
			
		||||
			r = 0;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Resource %s has wrong lockid %d.\n", resource, lockid);
 | 
			
		||||
out:
 | 
			
		||||
	if (dm_list_empty(head)) {
 | 
			
		||||
		//DEBUGLOG("Resource %s is no longer hashed (lockid=%d).\n", resource, lockid);
 | 
			
		||||
		dm_hash_remove(_locks, resource);
 | 
			
		||||
		dm_free(head);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&_lock_mutex);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _is_quorate(void)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_main_cluster_fd(void)
 | 
			
		||||
{
 | 
			
		||||
	return listen_fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
 | 
			
		||||
				const char *csid,
 | 
			
		||||
				struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_send_message(const void *buf, int msglen,
 | 
			
		||||
				 const char *csid,
 | 
			
		||||
				 const char *errtext)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_cluster_name(char *buf, int buflen)
 | 
			
		||||
{
 | 
			
		||||
	return dm_strncpy(buf, "localcluster", buflen) ? 0 : 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct cluster_ops _cluster_singlenode_ops = {
 | 
			
		||||
	.name                     = "singlenode",
 | 
			
		||||
	.cluster_init_completed   = NULL,
 | 
			
		||||
	.cluster_send_message     = _cluster_send_message,
 | 
			
		||||
	.name_from_csid           = _name_from_csid,
 | 
			
		||||
	.csid_from_name           = _csid_from_name,
 | 
			
		||||
	.get_num_nodes            = _get_num_nodes,
 | 
			
		||||
	.cluster_fd_callback      = _cluster_fd_callback,
 | 
			
		||||
	.get_main_cluster_fd      = _get_main_cluster_fd,
 | 
			
		||||
	.cluster_do_node_callback = _cluster_do_node_callback,
 | 
			
		||||
	.is_quorate               = _is_quorate,
 | 
			
		||||
	.get_our_csid             = _get_our_csid,
 | 
			
		||||
	.add_up_node              = _add_up_node,
 | 
			
		||||
	.reread_config            = NULL,
 | 
			
		||||
	.cluster_closedown        = _cluster_closedown,
 | 
			
		||||
	.get_cluster_name         = _get_cluster_name,
 | 
			
		||||
	.sync_lock                = _lock_resource,
 | 
			
		||||
	.sync_unlock              = _unlock_resource,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cluster_ops *init_singlenode_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!_init_cluster())
 | 
			
		||||
		return &_cluster_singlenode_ops;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2422
									
								
								daemons/clvmd/clvmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2422
									
								
								daemons/clvmd/clvmd.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										126
									
								
								daemons/clvmd/clvmd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								daemons/clvmd/clvmd.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _CLVMD_H
 | 
			
		||||
#define _CLVMD_H
 | 
			
		||||
 | 
			
		||||
#define CLVMD_MAJOR_VERSION 0
 | 
			
		||||
#define CLVMD_MINOR_VERSION 2
 | 
			
		||||
#define CLVMD_PATCH_VERSION 1
 | 
			
		||||
 | 
			
		||||
/* Default time (in seconds) we will wait for all remote commands to execute
 | 
			
		||||
   before declaring them dead */
 | 
			
		||||
#define DEFAULT_CMD_TIMEOUT 60
 | 
			
		||||
 | 
			
		||||
/* One of these for each reply we get from command execution on a node */
 | 
			
		||||
struct node_reply {
 | 
			
		||||
	char node[MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
	char *replymsg;
 | 
			
		||||
	int status;
 | 
			
		||||
	struct node_reply *next;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum {DEBUG_OFF, DEBUG_STDERR, DEBUG_SYSLOG} debug_t;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * These exist for the use of local sockets only when we are
 | 
			
		||||
 * collecting responses from all cluster nodes
 | 
			
		||||
 */
 | 
			
		||||
struct localsock_bits {
 | 
			
		||||
	struct node_reply *replies;
 | 
			
		||||
	int num_replies;
 | 
			
		||||
	int expected_replies;
 | 
			
		||||
	time_t sent_time;	/* So we can check for timeouts */
 | 
			
		||||
	int in_progress;	/* Only execute one cmd at a time per client */
 | 
			
		||||
	int sent_out;		/* Flag to indicate that a command was sent
 | 
			
		||||
				   to remote nodes */
 | 
			
		||||
	void *private;		/* Private area for command processor use */
 | 
			
		||||
	void *cmd;		/* Whole command as passed down local socket */
 | 
			
		||||
	int cmd_len;		/* Length of above */
 | 
			
		||||
	int pipe;		/* Pipe to send PRE completion status down */
 | 
			
		||||
	int finished;		/* Flag to tell subthread to exit */
 | 
			
		||||
	int all_success;	/* Set to 0 if any node (or the pre_command)
 | 
			
		||||
				   failed */
 | 
			
		||||
	int cleanup_needed;     /* helper for cleanup_zombie */
 | 
			
		||||
	struct local_client *pipe_client;
 | 
			
		||||
	pthread_t threadid;
 | 
			
		||||
	enum { PRE_COMMAND, POST_COMMAND } state;
 | 
			
		||||
	pthread_mutex_t mutex;	/* Main thread and worker synchronisation */
 | 
			
		||||
	pthread_cond_t cond;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Entries for PIPE clients */
 | 
			
		||||
struct pipe_bits {
 | 
			
		||||
	struct local_client *client;	/* Actual (localsock) client */
 | 
			
		||||
	pthread_t threadid;		/* Our own copy of the thread id */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Entries for Network socket clients */
 | 
			
		||||
struct netsock_bits {
 | 
			
		||||
	void *private;
 | 
			
		||||
	int flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef int (*fd_callback_t) (struct local_client * fd, char *buf, int len,
 | 
			
		||||
			      const char *csid,
 | 
			
		||||
			      struct local_client ** new_client);
 | 
			
		||||
 | 
			
		||||
/* One of these for each fd we are listening on */
 | 
			
		||||
struct local_client {
 | 
			
		||||
	int fd;
 | 
			
		||||
	enum { CLUSTER_MAIN_SOCK, CLUSTER_DATA_SOCK, LOCAL_RENDEZVOUS,
 | 
			
		||||
		    LOCAL_SOCK, THREAD_PIPE, CLUSTER_INTERNAL } type;
 | 
			
		||||
	struct local_client *next;
 | 
			
		||||
	unsigned short xid;
 | 
			
		||||
	fd_callback_t callback;
 | 
			
		||||
	uint8_t removeme;
 | 
			
		||||
 | 
			
		||||
	union {
 | 
			
		||||
		struct localsock_bits localsock;
 | 
			
		||||
		struct pipe_bits pipe;
 | 
			
		||||
		struct netsock_bits net;
 | 
			
		||||
	} bits;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define DEBUGLOG(fmt, args...) debuglog(fmt, ## args)
 | 
			
		||||
 | 
			
		||||
#ifndef max
 | 
			
		||||
#define max(a,b) ((a)>(b)?(a):(b))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* The real command processor is in clvmd-command.c */
 | 
			
		||||
extern int do_command(struct local_client *client, struct clvm_header *msg,
 | 
			
		||||
		      int msglen, char **buf, int buflen, int *retlen);
 | 
			
		||||
 | 
			
		||||
/* Pre and post command routines are called only on the local node */
 | 
			
		||||
extern int do_pre_command(struct local_client *client);
 | 
			
		||||
extern int do_post_command(struct local_client *client);
 | 
			
		||||
extern void cmd_client_cleanup(struct local_client *client);
 | 
			
		||||
extern int add_client(struct local_client *new_client);
 | 
			
		||||
 | 
			
		||||
extern void clvmd_cluster_init_completed(void);
 | 
			
		||||
extern void process_message(struct local_client *client, char *buf,
 | 
			
		||||
			    int len, const char *csid);
 | 
			
		||||
extern void debuglog(const char *fmt, ... )
 | 
			
		||||
  __attribute__ ((format(printf, 1, 2)));
 | 
			
		||||
 | 
			
		||||
void clvmd_set_debug(debug_t new_de);
 | 
			
		||||
debug_t clvmd_get_debug(void);
 | 
			
		||||
int clvmd_get_foreground(void);
 | 
			
		||||
 | 
			
		||||
int sync_lock(const char *resource, int mode, int flags, int *lockid);
 | 
			
		||||
int sync_unlock(const char *resource, int lockid);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										927
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										927
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,927 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
#include "lvm-functions.h"
 | 
			
		||||
 | 
			
		||||
/* LVM2 headers */
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
#include "lvm-globals.h"
 | 
			
		||||
#include "activate.h"
 | 
			
		||||
#include "archiver.h"
 | 
			
		||||
#include "memlock.h"
 | 
			
		||||
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
static struct cmd_context *cmd = NULL;
 | 
			
		||||
static struct dm_hash_table *lv_hash = NULL;
 | 
			
		||||
static pthread_mutex_t lv_hash_lock;
 | 
			
		||||
static pthread_mutex_t lvm_lock;
 | 
			
		||||
static char last_error[1024];
 | 
			
		||||
 | 
			
		||||
struct lv_info {
 | 
			
		||||
	int lock_id;
 | 
			
		||||
	int lock_mode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char *decode_full_locking_cmd(uint32_t cmdl)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[128];
 | 
			
		||||
	const char *type;
 | 
			
		||||
	const char *scope;
 | 
			
		||||
	const char *command;
 | 
			
		||||
 | 
			
		||||
	switch (cmdl & LCK_TYPE_MASK) {
 | 
			
		||||
	case LCK_NULL:
 | 
			
		||||
		type = "NULL";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_READ:
 | 
			
		||||
		type = "READ";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_PREAD:
 | 
			
		||||
		type = "PREAD";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_WRITE:
 | 
			
		||||
		type = "WRITE";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_EXCL:
 | 
			
		||||
		type = "EXCL";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_UNLOCK:
 | 
			
		||||
		type = "UNLOCK";
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		type = "unknown";
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (cmdl & LCK_SCOPE_MASK) {
 | 
			
		||||
	case LCK_VG:
 | 
			
		||||
		scope = "VG";
 | 
			
		||||
		command = "LCK_VG";
 | 
			
		||||
		break;
 | 
			
		||||
	case LCK_LV:
 | 
			
		||||
		scope = "LV";
 | 
			
		||||
		switch (cmdl & LCK_MASK) {
 | 
			
		||||
		case LCK_LV_EXCLUSIVE & LCK_MASK:
 | 
			
		||||
			command = "LCK_LV_EXCLUSIVE";
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_LV_SUSPEND & LCK_MASK:
 | 
			
		||||
			command = "LCK_LV_SUSPEND";
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_LV_RESUME & LCK_MASK:
 | 
			
		||||
			command = "LCK_LV_RESUME";
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_LV_ACTIVATE & LCK_MASK:
 | 
			
		||||
			command = "LCK_LV_ACTIVATE";
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_LV_DEACTIVATE & LCK_MASK:
 | 
			
		||||
			command = "LCK_LV_DEACTIVATE";
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			command = "unknown";
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		scope = "unknown";
 | 
			
		||||
		command = "unknown";
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sprintf(buf, "0x%x %s (%s|%s%s%s%s%s)", cmdl, command, type, scope,
 | 
			
		||||
		cmdl & LCK_NONBLOCK   ? "|NONBLOCK" : "",
 | 
			
		||||
		cmdl & LCK_HOLD       ? "|HOLD" : "",
 | 
			
		||||
		cmdl & LCK_CLUSTER_VG ? "|CLUSTER_VG" : "",
 | 
			
		||||
		cmdl & LCK_CACHE      ? "|CACHE" : "");
 | 
			
		||||
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Only processes 8 bits: excludes LCK_CACHE.
 | 
			
		||||
 */
 | 
			
		||||
static const char *decode_locking_cmd(unsigned char cmdl)
 | 
			
		||||
{
 | 
			
		||||
	return decode_full_locking_cmd((uint32_t) cmdl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *decode_flags(unsigned char flags)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[128];
 | 
			
		||||
	int len;
 | 
			
		||||
 | 
			
		||||
	len = sprintf(buf, "0x%x ( %s%s%s%s%s%s%s%s)", flags,
 | 
			
		||||
		flags & LCK_PARTIAL_MODE	  ? "PARTIAL_MODE|" : "",
 | 
			
		||||
		flags & LCK_MIRROR_NOSYNC_MODE	  ? "MIRROR_NOSYNC|" : "",
 | 
			
		||||
		flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "",
 | 
			
		||||
		flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "",
 | 
			
		||||
		flags & LCK_TEST_MODE ? "TEST|" : "",
 | 
			
		||||
		flags & LCK_CONVERT_MODE ? "CONVERT|" : "",
 | 
			
		||||
		flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : "",
 | 
			
		||||
		flags & LCK_REVERT_MODE ? "REVERT|" : "");
 | 
			
		||||
 | 
			
		||||
	if (len > 1)
 | 
			
		||||
		buf[len - 2] = ' ';
 | 
			
		||||
	else
 | 
			
		||||
		buf[0] = '\0';
 | 
			
		||||
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *get_last_lvm_error(void)
 | 
			
		||||
{
 | 
			
		||||
	return last_error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Hash lock info helpers
 | 
			
		||||
 */
 | 
			
		||||
static struct lv_info *lookup_info(const char *resource)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lv_hash_lock);
 | 
			
		||||
	lvi = dm_hash_lookup(lv_hash, resource);
 | 
			
		||||
	pthread_mutex_unlock(&lv_hash_lock);
 | 
			
		||||
 | 
			
		||||
	return lvi;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int insert_info(const char *resource, struct lv_info *lvi)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lv_hash_lock);
 | 
			
		||||
	ret = dm_hash_insert(lv_hash, resource, lvi);
 | 
			
		||||
	pthread_mutex_unlock(&lv_hash_lock);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void remove_info(const char *resource)
 | 
			
		||||
{
 | 
			
		||||
	int num_open;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lv_hash_lock);
 | 
			
		||||
	dm_hash_remove(lv_hash, resource);
 | 
			
		||||
 | 
			
		||||
	/* When last lock is remove, validate there are not left opened devices */
 | 
			
		||||
	if (!dm_hash_get_first(lv_hash)) {
 | 
			
		||||
		if (critical_section())
 | 
			
		||||
			log_error(INTERNAL_ERROR "No volumes are locked however clvmd is in activation mode critical section.");
 | 
			
		||||
		if ((num_open = dev_cache_check_for_open_devices()))
 | 
			
		||||
			log_error(INTERNAL_ERROR "No volumes are locked however %d devices are still open.", num_open);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&lv_hash_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the mode a lock is currently held at (or -1 if not held)
 | 
			
		||||
 */
 | 
			
		||||
static int get_current_lock(char *resource)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
 | 
			
		||||
	if ((lvi = lookup_info(resource)))
 | 
			
		||||
		return lvi->lock_mode;
 | 
			
		||||
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void init_lvhash(void)
 | 
			
		||||
{
 | 
			
		||||
	/* Create hash table for keeping LV locks & status */
 | 
			
		||||
	lv_hash = dm_hash_create(1024);
 | 
			
		||||
	pthread_mutex_init(&lv_hash_lock, NULL);
 | 
			
		||||
	pthread_mutex_init(&lvm_lock, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called at shutdown to tidy the lockspace */
 | 
			
		||||
void destroy_lvhash(void)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_hash_node *v;
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
	char *resource;
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lv_hash_lock);
 | 
			
		||||
 | 
			
		||||
	dm_hash_iterate(v, lv_hash) {
 | 
			
		||||
		lvi = dm_hash_get_data(lv_hash, v);
 | 
			
		||||
		resource = dm_hash_get_key(lv_hash, v);
 | 
			
		||||
 | 
			
		||||
		if ((status = sync_unlock(resource, lvi->lock_id)))
 | 
			
		||||
			DEBUGLOG("unlock_all. unlock failed(%d): %s\n",
 | 
			
		||||
				 status,  strerror(errno));
 | 
			
		||||
		dm_free(lvi);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_hash_destroy(lv_hash);
 | 
			
		||||
	lv_hash = NULL;
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&lv_hash_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Gets a real lock and keeps the info in the hash table */
 | 
			
		||||
static int hold_lock(char *resource, int mode, int flags)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	int saved_errno;
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
 | 
			
		||||
	/* Mask off invalid options */
 | 
			
		||||
	flags &= LCKF_NOQUEUE | LCKF_CONVERT;
 | 
			
		||||
 | 
			
		||||
	lvi = lookup_info(resource);
 | 
			
		||||
 | 
			
		||||
	if (lvi) {
 | 
			
		||||
		if (lvi->lock_mode == mode) {
 | 
			
		||||
			DEBUGLOG("hold_lock, lock mode %d already held\n",
 | 
			
		||||
				 mode);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		if ((lvi->lock_mode == LCK_EXCL) && (mode == LCK_WRITE)) {
 | 
			
		||||
			DEBUGLOG("hold_lock, lock already held LCK_EXCL, "
 | 
			
		||||
				 "ignoring LCK_WRITE request\n");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Only allow explicit conversions */
 | 
			
		||||
	if (lvi && !(flags & LCKF_CONVERT)) {
 | 
			
		||||
		errno = EBUSY;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (lvi) {
 | 
			
		||||
		/* Already exists - convert it */
 | 
			
		||||
		status = sync_lock(resource, mode, flags, &lvi->lock_id);
 | 
			
		||||
		saved_errno = errno;
 | 
			
		||||
		if (!status)
 | 
			
		||||
			lvi->lock_mode = mode;
 | 
			
		||||
		else
 | 
			
		||||
			DEBUGLOG("hold_lock. convert to %d failed: %s\n", mode,
 | 
			
		||||
				 strerror(errno));
 | 
			
		||||
		errno = saved_errno;
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!(lvi = dm_malloc(sizeof(struct lv_info)))) {
 | 
			
		||||
			errno = ENOMEM;
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		lvi->lock_mode = mode;
 | 
			
		||||
		lvi->lock_id = 0;
 | 
			
		||||
		status = sync_lock(resource, mode, flags & ~LCKF_CONVERT, &lvi->lock_id);
 | 
			
		||||
		saved_errno = errno;
 | 
			
		||||
		if (status) {
 | 
			
		||||
			dm_free(lvi);
 | 
			
		||||
			DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode,
 | 
			
		||||
				 strerror(errno));
 | 
			
		||||
		} else
 | 
			
		||||
			if (!insert_info(resource, lvi)) {
 | 
			
		||||
				errno = ENOMEM;
 | 
			
		||||
				return -1;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		errno = saved_errno;
 | 
			
		||||
	}
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Unlock and remove it from the hash table */
 | 
			
		||||
static int hold_unlock(char *resource)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
	int status;
 | 
			
		||||
	int saved_errno;
 | 
			
		||||
 | 
			
		||||
	if (!(lvi = lookup_info(resource))) {
 | 
			
		||||
		DEBUGLOG("hold_unlock, lock not already held\n");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	status = sync_unlock(resource, lvi->lock_id);
 | 
			
		||||
	saved_errno = errno;
 | 
			
		||||
	if (!status) {
 | 
			
		||||
		remove_info(resource);
 | 
			
		||||
		dm_free(lvi);
 | 
			
		||||
	} else {
 | 
			
		||||
		DEBUGLOG("hold_unlock. unlock failed(%d): %s\n", status,
 | 
			
		||||
			 strerror(errno));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	errno = saved_errno;
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Watch the return codes here.
 | 
			
		||||
   liblvm API functions return 1(true) for success, 0(false) for failure and don't set errno.
 | 
			
		||||
   libdlm API functions return 0 for success, -1 for failure and do set errno.
 | 
			
		||||
   These functions here return 0 for success or >0 for failure (where the retcode is errno)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/* Activate LV exclusive or non-exclusive */
 | 
			
		||||
static int do_activate_lv(char *resource, unsigned char command, unsigned char lock_flags, int mode)
 | 
			
		||||
{
 | 
			
		||||
	int oldmode;
 | 
			
		||||
	int status;
 | 
			
		||||
	int activate_lv;
 | 
			
		||||
	int exclusive = 0;
 | 
			
		||||
	struct lvinfo lvi;
 | 
			
		||||
 | 
			
		||||
	/* Is it already open ? */
 | 
			
		||||
	oldmode = get_current_lock(resource);
 | 
			
		||||
	if (oldmode == mode && (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		DEBUGLOG("do_activate_lv, lock already held at %d\n", oldmode);
 | 
			
		||||
		return 0;	/* Nothing to do */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Does the config file want us to activate this LV ? */
 | 
			
		||||
	if (!lv_activation_filter(cmd, resource, &activate_lv, NULL))
 | 
			
		||||
		return EIO;
 | 
			
		||||
 | 
			
		||||
	if (!activate_lv)
 | 
			
		||||
		return 0;	/* Success, we did nothing! */
 | 
			
		||||
 | 
			
		||||
	/* Do we need to activate exclusively? */
 | 
			
		||||
	if ((activate_lv == 2) || (mode == LCK_EXCL)) {
 | 
			
		||||
		exclusive = 1;
 | 
			
		||||
		mode = LCK_EXCL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Try to get the lock if it's a clustered volume group.
 | 
			
		||||
	 * Use lock conversion only if requested, to prevent implicit conversion
 | 
			
		||||
	 * of exclusive lock to shared one during activation.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!test_mode() && command & LCK_CLUSTER_VG) {
 | 
			
		||||
		status = hold_lock(resource, mode, LCKF_NOQUEUE | ((lock_flags & LCK_CONVERT_MODE) ? LCKF_CONVERT:0));
 | 
			
		||||
		if (status) {
 | 
			
		||||
			/* Return an LVM-sensible error for this.
 | 
			
		||||
			 * Forcing EIO makes the upper level return this text
 | 
			
		||||
			 * rather than the strerror text for EAGAIN.
 | 
			
		||||
			 */
 | 
			
		||||
			if (errno == EAGAIN) {
 | 
			
		||||
				sprintf(last_error, "Volume is busy on another node");
 | 
			
		||||
				errno = EIO;
 | 
			
		||||
			}
 | 
			
		||||
			return errno;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If it's suspended then resume it */
 | 
			
		||||
	if (!lv_info_by_lvid(cmd, resource, 0, &lvi, 0, 0))
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	if (lvi.suspended) {
 | 
			
		||||
		critical_section_inc(cmd, "resuming");
 | 
			
		||||
		if (!lv_resume(cmd, resource, 0, NULL)) {
 | 
			
		||||
			critical_section_dec(cmd, "resumed");
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Now activate it */
 | 
			
		||||
	if (!lv_activate(cmd, resource, exclusive, 0, 0, NULL))
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
error:
 | 
			
		||||
	if (!test_mode() && (oldmode == -1 || oldmode != mode))
 | 
			
		||||
		(void)hold_unlock(resource);
 | 
			
		||||
	return EIO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Resume the LV if it was active */
 | 
			
		||||
static int do_resume_lv(char *resource, unsigned char command, unsigned char lock_flags)
 | 
			
		||||
{
 | 
			
		||||
	int oldmode, origin_only, exclusive, revert;
 | 
			
		||||
 | 
			
		||||
	/* Is it open ? */
 | 
			
		||||
	oldmode = get_current_lock(resource);
 | 
			
		||||
	if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		DEBUGLOG("do_resume_lv, lock not already held\n");
 | 
			
		||||
		return 0;	/* We don't need to do anything */
 | 
			
		||||
	}
 | 
			
		||||
	origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
 | 
			
		||||
	exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
 | 
			
		||||
	revert = (lock_flags & LCK_REVERT_MODE) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	if (!lv_resume_if_active(cmd, resource, origin_only, exclusive, revert, NULL))
 | 
			
		||||
		return EIO;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Suspend the device if active */
 | 
			
		||||
static int do_suspend_lv(char *resource, unsigned char command, unsigned char lock_flags)
 | 
			
		||||
{
 | 
			
		||||
	int oldmode;
 | 
			
		||||
	unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
 | 
			
		||||
	unsigned exclusive;
 | 
			
		||||
 | 
			
		||||
	/* Is it open ? */
 | 
			
		||||
	oldmode = get_current_lock(resource);
 | 
			
		||||
	if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		DEBUGLOG("do_suspend_lv, lock not already held\n");
 | 
			
		||||
		return 0; /* Not active, so it's OK */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	/* Always call lv_suspend to read commited and precommited data */
 | 
			
		||||
	if (!lv_suspend_if_active(cmd, resource, origin_only, exclusive, NULL, NULL))
 | 
			
		||||
		return EIO;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int do_deactivate_lv(char *resource, unsigned char command, unsigned char lock_flags)
 | 
			
		||||
{
 | 
			
		||||
	int oldmode;
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	/* Is it open ? */
 | 
			
		||||
	oldmode = get_current_lock(resource);
 | 
			
		||||
	if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		DEBUGLOG("do_deactivate_lock, lock not already held\n");
 | 
			
		||||
		return 0;	/* We don't need to do anything */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lv_deactivate(cmd, resource, NULL))
 | 
			
		||||
		return EIO;
 | 
			
		||||
 | 
			
		||||
	if (!test_mode() && command & LCK_CLUSTER_VG) {
 | 
			
		||||
		status = hold_unlock(resource);
 | 
			
		||||
		if (status)
 | 
			
		||||
			return errno;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *do_lock_query(char *resource)
 | 
			
		||||
{
 | 
			
		||||
	int mode;
 | 
			
		||||
	const char *type;
 | 
			
		||||
 | 
			
		||||
	mode = get_current_lock(resource);
 | 
			
		||||
	switch (mode) {
 | 
			
		||||
	case LCK_NULL: type = "NL"; break;
 | 
			
		||||
	case LCK_READ: type = "CR"; break;
 | 
			
		||||
	case LCK_PREAD:type = "PR"; break;
 | 
			
		||||
	case LCK_WRITE:type = "PW"; break;
 | 
			
		||||
	case LCK_EXCL: type = "EX"; break;
 | 
			
		||||
	default: type = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("do_lock_query: resource '%s', mode %i (%s)\n", resource, mode, type ?: "--");
 | 
			
		||||
 | 
			
		||||
	return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This is the LOCK_LV part that happens on all nodes in the cluster -
 | 
			
		||||
   it is responsible for the interaction with device-mapper and LVM */
 | 
			
		||||
int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
 | 
			
		||||
{
 | 
			
		||||
	int status = 0;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
 | 
			
		||||
		 resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section());
 | 
			
		||||
 | 
			
		||||
	if (!cmd->initialized.config || config_files_changed(cmd)) {
 | 
			
		||||
		/* Reinitialise various settings inc. logging, filters */
 | 
			
		||||
		if (do_refresh_cache()) {
 | 
			
		||||
			log_error("Updated config file invalid. Aborting.");
 | 
			
		||||
			return EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
	init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
	if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
 | 
			
		||||
		init_mirror_in_sync(1);
 | 
			
		||||
 | 
			
		||||
	if (lock_flags & LCK_DMEVENTD_MONITOR_IGNORE)
 | 
			
		||||
		init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
 | 
			
		||||
	else {
 | 
			
		||||
		if (lock_flags & LCK_DMEVENTD_MONITOR_MODE)
 | 
			
		||||
			init_dmeventd_monitor(1);
 | 
			
		||||
		else
 | 
			
		||||
			init_dmeventd_monitor(0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd->partial_activation = (lock_flags & LCK_PARTIAL_MODE) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	/* clvmd should never try to read suspended device */
 | 
			
		||||
	init_ignore_suspended_devices(1);
 | 
			
		||||
 | 
			
		||||
	switch (command & LCK_MASK) {
 | 
			
		||||
	case LCK_LV_EXCLUSIVE:
 | 
			
		||||
		status = do_activate_lv(resource, command, lock_flags, LCK_EXCL);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_LV_SUSPEND:
 | 
			
		||||
		status = do_suspend_lv(resource, command, lock_flags);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_UNLOCK:
 | 
			
		||||
	case LCK_LV_RESUME:	/* if active */
 | 
			
		||||
		status = do_resume_lv(resource, command, lock_flags);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_LV_ACTIVATE:
 | 
			
		||||
		status = do_activate_lv(resource, command, lock_flags, LCK_READ);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case LCK_LV_DEACTIVATE:
 | 
			
		||||
		status = do_deactivate_lv(resource, command, lock_flags);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		DEBUGLOG("Invalid LV command 0x%x\n", command);
 | 
			
		||||
		status = EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
 | 
			
		||||
		init_mirror_in_sync(0);
 | 
			
		||||
 | 
			
		||||
	cmd->partial_activation = 0;
 | 
			
		||||
 | 
			
		||||
	/* clean the pool for another command */
 | 
			
		||||
	dm_pool_empty(cmd->mem);
 | 
			
		||||
	init_test(0);
 | 
			
		||||
	pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Command return is %d, critical_section is %d\n", status, critical_section());
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Functions to do on the local node only BEFORE the cluster-wide stuff above happens */
 | 
			
		||||
int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
 | 
			
		||||
{
 | 
			
		||||
	/* Nearly all the stuff happens cluster-wide. Apart from SUSPEND. Here we get the
 | 
			
		||||
	   lock out on this node (because we are the node modifying the metadata)
 | 
			
		||||
	   before suspending cluster-wide.
 | 
			
		||||
	   LCKF_CONVERT is used always, local node is going to modify metadata
 | 
			
		||||
	 */
 | 
			
		||||
	if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_SUSPEND &&
 | 
			
		||||
	    (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		DEBUGLOG("pre_lock_lv: resource '%s', cmd = %s, flags = %s\n",
 | 
			
		||||
			 resource, decode_locking_cmd(command), decode_flags(lock_flags));
 | 
			
		||||
 | 
			
		||||
		if (!(lock_flags & LCK_TEST_MODE) &&
 | 
			
		||||
		    hold_lock(resource, LCK_WRITE, LCKF_NOQUEUE | LCKF_CONVERT))
 | 
			
		||||
			return errno;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Functions to do on the local node only AFTER the cluster-wide stuff above happens */
 | 
			
		||||
int post_lock_lv(unsigned char command, unsigned char lock_flags,
 | 
			
		||||
		 char *resource)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	/* Opposite of above, done on resume after a metadata update */
 | 
			
		||||
	if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_RESUME &&
 | 
			
		||||
	    (command & LCK_CLUSTER_VG)) {
 | 
			
		||||
		int oldmode;
 | 
			
		||||
 | 
			
		||||
		DEBUGLOG("post_lock_lv: resource '%s', cmd = %s, flags = %s\n",
 | 
			
		||||
			 resource, decode_locking_cmd(command), decode_flags(lock_flags));
 | 
			
		||||
 | 
			
		||||
		/* If the lock state is PW then restore it to what it was */
 | 
			
		||||
		oldmode = get_current_lock(resource);
 | 
			
		||||
		if (oldmode == LCK_WRITE) {
 | 
			
		||||
			struct lvinfo lvi;
 | 
			
		||||
 | 
			
		||||
			pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
			status = lv_info_by_lvid(cmd, resource, origin_only, &lvi, 0, 0);
 | 
			
		||||
			pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
			if (!status)
 | 
			
		||||
				return EIO;
 | 
			
		||||
 | 
			
		||||
			if (!(lock_flags & LCK_TEST_MODE)) {
 | 
			
		||||
				if (lvi.exists) {
 | 
			
		||||
					if (hold_lock(resource, LCK_READ, LCKF_CONVERT))
 | 
			
		||||
						return errno;
 | 
			
		||||
				} else if (hold_unlock(resource))
 | 
			
		||||
					return errno;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int do_refresh_cache(void)
 | 
			
		||||
{
 | 
			
		||||
	DEBUGLOG("Refreshing context\n");
 | 
			
		||||
	log_notice("Refreshing context");
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
 | 
			
		||||
	if (!refresh_toolcontext(cmd)) {
 | 
			
		||||
		pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	init_ignore_suspended_devices(1);
 | 
			
		||||
	lvmcache_label_scan(cmd);
 | 
			
		||||
	label_scan_destroy(cmd); /* destroys bcache (to close devs), keeps lvmcache */
 | 
			
		||||
	dm_pool_empty(cmd->mem);
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Handle VG lock - drop metadata or update lvmcache state
 | 
			
		||||
 */
 | 
			
		||||
void do_lock_vg(unsigned char command, unsigned char lock_flags, char *resource)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t lock_cmd = command;
 | 
			
		||||
	char *vgname = resource + 2;
 | 
			
		||||
 | 
			
		||||
	lock_cmd &= (LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_HOLD);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Check if LCK_CACHE should be set. All P_ locks except # are cache related.
 | 
			
		||||
	 */
 | 
			
		||||
	if (strncmp(resource, "P_#", 3) && !strncmp(resource, "P_", 2))
 | 
			
		||||
		lock_cmd |= LCK_CACHE;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("do_lock_vg: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
 | 
			
		||||
		 resource, decode_full_locking_cmd(lock_cmd), decode_flags(lock_flags), critical_section());
 | 
			
		||||
 | 
			
		||||
	/* P_#global causes a full cache refresh */
 | 
			
		||||
	if (!strcmp(resource, "P_" VG_GLOBAL)) {
 | 
			
		||||
		do_refresh_cache();
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
	init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
	switch (lock_cmd) {
 | 
			
		||||
		case LCK_VG_COMMIT:
 | 
			
		||||
			DEBUGLOG("vg_commit notification for VG %s\n", vgname);
 | 
			
		||||
			lvmcache_commit_metadata(vgname);
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_VG_REVERT:
 | 
			
		||||
			DEBUGLOG("vg_revert notification for VG %s\n", vgname);
 | 
			
		||||
			lvmcache_drop_metadata(vgname, 1);
 | 
			
		||||
			break;
 | 
			
		||||
		case LCK_VG_DROP_CACHE:
 | 
			
		||||
		default:
 | 
			
		||||
			DEBUGLOG("Invalidating cached metadata for VG %s\n", vgname);
 | 
			
		||||
			lvmcache_drop_metadata(vgname, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	init_test(0);
 | 
			
		||||
	pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Ideally, clvmd should be started before any LVs are active
 | 
			
		||||
 * but this may not be the case...
 | 
			
		||||
 * I suppose this also comes in handy if clvmd crashes, not that it would!
 | 
			
		||||
 */
 | 
			
		||||
static int get_initial_state(struct dm_hash_table *excl_uuid)
 | 
			
		||||
{
 | 
			
		||||
	int lock_mode;
 | 
			
		||||
	char lv[65], vg[65], flags[26], vg_flags[26]; /* with space for '\0' */
 | 
			
		||||
	char uuid[65];
 | 
			
		||||
	char line[255];
 | 
			
		||||
	char *lvs_cmd;
 | 
			
		||||
	const char *lvm_binary = getenv("LVM_BINARY") ? : LVM_PATH;
 | 
			
		||||
	FILE *lvs;
 | 
			
		||||
 | 
			
		||||
	if (dm_asprintf(&lvs_cmd, "%s lvs  --config 'log{command_names=0 prefix=\"\"}' "
 | 
			
		||||
			"--nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr",
 | 
			
		||||
			lvm_binary) < 0)
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	/* FIXME: Maybe link and use liblvm2cmd directly instead of fork */
 | 
			
		||||
	if (!(lvs = popen(lvs_cmd, "r"))) {
 | 
			
		||||
		dm_free(lvs_cmd);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (fgets(line, sizeof(line), lvs)) {
 | 
			
		||||
	        if (sscanf(line, "%64s %64s %25s %25s\n", vg, lv, flags, vg_flags) == 4) {
 | 
			
		||||
 | 
			
		||||
			/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
 | 
			
		||||
		        if (strlen(vg) == 38 &&                         /* is is a valid UUID ? */
 | 
			
		||||
			    (flags[4] == 'a' || flags[4] == 's') &&	/* is it active or suspended? */
 | 
			
		||||
			    vg_flags[5] == 'c') {			/* is it clustered ? */
 | 
			
		||||
				/* Convert hyphen-separated UUIDs into one */
 | 
			
		||||
				memcpy(&uuid[0], &vg[0], 6);
 | 
			
		||||
				memcpy(&uuid[6], &vg[7], 4);
 | 
			
		||||
				memcpy(&uuid[10], &vg[12], 4);
 | 
			
		||||
				memcpy(&uuid[14], &vg[17], 4);
 | 
			
		||||
				memcpy(&uuid[18], &vg[22], 4);
 | 
			
		||||
				memcpy(&uuid[22], &vg[27], 4);
 | 
			
		||||
				memcpy(&uuid[26], &vg[32], 6);
 | 
			
		||||
				memcpy(&uuid[32], &lv[0], 6);
 | 
			
		||||
				memcpy(&uuid[38], &lv[7], 4);
 | 
			
		||||
				memcpy(&uuid[42], &lv[12], 4);
 | 
			
		||||
				memcpy(&uuid[46], &lv[17], 4);
 | 
			
		||||
				memcpy(&uuid[50], &lv[22], 4);
 | 
			
		||||
				memcpy(&uuid[54], &lv[27], 4);
 | 
			
		||||
				memcpy(&uuid[58], &lv[32], 6);
 | 
			
		||||
				uuid[64] = '\0';
 | 
			
		||||
 | 
			
		||||
				/* Look for this lock in the list of EX locks
 | 
			
		||||
				   we were passed on the command-line */
 | 
			
		||||
				lock_mode = (dm_hash_lookup(excl_uuid, uuid)) ?
 | 
			
		||||
					LCK_EXCL : LCK_READ;
 | 
			
		||||
 | 
			
		||||
				DEBUGLOG("getting initial lock for %s\n", uuid);
 | 
			
		||||
				if (hold_lock(uuid, lock_mode, LCKF_NOQUEUE))
 | 
			
		||||
					DEBUGLOG("Failed to hold lock %s\n", uuid);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (pclose(lvs))
 | 
			
		||||
		DEBUGLOG("lvs pclose failed: %s\n", strerror(errno));
 | 
			
		||||
 | 
			
		||||
	dm_free(lvs_cmd);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lvm2_log_fn(int level, const char *file, int line, int dm_errno,
 | 
			
		||||
			const char *message)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	/* Send messages to the normal LVM2 logging system too,
 | 
			
		||||
	   so we get debug output when it's asked for.
 | 
			
		||||
 	   We need to NULL the function ptr otherwise it will just call
 | 
			
		||||
	   back into here! */
 | 
			
		||||
	init_log_fn(NULL);
 | 
			
		||||
	print_log(level, file, line, dm_errno, "%s", message);
 | 
			
		||||
	init_log_fn(lvm2_log_fn);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Ignore non-error messages, but store the latest one for returning
 | 
			
		||||
	 * to the user.
 | 
			
		||||
	 */
 | 
			
		||||
	if (level != _LOG_ERR && level != _LOG_FATAL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	(void) dm_strncpy(last_error, message, sizeof(last_error));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* This checks some basic cluster-LVM configuration stuff */
 | 
			
		||||
static void check_config(void)
 | 
			
		||||
{
 | 
			
		||||
	int locking_type;
 | 
			
		||||
 | 
			
		||||
	locking_type = find_config_tree_int(cmd, global_locking_type_CFG, NULL);
 | 
			
		||||
 | 
			
		||||
	if (locking_type == 3) /* compiled-in cluster support */
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (locking_type == 2) { /* External library, check name */
 | 
			
		||||
		const char *libname;
 | 
			
		||||
 | 
			
		||||
		libname = find_config_tree_str(cmd, global_locking_library_CFG, NULL);
 | 
			
		||||
		if (libname && strstr(libname, "liblvm2clusterlock.so"))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work.");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	log_error("locking_type not set correctly in lvm.conf, cluster operations will not work.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Backups up the LVM metadata if it's changed */
 | 
			
		||||
void lvm_do_backup(const char *vgname)
 | 
			
		||||
{
 | 
			
		||||
	struct volume_group * vg;
 | 
			
		||||
	int consistent = 0;
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("Triggering backup of VG metadata for %s.\n", vgname);
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
 | 
			
		||||
	vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, 0, 0, WARN_PV_READ, &consistent);
 | 
			
		||||
 | 
			
		||||
	if (vg && consistent)
 | 
			
		||||
		check_current_backup(vg);
 | 
			
		||||
	else
 | 
			
		||||
		log_error("Error backing up metadata, can't find VG for group %s", vgname);
 | 
			
		||||
 | 
			
		||||
	release_vg(vg);
 | 
			
		||||
	dm_pool_empty(cmd->mem);
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_info *lvi;
 | 
			
		||||
 | 
			
		||||
	*name = NULL;
 | 
			
		||||
	if (!v)
 | 
			
		||||
		v = dm_hash_get_first(lv_hash);
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		if (v) {
 | 
			
		||||
			lvi = dm_hash_get_data(lv_hash, v);
 | 
			
		||||
			DEBUGLOG("Looking for EX locks. found %x mode %d\n", lvi->lock_id, lvi->lock_mode);
 | 
			
		||||
 | 
			
		||||
			if (lvi->lock_mode == LCK_EXCL) {
 | 
			
		||||
				*name = dm_hash_get_key(lv_hash, v);
 | 
			
		||||
			}
 | 
			
		||||
			v = dm_hash_get_next(lv_hash, v);
 | 
			
		||||
		}
 | 
			
		||||
	} while (v && !*name);
 | 
			
		||||
 | 
			
		||||
	if (*name)
 | 
			
		||||
		DEBUGLOG("returning EXclusive UUID %s\n", *name);
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lvm_do_fs_unlock(void)
 | 
			
		||||
{
 | 
			
		||||
	pthread_mutex_lock(&lvm_lock);
 | 
			
		||||
	DEBUGLOG("Syncing device names\n");
 | 
			
		||||
	fs_unlock();
 | 
			
		||||
	pthread_mutex_unlock(&lvm_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called to initialise the LVM context of the daemon */
 | 
			
		||||
int init_clvm(struct dm_hash_table *excl_uuid)
 | 
			
		||||
{
 | 
			
		||||
	/* Use LOG_DAEMON for syslog messages instead of LOG_USER */
 | 
			
		||||
	init_syslog(LOG_DAEMON);
 | 
			
		||||
	openlog("clvmd", LOG_PID, LOG_DAEMON);
 | 
			
		||||
 | 
			
		||||
	/* Initialise already held locks */
 | 
			
		||||
	if (!get_initial_state(excl_uuid))
 | 
			
		||||
		log_error("Cannot load initial lock states.");
 | 
			
		||||
 | 
			
		||||
	if (!udev_init_library_context())
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
 | 
			
		||||
		log_error("Failed to allocate command context");
 | 
			
		||||
		udev_fin_library_context();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (stored_errno()) {
 | 
			
		||||
		destroy_toolcontext(cmd);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd->cmd_line = "clvmd";
 | 
			
		||||
 | 
			
		||||
	/* Check lvm.conf is setup for cluster-LVM */
 | 
			
		||||
	check_config();
 | 
			
		||||
	init_ignore_suspended_devices(1);
 | 
			
		||||
 | 
			
		||||
	/* Trap log messages so we can pass them back to the user */
 | 
			
		||||
	init_log_fn(lvm2_log_fn);
 | 
			
		||||
	memlock_inc_daemon(cmd);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void destroy_lvm(void)
 | 
			
		||||
{
 | 
			
		||||
	if (cmd) {
 | 
			
		||||
		memlock_dec_daemon(cmd);
 | 
			
		||||
		destroy_toolcontext(cmd);
 | 
			
		||||
		udev_fin_library_context();
 | 
			
		||||
		cmd = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Functions in lvm-functions.c */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_FUNCTIONS_H
 | 
			
		||||
#define _LVM_FUNCTIONS_H
 | 
			
		||||
 | 
			
		||||
extern int pre_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
 | 
			
		||||
		       char *resource);
 | 
			
		||||
extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
 | 
			
		||||
		      char *resource);
 | 
			
		||||
extern const char *do_lock_query(char *resource);
 | 
			
		||||
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
 | 
			
		||||
			char *resource);
 | 
			
		||||
extern int do_refresh_cache(void);
 | 
			
		||||
extern int init_clvm(struct dm_hash_table *excl_uuid);
 | 
			
		||||
extern void destroy_lvm(void);
 | 
			
		||||
extern void init_lvhash(void);
 | 
			
		||||
extern void destroy_lvhash(void);
 | 
			
		||||
extern void lvm_do_backup(const char *vgname);
 | 
			
		||||
extern char *get_last_lvm_error(void);
 | 
			
		||||
extern void do_lock_vg(unsigned char command, unsigned char lock_flags,
 | 
			
		||||
		      char *resource);
 | 
			
		||||
extern struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name);
 | 
			
		||||
void lvm_do_fs_unlock(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										382
									
								
								daemons/clvmd/refresh_clvmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								daemons/clvmd/refresh_clvmd.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,382 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* FIXME Remove duplicated functions from this file. */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Send a command to a running clvmd from the command-line
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "clvmd-common.h"
 | 
			
		||||
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "refresh_clvmd.h"
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
 | 
			
		||||
typedef struct lvm_response {
 | 
			
		||||
	char node[255];
 | 
			
		||||
	char *response;
 | 
			
		||||
	int status;
 | 
			
		||||
	int len;
 | 
			
		||||
} lvm_response_t;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This gets stuck at the start of memory we allocate so we
 | 
			
		||||
 * can sanity-check it at deallocation time
 | 
			
		||||
 */
 | 
			
		||||
#define LVM_SIGNATURE 0x434C564D
 | 
			
		||||
 | 
			
		||||
static int _clvmd_sock = -1;
 | 
			
		||||
 | 
			
		||||
/* Open connection to the clvm daemon */
 | 
			
		||||
static int _open_local_sock(void)
 | 
			
		||||
{
 | 
			
		||||
	int local_socket;
 | 
			
		||||
	struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
 | 
			
		||||
 | 
			
		||||
	if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
 | 
			
		||||
		fprintf(stderr, "%s: clvmd socket name too long.", CLVMD_SOCKNAME);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Open local socket */
 | 
			
		||||
	if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
 | 
			
		||||
		fprintf(stderr, "Local socket creation failed: %s", strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (connect(local_socket,(struct sockaddr *) &sockaddr,
 | 
			
		||||
		    sizeof(sockaddr))) {
 | 
			
		||||
		int saved_errno = errno;
 | 
			
		||||
 | 
			
		||||
		fprintf(stderr, "connect() failed on local socket: %s\n",
 | 
			
		||||
			  strerror(errno));
 | 
			
		||||
		if (close(local_socket))
 | 
			
		||||
			return -1;
 | 
			
		||||
 | 
			
		||||
		errno = saved_errno;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return local_socket;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Send a request and return the status */
 | 
			
		||||
static int _send_request(const char *inbuf, int inlen, char **retbuf, int no_response)
 | 
			
		||||
{
 | 
			
		||||
	char outbuf[PIPE_BUF];
 | 
			
		||||
	struct clvm_header *outheader = (struct clvm_header *) outbuf;
 | 
			
		||||
	int len;
 | 
			
		||||
	unsigned off;
 | 
			
		||||
	int buflen;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	/* Send it to CLVMD */
 | 
			
		||||
 rewrite:
 | 
			
		||||
	if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
 | 
			
		||||
	        if (err == -1 && errno == EINTR)
 | 
			
		||||
		        goto rewrite;
 | 
			
		||||
		fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (no_response)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	/* Get the response */
 | 
			
		||||
 reread:
 | 
			
		||||
	if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
 | 
			
		||||
	        if (errno == EINTR)
 | 
			
		||||
		        goto reread;
 | 
			
		||||
		fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (len == 0) {
 | 
			
		||||
		fprintf(stderr, "EOF reading CLVMD");
 | 
			
		||||
		errno = ENOTCONN;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Allocate buffer */
 | 
			
		||||
	buflen = len + outheader->arglen;
 | 
			
		||||
	*retbuf = dm_malloc(buflen);
 | 
			
		||||
	if (!*retbuf) {
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Copy the header */
 | 
			
		||||
	memcpy(*retbuf, outbuf, len);
 | 
			
		||||
	outheader = (struct clvm_header *) *retbuf;
 | 
			
		||||
 | 
			
		||||
	/* Read the returned values */
 | 
			
		||||
	off = 1;		/* we've already read the first byte */
 | 
			
		||||
	while (off <= outheader->arglen && len > 0) {
 | 
			
		||||
		len = read(_clvmd_sock, outheader->args + off,
 | 
			
		||||
			   buflen - off - offsetof(struct clvm_header, args));
 | 
			
		||||
		if (len > 0)
 | 
			
		||||
			off += len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Was it an error ? */
 | 
			
		||||
	if (outheader->status != 0) {
 | 
			
		||||
		errno = outheader->status;
 | 
			
		||||
 | 
			
		||||
		/* Only return an error here if there are no node-specific
 | 
			
		||||
		   errors present in the message that might have more detail */
 | 
			
		||||
		if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
 | 
			
		||||
			fprintf(stderr, "cluster request failed: %s\n", strerror(errno));
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Build the structure header and parse-out wildcard node names */
 | 
			
		||||
static void _build_header(struct clvm_header *head, int cmd, const char *node,
 | 
			
		||||
			  unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
	head->cmd = cmd;
 | 
			
		||||
	head->status = 0;
 | 
			
		||||
	head->flags = 0;
 | 
			
		||||
	head->xid = 0;
 | 
			
		||||
	head->clientid = 0;
 | 
			
		||||
	if (len)
 | 
			
		||||
		/* 1 byte is used from struct clvm_header.args[1], so -> len - 1 */
 | 
			
		||||
		head->arglen = len - 1;
 | 
			
		||||
	else {
 | 
			
		||||
		head->arglen = 0;
 | 
			
		||||
		*head->args = '\0';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Translate special node names.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!node || !strcmp(node, NODE_ALL))
 | 
			
		||||
		head->node[0] = '\0';
 | 
			
		||||
	else if (!strcmp(node, NODE_LOCAL)) {
 | 
			
		||||
		head->node[0] = '\0';
 | 
			
		||||
		head->flags = CLVMD_FLAG_LOCAL;
 | 
			
		||||
	} else
 | 
			
		||||
		strcpy(head->node, node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Send a message to a(or all) node(s) in the cluster and wait for replies
 | 
			
		||||
 */
 | 
			
		||||
static int _cluster_request(char cmd, const char *node, void *data, int len,
 | 
			
		||||
			    lvm_response_t ** response, int *num, int no_response)
 | 
			
		||||
{
 | 
			
		||||
	char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
 | 
			
		||||
	char *inptr;
 | 
			
		||||
	char *retbuf = NULL;
 | 
			
		||||
	int status;
 | 
			
		||||
	int i;
 | 
			
		||||
	int num_responses = 0;
 | 
			
		||||
	struct clvm_header *head = (struct clvm_header *) outbuf;
 | 
			
		||||
	lvm_response_t *rarray;
 | 
			
		||||
 | 
			
		||||
	*num = 0;
 | 
			
		||||
 | 
			
		||||
	if (_clvmd_sock == -1)
 | 
			
		||||
		_clvmd_sock = _open_local_sock();
 | 
			
		||||
 | 
			
		||||
	if (_clvmd_sock == -1)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	_build_header(head, cmd, node, len);
 | 
			
		||||
	if (len)
 | 
			
		||||
		memcpy(head->node + strlen(head->node) + 1, data, len);
 | 
			
		||||
 | 
			
		||||
	status = _send_request(outbuf, sizeof(struct clvm_header) +
 | 
			
		||||
			       strlen(head->node) + len, &retbuf, no_response);
 | 
			
		||||
	if (!status || no_response)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	/* Count the number of responses we got */
 | 
			
		||||
	head = (struct clvm_header *) retbuf;
 | 
			
		||||
	inptr = head->args;
 | 
			
		||||
	while (inptr[0]) {
 | 
			
		||||
		num_responses++;
 | 
			
		||||
		inptr += strlen(inptr) + 1;
 | 
			
		||||
		inptr += sizeof(int);
 | 
			
		||||
		inptr += strlen(inptr) + 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Allocate response array.
 | 
			
		||||
	 * With an extra pair of INTs on the front to sanity
 | 
			
		||||
	 * check the pointer when we are given it back to free
 | 
			
		||||
	 */
 | 
			
		||||
	*response = NULL;
 | 
			
		||||
	if (!(rarray = dm_malloc(sizeof(lvm_response_t) * num_responses +
 | 
			
		||||
				 sizeof(int) * 2))) {
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		status = 0;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Unpack the response into an lvm_response_t array */
 | 
			
		||||
	inptr = head->args;
 | 
			
		||||
	i = 0;
 | 
			
		||||
	while (inptr[0]) {
 | 
			
		||||
		strcpy(rarray[i].node, inptr);
 | 
			
		||||
		inptr += strlen(inptr) + 1;
 | 
			
		||||
 | 
			
		||||
		memcpy(&rarray[i].status, inptr, sizeof(int));
 | 
			
		||||
		inptr += sizeof(int);
 | 
			
		||||
 | 
			
		||||
		rarray[i].response = dm_malloc(strlen(inptr) + 1);
 | 
			
		||||
		if (rarray[i].response == NULL) {
 | 
			
		||||
			/* Free up everything else and return error */
 | 
			
		||||
			int j;
 | 
			
		||||
			for (j = 0; j < i; j++)
 | 
			
		||||
				dm_free(rarray[i].response);
 | 
			
		||||
			dm_free(rarray);
 | 
			
		||||
			errno = ENOMEM;
 | 
			
		||||
			status = 0;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		strcpy(rarray[i].response, inptr);
 | 
			
		||||
		rarray[i].len = strlen(inptr);
 | 
			
		||||
		inptr += strlen(inptr) + 1;
 | 
			
		||||
		i++;
 | 
			
		||||
	}
 | 
			
		||||
	*num = num_responses;
 | 
			
		||||
	*response = rarray;
 | 
			
		||||
 | 
			
		||||
      out:
 | 
			
		||||
	dm_free(retbuf);
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Free reply array */
 | 
			
		||||
static int _cluster_free_request(lvm_response_t * response, int num)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num; i++) {
 | 
			
		||||
		dm_free(response[i].response);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_free(response);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int refresh_clvmd(int all_nodes)
 | 
			
		||||
{
 | 
			
		||||
	int num_responses;
 | 
			
		||||
	char args[1]; // No args really.
 | 
			
		||||
	lvm_response_t *response = NULL;
 | 
			
		||||
	int saved_errno;
 | 
			
		||||
	int status;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	status = _cluster_request(CLVMD_CMD_REFRESH, all_nodes ? NODE_ALL : NODE_LOCAL, args, 0, &response, &num_responses, 0);
 | 
			
		||||
 | 
			
		||||
	/* If any nodes were down then display them and return an error */
 | 
			
		||||
	for (i = 0; i < num_responses; i++) {
 | 
			
		||||
		if (response[i].status == EHOSTDOWN) {
 | 
			
		||||
			fprintf(stderr, "clvmd not running on node %s",
 | 
			
		||||
				  response[i].node);
 | 
			
		||||
			status = 0;
 | 
			
		||||
			errno = response[i].status;
 | 
			
		||||
		} else if (response[i].status) {
 | 
			
		||||
			fprintf(stderr, "Error resetting node %s: %s",
 | 
			
		||||
				  response[i].node,
 | 
			
		||||
				  response[i].response[0] ?
 | 
			
		||||
				  	response[i].response :
 | 
			
		||||
				  	strerror(response[i].status));
 | 
			
		||||
			status = 0;
 | 
			
		||||
			errno = response[i].status;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	saved_errno = errno;
 | 
			
		||||
	_cluster_free_request(response, num_responses);
 | 
			
		||||
	errno = saved_errno;
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int restart_clvmd(int all_nodes)
 | 
			
		||||
{
 | 
			
		||||
	int dummy, status;
 | 
			
		||||
 | 
			
		||||
	status = _cluster_request(CLVMD_CMD_RESTART, all_nodes ? NODE_ALL : NODE_LOCAL, NULL, 0, NULL, &dummy, 1);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * FIXME: we cannot receive response, clvmd re-exec before it.
 | 
			
		||||
	 *        but also should not close socket too early (the whole rq is dropped then).
 | 
			
		||||
	 * FIXME: This should be handled this way:
 | 
			
		||||
	 *  - client waits for RESTART ack (and socket close)
 | 
			
		||||
	 *  - server restarts
 | 
			
		||||
	 *  - client checks that server is ready again (VERSION command?)
 | 
			
		||||
	 */
 | 
			
		||||
	usleep(500000);
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int debug_clvmd(int level, int clusterwide)
 | 
			
		||||
{
 | 
			
		||||
	int num_responses;
 | 
			
		||||
	char args[1];
 | 
			
		||||
	const char *nodes;
 | 
			
		||||
	lvm_response_t *response = NULL;
 | 
			
		||||
	int saved_errno;
 | 
			
		||||
	int status;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	args[0] = level;
 | 
			
		||||
	if (clusterwide)
 | 
			
		||||
		nodes = NODE_ALL;
 | 
			
		||||
	else
 | 
			
		||||
		nodes = NODE_LOCAL;
 | 
			
		||||
 | 
			
		||||
	status = _cluster_request(CLVMD_CMD_SET_DEBUG, nodes, args, 1, &response, &num_responses, 0);
 | 
			
		||||
 | 
			
		||||
	/* If any nodes were down then display them and return an error */
 | 
			
		||||
	for (i = 0; i < num_responses; i++) {
 | 
			
		||||
		if (response[i].status == EHOSTDOWN) {
 | 
			
		||||
			fprintf(stderr, "clvmd not running on node %s",
 | 
			
		||||
				  response[i].node);
 | 
			
		||||
			status = 0;
 | 
			
		||||
			errno = response[i].status;
 | 
			
		||||
		} else if (response[i].status) {
 | 
			
		||||
			fprintf(stderr, "Error setting debug on node %s: %s",
 | 
			
		||||
				  response[i].node,
 | 
			
		||||
				  response[i].response[0] ?
 | 
			
		||||
				  	response[i].response :
 | 
			
		||||
				  	strerror(response[i].status));
 | 
			
		||||
			status = 0;
 | 
			
		||||
			errno = response[i].status;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	saved_errno = errno;
 | 
			
		||||
	_cluster_free_request(response, num_responses);
 | 
			
		||||
	errno = saved_errno;
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								daemons/clvmd/refresh_clvmd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								daemons/clvmd/refresh_clvmd.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int refresh_clvmd(int all_nodes);
 | 
			
		||||
int restart_clvmd(int all_nodes);
 | 
			
		||||
int debug_clvmd(int level, int clusterwide);
 | 
			
		||||
 | 
			
		||||
@@ -17,6 +17,8 @@ top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
CPG_LIBS = @CPG_LIBS@
 | 
			
		||||
CPG_CFLAGS = @CPG_CFLAGS@
 | 
			
		||||
SACKPT_LIBS = @SACKPT_LIBS@
 | 
			
		||||
SACKPT_CFLAGS = @SACKPT_CFLAGS@
 | 
			
		||||
 | 
			
		||||
SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c
 | 
			
		||||
 | 
			
		||||
@@ -24,15 +26,14 @@ TARGETS = cmirrord
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LMLIBS += $(CPG_LIBS)
 | 
			
		||||
CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
LIBS += -ldevmapper
 | 
			
		||||
LMLIBS += $(CPG_LIBS) $(SACKPT_LIBS)
 | 
			
		||||
CFLAGS += $(CPG_CFLAGS) $(SACKPT_CFLAGS) $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
 | 
			
		||||
 | 
			
		||||
cmirrord: $(OBJECTS)
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
 | 
			
		||||
		$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS)
 | 
			
		||||
cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
 | 
			
		||||
		$(LVMLIBS) $(LMLIBS) $(LIBS)
 | 
			
		||||
 | 
			
		||||
install: $(TARGETS)
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord
 | 
			
		||||
	$(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord
 | 
			
		||||
 
 | 
			
		||||
@@ -16,11 +16,7 @@
 | 
			
		||||
#include "functions.h"
 | 
			
		||||
#include "link_mon.h"
 | 
			
		||||
#include "local.h"
 | 
			
		||||
#include "lib/mm/xlate.h"
 | 
			
		||||
#include "base/memory/zalloc.h"
 | 
			
		||||
 | 
			
		||||
/* FIXME: remove this and the code */
 | 
			
		||||
#define CMIRROR_HAS_CHECKPOINT 0
 | 
			
		||||
#include "xlate.h"
 | 
			
		||||
 | 
			
		||||
#include <corosync/cpg.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
@@ -403,12 +399,13 @@ static struct checkpoint_data *prepare_checkpoint(struct clog_cpg *entry,
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	new = zalloc(sizeof(*new));
 | 
			
		||||
	new = malloc(sizeof(*new));
 | 
			
		||||
	if (!new) {
 | 
			
		||||
		LOG_ERROR("Unable to create checkpoint data for %u",
 | 
			
		||||
			  cp_requester);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	memset(new, 0, sizeof(*new));
 | 
			
		||||
	new->requester = cp_requester;
 | 
			
		||||
	strncpy(new->uuid, entry->name.value, entry->name.length);
 | 
			
		||||
 | 
			
		||||
@@ -643,12 +640,13 @@ static int export_checkpoint(struct checkpoint_data *cp)
 | 
			
		||||
	rq_size += RECOVERING_REGION_SECTION_SIZE;
 | 
			
		||||
	rq_size += cp->bitmap_size * 2; /* clean|sync_bits */
 | 
			
		||||
 | 
			
		||||
	rq = zalloc(rq_size);
 | 
			
		||||
	rq = malloc(rq_size);
 | 
			
		||||
	if (!rq) {
 | 
			
		||||
		LOG_ERROR("export_checkpoint: "
 | 
			
		||||
			  "Unable to allocate transfer structs");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	memset(rq, 0, rq_size);
 | 
			
		||||
 | 
			
		||||
	dm_list_init(&rq->u.list);
 | 
			
		||||
	rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY;
 | 
			
		||||
@@ -1620,11 +1618,12 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
 | 
			
		||||
			return -EEXIST;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	new = zalloc(sizeof(*new));
 | 
			
		||||
	new = malloc(sizeof(*new));
 | 
			
		||||
	if (!new) {
 | 
			
		||||
		LOG_ERROR("Unable to allocate memory for clog_cpg");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	memset(new, 0, sizeof(*new));
 | 
			
		||||
	dm_list_init(&new->list);
 | 
			
		||||
	new->lowest_id = 0xDEAD;
 | 
			
		||||
	dm_list_init(&new->startup_list);
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,8 @@
 | 
			
		||||
#ifndef _LVM_CLOG_CLUSTER_H
 | 
			
		||||
#define _LVM_CLOG_CLUSTER_H
 | 
			
		||||
 | 
			
		||||
#include "libdm/libdevmapper.h"
 | 
			
		||||
#include "libdm/misc/dm-log-userspace.h"
 | 
			
		||||
#include "dm-log-userspace.h"
 | 
			
		||||
#include "libdevmapper.h"
 | 
			
		||||
 | 
			
		||||
#define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */
 | 
			
		||||
#define DM_ULOG_CHECKPOINT_READY 21
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
#include "logging.h"
 | 
			
		||||
#include "cluster.h"
 | 
			
		||||
#include "compat.h"
 | 
			
		||||
#include "lib/mm/xlate.h"
 | 
			
		||||
#include "xlate.h"
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,6 @@
 | 
			
		||||
 */
 | 
			
		||||
#include "logging.h"
 | 
			
		||||
#include "functions.h"
 | 
			
		||||
#include "base/memory/zalloc.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/sysmacros.h>
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
@@ -436,7 +435,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
 | 
			
		||||
			block_on_error = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lc = zalloc(sizeof(*lc));
 | 
			
		||||
	lc = dm_zalloc(sizeof(*lc));
 | 
			
		||||
	if (!lc) {
 | 
			
		||||
		LOG_ERROR("Unable to allocate cluster log context");
 | 
			
		||||
		r = -ENOMEM;
 | 
			
		||||
@@ -533,9 +532,9 @@ fail:
 | 
			
		||||
			LOG_ERROR("Close device error, %s: %s",
 | 
			
		||||
				  disk_path, strerror(errno));
 | 
			
		||||
		free(lc->disk_buffer);
 | 
			
		||||
		free(lc->sync_bits);
 | 
			
		||||
		free(lc->clean_bits);
 | 
			
		||||
		free(lc);
 | 
			
		||||
		dm_free(lc->sync_bits);
 | 
			
		||||
		dm_free(lc->clean_bits);
 | 
			
		||||
		dm_free(lc);
 | 
			
		||||
	}
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
@@ -660,9 +659,9 @@ static int clog_dtr(struct dm_ulog_request *rq)
 | 
			
		||||
			  strerror(errno));
 | 
			
		||||
	if (lc->disk_buffer)
 | 
			
		||||
		free(lc->disk_buffer);
 | 
			
		||||
	free(lc->clean_bits);
 | 
			
		||||
	free(lc->sync_bits);
 | 
			
		||||
	free(lc);
 | 
			
		||||
	dm_free(lc->clean_bits);
 | 
			
		||||
	dm_free(lc->sync_bits);
 | 
			
		||||
	dm_free(lc);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,7 @@
 | 
			
		||||
#ifndef _LVM_CLOG_FUNCTIONS_H
 | 
			
		||||
#define _LVM_CLOG_FUNCTIONS_H
 | 
			
		||||
 | 
			
		||||
#include "libdm/libdevmapper.h"
 | 
			
		||||
#include "libdm/misc/dm-log-userspace.h"
 | 
			
		||||
#include "dm-log-userspace.h"
 | 
			
		||||
#include "cluster.h"
 | 
			
		||||
 | 
			
		||||
#define LOG_RESUMED   1
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,9 @@
 | 
			
		||||
#ifndef _LVM_CLOG_LOGGING_H
 | 
			
		||||
#define _LVM_CLOG_LOGGING_H
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
 | 
			
		||||
#include "configure.h"
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 
 | 
			
		||||
@@ -57,16 +57,14 @@ all: device-mapper
 | 
			
		||||
device-mapper: $(TARGETS)
 | 
			
		||||
 | 
			
		||||
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
LIBS += $(PTHREAD_LIBS) -L$(top_builddir)/libdm -ldevmapper
 | 
			
		||||
LIBS += -ldevmapper $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
dmeventd: $(LIB_SHARED) dmeventd.o
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
 | 
			
		||||
		-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) -lm
 | 
			
		||||
	$(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
 | 
			
		||||
		-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
 | 
			
		||||
 | 
			
		||||
dmeventd.static: $(LIB_STATIC) dmeventd.o
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
 | 
			
		||||
dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
 | 
			
		||||
		-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
 | 
			
		||||
 | 
			
		||||
ifeq ("@PKGCONFIG@", "yes")
 | 
			
		||||
@@ -75,6 +73,7 @@ endif
 | 
			
		||||
 | 
			
		||||
ifneq ("$(CFLOW_CMD)", "")
 | 
			
		||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
 | 
			
		||||
-include $(top_builddir)/libdm/libdevmapper.cflow
 | 
			
		||||
-include $(top_builddir)/lib/liblvm-internal.cflow
 | 
			
		||||
-include $(top_builddir)/lib/liblvm2cmd.cflow
 | 
			
		||||
-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
 | 
			
		||||
@@ -82,28 +81,23 @@ CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
install_include: $(srcdir)/libdevmapper-event.h
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F)
 | 
			
		||||
	$(INSTALL_DATA) -D $< $(includedir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_pkgconfig: libdevmapper-event.pc
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
 | 
			
		||||
	$(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
 | 
			
		||||
 | 
			
		||||
install_lib_dynamic: install_lib_shared
 | 
			
		||||
 | 
			
		||||
install_lib_static: $(LIB_STATIC)
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
 | 
			
		||||
	$(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_lib: $(INSTALL_LIB_TARGETS)
 | 
			
		||||
 | 
			
		||||
install_dmeventd_dynamic: dmeventd
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
	$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_dmeventd_static: dmeventd.static
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
 | 
			
		||||
	$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,12 +16,12 @@
 | 
			
		||||
 * dmeventd - dm event daemon to monitor active mapped devices
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dm-logging.h"
 | 
			
		||||
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
#include "dmeventd.h"
 | 
			
		||||
 | 
			
		||||
#include "libdm/misc/dm-logging.h"
 | 
			
		||||
#include "base/memory/zalloc.h"
 | 
			
		||||
#include "tool.h"
 | 
			
		||||
 | 
			
		||||
#include <dlfcn.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
@@ -33,8 +33,6 @@
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <arpa/inet.h>		/* for htonl, ntohl */
 | 
			
		||||
#include <fcntl.h>		/* for musl libc */
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
/*
 | 
			
		||||
@@ -62,6 +60,8 @@
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
#define DM_SIGNALED_EXIT  1
 | 
			
		||||
#define DM_SCHEDULED_EXIT 2
 | 
			
		||||
static volatile sig_atomic_t _exit_now = 0;	/* set to '1' when signal is given to exit */
 | 
			
		||||
@@ -264,19 +264,19 @@ static pthread_cond_t _timeout_cond = PTHREAD_COND_INITIALIZER;
 | 
			
		||||
/* DSO data allocate/free. */
 | 
			
		||||
static void _free_dso_data(struct dso_data *data)
 | 
			
		||||
{
 | 
			
		||||
	free(data->dso_name);
 | 
			
		||||
	free(data);
 | 
			
		||||
	dm_free(data->dso_name);
 | 
			
		||||
	dm_free(data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dso_data *_alloc_dso_data(struct message_data *data)
 | 
			
		||||
{
 | 
			
		||||
	struct dso_data *ret = (typeof(ret)) zalloc(sizeof(*ret));
 | 
			
		||||
	struct dso_data *ret = (typeof(ret)) dm_zalloc(sizeof(*ret));
 | 
			
		||||
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		return_NULL;
 | 
			
		||||
 | 
			
		||||
	if (!(ret->dso_name = strdup(data->dso_name))) {
 | 
			
		||||
		free(ret);
 | 
			
		||||
	if (!(ret->dso_name = dm_strdup(data->dso_name))) {
 | 
			
		||||
		dm_free(ret);
 | 
			
		||||
		return_NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -397,9 +397,9 @@ static void _free_thread_status(struct thread_status *thread)
 | 
			
		||||
	_lib_put(thread->dso_data);
 | 
			
		||||
	if (thread->wait_task)
 | 
			
		||||
		dm_task_destroy(thread->wait_task);
 | 
			
		||||
	free(thread->device.uuid);
 | 
			
		||||
	free(thread->device.name);
 | 
			
		||||
	free(thread);
 | 
			
		||||
	dm_free(thread->device.uuid);
 | 
			
		||||
	dm_free(thread->device.name);
 | 
			
		||||
	dm_free(thread);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Note: events_field must not be 0, ensured by caller */
 | 
			
		||||
@@ -408,7 +408,7 @@ static struct thread_status *_alloc_thread_status(const struct message_data *dat
 | 
			
		||||
{
 | 
			
		||||
	struct thread_status *thread;
 | 
			
		||||
 | 
			
		||||
	if (!(thread = zalloc(sizeof(*thread)))) {
 | 
			
		||||
	if (!(thread = dm_zalloc(sizeof(*thread)))) {
 | 
			
		||||
		log_error("Cannot create new thread, out of memory.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
@@ -422,11 +422,11 @@ static struct thread_status *_alloc_thread_status(const struct message_data *dat
 | 
			
		||||
	if (!dm_task_set_uuid(thread->wait_task, data->device_uuid))
 | 
			
		||||
		goto_out;
 | 
			
		||||
 | 
			
		||||
	if (!(thread->device.uuid = strdup(data->device_uuid)))
 | 
			
		||||
	if (!(thread->device.uuid = dm_strdup(data->device_uuid)))
 | 
			
		||||
		goto_out;
 | 
			
		||||
 | 
			
		||||
	/* Until real name resolved, use UUID */
 | 
			
		||||
	if (!(thread->device.name = strdup(data->device_uuid)))
 | 
			
		||||
	if (!(thread->device.name = dm_strdup(data->device_uuid)))
 | 
			
		||||
		goto_out;
 | 
			
		||||
 | 
			
		||||
	/* runs ioctl and may register lvm2 pluging */
 | 
			
		||||
@@ -515,7 +515,7 @@ static int _fetch_string(char **ptr, char **src, const int delimiter)
 | 
			
		||||
	if ((p = strchr(*src, delimiter))) {
 | 
			
		||||
		if (*src < p) {
 | 
			
		||||
			*p = 0; /* Temporary exit with \0 */
 | 
			
		||||
			if (!(*ptr = strdup(*src))) {
 | 
			
		||||
			if (!(*ptr = dm_strdup(*src))) {
 | 
			
		||||
				log_error("Failed to fetch item %s.", *src);
 | 
			
		||||
				ret = 0; /* Allocation fail */
 | 
			
		||||
			}
 | 
			
		||||
@@ -525,7 +525,7 @@ static int _fetch_string(char **ptr, char **src, const int delimiter)
 | 
			
		||||
		(*src)++; /* Skip delmiter, next field */
 | 
			
		||||
	} else if ((len = strlen(*src))) {
 | 
			
		||||
		/* No delimiter, item ends with '\0' */
 | 
			
		||||
		if (!(*ptr = strdup(*src))) {
 | 
			
		||||
		if (!(*ptr = dm_strdup(*src))) {
 | 
			
		||||
			log_error("Failed to fetch last item %s.", *src);
 | 
			
		||||
			ret = 0; /* Fail */
 | 
			
		||||
		}
 | 
			
		||||
@@ -538,11 +538,11 @@ out:
 | 
			
		||||
/* Free message memory. */
 | 
			
		||||
static void _free_message(struct message_data *message_data)
 | 
			
		||||
{
 | 
			
		||||
	free(message_data->id);
 | 
			
		||||
	free(message_data->dso_name);
 | 
			
		||||
	free(message_data->device_uuid);
 | 
			
		||||
	free(message_data->events_str);
 | 
			
		||||
	free(message_data->timeout_str);
 | 
			
		||||
	dm_free(message_data->id);
 | 
			
		||||
	dm_free(message_data->dso_name);
 | 
			
		||||
	dm_free(message_data->device_uuid);
 | 
			
		||||
	dm_free(message_data->events_str);
 | 
			
		||||
	dm_free(message_data->timeout_str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Parse a register message from the client. */
 | 
			
		||||
@@ -574,7 +574,7 @@ static int _parse_message(struct message_data *message_data)
 | 
			
		||||
		ret = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	free(msg->data);
 | 
			
		||||
	dm_free(msg->data);
 | 
			
		||||
	msg->data = NULL;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
@@ -608,8 +608,8 @@ static int _fill_device_data(struct thread_status *ts)
 | 
			
		||||
	if (!dm_task_run(dmt))
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
	free(ts->device.name);
 | 
			
		||||
	if (!(ts->device.name = strdup(dm_task_get_name(dmt))))
 | 
			
		||||
	dm_free(ts->device.name);
 | 
			
		||||
	if (!(ts->device.name = dm_strdup(dm_task_get_name(dmt))))
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_get_info(dmt, &dmi))
 | 
			
		||||
@@ -696,8 +696,8 @@ static int _get_status(struct message_data *message_data)
 | 
			
		||||
 | 
			
		||||
	len = strlen(message_data->id);
 | 
			
		||||
	msg->size = size + len + 1;
 | 
			
		||||
	free(msg->data);
 | 
			
		||||
	if (!(msg->data = malloc(msg->size)))
 | 
			
		||||
	dm_free(msg->data);
 | 
			
		||||
	if (!(msg->data = dm_malloc(msg->size)))
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	memcpy(msg->data, message_data->id, len);
 | 
			
		||||
@@ -712,7 +712,7 @@ static int _get_status(struct message_data *message_data)
 | 
			
		||||
	ret = 0;
 | 
			
		||||
 out:
 | 
			
		||||
	for (j = 0; j < i; ++j)
 | 
			
		||||
		free(buffers[j]);
 | 
			
		||||
		dm_free(buffers[j]);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
@@ -721,7 +721,7 @@ static int _get_parameters(struct message_data *message_data) {
 | 
			
		||||
	struct dm_event_daemon_message *msg = message_data->msg;
 | 
			
		||||
	int size;
 | 
			
		||||
 | 
			
		||||
	free(msg->data);
 | 
			
		||||
	dm_free(msg->data);
 | 
			
		||||
	if ((size = dm_asprintf(&msg->data, "%s pid=%d daemon=%s exec_method=%s",
 | 
			
		||||
				message_data->id, getpid(),
 | 
			
		||||
				_foreground ? "no" : "yes",
 | 
			
		||||
@@ -752,7 +752,7 @@ static void _exit_timeout(void *unused __attribute__((unused)))
 | 
			
		||||
static void *_timeout_thread(void *unused __attribute__((unused)))
 | 
			
		||||
{
 | 
			
		||||
	struct thread_status *thread;
 | 
			
		||||
	struct timespec timeout, real_time;
 | 
			
		||||
	struct timespec timeout;
 | 
			
		||||
	time_t curr_time;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
@@ -763,16 +763,7 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
 | 
			
		||||
	while (!dm_list_empty(&_timeout_registry)) {
 | 
			
		||||
		timeout.tv_sec = 0;
 | 
			
		||||
		timeout.tv_nsec = 0;
 | 
			
		||||
#ifndef HAVE_REALTIME
 | 
			
		||||
		curr_time = time(NULL);
 | 
			
		||||
#else
 | 
			
		||||
		if (clock_gettime(CLOCK_REALTIME, &real_time)) {
 | 
			
		||||
			log_error("Failed to read clock_gettime().");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		/* 10ms back to the future */
 | 
			
		||||
		curr_time = real_time.tv_sec + ((real_time.tv_nsec > (1000000000 - 10000000)) ? 1 : 0);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		dm_list_iterate_items_gen(thread, &_timeout_registry, timeout_list) {
 | 
			
		||||
			if (thread->next_time <= curr_time) {
 | 
			
		||||
@@ -1234,7 +1225,7 @@ static int _registered_device(struct message_data *message_data,
 | 
			
		||||
	int r;
 | 
			
		||||
	struct dm_event_daemon_message *msg = message_data->msg;
 | 
			
		||||
 | 
			
		||||
	free(msg->data);
 | 
			
		||||
	dm_free(msg->data);
 | 
			
		||||
 | 
			
		||||
	if ((r = dm_asprintf(&(msg->data), "%s %s %s %u",
 | 
			
		||||
			     message_data->id,
 | 
			
		||||
@@ -1374,7 +1365,7 @@ static int _get_timeout(struct message_data *message_data)
 | 
			
		||||
	if (!thread)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	free(msg->data);
 | 
			
		||||
	dm_free(msg->data);
 | 
			
		||||
	msg->size = dm_asprintf(&(msg->data), "%s %" PRIu32,
 | 
			
		||||
				message_data->id, thread->timeout);
 | 
			
		||||
 | 
			
		||||
@@ -1494,34 +1485,37 @@ static int _client_read(struct dm_event_fifos *fifos,
 | 
			
		||||
		t.tv_usec = 0;
 | 
			
		||||
		ret = select(fifos->client + 1, &fds, NULL, NULL, &t);
 | 
			
		||||
 | 
			
		||||
		if (!ret && bytes)
 | 
			
		||||
			continue; /* trying to finish read */
 | 
			
		||||
		if (!ret && !bytes)	/* nothing to read */
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		if (ret <= 0)	/* nothing to read */
 | 
			
		||||
			goto bad;
 | 
			
		||||
		if (!ret)	/* trying to finish read */
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (ret < 0)	/* error */
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		ret = read(fifos->client, buf + bytes, size - bytes);
 | 
			
		||||
		bytes += ret > 0 ? ret : 0;
 | 
			
		||||
		if (!msg->data && (bytes == 2 * sizeof(uint32_t))) {
 | 
			
		||||
		if (header && (bytes == 2 * sizeof(uint32_t))) {
 | 
			
		||||
			msg->cmd = ntohl(header[0]);
 | 
			
		||||
			size = msg->size = ntohl(header[1]);
 | 
			
		||||
			bytes = 0;
 | 
			
		||||
 | 
			
		||||
			if (!(size = msg->size = ntohl(header[1])))
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			if (!(buf = msg->data = malloc(msg->size)))
 | 
			
		||||
				goto bad;
 | 
			
		||||
			if (!size)
 | 
			
		||||
				break; /* No data -> error */
 | 
			
		||||
			buf = msg->data = dm_malloc(msg->size);
 | 
			
		||||
			if (!buf)
 | 
			
		||||
				break; /* No mem -> error */
 | 
			
		||||
			header = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bytes == size)
 | 
			
		||||
		return 1;
 | 
			
		||||
	if (bytes != size) {
 | 
			
		||||
		dm_free(msg->data);
 | 
			
		||||
		msg->data = NULL;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
bad:
 | 
			
		||||
	free(msg->data);
 | 
			
		||||
	msg->data = NULL;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -1536,7 +1530,7 @@ static int _client_write(struct dm_event_fifos *fifos,
 | 
			
		||||
	fd_set fds;
 | 
			
		||||
 | 
			
		||||
	size_t size = 2 * sizeof(uint32_t) + ((msg->data) ? msg->size : 0);
 | 
			
		||||
	uint32_t *header = malloc(size);
 | 
			
		||||
	uint32_t *header = dm_malloc(size);
 | 
			
		||||
	char *buf = (char *)header;
 | 
			
		||||
 | 
			
		||||
	if (!header) {
 | 
			
		||||
@@ -1566,7 +1560,7 @@ static int _client_write(struct dm_event_fifos *fifos,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (header != temp)
 | 
			
		||||
		free(header);
 | 
			
		||||
		dm_free(header);
 | 
			
		||||
 | 
			
		||||
	return (bytes == size);
 | 
			
		||||
}
 | 
			
		||||
@@ -1628,7 +1622,7 @@ static int _do_process_request(struct dm_event_daemon_message *msg)
 | 
			
		||||
			msg->size = dm_asprintf(&(msg->data), "%s %s %d", answer,
 | 
			
		||||
						(msg->cmd == DM_EVENT_CMD_DIE) ? "DYING" : "HELLO",
 | 
			
		||||
						DM_EVENT_PROTOCOL_VERSION);
 | 
			
		||||
			free(answer);
 | 
			
		||||
			dm_free(answer);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
 | 
			
		||||
		stack;
 | 
			
		||||
@@ -1670,7 +1664,7 @@ static void _process_request(struct dm_event_fifos *fifos)
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("<<< CMD:%s (0x%x) completed (result %d).", decode_cmd(cmd), cmd, msg.cmd);
 | 
			
		||||
 | 
			
		||||
	free(msg.data);
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
 | 
			
		||||
	if (cmd == DM_EVENT_CMD_DIE) {
 | 
			
		||||
		if (unlink(DMEVENTD_PIDFILE))
 | 
			
		||||
@@ -1751,8 +1745,7 @@ static void _init_thread_signals(void)
 | 
			
		||||
	sigdelset(&my_sigset, SIGHUP);
 | 
			
		||||
	sigdelset(&my_sigset, SIGQUIT);
 | 
			
		||||
 | 
			
		||||
	if (pthread_sigmask(SIG_BLOCK, &my_sigset, NULL))
 | 
			
		||||
		log_sys_error("pthread_sigmask", "SIG_BLOCK");
 | 
			
		||||
	pthread_sigmask(SIG_BLOCK, &my_sigset, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -1982,7 +1975,7 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
 | 
			
		||||
	int i, ret;
 | 
			
		||||
 | 
			
		||||
	ret = daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
 | 
			
		||||
	free(msg.data);
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
	msg.data = NULL;
 | 
			
		||||
 | 
			
		||||
	if (ret) {
 | 
			
		||||
@@ -2028,8 +2021,8 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
 | 
			
		||||
static void _restart_dmeventd(void)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_event_fifos fifos = {
 | 
			
		||||
		.client = -1,
 | 
			
		||||
		.server = -1,
 | 
			
		||||
		.client = -1,
 | 
			
		||||
		/* FIXME Make these either configurable or depend directly on dmeventd_path */
 | 
			
		||||
		.client_path = DM_EVENT_FIFO_CLIENT,
 | 
			
		||||
		.server_path = DM_EVENT_FIFO_SERVER
 | 
			
		||||
@@ -2068,13 +2061,13 @@ static void _restart_dmeventd(void)
 | 
			
		||||
			++count;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	if (!(_initial_registrations = malloc(sizeof(char*) * (count + 1)))) {
 | 
			
		||||
	if (!(_initial_registrations = dm_malloc(sizeof(char*) * (count + 1)))) {
 | 
			
		||||
		fprintf(stderr, "Memory allocation registration failed.\n");
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < count; ++i) {
 | 
			
		||||
		if (!(_initial_registrations[i] = strdup(message))) {
 | 
			
		||||
		if (!(_initial_registrations[i] = dm_strdup(message))) {
 | 
			
		||||
			fprintf(stderr, "Memory allocation for message failed.\n");
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
@@ -2243,8 +2236,7 @@ int main(int argc, char *argv[])
 | 
			
		||||
 | 
			
		||||
	_init_thread_signals();
 | 
			
		||||
 | 
			
		||||
	if (pthread_mutex_init(&_global_mutex, NULL))
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	pthread_mutex_init(&_global_mutex, NULL);
 | 
			
		||||
 | 
			
		||||
	if (!_systemd_activation && !_open_fifos(&fifos))
 | 
			
		||||
		exit(EXIT_FIFO_FAILURE);
 | 
			
		||||
 
 | 
			
		||||
@@ -12,12 +12,10 @@
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dm-logging.h"
 | 
			
		||||
#include "dmlib.h"
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
#include "dmeventd.h"
 | 
			
		||||
#include "libdm/misc/dm-logging.h"
 | 
			
		||||
#include "base/memory/zalloc.h"
 | 
			
		||||
 | 
			
		||||
#include "lib/misc/intl.h"
 | 
			
		||||
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <sys/file.h>
 | 
			
		||||
@@ -27,7 +25,6 @@
 | 
			
		||||
#include <arpa/inet.h>		/* for htonl, ntohl */
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
static int _debug_level = 0;
 | 
			
		||||
static int _use_syslog = 0;
 | 
			
		||||
@@ -50,8 +47,8 @@ struct dm_event_handler {
 | 
			
		||||
 | 
			
		||||
static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	free(dmevh->dev_name);
 | 
			
		||||
	free(dmevh->uuid);
 | 
			
		||||
	dm_free(dmevh->dev_name);
 | 
			
		||||
	dm_free(dmevh->uuid);
 | 
			
		||||
	dmevh->dev_name = dmevh->uuid = NULL;
 | 
			
		||||
	dmevh->major = dmevh->minor = 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -60,7 +57,7 @@ struct dm_event_handler *dm_event_handler_create(void)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_event_handler *dmevh;
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh = zalloc(sizeof(*dmevh)))) {
 | 
			
		||||
	if (!(dmevh = dm_zalloc(sizeof(*dmevh)))) {
 | 
			
		||||
		log_error("Failed to allocate event handler.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
@@ -71,9 +68,9 @@ struct dm_event_handler *dm_event_handler_create(void)
 | 
			
		||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh)
 | 
			
		||||
{
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
	free(dmevh->dso);
 | 
			
		||||
	free(dmevh->dmeventd_path);
 | 
			
		||||
	free(dmevh);
 | 
			
		||||
	dm_free(dmevh->dso);
 | 
			
		||||
	dm_free(dmevh->dmeventd_path);
 | 
			
		||||
	dm_free(dmevh);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path)
 | 
			
		||||
@@ -81,9 +78,9 @@ int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const cha
 | 
			
		||||
	if (!dmeventd_path) /* noop */
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	free(dmevh->dmeventd_path);
 | 
			
		||||
	dm_free(dmevh->dmeventd_path);
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->dmeventd_path = strdup(dmeventd_path)))
 | 
			
		||||
	if (!(dmevh->dmeventd_path = dm_strdup(dmeventd_path)))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
@@ -94,9 +91,9 @@ int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path)
 | 
			
		||||
	if (!path) /* noop */
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	free(dmevh->dso);
 | 
			
		||||
	dm_free(dmevh->dso);
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->dso = strdup(path)))
 | 
			
		||||
	if (!(dmevh->dso = dm_strdup(path)))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
@@ -109,7 +106,7 @@ int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *de
 | 
			
		||||
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->dev_name = strdup(dev_name)))
 | 
			
		||||
	if (!(dmevh->dev_name = dm_strdup(dev_name)))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
@@ -122,7 +119,7 @@ int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid)
 | 
			
		||||
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->uuid = strdup(uuid)))
 | 
			
		||||
	if (!(dmevh->uuid = dm_strdup(uuid)))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
@@ -237,16 +234,16 @@ static int _daemon_read(struct dm_event_fifos *fifos,
 | 
			
		||||
			ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
 | 
			
		||||
			if (ret < 0 && errno != EINTR) {
 | 
			
		||||
				log_error("Unable to read from event server.");
 | 
			
		||||
				goto bad;
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			if ((ret == 0) && (i > 4) && !bytes) {
 | 
			
		||||
				log_error("No input from event server.");
 | 
			
		||||
				goto bad;
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (ret < 1) {
 | 
			
		||||
			log_error("Unable to read from event server.");
 | 
			
		||||
			goto bad;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ret = read(fifos->server, buf + bytes, size);
 | 
			
		||||
@@ -255,32 +252,25 @@ static int _daemon_read(struct dm_event_fifos *fifos,
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			log_error("Unable to read from event server.");
 | 
			
		||||
			goto bad;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bytes += ret;
 | 
			
		||||
		if (!msg->data && (bytes == 2 * sizeof(uint32_t))) {
 | 
			
		||||
		if (header && (bytes == 2 * sizeof(uint32_t))) {
 | 
			
		||||
			msg->cmd = ntohl(header[0]);
 | 
			
		||||
			msg->size = ntohl(header[1]);
 | 
			
		||||
			buf = msg->data = dm_malloc(msg->size);
 | 
			
		||||
			size = msg->size;
 | 
			
		||||
			bytes = 0;
 | 
			
		||||
 | 
			
		||||
			if (!(size = msg->size = ntohl(header[1])))
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			if (!(buf = msg->data = malloc(msg->size))) {
 | 
			
		||||
				log_error("Unable to allocate message data.");
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			header = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bytes == size)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
bad:
 | 
			
		||||
	free(msg->data);
 | 
			
		||||
	msg->data = NULL;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	if (bytes != size) {
 | 
			
		||||
		dm_free(msg->data);
 | 
			
		||||
		msg->data = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	return bytes == size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Write message to daemon. */
 | 
			
		||||
@@ -380,13 +370,13 @@ int daemon_talk(struct dm_event_fifos *fifos,
 | 
			
		||||
	 */
 | 
			
		||||
	if (!_daemon_write(fifos, msg)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		free(msg->data);
 | 
			
		||||
		dm_free(msg->data);
 | 
			
		||||
		msg->data = NULL;
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		free(msg->data);
 | 
			
		||||
		dm_free(msg->data);
 | 
			
		||||
		msg->data = NULL;
 | 
			
		||||
 | 
			
		||||
		if (!_daemon_read(fifos, msg)) {
 | 
			
		||||
@@ -615,8 +605,8 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct dm_event_fifos fifos = {
 | 
			
		||||
		.client = -1,
 | 
			
		||||
		.server = -1,
 | 
			
		||||
		.client = -1,
 | 
			
		||||
		/* FIXME Make these either configurable or depend directly on dmeventd_path */
 | 
			
		||||
		.client_path = DM_EVENT_FIFO_CLIENT,
 | 
			
		||||
		.server_path = DM_EVENT_FIFO_SERVER
 | 
			
		||||
@@ -629,7 +619,7 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
 | 
			
		||||
 | 
			
		||||
	ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
 | 
			
		||||
 | 
			
		||||
	free(msg->data);
 | 
			
		||||
	dm_free(msg->data);
 | 
			
		||||
	msg->data = 0;
 | 
			
		||||
 | 
			
		||||
	if (!ret)
 | 
			
		||||
@@ -670,7 +660,7 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
 | 
			
		||||
		ret = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	free(msg.data);
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
 | 
			
		||||
@@ -697,7 +687,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
 | 
			
		||||
		ret = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	free(msg.data);
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
 | 
			
		||||
@@ -713,7 +703,7 @@ static char *_fetch_string(char **src, const int delimiter)
 | 
			
		||||
	if ((p = strchr(*src, delimiter)))
 | 
			
		||||
		*p = 0;
 | 
			
		||||
 | 
			
		||||
	if ((ret = strdup(*src)))
 | 
			
		||||
	if ((ret = dm_strdup(*src)))
 | 
			
		||||
		*src += strlen(ret) + 1;
 | 
			
		||||
 | 
			
		||||
	if (p)
 | 
			
		||||
@@ -733,11 +723,11 @@ static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
 | 
			
		||||
	    (*dso_name = _fetch_string(&p, ' ')) &&
 | 
			
		||||
	    (*uuid = _fetch_string(&p, ' '))) {
 | 
			
		||||
		*evmask = atoi(p);
 | 
			
		||||
		free(id);
 | 
			
		||||
		dm_free(id);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	free(id);
 | 
			
		||||
	dm_free(id);
 | 
			
		||||
	return -ENOMEM;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -779,7 +769,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 | 
			
		||||
	dm_task_destroy(dmt);
 | 
			
		||||
	dmt = NULL;
 | 
			
		||||
 | 
			
		||||
	free(msg.data);
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
	msg.data = NULL;
 | 
			
		||||
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
@@ -788,7 +778,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->uuid = strdup(reply_uuid))) {
 | 
			
		||||
	if (!(dmevh->uuid = dm_strdup(reply_uuid))) {
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
@@ -801,13 +791,13 @@ 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, reply_mask);
 | 
			
		||||
 | 
			
		||||
	free(reply_dso);
 | 
			
		||||
	dm_free(reply_dso);
 | 
			
		||||
	reply_dso = NULL;
 | 
			
		||||
 | 
			
		||||
	free(reply_uuid);
 | 
			
		||||
	dm_free(reply_uuid);
 | 
			
		||||
	reply_uuid = NULL;
 | 
			
		||||
 | 
			
		||||
	if (!(dmevh->dev_name = strdup(dm_task_get_name(dmt)))) {
 | 
			
		||||
	if (!(dmevh->dev_name = dm_strdup(dm_task_get_name(dmt)))) {
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
@@ -825,9 +815,9 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 | 
			
		||||
	return ret;
 | 
			
		||||
 | 
			
		||||
 fail:
 | 
			
		||||
	free(msg.data);
 | 
			
		||||
	free(reply_dso);
 | 
			
		||||
	free(reply_uuid);
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
	dm_free(reply_dso);
 | 
			
		||||
	dm_free(reply_uuid);
 | 
			
		||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
			
		||||
	if (dmt)
 | 
			
		||||
		dm_task_destroy(dmt);
 | 
			
		||||
@@ -992,12 +982,12 @@ int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
 | 
			
		||||
		if (!p) {
 | 
			
		||||
			log_error("Malformed reply from dmeventd '%s'.",
 | 
			
		||||
				  msg.data);
 | 
			
		||||
			free(msg.data);
 | 
			
		||||
			dm_free(msg.data);
 | 
			
		||||
			return -EIO;
 | 
			
		||||
		}
 | 
			
		||||
		*timeout = atoi(p);
 | 
			
		||||
	}
 | 
			
		||||
	free(msg.data);
 | 
			
		||||
	dm_free(msg.data);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,6 @@
 | 
			
		||||
#ifndef LIB_DMEVENT_H
 | 
			
		||||
#define LIB_DMEVENT_H
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -8,3 +8,4 @@ Description: device-mapper event library
 | 
			
		||||
Version: @DM_LIB_PATCHLEVEL@
 | 
			
		||||
Cflags: -I${includedir}
 | 
			
		||||
Libs: -L${libdir} -ldevmapper-event
 | 
			
		||||
Requires.private: devmapper
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,6 @@ top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
CLDFLAGS += -L$(top_builddir)/tools
 | 
			
		||||
LIBS += $(DMEVENT_LIBS) $(PTHREAD_LIBS) @LVM2CMD_LIB@
 | 
			
		||||
 | 
			
		||||
SOURCES = dmeventd_lvm.c
 | 
			
		||||
 | 
			
		||||
@@ -25,6 +24,8 @@ LIB_VERSION = $(LIB_VERSION_LVM)
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_lib_shared
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
 
 | 
			
		||||
@@ -12,10 +12,10 @@
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib/misc/lib.h"
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
			
		||||
#include "tools/lvm2cmd.h"
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
#include "lvm2cmd.h"
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
@@ -71,7 +71,7 @@ int dmeventd_lvm2_init(void)
 | 
			
		||||
	if (!_lvm_handle) {
 | 
			
		||||
		lvm2_log_fn(_lvm2_print_log);
 | 
			
		||||
 | 
			
		||||
		if (!(_lvm_handle = lvm2_init_threaded()))
 | 
			
		||||
		if (!(_lvm_handle = lvm2_init()))
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,8 @@ srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2
 | 
			
		||||
 | 
			
		||||
SOURCES = dmeventd_mirror.c
 | 
			
		||||
 | 
			
		||||
@@ -30,6 +30,8 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_dm_plugin
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
 
 | 
			
		||||
@@ -12,10 +12,10 @@
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib/misc/lib.h"
 | 
			
		||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
 | 
			
		||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
			
		||||
#include "lib/activate/activate.h"
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "activate.h"	/* For TARGET_NAME* */
 | 
			
		||||
 | 
			
		||||
/* FIXME Reformat to 80 char lines. */
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,8 @@ srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2
 | 
			
		||||
 | 
			
		||||
SOURCES = dmeventd_raid.c
 | 
			
		||||
 | 
			
		||||
@@ -29,6 +29,8 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_dm_plugin
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
 
 | 
			
		||||
@@ -12,10 +12,10 @@
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib/misc/lib.h"
 | 
			
		||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
 | 
			
		||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
			
		||||
#include "lib/config/defaults.h"
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "defaults.h"
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
 | 
			
		||||
/* Hold enough elements for the mximum number of RAID images */
 | 
			
		||||
#define	RAID_DEVS_ELEMS	((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
 | 
			
		||||
@@ -76,17 +76,14 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dead) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Use the first event to run a repair ignoring any additonal ones.
 | 
			
		||||
		 *
 | 
			
		||||
		 * We presume lvconvert to do pre-repair
 | 
			
		||||
		 * checks to avoid bloat in this plugin.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!state->warned && status->insync_regions < status->total_regions) {
 | 
			
		||||
			state->warned = 1;
 | 
			
		||||
			log_warn("WARNING: waiting for resynchronization to finish "
 | 
			
		||||
				 "before initiating repair on RAID device %s.", device);
 | 
			
		||||
			/* Fall through to allow lvconvert to run. */
 | 
			
		||||
		if (status->insync_regions < status->total_regions) {
 | 
			
		||||
			if (!state->warned) {
 | 
			
		||||
				state->warned = 1;
 | 
			
		||||
				log_warn("WARNING: waiting for resynchronization to finish "
 | 
			
		||||
					 "before initiating repair on RAID device %s.", device);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			goto out; /* Not yet done syncing with accessible devices */
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (state->failed)
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,8 @@ srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2
 | 
			
		||||
 | 
			
		||||
SOURCES = dmeventd_snapshot.c
 | 
			
		||||
 | 
			
		||||
@@ -26,6 +26,8 @@ LIB_VERSION = $(LIB_VERSION_LVM)
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_dm_plugin
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
 
 | 
			
		||||
@@ -12,9 +12,9 @@
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib/misc/lib.h"
 | 
			
		||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
 | 
			
		||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/sysmacros.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
@@ -175,7 +175,6 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
	const char *device = dm_task_get_name(dmt);
 | 
			
		||||
	int percent;
 | 
			
		||||
	struct dm_info info;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/* No longer monitoring, waiting for remove */
 | 
			
		||||
	if (!state->percent_check)
 | 
			
		||||
@@ -206,8 +205,7 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
		/* Maybe configurable ? */
 | 
			
		||||
		_remove(dm_task_get_uuid(dmt));
 | 
			
		||||
#endif
 | 
			
		||||
		if ((ret = pthread_kill(pthread_self(), SIGALRM)) && (ret != ESRCH))
 | 
			
		||||
			log_sys_error("pthread_kill", "self");
 | 
			
		||||
		pthread_kill(pthread_self(), SIGALRM);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -215,8 +213,7 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
		/* TODO eventually recognize earlier when room is enough */
 | 
			
		||||
		log_info("Dropping monitoring of fully provisioned snapshot %s.",
 | 
			
		||||
			 device);
 | 
			
		||||
		if ((ret = pthread_kill(pthread_self(), SIGALRM)) && (ret != ESRCH))
 | 
			
		||||
			log_sys_error("pthread_kill", "self");
 | 
			
		||||
		pthread_kill(pthread_self(), SIGALRM);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,8 @@ srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2
 | 
			
		||||
 | 
			
		||||
SOURCES = dmeventd_thin.c
 | 
			
		||||
 | 
			
		||||
@@ -29,6 +29,8 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_dm_plugin
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
 
 | 
			
		||||
@@ -12,16 +12,16 @@
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib/misc/lib.h"
 | 
			
		||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
 | 
			
		||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
			
		||||
#include "lib.h"	/* using here lvm log */
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
/* TODO - move this mountinfo code into library to be reusable */
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
#  include "libdm/misc/kdev_t.h"
 | 
			
		||||
#  include "kdev_t.h"
 | 
			
		||||
#else
 | 
			
		||||
#  define MAJOR(x) major((x))
 | 
			
		||||
#  define MINOR(x) minor((x))
 | 
			
		||||
@@ -286,7 +286,7 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
		if (state->fails++ <= state->max_fails) {
 | 
			
		||||
			log_debug("Postponing frequently failing policy (%u <= %u).",
 | 
			
		||||
				  state->fails - 1, state->max_fails);
 | 
			
		||||
			goto out;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (state->max_fails < MAX_FAILS)
 | 
			
		||||
			state->max_fails <<= 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,8 @@ srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2
 | 
			
		||||
 | 
			
		||||
SOURCES = dmeventd_vdo.c
 | 
			
		||||
 | 
			
		||||
@@ -29,6 +29,8 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_dm_plugin
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
 
 | 
			
		||||
@@ -12,17 +12,9 @@
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "lib/misc/lib.h"
 | 
			
		||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
 | 
			
		||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Use parser from new device_mapper library.
 | 
			
		||||
 * Although during compilation we can see dm_vdo_status_parse()
 | 
			
		||||
 * in runtime we are linked agains systems libdm 'older' library
 | 
			
		||||
 * which does not provide this symbol and plugin fails to load
 | 
			
		||||
 */
 | 
			
		||||
#include "device_mapper/vdo/status.c"
 | 
			
		||||
#include "lib.h"
 | 
			
		||||
#include "dmeventd_lvm.h"
 | 
			
		||||
#include "libdevmapper-event.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
@@ -53,6 +45,23 @@ struct dso_state {
 | 
			
		||||
	const char *name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct vdo_status {
 | 
			
		||||
	uint64_t used_blocks;
 | 
			
		||||
	uint64_t total_blocks;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int _vdo_status_parse(const char *params, struct vdo_status *status)
 | 
			
		||||
{
 | 
			
		||||
	if (sscanf(params, "%*s %*s %*s %*s %*s %" PRIu64 " %" PRIu64,
 | 
			
		||||
		   &status->used_blocks,
 | 
			
		||||
		   &status->total_blocks) < 2) {
 | 
			
		||||
		log_error("Failed to parse vdo params: %s.", params);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DM_EVENT_LOG_FN("vdo")
 | 
			
		||||
 | 
			
		||||
static int _run_command(struct dso_state *state)
 | 
			
		||||
@@ -156,7 +165,7 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
	char *params;
 | 
			
		||||
	int needs_policy = 0;
 | 
			
		||||
	struct dm_task *new_dmt = NULL;
 | 
			
		||||
	struct dm_vdo_status_parse_result vdop = { .status = NULL };
 | 
			
		||||
	struct vdo_status status;
 | 
			
		||||
 | 
			
		||||
#if VDO_DEBUG
 | 
			
		||||
	log_debug("Watch for VDO %s:%.2f%%.", state->name,
 | 
			
		||||
@@ -202,24 +211,24 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_vdo_status_parse(state->mem, params, &vdop)) {
 | 
			
		||||
	if (!_vdo_status_parse(params, &status)) {
 | 
			
		||||
		log_error("Failed to parse status.");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state->percent = dm_make_percent(vdop.status->used_blocks,
 | 
			
		||||
					 vdop.status->total_blocks);
 | 
			
		||||
	state->percent = dm_make_percent(status.used_blocks,
 | 
			
		||||
					 status.total_blocks);
 | 
			
		||||
 | 
			
		||||
#if VDO_DEBUG
 | 
			
		||||
	log_debug("VDO %s status  %.2f%% " FMTu64 "/" FMTu64 ".",
 | 
			
		||||
		  state->name, dm_percent_to_round_float(state->percent, 2),
 | 
			
		||||
		  vdop.status->used_blocks, vdop.status->total_blocks);
 | 
			
		||||
		  status.used_blocks, status.total_blocks);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* VDO pool size had changed. Clear the threshold. */
 | 
			
		||||
	if (state->known_data_size != vdop.status->total_blocks) {
 | 
			
		||||
	if (state->known_data_size != status.total_blocks) {
 | 
			
		||||
		state->percent_check = CHECK_MINIMUM;
 | 
			
		||||
		state->known_data_size = vdop.status->total_blocks;
 | 
			
		||||
		state->known_data_size = status.total_blocks;
 | 
			
		||||
		state->fails = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -252,7 +261,7 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
		if (state->fails++ <= state->max_fails) {
 | 
			
		||||
			log_debug("Postponing frequently failing policy (%u <= %u).",
 | 
			
		||||
				  state->fails - 1, state->max_fails);
 | 
			
		||||
			goto out;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (state->max_fails < MAX_FAILS)
 | 
			
		||||
			state->max_fails <<= 1;
 | 
			
		||||
@@ -260,12 +269,10 @@ void process_event(struct dm_task *dmt,
 | 
			
		||||
	} else
 | 
			
		||||
		state->max_fails = 1; /* Reset on success */
 | 
			
		||||
 | 
			
		||||
	if (needs_policy)
 | 
			
		||||
	/* FIXME: ATM nothing can be done, drop 0, once it becomes useful */
 | 
			
		||||
	if (0 && needs_policy)
 | 
			
		||||
		_use_policy(dmt, state);
 | 
			
		||||
out:
 | 
			
		||||
	if (vdop.status)
 | 
			
		||||
		dm_pool_free(state->mem, vdop.status);
 | 
			
		||||
 | 
			
		||||
	if (new_dmt)
 | 
			
		||||
		dm_task_destroy(new_dmt);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,2 +1 @@
 | 
			
		||||
dmsetup
 | 
			
		||||
dmfilemapd
 | 
			
		||||
							
								
								
									
										66
									
								
								daemons/dmfilemapd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								daemons/dmfilemapd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of the device-mapper userspace tools.
 | 
			
		||||
#
 | 
			
		||||
# This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
# of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 | 
			
		||||
srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
SOURCES = dmfilemapd.c
 | 
			
		||||
 | 
			
		||||
TARGETS = dmfilemapd
 | 
			
		||||
 | 
			
		||||
.PHONY: install_dmfilemapd install_dmfilemapd_static
 | 
			
		||||
 | 
			
		||||
INSTALL_DMFILEMAPD_TARGETS = install_dmfilemapd_dynamic
 | 
			
		||||
 | 
			
		||||
CLEAN_TARGETS = dmfilemapd.static
 | 
			
		||||
 | 
			
		||||
CFLOW_LIST = $(SOURCES)
 | 
			
		||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
			
		||||
CFLOW_TARGET = dmfilemapd
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
all: device-mapper
 | 
			
		||||
device-mapper: $(TARGETS)
 | 
			
		||||
 | 
			
		||||
CFLAGS_dmfilemapd.o += $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
LIBS += -ldevmapper
 | 
			
		||||
 | 
			
		||||
dmfilemapd: $(LIB_SHARED) dmfilemapd.o
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
 | 
			
		||||
		-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS)
 | 
			
		||||
 | 
			
		||||
dmfilemapd.static: $(LIB_STATIC) dmfilemapd.o $(interfacebuilddir)/libdevmapper.a
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L$(interfacebuilddir) \
 | 
			
		||||
		-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS) $(STATIC_LIBS)
 | 
			
		||||
 | 
			
		||||
ifneq ("$(CFLOW_CMD)", "")
 | 
			
		||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
 | 
			
		||||
-include $(top_builddir)/libdm/libdevmapper.cflow
 | 
			
		||||
-include $(top_builddir)/lib/liblvm-internal.cflow
 | 
			
		||||
-include $(top_builddir)/lib/liblvm2cmd.cflow
 | 
			
		||||
-include $(top_builddir)/daemons/dmfilemapd/$(LIB_NAME).cflow
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
install_dmfilemapd_dynamic: dmfilemapd
 | 
			
		||||
	$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_dmfilemapd_static: dmfilemapd.static
 | 
			
		||||
	$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_dmfilemapd: $(INSTALL_DMFILEMAPD_TARGETS)
 | 
			
		||||
 | 
			
		||||
install: install_dmfilemapd
 | 
			
		||||
 | 
			
		||||
install_device-mapper: install_dmfilemapd
 | 
			
		||||
@@ -14,8 +14,11 @@
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "libdm/misc/dm-logging.h"
 | 
			
		||||
#include "tool.h"
 | 
			
		||||
 | 
			
		||||
#include "dm-logging.h"
 | 
			
		||||
 | 
			
		||||
#include "defaults.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
@@ -26,15 +29,13 @@
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
#  include "libdm/misc/kdev_t.h"
 | 
			
		||||
#  include "kdev_t.h"
 | 
			
		||||
#else
 | 
			
		||||
#  define MAJOR(x) major((x))
 | 
			
		||||
#  define MINOR(x) minor((x))
 | 
			
		||||
#  define MKDEV(x,y) makedev((x),(y))
 | 
			
		||||
#  define MKDEV(x,y) makedev((dev_t)(x),(dev_t)(y))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_PROC_DIR "/proc"
 | 
			
		||||
 | 
			
		||||
/* limit to two updates/sec */
 | 
			
		||||
#define FILEMAPD_WAIT_USECS 500000
 | 
			
		||||
 | 
			
		||||
@@ -310,7 +311,7 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fm->path = strdup(argv[0]);
 | 
			
		||||
	fm->path = dm_strdup(argv[0]);
 | 
			
		||||
	if (!fm->path) {
 | 
			
		||||
		_early_log("Could not allocate memory for path argument.");
 | 
			
		||||
		return 0;
 | 
			
		||||
@@ -537,8 +538,8 @@ static void _filemap_monitor_destroy(struct filemap_monitor *fm)
 | 
			
		||||
		_filemap_monitor_end_notify(fm);
 | 
			
		||||
		_filemap_monitor_close_fd(fm);
 | 
			
		||||
	}
 | 
			
		||||
	free((void *) fm->program_id);
 | 
			
		||||
	free(fm->path);
 | 
			
		||||
	dm_free((void *) fm->program_id);
 | 
			
		||||
	dm_free(fm->path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _filemap_monitor_check_same_file(int fd1, int fd2)
 | 
			
		||||
@@ -698,7 +699,7 @@ static int _update_regions(struct dm_stats *dms, struct filemap_monitor *fm)
 | 
			
		||||
			 fm->group_id, regions[0]);
 | 
			
		||||
		fm->group_id = regions[0];
 | 
			
		||||
	}
 | 
			
		||||
	free(regions);
 | 
			
		||||
	dm_free(regions);
 | 
			
		||||
	fm->nr_regions = nr_regions;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -740,7 +741,7 @@ static int _dmfilemapd(struct filemap_monitor *fm)
 | 
			
		||||
	 */
 | 
			
		||||
	program_id = dm_stats_get_region_program_id(dms, fm->group_id);
 | 
			
		||||
	if (program_id)
 | 
			
		||||
		fm->program_id = strdup(program_id);
 | 
			
		||||
		fm->program_id = dm_strdup(program_id);
 | 
			
		||||
	else
 | 
			
		||||
		fm->program_id = NULL;
 | 
			
		||||
	dm_stats_set_program_id(dms, 1, program_id);
 | 
			
		||||
@@ -816,7 +817,7 @@ int main(int argc, char **argv)
 | 
			
		||||
	memset(&fm, 0, sizeof(fm));
 | 
			
		||||
 | 
			
		||||
	if (!_parse_args(argc, argv, &fm)) {
 | 
			
		||||
		free(fm.path);
 | 
			
		||||
		dm_free(fm.path);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -827,7 +828,7 @@ int main(int argc, char **argv)
 | 
			
		||||
		 _mode_names[fm.mode], fm.path);
 | 
			
		||||
 | 
			
		||||
	if (!_foreground && !_daemonise(&fm)) {
 | 
			
		||||
		free(fm.path);
 | 
			
		||||
		dm_free(fm.path);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -23,10 +23,11 @@ LVMDBUS_SRCDIR_FILES = \
 | 
			
		||||
	cfg.py \
 | 
			
		||||
	cmdhandler.py \
 | 
			
		||||
	fetch.py \
 | 
			
		||||
	__init__.py \
 | 
			
		||||
	job.py \
 | 
			
		||||
	loader.py \
 | 
			
		||||
	lv.py \
 | 
			
		||||
	main.py \
 | 
			
		||||
	lv.py \
 | 
			
		||||
	manager.py \
 | 
			
		||||
	objectmanager.py \
 | 
			
		||||
	pv.py \
 | 
			
		||||
@@ -34,8 +35,7 @@ LVMDBUS_SRCDIR_FILES = \
 | 
			
		||||
	state.py \
 | 
			
		||||
	udevwatch.py \
 | 
			
		||||
	utils.py \
 | 
			
		||||
	vg.py \
 | 
			
		||||
	__init__.py
 | 
			
		||||
	vg.py
 | 
			
		||||
 | 
			
		||||
LVMDBUS_BUILDDIR_FILES = \
 | 
			
		||||
	lvmdb.py \
 | 
			
		||||
@@ -51,18 +51,17 @@ include $(top_builddir)/make.tmpl
 | 
			
		||||
.PHONY: install_lvmdbusd
 | 
			
		||||
 | 
			
		||||
all:
 | 
			
		||||
	$(Q) test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
 | 
			
		||||
	test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
 | 
			
		||||
 | 
			
		||||
install_lvmdbusd:
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_DIR) $(sbindir)
 | 
			
		||||
	$(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
 | 
			
		||||
	$(Q) $(INSTALL_DIR) $(DESTDIR)$(lvmdbusdir)
 | 
			
		||||
	$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(DESTDIR)$(lvmdbusdir))
 | 
			
		||||
	$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(DESTDIR)$(lvmdbusdir)
 | 
			
		||||
	$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbusdir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
 | 
			
		||||
	$(Q) $(CHMOD) 755 $(DESTDIR)$(lvmdbusdir)/__pycache__
 | 
			
		||||
	$(Q) $(CHMOD) 444 $(DESTDIR)$(lvmdbusdir)/__pycache__/*.py[co]
 | 
			
		||||
	$(INSTALL_DIR) $(sbindir)
 | 
			
		||||
	$(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
 | 
			
		||||
	$(INSTALL_DIR) $(DESTDIR)$(lvmdbusdir)
 | 
			
		||||
	(cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(DESTDIR)$(lvmdbusdir))
 | 
			
		||||
	$(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(DESTDIR)$(lvmdbusdir)
 | 
			
		||||
	PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbusdir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
 | 
			
		||||
	$(CHMOD) 755 $(DESTDIR)$(lvmdbusdir)/__pycache__
 | 
			
		||||
	$(CHMOD) 444 $(DESTDIR)$(lvmdbusdir)/__pycache__/*.py[co]
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_lvmdbusd
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -155,7 +155,7 @@ class AutomatedProperties(dbus.service.Object):
 | 
			
		||||
		# through all dbus objects as some don't have a search method, like
 | 
			
		||||
		# 'Manager' object.
 | 
			
		||||
		if not self._ap_search_method:
 | 
			
		||||
			return 0
 | 
			
		||||
			return
 | 
			
		||||
 | 
			
		||||
		search = self.lvm_id
 | 
			
		||||
		if search_key:
 | 
			
		||||
 
 | 
			
		||||
@@ -47,11 +47,9 @@ BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
 | 
			
		||||
BASE_INTERFACE = 'com.redhat.lvmdbus1'
 | 
			
		||||
PV_INTERFACE = BASE_INTERFACE + '.Pv'
 | 
			
		||||
VG_INTERFACE = BASE_INTERFACE + '.Vg'
 | 
			
		||||
VG_VDO_INTERFACE = BASE_INTERFACE + '.VgVdo'
 | 
			
		||||
LV_INTERFACE = BASE_INTERFACE + '.Lv'
 | 
			
		||||
LV_COMMON_INTERFACE = BASE_INTERFACE + '.LvCommon'
 | 
			
		||||
THIN_POOL_INTERFACE = BASE_INTERFACE + '.ThinPool'
 | 
			
		||||
VDO_POOL_INTERFACE = BASE_INTERFACE + '.VdoPool'
 | 
			
		||||
CACHE_POOL_INTERFACE = BASE_INTERFACE + '.CachePool'
 | 
			
		||||
LV_CACHED = BASE_INTERFACE + '.CachedLv'
 | 
			
		||||
SNAPSHOT_INTERFACE = BASE_INTERFACE + '.Snapshot'
 | 
			
		||||
@@ -63,7 +61,6 @@ PV_OBJ_PATH = BASE_OBJ_PATH + '/Pv'
 | 
			
		||||
VG_OBJ_PATH = BASE_OBJ_PATH + '/Vg'
 | 
			
		||||
LV_OBJ_PATH = BASE_OBJ_PATH + '/Lv'
 | 
			
		||||
THIN_POOL_PATH = BASE_OBJ_PATH + "/ThinPool"
 | 
			
		||||
VDO_POOL_PATH = BASE_OBJ_PATH + "/VdoPool"
 | 
			
		||||
CACHE_POOL_PATH = BASE_OBJ_PATH + "/CachePool"
 | 
			
		||||
HIDDEN_LV_PATH = BASE_OBJ_PATH + "/HiddenLv"
 | 
			
		||||
MANAGER_OBJ_PATH = BASE_OBJ_PATH + '/Manager'
 | 
			
		||||
@@ -74,7 +71,6 @@ pv_id = itertools.count()
 | 
			
		||||
vg_id = itertools.count()
 | 
			
		||||
lv_id = itertools.count()
 | 
			
		||||
thin_id = itertools.count()
 | 
			
		||||
vdo_id = itertools.count()
 | 
			
		||||
cache_pool_id = itertools.count()
 | 
			
		||||
job_id = itertools.count()
 | 
			
		||||
hidden_lv = itertools.count()
 | 
			
		||||
@@ -83,9 +79,6 @@ hidden_lv = itertools.count()
 | 
			
		||||
load = None
 | 
			
		||||
event = None
 | 
			
		||||
 | 
			
		||||
# Boolean to denote if lvm supports VDO integration
 | 
			
		||||
vdo_support = False
 | 
			
		||||
 | 
			
		||||
# Global cached state
 | 
			
		||||
db = None
 | 
			
		||||
 | 
			
		||||
@@ -94,13 +87,3 @@ blackbox = None
 | 
			
		||||
 | 
			
		||||
# RequestEntry ctor
 | 
			
		||||
create_request_entry = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def exit_daemon():
 | 
			
		||||
    """
 | 
			
		||||
    Exit the daemon cleanly
 | 
			
		||||
    :return:
 | 
			
		||||
    """
 | 
			
		||||
    if run and loop:
 | 
			
		||||
        run.value = 0
 | 
			
		||||
        loop.quit()
 | 
			
		||||
 
 | 
			
		||||
@@ -67,7 +67,7 @@ class LvmFlightRecorder(object):
 | 
			
		||||
		with cmd_lock:
 | 
			
		||||
			if len(self.queue):
 | 
			
		||||
				log_error("LVM dbus flight recorder START")
 | 
			
		||||
				for c in reversed(self.queue):
 | 
			
		||||
				for c in self.queue:
 | 
			
		||||
					log_error(str(c))
 | 
			
		||||
				log_error("LVM dbus flight recorder END")
 | 
			
		||||
 | 
			
		||||
@@ -217,10 +217,7 @@ def options_to_cli_args(options):
 | 
			
		||||
		else:
 | 
			
		||||
			rc.append("--%s" % k)
 | 
			
		||||
		if v != "":
 | 
			
		||||
			if isinstance(v, int):
 | 
			
		||||
				rc.append(str(int(v)))
 | 
			
		||||
			else:
 | 
			
		||||
				rc.append(str(v))
 | 
			
		||||
			rc.append(str(v))
 | 
			
		||||
	return rc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -266,10 +263,10 @@ def lv_tag(lv_name, add, rm, tag_options):
 | 
			
		||||
	return _tag('lvchange', lv_name, add, rm, tag_options)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def vg_rename(vg_uuid, new_name, rename_options):
 | 
			
		||||
def vg_rename(vg, new_name, rename_options):
 | 
			
		||||
	cmd = ['vgrename']
 | 
			
		||||
	cmd.extend(options_to_cli_args(rename_options))
 | 
			
		||||
	cmd.extend([vg_uuid, new_name])
 | 
			
		||||
	cmd.extend([vg, new_name])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -283,7 +280,7 @@ def vg_remove(vg_name, remove_options):
 | 
			
		||||
def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests):
 | 
			
		||||
	cmd = ['lvcreate']
 | 
			
		||||
	cmd.extend(options_to_cli_args(create_options))
 | 
			
		||||
	cmd.extend(['--size', '%dB' % size_bytes])
 | 
			
		||||
	cmd.extend(['--size', str(size_bytes) + 'B'])
 | 
			
		||||
	cmd.extend(['--name', name, vg_name, '--yes'])
 | 
			
		||||
	pv_dest_ranges(cmd, pv_dests)
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
@@ -295,7 +292,7 @@ def vg_lv_snapshot(vg_name, snapshot_options, name, size_bytes):
 | 
			
		||||
	cmd.extend(["-s"])
 | 
			
		||||
 | 
			
		||||
	if size_bytes != 0:
 | 
			
		||||
		cmd.extend(['--size', '%dB' % size_bytes])
 | 
			
		||||
		cmd.extend(['--size', str(size_bytes) + 'B'])
 | 
			
		||||
 | 
			
		||||
	cmd.extend(['--name', name, vg_name])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
@@ -306,9 +303,9 @@ def _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool):
 | 
			
		||||
	cmd.extend(options_to_cli_args(create_options))
 | 
			
		||||
 | 
			
		||||
	if not thin_pool:
 | 
			
		||||
		cmd.extend(['--size', '%dB' % size_bytes])
 | 
			
		||||
		cmd.extend(['--size', str(size_bytes) + 'B'])
 | 
			
		||||
	else:
 | 
			
		||||
		cmd.extend(['--thin', '--size', '%dB' % size_bytes])
 | 
			
		||||
		cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
 | 
			
		||||
 | 
			
		||||
	cmd.extend(['--yes'])
 | 
			
		||||
	return cmd
 | 
			
		||||
@@ -323,10 +320,10 @@ def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
 | 
			
		||||
def vg_lv_create_striped(vg_name, create_options, name, size_bytes,
 | 
			
		||||
							num_stripes, stripe_size_kb, thin_pool):
 | 
			
		||||
	cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool)
 | 
			
		||||
	cmd.extend(['--stripes', str(int(num_stripes))])
 | 
			
		||||
	cmd.extend(['--stripes', str(num_stripes)])
 | 
			
		||||
 | 
			
		||||
	if stripe_size_kb != 0:
 | 
			
		||||
		cmd.extend(['--stripesize', str(int(stripe_size_kb))])
 | 
			
		||||
		cmd.extend(['--stripesize', str(stripe_size_kb)])
 | 
			
		||||
 | 
			
		||||
	cmd.extend(['--name', name, vg_name])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
@@ -339,13 +336,13 @@ def _vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
 | 
			
		||||
	cmd.extend(options_to_cli_args(create_options))
 | 
			
		||||
 | 
			
		||||
	cmd.extend(['--type', raid_type])
 | 
			
		||||
	cmd.extend(['--size', '%dB' % size_bytes])
 | 
			
		||||
	cmd.extend(['--size', str(size_bytes) + 'B'])
 | 
			
		||||
 | 
			
		||||
	if num_stripes != 0:
 | 
			
		||||
		cmd.extend(['--stripes', str(int(num_stripes))])
 | 
			
		||||
		cmd.extend(['--stripes', str(num_stripes)])
 | 
			
		||||
 | 
			
		||||
	if stripe_size_kb != 0:
 | 
			
		||||
		cmd.extend(['--stripesize', str(int(stripe_size_kb))])
 | 
			
		||||
		cmd.extend(['--stripesize', str(stripe_size_kb)])
 | 
			
		||||
 | 
			
		||||
	cmd.extend(['--name', name, vg_name, '--yes'])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
@@ -366,8 +363,8 @@ def vg_lv_create_mirror(
 | 
			
		||||
	cmd.extend(options_to_cli_args(create_options))
 | 
			
		||||
 | 
			
		||||
	cmd.extend(['--type', 'mirror'])
 | 
			
		||||
	cmd.extend(['--mirrors', str(int(num_copies))])
 | 
			
		||||
	cmd.extend(['--size', '%dB' % size_bytes])
 | 
			
		||||
	cmd.extend(['--mirrors', str(num_copies)])
 | 
			
		||||
	cmd.extend(['--size', str(size_bytes) + 'B'])
 | 
			
		||||
	cmd.extend(['--name', name, vg_name, '--yes'])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
@@ -388,24 +385,6 @@ def vg_create_thin_pool(md_full_name, data_full_name, create_options):
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def vg_create_vdo_pool_lv_and_lv(vg_name, pool_name, lv_name, data_size,
 | 
			
		||||
									virtual_size, create_options):
 | 
			
		||||
	cmd = ['lvcreate']
 | 
			
		||||
	cmd.extend(options_to_cli_args(create_options))
 | 
			
		||||
	cmd.extend(['-y', '--type', 'vdo', '-n', lv_name,
 | 
			
		||||
				'-L', '%dB' % data_size, '-V', '%dB' % virtual_size,
 | 
			
		||||
				"%s/%s" % (vg_name, pool_name)])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def vg_create_vdo_pool(pool_full_name, lv_name, virtual_size, create_options):
 | 
			
		||||
	cmd = ['lvconvert']
 | 
			
		||||
	cmd.extend(options_to_cli_args(create_options))
 | 
			
		||||
	cmd.extend(['--type', 'vdo-pool', '-n', lv_name, '--force', '-y',
 | 
			
		||||
				'-V', '%dB' % virtual_size, pool_full_name])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def lv_remove(lv_path, remove_options):
 | 
			
		||||
	cmd = ['lvremove']
 | 
			
		||||
	cmd.extend(options_to_cli_args(remove_options))
 | 
			
		||||
@@ -439,7 +418,7 @@ def lv_resize(lv_full_name, size_change, pv_dests,
 | 
			
		||||
def lv_lv_create(lv_full_name, create_options, name, size_bytes):
 | 
			
		||||
	cmd = ['lvcreate']
 | 
			
		||||
	cmd.extend(options_to_cli_args(create_options))
 | 
			
		||||
	cmd.extend(['--virtualsize', '%dB' % size_bytes, '-T'])
 | 
			
		||||
	cmd.extend(['--virtualsize', str(size_bytes) + 'B', '-T'])
 | 
			
		||||
	cmd.extend(['--name', name, lv_full_name, '--yes'])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
@@ -453,15 +432,6 @@ def lv_cache_lv(cache_pool_full_name, lv_full_name, cache_options):
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def lv_writecache_lv(cache_lv_full_name, lv_full_name, cache_options):
 | 
			
		||||
	# lvconvert --type writecache --cachevol VG/CacheLV VG/OriginLV
 | 
			
		||||
	cmd = ['lvconvert']
 | 
			
		||||
	cmd.extend(options_to_cli_args(cache_options))
 | 
			
		||||
	cmd.extend(['-y', '--type', 'writecache', '--cachevol',
 | 
			
		||||
				cache_lv_full_name, lv_full_name])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
 | 
			
		||||
	cmd = ['lvconvert']
 | 
			
		||||
	if destroy_cache:
 | 
			
		||||
@@ -477,28 +447,6 @@ def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def lv_vdo_compression(lv_path, enable, comp_options):
 | 
			
		||||
	cmd = ['lvchange', '--compression']
 | 
			
		||||
	if enable:
 | 
			
		||||
		cmd.append('y')
 | 
			
		||||
	else:
 | 
			
		||||
		cmd.append('n')
 | 
			
		||||
	cmd.extend(options_to_cli_args(comp_options))
 | 
			
		||||
	cmd.append(lv_path)
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def lv_vdo_deduplication(lv_path, enable, dedup_options):
 | 
			
		||||
	cmd = ['lvchange', '--deduplication']
 | 
			
		||||
	if enable:
 | 
			
		||||
		cmd.append('y')
 | 
			
		||||
	else:
 | 
			
		||||
		cmd.append('n')
 | 
			
		||||
	cmd.extend(options_to_cli_args(dedup_options))
 | 
			
		||||
	cmd.append(lv_path)
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def supports_json():
 | 
			
		||||
	cmd = ['help']
 | 
			
		||||
	rc, out, err = call(cmd)
 | 
			
		||||
@@ -511,16 +459,6 @@ def supports_json():
 | 
			
		||||
	return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def supports_vdo():
 | 
			
		||||
	cmd = ['segtypes']
 | 
			
		||||
	rc, out, err = call(cmd)
 | 
			
		||||
	if rc == 0:
 | 
			
		||||
		if "vdo" in out:
 | 
			
		||||
			log_debug("We have VDO support")
 | 
			
		||||
			return True
 | 
			
		||||
	return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def lvm_full_report_json():
 | 
			
		||||
	pv_columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
 | 
			
		||||
					'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
 | 
			
		||||
@@ -548,22 +486,6 @@ def lvm_full_report_json():
 | 
			
		||||
 | 
			
		||||
	lv_seg_columns = ['seg_pe_ranges', 'segtype', 'lv_uuid']
 | 
			
		||||
 | 
			
		||||
	if cfg.vdo_support:
 | 
			
		||||
		lv_columns.extend(
 | 
			
		||||
			['vdo_operating_mode', 'vdo_compression_state', 'vdo_index_state',
 | 
			
		||||
				'vdo_used_size', 'vdo_saving_percent']
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		lv_seg_columns.extend(
 | 
			
		||||
			['vdo_compression', 'vdo_deduplication',
 | 
			
		||||
				'vdo_use_metadata_hints', 'vdo_minimum_io_size',
 | 
			
		||||
				'vdo_block_map_cache_size', 'vdo_block_map_era_length',
 | 
			
		||||
				'vdo_use_sparse_index', 'vdo_index_memory_size',
 | 
			
		||||
				'vdo_slab_size', 'vdo_ack_threads', 'vdo_bio_threads',
 | 
			
		||||
				'vdo_bio_rotation', 'vdo_cpu_threads', 'vdo_hash_zone_threads',
 | 
			
		||||
				'vdo_logical_threads', 'vdo_physical_threads',
 | 
			
		||||
				'vdo_max_discard', 'vdo_write_policy', 'vdo_header_size'])
 | 
			
		||||
 | 
			
		||||
	cmd = _dc('fullreport', [
 | 
			
		||||
		'-a',		# Need hidden too
 | 
			
		||||
		'--configreport', 'pv', '-o', ','.join(pv_columns),
 | 
			
		||||
@@ -575,8 +497,7 @@ def lvm_full_report_json():
 | 
			
		||||
	])
 | 
			
		||||
 | 
			
		||||
	rc, out, err = call(cmd)
 | 
			
		||||
	# When we have an exported vg the exit code of lvs or fullreport will be 5
 | 
			
		||||
	if rc == 0 or rc == 5:
 | 
			
		||||
	if rc == 0:
 | 
			
		||||
		# 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
 | 
			
		||||
@@ -634,7 +555,7 @@ def pv_resize(device, size_bytes, create_options):
 | 
			
		||||
	cmd.extend(options_to_cli_args(create_options))
 | 
			
		||||
 | 
			
		||||
	if size_bytes != 0:
 | 
			
		||||
		cmd.extend(['--yes', '--setphysicalvolumesize', '%dB' % size_bytes])
 | 
			
		||||
		cmd.extend(['--yes', '--setphysicalvolumesize', str(size_bytes) + 'B'])
 | 
			
		||||
 | 
			
		||||
	cmd.extend([device])
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
@@ -730,12 +651,12 @@ def vg_allocation_policy(vg_name, policy, policy_options):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def vg_max_pv(vg_name, number, max_options):
 | 
			
		||||
	return _vg_value_set(vg_name, ['--maxphysicalvolumes', str(int(number))],
 | 
			
		||||
	return _vg_value_set(vg_name, ['--maxphysicalvolumes', str(number)],
 | 
			
		||||
							max_options)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def vg_max_lv(vg_name, number, max_options):
 | 
			
		||||
	return _vg_value_set(vg_name, ['-l', str(int(number))], max_options)
 | 
			
		||||
	return _vg_value_set(vg_name, ['-l', str(number)], max_options)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def vg_uuid_gen(vg_name, ignore, options):
 | 
			
		||||
@@ -777,7 +698,6 @@ def activate_deactivate(op, name, activate, control_flags, options):
 | 
			
		||||
		op += 'n'
 | 
			
		||||
 | 
			
		||||
	cmd.append(op)
 | 
			
		||||
	cmd.append("-y")
 | 
			
		||||
	cmd.append(name)
 | 
			
		||||
	return call(cmd)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@ from . import cfg
 | 
			
		||||
from .utils import MThreadRunner, log_debug, log_error
 | 
			
		||||
import threading
 | 
			
		||||
import queue
 | 
			
		||||
import time
 | 
			
		||||
import traceback
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -29,26 +28,11 @@ def _main_thread_load(refresh=True, emit_signal=True):
 | 
			
		||||
		refresh=refresh,
 | 
			
		||||
		emit_signal=emit_signal,
 | 
			
		||||
		cache_refresh=False)[1]
 | 
			
		||||
 | 
			
		||||
	lv_changes = load_lvs(
 | 
			
		||||
	num_total_changes += load_lvs(
 | 
			
		||||
		refresh=refresh,
 | 
			
		||||
		emit_signal=emit_signal,
 | 
			
		||||
		cache_refresh=False)[1]
 | 
			
		||||
 | 
			
		||||
	num_total_changes += lv_changes
 | 
			
		||||
 | 
			
		||||
	# When the LVs change it can cause another change in the VGs which is
 | 
			
		||||
	# missed if we don't scan through the VGs again.  We could achieve this
 | 
			
		||||
	# the other way and re-scan the LVs, but in general there are more LVs than
 | 
			
		||||
	# VGs, thus this should be more efficient.  This happens when a LV interface
 | 
			
		||||
	# changes causing the dbus object representing it to be removed and
 | 
			
		||||
	# recreated.
 | 
			
		||||
	if refresh and lv_changes > 0:
 | 
			
		||||
		num_total_changes += load_vgs(
 | 
			
		||||
			refresh=refresh,
 | 
			
		||||
			emit_signal=emit_signal,
 | 
			
		||||
			cache_refresh=False)[1]
 | 
			
		||||
 | 
			
		||||
	return num_total_changes
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -98,8 +82,6 @@ class StateUpdate(object):
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def update_thread(obj):
 | 
			
		||||
		exception_count = 0
 | 
			
		||||
 | 
			
		||||
		queued_requests = []
 | 
			
		||||
		while cfg.run.value != 0:
 | 
			
		||||
			# noinspection PyBroadException
 | 
			
		||||
@@ -154,26 +136,12 @@ class StateUpdate(object):
 | 
			
		||||
				# wake up if we get an exception
 | 
			
		||||
				queued_requests = []
 | 
			
		||||
 | 
			
		||||
				# We retrieved OK, clear exception count
 | 
			
		||||
				exception_count = 0
 | 
			
		||||
 | 
			
		||||
			except queue.Empty:
 | 
			
		||||
				pass
 | 
			
		||||
			except Exception as e:
 | 
			
		||||
			except Exception:
 | 
			
		||||
				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)
 | 
			
		||||
 | 
			
		||||
					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()
 | 
			
		||||
 
 | 
			
		||||
@@ -10,22 +10,20 @@
 | 
			
		||||
from .automatedproperties import AutomatedProperties
 | 
			
		||||
 | 
			
		||||
from . import utils
 | 
			
		||||
from .utils import vg_obj_path_generate, log_error, _handle_execute
 | 
			
		||||
from .utils import vg_obj_path_generate
 | 
			
		||||
import dbus
 | 
			
		||||
from . import cmdhandler
 | 
			
		||||
from . import cfg
 | 
			
		||||
from .cfg import LV_INTERFACE, THIN_POOL_INTERFACE, SNAPSHOT_INTERFACE, \
 | 
			
		||||
	LV_COMMON_INTERFACE, CACHE_POOL_INTERFACE, LV_CACHED, VDO_POOL_INTERFACE
 | 
			
		||||
	LV_COMMON_INTERFACE, CACHE_POOL_INTERFACE, LV_CACHED
 | 
			
		||||
from .request import RequestEntry
 | 
			
		||||
from .utils import n, n32, d
 | 
			
		||||
from .utils import n, n32
 | 
			
		||||
from .loader import common
 | 
			
		||||
from .state import State
 | 
			
		||||
from . import background
 | 
			
		||||
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 least dependencies
 | 
			
		||||
# first.  This may be error prone because of the flexibility LVM
 | 
			
		||||
@@ -74,66 +72,23 @@ def lvs_state_retrieve(selection, cache_refresh=True):
 | 
			
		||||
	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']))
 | 
			
		||||
		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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -237,8 +192,6 @@ class LvState(State):
 | 
			
		||||
	def _object_type_create(self):
 | 
			
		||||
		if self.Attr[0] == 't':
 | 
			
		||||
			return LvThinPool
 | 
			
		||||
		elif self.Attr[0] == 'd':
 | 
			
		||||
			return LvVdoPool
 | 
			
		||||
		elif self.Attr[0] == 'C':
 | 
			
		||||
			if 'pool' in self.layout:
 | 
			
		||||
				return LvCachePool
 | 
			
		||||
@@ -265,34 +218,6 @@ class LvState(State):
 | 
			
		||||
		return (klass, path_method)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LvStateVdo(LvState):
 | 
			
		||||
 | 
			
		||||
	def __init__(self, Uuid, Name, Path, SizeBytes,
 | 
			
		||||
					vg_name, vg_uuid, pool_lv_uuid, PoolLv,
 | 
			
		||||
					origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
 | 
			
		||||
					data_lv, metadata_lv, segtypes, role, layout, SnapPercent,
 | 
			
		||||
					MetaDataPercent, CopyPercent, SyncPercent,
 | 
			
		||||
					MetaDataSizeBytes, move_pv, move_pv_uuid,
 | 
			
		||||
					vdo_operating_mode, vdo_compression_state, vdo_index_state,
 | 
			
		||||
					vdo_used_size,vdo_saving_percent,vdo_compression,
 | 
			
		||||
					vdo_deduplication,vdo_use_metadata_hints,
 | 
			
		||||
					vdo_minimum_io_size,vdo_block_map_cache_size,
 | 
			
		||||
					vdo_block_map_era_length,vdo_use_sparse_index,
 | 
			
		||||
					vdo_index_memory_size,vdo_slab_size,vdo_ack_threads,
 | 
			
		||||
					vdo_bio_threads,vdo_bio_rotation,vdo_cpu_threads,
 | 
			
		||||
					vdo_hash_zone_threads,vdo_logical_threads,
 | 
			
		||||
					vdo_physical_threads,vdo_max_discard,
 | 
			
		||||
					vdo_write_policy,vdo_header_size):
 | 
			
		||||
		super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
 | 
			
		||||
					vg_name, vg_uuid, pool_lv_uuid, PoolLv,
 | 
			
		||||
					origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
 | 
			
		||||
					data_lv, metadata_lv, segtypes, role, layout, SnapPercent,
 | 
			
		||||
					MetaDataPercent, CopyPercent, SyncPercent,
 | 
			
		||||
					MetaDataSizeBytes, move_pv, move_pv_uuid)
 | 
			
		||||
 | 
			
		||||
		utils.init_class_from_arguments(self, "vdo_", snake_to_pascal=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# noinspection PyPep8Naming
 | 
			
		||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'Uuid', 's')
 | 
			
		||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'Name', 's')
 | 
			
		||||
@@ -348,7 +273,13 @@ class LvCommon(AutomatedProperties):
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def handle_execute(rc, out, err):
 | 
			
		||||
		_handle_execute(rc, out, err, LV_INTERFACE)
 | 
			
		||||
		if rc == 0:
 | 
			
		||||
			cfg.load()
 | 
			
		||||
		else:
 | 
			
		||||
			# Need to work on error handling, need consistent
 | 
			
		||||
			raise dbus.exceptions.DBusException(
 | 
			
		||||
				LV_INTERFACE,
 | 
			
		||||
				'Exit code %s, stderr = %s' % (str(rc), err))
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def validate_dbus_object(lv_uuid, lv_name):
 | 
			
		||||
@@ -360,22 +291,6 @@ class LvCommon(AutomatedProperties):
 | 
			
		||||
				(lv_uuid, lv_name))
 | 
			
		||||
		return dbo
 | 
			
		||||
 | 
			
		||||
	def attr_struct(self, index, type_map, default='undisclosed'):
 | 
			
		||||
		try:
 | 
			
		||||
			if self.state.Attr[index] not in type_map:
 | 
			
		||||
				log_error("LV %s %s with lv_attr %s, lv_attr[%d] = "
 | 
			
		||||
					"'%s' is not known" %
 | 
			
		||||
					(self.Uuid, self.Name, self.Attr, index,
 | 
			
		||||
					self.state.Attr[index]))
 | 
			
		||||
 | 
			
		||||
			return dbus.Struct((self.state.Attr[index],
 | 
			
		||||
				type_map.get(self.state.Attr[index], default)),
 | 
			
		||||
								signature="(ss)")
 | 
			
		||||
		except BaseException:
 | 
			
		||||
			st = traceback.format_exc()
 | 
			
		||||
			log_error("attr_struct: \n%s" % st)
 | 
			
		||||
			return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def VolumeType(self):
 | 
			
		||||
		type_map = {'C': 'Cache', 'm': 'mirrored',
 | 
			
		||||
@@ -388,16 +303,17 @@ class LvCommon(AutomatedProperties):
 | 
			
		||||
					'l': 'mirror log device', 'c': 'under conversion',
 | 
			
		||||
					'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
 | 
			
		||||
					'e': 'raid or pool metadata or pool metadata spare',
 | 
			
		||||
					'd': 'vdo pool', 'D': 'vdo pool data', 'g': 'integrity',
 | 
			
		||||
					'-': 'Unspecified'}
 | 
			
		||||
		return self.attr_struct(0, type_map)
 | 
			
		||||
		return dbus.Struct((self.state.Attr[0], type_map[self.state.Attr[0]]),
 | 
			
		||||
						signature="as")
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def Permissions(self):
 | 
			
		||||
		type_map = {'w': 'writable', 'r': 'read-only',
 | 
			
		||||
					'R': 'Read-only activation of non-read-only volume',
 | 
			
		||||
					'-': 'Unspecified'}
 | 
			
		||||
		return self.attr_struct(1, type_map)
 | 
			
		||||
		return dbus.Struct((self.state.Attr[1], type_map[self.state.Attr[1]]),
 | 
			
		||||
						signature="(ss)")
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def AllocationPolicy(self):
 | 
			
		||||
@@ -406,7 +322,8 @@ class LvCommon(AutomatedProperties):
 | 
			
		||||
					'i': 'inherited', 'I': 'inherited locked',
 | 
			
		||||
					'l': 'cling', 'L': 'cling locked',
 | 
			
		||||
					'n': 'normal', 'N': 'normal locked', '-': 'Unspecified'}
 | 
			
		||||
		return self.attr_struct(2, type_map)
 | 
			
		||||
		return dbus.Struct((self.state.Attr[2], type_map[self.state.Attr[2]]),
 | 
			
		||||
						signature="(ss)")
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def FixedMinor(self):
 | 
			
		||||
@@ -414,20 +331,15 @@ class LvCommon(AutomatedProperties):
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def State(self):
 | 
			
		||||
		type_map = {'a': 'active',
 | 
			
		||||
					's': 'suspended',
 | 
			
		||||
					'I': 'Invalid snapshot',
 | 
			
		||||
		type_map = {'a': 'active', 's': 'suspended', 'I': 'Invalid snapshot',
 | 
			
		||||
					'S': 'invalid Suspended snapshot',
 | 
			
		||||
					'm': 'snapshot merge failed',
 | 
			
		||||
					'M': 'suspended snapshot (M)erge failed',
 | 
			
		||||
					'd': 'mapped device present without  tables',
 | 
			
		||||
					'i': 'mapped device present with inactive table',
 | 
			
		||||
					'h': 'historical',
 | 
			
		||||
					'c': 'check needed suspended thin-pool',
 | 
			
		||||
					'C': 'check needed',
 | 
			
		||||
					'X': 'unknown',
 | 
			
		||||
					'-': 'Unspecified'}
 | 
			
		||||
		return self.attr_struct(4, type_map)
 | 
			
		||||
					'X': 'unknown', '-': 'Unspecified'}
 | 
			
		||||
		return dbus.Struct((self.state.Attr[4], type_map[self.state.Attr[4]]),
 | 
			
		||||
						signature="(ss)")
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def TargetType(self):
 | 
			
		||||
@@ -443,18 +355,11 @@ class LvCommon(AutomatedProperties):
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def Health(self):
 | 
			
		||||
		type_map = {'p': 'partial',
 | 
			
		||||
					'r': 'refresh needed',
 | 
			
		||||
					'm': 'mismatches',
 | 
			
		||||
					'w': 'writemostly',
 | 
			
		||||
					'X': 'unknown',
 | 
			
		||||
					'-': 'unspecified',
 | 
			
		||||
					's': 'reshaping',
 | 
			
		||||
					'F': 'failed',
 | 
			
		||||
					'D': 'Data space',
 | 
			
		||||
					'R': 'Remove',
 | 
			
		||||
					'M': 'Metadata'}
 | 
			
		||||
		return self.attr_struct(8, type_map)
 | 
			
		||||
		type_map = {'p': 'partial', 'r': 'refresh',
 | 
			
		||||
					'm': 'mismatches', 'w': 'writemostly',
 | 
			
		||||
					'X': 'X unknown', '-': 'Unspecified'}
 | 
			
		||||
		return dbus.Struct((self.state.Attr[8], type_map[self.state.Attr[8]]),
 | 
			
		||||
					signature="(ss)")
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def SkipActivation(self):
 | 
			
		||||
@@ -524,7 +429,8 @@ class Lv(LvCommon):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		LvCommon.validate_dbus_object(lv_uuid, lv_name)
 | 
			
		||||
		# Remove the LV, if successful then remove from the model
 | 
			
		||||
		LvCommon.handle_execute(*cmdhandler.lv_remove(lv_name, remove_options))
 | 
			
		||||
		rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
 | 
			
		||||
		LvCommon.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -544,8 +450,9 @@ class Lv(LvCommon):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		LvCommon.validate_dbus_object(lv_uuid, lv_name)
 | 
			
		||||
		# Rename the logical volume
 | 
			
		||||
		LvCommon.handle_execute(*cmdhandler.lv_rename(lv_name, new_name,
 | 
			
		||||
												rename_options))
 | 
			
		||||
		rc, out, err = cmdhandler.lv_rename(lv_name, new_name,
 | 
			
		||||
											rename_options)
 | 
			
		||||
		LvCommon.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -594,11 +501,13 @@ class Lv(LvCommon):
 | 
			
		||||
				remainder = space % 512
 | 
			
		||||
				optional_size = space + 512 - remainder
 | 
			
		||||
 | 
			
		||||
		LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
 | 
			
		||||
			lv_name, snapshot_options,name, optional_size))
 | 
			
		||||
		rc, out, err = cmdhandler.vg_lv_snapshot(
 | 
			
		||||
			lv_name, snapshot_options, name, optional_size)
 | 
			
		||||
		LvCommon.handle_execute(rc, out, err)
 | 
			
		||||
		full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
 | 
			
		||||
		return cfg.om.get_object_path_by_lvm_id(full_name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
		dbus_interface=LV_INTERFACE,
 | 
			
		||||
		in_signature='stia{sv}',
 | 
			
		||||
@@ -634,8 +543,9 @@ class Lv(LvCommon):
 | 
			
		||||
				pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
 | 
			
		||||
 | 
			
		||||
		size_change = new_size_bytes - dbo.SizeBytes
 | 
			
		||||
		LvCommon.handle_execute(*cmdhandler.lv_resize(
 | 
			
		||||
			dbo.lvm_id, size_change,pv_dests, resize_options))
 | 
			
		||||
		rc, out, err = cmdhandler.lv_resize(dbo.lvm_id, size_change,
 | 
			
		||||
											pv_dests, resize_options)
 | 
			
		||||
		LvCommon.handle_execute(rc, out, err)
 | 
			
		||||
		return "/"
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -670,8 +580,9 @@ class Lv(LvCommon):
 | 
			
		||||
								options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		LvCommon.validate_dbus_object(uuid, lv_name)
 | 
			
		||||
		LvCommon.handle_execute(*cmdhandler.activate_deactivate(
 | 
			
		||||
			'lvchange', lv_name, activate, control_flags, options))
 | 
			
		||||
		rc, out, err = cmdhandler.activate_deactivate(
 | 
			
		||||
			'lvchange', lv_name, activate, control_flags, options)
 | 
			
		||||
		LvCommon.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -705,8 +616,9 @@ class Lv(LvCommon):
 | 
			
		||||
	def _add_rm_tags(uuid, lv_name, tags_add, tags_del, tag_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		LvCommon.validate_dbus_object(uuid, lv_name)
 | 
			
		||||
		LvCommon.handle_execute(*cmdhandler.lv_tag(
 | 
			
		||||
			lv_name, tags_add, tags_del, tag_options))
 | 
			
		||||
		rc, out, err = cmdhandler.lv_tag(
 | 
			
		||||
			lv_name, tags_add, tags_del, tag_options)
 | 
			
		||||
		LvCommon.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -743,152 +655,6 @@ class Lv(LvCommon):
 | 
			
		||||
			cb, cbe, return_tuple=False)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	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)
 | 
			
		||||
 | 
			
		||||
		# 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_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
 | 
			
		||||
				# 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=LV_INTERFACE,
 | 
			
		||||
		in_signature='oia{sv}',
 | 
			
		||||
		out_signature='(oo)',
 | 
			
		||||
		async_callbacks=('cb', 'cbe'))
 | 
			
		||||
	def WriteCacheLv(self, lv_object, tmo, cache_options, cb, cbe):
 | 
			
		||||
		r = RequestEntry(
 | 
			
		||||
			tmo, Lv._writecache_lv,
 | 
			
		||||
			(self.Uuid, self.lvm_id, lv_object,
 | 
			
		||||
			cache_options), cb, cbe)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# noinspection PyPep8Naming
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'OperatingMode', 's')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'CompressionState', 's')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'IndexState', 's')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UsedSize', 't')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'SavingPercent', 'd')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'Compression', 's')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'Deduplication', 's')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UseMetadataHints', 's')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'MinimumIoSize', 'u')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BlockMapCacheSize', "t")
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BlockMapEraLength', 'u')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UseSparseIndex', 's')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'IndexMemorySize', 't')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'SlabSize', 't')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'AckThreads', 'u')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BioThreads', 'u')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BioRotation', 'u')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'CpuThreads', 'u')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'HashZoneThreads', 'u')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'LogicalThreads', 'u')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'PhysicalThreads', 'u')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'MaxDiscard', 'u')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'WritePolicy', 's')
 | 
			
		||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'HeaderSize', 'u')
 | 
			
		||||
class LvVdoPool(Lv):
 | 
			
		||||
	_DataLv_meta = ("o", VDO_POOL_INTERFACE)
 | 
			
		||||
 | 
			
		||||
	def __init__(self, object_path, object_state):
 | 
			
		||||
		super(LvVdoPool, self).__init__(object_path, object_state)
 | 
			
		||||
		self.set_interface(VDO_POOL_INTERFACE)
 | 
			
		||||
		self._data_lv, _ = self._get_data_meta()
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def DataLv(self):
 | 
			
		||||
		return dbus.ObjectPath(self._data_lv)
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _enable_disable_compression(pool_uuid, pool_name, enable, comp_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		LvCommon.validate_dbus_object(pool_uuid, pool_name)
 | 
			
		||||
		# Rename the logical volume
 | 
			
		||||
		LvCommon.handle_execute(*cmdhandler.lv_vdo_compression(
 | 
			
		||||
			pool_name, enable, comp_options))
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
		dbus_interface=VDO_POOL_INTERFACE,
 | 
			
		||||
		in_signature='ia{sv}',
 | 
			
		||||
		out_signature='o',
 | 
			
		||||
		async_callbacks=('cb', 'cbe'))
 | 
			
		||||
	def EnableCompression(self, tmo, comp_options, cb, cbe):
 | 
			
		||||
		r = RequestEntry(
 | 
			
		||||
			tmo, LvVdoPool._enable_disable_compression,
 | 
			
		||||
			(self.Uuid, self.lvm_id, True, comp_options),
 | 
			
		||||
			cb, cbe, False)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
	dbus_interface=VDO_POOL_INTERFACE,
 | 
			
		||||
	in_signature='ia{sv}',
 | 
			
		||||
	out_signature='o',
 | 
			
		||||
	async_callbacks=('cb', 'cbe'))
 | 
			
		||||
	def DisableCompression(self, tmo, comp_options, cb, cbe):
 | 
			
		||||
		r = RequestEntry(
 | 
			
		||||
			tmo, LvVdoPool._enable_disable_compression,
 | 
			
		||||
			(self.Uuid, self.lvm_id, False, comp_options),
 | 
			
		||||
			cb, cbe, False)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _enable_disable_deduplication(pool_uuid, pool_name, enable, dedup_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		LvCommon.validate_dbus_object(pool_uuid, pool_name)
 | 
			
		||||
		# Rename the logical volume
 | 
			
		||||
		LvCommon.handle_execute(*cmdhandler.lv_vdo_deduplication(
 | 
			
		||||
			pool_name, enable, dedup_options))
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
		dbus_interface=VDO_POOL_INTERFACE,
 | 
			
		||||
		in_signature='ia{sv}',
 | 
			
		||||
		out_signature='o',
 | 
			
		||||
		async_callbacks=('cb', 'cbe'))
 | 
			
		||||
	def EnableDeduplication(self, tmo, dedup_options, cb, cbe):
 | 
			
		||||
		r = RequestEntry(
 | 
			
		||||
			tmo, LvVdoPool._enable_disable_deduplication,
 | 
			
		||||
			(self.Uuid, self.lvm_id, True, dedup_options),
 | 
			
		||||
			cb, cbe, False)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
	dbus_interface=VDO_POOL_INTERFACE,
 | 
			
		||||
	in_signature='ia{sv}',
 | 
			
		||||
	out_signature='o',
 | 
			
		||||
	async_callbacks=('cb', 'cbe'))
 | 
			
		||||
	def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
 | 
			
		||||
		r = RequestEntry(
 | 
			
		||||
			tmo, LvVdoPool._enable_disable_deduplication,
 | 
			
		||||
			(self.Uuid, self.lvm_id, False, dedup_options),
 | 
			
		||||
			cb, cbe, False)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# noinspection PyPep8Naming
 | 
			
		||||
class LvThinPool(Lv):
 | 
			
		||||
@@ -912,8 +678,10 @@ class LvThinPool(Lv):
 | 
			
		||||
	def _lv_create(lv_uuid, lv_name, name, size_bytes, create_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
 | 
			
		||||
		LvCommon.handle_execute(*cmdhandler.lv_lv_create(
 | 
			
		||||
			lv_name, create_options, name, size_bytes))
 | 
			
		||||
 | 
			
		||||
		rc, out, err = cmdhandler.lv_lv_create(
 | 
			
		||||
			lv_name, create_options, name, size_bytes)
 | 
			
		||||
		LvCommon.handle_execute(rc, out, err)
 | 
			
		||||
		full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
 | 
			
		||||
		return cfg.om.get_object_path_by_lvm_id(full_name)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -220,10 +220,7 @@ class LVMShellProxy(object):
 | 
			
		||||
 | 
			
		||||
		# 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'):
 | 
			
		||||
			if report_json['log'][-1:][0]['log_ret_code'] == '1':
 | 
			
		||||
				rc = 0
 | 
			
		||||
			else:
 | 
			
		||||
				error_msg = self.get_error_msg()
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ from lvmdbusd.utils import log_debug, log_error
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DataStore(object):
 | 
			
		||||
	def __init__(self, usejson=True, vdo_support=False):
 | 
			
		||||
	def __init__(self, usejson=True):
 | 
			
		||||
		self.pvs = {}
 | 
			
		||||
		self.vgs = {}
 | 
			
		||||
		self.lvs = {}
 | 
			
		||||
@@ -43,8 +43,6 @@ class DataStore(object):
 | 
			
		||||
		else:
 | 
			
		||||
			self.json = usejson
 | 
			
		||||
 | 
			
		||||
		self.vdo_support = vdo_support
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _insert_record(table, key, record, allowed_multiple):
 | 
			
		||||
		if key in table:
 | 
			
		||||
@@ -143,22 +141,13 @@ class DataStore(object):
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _parse_vgs(_vgs):
 | 
			
		||||
		vgs = sorted(_vgs, key=lambda vk: vk['vg_uuid'])
 | 
			
		||||
		vgs = sorted(_vgs, key=lambda vk: vk['vg_name'])
 | 
			
		||||
 | 
			
		||||
		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']
 | 
			
		||||
			c_lookup[i['vg_name']] = i['vg_uuid']
 | 
			
		||||
			DataStore._insert_record(c_vgs, i['vg_uuid'], i, [])
 | 
			
		||||
 | 
			
		||||
		return c_vgs, c_lookup
 | 
			
		||||
@@ -173,22 +162,13 @@ class DataStore(object):
 | 
			
		||||
				tmp_vg.extend(r['vg'])
 | 
			
		||||
 | 
			
		||||
		# Sort for consistent output, however this is optional
 | 
			
		||||
		vgs = sorted(tmp_vg, key=lambda vk: vk['vg_uuid'])
 | 
			
		||||
		vgs = sorted(tmp_vg, key=lambda vk: vk['vg_name'])
 | 
			
		||||
 | 
			
		||||
		c_vgs = OrderedDict()
 | 
			
		||||
		c_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']
 | 
			
		||||
			c_lookup[i['vg_name']] = i['vg_uuid']
 | 
			
		||||
			c_vgs[i['vg_uuid']] = i
 | 
			
		||||
 | 
			
		||||
		return c_vgs, c_lookup
 | 
			
		||||
@@ -243,7 +223,8 @@ class DataStore(object):
 | 
			
		||||
 | 
			
		||||
		return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
 | 
			
		||||
 | 
			
		||||
	def _parse_lvs_json(self, _all):
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _parse_lvs_json(_all):
 | 
			
		||||
 | 
			
		||||
		c_lvs = OrderedDict()
 | 
			
		||||
		c_lv_full_lookup = {}
 | 
			
		||||
@@ -263,13 +244,8 @@ class DataStore(object):
 | 
			
		||||
				if 'seg' in r:
 | 
			
		||||
					for s in r['seg']:
 | 
			
		||||
						r = c_lvs[s['lv_uuid']]
 | 
			
		||||
						r.setdefault('seg_pe_ranges', []).\
 | 
			
		||||
							append(s['seg_pe_ranges'])
 | 
			
		||||
						r.setdefault('seg_pe_ranges', []).append(s['seg_pe_ranges'])
 | 
			
		||||
						r.setdefault('segtype', []).append(s['segtype'])
 | 
			
		||||
						if self.vdo_support:
 | 
			
		||||
							for seg_key, seg_val in s.items():
 | 
			
		||||
								if seg_key.startswith("vdo_"):
 | 
			
		||||
									r[seg_key] = seg_val
 | 
			
		||||
 | 
			
		||||
		return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
 | 
			
		||||
 | 
			
		||||
@@ -545,10 +521,6 @@ if __name__ == "__main__":
 | 
			
		||||
	for v in ds.vgs.values():
 | 
			
		||||
		pp.pprint(v)
 | 
			
		||||
 | 
			
		||||
	print("VG name to UUID")
 | 
			
		||||
	for k, v in ds.vg_name_to_uuid.items():
 | 
			
		||||
		print("%s: %s" % (k, v))
 | 
			
		||||
 | 
			
		||||
	print("LVS")
 | 
			
		||||
	for v in ds.lvs.values():
 | 
			
		||||
		pp.pprint(v)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ from .utils import log_debug, log_error
 | 
			
		||||
import argparse
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
from .cmdhandler import LvmFlightRecorder, supports_vdo
 | 
			
		||||
from .cmdhandler import LvmFlightRecorder
 | 
			
		||||
from .request import RequestEntry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -44,10 +44,10 @@ def process_request():
 | 
			
		||||
		try:
 | 
			
		||||
			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)))
 | 
			
		||||
				"Running method: %s with args %s" %
 | 
			
		||||
				(str(req.method), str(req.arguments)))
 | 
			
		||||
			req.run_cmd()
 | 
			
		||||
			log_debug("Method complete: %s" % str(req.method))
 | 
			
		||||
			log_debug("Method complete ")
 | 
			
		||||
		except queue.Empty:
 | 
			
		||||
			pass
 | 
			
		||||
		except Exception:
 | 
			
		||||
@@ -127,14 +127,6 @@ def main():
 | 
			
		||||
		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 = []
 | 
			
		||||
 | 
			
		||||
@@ -155,12 +147,12 @@ def main():
 | 
			
		||||
	cfg.om = Lvm(BASE_OBJ_PATH)
 | 
			
		||||
	cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
 | 
			
		||||
 | 
			
		||||
	cfg.db = lvmdb.DataStore(cfg.args.use_json, cfg.vdo_support)
 | 
			
		||||
	cfg.db = lvmdb.DataStore(cfg.args.use_json)
 | 
			
		||||
 | 
			
		||||
	# 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'))
 | 
			
		||||
	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
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ class Manager(AutomatedProperties):
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def Version(self):
 | 
			
		||||
		return dbus.String('1.1.0')
 | 
			
		||||
		return dbus.String('1.0.0')
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def handle_execute(rc, out, err):
 | 
			
		||||
@@ -107,10 +107,10 @@ class Manager(AutomatedProperties):
 | 
			
		||||
		rc = cfg.load(log=False)
 | 
			
		||||
 | 
			
		||||
		if rc != 0:
 | 
			
		||||
			utils.log_debug('Manager.Refresh - exit %d %d' % (rc, lc),
 | 
			
		||||
			utils.log_debug('Manager.Refresh - exit %d' % (rc),
 | 
			
		||||
							'bg_black', 'fg_light_red')
 | 
			
		||||
		else:
 | 
			
		||||
			utils.log_debug('Manager.Refresh - exit %d %d' % (rc, lc))
 | 
			
		||||
			utils.log_debug('Manager.Refresh - exit %d' % (rc))
 | 
			
		||||
		return rc + lc
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -164,8 +164,6 @@ class Manager(AutomatedProperties):
 | 
			
		||||
		return the object path in O(1) time.
 | 
			
		||||
 | 
			
		||||
		:param key: The lookup value
 | 
			
		||||
		:param cb:	dbus python call back parameter, not client visible
 | 
			
		||||
		:param cbe:	dbus python error call back parameter, not client visible
 | 
			
		||||
		:return: Return the object path.  If object not found you will get '/'
 | 
			
		||||
		"""
 | 
			
		||||
		r = RequestEntry(-1, Manager._lookup_by_lvm_id, (key,), cb, cbe, False)
 | 
			
		||||
 
 | 
			
		||||
@@ -189,8 +189,8 @@ class ObjectManager(AutomatedProperties):
 | 
			
		||||
			path = dbus_object.dbus_object_path()
 | 
			
		||||
			interfaces = dbus_object.interface()
 | 
			
		||||
 | 
			
		||||
			# print('UN-Registering object path %s for %s' %
 | 
			
		||||
			#		(path, dbus_object.lvm_id))
 | 
			
		||||
			# print 'UN-Registering object path %s for %s' % \
 | 
			
		||||
			#      (path, dbus_object.lvm_id)
 | 
			
		||||
 | 
			
		||||
			self._lookup_remove(path)
 | 
			
		||||
 | 
			
		||||
@@ -240,19 +240,39 @@ class ObjectManager(AutomatedProperties):
 | 
			
		||||
				return lookup_rc
 | 
			
		||||
			return '/'
 | 
			
		||||
 | 
			
		||||
	def _id_verify(self, path, uuid, lvm_id):
 | 
			
		||||
	def _uuid_verify(self, path, uuid, lvm_id):
 | 
			
		||||
		"""
 | 
			
		||||
		Ensure our lookups are correct
 | 
			
		||||
		Ensure uuid is present for a successful lvm_id lookup
 | 
			
		||||
		NOTE: Internal call, assumes under object manager lock
 | 
			
		||||
		:param path: 		Path to object we looked up
 | 
			
		||||
		:param uuid: 		uuid lookup
 | 
			
		||||
		:param lvm_id:		lvm_id lookup
 | 
			
		||||
		:param uuid: 		lvm uuid to verify
 | 
			
		||||
		:param lvm_id:		lvm_id used to find object
 | 
			
		||||
		:return: None
 | 
			
		||||
		"""
 | 
			
		||||
		# There is no durable non-changeable name in lvm
 | 
			
		||||
		# This gets called when we found an object based on lvm_id, ensure
 | 
			
		||||
		# uuid is correct too, as they can change. There is no durable
 | 
			
		||||
		# non-changeable name in lvm
 | 
			
		||||
		if lvm_id != uuid:
 | 
			
		||||
			obj = self.get_object_by_path(path)
 | 
			
		||||
			self._lookup_add(obj, path, lvm_id, uuid)
 | 
			
		||||
			if uuid and uuid not in self._id_to_object_path:
 | 
			
		||||
				obj = self.get_object_by_path(path)
 | 
			
		||||
				self._lookup_add(obj, path, lvm_id, uuid)
 | 
			
		||||
 | 
			
		||||
	def _lvm_id_verify(self, path, uuid, lvm_id):
 | 
			
		||||
		"""
 | 
			
		||||
		Ensure lvm_id is present for a successful uuid lookup
 | 
			
		||||
		NOTE: Internal call, assumes under object manager lock
 | 
			
		||||
		:param path: 		Path to object we looked up
 | 
			
		||||
		:param uuid: 		uuid used to find object
 | 
			
		||||
		:param lvm_id:		lvm_id to verify
 | 
			
		||||
		:return: None
 | 
			
		||||
		"""
 | 
			
		||||
		# This gets called when we found an object based on uuid, ensure
 | 
			
		||||
		# lvm_id is correct too, as they can change.  There is no durable
 | 
			
		||||
		# non-changeable name in lvm
 | 
			
		||||
		if lvm_id != uuid:
 | 
			
		||||
			if lvm_id and lvm_id not in self._id_to_object_path:
 | 
			
		||||
				obj = self.get_object_by_path(path)
 | 
			
		||||
				self._lookup_add(obj, path, lvm_id, uuid)
 | 
			
		||||
 | 
			
		||||
	def _id_lookup(self, the_id):
 | 
			
		||||
		path = None
 | 
			
		||||
@@ -319,22 +339,22 @@ class ObjectManager(AutomatedProperties):
 | 
			
		||||
				# Lets check for the uuid first
 | 
			
		||||
				path = self._id_lookup(uuid)
 | 
			
		||||
				if path:
 | 
			
		||||
					# Ensure table lookups are correct
 | 
			
		||||
					self._id_verify(path, uuid, lvm_id)
 | 
			
		||||
					# Verify the lvm_id is sane
 | 
			
		||||
					self._lvm_id_verify(path, uuid, lvm_id)
 | 
			
		||||
				else:
 | 
			
		||||
					# Unable to find by UUID, lets lookup by lvm_id
 | 
			
		||||
					path = self._id_lookup(lvm_id)
 | 
			
		||||
					if path:
 | 
			
		||||
						# Ensure table lookups are correct
 | 
			
		||||
						self._id_verify(path, uuid, lvm_id)
 | 
			
		||||
						# Verify the uuid is sane
 | 
			
		||||
						self._uuid_verify(path, uuid, lvm_id)
 | 
			
		||||
					else:
 | 
			
		||||
						# We have exhausted all lookups, let's create if we can
 | 
			
		||||
						if path_create:
 | 
			
		||||
							path = path_create()
 | 
			
		||||
							self._lookup_add(None, path, lvm_id, uuid)
 | 
			
		||||
 | 
			
		||||
			# print('get_object_path_by_lvm_id(%s, %s, %s): return %s' %
 | 
			
		||||
			#	(uuid, lvm_id, str(path_create), path))
 | 
			
		||||
			# print('get_object_path_by_lvm_id(%s, %s, %s, %s: return %s' %
 | 
			
		||||
			# 	   (uuid, lvm_id, str(path_create), str(gen_new), path))
 | 
			
		||||
 | 
			
		||||
			return path
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ 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
 | 
			
		||||
	lv_object_path_method
 | 
			
		||||
from .loader import common
 | 
			
		||||
from .request import RequestEntry
 | 
			
		||||
from .state import State
 | 
			
		||||
@@ -138,12 +138,19 @@ class Pv(AutomatedProperties):
 | 
			
		||||
		# Remove the PV, if successful then remove from the model
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Pv.validate_dbus_object(pv_uuid, pv_name)
 | 
			
		||||
		Pv.handle_execute(*cmdhandler.pv_remove(pv_name, remove_options))
 | 
			
		||||
		rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
 | 
			
		||||
		Pv.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def handle_execute(rc, out, err):
 | 
			
		||||
		return _handle_execute(rc, out, err, PV_INTERFACE)
 | 
			
		||||
		if rc == 0:
 | 
			
		||||
			cfg.load()
 | 
			
		||||
		else:
 | 
			
		||||
			# Need to work on error handling, need consistent
 | 
			
		||||
			raise dbus.exceptions.DBusException(
 | 
			
		||||
				PV_INTERFACE,
 | 
			
		||||
				'Exit code %s, stderr = %s' % (str(rc), err))
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def validate_dbus_object(pv_uuid, pv_name):
 | 
			
		||||
@@ -171,8 +178,10 @@ class Pv(AutomatedProperties):
 | 
			
		||||
	def _resize(pv_uuid, pv_name, new_size_bytes, resize_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Pv.validate_dbus_object(pv_uuid, pv_name)
 | 
			
		||||
		Pv.handle_execute(*cmdhandler.pv_resize(pv_name, new_size_bytes,
 | 
			
		||||
												resize_options))
 | 
			
		||||
 | 
			
		||||
		rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
 | 
			
		||||
												resize_options)
 | 
			
		||||
		Pv.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -191,8 +200,9 @@ class Pv(AutomatedProperties):
 | 
			
		||||
	def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Pv.validate_dbus_object(pv_uuid, pv_name)
 | 
			
		||||
		Pv.handle_execute(*cmdhandler.pv_allocatable(pv_name, yes_no,
 | 
			
		||||
														allocation_options))
 | 
			
		||||
		rc, out, err = cmdhandler.pv_allocatable(
 | 
			
		||||
			pv_name, yes_no, allocation_options)
 | 
			
		||||
		Pv.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
 
 | 
			
		||||
@@ -26,15 +26,6 @@ import signal
 | 
			
		||||
STDOUT_TTY = os.isatty(sys.stdout.fileno())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _handle_execute(rc, out, err, interface):
 | 
			
		||||
	if rc == 0:
 | 
			
		||||
		cfg.load()
 | 
			
		||||
	else:
 | 
			
		||||
		# Need to work on error handling, need consistent
 | 
			
		||||
		raise dbus.exceptions.DBusException(
 | 
			
		||||
			interface, 'Exit code %s, stderr = %s' % (str(rc), err))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def rtype(dbus_type):
 | 
			
		||||
	"""
 | 
			
		||||
	Decorator making sure that the decorated function returns a value of
 | 
			
		||||
@@ -66,20 +57,8 @@ def n32(v):
 | 
			
		||||
	return int(float(v))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@rtype(dbus.Double)
 | 
			
		||||
def d(v):
 | 
			
		||||
	if not v:
 | 
			
		||||
		return 0.0
 | 
			
		||||
	return float(v)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _snake_to_pascal(s):
 | 
			
		||||
	return ''.join(x.title() for x in s.split('_'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# noinspection PyProtectedMember
 | 
			
		||||
def init_class_from_arguments(
 | 
			
		||||
		obj_instance, begin_suffix=None, snake_to_pascal=False):
 | 
			
		||||
def init_class_from_arguments(obj_instance):
 | 
			
		||||
	for k, v in list(sys._getframe(1).f_locals.items()):
 | 
			
		||||
		if k != 'self':
 | 
			
		||||
			nt = k
 | 
			
		||||
@@ -90,17 +69,8 @@ def init_class_from_arguments(
 | 
			
		||||
			cur = getattr(obj_instance, nt, v)
 | 
			
		||||
 | 
			
		||||
			# print 'Init class %s = %s' % (nt, str(v))
 | 
			
		||||
			if not (cur and len(str(cur)) and (v is None or len(str(v))) == 0)\
 | 
			
		||||
					and (begin_suffix is None or nt.startswith(begin_suffix)):
 | 
			
		||||
 | 
			
		||||
				if begin_suffix and nt.startswith(begin_suffix):
 | 
			
		||||
					name = nt[len(begin_suffix):]
 | 
			
		||||
					if snake_to_pascal:
 | 
			
		||||
						name = _snake_to_pascal(name)
 | 
			
		||||
 | 
			
		||||
					setattr(obj_instance, name, v)
 | 
			
		||||
				else:
 | 
			
		||||
					setattr(obj_instance, nt, v)
 | 
			
		||||
			if not (cur and len(str(cur)) and (v is None or len(str(v))) == 0):
 | 
			
		||||
				setattr(obj_instance, nt, v)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_properties(f):
 | 
			
		||||
@@ -368,8 +338,6 @@ def lv_object_path_method(name, meta):
 | 
			
		||||
		return _hidden_lv_obj_path_generate
 | 
			
		||||
	elif meta[0][0] == 't':
 | 
			
		||||
		return _thin_pool_obj_path_generate
 | 
			
		||||
	elif meta[0][0] == 'd':
 | 
			
		||||
		return _vdo_pool_object_path_generate
 | 
			
		||||
	elif meta[0][0] == 'C' and 'pool' in meta[1]:
 | 
			
		||||
		return _cache_pool_obj_path_generate
 | 
			
		||||
 | 
			
		||||
@@ -387,10 +355,6 @@ def _thin_pool_obj_path_generate():
 | 
			
		||||
	return cfg.THIN_POOL_PATH + "/%d" % next(cfg.thin_id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _vdo_pool_object_path_generate():
 | 
			
		||||
	return cfg.VDO_POOL_PATH + "/%d" % next(cfg.vdo_id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _cache_pool_obj_path_generate():
 | 
			
		||||
	return cfg.CACHE_POOL_PATH + "/%d" % next(cfg.cache_pool_id)
 | 
			
		||||
 | 
			
		||||
@@ -482,7 +446,7 @@ _ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
 | 
			
		||||
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
 | 
			
		||||
_ALLOWABLE_VG_LV_CH_SET = set(_ALLOWABLE_VG_LV_CH)
 | 
			
		||||
_LV_NAME_RESERVED = ("_cdata", "_cmeta", "_corig", "_mimage", "_mlog",
 | 
			
		||||
	"_pmspare", "_rimage", "_rmeta", "_tdata", "_tmeta", "_vorigin", "_vdata")
 | 
			
		||||
	"_pmspare", "_rimage", "_rmeta", "_tdata", "_tmeta", "_vorigin")
 | 
			
		||||
 | 
			
		||||
# Tags can have the characters, based on the code
 | 
			
		||||
# a-zA-Z0-9._-+/=!:&#
 | 
			
		||||
 
 | 
			
		||||
@@ -10,11 +10,10 @@
 | 
			
		||||
from .automatedproperties import AutomatedProperties
 | 
			
		||||
 | 
			
		||||
from . import utils
 | 
			
		||||
from .utils import pv_obj_path_generate, vg_obj_path_generate, n, \
 | 
			
		||||
	_handle_execute
 | 
			
		||||
from .utils import pv_obj_path_generate, vg_obj_path_generate, n
 | 
			
		||||
import dbus
 | 
			
		||||
from . import cfg
 | 
			
		||||
from .cfg import VG_INTERFACE, VG_VDO_INTERFACE
 | 
			
		||||
from .cfg import VG_INTERFACE
 | 
			
		||||
from . import cmdhandler
 | 
			
		||||
from .request import RequestEntry
 | 
			
		||||
from .loader import common
 | 
			
		||||
@@ -47,29 +46,24 @@ def vgs_state_retrieve(selection, cache_refresh=True):
 | 
			
		||||
 | 
			
		||||
def load_vgs(vg_specific=None, object_path=None, refresh=False,
 | 
			
		||||
		emit_signal=False, cache_refresh=True):
 | 
			
		||||
	return common(vgs_state_retrieve, (Vg, VgVdo, ), vg_specific, object_path, refresh,
 | 
			
		||||
	return common(vgs_state_retrieve, (Vg,), vg_specific, object_path, refresh,
 | 
			
		||||
					emit_signal, cache_refresh)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
 | 
			
		||||
class VgState(State):
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def internal_name(self):
 | 
			
		||||
		return self.Name
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def lvm_id(self):
 | 
			
		||||
		return self.internal_name
 | 
			
		||||
		return self.Name
 | 
			
		||||
 | 
			
		||||
	def identifiers(self):
 | 
			
		||||
		return (self.Uuid, self.internal_name)
 | 
			
		||||
		return (self.Uuid, self.Name)
 | 
			
		||||
 | 
			
		||||
	def _lv_paths_build(self):
 | 
			
		||||
		rc = []
 | 
			
		||||
		for lv in cfg.db.lvs_in_vg(self.Uuid):
 | 
			
		||||
			(lv_name, meta, lv_uuid) = lv
 | 
			
		||||
			full_name = "%s/%s" % (self.internal_name, lv_name)
 | 
			
		||||
			full_name = "%s/%s" % (self.Name, lv_name)
 | 
			
		||||
 | 
			
		||||
			gen = utils.lv_object_path_method(lv_name, meta)
 | 
			
		||||
 | 
			
		||||
@@ -98,12 +92,8 @@ class VgState(State):
 | 
			
		||||
	def create_dbus_object(self, path):
 | 
			
		||||
		if not path:
 | 
			
		||||
			path = cfg.om.get_object_path_by_uuid_lvm_id(
 | 
			
		||||
				self.Uuid, self.internal_name, vg_obj_path_generate)
 | 
			
		||||
 | 
			
		||||
		if cfg.vdo_support:
 | 
			
		||||
			return VgVdo(path, self)
 | 
			
		||||
		else:
 | 
			
		||||
			return Vg(path, self)
 | 
			
		||||
				self.Uuid, self.Name, vg_obj_path_generate)
 | 
			
		||||
		return Vg(path, self)
 | 
			
		||||
 | 
			
		||||
	# noinspection PyMethodMayBeStatic
 | 
			
		||||
	def creation_signature(self):
 | 
			
		||||
@@ -112,6 +102,7 @@ class VgState(State):
 | 
			
		||||
 | 
			
		||||
# noinspection PyPep8Naming
 | 
			
		||||
@utils.dbus_property(VG_INTERFACE, 'Uuid', 's')
 | 
			
		||||
@utils.dbus_property(VG_INTERFACE, 'Name', 's')
 | 
			
		||||
@utils.dbus_property(VG_INTERFACE, 'Fmt', 's')
 | 
			
		||||
@utils.dbus_property(VG_INTERFACE, 'SizeBytes', 't', 0)
 | 
			
		||||
@utils.dbus_property(VG_INTERFACE, 'FreeBytes', 't', 0)
 | 
			
		||||
@@ -144,7 +135,6 @@ class Vg(AutomatedProperties):
 | 
			
		||||
	_AllocNormal_meta = ('b', VG_INTERFACE)
 | 
			
		||||
	_AllocAnywhere_meta = ('b', VG_INTERFACE)
 | 
			
		||||
	_Clustered_meta = ('b', VG_INTERFACE)
 | 
			
		||||
	_Name_meta = ('s', VG_INTERFACE)
 | 
			
		||||
 | 
			
		||||
	# noinspection PyUnusedLocal,PyPep8Naming
 | 
			
		||||
	def __init__(self, object_path, object_state):
 | 
			
		||||
@@ -159,7 +149,13 @@ class Vg(AutomatedProperties):
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def handle_execute(rc, out, err):
 | 
			
		||||
		return _handle_execute(rc, out, err, VG_INTERFACE)
 | 
			
		||||
		if rc == 0:
 | 
			
		||||
			cfg.load()
 | 
			
		||||
		else:
 | 
			
		||||
			# Need to work on error handling, need consistent
 | 
			
		||||
			raise dbus.exceptions.DBusException(
 | 
			
		||||
				VG_INTERFACE,
 | 
			
		||||
				'Exit code %s, stderr = %s' % (str(rc), err))
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def validate_dbus_object(vg_uuid, vg_name):
 | 
			
		||||
@@ -175,8 +171,9 @@ class Vg(AutomatedProperties):
 | 
			
		||||
	def _rename(uuid, vg_name, new_name, rename_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_rename(
 | 
			
		||||
			uuid, new_name, rename_options))
 | 
			
		||||
		rc, out, err = cmdhandler.vg_rename(
 | 
			
		||||
			vg_name, new_name, rename_options)
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -195,7 +192,8 @@ class Vg(AutomatedProperties):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
		# Remove the VG, if successful then remove from the model
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_remove(vg_name, remove_options))
 | 
			
		||||
		rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -211,13 +209,14 @@ class Vg(AutomatedProperties):
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _change(uuid, vg_name, change_options):
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_change(change_options, vg_name))
 | 
			
		||||
		rc, out, err = cmdhandler.vg_change(change_options, vg_name)
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	# TODO: This should be broken into a number of different methods
 | 
			
		||||
	# instead of having one method that takes a hash for parameters.  Some of
 | 
			
		||||
	# the changes that vgchange does works on entire system, not just a
 | 
			
		||||
	# specific vg, thus that should be in the Manager interface.
 | 
			
		||||
	# specfic vg, thus that should be in the Manager interface.
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
		dbus_interface=VG_INTERFACE,
 | 
			
		||||
		in_signature='ia{sv}',
 | 
			
		||||
@@ -247,8 +246,9 @@ class Vg(AutomatedProperties):
 | 
			
		||||
						VG_INTERFACE,
 | 
			
		||||
						'PV Object path not found = %s!' % pv_op)
 | 
			
		||||
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_reduce(
 | 
			
		||||
			vg_name, missing, pv_devices, reduce_options))
 | 
			
		||||
		rc, out, err = cmdhandler.vg_reduce(vg_name, missing, pv_devices,
 | 
			
		||||
											reduce_options)
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -278,8 +278,9 @@ class Vg(AutomatedProperties):
 | 
			
		||||
					VG_INTERFACE, 'PV Object path not found = %s!' % i)
 | 
			
		||||
 | 
			
		||||
		if len(extend_devices):
 | 
			
		||||
			Vg.handle_execute(*cmdhandler.vg_extend(
 | 
			
		||||
				vg_name, extend_devices, extend_options))
 | 
			
		||||
			rc, out, err = cmdhandler.vg_extend(vg_name, extend_devices,
 | 
			
		||||
												extend_options)
 | 
			
		||||
			Vg.handle_execute(rc, out, err)
 | 
			
		||||
		else:
 | 
			
		||||
			raise dbus.exceptions.DBusException(
 | 
			
		||||
				VG_INTERFACE, 'No pv_object_paths provided!')
 | 
			
		||||
@@ -333,8 +334,10 @@ class Vg(AutomatedProperties):
 | 
			
		||||
 | 
			
		||||
				pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
 | 
			
		||||
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_lv_create(
 | 
			
		||||
			vg_name, create_options, name, size_bytes, pv_dests))
 | 
			
		||||
		rc, out, err = cmdhandler.vg_lv_create(
 | 
			
		||||
			vg_name, create_options, name, size_bytes, pv_dests)
 | 
			
		||||
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return Vg.fetch_new_lv(vg_name, name)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -372,8 +375,11 @@ class Vg(AutomatedProperties):
 | 
			
		||||
			thin_pool, create_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_lv_create_linear(
 | 
			
		||||
			vg_name, create_options, name, size_bytes, thin_pool))
 | 
			
		||||
 | 
			
		||||
		rc, out, err = cmdhandler.vg_lv_create_linear(
 | 
			
		||||
			vg_name, create_options, name, size_bytes, thin_pool)
 | 
			
		||||
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return Vg.fetch_new_lv(vg_name, name)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -395,9 +401,10 @@ class Vg(AutomatedProperties):
 | 
			
		||||
			stripe_size_kb, thin_pool, create_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_lv_create_striped(
 | 
			
		||||
		rc, out, err = cmdhandler.vg_lv_create_striped(
 | 
			
		||||
			vg_name, create_options, name, size_bytes,
 | 
			
		||||
			num_stripes, stripe_size_kb, thin_pool))
 | 
			
		||||
			num_stripes, stripe_size_kb, thin_pool)
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return Vg.fetch_new_lv(vg_name, name)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -422,8 +429,9 @@ class Vg(AutomatedProperties):
 | 
			
		||||
			num_copies, create_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_lv_create_mirror(
 | 
			
		||||
			vg_name, create_options, name, size_bytes, num_copies))
 | 
			
		||||
		rc, out, err = cmdhandler.vg_lv_create_mirror(
 | 
			
		||||
			vg_name, create_options, name, size_bytes, num_copies)
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return Vg.fetch_new_lv(vg_name, name)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -446,9 +454,10 @@ class Vg(AutomatedProperties):
 | 
			
		||||
						num_stripes, stripe_size_kb, create_options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_lv_create_raid(
 | 
			
		||||
		rc, out, err = cmdhandler.vg_lv_create_raid(
 | 
			
		||||
			vg_name, create_options, name, raid_type, size_bytes,
 | 
			
		||||
			num_stripes, stripe_size_kb))
 | 
			
		||||
			num_stripes, stripe_size_kb)
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return Vg.fetch_new_lv(vg_name, name)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -546,8 +555,9 @@ class Vg(AutomatedProperties):
 | 
			
		||||
				raise dbus.exceptions.DBusException(
 | 
			
		||||
					VG_INTERFACE, 'PV object path = %s not found' % p)
 | 
			
		||||
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.pv_tag(
 | 
			
		||||
			pv_devices, tags_add, tags_del, tag_options))
 | 
			
		||||
		rc, out, err = cmdhandler.pv_tag(
 | 
			
		||||
			pv_devices, tags_add, tags_del, tag_options)
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -588,8 +598,9 @@ class Vg(AutomatedProperties):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_tag(
 | 
			
		||||
			vg_name, tags_add, tags_del, tag_options))
 | 
			
		||||
		rc, out, err = cmdhandler.vg_tag(
 | 
			
		||||
			vg_name, tags_add, tags_del, tag_options)
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -628,7 +639,8 @@ class Vg(AutomatedProperties):
 | 
			
		||||
	def _vg_change_set(uuid, vg_name, method, value, options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
		Vg.handle_execute(*method(vg_name, value, options))
 | 
			
		||||
		rc, out, err = method(vg_name, value, options)
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -688,8 +700,9 @@ class Vg(AutomatedProperties):
 | 
			
		||||
								options):
 | 
			
		||||
		# Make sure we have a dbus object representing it
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.activate_deactivate(
 | 
			
		||||
			'vgchange', vg_name, activate, control_flags, options))
 | 
			
		||||
		rc, out, err = cmdhandler.activate_deactivate(
 | 
			
		||||
			'vgchange', vg_name, activate, control_flags, options)
 | 
			
		||||
		Vg.handle_execute(rc, out, err)
 | 
			
		||||
		return '/'
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
@@ -716,12 +729,6 @@ class Vg(AutomatedProperties):
 | 
			
		||||
				cb, cbe, return_tuple=False)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def Name(self):
 | 
			
		||||
		if ':' in self.state.Name:
 | 
			
		||||
			return self.state.Name.split(':')[0]
 | 
			
		||||
		return self.state.Name
 | 
			
		||||
 | 
			
		||||
	@property
 | 
			
		||||
	def Tags(self):
 | 
			
		||||
		return utils.parse_tags(self.state.tags)
 | 
			
		||||
@@ -777,71 +784,3 @@ class Vg(AutomatedProperties):
 | 
			
		||||
	@property
 | 
			
		||||
	def Clustered(self):
 | 
			
		||||
		return self._attribute(5, 'c')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VgVdo(Vg):
 | 
			
		||||
 | 
			
		||||
	# noinspection PyUnusedLocal,PyPep8Naming
 | 
			
		||||
	def __init__(self, object_path, object_state):
 | 
			
		||||
		super(VgVdo, self).__init__(object_path, vgs_state_retrieve)
 | 
			
		||||
		self.set_interface(VG_VDO_INTERFACE)
 | 
			
		||||
		self._object_path = object_path
 | 
			
		||||
		self.state = object_state
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _lv_vdo_pool_create_with_lv(uuid, vg_name, pool_name, lv_name,
 | 
			
		||||
									data_size, virtual_size, create_options):
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_create_vdo_pool_lv_and_lv(
 | 
			
		||||
			vg_name, pool_name, lv_name, data_size, virtual_size,
 | 
			
		||||
			create_options))
 | 
			
		||||
		return Vg.fetch_new_lv(vg_name, pool_name)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
		dbus_interface=VG_VDO_INTERFACE,
 | 
			
		||||
		in_signature='ssttia{sv}',
 | 
			
		||||
		out_signature='(oo)',
 | 
			
		||||
		async_callbacks=('cb', 'cbe'))
 | 
			
		||||
	def CreateVdoPoolandLv(self, pool_name, lv_name, data_size, virtual_size,
 | 
			
		||||
							tmo, create_options, cb, cbe):
 | 
			
		||||
		utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, pool_name)
 | 
			
		||||
		utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, lv_name)
 | 
			
		||||
 | 
			
		||||
		r = RequestEntry(tmo, VgVdo._lv_vdo_pool_create_with_lv,
 | 
			
		||||
							(self.state.Uuid, self.state.lvm_id,
 | 
			
		||||
							pool_name, lv_name, round_size(data_size),
 | 
			
		||||
							round_size(virtual_size),
 | 
			
		||||
							create_options), cb, cbe)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 | 
			
		||||
	@staticmethod
 | 
			
		||||
	def _vdo_pool_create(uuid, vg_name, pool_lv, name, virtual_size, create_options):
 | 
			
		||||
		Vg.validate_dbus_object(uuid, vg_name)
 | 
			
		||||
 | 
			
		||||
		# Retrieve the full name of the pool lv
 | 
			
		||||
		pool = cfg.om.get_object_by_path(pool_lv)
 | 
			
		||||
		if not pool:
 | 
			
		||||
			msg = 'LV with object path %s not present!' % \
 | 
			
		||||
					(pool_lv)
 | 
			
		||||
			raise dbus.exceptions.DBusException(VG_VDO_INTERFACE, msg)
 | 
			
		||||
 | 
			
		||||
		Vg.handle_execute(*cmdhandler.vg_create_vdo_pool(
 | 
			
		||||
			pool.lv_full_name(), name, virtual_size,
 | 
			
		||||
			create_options))
 | 
			
		||||
		return Vg.fetch_new_lv(vg_name, pool.Name)
 | 
			
		||||
 | 
			
		||||
	@dbus.service.method(
 | 
			
		||||
		dbus_interface=VG_VDO_INTERFACE,
 | 
			
		||||
		in_signature='ostia{sv}',
 | 
			
		||||
		out_signature='(oo)',
 | 
			
		||||
		async_callbacks=('cb', 'cbe'))
 | 
			
		||||
	def CreateVdoPool(self, pool_lv, name, virtual_size,
 | 
			
		||||
						tmo, create_options, cb, cbe):
 | 
			
		||||
		utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, name)
 | 
			
		||||
 | 
			
		||||
		r = RequestEntry(tmo, VgVdo._vdo_pool_create,
 | 
			
		||||
							(self.state.Uuid, self.state.lvm_id,
 | 
			
		||||
							pool_lv, name,
 | 
			
		||||
							round_size(virtual_size),
 | 
			
		||||
							create_options), cb, cbe)
 | 
			
		||||
		cfg.worker_q.put(r)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								daemons/lvmetad/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								daemons/lvmetad/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
lvmetad
 | 
			
		||||
lvmetactl
 | 
			
		||||
							
								
								
									
										62
									
								
								daemons/lvmetad/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								daemons/lvmetad/Makefile.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2011-2012 Red Hat, Inc.
 | 
			
		||||
#
 | 
			
		||||
# This file is part of LVM2.
 | 
			
		||||
#
 | 
			
		||||
# This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
# of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 | 
			
		||||
srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
SOURCES = lvmetad-core.c
 | 
			
		||||
SOURCES2 = lvmetactl.c
 | 
			
		||||
 | 
			
		||||
TARGETS = lvmetad lvmetactl
 | 
			
		||||
 | 
			
		||||
.PHONY: install_lvmetad
 | 
			
		||||
 | 
			
		||||
CFLOW_LIST = $(SOURCES)
 | 
			
		||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
			
		||||
CFLOW_TARGET = lvmetad
 | 
			
		||||
 | 
			
		||||
include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
CFLAGS_lvmetactl.o += $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
CFLAGS_lvmetad-core.o += $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
 | 
			
		||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
 | 
			
		||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
 | 
			
		||||
		    $(top_builddir)/libdaemon/server/libdaemonserver.a
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) -ldaemonserver $(LIBS)
 | 
			
		||||
 | 
			
		||||
lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
 | 
			
		||||
	$(top_builddir)/libdaemon/server/libdaemonserver.a
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LIBS)
 | 
			
		||||
 | 
			
		||||
CLEAN_TARGETS += lvmetactl.o
 | 
			
		||||
 | 
			
		||||
# TODO: No idea. No idea how to test either.
 | 
			
		||||
#ifneq ("$(CFLOW_CMD)", "")
 | 
			
		||||
#CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
 | 
			
		||||
#-include $(top_builddir)/libdm/libdevmapper.cflow
 | 
			
		||||
#-include $(top_builddir)/lib/liblvm-internal.cflow
 | 
			
		||||
#-include $(top_builddir)/lib/liblvm2cmd.cflow
 | 
			
		||||
#-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
 | 
			
		||||
#-include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
install_lvmetad: lvmetad
 | 
			
		||||
	$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_lvmetad
 | 
			
		||||
 | 
			
		||||
install: install_lvm2
 | 
			
		||||
							
								
								
									
										249
									
								
								daemons/lvmetad/lvmetactl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								daemons/lvmetad/lvmetactl.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,249 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2014 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "tool.h"
 | 
			
		||||
 | 
			
		||||
#include "lvmetad-client.h"
 | 
			
		||||
 | 
			
		||||
daemon_handle h;
 | 
			
		||||
 | 
			
		||||
static void print_reply(daemon_reply reply)
 | 
			
		||||
{
 | 
			
		||||
	const char *a = daemon_reply_str(reply, "response", NULL);
 | 
			
		||||
	const char *b = daemon_reply_str(reply, "status", NULL);
 | 
			
		||||
	const char *c = daemon_reply_str(reply, "reason", NULL);
 | 
			
		||||
 | 
			
		||||
	printf("response \"%s\" status \"%s\" reason \"%s\"\n",
 | 
			
		||||
	       a ? a : "", b ? b : "", c ? c : "");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	daemon_reply reply;
 | 
			
		||||
	char *cmd;
 | 
			
		||||
	char *uuid;
 | 
			
		||||
	char *name;
 | 
			
		||||
	int val;
 | 
			
		||||
	int ver;
 | 
			
		||||
 | 
			
		||||
	if (argc < 2) {
 | 
			
		||||
		printf("lvmetactl dump\n");
 | 
			
		||||
		printf("lvmetactl pv_list\n");
 | 
			
		||||
		printf("lvmetactl vg_list\n");
 | 
			
		||||
		printf("lvmetactl get_global_info\n");
 | 
			
		||||
		printf("lvmetactl vg_lookup_name <name>\n");
 | 
			
		||||
		printf("lvmetactl vg_lookup_uuid <uuid>\n");
 | 
			
		||||
		printf("lvmetactl pv_lookup_uuid <uuid>\n");
 | 
			
		||||
		printf("lvmetactl set_global_invalid 0|1\n");
 | 
			
		||||
		printf("lvmetactl set_global_disable 0|1\n");
 | 
			
		||||
		printf("lvmetactl set_vg_version <uuid> <name> <version>\n");
 | 
			
		||||
		printf("lvmetactl vg_lock_type <uuid>\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd = argv[1];
 | 
			
		||||
 | 
			
		||||
	h = lvmetad_open(NULL);
 | 
			
		||||
 | 
			
		||||
	if (!strcmp(cmd, "dump")) {
 | 
			
		||||
		reply = daemon_send_simple(h, "dump",
 | 
			
		||||
					   "token = %s", "skip",
 | 
			
		||||
					   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
					   "cmd = %s", "lvmetactl",
 | 
			
		||||
					   NULL);
 | 
			
		||||
		printf("%s\n", reply.buffer.mem);
 | 
			
		||||
 | 
			
		||||
	} else if (!strcmp(cmd, "pv_list")) {
 | 
			
		||||
		reply = daemon_send_simple(h, "pv_list",
 | 
			
		||||
					   "token = %s", "skip",
 | 
			
		||||
					   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
					   "cmd = %s", "lvmetactl",
 | 
			
		||||
					   NULL);
 | 
			
		||||
		printf("%s\n", reply.buffer.mem);
 | 
			
		||||
 | 
			
		||||
	} else if (!strcmp(cmd, "vg_list")) {
 | 
			
		||||
		reply = daemon_send_simple(h, "vg_list",
 | 
			
		||||
					   "token = %s", "skip",
 | 
			
		||||
					   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
					   "cmd = %s", "lvmetactl",
 | 
			
		||||
					   NULL);
 | 
			
		||||
		printf("%s\n", reply.buffer.mem);
 | 
			
		||||
 | 
			
		||||
	} else if (!strcmp(cmd, "get_global_info")) {
 | 
			
		||||
		reply = daemon_send_simple(h, "get_global_info",
 | 
			
		||||
					   "token = %s", "skip",
 | 
			
		||||
					   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
					   "cmd = %s", "lvmetactl",
 | 
			
		||||
					   NULL);
 | 
			
		||||
		printf("%s\n", reply.buffer.mem);
 | 
			
		||||
 | 
			
		||||
	} else if (!strcmp(cmd, "set_global_invalid")) {
 | 
			
		||||
		if (argc < 3) {
 | 
			
		||||
			printf("set_global_invalid 0|1\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		val = atoi(argv[2]);
 | 
			
		||||
 | 
			
		||||
		reply = daemon_send_simple(h, "set_global_info",
 | 
			
		||||
					   "global_invalid = " FMTd64, (int64_t) val,
 | 
			
		||||
					   "token = %s", "skip",
 | 
			
		||||
					   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
					   "cmd = %s", "lvmetactl",
 | 
			
		||||
					   NULL);
 | 
			
		||||
		print_reply(reply);
 | 
			
		||||
 | 
			
		||||
	} else if (!strcmp(cmd, "set_global_disable")) {
 | 
			
		||||
		if (argc < 3) {
 | 
			
		||||
			printf("set_global_disable 0|1\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		val = atoi(argv[2]);
 | 
			
		||||
 | 
			
		||||
		reply = daemon_send_simple(h, "set_global_info",
 | 
			
		||||
					   "global_disable = " FMTd64, (int64_t) val,
 | 
			
		||||
					   "disable_reason = %s", LVMETAD_DISABLE_REASON_DIRECT,
 | 
			
		||||
					   "token = %s", "skip",
 | 
			
		||||
					   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
					   "cmd = %s", "lvmetactl",
 | 
			
		||||
					   NULL);
 | 
			
		||||
		print_reply(reply);
 | 
			
		||||
 | 
			
		||||
	} else if (!strcmp(cmd, "set_vg_version")) {
 | 
			
		||||
		if (argc < 5) {
 | 
			
		||||
			printf("set_vg_version <uuid> <name> <ver>\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		uuid = argv[2];
 | 
			
		||||
		name = argv[3];
 | 
			
		||||
		ver = atoi(argv[4]);
 | 
			
		||||
 | 
			
		||||
		if ((strlen(uuid) == 1) && (uuid[0] == '-'))
 | 
			
		||||
			uuid = NULL;
 | 
			
		||||
		if ((strlen(name) == 1) && (name[0] == '-'))
 | 
			
		||||
			name = NULL;
 | 
			
		||||
 | 
			
		||||
		if (uuid && name) {
 | 
			
		||||
			reply = daemon_send_simple(h, "set_vg_info",
 | 
			
		||||
						   "uuid = %s", uuid,
 | 
			
		||||
						   "name = %s", name,
 | 
			
		||||
						   "version = " FMTd64, (int64_t) ver,
 | 
			
		||||
						   "token = %s", "skip",
 | 
			
		||||
						   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
						   "cmd = %s", "lvmetactl",
 | 
			
		||||
						   NULL);
 | 
			
		||||
		} else if (uuid) {
 | 
			
		||||
			reply = daemon_send_simple(h, "set_vg_info",
 | 
			
		||||
						   "uuid = %s", uuid,
 | 
			
		||||
						   "version = " FMTd64, (int64_t) ver,
 | 
			
		||||
						   "token = %s", "skip",
 | 
			
		||||
						   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
						   "cmd = %s", "lvmetactl",
 | 
			
		||||
						   NULL);
 | 
			
		||||
		} else if (name) {
 | 
			
		||||
			reply = daemon_send_simple(h, "set_vg_info",
 | 
			
		||||
						   "name = %s", name,
 | 
			
		||||
						   "version = " FMTd64, (int64_t) ver,
 | 
			
		||||
						   "token = %s", "skip",
 | 
			
		||||
						   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
						   "cmd = %s", "lvmetactl",
 | 
			
		||||
						   NULL);
 | 
			
		||||
		} else {
 | 
			
		||||
			printf("name or uuid required\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		print_reply(reply);
 | 
			
		||||
 | 
			
		||||
	} else if (!strcmp(cmd, "vg_lookup_name")) {
 | 
			
		||||
		if (argc < 3) {
 | 
			
		||||
			printf("vg_lookup_name <name>\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		name = argv[2];
 | 
			
		||||
 | 
			
		||||
		reply = daemon_send_simple(h, "vg_lookup",
 | 
			
		||||
					   "name = %s", name,
 | 
			
		||||
					   "token = %s", "skip",
 | 
			
		||||
					   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
					   "cmd = %s", "lvmetactl",
 | 
			
		||||
					   NULL);
 | 
			
		||||
		printf("%s\n", reply.buffer.mem);
 | 
			
		||||
 | 
			
		||||
	} else if (!strcmp(cmd, "vg_lookup_uuid")) {
 | 
			
		||||
		if (argc < 3) {
 | 
			
		||||
			printf("vg_lookup_uuid <uuid>\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		uuid = argv[2];
 | 
			
		||||
 | 
			
		||||
		reply = daemon_send_simple(h, "vg_lookup",
 | 
			
		||||
					   "uuid = %s", uuid,
 | 
			
		||||
					   "token = %s", "skip",
 | 
			
		||||
					   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
					   "cmd = %s", "lvmetactl",
 | 
			
		||||
					   NULL);
 | 
			
		||||
		printf("%s\n", reply.buffer.mem);
 | 
			
		||||
 | 
			
		||||
	} else if (!strcmp(cmd, "vg_lock_type")) {
 | 
			
		||||
		struct dm_config_node *metadata;
 | 
			
		||||
		const char *lock_type;
 | 
			
		||||
 | 
			
		||||
		if (argc < 3) {
 | 
			
		||||
			printf("vg_lock_type <uuid>\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		uuid = argv[2];
 | 
			
		||||
 | 
			
		||||
		reply = daemon_send_simple(h, "vg_lookup",
 | 
			
		||||
					   "uuid = %s", uuid,
 | 
			
		||||
					   "token = %s", "skip",
 | 
			
		||||
					   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
					   "cmd = %s", "lvmetactl",
 | 
			
		||||
					   NULL);
 | 
			
		||||
		/* printf("%s\n", reply.buffer.mem); */
 | 
			
		||||
 | 
			
		||||
		metadata = dm_config_find_node(reply.cft->root, "metadata");
 | 
			
		||||
		if (!metadata) {
 | 
			
		||||
			printf("no metadata\n");
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL);
 | 
			
		||||
		if (!lock_type) {
 | 
			
		||||
			printf("no lock_type\n");
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		printf("lock_type %s\n", lock_type);
 | 
			
		||||
 | 
			
		||||
	} else if (!strcmp(cmd, "pv_lookup_uuid")) {
 | 
			
		||||
		if (argc < 3) {
 | 
			
		||||
			printf("pv_lookup_uuid <uuid>\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		uuid = argv[2];
 | 
			
		||||
 | 
			
		||||
		reply = daemon_send_simple(h, "pv_lookup",
 | 
			
		||||
					   "uuid = %s", uuid,
 | 
			
		||||
					   "token = %s", "skip",
 | 
			
		||||
					   "pid = " FMTd64, (int64_t)getpid(),
 | 
			
		||||
					   "cmd = %s", "lvmetactl",
 | 
			
		||||
					   NULL);
 | 
			
		||||
		printf("%s\n", reply.buffer.mem);
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		printf("unknown command\n");
 | 
			
		||||
		goto out_close;
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	daemon_reply_destroy(reply);
 | 
			
		||||
out_close:
 | 
			
		||||
	daemon_close(h);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								daemons/lvmetad/lvmetad-client.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								daemons/lvmetad/lvmetad-client.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011-2012 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_LVMETAD_CLIENT_H
 | 
			
		||||
#define _LVM_LVMETAD_CLIENT_H
 | 
			
		||||
 | 
			
		||||
#include "daemon-client.h"
 | 
			
		||||
 | 
			
		||||
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
 | 
			
		||||
 | 
			
		||||
#define LVMETAD_TOKEN_UPDATE_IN_PROGRESS "update in progress"
 | 
			
		||||
 | 
			
		||||
#define LVMETAD_DISABLE_REASON_DIRECT		"DIRECT"
 | 
			
		||||
#define LVMETAD_DISABLE_REASON_DUPLICATES	"DUPLICATES"
 | 
			
		||||
#define LVMETAD_DISABLE_REASON_VGRESTORE	"VGRESTORE"
 | 
			
		||||
#define LVMETAD_DISABLE_REASON_REPAIR		"REPAIR"
 | 
			
		||||
 | 
			
		||||
struct volume_group;
 | 
			
		||||
 | 
			
		||||
/* Different types of replies we may get from lvmetad. */
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	daemon_reply r;
 | 
			
		||||
	const char **uuids; /* NULL terminated array */
 | 
			
		||||
} lvmetad_uuidlist;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	daemon_reply r;
 | 
			
		||||
	struct dm_config_tree *cft;
 | 
			
		||||
} lvmetad_vg;
 | 
			
		||||
 | 
			
		||||
/* Get a list of VG UUIDs that match a given VG name. */
 | 
			
		||||
lvmetad_uuidlist lvmetad_lookup_vgname(daemon_handle h, const char *name);
 | 
			
		||||
 | 
			
		||||
/* Get the metadata of a single VG, identified by UUID. */
 | 
			
		||||
lvmetad_vg lvmetad_get_vg(daemon_handle h, const char *uuid);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Add and remove PVs on demand. Udev-driven systems will use this interface
 | 
			
		||||
 * instead of scanning.
 | 
			
		||||
 */
 | 
			
		||||
daemon_reply lvmetad_add_pv(daemon_handle h, const char *pv_uuid, const char *mda_content);
 | 
			
		||||
daemon_reply lvmetad_remove_pv(daemon_handle h, const char *pv_uuid);
 | 
			
		||||
 | 
			
		||||
/* Trigger a full disk scan, throwing away all caches. XXX do we eventually want
 | 
			
		||||
 * this? Probably not yet, anyway.
 | 
			
		||||
 *     daemon_reply lvmetad_rescan(daemon_handle h);
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Update the version of metadata of a volume group. The VG has to be locked for
 | 
			
		||||
 * writing for this, and the VG metadata here has to match whatever has been
 | 
			
		||||
 * written to the disk (under this lock). This initially avoids the requirement
 | 
			
		||||
 * for lvmetad to write to disk (in later revisions, lvmetad_supersede_vg may
 | 
			
		||||
 * also do the writing, or we probably add another function to do that).
 | 
			
		||||
 */
 | 
			
		||||
daemon_reply lvmetad_supersede_vg(daemon_handle h, struct volume_group *vg);
 | 
			
		||||
 | 
			
		||||
/* Wrappers to open/close connection */
 | 
			
		||||
 | 
			
		||||
static inline daemon_handle lvmetad_open(const char *socket)
 | 
			
		||||
{
 | 
			
		||||
	daemon_info lvmetad_info = {
 | 
			
		||||
		.path = "lvmetad",
 | 
			
		||||
		.socket = socket ?: LVMETAD_SOCKET,
 | 
			
		||||
		.protocol = "lvmetad",
 | 
			
		||||
		.protocol_version = 1,
 | 
			
		||||
		.autostart = 0
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return daemon_open(lvmetad_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void lvmetad_close(daemon_handle h)
 | 
			
		||||
{
 | 
			
		||||
	return daemon_close(h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										3010
									
								
								daemons/lvmetad/lvmetad-core.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3010
									
								
								daemons/lvmetad/lvmetad-core.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										16
									
								
								daemons/lvmetad/test.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										16
									
								
								daemons/lvmetad/test.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
export LD_LIBRARY_PATH="$1"
 | 
			
		||||
 | 
			
		||||
test -n "$2" && {
 | 
			
		||||
    rm -f /var/run/lvmetad.{socket,pid}
 | 
			
		||||
    chmod +rx lvmetad
 | 
			
		||||
    valgrind ./lvmetad -f &
 | 
			
		||||
    PID=$!
 | 
			
		||||
    sleep 1
 | 
			
		||||
    ./testclient
 | 
			
		||||
    kill $PID
 | 
			
		||||
    exit 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sudo ./test.sh "$1" .
 | 
			
		||||
							
								
								
									
										147
									
								
								daemons/lvmetad/testclient.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								daemons/lvmetad/testclient.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011-2014 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU General Public License v.2.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
#include "tool.h"
 | 
			
		||||
 | 
			
		||||
#include "lvmetad-client.h"
 | 
			
		||||
#include "label.h"
 | 
			
		||||
#include "lvmcache.h"
 | 
			
		||||
#include "metadata.h"
 | 
			
		||||
 | 
			
		||||
const char *uuid1 = "abcd-efgh";
 | 
			
		||||
const char *uuid2 = "bbcd-efgh";
 | 
			
		||||
const char *vgid = "yada-yada";
 | 
			
		||||
const char *uuid3 = "cbcd-efgh";
 | 
			
		||||
 | 
			
		||||
const char *metadata2 = "{\n"
 | 
			
		||||
	"id = \"yada-yada\"\n"
 | 
			
		||||
	"seqno = 15\n"
 | 
			
		||||
	"status = [\"READ\", \"WRITE\"]\n"
 | 
			
		||||
	"flags = []\n"
 | 
			
		||||
	"extent_size = 8192\n"
 | 
			
		||||
	"physical_volumes {\n"
 | 
			
		||||
	"    pv0 {\n"
 | 
			
		||||
	"        id = \"abcd-efgh\"\n"
 | 
			
		||||
	"    }\n"
 | 
			
		||||
	"    pv1 {\n"
 | 
			
		||||
	"        id = \"bbcd-efgh\"\n"
 | 
			
		||||
	"    }\n"
 | 
			
		||||
	"    pv2 {\n"
 | 
			
		||||
	"        id = \"cbcd-efgh\"\n"
 | 
			
		||||
	"    }\n"
 | 
			
		||||
	"}\n"
 | 
			
		||||
	"}\n";
 | 
			
		||||
 | 
			
		||||
void _handle_reply(daemon_reply reply) {
 | 
			
		||||
	const char *repl = daemon_reply_str(reply, "response", NULL);
 | 
			
		||||
	const char *status = daemon_reply_str(reply, "status", NULL);
 | 
			
		||||
	const char *vgid = daemon_reply_str(reply, "vgid", NULL);
 | 
			
		||||
 | 
			
		||||
	fprintf(stderr, "[C] REPLY: %s\n", repl);
 | 
			
		||||
	if (!strcmp(repl, "failed"))
 | 
			
		||||
		fprintf(stderr, "[C] REASON: %s\n", daemon_reply_str(reply, "reason", "unknown"));
 | 
			
		||||
	if (vgid)
 | 
			
		||||
		fprintf(stderr, "[C] VGID: %s\n", vgid);
 | 
			
		||||
	if (status)
 | 
			
		||||
		fprintf(stderr, "[C] STATUS: %s\n", status);
 | 
			
		||||
	daemon_reply_destroy(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void _pv_add(daemon_handle h, const char *uuid, const char *metadata)
 | 
			
		||||
{
 | 
			
		||||
	daemon_reply reply = daemon_send_simple(h, "pv_add", "uuid = %s", uuid,
 | 
			
		||||
						             "metadata = %b", metadata,
 | 
			
		||||
						             NULL);
 | 
			
		||||
	_handle_reply(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int scan(daemon_handle h, char *fn) {
 | 
			
		||||
	struct device *dev = dev_cache_get(fn, NULL);
 | 
			
		||||
 | 
			
		||||
	struct label *label;
 | 
			
		||||
	if (!label_read(dev, &label, 0)) {
 | 
			
		||||
		fprintf(stderr, "[C] no label found on %s\n", fn);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	char uuid[64];
 | 
			
		||||
	if (!id_write_format(dev->pvid, uuid, 64)) {
 | 
			
		||||
		fprintf(stderr, "[C] Failed to format PV UUID for %s", dev_name(dev));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	fprintf(stderr, "[C] found PV: %s\n", uuid);
 | 
			
		||||
	struct lvmcache_info *info = (struct lvmcache_info *) label->info;
 | 
			
		||||
	struct physical_volume pv = { 0, };
 | 
			
		||||
 | 
			
		||||
	if (!(info->fmt->ops->pv_read(info->fmt, dev_name(dev), &pv, 0))) {
 | 
			
		||||
		fprintf(stderr, "[C] Failed to read PV %s", dev_name(dev));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct format_instance_ctx fic;
 | 
			
		||||
	struct format_instance *fid = info->fmt->ops->create_instance(info->fmt, &fic);
 | 
			
		||||
	struct metadata_area *mda;
 | 
			
		||||
	struct volume_group *vg = NULL;
 | 
			
		||||
	dm_list_iterate_items(mda, &info->mdas) {
 | 
			
		||||
		struct volume_group *this = mda->ops->vg_read(fid, "", mda);
 | 
			
		||||
		if (this && !vg || this->seqno > vg->seqno)
 | 
			
		||||
			vg = this;
 | 
			
		||||
	}
 | 
			
		||||
	if (vg) {
 | 
			
		||||
		char *buf = NULL;
 | 
			
		||||
		/* TODO. This is not entirely correct, since export_vg_to_buffer
 | 
			
		||||
		 * adds trailing garbage to the buffer. We may need to use
 | 
			
		||||
		 * export_vg_to_config_tree and format the buffer ourselves. It
 | 
			
		||||
		 * does, however, work for now, since the garbage is well
 | 
			
		||||
		 * formatted and has no conflicting keys with the rest of the
 | 
			
		||||
		 * request.  */
 | 
			
		||||
		export_vg_to_buffer(vg, &buf);
 | 
			
		||||
		daemon_reply reply =
 | 
			
		||||
			daemon_send_simple(h, "pv_add", "uuid = %s", uuid,
 | 
			
		||||
					      "metadata = %b", strchr(buf, '{'),
 | 
			
		||||
					      NULL);
 | 
			
		||||
		_handle_reply(reply);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void _dump_vg(daemon_handle h, const char *uuid)
 | 
			
		||||
{
 | 
			
		||||
	daemon_reply reply = daemon_send_simple(h, "vg_by_uuid", "uuid = %s", uuid, NULL);
 | 
			
		||||
	fprintf(stderr, "[C] reply buffer: %s\n", reply.buffer);
 | 
			
		||||
	daemon_reply_destroy(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
	daemon_handle h = lvmetad_open();
 | 
			
		||||
	/* FIXME Missing error path */
 | 
			
		||||
 | 
			
		||||
	if (argc > 1) {
 | 
			
		||||
		int i;
 | 
			
		||||
		struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0, 1, 1);
 | 
			
		||||
		for (i = 1; i < argc; ++i) {
 | 
			
		||||
			const char *uuid = NULL;
 | 
			
		||||
			scan(h, argv[i]);
 | 
			
		||||
		}
 | 
			
		||||
		destroy_toolcontext(cmd);
 | 
			
		||||
		/* FIXME Missing lvmetad_close() */
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_pv_add(h, uuid1, NULL);
 | 
			
		||||
	_pv_add(h, uuid2, metadata2);
 | 
			
		||||
	_dump_vg(h, vgid);
 | 
			
		||||
	_pv_add(h, uuid3, NULL);
 | 
			
		||||
 | 
			
		||||
	daemon_close(h);	/* FIXME lvmetad_close? */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -15,8 +15,6 @@ srcdir = @srcdir@
 | 
			
		||||
top_srcdir = @top_srcdir@
 | 
			
		||||
top_builddir = @top_builddir@
 | 
			
		||||
 | 
			
		||||
USE_SD_NOTIFY=yes
 | 
			
		||||
 | 
			
		||||
SOURCES = lvmlockd-core.c
 | 
			
		||||
 | 
			
		||||
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
 | 
			
		||||
@@ -27,7 +25,6 @@ endif
 | 
			
		||||
ifeq ("@BUILD_LOCKDDLM@", "yes")
 | 
			
		||||
  SOURCES += lvmlockd-dlm.c
 | 
			
		||||
  LOCK_LIBS += -ldlm_lt
 | 
			
		||||
  LOCK_LIBS += -ldlmcontrol
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
SOURCES2 = lvmlockctl.c
 | 
			
		||||
@@ -41,30 +38,20 @@ 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 += $(RT_LIBS) $(DAEMON_LIBS) $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ifeq ($(USE_SD_NOTIFY),yes)
 | 
			
		||||
	CFLAGS += $(shell pkg-config --cflags libsystemd) -DUSE_SD_NOTIFY
 | 
			
		||||
	LIBS += $(shell pkg-config --libs libsystemd)
 | 
			
		||||
endif
 | 
			
		||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
 | 
			
		||||
		    $(top_builddir)/libdaemon/server/libdaemonserver.a
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LOCK_LIBS) -ldaemonserver $(INTERNAL_LIBS) $(LIBS)
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LOCK_LIBS) -ldaemonserver $(LIBS)
 | 
			
		||||
 | 
			
		||||
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(INTERNAL_LIBS) $(LIBS)
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(LIBS)
 | 
			
		||||
 | 
			
		||||
install_lvmlockd: lvmlockd
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
	$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_lvmlockctl: lvmlockctl
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
	$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_lvmlockd install_lvmlockctl
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,9 +8,9 @@
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "tools/tool.h"
 | 
			
		||||
#include "tool.h"
 | 
			
		||||
 | 
			
		||||
#include "daemons/lvmlockd/lvmlockd-client.h"
 | 
			
		||||
#include "lvmlockd-client.h"
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
static int quit = 0;
 | 
			
		||||
static int info = 0;
 | 
			
		||||
static int dump = 0;
 | 
			
		||||
static int wait_opt = 1;
 | 
			
		||||
static int wait_opt = 0;
 | 
			
		||||
static int force_opt = 0;
 | 
			
		||||
static int kill_vg = 0;
 | 
			
		||||
static int drop_vg = 0;
 | 
			
		||||
@@ -280,12 +280,13 @@ static void format_info_line(char *line, char *r_name, char *r_type)
 | 
			
		||||
 | 
			
		||||
static void format_info(void)
 | 
			
		||||
{
 | 
			
		||||
	char line[MAX_LINE] = { 0 };
 | 
			
		||||
	char r_name[MAX_NAME+1] = { 0 };
 | 
			
		||||
	char r_type[MAX_NAME+1] = { 0 };
 | 
			
		||||
	char line[MAX_LINE];
 | 
			
		||||
	char r_name[MAX_NAME+1];
 | 
			
		||||
	char r_type[MAX_NAME+1];
 | 
			
		||||
	int i, j;
 | 
			
		||||
 | 
			
		||||
	j = 0;
 | 
			
		||||
	memset(line, 0, sizeof(line));
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < dump_len; i++) {
 | 
			
		||||
		line[j++] = dump_buf[i];
 | 
			
		||||
@@ -325,8 +326,6 @@ static int _lvmlockd_result(daemon_reply reply, int *result)
 | 
			
		||||
{
 | 
			
		||||
	int reply_result;
 | 
			
		||||
 | 
			
		||||
	*result = NO_LOCKD_RESULT;
 | 
			
		||||
 | 
			
		||||
	if (reply.error) {
 | 
			
		||||
		log_error("lvmlockd_result reply error %d", reply.error);
 | 
			
		||||
		return 0;
 | 
			
		||||
@@ -338,7 +337,7 @@ static int _lvmlockd_result(daemon_reply reply, int *result)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	reply_result = daemon_reply_int(reply, "op_result", NO_LOCKD_RESULT);
 | 
			
		||||
	if (reply_result == NO_LOCKD_RESULT) {
 | 
			
		||||
	if (reply_result == -1000) {
 | 
			
		||||
		log_error("lvmlockd_result no op_result");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,10 +11,9 @@
 | 
			
		||||
#ifndef _LVM_LVMLOCKD_CLIENT_H
 | 
			
		||||
#define _LVM_LVMLOCKD_CLIENT_H
 | 
			
		||||
 | 
			
		||||
#include "libdaemon/client/daemon-client.h"
 | 
			
		||||
#include "daemon-client.h"
 | 
			
		||||
 | 
			
		||||
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
 | 
			
		||||
#define LVMLOCKD_ADOPT_FILE DEFAULT_RUN_DIR "/lvmlockd.adopt"
 | 
			
		||||
 | 
			
		||||
/* Wrappers to open/close connection */
 | 
			
		||||
 | 
			
		||||
@@ -23,9 +22,9 @@ static inline daemon_handle lvmlockd_open(const char *sock)
 | 
			
		||||
	daemon_info lvmlockd_info = {
 | 
			
		||||
		.path = "lvmlockd",
 | 
			
		||||
		.socket = sock ?: LVMLOCKD_SOCKET,
 | 
			
		||||
		.autostart = 0,
 | 
			
		||||
		.protocol = "lvmlockd",
 | 
			
		||||
		.protocol_version = 1,
 | 
			
		||||
		.autostart = 0
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return daemon_open(lvmlockd_info);
 | 
			
		||||
@@ -33,7 +32,7 @@ static inline daemon_handle lvmlockd_open(const char *sock)
 | 
			
		||||
 | 
			
		||||
static inline void lvmlockd_close(daemon_handle h)
 | 
			
		||||
{
 | 
			
		||||
	daemon_close(h);
 | 
			
		||||
	return daemon_close(h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -8,13 +8,18 @@
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "tools/tool.h"
 | 
			
		||||
#define _XOPEN_SOURCE 500  /* pthread */
 | 
			
		||||
#define _ISOC99_SOURCE
 | 
			
		||||
#define _REENTRANT
 | 
			
		||||
 | 
			
		||||
#include "libdaemon/client/daemon-io.h"
 | 
			
		||||
#include "tool.h"
 | 
			
		||||
 | 
			
		||||
#include "daemon-io.h"
 | 
			
		||||
#include "daemon-server.h"
 | 
			
		||||
#include "lvm-version.h"
 | 
			
		||||
#include "daemons/lvmlockd/lvmlockd-client.h"
 | 
			
		||||
#include "device_mapper/misc/dm-ioctl.h"
 | 
			
		||||
#include "lvmetad-client.h"
 | 
			
		||||
#include "lvmlockd-client.h"
 | 
			
		||||
#include "dm-ioctl.h" /* for DM_UUID_LEN */
 | 
			
		||||
 | 
			
		||||
/* #include <assert.h> */
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
@@ -31,15 +36,9 @@
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
 | 
			
		||||
#ifdef USE_SD_NOTIFY
 | 
			
		||||
#include <systemd/sd-daemon.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define EXTERN
 | 
			
		||||
#include "lvmlockd-internal.h"
 | 
			
		||||
 | 
			
		||||
static int str_to_mode(const char *str);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Basic operation of lvmlockd
 | 
			
		||||
 *
 | 
			
		||||
@@ -144,8 +143,10 @@ static const char *lvmlockd_protocol = "lvmlockd";
 | 
			
		||||
static const int lvmlockd_protocol_version = 1;
 | 
			
		||||
static int daemon_quit;
 | 
			
		||||
static int adopt_opt;
 | 
			
		||||
static uint32_t adopt_update_count;
 | 
			
		||||
static const char *adopt_file;
 | 
			
		||||
 | 
			
		||||
static daemon_handle lvmetad_handle;
 | 
			
		||||
static pthread_mutex_t lvmetad_mutex;
 | 
			
		||||
static int lvmetad_connected;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * We use a separate socket for dumping daemon info.
 | 
			
		||||
@@ -409,11 +410,12 @@ struct lockspace *alloc_lockspace(void)
 | 
			
		||||
{
 | 
			
		||||
	struct lockspace *ls;
 | 
			
		||||
 | 
			
		||||
	if (!(ls = zalloc(sizeof(struct lockspace)))) {
 | 
			
		||||
	if (!(ls = malloc(sizeof(struct lockspace)))) {
 | 
			
		||||
		log_error("out of memory for lockspace");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memset(ls, 0, sizeof(struct lockspace));
 | 
			
		||||
	INIT_LIST_HEAD(&ls->actions);
 | 
			
		||||
	INIT_LIST_HEAD(&ls->resources);
 | 
			
		||||
	pthread_mutex_init(&ls->mutex, NULL);
 | 
			
		||||
@@ -506,10 +508,6 @@ static struct lock *alloc_lock(void)
 | 
			
		||||
 | 
			
		||||
static void free_action(struct action *act)
 | 
			
		||||
{
 | 
			
		||||
	if (act->path) {
 | 
			
		||||
		free(act->path);
 | 
			
		||||
		act->path = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	pthread_mutex_lock(&unused_struct_mutex);
 | 
			
		||||
	if (unused_action_count >= MAX_UNUSED_ACTION) {
 | 
			
		||||
		free(act);
 | 
			
		||||
@@ -733,8 +731,6 @@ static const char *op_str(int x)
 | 
			
		||||
		return "rename_final";
 | 
			
		||||
	case LD_OP_RUNNING_LM:
 | 
			
		||||
		return "running_lm";
 | 
			
		||||
	case LD_OP_QUERY_LOCK:
 | 
			
		||||
		return "query_lock";
 | 
			
		||||
	case LD_OP_FIND_FREE_LOCK:
 | 
			
		||||
		return "find_free_lock";
 | 
			
		||||
	case LD_OP_KILL_VG:
 | 
			
		||||
@@ -747,8 +743,6 @@ static const char *op_str(int x)
 | 
			
		||||
		return "dump_info";
 | 
			
		||||
	case LD_OP_BUSY:
 | 
			
		||||
		return "busy";
 | 
			
		||||
	case LD_OP_REFRESH_LV:
 | 
			
		||||
		return "refresh_lv";
 | 
			
		||||
	default:
 | 
			
		||||
		return "op_unknown";
 | 
			
		||||
	};
 | 
			
		||||
@@ -815,144 +809,6 @@ int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsi
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Write new info when a command exits if that command has acquired a new LV
 | 
			
		||||
 * lock.  If the command has released an LV lock we don't bother updating the
 | 
			
		||||
 * info.  When adopting, we eliminate any LV lock adoptions if there is no dm
 | 
			
		||||
 * device for that LV.  If lvmlockd is terminated after acquiring but before
 | 
			
		||||
 * writing this file, those LV locks would not be adopted on restart.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define ADOPT_VERSION_MAJOR 1
 | 
			
		||||
#define ADOPT_VERSION_MINOR 0
 | 
			
		||||
 | 
			
		||||
static void write_adopt_file(void)
 | 
			
		||||
{
 | 
			
		||||
	struct lockspace *ls;
 | 
			
		||||
	struct resource *r;
 | 
			
		||||
	struct lock *lk;
 | 
			
		||||
	time_t t;
 | 
			
		||||
	FILE *fp;
 | 
			
		||||
 | 
			
		||||
	if (!(fp = fopen(adopt_file, "w")))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	adopt_update_count++;
 | 
			
		||||
 | 
			
		||||
	t = time(NULL);
 | 
			
		||||
	fprintf(fp, "lvmlockd adopt_version %u.%u pid %d updates %u %s",
 | 
			
		||||
		ADOPT_VERSION_MAJOR, ADOPT_VERSION_MINOR, getpid(), adopt_update_count, ctime(&t));
 | 
			
		||||
 | 
			
		||||
	pthread_mutex_lock(&lockspaces_mutex);
 | 
			
		||||
	list_for_each_entry(ls, &lockspaces, list) {
 | 
			
		||||
		if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm))
 | 
			
		||||
			continue;
 | 
			
		||||
		fprintf(fp, "VG: %38s %s %s %s\n",
 | 
			
		||||
			ls->vg_uuid, ls->vg_name, lm_str(ls->lm_type), ls->vg_args);
 | 
			
		||||
		list_for_each_entry(r, &ls->resources, list) {
 | 
			
		||||
			if (r->type != LD_RT_LV)
 | 
			
		||||
				continue;
 | 
			
		||||
			if ((r->mode != LD_LK_EX) && (r->mode != LD_LK_SH))
 | 
			
		||||
				continue;
 | 
			
		||||
			list_for_each_entry(lk, &r->locks, list) {
 | 
			
		||||
				fprintf(fp, "LV: %38s %s %s %s %u\n",
 | 
			
		||||
					ls->vg_uuid, r->name, r->lv_args, mode_str(r->mode), r->version);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	pthread_mutex_unlock(&lockspaces_mutex);
 | 
			
		||||
 | 
			
		||||
	fflush(fp);
 | 
			
		||||
	fclose(fp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int read_adopt_file(struct list_head *vg_lockd)
 | 
			
		||||
{
 | 
			
		||||
	char adopt_line[512];
 | 
			
		||||
	char vg_uuid[72];
 | 
			
		||||
	char lm_type_str[16];
 | 
			
		||||
	char mode[8];
 | 
			
		||||
	struct lockspace *ls, *ls2;
 | 
			
		||||
	struct resource *r;
 | 
			
		||||
	FILE *fp;
 | 
			
		||||
 | 
			
		||||
	if (MAX_ARGS != 64 || MAX_NAME != 64)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	if (!(fp = fopen(adopt_file, "r")))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	while (fgets(adopt_line, sizeof(adopt_line), fp)) {
 | 
			
		||||
		if (adopt_line[0] == '#')
 | 
			
		||||
			continue;
 | 
			
		||||
		else if (!strncmp(adopt_line, "lvmlockd", 8)) {
 | 
			
		||||
			unsigned int v_major = 0, v_minor = 0;
 | 
			
		||||
			if ((sscanf(adopt_line, "lvmlockd adopt_version %u.%u", &v_major, &v_minor) != 2) ||
 | 
			
		||||
			    (v_major != ADOPT_VERSION_MAJOR))
 | 
			
		||||
				goto fail;
 | 
			
		||||
 | 
			
		||||
		} else if (!strncmp(adopt_line, "VG:", 3)) {
 | 
			
		||||
			if (!(ls = alloc_lockspace()))
 | 
			
		||||
				goto fail;
 | 
			
		||||
 | 
			
		||||
			memset(vg_uuid, 0, sizeof(vg_uuid));
 | 
			
		||||
 | 
			
		||||
			if (sscanf(adopt_line, "VG: %63s %64s %16s %64s",
 | 
			
		||||
				   vg_uuid, ls->vg_name, lm_type_str, ls->vg_args) != 4) {
 | 
			
		||||
				goto fail;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			memcpy(ls->vg_uuid, vg_uuid, 64);
 | 
			
		||||
 | 
			
		||||
			if ((ls->lm_type = str_to_lm(lm_type_str)) < 0)
 | 
			
		||||
				goto fail;
 | 
			
		||||
 | 
			
		||||
			list_add(&ls->list, vg_lockd);
 | 
			
		||||
 | 
			
		||||
		} else if (!strncmp(adopt_line, "LV:", 3)) {
 | 
			
		||||
			if (!(r = alloc_resource()))
 | 
			
		||||
				goto fail;
 | 
			
		||||
 | 
			
		||||
			r->type = LD_RT_LV;
 | 
			
		||||
 | 
			
		||||
			memset(vg_uuid, 0, sizeof(vg_uuid));
 | 
			
		||||
 | 
			
		||||
			if (sscanf(adopt_line, "LV: %64s %64s %s %8s %u",
 | 
			
		||||
				   vg_uuid, r->name, r->lv_args, mode, &r->version) != 5) {
 | 
			
		||||
				goto fail;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if ((r->adopt_mode = str_to_mode(mode)) == LD_LK_IV)
 | 
			
		||||
				goto fail;
 | 
			
		||||
 | 
			
		||||
			if (ls && !memcmp(ls->vg_uuid, vg_uuid, 64)) {
 | 
			
		||||
				list_add(&r->list, &ls->resources);
 | 
			
		||||
				r = NULL;
 | 
			
		||||
			} else {
 | 
			
		||||
				list_for_each_entry(ls2, vg_lockd, list) {
 | 
			
		||||
					if (memcmp(ls2->vg_uuid, vg_uuid, 64))
 | 
			
		||||
						continue;
 | 
			
		||||
					list_add(&r->list, &ls2->resources);
 | 
			
		||||
					r = NULL;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (r) {
 | 
			
		||||
				log_error("No lockspace found for resource %s vg_uuid %s", r->name, vg_uuid);
 | 
			
		||||
				goto fail;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fclose(fp);
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
	fclose(fp);
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * These are few enough that arrays of function pointers can
 | 
			
		||||
 * be avoided.
 | 
			
		||||
@@ -1074,12 +930,12 @@ static void lm_rem_resource(struct lockspace *ls, struct resource *r)
 | 
			
		||||
		lm_rem_resource_sanlock(ls, r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int lm_find_free_lock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size)
 | 
			
		||||
static int lm_find_free_lock(struct lockspace *ls, uint64_t *free_offset)
 | 
			
		||||
{
 | 
			
		||||
	if (ls->lm_type == LD_LM_DLM)
 | 
			
		||||
		return 0;
 | 
			
		||||
	else if (ls->lm_type == LD_LM_SANLOCK)
 | 
			
		||||
		return lm_find_free_lock_sanlock(ls, free_offset, sector_size, align_size);
 | 
			
		||||
		return lm_find_free_lock_sanlock(ls, free_offset);
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1153,6 +1009,54 @@ static void add_work_action(struct action *act)
 | 
			
		||||
	pthread_mutex_unlock(&worker_mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define ERR_LVMETAD_NOT_RUNNING -200
 | 
			
		||||
 | 
			
		||||
static daemon_reply send_lvmetad(const char *id, ...)
 | 
			
		||||
{
 | 
			
		||||
	daemon_reply reply;
 | 
			
		||||
	va_list ap;
 | 
			
		||||
	int retries = 0;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	va_start(ap, id);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * mutex is used because all threads share a single
 | 
			
		||||
	 * lvmetad connection/handle.
 | 
			
		||||
	 */
 | 
			
		||||
	pthread_mutex_lock(&lvmetad_mutex);
 | 
			
		||||
retry:
 | 
			
		||||
	if (!lvmetad_connected) {
 | 
			
		||||
		lvmetad_handle = lvmetad_open(NULL);
 | 
			
		||||
		if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0) {
 | 
			
		||||
			err = lvmetad_handle.error ?: lvmetad_handle.socket_fd;
 | 
			
		||||
			pthread_mutex_unlock(&lvmetad_mutex);
 | 
			
		||||
			log_debug("lvmetad_open reconnect error %d", err);
 | 
			
		||||
			memset(&reply, 0, sizeof(reply));
 | 
			
		||||
			reply.error = ERR_LVMETAD_NOT_RUNNING;
 | 
			
		||||
			va_end(ap);
 | 
			
		||||
			return reply;
 | 
			
		||||
		} else {
 | 
			
		||||
			log_debug("lvmetad reconnected");
 | 
			
		||||
			lvmetad_connected = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	reply = daemon_send_simple_v(lvmetad_handle, id, ap);
 | 
			
		||||
 | 
			
		||||
	/* lvmetad may have been restarted */
 | 
			
		||||
	if ((reply.error == ECONNRESET) && (retries < 2)) {
 | 
			
		||||
		daemon_close(lvmetad_handle);
 | 
			
		||||
		lvmetad_connected = 0;
 | 
			
		||||
		retries++;
 | 
			
		||||
		goto retry;
 | 
			
		||||
	}
 | 
			
		||||
	pthread_mutex_unlock(&lvmetad_mutex);
 | 
			
		||||
 | 
			
		||||
	va_end(ap);
 | 
			
		||||
	return reply;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int res_lock(struct lockspace *ls, struct resource *r, struct action *act, int *retry)
 | 
			
		||||
{
 | 
			
		||||
	struct lock *lk;
 | 
			
		||||
@@ -1348,18 +1252,6 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
 | 
			
		||||
		rv = -EREMOVED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * lvmetad is no longer used, but the infrastructure for
 | 
			
		||||
	 * distributed cache validation remains.  The points
 | 
			
		||||
	 * where vg or global cache state would be invalidated
 | 
			
		||||
	 * remain below and log_debug messages point out where
 | 
			
		||||
	 * they would occur.
 | 
			
		||||
	 *
 | 
			
		||||
	 * The comments related to "lvmetad" remain because they
 | 
			
		||||
	 * describe how some other local cache like lvmetad would
 | 
			
		||||
	 * be invalidated here.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * r is vglk: tell lvmetad to set the vg invalid
 | 
			
		||||
	 * flag, and provide the new r_version.  If lvmetad finds
 | 
			
		||||
@@ -1385,12 +1277,47 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	if (inval_meta && (r->type == LD_RT_VG)) {
 | 
			
		||||
		log_debug("S %s R %s res_lock invalidate vg state version %u",
 | 
			
		||||
		daemon_reply reply;
 | 
			
		||||
		char *uuid;
 | 
			
		||||
 | 
			
		||||
		log_debug("S %s R %s res_lock set lvmetad vg version %u",
 | 
			
		||||
			  ls->name, r->name, new_version);
 | 
			
		||||
	
 | 
			
		||||
		if (!ls->vg_uuid[0] || !strcmp(ls->vg_uuid, "none"))
 | 
			
		||||
			uuid = (char *)"none";
 | 
			
		||||
		else
 | 
			
		||||
			uuid = ls->vg_uuid;
 | 
			
		||||
 | 
			
		||||
		reply = send_lvmetad("set_vg_info",
 | 
			
		||||
				     "token = %s", "skip",
 | 
			
		||||
				     "uuid = %s", uuid,
 | 
			
		||||
				     "name = %s", ls->vg_name,
 | 
			
		||||
				     "version = " FMTd64, (int64_t)new_version,
 | 
			
		||||
				     NULL);
 | 
			
		||||
 | 
			
		||||
		if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
 | 
			
		||||
			if (reply.error != ERR_LVMETAD_NOT_RUNNING)
 | 
			
		||||
				log_error("set_vg_info in lvmetad failed %d", reply.error);
 | 
			
		||||
		}
 | 
			
		||||
		daemon_reply_destroy(reply);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (inval_meta && (r->type == LD_RT_GL)) {
 | 
			
		||||
		log_debug("S %s R %s res_lock invalidate global state", ls->name, r->name);
 | 
			
		||||
		daemon_reply reply;
 | 
			
		||||
 | 
			
		||||
		log_debug("S %s R %s res_lock set lvmetad global invalid",
 | 
			
		||||
			  ls->name, r->name);
 | 
			
		||||
 | 
			
		||||
		reply = send_lvmetad("set_global_info",
 | 
			
		||||
				     "token = %s", "skip",
 | 
			
		||||
				     "global_invalid = " FMTd64, INT64_C(1),
 | 
			
		||||
				     NULL);
 | 
			
		||||
 | 
			
		||||
		if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
 | 
			
		||||
			if (reply.error != ERR_LVMETAD_NOT_RUNNING)
 | 
			
		||||
				log_error("set_global_info in lvmetad failed %d", reply.error);
 | 
			
		||||
		}
 | 
			
		||||
		daemon_reply_destroy(reply);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@@ -1964,9 +1891,9 @@ static void res_process(struct lockspace *ls, struct resource *r,
 | 
			
		||||
			add_client_result(act);
 | 
			
		||||
		} else {
 | 
			
		||||
			/* persistent lock is sh, transient request is ex */
 | 
			
		||||
			/* FIXME: can we remove this case? do a convert here? */
 | 
			
		||||
			log_debug("res_process %s existing persistent lock new transient", r->name);
 | 
			
		||||
			r->last_client_id = act->client_id;
 | 
			
		||||
			act->flags |= LD_AF_SH_EXISTS;
 | 
			
		||||
			act->result = -EEXIST;
 | 
			
		||||
			list_del(&act->list);
 | 
			
		||||
			add_client_result(act);
 | 
			
		||||
@@ -2346,7 +2273,6 @@ static int process_op_during_kill(struct action *act)
 | 
			
		||||
	case LD_OP_UPDATE:
 | 
			
		||||
	case LD_OP_RENAME_BEFORE:
 | 
			
		||||
	case LD_OP_RENAME_FINAL:
 | 
			
		||||
	case LD_OP_QUERY_LOCK:
 | 
			
		||||
	case LD_OP_FIND_FREE_LOCK:
 | 
			
		||||
		return 0;
 | 
			
		||||
	};
 | 
			
		||||
@@ -2372,7 +2298,7 @@ static void *lockspace_thread_main(void *arg_in)
 | 
			
		||||
	struct action *act_op_free = NULL;
 | 
			
		||||
	struct list_head tmp_act;
 | 
			
		||||
	struct list_head act_close;
 | 
			
		||||
	char tmp_name[MAX_NAME+5];
 | 
			
		||||
	char tmp_name[MAX_NAME+1];
 | 
			
		||||
	int free_vg = 0;
 | 
			
		||||
	int drop_vg = 0;
 | 
			
		||||
	int error = 0;
 | 
			
		||||
@@ -2571,31 +2497,13 @@ static void *lockspace_thread_main(void *arg_in)
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (act->op == LD_OP_QUERY_LOCK) {
 | 
			
		||||
				r = find_resource_act(ls, act, 0);
 | 
			
		||||
				if (!r)
 | 
			
		||||
					act->result = -ENOENT;
 | 
			
		||||
				else {
 | 
			
		||||
					act->result = 0;
 | 
			
		||||
					act->mode = r->mode;
 | 
			
		||||
				}
 | 
			
		||||
				list_del(&act->list);
 | 
			
		||||
				add_client_result(act);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (act->op == LD_OP_FIND_FREE_LOCK && act->rt == LD_RT_VG) {
 | 
			
		||||
				uint64_t free_offset = 0;
 | 
			
		||||
				int sector_size = 0;
 | 
			
		||||
				int align_size = 0;
 | 
			
		||||
 | 
			
		||||
				log_debug("S %s find free lock", ls->name);
 | 
			
		||||
				rv = lm_find_free_lock(ls, &free_offset, §or_size, &align_size);
 | 
			
		||||
				log_debug("S %s find free lock %d offset %llu sector_size %d align_size %d",
 | 
			
		||||
					  ls->name, rv, (unsigned long long)free_offset, sector_size, align_size);
 | 
			
		||||
				rv = lm_find_free_lock(ls, &free_offset);
 | 
			
		||||
				log_debug("S %s find free lock %d offset %llu",
 | 
			
		||||
					  ls->name, rv, (unsigned long long)free_offset);
 | 
			
		||||
				ls->free_lock_offset = free_offset;
 | 
			
		||||
				ls->free_lock_sector_size = sector_size;
 | 
			
		||||
				ls->free_lock_align_size = align_size;
 | 
			
		||||
				list_del(&act->list);
 | 
			
		||||
				act->result = rv;
 | 
			
		||||
				add_client_result(act);
 | 
			
		||||
@@ -2766,10 +2674,8 @@ out_act:
 | 
			
		||||
	 * blank or fill it with garbage, but instead set it to REM:<name>
 | 
			
		||||
	 * to make it easier to follow progress of freeing is via log_debug.
 | 
			
		||||
	 */
 | 
			
		||||
	memset(tmp_name, 0, sizeof(tmp_name));
 | 
			
		||||
	memcpy(tmp_name, "REM:", 4);
 | 
			
		||||
	strncpy(tmp_name+4, ls->name, sizeof(tmp_name)-4);
 | 
			
		||||
	memcpy(ls->name, tmp_name, sizeof(ls->name));
 | 
			
		||||
	dm_strncpy(tmp_name, ls->name, sizeof(tmp_name));
 | 
			
		||||
	snprintf(ls->name, sizeof(ls->name), "REM:%s", tmp_name);
 | 
			
		||||
	pthread_mutex_unlock(&lockspaces_mutex);
 | 
			
		||||
 | 
			
		||||
	/* worker_thread will join this thread, and free the ls */
 | 
			
		||||
@@ -3406,8 +3312,6 @@ static int work_init_lv(struct action *act)
 | 
			
		||||
	char vg_args[MAX_ARGS+1];
 | 
			
		||||
	char lv_args[MAX_ARGS+1];
 | 
			
		||||
	uint64_t free_offset = 0;
 | 
			
		||||
	int sector_size = 0;
 | 
			
		||||
	int align_size = 0;
 | 
			
		||||
	int lm_type = 0;
 | 
			
		||||
	int rv = 0;
 | 
			
		||||
 | 
			
		||||
@@ -3423,8 +3327,6 @@ static int work_init_lv(struct action *act)
 | 
			
		||||
		lm_type = ls->lm_type;
 | 
			
		||||
		memcpy(vg_args, ls->vg_args, MAX_ARGS);
 | 
			
		||||
		free_offset = ls->free_lock_offset;
 | 
			
		||||
		sector_size = ls->free_lock_sector_size;
 | 
			
		||||
		align_size = ls->free_lock_align_size;
 | 
			
		||||
	}
 | 
			
		||||
	pthread_mutex_unlock(&lockspaces_mutex);
 | 
			
		||||
 | 
			
		||||
@@ -3441,7 +3343,7 @@ static int work_init_lv(struct action *act)
 | 
			
		||||
 | 
			
		||||
	if (lm_type == LD_LM_SANLOCK) {
 | 
			
		||||
		rv = lm_init_lv_sanlock(ls_name, act->vg_name, act->lv_uuid,
 | 
			
		||||
					vg_args, lv_args, sector_size, align_size, free_offset);
 | 
			
		||||
					vg_args, lv_args, free_offset);
 | 
			
		||||
 | 
			
		||||
		memcpy(act->lv_args, lv_args, MAX_ARGS);
 | 
			
		||||
		return rv;
 | 
			
		||||
@@ -3571,15 +3473,6 @@ static void *worker_thread_main(void *arg_in)
 | 
			
		||||
			else
 | 
			
		||||
				list_add(&act->list, &delayed_list);
 | 
			
		||||
 | 
			
		||||
		} else if (act->op == LD_OP_REFRESH_LV) {
 | 
			
		||||
			log_debug("work refresh_lv %s %s", act->lv_uuid, act->path);
 | 
			
		||||
			rv = lm_refresh_lv_start_dlm(act);
 | 
			
		||||
			if (rv < 0) {
 | 
			
		||||
				act->result = rv;
 | 
			
		||||
				add_client_result(act);
 | 
			
		||||
			} else
 | 
			
		||||
				list_add(&act->list, &delayed_list);
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
			log_error("work unknown op %d", act->op);
 | 
			
		||||
			act->result = -EINVAL;
 | 
			
		||||
@@ -3615,19 +3508,6 @@ static void *worker_thread_main(void *arg_in)
 | 
			
		||||
					act->result = 0;
 | 
			
		||||
					add_client_result(act);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			} else if (act->op == LD_OP_REFRESH_LV) {
 | 
			
		||||
				log_debug("work delayed refresh_lv");
 | 
			
		||||
				rv = lm_refresh_lv_check_dlm(act);
 | 
			
		||||
				if (!rv) {
 | 
			
		||||
					list_del(&act->list);
 | 
			
		||||
					act->result = 0;
 | 
			
		||||
					add_client_result(act);
 | 
			
		||||
				} else if ((rv < 0) && (rv != -EAGAIN)) {
 | 
			
		||||
					list_del(&act->list);
 | 
			
		||||
					act->result = rv;
 | 
			
		||||
					add_client_result(act);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -3833,9 +3713,6 @@ static int client_send_result(struct client *cl, struct action *act)
 | 
			
		||||
	if ((act->flags & LD_AF_WARN_GL_REMOVED) || gl_vg_removed)
 | 
			
		||||
		strcat(result_flags, "WARN_GL_REMOVED,");
 | 
			
		||||
	
 | 
			
		||||
	if (act->flags & LD_AF_SH_EXISTS)
 | 
			
		||||
		strcat(result_flags, "SH_EXISTS,");
 | 
			
		||||
 | 
			
		||||
	if (act->op == LD_OP_INIT) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * init is a special case where lock args need
 | 
			
		||||
@@ -3864,20 +3741,6 @@ static int client_send_result(struct client *cl, struct action *act)
 | 
			
		||||
					  "result_flags = %s", result_flags[0] ? result_flags : "none",
 | 
			
		||||
					  NULL);
 | 
			
		||||
 | 
			
		||||
	} else if (act->op == LD_OP_QUERY_LOCK) {
 | 
			
		||||
 | 
			
		||||
		log_debug("send %s[%d] cl %u %s %s rv %d mode %d",
 | 
			
		||||
			  cl->name[0] ? cl->name : "client", cl->pid, cl->id,
 | 
			
		||||
			  op_str(act->op), rt_str(act->rt),
 | 
			
		||||
			  act->result, act->mode);
 | 
			
		||||
 | 
			
		||||
		res = daemon_reply_simple("OK",
 | 
			
		||||
					  "op = " FMTd64, (int64_t)act->op,
 | 
			
		||||
					  "op_result = " FMTd64, (int64_t) act->result,
 | 
			
		||||
					  "lock_type = %s", lm_str(act->lm_type),
 | 
			
		||||
					  "mode = %s", mode_str(act->mode),
 | 
			
		||||
					  NULL);
 | 
			
		||||
 | 
			
		||||
	} else if (act->op == LD_OP_DUMP_LOG || act->op == LD_OP_DUMP_INFO) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * lvmlockctl creates the unix socket then asks us to write to it.
 | 
			
		||||
@@ -4208,16 +4071,6 @@ static int str_to_op_rt(const char *req_name, int *op, int *rt)
 | 
			
		||||
		*rt = 0;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (!strcmp(req_name, "query_lock_vg")) {
 | 
			
		||||
		*op = LD_OP_QUERY_LOCK;
 | 
			
		||||
		*rt = LD_RT_VG;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (!strcmp(req_name, "query_lock_lv")) {
 | 
			
		||||
		*op = LD_OP_QUERY_LOCK;
 | 
			
		||||
		*rt = LD_RT_LV;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (!strcmp(req_name, "find_free_lock")) {
 | 
			
		||||
		*op = LD_OP_FIND_FREE_LOCK;
 | 
			
		||||
		*rt = LD_RT_VG;
 | 
			
		||||
@@ -4233,11 +4086,6 @@ static int str_to_op_rt(const char *req_name, int *op, int *rt)
 | 
			
		||||
		*rt = LD_RT_VG;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (!strcmp(req_name, "refresh_lv")) {
 | 
			
		||||
		*op = LD_OP_REFRESH_LV;
 | 
			
		||||
		*rt = 0;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
@@ -4599,7 +4447,6 @@ static void client_recv_action(struct client *cl)
 | 
			
		||||
	const char *vg_name;
 | 
			
		||||
	const char *vg_uuid;
 | 
			
		||||
	const char *vg_sysid;
 | 
			
		||||
	const char *path;
 | 
			
		||||
	const char *str;
 | 
			
		||||
	int64_t val;
 | 
			
		||||
	uint32_t opts = 0;
 | 
			
		||||
@@ -4686,7 +4533,6 @@ static void client_recv_action(struct client *cl)
 | 
			
		||||
	opts = str_to_opts(str);
 | 
			
		||||
	str = daemon_request_str(req, "vg_lock_type", NULL);
 | 
			
		||||
	lm = str_to_lm(str);
 | 
			
		||||
	path = daemon_request_str(req, "path", NULL);
 | 
			
		||||
 | 
			
		||||
	if (cl_pid && cl_pid != cl->pid)
 | 
			
		||||
		log_error("client recv bad message pid %d client %d", cl_pid, cl->pid);
 | 
			
		||||
@@ -4719,9 +4565,6 @@ static void client_recv_action(struct client *cl)
 | 
			
		||||
	act->flags = opts;
 | 
			
		||||
	act->lm_type = lm;
 | 
			
		||||
 | 
			
		||||
	if (path)
 | 
			
		||||
		act->path = strdup(path);
 | 
			
		||||
 | 
			
		||||
	if (vg_name && strcmp(vg_name, "none"))
 | 
			
		||||
		strncpy(act->vg_name, vg_name, MAX_NAME);
 | 
			
		||||
 | 
			
		||||
@@ -4798,7 +4641,6 @@ static void client_recv_action(struct client *cl)
 | 
			
		||||
	case LD_OP_STOP_ALL:
 | 
			
		||||
	case LD_OP_RENAME_FINAL:
 | 
			
		||||
	case LD_OP_RUNNING_LM:
 | 
			
		||||
	case LD_OP_REFRESH_LV:
 | 
			
		||||
		add_work_action(act);
 | 
			
		||||
		rv = 0;
 | 
			
		||||
		break;
 | 
			
		||||
@@ -4808,7 +4650,6 @@ static void client_recv_action(struct client *cl)
 | 
			
		||||
	case LD_OP_DISABLE:
 | 
			
		||||
	case LD_OP_FREE:
 | 
			
		||||
	case LD_OP_RENAME_BEFORE:
 | 
			
		||||
	case LD_OP_QUERY_LOCK:
 | 
			
		||||
	case LD_OP_FIND_FREE_LOCK:
 | 
			
		||||
	case LD_OP_KILL_VG:
 | 
			
		||||
	case LD_OP_DROP_VG:
 | 
			
		||||
@@ -4831,7 +4672,6 @@ static void *client_thread_main(void *arg_in)
 | 
			
		||||
	struct client *cl;
 | 
			
		||||
	struct action *act;
 | 
			
		||||
	struct action *act_un;
 | 
			
		||||
	uint32_t lock_acquire_count = 0, lock_acquire_written = 0;
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
@@ -4863,9 +4703,6 @@ static void *client_thread_main(void *arg_in)
 | 
			
		||||
				rv = -1;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (act->flags & LD_AF_LV_LOCK)
 | 
			
		||||
				lock_acquire_count++;
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
			 * The client failed after we acquired an LV lock for
 | 
			
		||||
			 * it, but before getting this reply saying it's done.
 | 
			
		||||
@@ -4887,11 +4724,6 @@ static void *client_thread_main(void *arg_in)
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (adopt_opt && (lock_acquire_count > lock_acquire_written)) {
 | 
			
		||||
			lock_acquire_written = lock_acquire_count;
 | 
			
		||||
			write_adopt_file();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Queue incoming actions for lockspace threads
 | 
			
		||||
		 */
 | 
			
		||||
@@ -4965,8 +4797,6 @@ static void *client_thread_main(void *arg_in)
 | 
			
		||||
			pthread_mutex_unlock(&client_mutex);
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	if (adopt_opt && lock_acquire_written)
 | 
			
		||||
		unlink(adopt_file);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -4999,6 +4829,176 @@ static void close_client_thread(void)
 | 
			
		||||
		log_error("pthread_join client_thread error %d", perrno);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Get a list of all VGs with a lockd type (sanlock|dlm) from lvmetad.
 | 
			
		||||
 * We'll match this list against a list of existing lockspaces that are
 | 
			
		||||
 * found in the lock manager.
 | 
			
		||||
 *
 | 
			
		||||
 * For each of these VGs, also create a struct resource on ls->resources to
 | 
			
		||||
 * represent each LV in the VG that uses a lock.  For each of these LVs
 | 
			
		||||
 * that are active, we'll attempt to adopt a lock.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int get_lockd_vgs(struct list_head *vg_lockd)
 | 
			
		||||
{
 | 
			
		||||
	struct list_head update_vgs;
 | 
			
		||||
	daemon_reply reply;
 | 
			
		||||
	struct dm_config_node *cn;
 | 
			
		||||
	struct dm_config_node *metadata;
 | 
			
		||||
	struct dm_config_node *md_cn;
 | 
			
		||||
	struct dm_config_node *lv_cn;
 | 
			
		||||
	struct lockspace *ls, *safe;
 | 
			
		||||
	struct resource *r;
 | 
			
		||||
	const char *vg_name;
 | 
			
		||||
	const char *vg_uuid;
 | 
			
		||||
	const char *lv_uuid;
 | 
			
		||||
	const char *lock_type;
 | 
			
		||||
	const char *lock_args;
 | 
			
		||||
	char find_str_path[PATH_MAX];
 | 
			
		||||
	int rv = 0;
 | 
			
		||||
 | 
			
		||||
	INIT_LIST_HEAD(&update_vgs);
 | 
			
		||||
 | 
			
		||||
	reply = send_lvmetad("vg_list", "token = %s", "skip", NULL);
 | 
			
		||||
 | 
			
		||||
	if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
 | 
			
		||||
		log_error("vg_list from lvmetad failed %d", reply.error);
 | 
			
		||||
		rv = -EINVAL;
 | 
			
		||||
		goto destroy;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(cn = dm_config_find_node(reply.cft->root, "volume_groups"))) {
 | 
			
		||||
		log_error("get_lockd_vgs no vgs");
 | 
			
		||||
		rv = -EINVAL;
 | 
			
		||||
		goto destroy;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* create an update_vgs list of all vg uuids */
 | 
			
		||||
 | 
			
		||||
	for (cn = cn->child; cn; cn = cn->sib) {
 | 
			
		||||
		vg_uuid = cn->key;
 | 
			
		||||
 | 
			
		||||
		if (!(ls = alloc_lockspace())) {
 | 
			
		||||
			rv = -ENOMEM;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		strncpy(ls->vg_uuid, vg_uuid, 64);
 | 
			
		||||
		list_add_tail(&ls->list, &update_vgs);
 | 
			
		||||
		log_debug("get_lockd_vgs %s", vg_uuid);
 | 
			
		||||
	}
 | 
			
		||||
 destroy:
 | 
			
		||||
	daemon_reply_destroy(reply);
 | 
			
		||||
 | 
			
		||||
	if (rv < 0)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	/* get vg_name and lock_type for each vg uuid entry in update_vgs */
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(ls, &update_vgs, list) {
 | 
			
		||||
		reply = send_lvmetad("vg_lookup",
 | 
			
		||||
				     "token = %s", "skip",
 | 
			
		||||
				     "uuid = %s", ls->vg_uuid,
 | 
			
		||||
				     NULL);
 | 
			
		||||
 | 
			
		||||
		if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
 | 
			
		||||
			log_error("vg_lookup from lvmetad failed %d", reply.error);
 | 
			
		||||
			rv = -EINVAL;
 | 
			
		||||
			goto next;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		vg_name = daemon_reply_str(reply, "name", NULL);
 | 
			
		||||
		if (!vg_name) {
 | 
			
		||||
			log_error("get_lockd_vgs %s no name", ls->vg_uuid);
 | 
			
		||||
			rv = -EINVAL;
 | 
			
		||||
			goto next;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		strncpy(ls->vg_name, vg_name, MAX_NAME);
 | 
			
		||||
 | 
			
		||||
		metadata = dm_config_find_node(reply.cft->root, "metadata");
 | 
			
		||||
		if (!metadata) {
 | 
			
		||||
			log_error("get_lockd_vgs %s name %s no metadata",
 | 
			
		||||
				  ls->vg_uuid, ls->vg_name);
 | 
			
		||||
			rv = -EINVAL;
 | 
			
		||||
			goto next;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL);
 | 
			
		||||
		ls->lm_type = str_to_lm(lock_type);
 | 
			
		||||
 | 
			
		||||
		if ((ls->lm_type != LD_LM_SANLOCK) && (ls->lm_type != LD_LM_DLM)) {
 | 
			
		||||
			log_debug("get_lockd_vgs %s not lockd type", ls->vg_name);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		lock_args = dm_config_find_str(metadata, "metadata/lock_args", NULL);
 | 
			
		||||
		if (lock_args)
 | 
			
		||||
			strncpy(ls->vg_args, lock_args, MAX_ARGS);
 | 
			
		||||
 | 
			
		||||
		log_debug("get_lockd_vgs %s lock_type %s lock_args %s",
 | 
			
		||||
			  ls->vg_name, lock_type, lock_args ?: "none");
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Make a record (struct resource) of each lv that uses a lock.
 | 
			
		||||
		 * For any lv that uses a lock, we'll check if the lv is active
 | 
			
		||||
		 * and if so try to adopt a lock for it.
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		for (md_cn = metadata->child; md_cn; md_cn = md_cn->sib) {
 | 
			
		||||
			if (strcmp(md_cn->key, "logical_volumes"))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			for (lv_cn = md_cn->child; lv_cn; lv_cn = lv_cn->sib) {
 | 
			
		||||
				snprintf(find_str_path, PATH_MAX, "%s/lock_args", lv_cn->key);
 | 
			
		||||
				lock_args = dm_config_find_str(lv_cn, find_str_path, NULL);
 | 
			
		||||
				if (!lock_args)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				snprintf(find_str_path, PATH_MAX, "%s/id", lv_cn->key);
 | 
			
		||||
				lv_uuid = dm_config_find_str(lv_cn, find_str_path, NULL);
 | 
			
		||||
 | 
			
		||||
				if (!lv_uuid) {
 | 
			
		||||
					log_error("get_lock_vgs no lv id for name %s", lv_cn->key);
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (!(r = alloc_resource())) {
 | 
			
		||||
					rv = -ENOMEM;
 | 
			
		||||
					goto next;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				r->use_vb = 0;
 | 
			
		||||
				r->type = LD_RT_LV;
 | 
			
		||||
				strncpy(r->name, lv_uuid, MAX_NAME);
 | 
			
		||||
				if (lock_args)
 | 
			
		||||
					strncpy(r->lv_args, lock_args, MAX_ARGS);
 | 
			
		||||
				list_add_tail(&r->list, &ls->resources);
 | 
			
		||||
				log_debug("get_lockd_vgs %s lv %s %s (name %s)",
 | 
			
		||||
					  ls->vg_name, r->name, lock_args ? lock_args : "", lv_cn->key);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 next:
 | 
			
		||||
		daemon_reply_destroy(reply);
 | 
			
		||||
 | 
			
		||||
		if (rv < 0)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	/* Return lockd VG's on the vg_lockd list. */
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry_safe(ls, safe, &update_vgs, list) {
 | 
			
		||||
		list_del(&ls->list);
 | 
			
		||||
 | 
			
		||||
		if ((ls->lm_type == LD_LM_SANLOCK) || (ls->lm_type == LD_LM_DLM))
 | 
			
		||||
			list_add_tail(&ls->list, vg_lockd);
 | 
			
		||||
		else
 | 
			
		||||
			free(ls);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char _dm_uuid[DM_UUID_LEN];
 | 
			
		||||
 | 
			
		||||
static char *get_dm_uuid(char *dm_name)
 | 
			
		||||
@@ -5215,9 +5215,9 @@ static void adopt_locks(void)
 | 
			
		||||
	INIT_LIST_HEAD(&to_unlock);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Get list of lockspaces from currently running lock managers.
 | 
			
		||||
	 * Get list of shared VGs from file written by prior lvmlockd.
 | 
			
		||||
	 * Get list of active LVs (in the shared VGs) from the file.
 | 
			
		||||
	 * Get list of lockspaces from lock managers.
 | 
			
		||||
	 * Get list of VGs from lvmetad with a lockd type.
 | 
			
		||||
	 * Get list of active lockd type LVs from /dev.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	if (lm_support_dlm() && lm_is_running_dlm()) {
 | 
			
		||||
@@ -5241,17 +5241,12 @@ static void adopt_locks(void)
 | 
			
		||||
	 * Adds a struct lockspace to vg_lockd for each lockd VG.
 | 
			
		||||
	 * Adds a struct resource to ls->resources for each LV.
 | 
			
		||||
	 */
 | 
			
		||||
	rv = read_adopt_file(&vg_lockd);
 | 
			
		||||
	rv = get_lockd_vgs(&vg_lockd);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_error("adopt_locks read_adopt_file failed");
 | 
			
		||||
		log_error("adopt_locks get_lockd_vgs failed");
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (list_empty(&vg_lockd)) {
 | 
			
		||||
		log_debug("No lockspaces in adopt file");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * For each resource on each lockspace, check if the
 | 
			
		||||
	 * corresponding LV is active.  If so, leave the
 | 
			
		||||
@@ -5276,7 +5271,7 @@ static void adopt_locks(void)
 | 
			
		||||
		gl_use_sanlock = 1;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(ls, &vg_lockd, list) {
 | 
			
		||||
		log_debug("adopt vg %s lock_type %s lock_args %s",
 | 
			
		||||
		log_debug("adopt lvmetad vg %s lock_type %s lock_args %s",
 | 
			
		||||
			  ls->vg_name, lm_str(ls->lm_type), ls->vg_args);
 | 
			
		||||
 | 
			
		||||
		list_for_each_entry(r, &ls->resources, list)
 | 
			
		||||
@@ -5341,7 +5336,7 @@ static void adopt_locks(void)
 | 
			
		||||
		/*
 | 
			
		||||
		 * LS in ls_found, not in vg_lockd.
 | 
			
		||||
		 * An lvm lockspace found in the lock manager has no
 | 
			
		||||
		 * corresponding VG.  This shouldn't usually
 | 
			
		||||
		 * corresponding VG in lvmetad.  This shouldn't usually
 | 
			
		||||
		 * happen, but it's possible the VG could have been removed
 | 
			
		||||
		 * while the orphaned lockspace from it was still around.
 | 
			
		||||
		 * Report an error and leave the ls in the lm alone.
 | 
			
		||||
@@ -5356,7 +5351,7 @@ static void adopt_locks(void)
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * LS in vg_lockd, not in ls_found.
 | 
			
		||||
	 * lockd vgs that do not have an existing lockspace.
 | 
			
		||||
	 * lockd vgs from lvmetad that do not have an existing lockspace.
 | 
			
		||||
	 * This wouldn't be unusual; we just skip the vg.
 | 
			
		||||
	 * But, if the vg has active lvs, then it should have had locks
 | 
			
		||||
	 * and a lockspace.  Should we attempt to join the lockspace and
 | 
			
		||||
@@ -5408,6 +5403,8 @@ static void adopt_locks(void)
 | 
			
		||||
		memcpy(act->vg_args, ls->vg_args, MAX_ARGS);
 | 
			
		||||
		act->host_id = ls->host_id;
 | 
			
		||||
 | 
			
		||||
		/* set act->version from lvmetad data? */
 | 
			
		||||
 | 
			
		||||
		log_debug("adopt add %s vg lockspace %s", lm_str(act->lm_type), act->vg_name);
 | 
			
		||||
 | 
			
		||||
		rv = add_lockspace_thread(ls->name, act->vg_name, act->vg_uuid,
 | 
			
		||||
@@ -5490,7 +5487,7 @@ static void adopt_locks(void)
 | 
			
		||||
				goto fail;
 | 
			
		||||
			act->op = LD_OP_LOCK;
 | 
			
		||||
			act->rt = LD_RT_LV;
 | 
			
		||||
			act->mode = r->adopt_mode;
 | 
			
		||||
			act->mode = LD_LK_EX;
 | 
			
		||||
			act->flags = (LD_AF_ADOPT | LD_AF_PERSISTENT);
 | 
			
		||||
			act->client_id = INTERNAL_CLIENT_ID;
 | 
			
		||||
			act->lm_type = ls->lm_type;
 | 
			
		||||
@@ -5588,9 +5585,8 @@ static void adopt_locks(void)
 | 
			
		||||
			 * Adopt failed because the orphan has a different mode
 | 
			
		||||
			 * than initially requested.  Repeat the lock-adopt operation
 | 
			
		||||
			 * with the other mode.  N.B. this logic depends on first
 | 
			
		||||
			 * trying sh then ex for GL/VG locks; for LV locks the mode
 | 
			
		||||
			 * from the adopt file is tried first, the alternate
 | 
			
		||||
			 * (if the mode in adopt file was wrong somehow.)
 | 
			
		||||
			 * trying sh then ex for GL/VG locks, and ex then sh for
 | 
			
		||||
			 * LV locks.
 | 
			
		||||
			 */
 | 
			
		||||
 | 
			
		||||
			if ((act->rt != LD_RT_LV) && (act->mode == LD_LK_SH)) {
 | 
			
		||||
@@ -5598,12 +5594,9 @@ static void adopt_locks(void)
 | 
			
		||||
				act->mode = LD_LK_EX;
 | 
			
		||||
				rv = add_lock_action(act);
 | 
			
		||||
 | 
			
		||||
			} else if (act->rt == LD_RT_LV) {
 | 
			
		||||
				/* LV locks: attempt to adopt the other mode. */
 | 
			
		||||
				if (act->mode == LD_LK_EX)
 | 
			
		||||
					act->mode = LD_LK_SH;
 | 
			
		||||
				else if (act->mode == LD_LK_SH)
 | 
			
		||||
					act->mode = LD_LK_EX;
 | 
			
		||||
			} else if ((act->rt == LD_RT_LV) && (act->mode == LD_LK_EX)) {
 | 
			
		||||
				/* LV locks: attempt to adopt sh after ex failed. */
 | 
			
		||||
				act->mode = LD_LK_SH;
 | 
			
		||||
				rv = add_lock_action(act);
 | 
			
		||||
 | 
			
		||||
			} else {
 | 
			
		||||
@@ -5738,13 +5731,10 @@ static void adopt_locks(void)
 | 
			
		||||
	if (count_start_fail || count_adopt_fail)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
	unlink(adopt_file);
 | 
			
		||||
	write_adopt_file();
 | 
			
		||||
	log_debug("adopt_locks done");
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
	unlink(adopt_file);
 | 
			
		||||
	log_error("adopt_locks failed, reset host");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -5873,16 +5863,24 @@ static int main_loop(daemon_state *ds_arg)
 | 
			
		||||
	setup_worker_thread();
 | 
			
		||||
	setup_restart();
 | 
			
		||||
 | 
			
		||||
#ifdef USE_SD_NOTIFY
 | 
			
		||||
	sd_notify(0, "READY=1");
 | 
			
		||||
#endif
 | 
			
		||||
	pthread_mutex_init(&lvmetad_mutex, NULL);
 | 
			
		||||
	lvmetad_handle = lvmetad_open(NULL);
 | 
			
		||||
	if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0)
 | 
			
		||||
		log_debug("lvmetad_open error %d", lvmetad_handle.error);
 | 
			
		||||
	else
 | 
			
		||||
		lvmetad_connected = 1;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Attempt to rejoin lockspaces and adopt locks from a previous
 | 
			
		||||
	 * instance of lvmlockd that left behind lockspaces/locks.
 | 
			
		||||
	 */
 | 
			
		||||
	if (adopt_opt)
 | 
			
		||||
		adopt_locks();
 | 
			
		||||
	if (adopt_opt) {
 | 
			
		||||
		/* FIXME: implement this without lvmetad */
 | 
			
		||||
		if (!lvmetad_connected)
 | 
			
		||||
			log_error("Cannot adopt locks without lvmetad running.");
 | 
			
		||||
		else
 | 
			
		||||
			adopt_locks();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		rv = poll(pollfd, pollfd_maxi + 1, -1);
 | 
			
		||||
@@ -5998,6 +5996,7 @@ static int main_loop(daemon_state *ds_arg)
 | 
			
		||||
	close_worker_thread();
 | 
			
		||||
	close_client_thread();
 | 
			
		||||
	closelog();
 | 
			
		||||
	daemon_close(lvmetad_handle);
 | 
			
		||||
	return 1; /* libdaemon uses 1 for success */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -6019,8 +6018,6 @@ static void usage(char *prog, FILE *file)
 | 
			
		||||
	fprintf(file, "        Set path to the pid file. [%s]\n", LVMLOCKD_PIDFILE);
 | 
			
		||||
	fprintf(file, "  --socket-path | -s <path>\n");
 | 
			
		||||
	fprintf(file, "        Set path to the socket to listen on. [%s]\n", LVMLOCKD_SOCKET);
 | 
			
		||||
	fprintf(file, "  --adopt-file <path>\n");
 | 
			
		||||
	fprintf(file, "        Set path to the adopt file. [%s]\n", LVMLOCKD_ADOPT_FILE);
 | 
			
		||||
	fprintf(file, "  --syslog-priority | -S err|warning|debug\n");
 | 
			
		||||
	fprintf(file, "        Write log messages from this level up to syslog. [%s]\n", _syslog_num_to_name(LOG_SYSLOG_PRIO));
 | 
			
		||||
	fprintf(file, "  --gl-type | -g <str>\n");
 | 
			
		||||
@@ -6038,14 +6035,14 @@ static void usage(char *prog, FILE *file)
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	daemon_state ds = {
 | 
			
		||||
		.name = "lvmlockd",
 | 
			
		||||
		.daemon_main = main_loop,
 | 
			
		||||
		.daemon_init = NULL,
 | 
			
		||||
		.daemon_fini = NULL,
 | 
			
		||||
		.pidfile = getenv("LVM_LVMLOCKD_PIDFILE"),
 | 
			
		||||
		.socket_path = getenv("LVM_LVMLOCKD_SOCKET"),
 | 
			
		||||
		.protocol = lvmlockd_protocol,
 | 
			
		||||
		.protocol_version = lvmlockd_protocol_version,
 | 
			
		||||
		.daemon_init = NULL,
 | 
			
		||||
		.daemon_fini = NULL,
 | 
			
		||||
		.daemon_main = main_loop,
 | 
			
		||||
		.name = "lvmlockd",
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static struct option long_options[] = {
 | 
			
		||||
@@ -6056,7 +6053,6 @@ int main(int argc, char *argv[])
 | 
			
		||||
		{"daemon-debug",    no_argument,       0, 'D' },
 | 
			
		||||
		{"pid-file",        required_argument, 0, 'p' },
 | 
			
		||||
		{"socket-path",     required_argument, 0, 's' },
 | 
			
		||||
		{"adopt-file",      required_argument, 0, 128 },
 | 
			
		||||
		{"gl-type",         required_argument, 0, 'g' },
 | 
			
		||||
		{"host-id",         required_argument, 0, 'i' },
 | 
			
		||||
		{"host-id-file",    required_argument, 0, 'F' },
 | 
			
		||||
@@ -6079,9 +6075,6 @@ int main(int argc, char *argv[])
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case '0':
 | 
			
		||||
			break;
 | 
			
		||||
		case 128:
 | 
			
		||||
			adopt_file = strdup(optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'h':
 | 
			
		||||
			usage(argv[0], stdout);
 | 
			
		||||
			exit(EXIT_SUCCESS);
 | 
			
		||||
@@ -6143,9 +6136,6 @@ int main(int argc, char *argv[])
 | 
			
		||||
	if (!ds.socket_path)
 | 
			
		||||
		ds.socket_path = LVMLOCKD_SOCKET;
 | 
			
		||||
 | 
			
		||||
	if (!adopt_file)
 | 
			
		||||
		adopt_file = LVMLOCKD_ADOPT_FILE;
 | 
			
		||||
 | 
			
		||||
	/* runs daemon_main/main_loop */
 | 
			
		||||
	daemon_start(ds);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,20 +11,19 @@
 | 
			
		||||
#define _XOPEN_SOURCE 500  /* pthread */
 | 
			
		||||
#define _ISOC99_SOURCE
 | 
			
		||||
 | 
			
		||||
#include "tools/tool.h"
 | 
			
		||||
#include "tool.h"
 | 
			
		||||
 | 
			
		||||
#include "daemon-server.h"
 | 
			
		||||
#include "lib/mm/xlate.h"
 | 
			
		||||
#include "xlate.h"
 | 
			
		||||
 | 
			
		||||
#include "lvmlockd-internal.h"
 | 
			
		||||
#include "daemons/lvmlockd/lvmlockd-client.h"
 | 
			
		||||
#include "lvmlockd-client.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Using synchronous _wait dlm apis so do not define _REENTRANT and
 | 
			
		||||
 * link with non-threaded version of library, libdlm_lt.
 | 
			
		||||
 */
 | 
			
		||||
#include "libdlm.h"
 | 
			
		||||
#include "libdlmcontrol.h"
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <poll.h>
 | 
			
		||||
@@ -128,18 +127,16 @@ static int read_cluster_name(char *clustername)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define MAX_VERSION 16
 | 
			
		||||
 | 
			
		||||
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
 | 
			
		||||
{
 | 
			
		||||
	char clustername[MAX_ARGS+1];
 | 
			
		||||
	char lock_args_version[MAX_VERSION+1];
 | 
			
		||||
	char lock_args_version[MAX_ARGS+1];
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	memset(clustername, 0, sizeof(clustername));
 | 
			
		||||
	memset(lock_args_version, 0, sizeof(lock_args_version));
 | 
			
		||||
 | 
			
		||||
	snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
 | 
			
		||||
	snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
 | 
			
		||||
		 VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
 | 
			
		||||
 | 
			
		||||
	rv = read_cluster_name(clustername);
 | 
			
		||||
@@ -151,9 +148,7 @@ int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
 | 
			
		||||
		return -EARGS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, clustername);
 | 
			
		||||
	if (rv >= MAX_ARGS)
 | 
			
		||||
		log_debug("init_vg_dlm vg_args may be too long %d %s", rv, vg_args);
 | 
			
		||||
	snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, clustername);
 | 
			
		||||
	rv = 0;
 | 
			
		||||
 | 
			
		||||
	log_debug("init_vg_dlm done %s vg_args %s", ls_name, vg_args);
 | 
			
		||||
@@ -277,9 +272,10 @@ static int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int wit
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
 | 
			
		||||
		buf = zalloc(sizeof(struct val_blk) + DLM_LVB_LEN);
 | 
			
		||||
		buf = malloc(sizeof(struct val_blk) + DLM_LVB_LEN);
 | 
			
		||||
		if (!buf)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		memset(buf, 0, sizeof(struct val_blk) + DLM_LVB_LEN);
 | 
			
		||||
 | 
			
		||||
		rdd->vb = (struct val_blk *)buf;
 | 
			
		||||
		rdd->lksb.sb_lvbptr = buf + sizeof(struct val_blk);
 | 
			
		||||
@@ -398,18 +394,12 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
 | 
			
		||||
			  (void *)1, (void *)1, (void *)1,
 | 
			
		||||
			  NULL, NULL);
 | 
			
		||||
 | 
			
		||||
	if (rv == -1 && (errno == EAGAIN)) {
 | 
			
		||||
	if (rv == -1 && errno == -EAGAIN) {
 | 
			
		||||
		log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
 | 
			
		||||
			  ls->name, r->name, ld_mode);
 | 
			
		||||
		rv = -EUCLEAN;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
	if (rv == -1 && (errno == ENOENT)) {
 | 
			
		||||
		log_debug("S %s R %s adopt_dlm adopt mode %d no lock",
 | 
			
		||||
			  ls->name, r->name, ld_mode);
 | 
			
		||||
		rv = -ENOENT;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
 | 
			
		||||
			  ls->name, r->name, mode, flags, rv, errno);
 | 
			
		||||
@@ -787,107 +777,3 @@ int lm_is_running_dlm(void)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef LOCKDDLM_CONTROL_SUPPORT
 | 
			
		||||
 | 
			
		||||
int lm_refresh_lv_start_dlm(struct action *act)
 | 
			
		||||
{
 | 
			
		||||
	char path[PATH_MAX];
 | 
			
		||||
	char command[DLMC_RUN_COMMAND_LEN];
 | 
			
		||||
	char run_uuid[DLMC_RUN_UUID_LEN];
 | 
			
		||||
	char *p, *vgname, *lvname;
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	/* split /dev/vgname/lvname into vgname and lvname strings */
 | 
			
		||||
	strncpy(path, act->path, strlen(act->path));
 | 
			
		||||
 | 
			
		||||
	/* skip past dev */
 | 
			
		||||
	p = strchr(path + 1, '/');
 | 
			
		||||
 | 
			
		||||
	/* skip past slashes */
 | 
			
		||||
	while (*p == '/')
 | 
			
		||||
		p++;
 | 
			
		||||
 | 
			
		||||
	/* start of vgname */
 | 
			
		||||
	vgname = p;
 | 
			
		||||
 | 
			
		||||
	/* skip past vgname */
 | 
			
		||||
	while (*p != '/')
 | 
			
		||||
		p++;
 | 
			
		||||
 | 
			
		||||
	/* terminate vgname */
 | 
			
		||||
	*p = '\0';
 | 
			
		||||
	p++;
 | 
			
		||||
 | 
			
		||||
	/* skip past slashes */
 | 
			
		||||
	while (*p == '/')
 | 
			
		||||
		p++;
 | 
			
		||||
 | 
			
		||||
	lvname = p;
 | 
			
		||||
 | 
			
		||||
	memset(command, 0, sizeof(command));
 | 
			
		||||
	memset(run_uuid, 0, sizeof(run_uuid));
 | 
			
		||||
 | 
			
		||||
	/* todo: add --readonly */
 | 
			
		||||
 | 
			
		||||
	snprintf(command, DLMC_RUN_COMMAND_LEN,
 | 
			
		||||
		 "lvm lvchange --refresh --partial --nolocking %s/%s",
 | 
			
		||||
		 vgname, lvname);
 | 
			
		||||
 | 
			
		||||
	rv = dlmc_run_start(command, strlen(command), 0,
 | 
			
		||||
			    DLMC_FLAG_RUN_START_NODE_NONE,
 | 
			
		||||
			    run_uuid);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_debug("refresh_lv run_start error %d", rv);
 | 
			
		||||
		return rv;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_debug("refresh_lv run_start %s", run_uuid);
 | 
			
		||||
 | 
			
		||||
	/* Bit of a hack here, we don't need path once started,
 | 
			
		||||
	   but we do need to save the run_uuid somewhere, so just
 | 
			
		||||
	   replace the path with the uuid. */
 | 
			
		||||
 | 
			
		||||
	free(act->path);
 | 
			
		||||
	act->path = strdup(run_uuid);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lm_refresh_lv_check_dlm(struct action *act)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t check_status = 0;
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	/* NB act->path was replaced with run_uuid */
 | 
			
		||||
 | 
			
		||||
	rv = dlmc_run_check(act->path, strlen(act->path), 0,
 | 
			
		||||
			    DLMC_FLAG_RUN_CHECK_CLEAR,
 | 
			
		||||
			    &check_status);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_debug("refresh_lv check error %d", rv);
 | 
			
		||||
		return rv;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_debug("refresh_lv check %s status %x", act->path, check_status);
 | 
			
		||||
 | 
			
		||||
	if (!(check_status & DLMC_RUN_STATUS_DONE))
 | 
			
		||||
		return -EAGAIN;
 | 
			
		||||
 | 
			
		||||
	if (check_status & DLMC_RUN_STATUS_FAILED)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else /* LOCKDDLM_CONTROL_SUPPORT */
 | 
			
		||||
 | 
			
		||||
int lm_refresh_lv_start_dlm(struct action *act)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lm_refresh_lv_check_dlm(struct action *act)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* LOCKDDLM_CONTROL_SUPPORT */
 | 
			
		||||
 
 | 
			
		||||
@@ -11,8 +11,6 @@
 | 
			
		||||
#ifndef _LVM_LVMLOCKD_INTERNAL_H
 | 
			
		||||
#define _LVM_LVMLOCKD_INTERNAL_H
 | 
			
		||||
 | 
			
		||||
#include "base/memory/container_of.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_NAME 64
 | 
			
		||||
#define MAX_ARGS 64
 | 
			
		||||
 | 
			
		||||
@@ -55,8 +53,6 @@ enum {
 | 
			
		||||
	LD_OP_KILL_VG,
 | 
			
		||||
	LD_OP_DROP_VG,
 | 
			
		||||
	LD_OP_BUSY,
 | 
			
		||||
	LD_OP_QUERY_LOCK,
 | 
			
		||||
	LD_OP_REFRESH_LV,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* resource types */
 | 
			
		||||
@@ -109,7 +105,6 @@ struct client {
 | 
			
		||||
#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
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Number of times to repeat a lock request after
 | 
			
		||||
@@ -132,7 +127,6 @@ struct action {
 | 
			
		||||
	int max_retries;
 | 
			
		||||
	int result;
 | 
			
		||||
	int lm_rv;			/* return value from lm_ function */
 | 
			
		||||
	char *path;
 | 
			
		||||
	char vg_uuid[64];
 | 
			
		||||
	char vg_name[MAX_NAME+1];
 | 
			
		||||
	char lv_name[MAX_NAME+1];
 | 
			
		||||
@@ -147,7 +141,6 @@ struct resource {
 | 
			
		||||
	char name[MAX_NAME+1];		/* vg name or lv name */
 | 
			
		||||
	int8_t type;			/* resource type LD_RT_ */
 | 
			
		||||
	int8_t mode;
 | 
			
		||||
	int8_t adopt_mode;
 | 
			
		||||
	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 */
 | 
			
		||||
@@ -158,7 +151,7 @@ struct resource {
 | 
			
		||||
	struct list_head locks;
 | 
			
		||||
	struct list_head actions;
 | 
			
		||||
	char lv_args[MAX_ARGS+1];
 | 
			
		||||
	char lm_data[];			/* lock manager specific data */
 | 
			
		||||
	char lm_data[0];		/* lock manager specific data */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define LD_LF_PERSISTENT 0x00000001
 | 
			
		||||
@@ -181,9 +174,7 @@ struct lockspace {
 | 
			
		||||
	int8_t lm_type;			/* lock manager: LM_DLM, LM_SANLOCK */
 | 
			
		||||
	void *lm_data;
 | 
			
		||||
	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 */
 | 
			
		||||
	uint64_t free_lock_offset;	/* start search for free lock here */
 | 
			
		||||
 | 
			
		||||
	uint32_t start_client_id;	/* client_id that started the lockspace */
 | 
			
		||||
	pthread_t thread;		/* makes synchronous lock requests */
 | 
			
		||||
@@ -219,6 +210,10 @@ struct val_blk {
 | 
			
		||||
/* lm_unlock flags */
 | 
			
		||||
#define LMUF_FREE_VG 0x00000001
 | 
			
		||||
 | 
			
		||||
#define container_of(ptr, type, member) ({                      \
 | 
			
		||||
	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
 | 
			
		||||
	(type *)( (char *)__mptr - offsetof(type,member) );})
 | 
			
		||||
 | 
			
		||||
static inline void INIT_LIST_HEAD(struct list_head *list)
 | 
			
		||||
{
 | 
			
		||||
	list->next = list;
 | 
			
		||||
@@ -392,8 +387,6 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin);
 | 
			
		||||
int lm_data_size_dlm(void);
 | 
			
		||||
int lm_is_running_dlm(void);
 | 
			
		||||
int lm_hosts_dlm(struct lockspace *ls, int notify);
 | 
			
		||||
int lm_refresh_lv_start_dlm(struct action *act);
 | 
			
		||||
int lm_refresh_lv_check_dlm(struct action *act);
 | 
			
		||||
 | 
			
		||||
static inline int lm_support_dlm(void)
 | 
			
		||||
{
 | 
			
		||||
@@ -470,22 +463,12 @@ static inline int lm_hosts_dlm(struct lockspace *ls, int notify)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_refresh_lv_start_dlm(struct action *act)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_refresh_lv_check_dlm(struct action *act)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* dlm support */
 | 
			
		||||
 | 
			
		||||
#ifdef LOCKDSANLOCK_SUPPORT
 | 
			
		||||
 | 
			
		||||
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_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset);
 | 
			
		||||
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
 | 
			
		||||
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
 | 
			
		||||
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
 | 
			
		||||
@@ -505,7 +488,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 *free_offset, int *sector_size, int *align_size);
 | 
			
		||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset);
 | 
			
		||||
 | 
			
		||||
static inline int lm_support_sanlock(void)
 | 
			
		||||
{
 | 
			
		||||
@@ -519,7 +502,7 @@ static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flag
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
static inline int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset)
 | 
			
		||||
{
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
@@ -607,7 +590,7 @@ static inline int lm_is_running_sanlock(void)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size)
 | 
			
		||||
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
 | 
			
		||||
{
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,42 +11,23 @@
 | 
			
		||||
#define _XOPEN_SOURCE 500  /* pthread */
 | 
			
		||||
#define _ISOC99_SOURCE
 | 
			
		||||
 | 
			
		||||
#include "tools/tool.h"
 | 
			
		||||
#include "tool.h"
 | 
			
		||||
 | 
			
		||||
#include "daemon-server.h"
 | 
			
		||||
#include "lib/mm/xlate.h"
 | 
			
		||||
#include "xlate.h"
 | 
			
		||||
 | 
			
		||||
#include "lvmlockd-internal.h"
 | 
			
		||||
#include "daemons/lvmlockd/lvmlockd-client.h"
 | 
			
		||||
#include "lvmlockd-client.h"
 | 
			
		||||
 | 
			
		||||
#include "sanlock.h"
 | 
			
		||||
#include "sanlock_rv.h"
 | 
			
		||||
#include "sanlock_admin.h"
 | 
			
		||||
#include "sanlock_resource.h"
 | 
			
		||||
 | 
			
		||||
/* FIXME: these are copied from sanlock.h only until
 | 
			
		||||
   an updated version of sanlock is available with them. */
 | 
			
		||||
#define SANLK_RES_ALIGN1M       0x00000010
 | 
			
		||||
#define SANLK_RES_ALIGN2M       0x00000020
 | 
			
		||||
#define SANLK_RES_ALIGN4M       0x00000040
 | 
			
		||||
#define SANLK_RES_ALIGN8M       0x00000080
 | 
			
		||||
#define SANLK_RES_SECTOR512     0x00000100
 | 
			
		||||
#define SANLK_RES_SECTOR4K      0x00000200
 | 
			
		||||
#define SANLK_LSF_ALIGN1M       0x00000010
 | 
			
		||||
#define SANLK_LSF_ALIGN2M       0x00000020
 | 
			
		||||
#define SANLK_LSF_ALIGN4M       0x00000040
 | 
			
		||||
#define SANLK_LSF_ALIGN8M       0x00000080
 | 
			
		||||
#define SANLK_LSF_SECTOR512     0x00000100
 | 
			
		||||
#define SANLK_LSF_SECTOR4K      0x00000200
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <poll.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
#include <blkid/blkid.h>
 | 
			
		||||
#include <sys/sysmacros.h>
 | 
			
		||||
 | 
			
		||||
#define ONE_MB 1048576
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
-------------------------------------------------------------------------------
 | 
			
		||||
@@ -158,7 +139,6 @@ release all the leases for the VG.
 | 
			
		||||
 | 
			
		||||
struct lm_sanlock {
 | 
			
		||||
	struct sanlk_lockspace ss;
 | 
			
		||||
	int sector_size;
 | 
			
		||||
	int align_size;
 | 
			
		||||
	int sock; /* sanlock daemon connection */
 | 
			
		||||
};
 | 
			
		||||
@@ -221,6 +201,7 @@ int lm_data_size_sanlock(void)
 | 
			
		||||
 * ...
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define LS_BEGIN 0
 | 
			
		||||
#define GL_LOCK_BEGIN UINT64_C(65)
 | 
			
		||||
#define VG_LOCK_BEGIN UINT64_C(66)
 | 
			
		||||
#define LV_LOCK_BEGIN UINT64_C(67)
 | 
			
		||||
@@ -307,8 +288,7 @@ static int read_host_id_file(void)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (fclose(file))
 | 
			
		||||
		log_debug("Failed to fclose host id file %s (%s).",
 | 
			
		||||
			  daemon_host_id_file, strerror(errno));
 | 
			
		||||
		log_error("failed to close host id file %s", daemon_host_id_file);
 | 
			
		||||
out:
 | 
			
		||||
	log_debug("host_id %d from %s", host_id, daemon_host_id_file);
 | 
			
		||||
	return host_id;
 | 
			
		||||
@@ -344,154 +324,6 @@ fail:
 | 
			
		||||
	return rv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _read_sysfs_size(dev_t devno, const char *name, unsigned int *val)
 | 
			
		||||
{
 | 
			
		||||
	char path[PATH_MAX];
 | 
			
		||||
	char buf[32];
 | 
			
		||||
	FILE *fp;
 | 
			
		||||
	size_t len;
 | 
			
		||||
 | 
			
		||||
	snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/queue/%s",
 | 
			
		||||
		 (int)major(devno), (int)minor(devno), name);
 | 
			
		||||
 | 
			
		||||
	if (!(fp = fopen(path, "r")))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (!fgets(buf, sizeof(buf), fp))
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if ((len = strlen(buf)) && buf[len - 1] == '\n')
 | 
			
		||||
		buf[--len] = '\0';
 | 
			
		||||
 | 
			
		||||
	if (strlen(buf))
 | 
			
		||||
		*val = atoi(buf);
 | 
			
		||||
out:
 | 
			
		||||
	if (fclose(fp))
 | 
			
		||||
		log_debug("Failed to fclose host id file %s (%s).", path, strerror(errno));
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Select sector/align size for a new VG based on what the device reports for
 | 
			
		||||
   sector size of the lvmlock LV. */
 | 
			
		||||
 | 
			
		||||
static int get_sizes_device(char *path, int *sector_size, int *align_size)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int physical_block_size = 0;
 | 
			
		||||
	unsigned int logical_block_size = 0;
 | 
			
		||||
	struct stat st;
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	rv = stat(path, &st);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_error("Failed to stat device to get block size %s %d", path, errno);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_read_sysfs_size(st.st_rdev, "physical_block_size", &physical_block_size);
 | 
			
		||||
	_read_sysfs_size(st.st_rdev, "logical_block_size", &logical_block_size);
 | 
			
		||||
 | 
			
		||||
	if ((physical_block_size == 512) && (logical_block_size == 512)) {
 | 
			
		||||
		*sector_size = 512;
 | 
			
		||||
		*align_size = ONE_MB;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((physical_block_size == 4096) && (logical_block_size == 4096)) {
 | 
			
		||||
		*sector_size = 4096;
 | 
			
		||||
		*align_size = 8 * ONE_MB;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (physical_block_size && (physical_block_size != 512) && (physical_block_size != 4096)) {
 | 
			
		||||
		log_warn("WARNING: invalid block sizes physical %u logical %u for %s",
 | 
			
		||||
			 physical_block_size, logical_block_size, path);
 | 
			
		||||
		physical_block_size = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (logical_block_size && (logical_block_size != 512) && (logical_block_size != 4096)) {
 | 
			
		||||
		log_warn("WARNING: invalid block sizes physical %u logical %u for %s",
 | 
			
		||||
			 physical_block_size, logical_block_size, path);
 | 
			
		||||
		logical_block_size = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!physical_block_size && !logical_block_size) {
 | 
			
		||||
		log_error("Failed to get a block size for %s", path);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!physical_block_size || !logical_block_size) {
 | 
			
		||||
		log_warn("WARNING: incomplete block size information physical %u logical %u for %s",
 | 
			
		||||
			 physical_block_size, logical_block_size, path);
 | 
			
		||||
		if (!physical_block_size)
 | 
			
		||||
			physical_block_size = logical_block_size;
 | 
			
		||||
		if (!logical_block_size)
 | 
			
		||||
			logical_block_size = physical_block_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((logical_block_size == 4096) && (physical_block_size == 512)) {
 | 
			
		||||
		log_warn("WARNING: mixed block sizes physical %u logical %u (using 4096) for %s",
 | 
			
		||||
			 physical_block_size, logical_block_size, path);
 | 
			
		||||
		*sector_size = 4096;
 | 
			
		||||
		*align_size = 8 * ONE_MB;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((physical_block_size == 4096) && (logical_block_size == 512)) {
 | 
			
		||||
		log_warn("WARNING: mixed block sizes physical %u logical %u (using 4096) for %s",
 | 
			
		||||
			 physical_block_size, logical_block_size, path);
 | 
			
		||||
		*sector_size = 4096;
 | 
			
		||||
		*align_size = 8 * ONE_MB;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (physical_block_size == 512) {
 | 
			
		||||
		*sector_size = 512;
 | 
			
		||||
		*align_size = ONE_MB;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (physical_block_size == 4096) {
 | 
			
		||||
		*sector_size = 4096;
 | 
			
		||||
		*align_size = 8 * ONE_MB;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_error("Failed to get a block size for %s", path);
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Get the sector/align sizes that were used to create an existing VG.
 | 
			
		||||
   sanlock encoded this in the lockspace/resource structs on disk. */
 | 
			
		||||
 | 
			
		||||
static int get_sizes_lockspace(char *path, int *sector_size, int *align_size)
 | 
			
		||||
{
 | 
			
		||||
	struct sanlk_lockspace ss;
 | 
			
		||||
	uint32_t io_timeout = 0;
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	memset(&ss, 0, sizeof(ss));
 | 
			
		||||
	memcpy(ss.host_id_disk.path, path, SANLK_PATH_LEN);
 | 
			
		||||
	ss.host_id_disk.offset = 0;
 | 
			
		||||
 | 
			
		||||
	rv = sanlock_read_lockspace(&ss, 0, &io_timeout);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_error("get_sizes_lockspace %s error %d", path, rv);
 | 
			
		||||
		return rv;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((ss.flags & SANLK_LSF_SECTOR4K) && (ss.flags & SANLK_LSF_ALIGN8M)) {
 | 
			
		||||
		*sector_size = 4096;
 | 
			
		||||
		*align_size = 8 * ONE_MB;
 | 
			
		||||
	} else if ((ss.flags & SANLK_LSF_SECTOR512) && (ss.flags & SANLK_LSF_ALIGN1M)) {
 | 
			
		||||
		*sector_size = 512;
 | 
			
		||||
		*align_size = ONE_MB;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_debug("get_sizes_lockspace found %d %d", *sector_size, *align_size);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * vgcreate
 | 
			
		||||
 *
 | 
			
		||||
@@ -500,21 +332,18 @@ static int get_sizes_lockspace(char *path, int *sector_size, int *align_size)
 | 
			
		||||
 * version and lv name, and returns the real lock_args in vg_args.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define MAX_VERSION 16
 | 
			
		||||
 | 
			
		||||
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
 | 
			
		||||
{
 | 
			
		||||
	struct sanlk_lockspace ss;
 | 
			
		||||
	struct sanlk_resourced rd;
 | 
			
		||||
	struct sanlk_disk disk;
 | 
			
		||||
	char lock_lv_name[MAX_ARGS+1];
 | 
			
		||||
	char lock_args_version[MAX_VERSION+1];
 | 
			
		||||
	char lock_args_version[MAX_ARGS+1];
 | 
			
		||||
	const char *gl_name = NULL;
 | 
			
		||||
	uint32_t daemon_version;
 | 
			
		||||
	uint32_t daemon_proto;
 | 
			
		||||
	uint64_t offset;
 | 
			
		||||
	int sector_size = 0;
 | 
			
		||||
	int align_size = 0;
 | 
			
		||||
	int align_size;
 | 
			
		||||
	int i, rv;
 | 
			
		||||
 | 
			
		||||
	memset(&ss, 0, sizeof(ss));
 | 
			
		||||
@@ -528,7 +357,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
 | 
			
		||||
		return -EARGS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
 | 
			
		||||
	snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
 | 
			
		||||
		 VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
 | 
			
		||||
 | 
			
		||||
	/* see comment above about input vg_args being only lock_lv_name */
 | 
			
		||||
@@ -545,9 +374,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
 | 
			
		||||
	if (daemon_test) {
 | 
			
		||||
		if (!gl_lsname_sanlock[0])
 | 
			
		||||
			strncpy(gl_lsname_sanlock, ls_name, MAX_NAME);
 | 
			
		||||
		rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
 | 
			
		||||
		if (rv >= MAX_ARGS)
 | 
			
		||||
			log_debug("init_vg_san vg_args may be too long %d %s", rv, vg_args);
 | 
			
		||||
		snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -560,25 +387,23 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
 | 
			
		||||
	log_debug("sanlock daemon version %08x proto %08x",
 | 
			
		||||
		  daemon_version, daemon_proto);
 | 
			
		||||
 | 
			
		||||
	/* Nothing formatted on disk yet, use what the device reports. */
 | 
			
		||||
	rv = get_sizes_device(disk.path, §or_size, &align_size);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
	rv = sanlock_align(&disk);
 | 
			
		||||
	if (rv <= 0) {
 | 
			
		||||
		if (rv == -EACCES) {
 | 
			
		||||
			log_error("S %s init_vg_san sanlock error -EACCES: no permission to access %s",
 | 
			
		||||
				  ls_name, disk.path);
 | 
			
		||||
			return -EDEVOPEN;
 | 
			
		||||
		} else {
 | 
			
		||||
			log_error("S %s init_vg_san sanlock error %d trying to get sector/align size of %s",
 | 
			
		||||
			log_error("S %s init_vg_san sanlock error %d trying to get align size of %s",
 | 
			
		||||
				  ls_name, rv, disk.path);
 | 
			
		||||
			return -EARGS;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	} else
 | 
			
		||||
		align_size = rv;
 | 
			
		||||
 | 
			
		||||
	strncpy(ss.name, ls_name, SANLK_NAME_LEN);
 | 
			
		||||
	memcpy(ss.host_id_disk.path, disk.path, SANLK_PATH_LEN);
 | 
			
		||||
	ss.host_id_disk.offset = 0;
 | 
			
		||||
	ss.flags = (sector_size == 4096) ? (SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN8M) :
 | 
			
		||||
					   (SANLK_LSF_SECTOR512 | SANLK_LSF_ALIGN1M);
 | 
			
		||||
	ss.host_id_disk.offset = LS_BEGIN * align_size;
 | 
			
		||||
 | 
			
		||||
	rv = sanlock_write_lockspace(&ss, 0, 0, sanlock_io_timeout);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
@@ -611,8 +436,6 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
 | 
			
		||||
	memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
 | 
			
		||||
	rd.rs.disks[0].offset = align_size * GL_LOCK_BEGIN;
 | 
			
		||||
	rd.rs.num_disks = 1;
 | 
			
		||||
	rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
 | 
			
		||||
					      (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
 | 
			
		||||
 | 
			
		||||
	rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
@@ -626,8 +449,6 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
 | 
			
		||||
	memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
 | 
			
		||||
	rd.rs.disks[0].offset = align_size * VG_LOCK_BEGIN;
 | 
			
		||||
	rd.rs.num_disks = 1;
 | 
			
		||||
	rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
 | 
			
		||||
					      (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
 | 
			
		||||
 | 
			
		||||
	rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
@@ -639,9 +460,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
 | 
			
		||||
	if (!strcmp(gl_name, R_NAME_GL))
 | 
			
		||||
		strncpy(gl_lsname_sanlock, ls_name, MAX_NAME);
 | 
			
		||||
 
 | 
			
		||||
	rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
 | 
			
		||||
	if (rv >= MAX_ARGS)
 | 
			
		||||
		log_debug("init_vg_san vg_args may be too long %d %s", rv, vg_args);
 | 
			
		||||
	snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
 | 
			
		||||
 | 
			
		||||
	log_debug("S %s init_vg_san done vg_args %s", ls_name, vg_args);
 | 
			
		||||
 | 
			
		||||
@@ -653,8 +472,6 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
 | 
			
		||||
 | 
			
		||||
	memset(&rd, 0, sizeof(rd));
 | 
			
		||||
	rd.rs.num_disks = 1;
 | 
			
		||||
	rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
 | 
			
		||||
					      (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
 | 
			
		||||
	memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
 | 
			
		||||
	strncpy(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
 | 
			
		||||
	strcpy(rd.rs.name, "#unused");
 | 
			
		||||
@@ -693,13 +510,13 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
		       char *vg_args, char *lv_args, uint64_t free_offset)
 | 
			
		||||
{
 | 
			
		||||
	struct sanlk_resourced rd;
 | 
			
		||||
	char lock_lv_name[MAX_ARGS+1];
 | 
			
		||||
	char lock_args_version[MAX_VERSION+1];
 | 
			
		||||
	char lock_args_version[MAX_ARGS+1];
 | 
			
		||||
	uint64_t offset;
 | 
			
		||||
	int align_size;
 | 
			
		||||
	int rv;
 | 
			
		||||
 | 
			
		||||
	memset(&rd, 0, sizeof(rd));
 | 
			
		||||
@@ -713,11 +530,11 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
 | 
			
		||||
		return rv;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
 | 
			
		||||
	snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
 | 
			
		||||
		 LV_LOCK_ARGS_MAJOR, LV_LOCK_ARGS_MINOR, LV_LOCK_ARGS_PATCH);
 | 
			
		||||
 | 
			
		||||
	if (daemon_test) {
 | 
			
		||||
		align_size = ONE_MB;
 | 
			
		||||
		align_size = 1048576;
 | 
			
		||||
		snprintf(lv_args, MAX_ARGS, "%s:%llu",
 | 
			
		||||
			 lock_args_version,
 | 
			
		||||
			 (unsigned long long)((align_size * LV_LOCK_BEGIN) + (align_size * daemon_test_lv_count)));
 | 
			
		||||
@@ -730,35 +547,12 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
 | 
			
		||||
	if ((rv = build_dm_path(rd.rs.disks[0].path, SANLK_PATH_LEN, vg_name, lock_lv_name)))
 | 
			
		||||
		return rv;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * These should not usually be zero, maybe only the first time this function is called?
 | 
			
		||||
	 * We need to use the same sector/align sizes that are already being used.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!sector_size || !align_size) {
 | 
			
		||||
		rv = get_sizes_lockspace(rd.rs.disks[0].path, §or_size, &align_size);
 | 
			
		||||
		if (rv < 0) {
 | 
			
		||||
			log_error("S %s init_lv_san read_lockspace error %d %s",
 | 
			
		||||
				  ls_name, rv, rd.rs.disks[0].path);
 | 
			
		||||
			return rv;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (sector_size)
 | 
			
		||||
			log_debug("S %s init_lv_san found ls sector_size %d align_size %d", ls_name, sector_size, align_size);
 | 
			
		||||
		else {
 | 
			
		||||
			/* use the old method */
 | 
			
		||||
			align_size = sanlock_align(&rd.rs.disks[0]);
 | 
			
		||||
			if (align_size <= 0) {
 | 
			
		||||
				log_error("S %s init_lv_san align error %d", ls_name, align_size);
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
			}
 | 
			
		||||
			sector_size = (align_size == ONE_MB) ? 512 : 4096;
 | 
			
		||||
			log_debug("S %s init_lv_san found old sector_size %d align_size %d", ls_name, sector_size, align_size);
 | 
			
		||||
		}
 | 
			
		||||
	align_size = sanlock_align(&rd.rs.disks[0]);
 | 
			
		||||
	if (align_size <= 0) {
 | 
			
		||||
		log_error("S %s init_lv_san align error %d", ls_name, align_size);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
 | 
			
		||||
					      (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
 | 
			
		||||
 | 
			
		||||
	if (free_offset)
 | 
			
		||||
		offset = free_offset;
 | 
			
		||||
	else
 | 
			
		||||
@@ -801,8 +595,6 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
 | 
			
		||||
				  ls_name, lv_name, (unsigned long long)offset);
 | 
			
		||||
 | 
			
		||||
			strncpy(rd.rs.name, lv_name, SANLK_NAME_LEN);
 | 
			
		||||
			rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
 | 
			
		||||
							      (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
 | 
			
		||||
 | 
			
		||||
			rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
 | 
			
		||||
			if (!rv) {
 | 
			
		||||
@@ -834,8 +626,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
 | 
			
		||||
	char lock_lv_name[MAX_ARGS+1];
 | 
			
		||||
	uint64_t offset;
 | 
			
		||||
	uint32_t io_timeout;
 | 
			
		||||
	int sector_size = 0;
 | 
			
		||||
	int align_size = 0;
 | 
			
		||||
	int align_size;
 | 
			
		||||
	int i, rv;
 | 
			
		||||
 | 
			
		||||
	memset(&disk, 0, sizeof(disk));
 | 
			
		||||
@@ -864,13 +655,20 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
 | 
			
		||||
	/* FIXME: device is not always ready for us here */
 | 
			
		||||
	sleep(1);
 | 
			
		||||
 | 
			
		||||
	align_size = sanlock_align(&disk);
 | 
			
		||||
	if (align_size <= 0) {
 | 
			
		||||
		log_error("S %s rename_vg_san bad align size %d %s",
 | 
			
		||||
			  ls_name, align_size, disk.path);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Lockspace
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	memset(&ss, 0, sizeof(ss));
 | 
			
		||||
	memcpy(ss.host_id_disk.path, disk.path, SANLK_PATH_LEN);
 | 
			
		||||
	ss.host_id_disk.offset = 0;
 | 
			
		||||
	ss.host_id_disk.offset = LS_BEGIN * align_size;
 | 
			
		||||
 | 
			
		||||
	rv = sanlock_read_lockspace(&ss, 0, &io_timeout);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
@@ -879,26 +677,6 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
 | 
			
		||||
		return rv;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((ss.flags & SANLK_LSF_SECTOR4K) && (ss.flags & SANLK_LSF_ALIGN8M)) {
 | 
			
		||||
		sector_size = 4096;
 | 
			
		||||
		align_size = 8 * ONE_MB;
 | 
			
		||||
	} else if ((ss.flags & SANLK_LSF_SECTOR512) && (ss.flags & SANLK_LSF_ALIGN1M)) {
 | 
			
		||||
		sector_size = 512;
 | 
			
		||||
		align_size = ONE_MB;
 | 
			
		||||
	} else {
 | 
			
		||||
		/* use the old method */
 | 
			
		||||
		align_size = sanlock_align(&ss.host_id_disk);
 | 
			
		||||
		if (align_size <= 0) {
 | 
			
		||||
			log_error("S %s rename_vg_san unknown sector/align size for %s",
 | 
			
		||||
				 ls_name, ss.host_id_disk.path);
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		sector_size = (align_size == ONE_MB) ? 512 : 4096;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!sector_size || !align_size)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	strncpy(ss.name, ls_name, SANLK_NAME_LEN);
 | 
			
		||||
 | 
			
		||||
	rv = sanlock_write_lockspace(&ss, 0, 0, sanlock_io_timeout);
 | 
			
		||||
@@ -1052,11 +830,6 @@ int lm_ex_disable_gl_sanlock(struct lockspace *ls)
 | 
			
		||||
	rd1.rs.num_disks = 1;
 | 
			
		||||
	strncpy(rd1.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
 | 
			
		||||
	rd1.rs.disks[0].offset = lms->align_size * GL_LOCK_BEGIN;
 | 
			
		||||
	
 | 
			
		||||
	rd1.rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
 | 
			
		||||
						    (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
 | 
			
		||||
	rd2.rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
 | 
			
		||||
						    (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
 | 
			
		||||
 | 
			
		||||
	rv = sanlock_acquire(lms->sock, -1, 0, 1, &rs1, NULL);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
@@ -1118,8 +891,6 @@ int lm_able_gl_sanlock(struct lockspace *ls, int enable)
 | 
			
		||||
	rd.rs.num_disks = 1;
 | 
			
		||||
	strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
 | 
			
		||||
	rd.rs.disks[0].offset = lms->align_size * GL_LOCK_BEGIN;
 | 
			
		||||
	rd.rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
 | 
			
		||||
						   (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
 | 
			
		||||
 | 
			
		||||
	rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
@@ -1165,8 +936,7 @@ static int gl_is_enabled(struct lockspace *ls, struct lm_sanlock *lms)
 | 
			
		||||
 | 
			
		||||
	rv = sanlock_read_resource(&rd.rs, 0);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_error("gl_is_enabled read_resource align_size %d offset %llu error %d",
 | 
			
		||||
			  lms->align_size, (unsigned long long)offset, rv);
 | 
			
		||||
		log_error("gl_is_enabled read_resource error %d", rv);
 | 
			
		||||
		return rv;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1203,7 +973,7 @@ int lm_gl_is_enabled(struct lockspace *ls)
 | 
			
		||||
 * been disabled.)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size)
 | 
			
		||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
 | 
			
		||||
{
 | 
			
		||||
	struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
 | 
			
		||||
	struct sanlk_resourced rd;
 | 
			
		||||
@@ -1213,22 +983,15 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *
 | 
			
		||||
	int round = 0;
 | 
			
		||||
 | 
			
		||||
	if (daemon_test) {
 | 
			
		||||
		*free_offset = (ONE_MB * LV_LOCK_BEGIN) + (ONE_MB * (daemon_test_lv_count + 1));
 | 
			
		||||
		*sector_size = 512;
 | 
			
		||||
		*align_size = ONE_MB;
 | 
			
		||||
		*free_offset = (1048576 * LV_LOCK_BEGIN) + (1048576 * (daemon_test_lv_count + 1));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*sector_size = lms->sector_size;
 | 
			
		||||
	*align_size = lms->align_size;
 | 
			
		||||
 | 
			
		||||
	memset(&rd, 0, sizeof(rd));
 | 
			
		||||
 | 
			
		||||
	strncpy(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
 | 
			
		||||
	rd.rs.num_disks = 1;
 | 
			
		||||
	strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
 | 
			
		||||
	rd.rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
 | 
			
		||||
						   (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
 | 
			
		||||
 | 
			
		||||
	if (ls->free_lock_offset)
 | 
			
		||||
		offset = ls->free_lock_offset;
 | 
			
		||||
@@ -1328,8 +1091,6 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
 | 
			
		||||
	char disk_path[SANLK_PATH_LEN];
 | 
			
		||||
	char killpath[SANLK_PATH_LEN];
 | 
			
		||||
	char killargs[SANLK_PATH_LEN];
 | 
			
		||||
	int sector_size = 0;
 | 
			
		||||
	int align_size = 0;
 | 
			
		||||
	int gl_found;
 | 
			
		||||
	int ret, rv;
 | 
			
		||||
 | 
			
		||||
@@ -1399,7 +1160,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lms = zalloc(sizeof(struct lm_sanlock));
 | 
			
		||||
	lms = malloc(sizeof(struct lm_sanlock));
 | 
			
		||||
	if (!lms) {
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto fail;
 | 
			
		||||
@@ -1408,6 +1169,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
 | 
			
		||||
	memset(lsname, 0, sizeof(lsname));
 | 
			
		||||
	strncpy(lsname, ls->name, SANLK_NAME_LEN);
 | 
			
		||||
 | 
			
		||||
	memset(lms, 0, sizeof(struct lm_sanlock));
 | 
			
		||||
	memcpy(lms->ss.name, lsname, SANLK_NAME_LEN);
 | 
			
		||||
	lms->ss.host_id_disk.offset = 0;
 | 
			
		||||
	lms->ss.host_id = ls->host_id;
 | 
			
		||||
@@ -1445,34 +1207,13 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rv = get_sizes_lockspace(disk_path, §or_size, &align_size);
 | 
			
		||||
	if (rv < 0) {
 | 
			
		||||
		log_error("S %s prepare_lockspace_san cannot get sector/align sizes %d", lsname, rv);
 | 
			
		||||
	lms->align_size = sanlock_align(&lms->ss.host_id_disk);
 | 
			
		||||
	if (lms->align_size <= 0) {
 | 
			
		||||
		log_error("S %s prepare_lockspace_san align error %d", lsname, lms->align_size);
 | 
			
		||||
		ret = -EMANAGER;
 | 
			
		||||
		goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!sector_size) {
 | 
			
		||||
		log_debug("S %s prepare_lockspace_san using old size method", lsname);
 | 
			
		||||
		/* use the old method */
 | 
			
		||||
		align_size = sanlock_align(&lms->ss.host_id_disk);
 | 
			
		||||
		if (align_size <= 0) {
 | 
			
		||||
			log_error("S %s prepare_lockspace_san align error %d", lsname, align_size);
 | 
			
		||||
			ret = -EINVAL;
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
		sector_size = (align_size == ONE_MB) ? 512 : 4096;
 | 
			
		||||
		log_debug("S %s prepare_lockspace_san found old sector_size %d align_size %d", lsname, sector_size, align_size);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_debug("S %s prepare_lockspace_san sizes %d %d", lsname, sector_size, align_size);
 | 
			
		||||
 | 
			
		||||
	lms->align_size = align_size;
 | 
			
		||||
	lms->sector_size = sector_size;
 | 
			
		||||
 | 
			
		||||
	lms->ss.flags = (sector_size == 4096) ? (SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN8M) :
 | 
			
		||||
						(SANLK_LSF_SECTOR512 | SANLK_LSF_ALIGN1M);
 | 
			
		||||
 | 
			
		||||
	gl_found = gl_is_enabled(ls, lms);
 | 
			
		||||
	if (gl_found < 0) {
 | 
			
		||||
		log_error("S %s prepare_lockspace_san gl_enabled error %d", lsname, gl_found);
 | 
			
		||||
@@ -1610,7 +1351,6 @@ static int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
 | 
			
		||||
	strncpy(rds->rs.name, r->name, SANLK_NAME_LEN);
 | 
			
		||||
	rds->rs.num_disks = 1;
 | 
			
		||||
	memcpy(rds->rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN);
 | 
			
		||||
	rds->rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) : (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
 | 
			
		||||
 | 
			
		||||
	if (r->type == LD_RT_GL)
 | 
			
		||||
		rds->rs.disks[0].offset = GL_LOCK_BEGIN * lms->align_size;
 | 
			
		||||
@@ -1620,9 +1360,10 @@ static int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
 | 
			
		||||
	/* LD_RT_LV offset is set in each lm_lock call from lv_args. */
 | 
			
		||||
 | 
			
		||||
	if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
 | 
			
		||||
		rds->vb = zalloc(sizeof(struct val_blk));
 | 
			
		||||
		rds->vb = malloc(sizeof(struct val_blk));
 | 
			
		||||
		if (!rds->vb)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		memset(rds->vb, 0, sizeof(struct val_blk));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
@@ -2119,20 +1860,12 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
 | 
			
		||||
	if (rv < 0)
 | 
			
		||||
		log_error("S %s R %s unlock_san release error %d", ls->name, r->name, rv);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * sanlock may return an error here if it fails to release the lease on
 | 
			
		||||
	 * disk because of an io timeout.  But, sanlock will continue trying to
 | 
			
		||||
	 * release the lease after this call returns.  We shouldn't return an
 | 
			
		||||
	 * error here which would result in lvmlockd-core keeping the lock
 | 
			
		||||
	 * around.  By releasing the lock in lvmlockd-core at this point,
 | 
			
		||||
	 * lvmlockd may send another acquire request to lvmlockd.  If sanlock
 | 
			
		||||
	 * has not been able to release the previous instance of the lock yet,
 | 
			
		||||
	 * then it will return an error for the new request.  But, acquiring a
 | 
			
		||||
	 * new lock is able o fail gracefully, until sanlock is finally able to
 | 
			
		||||
	 * release the old lock.
 | 
			
		||||
	 */
 | 
			
		||||
	if (rv == -EIO)
 | 
			
		||||
		rv = -ELOCKIO;
 | 
			
		||||
	else if (rv < 0)
 | 
			
		||||
		rv = -ELMERR;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	return rv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lm_hosts_sanlock(struct lockspace *ls, int notify)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,16 +29,15 @@ include $(top_builddir)/make.tmpl
 | 
			
		||||
 | 
			
		||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
 | 
			
		||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
 | 
			
		||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
 | 
			
		||||
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
 | 
			
		||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
 | 
			
		||||
LIBS += $(DAEMON_LIBS) -ldaemonserver -ldevmapper $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
 | 
			
		||||
	@echo "    [CC] $@"
 | 
			
		||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
 | 
			
		||||
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
 | 
			
		||||
		    $(top_builddir)/libdaemon/server/libdaemonserver.a
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
 | 
			
		||||
 | 
			
		||||
install_lvmpolld: lvmpolld
 | 
			
		||||
	@echo "    [INSTALL] $<"
 | 
			
		||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
	$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
			
		||||
 | 
			
		||||
install_lvm2: install_lvmpolld
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
 | 
			
		||||
	const char **newargv;
 | 
			
		||||
 | 
			
		||||
	if (*ind && !(*ind % MIN_ARGV_SIZE)) {
 | 
			
		||||
		newargv = realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
 | 
			
		||||
		newargv = dm_realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
 | 
			
		||||
		if (!newargv)
 | 
			
		||||
			return 0;
 | 
			
		||||
		*cmdargv = newargv;
 | 
			
		||||
@@ -50,7 +50,7 @@ static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
 | 
			
		||||
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort_polling, unsigned handle_missing_pvs)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i = 0;
 | 
			
		||||
	const char **cmd_argv = malloc(MIN_ARGV_SIZE * sizeof(char *));
 | 
			
		||||
	const char **cmd_argv = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
 | 
			
		||||
 | 
			
		||||
	if (!cmd_argv)
 | 
			
		||||
		return NULL;
 | 
			
		||||
@@ -98,7 +98,7 @@ const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary,
 | 
			
		||||
 | 
			
		||||
	return cmd_argv;
 | 
			
		||||
err:
 | 
			
		||||
	free(cmd_argv);
 | 
			
		||||
	dm_free(cmd_argv);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -122,7 +122,7 @@ static int copy_env(const char ***cmd_envp, unsigned *i, const char *exclude)
 | 
			
		||||
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i = 0;
 | 
			
		||||
	const char **cmd_envp = malloc(MIN_ARGV_SIZE * sizeof(char *));
 | 
			
		||||
	const char **cmd_envp = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
 | 
			
		||||
 | 
			
		||||
	if (!cmd_envp)
 | 
			
		||||
		return NULL;
 | 
			
		||||
@@ -141,6 +141,6 @@ const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
 | 
			
		||||
 | 
			
		||||
	return cmd_envp;
 | 
			
		||||
err:
 | 
			
		||||
	free(cmd_envp);
 | 
			
		||||
	dm_free(cmd_envp);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,10 +18,12 @@
 | 
			
		||||
#ifndef _LVM_LVMPOLLD_COMMON_H
 | 
			
		||||
#define _LVM_LVMPOLLD_COMMON_H
 | 
			
		||||
 | 
			
		||||
#include "tools/tool.h"
 | 
			
		||||
#define _REENTRANT
 | 
			
		||||
 | 
			
		||||
#include "tool.h"
 | 
			
		||||
 | 
			
		||||
#include "lvmpolld-cmd-utils.h"
 | 
			
		||||
#include "daemons/lvmpolld/lvmpolld-protocol.h"
 | 
			
		||||
#include "lvmpolld-protocol.h"
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user