mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-11-04 12:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			dev-dct-de
			...
			dev-bmr-dm
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					59a6fc0e4c | ||
| 
						 | 
					f64da7c628 | 
							
								
								
									
										112
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										112
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,15 +1,12 @@
 | 
				
			|||||||
*.5
 | 
					*.5
 | 
				
			||||||
*.7
 | 
					*.7
 | 
				
			||||||
*.8
 | 
					*.8
 | 
				
			||||||
*.8_gen
 | 
					 | 
				
			||||||
*.a
 | 
					*.a
 | 
				
			||||||
*.d
 | 
					*.d
 | 
				
			||||||
*.o
 | 
					*.o
 | 
				
			||||||
*.orig
 | 
					*.orig
 | 
				
			||||||
*.pc
 | 
					*.pc
 | 
				
			||||||
*.pot
 | 
					*.pot
 | 
				
			||||||
*.pyc
 | 
					 | 
				
			||||||
*.pyo
 | 
					 | 
				
			||||||
*.rej
 | 
					*.rej
 | 
				
			||||||
*.so
 | 
					*.so
 | 
				
			||||||
*.so.*
 | 
					*.so.*
 | 
				
			||||||
@@ -25,118 +22,9 @@ make.tmpl
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/autom4te.cache/
 | 
					/autom4te.cache/
 | 
				
			||||||
/autoscan.log
 | 
					/autoscan.log
 | 
				
			||||||
/build/
 | 
					 | 
				
			||||||
/config.cache
 | 
					 | 
				
			||||||
/config.log
 | 
					/config.log
 | 
				
			||||||
/config.status
 | 
					/config.status
 | 
				
			||||||
/configure.scan
 | 
					/configure.scan
 | 
				
			||||||
/cscope.out
 | 
					/cscope.out
 | 
				
			||||||
/html/
 | 
					 | 
				
			||||||
/reports/
 | 
					 | 
				
			||||||
/tags
 | 
					/tags
 | 
				
			||||||
/tmp/
 | 
					/tmp/
 | 
				
			||||||
 | 
					 | 
				
			||||||
coverity/coverity_model.xml
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
					 | 
				
			||||||
test/lib/lvdisplay
 | 
					 | 
				
			||||||
test/lib/lvextend
 | 
					 | 
				
			||||||
test/lib/lvmconfig
 | 
					 | 
				
			||||||
test/lib/lvmdiskscan
 | 
					 | 
				
			||||||
test/lib/lvmsadc
 | 
					 | 
				
			||||||
test/lib/lvmsar
 | 
					 | 
				
			||||||
test/lib/lvreduce
 | 
					 | 
				
			||||||
test/lib/lvremove
 | 
					 | 
				
			||||||
test/lib/lvrename
 | 
					 | 
				
			||||||
test/lib/lvresize
 | 
					 | 
				
			||||||
test/lib/lvs
 | 
					 | 
				
			||||||
test/lib/lvscan
 | 
					 | 
				
			||||||
test/lib/pvchange
 | 
					 | 
				
			||||||
test/lib/pvck
 | 
					 | 
				
			||||||
test/lib/pvcreate
 | 
					 | 
				
			||||||
test/lib/pvdisplay
 | 
					 | 
				
			||||||
test/lib/pvmove
 | 
					 | 
				
			||||||
test/lib/pvremove
 | 
					 | 
				
			||||||
test/lib/pvresize
 | 
					 | 
				
			||||||
test/lib/pvs
 | 
					 | 
				
			||||||
test/lib/pvscan
 | 
					 | 
				
			||||||
test/lib/securetest
 | 
					 | 
				
			||||||
test/lib/vgcfgbackup
 | 
					 | 
				
			||||||
test/lib/vgcfgrestore
 | 
					 | 
				
			||||||
test/lib/vgchange
 | 
					 | 
				
			||||||
test/lib/vgck
 | 
					 | 
				
			||||||
test/lib/vgconvert
 | 
					 | 
				
			||||||
test/lib/vgcreate
 | 
					 | 
				
			||||||
test/lib/vgdisplay
 | 
					 | 
				
			||||||
test/lib/vgexport
 | 
					 | 
				
			||||||
test/lib/vgextend
 | 
					 | 
				
			||||||
test/lib/vgimport
 | 
					 | 
				
			||||||
test/lib/vgimportclone
 | 
					 | 
				
			||||||
test/lib/vgmerge
 | 
					 | 
				
			||||||
test/lib/vgmknodes
 | 
					 | 
				
			||||||
test/lib/vgreduce
 | 
					 | 
				
			||||||
test/lib/vgremove
 | 
					 | 
				
			||||||
test/lib/vgrename
 | 
					 | 
				
			||||||
test/lib/vgs
 | 
					 | 
				
			||||||
test/lib/vgscan
 | 
					 | 
				
			||||||
test/lib/vgsplit
 | 
					 | 
				
			||||||
test/api/lvtest.t
 | 
					 | 
				
			||||||
test/api/pe_start.t
 | 
					 | 
				
			||||||
test/api/percent.t
 | 
					 | 
				
			||||||
test/api/python_lvm_unit.py
 | 
					 | 
				
			||||||
test/api/test
 | 
					 | 
				
			||||||
test/api/thin_percent.t
 | 
					 | 
				
			||||||
test/api/vglist.t
 | 
					 | 
				
			||||||
test/api/vgtest.t
 | 
					 | 
				
			||||||
test/lib/aux
 | 
					 | 
				
			||||||
test/lib/check
 | 
					 | 
				
			||||||
test/lib/clvmd
 | 
					 | 
				
			||||||
test/lib/dm-version-expected
 | 
					 | 
				
			||||||
test/lib/dmeventd
 | 
					 | 
				
			||||||
test/lib/dmsetup
 | 
					 | 
				
			||||||
test/lib/dmstats
 | 
					 | 
				
			||||||
test/lib/fail
 | 
					 | 
				
			||||||
test/lib/flavour-ndev-cluster
 | 
					 | 
				
			||||||
test/lib/flavour-ndev-cluster-lvmpolld
 | 
					 | 
				
			||||||
test/lib/flavour-ndev-lvmetad
 | 
					 | 
				
			||||||
test/lib/flavour-ndev-lvmetad-lvmpolld
 | 
					 | 
				
			||||||
test/lib/flavour-ndev-lvmpolld
 | 
					 | 
				
			||||||
test/lib/flavour-ndev-vanilla
 | 
					 | 
				
			||||||
test/lib/flavour-udev-cluster
 | 
					 | 
				
			||||||
test/lib/flavour-udev-cluster-lvmpolld
 | 
					 | 
				
			||||||
test/lib/flavour-udev-lvmetad
 | 
					 | 
				
			||||||
test/lib/flavour-udev-lvmetad-lvmpolld
 | 
					 | 
				
			||||||
test/lib/flavour-udev-lvmlockd-dlm
 | 
					 | 
				
			||||||
test/lib/flavour-udev-lvmlockd-sanlock
 | 
					 | 
				
			||||||
test/lib/flavour-udev-lvmlockd-test
 | 
					 | 
				
			||||||
test/lib/flavour-udev-lvmpolld
 | 
					 | 
				
			||||||
test/lib/flavour-udev-vanilla
 | 
					 | 
				
			||||||
test/lib/fsadm
 | 
					 | 
				
			||||||
test/lib/get
 | 
					 | 
				
			||||||
test/lib/inittest
 | 
					 | 
				
			||||||
test/lib/invalid
 | 
					 | 
				
			||||||
test/lib/lvm
 | 
					 | 
				
			||||||
test/lib/lvm-wrapper
 | 
					 | 
				
			||||||
test/lib/lvmchange
 | 
					 | 
				
			||||||
test/lib/lvmdbusd.profile
 | 
					 | 
				
			||||||
test/lib/lvmetad
 | 
					 | 
				
			||||||
test/lib/lvmpolld
 | 
					 | 
				
			||||||
test/lib/not
 | 
					 | 
				
			||||||
test/lib/paths
 | 
					 | 
				
			||||||
test/lib/paths-common
 | 
					 | 
				
			||||||
test/lib/runner
 | 
					 | 
				
			||||||
test/lib/should
 | 
					 | 
				
			||||||
test/lib/test
 | 
					 | 
				
			||||||
test/lib/thin-performance.profile
 | 
					 | 
				
			||||||
test/lib/utils
 | 
					 | 
				
			||||||
test/lib/version-expected
 | 
					 | 
				
			||||||
test/unit/dmraid_t.c
 | 
					 | 
				
			||||||
test/unit/unit-test
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								COPYING
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								COPYING
									
									
									
									
									
								
							@@ -2,7 +2,7 @@
 | 
				
			|||||||
		       Version 2, June 1991
 | 
							       Version 2, June 1991
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 | 
					 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 | 
				
			||||||
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
					     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 Everyone is permitted to copy and distribute verbatim copies
 | 
					 Everyone is permitted to copy and distribute verbatim copies
 | 
				
			||||||
 of this license document, but changing it is not allowed.
 | 
					 of this license document, but changing it is not allowed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -305,7 +305,7 @@ the "copyright" line and a pointer to where the full notice is found.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    You should have received a copy of the GNU General Public License
 | 
					    You should have received a copy of the GNU General Public License
 | 
				
			||||||
    along with this program; if not, write to the Free Software
 | 
					    along with this program; if not, write to the Free Software
 | 
				
			||||||
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Also add information on how to contact you by electronic and paper mail.
 | 
					Also add information on how to contact you by electronic and paper mail.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								COPYING.BSD
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								COPYING.BSD
									
									
									
									
									
								
							@@ -1,25 +0,0 @@
 | 
				
			|||||||
BSD 2-Clause License
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Copyright (c) 2014, Red Hat, Inc.
 | 
					 | 
				
			||||||
All rights reserved.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Redistribution and use in source and binary forms, with or without
 | 
					 | 
				
			||||||
modification, are permitted provided that the following conditions are met:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
1. Redistributions of source code must retain the above copyright notice, this
 | 
					 | 
				
			||||||
   list of conditions and the following disclaimer.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2. Redistributions in binary form must reproduce the above copyright notice,
 | 
					 | 
				
			||||||
   this list of conditions and the following disclaimer in the documentation
 | 
					 | 
				
			||||||
   and/or other materials provided with the distribution.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | 
					 | 
				
			||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
					 | 
				
			||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
					 | 
				
			||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 | 
					 | 
				
			||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
					 | 
				
			||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
					 | 
				
			||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
					 | 
				
			||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
					 | 
				
			||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
					 | 
				
			||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
					 | 
				
			||||||
							
								
								
									
										124
									
								
								Makefile.in
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								Makefile.in
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
 | 
					# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
 | 
				
			||||||
# 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.
 | 
					# This file is part of LVM2.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
# along with this program; if not, write to the Free Software Foundation,
 | 
					# along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
srcdir = @srcdir@
 | 
					srcdir = @srcdir@
 | 
				
			||||||
top_srcdir = @top_srcdir@
 | 
					top_srcdir = @top_srcdir@
 | 
				
			||||||
@@ -28,6 +28,14 @@ ifeq ("@INTL@", "yes")
 | 
				
			|||||||
  SUBDIRS += po
 | 
					  SUBDIRS += po
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ("@APPLIB@", "yes")
 | 
				
			||||||
 | 
					  SUBDIRS += liblvm
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ("@PYTHON_BINDINGS@", "yes")
 | 
				
			||||||
 | 
					  SUBDIRS += python
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(MAKECMDGOALS),clean)
 | 
					ifeq ($(MAKECMDGOALS),clean)
 | 
				
			||||||
  SUBDIRS += test
 | 
					  SUBDIRS += test
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
@@ -35,7 +43,8 @@ endif
 | 
				
			|||||||
ifeq ($(MAKECMDGOALS),distclean)
 | 
					ifeq ($(MAKECMDGOALS),distclean)
 | 
				
			||||||
  SUBDIRS = conf include man test scripts \
 | 
					  SUBDIRS = conf include man test scripts \
 | 
				
			||||||
    libdaemon lib tools daemons libdm \
 | 
					    libdaemon lib tools daemons libdm \
 | 
				
			||||||
    udev po
 | 
					    udev po liblvm python \
 | 
				
			||||||
 | 
					    unit-tests/datastruct unit-tests/mm unit-tests/regex
 | 
				
			||||||
tools.distclean: test.distclean
 | 
					tools.distclean: test.distclean
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
DISTCLEAN_DIRS += lcov_reports*
 | 
					DISTCLEAN_DIRS += lcov_reports*
 | 
				
			||||||
@@ -43,25 +52,18 @@ DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
include make.tmpl
 | 
					include make.tmpl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include $(top_srcdir)/base/Makefile
 | 
					 | 
				
			||||||
include $(top_srcdir)/device_mapper/Makefile
 | 
					 | 
				
			||||||
include $(top_srcdir)/test/unit/Makefile
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
libdm: include
 | 
					libdm: include
 | 
				
			||||||
libdaemon: include
 | 
					libdaemon: include
 | 
				
			||||||
lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
 | 
					lib: libdm libdaemon
 | 
				
			||||||
 | 
					liblvm: lib
 | 
				
			||||||
daemons: lib libdaemon tools
 | 
					daemons: lib libdaemon tools
 | 
				
			||||||
scripts: lib
 | 
					tools: lib libdaemon device-mapper
 | 
				
			||||||
tools: lib libdaemon
 | 
					 | 
				
			||||||
po: tools daemons
 | 
					po: tools daemons
 | 
				
			||||||
man: tools
 | 
					scripts: liblvm libdm
 | 
				
			||||||
all_man: tools
 | 
					 | 
				
			||||||
scripts: libdm
 | 
					 | 
				
			||||||
test: tools daemons
 | 
					 | 
				
			||||||
unit-test  run-unit-test: test
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
lib.device-mapper: include.device-mapper
 | 
					lib.device-mapper: include.device-mapper
 | 
				
			||||||
libdm.device-mapper: include.device-mapper
 | 
					libdm.device-mapper: include.device-mapper
 | 
				
			||||||
 | 
					liblvm.device-mapper: include.device-mapper
 | 
				
			||||||
daemons.device-mapper: libdm.device-mapper
 | 
					daemons.device-mapper: libdm.device-mapper
 | 
				
			||||||
tools.device-mapper: libdm.device-mapper
 | 
					tools.device-mapper: libdm.device-mapper
 | 
				
			||||||
scripts.device-mapper: include.device-mapper
 | 
					scripts.device-mapper: include.device-mapper
 | 
				
			||||||
@@ -75,6 +77,10 @@ po.pofile: tools.pofile daemons.pofile
 | 
				
			|||||||
pofile: po.pofile
 | 
					pofile: po.pofile
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ("@PYTHON_BINDINGS@", "yes")
 | 
				
			||||||
 | 
					python: liblvm
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifneq ("$(CFLOW_CMD)", "")
 | 
					ifneq ("$(CFLOW_CMD)", "")
 | 
				
			||||||
tools.cflow: libdm.cflow lib.cflow
 | 
					tools.cflow: libdm.cflow lib.cflow
 | 
				
			||||||
daemons.cflow: tools.cflow
 | 
					daemons.cflow: tools.cflow
 | 
				
			||||||
@@ -89,10 +95,10 @@ endif
 | 
				
			|||||||
DISTCLEAN_TARGETS += cscope.out
 | 
					DISTCLEAN_TARGETS += cscope.out
 | 
				
			||||||
CLEAN_DIRS += autom4te.cache
 | 
					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 unit: all
 | 
				
			||||||
	$(MAKE) -C test $(@)
 | 
						$(MAKE) -C test $(@)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
conf.generate man.generate: tools
 | 
					conf.generate: tools
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# how to use parenthesis in makefiles
 | 
					# how to use parenthesis in makefiles
 | 
				
			||||||
leftparen:=(
 | 
					leftparen:=(
 | 
				
			||||||
@@ -122,12 +128,8 @@ rpm: dist
 | 
				
			|||||||
	    $(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
 | 
						    $(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
 | 
				
			||||||
	rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
 | 
						rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
generate: conf.generate man.generate
 | 
					generate: conf.generate
 | 
				
			||||||
	$(MAKE) -C conf generate
 | 
						$(MAKE) -C conf generate
 | 
				
			||||||
	$(MAKE) -C man generate
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
all_man:
 | 
					 | 
				
			||||||
	$(MAKE) -C man all_man
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_system_dirs:
 | 
					install_system_dirs:
 | 
				
			||||||
	$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
 | 
						$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
 | 
				
			||||||
@@ -138,7 +140,7 @@ install_system_dirs:
 | 
				
			|||||||
	$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR)
 | 
						$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR)
 | 
				
			||||||
	$(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache
 | 
						$(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_initscripts:
 | 
					install_initscripts: 
 | 
				
			||||||
	$(MAKE) -C scripts install_initscripts
 | 
						$(MAKE) -C scripts install_initscripts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_systemd_generators:
 | 
					install_systemd_generators:
 | 
				
			||||||
@@ -148,14 +150,26 @@ install_systemd_generators:
 | 
				
			|||||||
install_systemd_units:
 | 
					install_systemd_units:
 | 
				
			||||||
	$(MAKE) -C scripts install_systemd_units
 | 
						$(MAKE) -C scripts install_systemd_units
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_all_man:
 | 
					install_full_man:
 | 
				
			||||||
	$(MAKE) -C man install_all_man
 | 
						$(MAKE) -C man install_full_man
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ("@PYTHON_BINDINGS@", "yes")
 | 
				
			||||||
 | 
					install_python_bindings:
 | 
				
			||||||
 | 
						$(MAKE) -C liblvm/python install_python_bindings
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_tmpfiles_configuration:
 | 
					install_tmpfiles_configuration:
 | 
				
			||||||
	$(MAKE) -C scripts 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 \
 | 
				
			||||||
 | 
						daemons/clvmd.info daemons/dmeventd.info \
 | 
				
			||||||
 | 
						daemons/lvmetad.info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CLEAN_TARGETS += $(LCOV_TRACES)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifneq ("$(LCOV)", "")
 | 
					ifneq ("$(LCOV)", "")
 | 
				
			||||||
.PHONY: lcov-reset lcov lcov-dated
 | 
					.PHONY: lcov-reset lcov lcov-dated $(LCOV_TRACES)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(MAKECMDGOALS),lcov-dated)
 | 
					ifeq ($(MAKECMDGOALS),lcov-dated)
 | 
				
			||||||
LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S)
 | 
					LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S)
 | 
				
			||||||
@@ -165,26 +179,60 @@ LCOV_REPORTS_DIR := lcov_reports
 | 
				
			|||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lcov-reset:
 | 
					lcov-reset:
 | 
				
			||||||
	$(LCOV) --zerocounters --directory $(top_builddir)
 | 
						$(LCOV) --zerocounters $(addprefix -d , $(basename $(LCOV_TRACES)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# maybe use subdirs processing to create tracefiles...
 | 
				
			||||||
 | 
					$(LCOV_TRACES):
 | 
				
			||||||
 | 
						$(LCOV) -b $(basename $@) -d $(basename $@) \
 | 
				
			||||||
 | 
							--ignore-errors source -c -o - | $(SED) \
 | 
				
			||||||
 | 
							-e "s/\(dmeventd_lvm.[ch]\)/plugins\/lvm2\/\1/" \
 | 
				
			||||||
 | 
							-e "s/dmeventd_\(mirror\|snapshot\|thin\|raid\)\.c/plugins\/\1\/dmeventd_\1\.c/" \
 | 
				
			||||||
 | 
							>$@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifneq ("$(GENHTML)", "")
 | 
					ifneq ("$(GENHTML)", "")
 | 
				
			||||||
lcov:
 | 
					lcov: $(LCOV_TRACES)
 | 
				
			||||||
	$(RM) -rf $(LCOV_REPORTS_DIR)
 | 
						$(RM) -r $(LCOV_REPORTS_DIR)
 | 
				
			||||||
	$(MKDIR_P) $(LCOV_REPORTS_DIR)
 | 
						$(MKDIR_P) $(LCOV_REPORTS_DIR)
 | 
				
			||||||
	$(LCOV) --capture --directory $(top_builddir) --ignore-errors source \
 | 
						for i in $(LCOV_TRACES); do \
 | 
				
			||||||
		--output-file $(LCOV_REPORTS_DIR)/out.info
 | 
							test -s $$i -a $$(wc -w <$$i) -ge 100 && lc="$$lc $$i"; \
 | 
				
			||||||
	-test ! -s $(LCOV_REPORTS_DIR)/out.info || \
 | 
						done; \
 | 
				
			||||||
		$(GENHTML) -o $(LCOV_REPORTS_DIR) --ignore-errors source \
 | 
						test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \
 | 
				
			||||||
		$(LCOV_REPORTS_DIR)/out.info
 | 
							-o $(LCOV_REPORTS_DIR) $$lc
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifneq ($(shell which ctags 2>/dev/null),)
 | 
					ifeq ("$(TESTING)", "yes")
 | 
				
			||||||
 | 
					# testing and report generation
 | 
				
			||||||
 | 
					RUBY=ruby1.9 -Ireport-generators/lib -Ireport-generators/test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: unit-test ruby-test test-programs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# FIXME: put dependencies on libdm and liblvm
 | 
				
			||||||
 | 
					# FIXME: Should be handled by Makefiles in subdirs, not here at top level.
 | 
				
			||||||
 | 
					test-programs:
 | 
				
			||||||
 | 
						cd unit-tests/regex && $(MAKE)
 | 
				
			||||||
 | 
						cd unit-tests/datastruct && $(MAKE)
 | 
				
			||||||
 | 
						cd unit-tests/mm && $(MAKE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unit-test: test-programs
 | 
				
			||||||
 | 
						$(RUBY) report-generators/unit_test.rb $(shell find . -name TESTS)
 | 
				
			||||||
 | 
						$(RUBY) report-generators/title_page.rb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					memcheck: test-programs
 | 
				
			||||||
 | 
						$(RUBY) report-generators/memcheck.rb $(shell find . -name TESTS)
 | 
				
			||||||
 | 
						$(RUBY) report-generators/title_page.rb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ruby-test:
 | 
				
			||||||
 | 
						$(RUBY) report-generators/test/ts.rb
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifneq ($(shell which ctags),)
 | 
				
			||||||
.PHONY: tags
 | 
					.PHONY: tags
 | 
				
			||||||
 | 
					all: tags
 | 
				
			||||||
tags:
 | 
					tags:
 | 
				
			||||||
	test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
 | 
						test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags | head -1)" || $(RM) tags
 | 
				
			||||||
	test -f tags || find $(top_srcdir) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
 | 
						test -f tags || find $(top_srcdir) -maxdepth 4 -type f -name '*.[ch]' -exec ctags -a '{}' +
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CLEAN_TARGETS += tags
 | 
					DISTCLEAN_TARGETS += tags
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								README
									
									
									
									
									
								
							@@ -1,25 +1,16 @@
 | 
				
			|||||||
This tree contains the LVM2 and device-mapper tools and libraries.
 | 
					This tree contains the LVM2 and device-mapper tools and libraries.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This is development branch, for stable 2.02 release see 2018-06-01-stable
 | 
					 | 
				
			||||||
branch.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
For more information about LVM2 read the changelog in the WHATS_NEW file.
 | 
					For more information about LVM2 read the changelog in the WHATS_NEW file.
 | 
				
			||||||
Installation instructions are in INSTALL.
 | 
					Installation instructions are in INSTALL.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
There is no warranty - see COPYING and COPYING.LIB.
 | 
					There is no warranty - see COPYING and COPYING.LIB.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Tarballs are available from:
 | 
					Tarballs are available from:
 | 
				
			||||||
  ftp://sourceware.org/pub/lvm2/
 | 
					 | 
				
			||||||
  ftp://sources.redhat.com/pub/lvm2/
 | 
					  ftp://sources.redhat.com/pub/lvm2/
 | 
				
			||||||
  https://github.com/lvmteam/lvm2/releases
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
The source code is stored in git:
 | 
					The source code is stored in git:
 | 
				
			||||||
  https://sourceware.org/git/?p=lvm2.git
 | 
					  http://git.fedorahosted.org/git/lvm2.git
 | 
				
			||||||
  git clone git://sourceware.org/git/lvm2.git
 | 
					  git clone git://git.fedorahosted.org/git/lvm2.git
 | 
				
			||||||
mirrored to:
 | 
					 | 
				
			||||||
  https://github.com/lvmteam/lvm2
 | 
					 | 
				
			||||||
  git clone https://github.com/lvmteam/lvm2.git
 | 
					 | 
				
			||||||
  git clone git@github.com:lvmteam/lvm2.git
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Mailing list for general discussion related to LVM2:
 | 
					Mailing list for general discussion related to LVM2:
 | 
				
			||||||
  linux-lvm@redhat.com
 | 
					  linux-lvm@redhat.com
 | 
				
			||||||
@@ -37,14 +28,6 @@ and multipath-tools:
 | 
				
			|||||||
  dm-devel@redhat.com
 | 
					  dm-devel@redhat.com
 | 
				
			||||||
  Subscribe from https://www.redhat.com/mailman/listinfo/dm-devel
 | 
					  Subscribe from https://www.redhat.com/mailman/listinfo/dm-devel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Website:
 | 
					 | 
				
			||||||
  https://sourceware.org/lvm2/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Report upstream bugs at:
 | 
					 | 
				
			||||||
  https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper
 | 
					 | 
				
			||||||
or open issues at:
 | 
					 | 
				
			||||||
  https://github.com/lvmteam/lvm2/issues
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The source code repository used until 7th June 2012 is accessible here:
 | 
					The source code repository used until 7th June 2012 is accessible here:
 | 
				
			||||||
  http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2.
 | 
					  http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										62
									
								
								TESTING
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								TESTING
									
									
									
									
									
								
							@@ -1,62 +0,0 @@
 | 
				
			|||||||
LVM2 Test Suite
 | 
					 | 
				
			||||||
===============
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The codebase contains many tests in the test subdirectory.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Before running tests
 | 
					 | 
				
			||||||
--------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Keep in mind the testsuite MUST run under root user.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
It is recommended not to use LVM on the test machine, especially when running
 | 
					 | 
				
			||||||
tests with udev (`make check_system`.)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
You MUST disable (or mask) any LVM daemons:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- lvmetad
 | 
					 | 
				
			||||||
- dmeventd
 | 
					 | 
				
			||||||
- lvmpolld
 | 
					 | 
				
			||||||
- lvmdbusd
 | 
					 | 
				
			||||||
- lvmlockd
 | 
					 | 
				
			||||||
- clvmd
 | 
					 | 
				
			||||||
- cmirrord
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
For running cluster tests, we are using singlenode locking. Pass
 | 
					 | 
				
			||||||
`--with-clvmd=singlenode` to configure.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
NOTE: This is useful only for testing, and should not be used in produciton
 | 
					 | 
				
			||||||
code.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
To run D-Bus daemon tests, existing D-Bus session is required.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Running tests
 | 
					 | 
				
			||||||
-------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
As root run:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    make check
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
To run only tests matching a string:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    make check T=test
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
To skip tests matching a string:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    make check S=test
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
There are other targets and many environment variables can be used to tweak the
 | 
					 | 
				
			||||||
testsuite - for full list and description run `make -C test help`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Installing testsuite
 | 
					 | 
				
			||||||
--------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
It is possible to install and run a testsuite against installed LVM. Run the
 | 
					 | 
				
			||||||
following:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    make -C test install
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Then lvm2-testsuite binary can be executed to test installed binaries.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
See `lvm2-testsuite --help` for options. The same environment variables can be
 | 
					 | 
				
			||||||
used as with `make check`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -1 +1 @@
 | 
				
			|||||||
1.02.173-git (2020-03-26)
 | 
					1.02.107-git (2015-08-26)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										379
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										379
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							@@ -1,382 +1,13 @@
 | 
				
			|||||||
Version 1.02.173 - 
 | 
					Version 1.02.107 - 
 | 
				
			||||||
==================================
 | 
					 | 
				
			||||||
  Add support for VDO in blkdeactivate script.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.171 - 26th March 2020
 | 
					 | 
				
			||||||
==================================
 | 
					 | 
				
			||||||
  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.
 | 
					 | 
				
			||||||
  Fix versioning of dm_stats_create_region and dm_stats_create_region.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.163 - 15th June 2019
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.161 - 10th June 2019
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.159 - 07th June 2019
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
  Parsing of cache status understand no_discard_passdown.
 | 
					 | 
				
			||||||
  Ensure migration_threshold for cache is at least 8 chunks.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.155 - 18th December 2018
 | 
					 | 
				
			||||||
=====================================
 | 
					 | 
				
			||||||
  Include correct internal header inside libdm list.c.
 | 
					 | 
				
			||||||
  Enhance ioctl flattening and add parameters only when needed.
 | 
					 | 
				
			||||||
  Add DM_DEVICE_ARM_POLL for API completness matching kernel.
 | 
					 | 
				
			||||||
  Do not add parameters for RESUME with DM_DEVICE_CREATE dm task.
 | 
					 | 
				
			||||||
  Fix dmstats report printing no output.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.153 - 31st October 2018
 | 
					 | 
				
			||||||
====================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.151 - 10th October 2018
 | 
					 | 
				
			||||||
====================================
 | 
					 | 
				
			||||||
  Add hot fix to avoiding locking collision when monitoring thin-pools.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.150 - 01 August 2018
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
  Add vdo plugin for monitoring VDO devices.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.149 - 19th July 2018
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.148 - 18th June 2018
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.147 - 13th June 2018
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.147-rc1 - 24th May 2018
 | 
					 | 
				
			||||||
====================================
 | 
					 | 
				
			||||||
  Reuse uname() result for mirror target.
 | 
					 | 
				
			||||||
  Recognize also mounted btrfs through dm_device_has_mounted_fs().
 | 
					 | 
				
			||||||
  Add missing log_error() into dm_stats_populate() returning 0.
 | 
					 | 
				
			||||||
  Avoid calling dm_stats_populat() for DM devices without any stats regions.
 | 
					 | 
				
			||||||
  Support DM_DEBUG_WITH_LINE_NUMBERS envvar for debug msg with source:line.
 | 
					 | 
				
			||||||
  Configured command for thin pool threshold handling gets whole environment.
 | 
					 | 
				
			||||||
  Fix tests for failing dm_snprintf() in stats code.
 | 
					 | 
				
			||||||
  Parsing mirror status accepts 'userspace' keyword in status.
 | 
					 | 
				
			||||||
  Introduce dm_malloc_aligned for page alignment of buffers.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.146 - 18th December 2017
 | 
					 | 
				
			||||||
=====================================
 | 
					 | 
				
			||||||
  Activation tree of thin pool skips duplicated check of pool status.
 | 
					 | 
				
			||||||
  Remove code supporting replicator target.
 | 
					 | 
				
			||||||
  Do not ignore failure of _info_by_dev().
 | 
					 | 
				
			||||||
  Propagate delayed resume for pvmove subvolumes.
 | 
					 | 
				
			||||||
  Suppress integrity encryption keys in 'table' output unless --showkeys supplied.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.145 - 3rd November 2017
 | 
					 | 
				
			||||||
====================================
 | 
					 | 
				
			||||||
  Keep Install section only in dm-event.socket systemd unit.
 | 
					 | 
				
			||||||
  Issue a specific error with dmsetup status if device is unknown.
 | 
					 | 
				
			||||||
  Fix RT_LIBS reference in generated libdevmapper.pc for pkg-config
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.144 - 6th October 2017
 | 
					 | 
				
			||||||
===================================
 | 
					===================================
 | 
				
			||||||
  Schedule exit when received SIGTERM in dmeventd.
 | 
					 | 
				
			||||||
  Also try to unmount /boot on blkdeactivate -u if on top of supported device.
 | 
					 | 
				
			||||||
  Use blkdeactivate -r wait in blk-availability systemd service/initscript.
 | 
					 | 
				
			||||||
  Add blkdeactivate -r wait option to wait for MD resync/recovery/reshape.
 | 
					 | 
				
			||||||
  Fix blkdeactivate regression with failing DM/MD devs deactivation (1.02.142).
 | 
					 | 
				
			||||||
  Fix typo in blkdeactivate's '--{dm,lvm,mpath}options' option name.
 | 
					 | 
				
			||||||
  Correct return value testing when get reserved values for reporting.
 | 
					 | 
				
			||||||
  Take -S with dmsetup suspend/resume/clear/wipe_table/remove/deps/status/table.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.143 - 13th September 2017
 | 
					 | 
				
			||||||
======================================
 | 
					 | 
				
			||||||
  Restore umask when creation of node fails.
 | 
					 | 
				
			||||||
  Add --concise to dmsetup create for many devices with tables in one command.
 | 
					 | 
				
			||||||
  Accept minor number without major in library when it knows dm major number.
 | 
					 | 
				
			||||||
  Introduce single-line concise table output format: dmsetup table --concise
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.142 - 20th July 2017
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
  Create /dev/disk/by-part{uuid,label} and gpt-auto-root symlinks with udev.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.141 - 28th June 2017
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
  Fix reusing of dm_task structure for status reading (used by dmeventd).
 | 
					 | 
				
			||||||
  Add dm_percent_to_round_float for adjusted percentage rounding.
 | 
					 | 
				
			||||||
  Reset array with dead rimage devices once raid gets in sync.
 | 
					 | 
				
			||||||
  Drop unneeded --config option from raid dmeventd plugin.
 | 
					 | 
				
			||||||
  dm_get_status_raid() handle better some incosistent md statuses.
 | 
					 | 
				
			||||||
  Accept truncated files in calls to dm_stats_update_regions_from_fd().
 | 
					 | 
				
			||||||
  Restore Warning by 5% increment when thin-pool is over 80% (1.02.138).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.140 - 3rd May 2017
 | 
					 | 
				
			||||||
===============================
 | 
					 | 
				
			||||||
  Add missing configure --enable-dmfilemapd status message and fix --disable.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.139 - 13th April 2017
 | 
					 | 
				
			||||||
==================================
 | 
					 | 
				
			||||||
  Fix assignment in _target_version() when dm task can't run.
 | 
					 | 
				
			||||||
  Flush stdout on each iteration when using --count or --interval.
 | 
					 | 
				
			||||||
  Show detailed error message when execvp fails while starting dmfilemapd.
 | 
					 | 
				
			||||||
  Fix segmentation fault when dmfilemapd is run with no arguments.
 | 
					 | 
				
			||||||
  Numerous minor dmfilemapd fixes from coverity.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.138 - 28th March 2017
 | 
					 | 
				
			||||||
==================================
 | 
					 | 
				
			||||||
  Support additional raid5/6 configurations.
 | 
					 | 
				
			||||||
  Provide dm_tree_node_add_cache_target@base compatible symbol.
 | 
					 | 
				
			||||||
  Support DM_CACHE_FEATURE_METADATA2, new cache metadata format 2.
 | 
					 | 
				
			||||||
  Improve code to handle mode mask for cache nodes.
 | 
					 | 
				
			||||||
  Cache status check for passthrough also require trailing space.
 | 
					 | 
				
			||||||
  Add extra memory page when limiting pthread stack size in dmeventd.
 | 
					 | 
				
			||||||
  Avoids immediate resume when preloaded device is smaller.
 | 
					 | 
				
			||||||
  Do not suppress kernel key description in dmsetup table output for dm-crypt.
 | 
					 | 
				
			||||||
  Support configurable command executed from dmeventd thin plugin.
 | 
					 | 
				
			||||||
  Support new R|r human readable units output format.
 | 
					 | 
				
			||||||
  Thin dmeventd plugin reacts faster on lvextend failure path with umount.
 | 
					 | 
				
			||||||
  Add dm_stats_bind_from_fd() to bind a stats handle from a file descriptor.
 | 
					 | 
				
			||||||
  Do not try call callback when reverting activation on error path.
 | 
					 | 
				
			||||||
  Fix file mapping for extents with physically adjacent extents in dmstats.
 | 
					 | 
				
			||||||
  Validation vsnprintf result in runtime translate of dm_log (1.02.136).
 | 
					 | 
				
			||||||
  Separate filemap extent allocation from region table in dmstats.
 | 
					 | 
				
			||||||
  Fix segmentation fault when filemap region creation fails in dmstats.
 | 
					 | 
				
			||||||
  Fix performance of region cleanup for failed filemap creation in dmstats.
 | 
					 | 
				
			||||||
  Fix very slow region deletion with many regions in dmstats.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.137 - 30th November 2016
 | 
					 | 
				
			||||||
=====================================
 | 
					 | 
				
			||||||
  Document raid status values.
 | 
					 | 
				
			||||||
  Always exit dmsetup with success when asked to display help/version.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.136 - 5th November 2016
 | 
					 | 
				
			||||||
====================================
 | 
					 | 
				
			||||||
  Log failure of raid device with log_error level.
 | 
					 | 
				
			||||||
  Use dm_log_with_errno and translate runtime to dm_log only when needed.
 | 
					 | 
				
			||||||
  Make log messages from dm and lvm library different from dmeventd.
 | 
					 | 
				
			||||||
  Notice and Info messages are again logged from dmeventd and its plugins.
 | 
					 | 
				
			||||||
  Dmeventd now also respects DM_ABORT_ON_INTERNAL_ERRORS as libdm based tool.
 | 
					 | 
				
			||||||
  Report as non default dm logging also when logging with errno was changed.
 | 
					 | 
				
			||||||
  Use log_level() macro to consistently decode message log level in dmeventd.
 | 
					 | 
				
			||||||
  Still produce output when dmsetup dependency tree building finds dev missing.
 | 
					 | 
				
			||||||
  Check and report pthread_sigmask() failure in dmeventd.
 | 
					 | 
				
			||||||
  Check mem alloc fail in _canonicalize_field_ids().
 | 
					 | 
				
			||||||
  Use unsigned math when checking more then 31 legs of raid.
 | 
					 | 
				
			||||||
  Fix 'dmstats delete' with dmsetup older than v1.02.129
 | 
					 | 
				
			||||||
  Fix stats walk segfault with dmsetup older than v1.02.129
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.135 - 26th September 2016
 | 
					 | 
				
			||||||
======================================
 | 
					 | 
				
			||||||
  Fix man entry for dmsetup status.
 | 
					 | 
				
			||||||
  Introduce new dm_config_parse_without_dup_node_check().
 | 
					 | 
				
			||||||
  Don't omit last entry in dmstats list --group.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.134 - 7th September 2016
 | 
					 | 
				
			||||||
=====================================
 | 
					 | 
				
			||||||
  Improve explanation of udev fallback in libdevmapper.h.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.133 - 10th August 2016
 | 
					 | 
				
			||||||
===================================
 | 
					 | 
				
			||||||
  Add dm_report_destroy_rows/dm_report_group_output_and_pop_all for lvm shell.
 | 
					 | 
				
			||||||
  Adjust group handling and json production for lvm shell.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.132 - 28th July 2016
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
  Fix json reporting to escape '"' character that may appear in reported string.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.131 - 15th July 2016
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
  Disable queueing on mpath devs in blk-availability systemd service/initscript.
 | 
					 | 
				
			||||||
  Add new -m|--mpathoption disablequeueing to blkdeactivate.
 | 
					 | 
				
			||||||
  Automatically group regions with 'create --segments' unless --nogroup.
 | 
					 | 
				
			||||||
  Fix resource leak when deleting the first member of a group.
 | 
					 | 
				
			||||||
  Allow --bounds with 'create --filemap' for dmstats.
 | 
					 | 
				
			||||||
  Enable creation of filemap regions with histograms.
 | 
					 | 
				
			||||||
  Enable histogram aggregation for regions with more than one area.
 | 
					 | 
				
			||||||
  Enable histogram aggregation for groups of regions.
 | 
					 | 
				
			||||||
  Add a --filemap option to 'dmstats create' to allow mapping of files.
 | 
					 | 
				
			||||||
  Add dm_stats_create_regions_from_fd() to map file extents to regions.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.130 - 6th July 2016
 | 
					 | 
				
			||||||
================================
 | 
					 | 
				
			||||||
  Minor fixes from coverity.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.129 - 6th July 2016
 | 
					 | 
				
			||||||
================================
 | 
					 | 
				
			||||||
  Update default dmstats field selections for groups.
 | 
					 | 
				
			||||||
  Add 'obj_type', 'group_id', and 'statsname' fields to dmstats reports.
 | 
					 | 
				
			||||||
  Add --area, --region, and --group to dmstats to control object selection.
 | 
					 | 
				
			||||||
  Add --alias, --groupid, --regions to dmstats for group creation and deletion.
 | 
					 | 
				
			||||||
  Add 'group' and 'ungroup' commands to dmstats.
 | 
					 | 
				
			||||||
  Allow dm_stats_delete_group() to optionally delete all group members.
 | 
					 | 
				
			||||||
  Add dm_stats_get_object_type() to return the type of object present.
 | 
					 | 
				
			||||||
  Add dm_stats_walk_init() allowing control of objects visited by walks.
 | 
					 | 
				
			||||||
  Add dm_stats_get_group_descriptor() to return the member list as a string.
 | 
					 | 
				
			||||||
  Introduce dm_stats_get_nr_groups() and dm_stats_group_present().
 | 
					 | 
				
			||||||
  Add dm_stats_{get,set}_alias() to set and retrieve alias names for groups.
 | 
					 | 
				
			||||||
  Add dm_stats_get_group_id() to return the group ID for a given region.
 | 
					 | 
				
			||||||
  Add dm_stats_{create,delete}_group() to allow grouping of stats regions.
 | 
					 | 
				
			||||||
  Add enum-driven dm_stats_get_{metric,counter}() interfaces.
 | 
					 | 
				
			||||||
  Add dm_bitset_parse_list() to parse a string representation of a bitset.
 | 
					 | 
				
			||||||
  Thin dmeventd plugin umounts lvm2 volume only when pool is 95% or more.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.128 - 25th June 2016
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
  Recognize 'all' keyword used in selection as synonym for "" (no selection).
 | 
					 | 
				
			||||||
  Add dm_report_set_selection to set selection for multiple output of report.
 | 
					 | 
				
			||||||
  Add DM_REPORT_OUTPUT_MULTIPLE_TIMES flag for multiple output of same report.
 | 
					 | 
				
			||||||
  Move field width handling/sort init from dm_report_object to dm_report_output.
 | 
					 | 
				
			||||||
  Add _LOG_BYPASS_REPORT flag for bypassing any log report currently set.
 | 
					 | 
				
			||||||
  Introduce DM_REPORT_GROUP_JSON for report group with JSON output format.
 | 
					 | 
				
			||||||
  Introduce DM_REPORT_GROUP_BASIC for report group with basic report output.
 | 
					 | 
				
			||||||
  Introduce DM_REPORT_GROUP_SINGLE for report group having single report only.
 | 
					 | 
				
			||||||
  Add dm_report_group_{create,push,pop,destroy} to support report grouping.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.127 - 11th June 2016
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
 Fix blkdeactivate regression causing skipping of dm + md devices. (1.02.126)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.126 - 3rd June 2016
 | 
					 | 
				
			||||||
================================
 | 
					 | 
				
			||||||
  Report passthrough caching mode when parsing cache mode.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.125 - 14th May 2016
 | 
					 | 
				
			||||||
================================
 | 
					 | 
				
			||||||
  Show library version in message even if dm driver version is unavailable.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.124 - 30th April 2016
 | 
					 | 
				
			||||||
==================================
 | 
					 | 
				
			||||||
  Add dm_udev_wait_immediate to libdevmapper for waiting outside the library.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.123 - 23rd April 2016
 | 
					 | 
				
			||||||
==================================
 | 
					 | 
				
			||||||
  Do not strip LVM- when debug reporting not found uuid.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.122 - 9th April 2016
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
  Change log_debug ioctl flags from single characters into words.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.121 - 26th March 2016
 | 
					 | 
				
			||||||
==================================
 | 
					 | 
				
			||||||
  Adjust raid status function.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.120 - 11th March 2016
 | 
					 | 
				
			||||||
==================================
 | 
					 | 
				
			||||||
  Improve parsing of cache status and report Fail, Error, needs_check, ro.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.119 - 4th March 2016
 | 
					 | 
				
			||||||
=================================
 | 
					 | 
				
			||||||
  Fix dm_config_write_node and variants to return error on subsection failures.
 | 
					 | 
				
			||||||
  Remove 4096 char limit due to buffer size if writing dm_config_node.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.118 - 26th February 2016
 | 
					 | 
				
			||||||
=====================================
 | 
					 | 
				
			||||||
  Fix string boundary check in _get_canonical_field_name().
 | 
					 | 
				
			||||||
  Always initialized hist struct in _stats_parse_histogram().
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.117 - 21st February 2016
 | 
					 | 
				
			||||||
=====================================
 | 
					 | 
				
			||||||
  Improve status parsing for thin-pool and thin devices.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.116 - 15th February 2016
 | 
					 | 
				
			||||||
=====================================
 | 
					 | 
				
			||||||
  Use fully aligned allocations for dm_pool_strdup/strndup() (1.02.64).
 | 
					 | 
				
			||||||
  Fix thin-pool table parameter feature order to match kernel output.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.115 - 25th January 2016
 | 
					 | 
				
			||||||
====================================
 | 
					 | 
				
			||||||
  Fix man page for dmsetup udevcreatecookie.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.114 - 14th December 2015
 | 
					 | 
				
			||||||
=====================================
 | 
					 | 
				
			||||||
  Better support for dmsetup static linkage.
 | 
					 | 
				
			||||||
  Extend validity checks on dmeventd client socket.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.113 - 5th December 2015
 | 
					 | 
				
			||||||
====================================
 | 
					 | 
				
			||||||
  Mirror plugin in dmeventd uses dm_get_status_mirror().
 | 
					 | 
				
			||||||
  Add dm_get_status_mirror() for parsing mirror status line.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.112 - 28th November 2015
 | 
					 | 
				
			||||||
=====================================
 | 
					 | 
				
			||||||
  Show error message when trying to create unsupported raid type.
 | 
					 | 
				
			||||||
  Improve preloading sequence of an active thin-pool target.
 | 
					 | 
				
			||||||
  Drop extra space from cache target line to fix unneded table reloads.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.111 - 23rd November 2015
 | 
					 | 
				
			||||||
=====================================
 | 
					 | 
				
			||||||
  Extend dm_hash to support multiple values with the same key.
 | 
					 | 
				
			||||||
  Add missing check for allocation inside dm_split_lvm_name().
 | 
					 | 
				
			||||||
  Test dm_task_get_message_response for !NULL in dm_stats_print_region().
 | 
					 | 
				
			||||||
  Add checks for failing dm_stats_create() in dmsetup.
 | 
					 | 
				
			||||||
  Add missing fifo close when failed to initialize client connection.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.110 - 30th October 2015
 | 
					 | 
				
			||||||
====================================
 | 
					 | 
				
			||||||
  Disable thin monitoring plugin when it fails too often (>10 times).
 | 
					 | 
				
			||||||
  Fix/restore parsing of empty field '-' when processing dmeventd event.
 | 
					 | 
				
			||||||
  Enhance dm_tree_node_size_changed() to recognize size reduction.
 | 
					 | 
				
			||||||
  Support exit on idle for dmenventd (1 hour).
 | 
					 | 
				
			||||||
  Add support to allow unmonitor device from plugin itself.
 | 
					 | 
				
			||||||
  New design for thread co-operation in dmeventd.
 | 
					 | 
				
			||||||
  Dmeventd read device status with 'noflush'.
 | 
					 | 
				
			||||||
  Dmeventd closes control device when no device is monitored.
 | 
					 | 
				
			||||||
  Thin plugin for dmeventd improved percentage usage.
 | 
					 | 
				
			||||||
  Snapshot plugin for dmeventd improved percentage usage.
 | 
					 | 
				
			||||||
  Add dm_hold_control_dev to allow holding of control device open.
 | 
					 | 
				
			||||||
  Add dm_report_compact_given_fields to remove given empty fields from report.
 | 
					 | 
				
			||||||
  Use libdm status parsing and local mem raid dmeventd plugin.
 | 
					 | 
				
			||||||
  Use local mem pool and lock only lvm2 execution for mirror dmeventd plugin.
 | 
					 | 
				
			||||||
  Lock protect only lvm2 execution for snapshot and thin dmeventd plugin.
 | 
					 | 
				
			||||||
  Use local mempool for raid and mirror plugins.
 | 
					 | 
				
			||||||
  Reworked thread initialization for dmeventd plugins.
 | 
					 | 
				
			||||||
  Dmeventd handles snapshot overflow for now equally as invalid.
 | 
					 | 
				
			||||||
  Convert dmeventd to use common logging macro system from libdm.
 | 
					 | 
				
			||||||
  Return -ENOMEM when device registration fails instead of 0 (=success).
 | 
					 | 
				
			||||||
  Enforce writethrough mode for cleaner policy.
 | 
					 | 
				
			||||||
  Add support for recognition and deactivation of MD devices to blkdeactivate.
 | 
					 | 
				
			||||||
  Move target status functions out of libdm-deptree.
 | 
					 | 
				
			||||||
  Correct use of max_write_behind parameter when generating raid target line.
 | 
					 | 
				
			||||||
  Fix dm-event systemd service to make sure it is executed before mounting.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.109 - 22nd September 2015
 | 
					 | 
				
			||||||
======================================
 | 
					 | 
				
			||||||
  Update man pages for dmsetup and dmstats.
 | 
					 | 
				
			||||||
  Improve help text for dmsetup.
 | 
					 | 
				
			||||||
  Use --noflush and --nolockfs when removing device with --force.
 | 
					 | 
				
			||||||
  Parse new Overflow status string for snapshot target.
 | 
					 | 
				
			||||||
  Check dir path components are valid if using dm_create_dir, error out if not.
 | 
					 | 
				
			||||||
  Fix /dev/mapper handling to remove dangling entries if symlinks are found.
 | 
					 | 
				
			||||||
  Make it possible to use blank value as selection for string list report field.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.108 - 15th September 2015
 | 
					 | 
				
			||||||
======================================
 | 
					 | 
				
			||||||
  Do not check for full thin pool when activating without messages (1.02.107).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Version 1.02.107 - 5th September 2015
 | 
					 | 
				
			||||||
=====================================
 | 
					 | 
				
			||||||
  Parse thin-pool status with one single routine internally.
 | 
					 | 
				
			||||||
  Add --histogram to select default histogram fields for list and report.
 | 
					 | 
				
			||||||
  Add report fields for displaying latency histogram configuration and data.
 | 
					 | 
				
			||||||
  Add dmstats --bounds to specify histogram boundaries for a new region.
 | 
					 | 
				
			||||||
  Add dm_histogram_to_string() to format histogram data in string form.
 | 
					 | 
				
			||||||
  Add public methods to libdm to access numerical histogram config and data.
 | 
					 | 
				
			||||||
  Parse and store histogram data in dm_stats_list() and dm_stats_populate().
 | 
					 | 
				
			||||||
  Add an argument to specify histogram bounds to dm_stats_create_region().
 | 
					 | 
				
			||||||
  Add dm_histogram_bounds_from_{string,uint64_t}() to parse histogram bounds.
 | 
					 | 
				
			||||||
  Add dm_histogram handle type to represent a latency histogram and its bounds.
 | 
					 | 
				
			||||||
  Fix devmapper.pc pkgconfig file to not reference non-existent rt.pc file.
 | 
					 | 
				
			||||||
  Reinstate dm_task_get_info@Base to libdevmapper exports. (1.02.106)
 | 
					  Reinstate dm_task_get_info@Base to libdevmapper exports. (1.02.106)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Version 1.02.106 - 26th August 2015
 | 
					Version 1.02.106 - 26th August 2015
 | 
				
			||||||
===================================
 | 
					===================================
 | 
				
			||||||
 | 
					  Add basic report fields for displaying latency histogram data.
 | 
				
			||||||
 | 
					  Add dmstats --histogram to specify histogram boundaries for a region.
 | 
				
			||||||
 | 
					  Add public methods to libdm-stats to access numerical histogram data.
 | 
				
			||||||
 | 
					  Add the ability to parse histogram data into numeric form to libdm-stats.
 | 
				
			||||||
  Add 'precise' column to statistics reports.
 | 
					  Add 'precise' column to statistics reports.
 | 
				
			||||||
  Add --precise switch to 'dmstats create' to request nanosecond counters.
 | 
					  Add --precise switch to 'dmstats create' to request nanosecond counters.
 | 
				
			||||||
  Add precise argument to dm_stats_create_region().
 | 
					  Add precise argument to dm_stats_create_region().
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										171
									
								
								acinclude.m4
									
									
									
									
									
								
							
							
						
						
									
										171
									
								
								acinclude.m4
									
									
									
									
									
								
							@@ -61,174 +61,3 @@ AC_DEFUN([AC_TRY_LDFLAGS],
 | 
				
			|||||||
        ifelse([$4], [], [:], [$4])
 | 
					        ifelse([$4], [], [:], [$4])
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
 | 
					 | 
				
			||||||
# ===========================================================================
 | 
					 | 
				
			||||||
#      http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html
 | 
					 | 
				
			||||||
# ===========================================================================
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# SYNOPSIS
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   AX_GCC_BUILTIN(BUILTIN)
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# DESCRIPTION
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   This macro checks if the compiler supports one of GCC's built-in
 | 
					 | 
				
			||||||
#   functions; many other compilers also provide those same built-ins.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   The BUILTIN parameter is the name of the built-in function.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   If BUILTIN is supported define HAVE_<BUILTIN>. Keep in mind that since
 | 
					 | 
				
			||||||
#   builtins usually start with two underscores they will be copied over
 | 
					 | 
				
			||||||
#   into the HAVE_<BUILTIN> definition (e.g. HAVE___BUILTIN_EXPECT for
 | 
					 | 
				
			||||||
#   __builtin_expect()).
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   The macro caches its result in the ax_cv_have_<BUILTIN> variable (e.g.
 | 
					 | 
				
			||||||
#   ax_cv_have___builtin_expect).
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   The macro currently supports the following built-in functions:
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#    __builtin_assume_aligned
 | 
					 | 
				
			||||||
#    __builtin_bswap16
 | 
					 | 
				
			||||||
#    __builtin_bswap32
 | 
					 | 
				
			||||||
#    __builtin_bswap64
 | 
					 | 
				
			||||||
#    __builtin_choose_expr
 | 
					 | 
				
			||||||
#    __builtin___clear_cache
 | 
					 | 
				
			||||||
#    __builtin_clrsb
 | 
					 | 
				
			||||||
#    __builtin_clrsbl
 | 
					 | 
				
			||||||
#    __builtin_clrsbll
 | 
					 | 
				
			||||||
#    __builtin_clz
 | 
					 | 
				
			||||||
#    __builtin_clzl
 | 
					 | 
				
			||||||
#    __builtin_clzll
 | 
					 | 
				
			||||||
#    __builtin_complex
 | 
					 | 
				
			||||||
#    __builtin_constant_p
 | 
					 | 
				
			||||||
#    __builtin_ctz
 | 
					 | 
				
			||||||
#    __builtin_ctzl
 | 
					 | 
				
			||||||
#    __builtin_ctzll
 | 
					 | 
				
			||||||
#    __builtin_expect
 | 
					 | 
				
			||||||
#    __builtin_ffs
 | 
					 | 
				
			||||||
#    __builtin_ffsl
 | 
					 | 
				
			||||||
#    __builtin_ffsll
 | 
					 | 
				
			||||||
#    __builtin_fpclassify
 | 
					 | 
				
			||||||
#    __builtin_huge_val
 | 
					 | 
				
			||||||
#    __builtin_huge_valf
 | 
					 | 
				
			||||||
#    __builtin_huge_vall
 | 
					 | 
				
			||||||
#    __builtin_inf
 | 
					 | 
				
			||||||
#    __builtin_infd128
 | 
					 | 
				
			||||||
#    __builtin_infd32
 | 
					 | 
				
			||||||
#    __builtin_infd64
 | 
					 | 
				
			||||||
#    __builtin_inff
 | 
					 | 
				
			||||||
#    __builtin_infl
 | 
					 | 
				
			||||||
#    __builtin_isinf_sign
 | 
					 | 
				
			||||||
#    __builtin_nan
 | 
					 | 
				
			||||||
#    __builtin_nand128
 | 
					 | 
				
			||||||
#    __builtin_nand32
 | 
					 | 
				
			||||||
#    __builtin_nand64
 | 
					 | 
				
			||||||
#    __builtin_nanf
 | 
					 | 
				
			||||||
#    __builtin_nanl
 | 
					 | 
				
			||||||
#    __builtin_nans
 | 
					 | 
				
			||||||
#    __builtin_nansf
 | 
					 | 
				
			||||||
#    __builtin_nansl
 | 
					 | 
				
			||||||
#    __builtin_object_size
 | 
					 | 
				
			||||||
#    __builtin_parity
 | 
					 | 
				
			||||||
#    __builtin_parityl
 | 
					 | 
				
			||||||
#    __builtin_parityll
 | 
					 | 
				
			||||||
#    __builtin_popcount
 | 
					 | 
				
			||||||
#    __builtin_popcountl
 | 
					 | 
				
			||||||
#    __builtin_popcountll
 | 
					 | 
				
			||||||
#    __builtin_powi
 | 
					 | 
				
			||||||
#    __builtin_powif
 | 
					 | 
				
			||||||
#    __builtin_powil
 | 
					 | 
				
			||||||
#    __builtin_prefetch
 | 
					 | 
				
			||||||
#    __builtin_trap
 | 
					 | 
				
			||||||
#    __builtin_types_compatible_p
 | 
					 | 
				
			||||||
#    __builtin_unreachable
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   Unsuppored built-ins will be tested with an empty parameter set and the
 | 
					 | 
				
			||||||
#   result of the check might be wrong or meaningless so use with care.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# LICENSE
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   Copyright (c) 2013 Gabriele Svelto <gabriele.svelto@gmail.com>
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   Copying and distribution of this file, with or without modification, are
 | 
					 | 
				
			||||||
#   permitted in any medium without royalty provided the copyright notice
 | 
					 | 
				
			||||||
#   and this notice are preserved.  This file is offered as-is, without any
 | 
					 | 
				
			||||||
#   warranty.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
serial 3
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AC_DEFUN([AX_GCC_BUILTIN], [
 | 
					 | 
				
			||||||
    AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    AC_CACHE_CHECK([for $1], [ac_var], [
 | 
					 | 
				
			||||||
        AC_LINK_IFELSE([AC_LANG_PROGRAM([], [
 | 
					 | 
				
			||||||
            m4_case([$1],
 | 
					 | 
				
			||||||
                [__builtin_assume_aligned], [$1("", 0)],
 | 
					 | 
				
			||||||
                [__builtin_bswap16], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_bswap32], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_bswap64], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_choose_expr], [$1(0, 0, 0)],
 | 
					 | 
				
			||||||
                [__builtin___clear_cache], [$1("", "")],
 | 
					 | 
				
			||||||
                [__builtin_clrsb], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_clrsbl], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_clrsbll], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_clz], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_clzl], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_clzll], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_complex], [$1(0.0, 0.0)],
 | 
					 | 
				
			||||||
                [__builtin_constant_p], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_ctz], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_ctzl], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_ctzll], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_expect], [$1(0, 0)],
 | 
					 | 
				
			||||||
                [__builtin_ffs], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_ffsl], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_ffsll], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_fpclassify], [$1(0, 1, 2, 3, 4, 0.0)],
 | 
					 | 
				
			||||||
                [__builtin_huge_val], [$1()],
 | 
					 | 
				
			||||||
                [__builtin_huge_valf], [$1()],
 | 
					 | 
				
			||||||
                [__builtin_huge_vall], [$1()],
 | 
					 | 
				
			||||||
                [__builtin_inf], [$1()],
 | 
					 | 
				
			||||||
                [__builtin_infd128], [$1()],
 | 
					 | 
				
			||||||
                [__builtin_infd32], [$1()],
 | 
					 | 
				
			||||||
                [__builtin_infd64], [$1()],
 | 
					 | 
				
			||||||
                [__builtin_inff], [$1()],
 | 
					 | 
				
			||||||
                [__builtin_infl], [$1()],
 | 
					 | 
				
			||||||
                [__builtin_isinf_sign], [$1(0.0)],
 | 
					 | 
				
			||||||
                [__builtin_nan], [$1("")],
 | 
					 | 
				
			||||||
                [__builtin_nand128], [$1("")],
 | 
					 | 
				
			||||||
                [__builtin_nand32], [$1("")],
 | 
					 | 
				
			||||||
                [__builtin_nand64], [$1("")],
 | 
					 | 
				
			||||||
                [__builtin_nanf], [$1("")],
 | 
					 | 
				
			||||||
                [__builtin_nanl], [$1("")],
 | 
					 | 
				
			||||||
                [__builtin_nans], [$1("")],
 | 
					 | 
				
			||||||
                [__builtin_nansf], [$1("")],
 | 
					 | 
				
			||||||
                [__builtin_nansl], [$1("")],
 | 
					 | 
				
			||||||
                [__builtin_object_size], [$1("", 0)],
 | 
					 | 
				
			||||||
                [__builtin_parity], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_parityl], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_parityll], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_popcount], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_popcountl], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_popcountll], [$1(0)],
 | 
					 | 
				
			||||||
                [__builtin_powi], [$1(0, 0)],
 | 
					 | 
				
			||||||
                [__builtin_powif], [$1(0, 0)],
 | 
					 | 
				
			||||||
                [__builtin_powil], [$1(0, 0)],
 | 
					 | 
				
			||||||
                [__builtin_prefetch], [$1("")],
 | 
					 | 
				
			||||||
                [__builtin_trap], [$1()],
 | 
					 | 
				
			||||||
                [__builtin_types_compatible_p], [$1(int, int)],
 | 
					 | 
				
			||||||
                [__builtin_unreachable], [$1()],
 | 
					 | 
				
			||||||
                [m4_warn([syntax], [Unsupported built-in $1, the test may fail])
 | 
					 | 
				
			||||||
                 $1()]
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            ])],
 | 
					 | 
				
			||||||
            [AS_VAR_SET([ac_var], [yes])],
 | 
					 | 
				
			||||||
            [AS_VAR_SET([ac_var], [no])])
 | 
					 | 
				
			||||||
    ])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    AS_IF([test yes = AS_VAR_GET([ac_var])],
 | 
					 | 
				
			||||||
        [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1), 1,
 | 
					 | 
				
			||||||
            [Define to 1 if the system has the `$1' built-in function])], [])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    AS_VAR_POPDEF([ac_var])
 | 
					 | 
				
			||||||
])
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										583
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										583
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
 | 
					# generated automatically by aclocal 1.15 -*- Autoconf -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 | 
					# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# This file is free software; the Free Software Foundation
 | 
					# This file is free software; the Free Software Foundation
 | 
				
			||||||
# gives unlimited permission to copy and/or distribute it,
 | 
					# gives unlimited permission to copy and/or distribute it,
 | 
				
			||||||
@@ -12,120 +12,32 @@
 | 
				
			|||||||
# PARTICULAR PURPOSE.
 | 
					# PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
 | 
					m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
 | 
				
			||||||
# ===========================================================================
 | 
					# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
 | 
				
			||||||
#     https://www.gnu.org/software/autoconf-archive/ax_python_module.html
 | 
					# serial 1 (pkg-config-0.24)
 | 
				
			||||||
# ===========================================================================
 | 
					# 
 | 
				
			||||||
 | 
					# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# SYNOPSIS
 | 
					# This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#   AX_PYTHON_MODULE(modname[, fatal, python])
 | 
					# This program is distributed in the hope that it will be useful, but
 | 
				
			||||||
 | 
					# WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
				
			||||||
 | 
					# General Public License for more details.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# DESCRIPTION
 | 
					# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#   Checks for Python module.
 | 
					# As a special exception to the GNU General Public License, if you
 | 
				
			||||||
#
 | 
					# distribute this file as part of a program that contains a
 | 
				
			||||||
#   If fatal is non-empty then absence of a module will trigger an error.
 | 
					# configuration script generated by Autoconf, you may include it under
 | 
				
			||||||
#   The third parameter can either be "python" for Python 2 or "python3" for
 | 
					# the same distribution terms that you use for the rest of that program.
 | 
				
			||||||
#   Python 3; defaults to Python 3.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# LICENSE
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   Copyright (c) 2008 Andrew Collier
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   Copying and distribution of this file, with or without modification, are
 | 
					 | 
				
			||||||
#   permitted in any medium without royalty provided the copyright notice
 | 
					 | 
				
			||||||
#   and this notice are preserved. This file is offered as-is, without any
 | 
					 | 
				
			||||||
#   warranty.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#serial 9
 | 
					# PKG_PROG_PKG_CONFIG([MIN-VERSION])
 | 
				
			||||||
 | 
					# ----------------------------------
 | 
				
			||||||
AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE])
 | 
					 | 
				
			||||||
AC_DEFUN([AX_PYTHON_MODULE],[
 | 
					 | 
				
			||||||
    if test -z $PYTHON;
 | 
					 | 
				
			||||||
    then
 | 
					 | 
				
			||||||
        if test -z "$3";
 | 
					 | 
				
			||||||
        then
 | 
					 | 
				
			||||||
            PYTHON="python3"
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            PYTHON="$3"
 | 
					 | 
				
			||||||
        fi
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    PYTHON_NAME=`basename $PYTHON`
 | 
					 | 
				
			||||||
    AC_MSG_CHECKING($PYTHON_NAME module: $1)
 | 
					 | 
				
			||||||
    $PYTHON -c "import $1" 2>/dev/null
 | 
					 | 
				
			||||||
    if test $? -eq 0;
 | 
					 | 
				
			||||||
    then
 | 
					 | 
				
			||||||
        AC_MSG_RESULT(yes)
 | 
					 | 
				
			||||||
        eval AS_TR_CPP(HAVE_PYMOD_$1)=yes
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        AC_MSG_RESULT(no)
 | 
					 | 
				
			||||||
        eval AS_TR_CPP(HAVE_PYMOD_$1)=no
 | 
					 | 
				
			||||||
        #
 | 
					 | 
				
			||||||
        if test -n "$2"
 | 
					 | 
				
			||||||
        then
 | 
					 | 
				
			||||||
            AC_MSG_ERROR(failed to find required module $1)
 | 
					 | 
				
			||||||
            exit 1
 | 
					 | 
				
			||||||
        fi
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
 | 
					 | 
				
			||||||
# serial 11 (pkg-config-0.29.1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
 | 
					 | 
				
			||||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
 | 
					 | 
				
			||||||
dnl
 | 
					 | 
				
			||||||
dnl This program is free software; you can redistribute it and/or modify
 | 
					 | 
				
			||||||
dnl it under the terms of the GNU General Public License as published by
 | 
					 | 
				
			||||||
dnl the Free Software Foundation; either version 2 of the License, or
 | 
					 | 
				
			||||||
dnl (at your option) any later version.
 | 
					 | 
				
			||||||
dnl
 | 
					 | 
				
			||||||
dnl This program is distributed in the hope that it will be useful, but
 | 
					 | 
				
			||||||
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 | 
					 | 
				
			||||||
dnl General Public License for more details.
 | 
					 | 
				
			||||||
dnl
 | 
					 | 
				
			||||||
dnl You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
dnl along with this program; if not, write to the Free Software
 | 
					 | 
				
			||||||
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | 
					 | 
				
			||||||
dnl 02111-1307, USA.
 | 
					 | 
				
			||||||
dnl
 | 
					 | 
				
			||||||
dnl As a special exception to the GNU General Public License, if you
 | 
					 | 
				
			||||||
dnl distribute this file as part of a program that contains a
 | 
					 | 
				
			||||||
dnl configuration script generated by Autoconf, you may include it under
 | 
					 | 
				
			||||||
dnl the same distribution terms that you use for the rest of that
 | 
					 | 
				
			||||||
dnl program.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dnl PKG_PREREQ(MIN-VERSION)
 | 
					 | 
				
			||||||
dnl -----------------------
 | 
					 | 
				
			||||||
dnl Since: 0.29
 | 
					 | 
				
			||||||
dnl
 | 
					 | 
				
			||||||
dnl Verify that the version of the pkg-config macros are at least
 | 
					 | 
				
			||||||
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
 | 
					 | 
				
			||||||
dnl installed version of pkg-config, this checks the developer's version
 | 
					 | 
				
			||||||
dnl of pkg.m4 when generating configure.
 | 
					 | 
				
			||||||
dnl
 | 
					 | 
				
			||||||
dnl To ensure that this macro is defined, also add:
 | 
					 | 
				
			||||||
dnl m4_ifndef([PKG_PREREQ],
 | 
					 | 
				
			||||||
dnl     [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
 | 
					 | 
				
			||||||
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_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
 | 
					 | 
				
			||||||
    [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
 | 
					 | 
				
			||||||
])dnl PKG_PREREQ
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
 | 
					 | 
				
			||||||
dnl ----------------------------------
 | 
					 | 
				
			||||||
dnl Since: 0.16
 | 
					 | 
				
			||||||
dnl
 | 
					 | 
				
			||||||
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
 | 
					 | 
				
			||||||
dnl first found in the path. Checks that the version of pkg-config found
 | 
					 | 
				
			||||||
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
 | 
					 | 
				
			||||||
dnl used since that's the first version where most current features of
 | 
					 | 
				
			||||||
dnl pkg-config existed.
 | 
					 | 
				
			||||||
AC_DEFUN([PKG_PROG_PKG_CONFIG],
 | 
					AC_DEFUN([PKG_PROG_PKG_CONFIG],
 | 
				
			||||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
 | 
					[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
 | 
				
			||||||
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
 | 
					m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
 | 
				
			||||||
@@ -147,19 +59,18 @@ if test -n "$PKG_CONFIG"; then
 | 
				
			|||||||
		PKG_CONFIG=""
 | 
							PKG_CONFIG=""
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
fi[]dnl
 | 
					fi[]dnl
 | 
				
			||||||
])dnl PKG_PROG_PKG_CONFIG
 | 
					])# PKG_PROG_PKG_CONFIG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
 | 
					# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
 | 
				
			||||||
dnl -------------------------------------------------------------------
 | 
					#
 | 
				
			||||||
dnl Since: 0.18
 | 
					# Check to see whether a particular set of modules exists.  Similar
 | 
				
			||||||
dnl
 | 
					# to PKG_CHECK_MODULES(), but does not set variables or print errors.
 | 
				
			||||||
dnl Check to see whether a particular set of modules exists. Similar to
 | 
					#
 | 
				
			||||||
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
 | 
					# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
 | 
				
			||||||
dnl
 | 
					# only at the first occurence in configure.ac, so if the first place
 | 
				
			||||||
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
 | 
					# it's called might be skipped (such as if it is within an "if", you
 | 
				
			||||||
dnl only at the first occurence in configure.ac, so if the first place
 | 
					# have to call PKG_CHECK_EXISTS manually
 | 
				
			||||||
dnl it's called might be skipped (such as if it is within an "if", you
 | 
					# --------------------------------------------------------------
 | 
				
			||||||
dnl have to call PKG_CHECK_EXISTS manually
 | 
					 | 
				
			||||||
AC_DEFUN([PKG_CHECK_EXISTS],
 | 
					AC_DEFUN([PKG_CHECK_EXISTS],
 | 
				
			||||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 | 
					[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 | 
				
			||||||
if test -n "$PKG_CONFIG" && \
 | 
					if test -n "$PKG_CONFIG" && \
 | 
				
			||||||
@@ -169,10 +80,8 @@ m4_ifvaln([$3], [else
 | 
				
			|||||||
  $3])dnl
 | 
					  $3])dnl
 | 
				
			||||||
fi])
 | 
					fi])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
 | 
					# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
 | 
				
			||||||
dnl ---------------------------------------------
 | 
					# ---------------------------------------------
 | 
				
			||||||
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
 | 
					 | 
				
			||||||
dnl pkg_failed based on the result.
 | 
					 | 
				
			||||||
m4_define([_PKG_CONFIG],
 | 
					m4_define([_PKG_CONFIG],
 | 
				
			||||||
[if test -n "$$1"; then
 | 
					[if test -n "$$1"; then
 | 
				
			||||||
    pkg_cv_[]$1="$$1"
 | 
					    pkg_cv_[]$1="$$1"
 | 
				
			||||||
@@ -184,11 +93,10 @@ m4_define([_PKG_CONFIG],
 | 
				
			|||||||
 else
 | 
					 else
 | 
				
			||||||
    pkg_failed=untried
 | 
					    pkg_failed=untried
 | 
				
			||||||
fi[]dnl
 | 
					fi[]dnl
 | 
				
			||||||
])dnl _PKG_CONFIG
 | 
					])# _PKG_CONFIG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl _PKG_SHORT_ERRORS_SUPPORTED
 | 
					# _PKG_SHORT_ERRORS_SUPPORTED
 | 
				
			||||||
dnl ---------------------------
 | 
					# -----------------------------
 | 
				
			||||||
dnl Internal check to see if pkg-config supports short errors.
 | 
					 | 
				
			||||||
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
 | 
					AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
 | 
				
			||||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
 | 
					[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
 | 
				
			||||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
 | 
					if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
 | 
				
			||||||
@@ -196,17 +104,19 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
 | 
				
			|||||||
else
 | 
					else
 | 
				
			||||||
        _pkg_short_errors_supported=no
 | 
					        _pkg_short_errors_supported=no
 | 
				
			||||||
fi[]dnl
 | 
					fi[]dnl
 | 
				
			||||||
])dnl _PKG_SHORT_ERRORS_SUPPORTED
 | 
					])# _PKG_SHORT_ERRORS_SUPPORTED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
 | 
					# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
 | 
				
			||||||
dnl   [ACTION-IF-NOT-FOUND])
 | 
					# [ACTION-IF-NOT-FOUND])
 | 
				
			||||||
dnl --------------------------------------------------------------
 | 
					#
 | 
				
			||||||
dnl Since: 0.4.0
 | 
					#
 | 
				
			||||||
dnl
 | 
					# Note that if there is a possibility the first call to
 | 
				
			||||||
dnl Note that if there is a possibility the first call to
 | 
					# PKG_CHECK_MODULES might not happen, you should be sure to include an
 | 
				
			||||||
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
 | 
					# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
 | 
				
			||||||
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
 | 
					#
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# --------------------------------------------------------------
 | 
				
			||||||
AC_DEFUN([PKG_CHECK_MODULES],
 | 
					AC_DEFUN([PKG_CHECK_MODULES],
 | 
				
			||||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 | 
					[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 | 
				
			||||||
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
 | 
					AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
 | 
				
			||||||
@@ -260,40 +170,16 @@ else
 | 
				
			|||||||
        AC_MSG_RESULT([yes])
 | 
					        AC_MSG_RESULT([yes])
 | 
				
			||||||
	$3
 | 
						$3
 | 
				
			||||||
fi[]dnl
 | 
					fi[]dnl
 | 
				
			||||||
])dnl PKG_CHECK_MODULES
 | 
					])# PKG_CHECK_MODULES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
 | 
					# PKG_INSTALLDIR(DIRECTORY)
 | 
				
			||||||
dnl   [ACTION-IF-NOT-FOUND])
 | 
					# -------------------------
 | 
				
			||||||
dnl ---------------------------------------------------------------------
 | 
					# Substitutes the variable pkgconfigdir as the location where a module
 | 
				
			||||||
dnl Since: 0.29
 | 
					# should install pkg-config .pc files. By default the directory is
 | 
				
			||||||
dnl
 | 
					# $libdir/pkgconfig, but the default can be changed by passing
 | 
				
			||||||
dnl Checks for existence of MODULES and gathers its build flags with
 | 
					# DIRECTORY. The user can override through the --with-pkgconfigdir
 | 
				
			||||||
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
 | 
					# parameter.
 | 
				
			||||||
dnl and VARIABLE-PREFIX_LIBS from --libs.
 | 
					 | 
				
			||||||
dnl
 | 
					 | 
				
			||||||
dnl Note that if there is a possibility the first call to
 | 
					 | 
				
			||||||
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
 | 
					 | 
				
			||||||
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
 | 
					 | 
				
			||||||
dnl configure.ac.
 | 
					 | 
				
			||||||
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
 | 
					 | 
				
			||||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 | 
					 | 
				
			||||||
_save_PKG_CONFIG=$PKG_CONFIG
 | 
					 | 
				
			||||||
PKG_CONFIG="$PKG_CONFIG --static"
 | 
					 | 
				
			||||||
PKG_CHECK_MODULES($@)
 | 
					 | 
				
			||||||
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
 | 
					 | 
				
			||||||
])dnl PKG_CHECK_MODULES_STATIC
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dnl PKG_INSTALLDIR([DIRECTORY])
 | 
					 | 
				
			||||||
dnl -------------------------
 | 
					 | 
				
			||||||
dnl Since: 0.27
 | 
					 | 
				
			||||||
dnl
 | 
					 | 
				
			||||||
dnl Substitutes the variable pkgconfigdir as the location where a module
 | 
					 | 
				
			||||||
dnl should install pkg-config .pc files. By default the directory is
 | 
					 | 
				
			||||||
dnl $libdir/pkgconfig, but the default can be changed by passing
 | 
					 | 
				
			||||||
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
 | 
					 | 
				
			||||||
dnl parameter.
 | 
					 | 
				
			||||||
AC_DEFUN([PKG_INSTALLDIR],
 | 
					AC_DEFUN([PKG_INSTALLDIR],
 | 
				
			||||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
 | 
					[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
 | 
				
			||||||
m4_pushdef([pkg_description],
 | 
					m4_pushdef([pkg_description],
 | 
				
			||||||
@@ -304,18 +190,16 @@ AC_ARG_WITH([pkgconfigdir],
 | 
				
			|||||||
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
 | 
					AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
 | 
				
			||||||
m4_popdef([pkg_default])
 | 
					m4_popdef([pkg_default])
 | 
				
			||||||
m4_popdef([pkg_description])
 | 
					m4_popdef([pkg_description])
 | 
				
			||||||
])dnl PKG_INSTALLDIR
 | 
					]) dnl PKG_INSTALLDIR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
 | 
					# PKG_NOARCH_INSTALLDIR(DIRECTORY)
 | 
				
			||||||
dnl --------------------------------
 | 
					# -------------------------
 | 
				
			||||||
dnl Since: 0.27
 | 
					# Substitutes the variable noarch_pkgconfigdir as the location where a
 | 
				
			||||||
dnl
 | 
					# module should install arch-independent pkg-config .pc files. By
 | 
				
			||||||
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
 | 
					# default the directory is $datadir/pkgconfig, but the default can be
 | 
				
			||||||
dnl module should install arch-independent pkg-config .pc files. By
 | 
					# changed by passing DIRECTORY. The user can override through the
 | 
				
			||||||
dnl default the directory is $datadir/pkgconfig, but the default can be
 | 
					# --with-noarch-pkgconfigdir parameter.
 | 
				
			||||||
dnl changed by passing DIRECTORY. The user can override through the
 | 
					 | 
				
			||||||
dnl --with-noarch-pkgconfigdir parameter.
 | 
					 | 
				
			||||||
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
 | 
					AC_DEFUN([PKG_NOARCH_INSTALLDIR],
 | 
				
			||||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
 | 
					[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
 | 
				
			||||||
m4_pushdef([pkg_description],
 | 
					m4_pushdef([pkg_description],
 | 
				
			||||||
@@ -326,15 +210,13 @@ AC_ARG_WITH([noarch-pkgconfigdir],
 | 
				
			|||||||
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
 | 
					AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
 | 
				
			||||||
m4_popdef([pkg_default])
 | 
					m4_popdef([pkg_default])
 | 
				
			||||||
m4_popdef([pkg_description])
 | 
					m4_popdef([pkg_description])
 | 
				
			||||||
])dnl PKG_NOARCH_INSTALLDIR
 | 
					]) dnl PKG_NOARCH_INSTALLDIR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
 | 
					# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
 | 
				
			||||||
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
 | 
					# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
 | 
				
			||||||
dnl -------------------------------------------
 | 
					# -------------------------------------------
 | 
				
			||||||
dnl Since: 0.28
 | 
					# Retrieves the value of the pkg-config variable for the given module.
 | 
				
			||||||
dnl
 | 
					 | 
				
			||||||
dnl Retrieves the value of the pkg-config variable for the given module.
 | 
					 | 
				
			||||||
AC_DEFUN([PKG_CHECK_VAR],
 | 
					AC_DEFUN([PKG_CHECK_VAR],
 | 
				
			||||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 | 
					[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 | 
				
			||||||
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
 | 
					AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
 | 
				
			||||||
@@ -343,327 +225,6 @@ _PKG_CONFIG([$1], [variable="][$3]["], [$2])
 | 
				
			|||||||
AS_VAR_COPY([$1], [pkg_cv_][$1])
 | 
					AS_VAR_COPY([$1], [pkg_cv_][$1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
 | 
					AS_VAR_IF([$1], [""], [$5], [$4])dnl
 | 
				
			||||||
])dnl PKG_CHECK_VAR
 | 
					])# 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-2017 Free Software Foundation, Inc.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This file is free software; the Free Software Foundation
 | 
					 | 
				
			||||||
# gives unlimited permission to copy and/or distribute it,
 | 
					 | 
				
			||||||
# with or without modifications, as long as this notice is preserved.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
 | 
					 | 
				
			||||||
# ---------------------------------------------------------------------------
 | 
					 | 
				
			||||||
# Adds support for distributing Python modules and packages.  To
 | 
					 | 
				
			||||||
# install modules, copy them to $(pythondir), using the python_PYTHON
 | 
					 | 
				
			||||||
# automake variable.  To install a package with the same name as the
 | 
					 | 
				
			||||||
# automake package, install to $(pkgpythondir), or use the
 | 
					 | 
				
			||||||
# pkgpython_PYTHON automake variable.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as
 | 
					 | 
				
			||||||
# locations to install python extension modules (shared libraries).
 | 
					 | 
				
			||||||
# Another macro is required to find the appropriate flags to compile
 | 
					 | 
				
			||||||
# extension modules.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# If your package is configured with a different prefix to python,
 | 
					 | 
				
			||||||
# users will have to add the install directory to the PYTHONPATH
 | 
					 | 
				
			||||||
# environment variable, or create a .pth file (see the python
 | 
					 | 
				
			||||||
# documentation for details).
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will
 | 
					 | 
				
			||||||
# cause an error if the version of python installed on the system
 | 
					 | 
				
			||||||
# doesn't meet the requirement.  MINIMUM-VERSION should consist of
 | 
					 | 
				
			||||||
# numbers and dots only.
 | 
					 | 
				
			||||||
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).
 | 
					 | 
				
			||||||
  dnl FIXME: Remove the need to hard-code Python versions here.
 | 
					 | 
				
			||||||
  m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
 | 
					 | 
				
			||||||
[python python2 python3 python3.5 python3.4 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])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  m4_if([$1],[],[
 | 
					 | 
				
			||||||
    dnl No version check is needed.
 | 
					 | 
				
			||||||
    # Find any Python interpreter.
 | 
					 | 
				
			||||||
    if test -z "$PYTHON"; then
 | 
					 | 
				
			||||||
      AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :)
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    am_display_PYTHON=python
 | 
					 | 
				
			||||||
  ], [
 | 
					 | 
				
			||||||
    dnl A version check is needed.
 | 
					 | 
				
			||||||
    if test -n "$PYTHON"; then
 | 
					 | 
				
			||||||
      # If the user set $PYTHON, use it and don't search something else.
 | 
					 | 
				
			||||||
      AC_MSG_CHECKING([whether $PYTHON version is >= $1])
 | 
					 | 
				
			||||||
      AM_PYTHON_CHECK_VERSION([$PYTHON], [$1],
 | 
					 | 
				
			||||||
			      [AC_MSG_RESULT([yes])],
 | 
					 | 
				
			||||||
			      [AC_MSG_RESULT([no])
 | 
					 | 
				
			||||||
			       AC_MSG_ERROR([Python interpreter is too old])])
 | 
					 | 
				
			||||||
      am_display_PYTHON=$PYTHON
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      # Otherwise, try each interpreter until we find one that satisfies
 | 
					 | 
				
			||||||
      # VERSION.
 | 
					 | 
				
			||||||
      AC_CACHE_CHECK([for a Python interpreter with version >= $1],
 | 
					 | 
				
			||||||
	[am_cv_pathless_PYTHON],[
 | 
					 | 
				
			||||||
	for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do
 | 
					 | 
				
			||||||
	  test "$am_cv_pathless_PYTHON" = none && break
 | 
					 | 
				
			||||||
	  AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break])
 | 
					 | 
				
			||||||
	done])
 | 
					 | 
				
			||||||
      # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON.
 | 
					 | 
				
			||||||
      if test "$am_cv_pathless_PYTHON" = none; then
 | 
					 | 
				
			||||||
	PYTHON=:
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON])
 | 
					 | 
				
			||||||
      fi
 | 
					 | 
				
			||||||
      am_display_PYTHON=$am_cv_pathless_PYTHON
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
  ])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if test "$PYTHON" = :; then
 | 
					 | 
				
			||||||
  dnl Run any user-specified action, or abort.
 | 
					 | 
				
			||||||
    m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  dnl Query Python for its version number.  Getting [:3] seems to be
 | 
					 | 
				
			||||||
  dnl the best way to do this; it's what "site.py" does in the standard
 | 
					 | 
				
			||||||
  dnl library.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
 | 
					 | 
				
			||||||
    [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`])
 | 
					 | 
				
			||||||
  AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  dnl Use the values of $prefix and $exec_prefix for the corresponding
 | 
					 | 
				
			||||||
  dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX.  These are made
 | 
					 | 
				
			||||||
  dnl distinct variables so they can be overridden if need be.  However,
 | 
					 | 
				
			||||||
  dnl general consensus is that you shouldn't need this ability.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
 | 
					 | 
				
			||||||
  AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  dnl At times (like when building shared libraries) you may want
 | 
					 | 
				
			||||||
  dnl to know which OS platform Python thinks this is.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
 | 
					 | 
				
			||||||
    [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
 | 
					 | 
				
			||||||
  AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # Just factor out some code duplication.
 | 
					 | 
				
			||||||
  am_python_setup_sysconfig="\
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
# Prefer sysconfig over distutils.sysconfig, for better compatibility
 | 
					 | 
				
			||||||
# with python 3.x.  See automake bug#10227.
 | 
					 | 
				
			||||||
try:
 | 
					 | 
				
			||||||
    import sysconfig
 | 
					 | 
				
			||||||
except ImportError:
 | 
					 | 
				
			||||||
    can_use_sysconfig = 0
 | 
					 | 
				
			||||||
else:
 | 
					 | 
				
			||||||
    can_use_sysconfig = 1
 | 
					 | 
				
			||||||
# Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs:
 | 
					 | 
				
			||||||
# <https://github.com/pypa/virtualenv/issues/118>
 | 
					 | 
				
			||||||
try:
 | 
					 | 
				
			||||||
    from platform import python_implementation
 | 
					 | 
				
			||||||
    if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7':
 | 
					 | 
				
			||||||
        can_use_sysconfig = 0
 | 
					 | 
				
			||||||
except ImportError:
 | 
					 | 
				
			||||||
    pass"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  dnl Set up 4 directories:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  dnl pythondir -- where to install python scripts.  This is the
 | 
					 | 
				
			||||||
  dnl   site-packages directory, not the python standard library
 | 
					 | 
				
			||||||
  dnl   directory like in previous automake betas.  This behavior
 | 
					 | 
				
			||||||
  dnl   is more consistent with lispdir.m4 for example.
 | 
					 | 
				
			||||||
  dnl Query distutils for this directory.
 | 
					 | 
				
			||||||
  AC_CACHE_CHECK([for $am_display_PYTHON script directory],
 | 
					 | 
				
			||||||
    [am_cv_python_pythondir],
 | 
					 | 
				
			||||||
    [if test "x$prefix" = xNONE
 | 
					 | 
				
			||||||
     then
 | 
					 | 
				
			||||||
       am_py_prefix=$ac_default_prefix
 | 
					 | 
				
			||||||
     else
 | 
					 | 
				
			||||||
       am_py_prefix=$prefix
 | 
					 | 
				
			||||||
     fi
 | 
					 | 
				
			||||||
     am_cv_python_pythondir=`$PYTHON -c "
 | 
					 | 
				
			||||||
$am_python_setup_sysconfig
 | 
					 | 
				
			||||||
if can_use_sysconfig:
 | 
					 | 
				
			||||||
    sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
 | 
					 | 
				
			||||||
else:
 | 
					 | 
				
			||||||
    from distutils import sysconfig
 | 
					 | 
				
			||||||
    sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
 | 
					 | 
				
			||||||
sys.stdout.write(sitedir)"`
 | 
					 | 
				
			||||||
     case $am_cv_python_pythondir in
 | 
					 | 
				
			||||||
     $am_py_prefix*)
 | 
					 | 
				
			||||||
       am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
 | 
					 | 
				
			||||||
       am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
 | 
					 | 
				
			||||||
       ;;
 | 
					 | 
				
			||||||
     *)
 | 
					 | 
				
			||||||
       case $am_py_prefix in
 | 
					 | 
				
			||||||
         /usr|/System*) ;;
 | 
					 | 
				
			||||||
         *)
 | 
					 | 
				
			||||||
	  am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
 | 
					 | 
				
			||||||
	  ;;
 | 
					 | 
				
			||||||
       esac
 | 
					 | 
				
			||||||
       ;;
 | 
					 | 
				
			||||||
     esac
 | 
					 | 
				
			||||||
    ])
 | 
					 | 
				
			||||||
  AC_SUBST([pythondir], [$am_cv_python_pythondir])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  dnl pkgpythondir -- $PACKAGE directory under pythondir.  Was
 | 
					 | 
				
			||||||
  dnl   PYTHON_SITE_PACKAGE in previous betas, but this naming is
 | 
					 | 
				
			||||||
  dnl   more consistent with the rest of automake.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  dnl pyexecdir -- directory for installing python extension modules
 | 
					 | 
				
			||||||
  dnl   (shared libraries)
 | 
					 | 
				
			||||||
  dnl Query distutils for this directory.
 | 
					 | 
				
			||||||
  AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
 | 
					 | 
				
			||||||
    [am_cv_python_pyexecdir],
 | 
					 | 
				
			||||||
    [if test "x$exec_prefix" = xNONE
 | 
					 | 
				
			||||||
     then
 | 
					 | 
				
			||||||
       am_py_exec_prefix=$am_py_prefix
 | 
					 | 
				
			||||||
     else
 | 
					 | 
				
			||||||
       am_py_exec_prefix=$exec_prefix
 | 
					 | 
				
			||||||
     fi
 | 
					 | 
				
			||||||
     am_cv_python_pyexecdir=`$PYTHON -c "
 | 
					 | 
				
			||||||
$am_python_setup_sysconfig
 | 
					 | 
				
			||||||
if can_use_sysconfig:
 | 
					 | 
				
			||||||
    sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
 | 
					 | 
				
			||||||
else:
 | 
					 | 
				
			||||||
    from distutils import sysconfig
 | 
					 | 
				
			||||||
    sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
 | 
					 | 
				
			||||||
sys.stdout.write(sitedir)"`
 | 
					 | 
				
			||||||
     case $am_cv_python_pyexecdir in
 | 
					 | 
				
			||||||
     $am_py_exec_prefix*)
 | 
					 | 
				
			||||||
       am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
 | 
					 | 
				
			||||||
       am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
 | 
					 | 
				
			||||||
       ;;
 | 
					 | 
				
			||||||
     *)
 | 
					 | 
				
			||||||
       case $am_py_exec_prefix in
 | 
					 | 
				
			||||||
         /usr|/System*) ;;
 | 
					 | 
				
			||||||
         *)
 | 
					 | 
				
			||||||
	   am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
 | 
					 | 
				
			||||||
	   ;;
 | 
					 | 
				
			||||||
       esac
 | 
					 | 
				
			||||||
       ;;
 | 
					 | 
				
			||||||
     esac
 | 
					 | 
				
			||||||
    ])
 | 
					 | 
				
			||||||
  AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  dnl Run any user-specified action.
 | 
					 | 
				
			||||||
  $2
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
 | 
					 | 
				
			||||||
# ---------------------------------------------------------------------------
 | 
					 | 
				
			||||||
# Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION.
 | 
					 | 
				
			||||||
# Run ACTION-IF-FALSE otherwise.
 | 
					 | 
				
			||||||
# This test uses sys.hexversion instead of the string equivalent (first
 | 
					 | 
				
			||||||
# word of sys.version), in order to cope with versions such as 2.2c1.
 | 
					 | 
				
			||||||
# This supports Python 2.0 or higher. (2.0 was released on October 16, 2000).
 | 
					 | 
				
			||||||
AC_DEFUN([AM_PYTHON_CHECK_VERSION],
 | 
					 | 
				
			||||||
 [prog="import sys
 | 
					 | 
				
			||||||
# split strings by '.' and convert to numeric.  Append some zeros
 | 
					 | 
				
			||||||
# because we need at least 4 digits for the hex conversion.
 | 
					 | 
				
			||||||
# map returns an iterator in Python 3.0 and a list in 2.x
 | 
					 | 
				
			||||||
minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]]
 | 
					 | 
				
			||||||
minverhex = 0
 | 
					 | 
				
			||||||
# xrange is not present in Python 3.0 and range returns an iterator
 | 
					 | 
				
			||||||
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-2017 Free Software Foundation, Inc.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This file is free software; the Free Software Foundation
 | 
					 | 
				
			||||||
# gives unlimited permission to copy and/or distribute it,
 | 
					 | 
				
			||||||
# with or without modifications, as long as this notice is preserved.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# AM_RUN_LOG(COMMAND)
 | 
					 | 
				
			||||||
# -------------------
 | 
					 | 
				
			||||||
# Run COMMAND, save the exit status in ac_status, and log it.
 | 
					 | 
				
			||||||
# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
 | 
					 | 
				
			||||||
AC_DEFUN([AM_RUN_LOG],
 | 
					 | 
				
			||||||
[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
 | 
					 | 
				
			||||||
   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
 | 
					 | 
				
			||||||
   ac_status=$?
 | 
					 | 
				
			||||||
   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
 | 
					 | 
				
			||||||
   (exit $ac_status); }])
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
m4_include([acinclude.m4])
 | 
					m4_include([acinclude.m4])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,170 +0,0 @@
 | 
				
			|||||||
#!/bin/sh
 | 
					 | 
				
			||||||
# py-compile - Compile a Python program
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
scriptversion=2011-06-08.12; # UTC
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Copyright (C) 2000-2014 Free Software Foundation, Inc.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# This program is free software; you can redistribute it and/or modify
 | 
					 | 
				
			||||||
# it under the terms of the GNU General Public License as published by
 | 
					 | 
				
			||||||
# the Free Software Foundation; either version 2, or (at your option)
 | 
					 | 
				
			||||||
# any later version.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# This program is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
# GNU General Public License for more details.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# As a special exception to the GNU General Public License, if you
 | 
					 | 
				
			||||||
# distribute this file as part of a program that contains a
 | 
					 | 
				
			||||||
# configuration script generated by Autoconf, you may include it under
 | 
					 | 
				
			||||||
# the same distribution terms that you use for the rest of that program.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# This file is maintained in Automake, please report
 | 
					 | 
				
			||||||
# bugs to <bug-automake@gnu.org> or send patches to
 | 
					 | 
				
			||||||
# <automake-patches@gnu.org>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ -z "$PYTHON" ]; then
 | 
					 | 
				
			||||||
  PYTHON=python
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
me=py-compile
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
usage_error ()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  echo "$me: $*" >&2
 | 
					 | 
				
			||||||
  echo "Try '$me --help' for more information." >&2
 | 
					 | 
				
			||||||
  exit 1
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
basedir=
 | 
					 | 
				
			||||||
destdir=
 | 
					 | 
				
			||||||
while test $# -ne 0; do
 | 
					 | 
				
			||||||
  case "$1" in
 | 
					 | 
				
			||||||
    --basedir)
 | 
					 | 
				
			||||||
      if test $# -lt 2; then
 | 
					 | 
				
			||||||
        usage_error "option '--basedir' requires an argument"
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        basedir=$2
 | 
					 | 
				
			||||||
      fi
 | 
					 | 
				
			||||||
      shift
 | 
					 | 
				
			||||||
      ;;
 | 
					 | 
				
			||||||
    --destdir)
 | 
					 | 
				
			||||||
      if test $# -lt 2; then
 | 
					 | 
				
			||||||
        usage_error "option '--destdir' requires an argument"
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        destdir=$2
 | 
					 | 
				
			||||||
      fi
 | 
					 | 
				
			||||||
      shift
 | 
					 | 
				
			||||||
      ;;
 | 
					 | 
				
			||||||
    -h|--help)
 | 
					 | 
				
			||||||
      cat <<\EOF
 | 
					 | 
				
			||||||
Usage: py-compile [--help] [--version] [--basedir DIR] [--destdir DIR] FILES..."
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Byte compile some python scripts FILES.  Use --destdir to specify any
 | 
					 | 
				
			||||||
leading directory path to the FILES that you don't want to include in the
 | 
					 | 
				
			||||||
byte compiled file.  Specify --basedir for any additional path information you
 | 
					 | 
				
			||||||
do want to be shown in the byte compiled file.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Example:
 | 
					 | 
				
			||||||
  py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Report bugs to <bug-automake@gnu.org>.
 | 
					 | 
				
			||||||
EOF
 | 
					 | 
				
			||||||
      exit $?
 | 
					 | 
				
			||||||
      ;;
 | 
					 | 
				
			||||||
    -v|--version)
 | 
					 | 
				
			||||||
      echo "$me $scriptversion"
 | 
					 | 
				
			||||||
      exit $?
 | 
					 | 
				
			||||||
      ;;
 | 
					 | 
				
			||||||
    --)
 | 
					 | 
				
			||||||
      shift
 | 
					 | 
				
			||||||
      break
 | 
					 | 
				
			||||||
      ;;
 | 
					 | 
				
			||||||
    -*)
 | 
					 | 
				
			||||||
      usage_error "unrecognized option '$1'"
 | 
					 | 
				
			||||||
      ;;
 | 
					 | 
				
			||||||
    *)
 | 
					 | 
				
			||||||
      break
 | 
					 | 
				
			||||||
      ;;
 | 
					 | 
				
			||||||
  esac
 | 
					 | 
				
			||||||
  shift
 | 
					 | 
				
			||||||
done
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
files=$*
 | 
					 | 
				
			||||||
if test -z "$files"; then
 | 
					 | 
				
			||||||
    usage_error "no files given"
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# if basedir was given, then it should be prepended to filenames before
 | 
					 | 
				
			||||||
# byte compilation.
 | 
					 | 
				
			||||||
if [ -z "$basedir" ]; then
 | 
					 | 
				
			||||||
    pathtrans="path = file"
 | 
					 | 
				
			||||||
else
 | 
					 | 
				
			||||||
    pathtrans="path = os.path.join('$basedir', file)"
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# if destdir was given, then it needs to be prepended to the filename to
 | 
					 | 
				
			||||||
# byte compile but not go into the compiled file.
 | 
					 | 
				
			||||||
if [ -z "$destdir" ]; then
 | 
					 | 
				
			||||||
    filetrans="filepath = path"
 | 
					 | 
				
			||||||
else
 | 
					 | 
				
			||||||
    filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$PYTHON -c "
 | 
					 | 
				
			||||||
import sys, os, py_compile, imp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
files = '''$files'''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sys.stdout.write('Byte-compiling python modules...\n')
 | 
					 | 
				
			||||||
for file in files.split():
 | 
					 | 
				
			||||||
    $pathtrans
 | 
					 | 
				
			||||||
    $filetrans
 | 
					 | 
				
			||||||
    if not os.path.exists(filepath) or not (len(filepath) >= 3
 | 
					 | 
				
			||||||
                                            and filepath[-3:] == '.py'):
 | 
					 | 
				
			||||||
	    continue
 | 
					 | 
				
			||||||
    sys.stdout.write(file)
 | 
					 | 
				
			||||||
    sys.stdout.flush()
 | 
					 | 
				
			||||||
    if hasattr(imp, 'get_tag'):
 | 
					 | 
				
			||||||
        py_compile.compile(filepath, imp.cache_from_source(filepath), path)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        py_compile.compile(filepath, filepath + 'c', path)
 | 
					 | 
				
			||||||
sys.stdout.write('\n')" || exit $?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# this will fail for python < 1.5, but that doesn't matter ...
 | 
					 | 
				
			||||||
$PYTHON -O -c "
 | 
					 | 
				
			||||||
import sys, os, py_compile, imp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# pypy does not use .pyo optimization
 | 
					 | 
				
			||||||
if hasattr(sys, 'pypy_translation_info'):
 | 
					 | 
				
			||||||
    sys.exit(0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
files = '''$files'''
 | 
					 | 
				
			||||||
sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n')
 | 
					 | 
				
			||||||
for file in files.split():
 | 
					 | 
				
			||||||
    $pathtrans
 | 
					 | 
				
			||||||
    $filetrans
 | 
					 | 
				
			||||||
    if not os.path.exists(filepath) or not (len(filepath) >= 3
 | 
					 | 
				
			||||||
                                            and filepath[-3:] == '.py'):
 | 
					 | 
				
			||||||
	    continue
 | 
					 | 
				
			||||||
    sys.stdout.write(file)
 | 
					 | 
				
			||||||
    sys.stdout.flush()
 | 
					 | 
				
			||||||
    if hasattr(imp, 'get_tag'):
 | 
					 | 
				
			||||||
        py_compile.compile(filepath, imp.cache_from_source(filepath, False), path)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        py_compile.compile(filepath, filepath + 'o', path)
 | 
					 | 
				
			||||||
sys.stdout.write('\n')" 2>/dev/null || :
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Local Variables:
 | 
					 | 
				
			||||||
# mode: shell-script
 | 
					 | 
				
			||||||
# sh-indentation: 2
 | 
					 | 
				
			||||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
 | 
					 | 
				
			||||||
# time-stamp-start: "scriptversion="
 | 
					 | 
				
			||||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
 | 
					 | 
				
			||||||
# time-stamp-time-zone: "UTC"
 | 
					 | 
				
			||||||
# time-stamp-end: "; # UTC"
 | 
					 | 
				
			||||||
# End:
 | 
					 | 
				
			||||||
@@ -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,394 +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[0];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 char *str, unsigned len)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct dm_hash_node *n = malloc(sizeof(*n) + len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (n) {
 | 
					 | 
				
			||||||
		memcpy(n->key, str, len);
 | 
					 | 
				
			||||||
		n->keylen = len;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return n;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static unsigned long _hash(const char *str, unsigned len)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long h = 0, g;
 | 
					 | 
				
			||||||
	unsigned i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < len; i++) {
 | 
					 | 
				
			||||||
		h <<= 4;
 | 
					 | 
				
			||||||
		h += _nums[(unsigned char) *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)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//----------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -1,21 +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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//----------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef SIMPLE_RADIX_TREE
 | 
					 | 
				
			||||||
#include "base/data-struct/radix-tree-simple.c"
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#include "base/data-struct/radix-tree-adaptive.c"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//----------------------------------------------------------------
 | 
					 | 
				
			||||||
@@ -1,64 +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
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
#ifndef BASE_DATA_STRUCT_RADIX_TREE_H
 | 
					 | 
				
			||||||
#define BASE_DATA_STRUCT_RADIX_TREE_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//----------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct radix_tree;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
union radix_value {
 | 
					 | 
				
			||||||
	void *ptr;
 | 
					 | 
				
			||||||
	uint64_t n;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef void (*radix_value_dtr)(void *context, union radix_value v);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// dtr will be called on any deleted entries.  dtr may be NULL.
 | 
					 | 
				
			||||||
struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context);
 | 
					 | 
				
			||||||
void radix_tree_destroy(struct radix_tree *rt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
unsigned radix_tree_size(struct radix_tree *rt);
 | 
					 | 
				
			||||||
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v);
 | 
					 | 
				
			||||||
bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Returns the number of values removed
 | 
					 | 
				
			||||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *prefix_b, uint8_t *prefix_e);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool radix_tree_lookup(struct radix_tree *rt,
 | 
					 | 
				
			||||||
		       uint8_t *kb, uint8_t *ke, union radix_value *result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// The radix tree stores entries in lexicographical order.  Which means
 | 
					 | 
				
			||||||
// we can iterate entries, in order.  Or iterate entries with a particular
 | 
					 | 
				
			||||||
// prefix.
 | 
					 | 
				
			||||||
struct radix_tree_iterator {
 | 
					 | 
				
			||||||
        // Returns false if the iteration should end.
 | 
					 | 
				
			||||||
	bool (*visit)(struct radix_tree_iterator *it,
 | 
					 | 
				
			||||||
                      uint8_t *kb, uint8_t *ke, union radix_value v);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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,25 +0,0 @@
 | 
				
			|||||||
// Copyright (C) 2018 - 2020 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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef BASE_MEMORY_CONTAINER_OF_H
 | 
					 | 
				
			||||||
#define BASE_MEMORY_CONTAINER_OF_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stddef.h>  // offsetof
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//----------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define container_of(v, t, head) \
 | 
					 | 
				
			||||||
    ((t *)((const char *)(v) - offsetof(t, head)))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//----------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
@@ -1,27 +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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef BASE_MEMORY_ZALLOC_H
 | 
					 | 
				
			||||||
#define BASE_MEMORY_ZALLOC_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//----------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void *zalloc(size_t len)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return calloc(1, len);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//----------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
							
								
								
									
										2
									
								
								conf/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								conf/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -2,5 +2,3 @@ command_profile_template.profile
 | 
				
			|||||||
example.conf
 | 
					example.conf
 | 
				
			||||||
lvmlocal.conf
 | 
					lvmlocal.conf
 | 
				
			||||||
metadata_profile_template.profile
 | 
					metadata_profile_template.profile
 | 
				
			||||||
configure.h
 | 
					 | 
				
			||||||
lvm-version.h
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
					# This file is part of LVM2.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -9,7 +9,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
# along with this program; if not, write to the Free Software Foundation,
 | 
					# along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
srcdir = @srcdir@
 | 
					srcdir = @srcdir@
 | 
				
			||||||
top_srcdir = @top_srcdir@
 | 
					top_srcdir = @top_srcdir@
 | 
				
			||||||
@@ -24,17 +24,15 @@ PROFILES=$(PROFILE_TEMPLATES) \
 | 
				
			|||||||
	$(srcdir)/cache-mq.profile \
 | 
						$(srcdir)/cache-mq.profile \
 | 
				
			||||||
	$(srcdir)/cache-smq.profile \
 | 
						$(srcdir)/cache-smq.profile \
 | 
				
			||||||
	$(srcdir)/thin-generic.profile \
 | 
						$(srcdir)/thin-generic.profile \
 | 
				
			||||||
	$(srcdir)/thin-performance.profile \
 | 
						$(srcdir)/thin-performance.profile
 | 
				
			||||||
	$(srcdir)/vdo-small.profile \
 | 
					 | 
				
			||||||
	$(srcdir)/lvmdbusd.profile
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
include $(top_builddir)/make.tmpl
 | 
					include $(top_builddir)/make.tmpl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: install_conf install_localconf install_profiles
 | 
					.PHONY: install_conf install_localconf install_profiles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
generate:
 | 
					generate:
 | 
				
			||||||
	$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in
 | 
						(cat $(top_srcdir)/conf/example.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --ignorelocal --withspaces) > example.conf.in
 | 
				
			||||||
	$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --withcomments --withspaces local > lvmlocal.conf.in
 | 
						(cat $(top_srcdir)/conf/lvmlocal.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --withspaces local) > lvmlocal.conf.in
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_conf: $(CONFSRC)
 | 
					install_conf: $(CONFSRC)
 | 
				
			||||||
	@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
 | 
						@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
 | 
				
			||||||
@@ -49,9 +47,8 @@ install_localconf: $(CONFLOCAL)
 | 
				
			|||||||
	fi
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_profiles: $(PROFILES)
 | 
					install_profiles: $(PROFILES)
 | 
				
			||||||
	@echo "    [INSTALL] $<"
 | 
						$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_PROFILE_DIR)
 | 
				
			||||||
	$(Q) $(INSTALL_DIR) $(profiledir)
 | 
						$(INSTALL_DATA) $(PROFILES) $(DESTDIR)$(DEFAULT_PROFILE_DIR)/
 | 
				
			||||||
	$(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_lvm2: install_conf install_localconf install_profiles
 | 
					install_lvm2: install_conf install_localconf install_profiles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,6 @@ allocation {
 | 
				
			|||||||
	cache_mode = "writethrough"
 | 
						cache_mode = "writethrough"
 | 
				
			||||||
	cache_policy = "smq"
 | 
						cache_policy = "smq"
 | 
				
			||||||
	cache_settings {
 | 
						cache_settings {
 | 
				
			||||||
	        # currently no settings for "smq" policy
 | 
						        # currently no settins for "smq" policy
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,17 +11,6 @@
 | 
				
			|||||||
# Refer to 'man lvm.conf' for further information about profiles and
 | 
					# Refer to 'man lvm.conf' for further information about profiles and
 | 
				
			||||||
# general configuration file layout.
 | 
					# general configuration file layout.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
allocation {
 | 
					 | 
				
			||||||
	cache_mode="writethrough"
 | 
					 | 
				
			||||||
	cache_settings {
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
log {
 | 
					 | 
				
			||||||
	report_command_log=0
 | 
					 | 
				
			||||||
	command_log_sort="log_seq_num"
 | 
					 | 
				
			||||||
	command_log_cols="log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code"
 | 
					 | 
				
			||||||
	command_log_selection="!(log_type=status && message=success)"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
global {
 | 
					global {
 | 
				
			||||||
	units="h"
 | 
						units="h"
 | 
				
			||||||
	si_unit_consistency=1
 | 
						si_unit_consistency=1
 | 
				
			||||||
@@ -29,9 +18,7 @@ global {
 | 
				
			|||||||
	lvdisplay_shows_full_device_path=0
 | 
						lvdisplay_shows_full_device_path=0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
report {
 | 
					report {
 | 
				
			||||||
	output_format="basic"
 | 
					 | 
				
			||||||
	compact_output=0
 | 
						compact_output=0
 | 
				
			||||||
	compact_output_cols=""
 | 
					 | 
				
			||||||
	aligned=1
 | 
						aligned=1
 | 
				
			||||||
	buffered=1
 | 
						buffered=1
 | 
				
			||||||
	headings=1
 | 
						headings=1
 | 
				
			||||||
@@ -39,9 +26,8 @@ report {
 | 
				
			|||||||
	list_item_separator=","
 | 
						list_item_separator=","
 | 
				
			||||||
	prefixes=0
 | 
						prefixes=0
 | 
				
			||||||
	quoted=1
 | 
						quoted=1
 | 
				
			||||||
	columns_as_rows=0
 | 
						colums_as_rows=0
 | 
				
			||||||
	binary_values_as_numeric=0
 | 
						binary_values_as_numeric=0
 | 
				
			||||||
	time_format="%Y-%m-%d %T %z"
 | 
					 | 
				
			||||||
	devtypes_sort="devtype_name"
 | 
						devtypes_sort="devtype_name"
 | 
				
			||||||
	devtypes_cols="devtype_name,devtype_max_partitions,devtype_description"
 | 
						devtypes_cols="devtype_name,devtype_max_partitions,devtype_description"
 | 
				
			||||||
	devtypes_cols_verbose="devtype_name,devtype_max_partitions,devtype_description"
 | 
						devtypes_cols_verbose="devtype_name,devtype_max_partitions,devtype_description"
 | 
				
			||||||
@@ -60,15 +46,4 @@ report {
 | 
				
			|||||||
	pvsegs_sort="pv_name,pvseg_start"
 | 
						pvsegs_sort="pv_name,pvseg_start"
 | 
				
			||||||
	pvsegs_cols="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
 | 
						pvsegs_cols="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
 | 
				
			||||||
	pvsegs_cols_verbose="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges"
 | 
						pvsegs_cols_verbose="pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges"
 | 
				
			||||||
	vgs_cols_full="vg_all"
 | 
					 | 
				
			||||||
	pvs_cols_full="pv_all"
 | 
					 | 
				
			||||||
	lvs_cols_full="lv_all"
 | 
					 | 
				
			||||||
	pvsegs_cols_full="pvseg_all,pv_uuid,lv_uuid"
 | 
					 | 
				
			||||||
	segs_cols_full="seg_all,lv_uuid"
 | 
					 | 
				
			||||||
	vgs_sort_full="vg_name"
 | 
					 | 
				
			||||||
	pvs_sort_full="pv_name"
 | 
					 | 
				
			||||||
	lvs_sort_full="vg_name,lv_name"
 | 
					 | 
				
			||||||
	pvsegs_sort_full="pv_uuid,pvseg_start"
 | 
					 | 
				
			||||||
	segs_sort_full="lv_uuid,seg_start"
 | 
					 | 
				
			||||||
	mark_hidden_devices=1
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										23
									
								
								conf/example.conf.base
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								conf/example.conf.base
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					# This is an example configuration file for the LVM2 system.
 | 
				
			||||||
 | 
					# It contains the default settings that would be used if there was no
 | 
				
			||||||
 | 
					# @DEFAULT_SYS_DIR@/lvm.conf file.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Refer to 'man lvm.conf' for further information including the file layout.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Refer to 'man lvm.conf' for information about how settings configured in
 | 
				
			||||||
 | 
					# this file are combined with built-in values and command line options to
 | 
				
			||||||
 | 
					# arrive at the final values used by LVM.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Refer to 'man lvmconfig' for information about displaying the built-in
 | 
				
			||||||
 | 
					# and configured values used by LVM.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# If a default value is set in this file (not commented out), then a
 | 
				
			||||||
 | 
					# new version of LVM using this file will continue using that value,
 | 
				
			||||||
 | 
					# even if the new version of LVM changes the built-in default value.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# To put this file in a different directory and override @DEFAULT_SYS_DIR@ set
 | 
				
			||||||
 | 
					# the environment variable LVM_SYSTEM_DIR before running the tools.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# N.B. Take care that each setting only appears once if uncommenting
 | 
				
			||||||
 | 
					# example settings in this file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,50 +0,0 @@
 | 
				
			|||||||
#
 | 
					 | 
				
			||||||
# DO NOT EDIT THIS FILE!
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# LVM configuration profile used by lvmdbusd daemon.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This sets up LVM to produce output in the most suitable format for processing
 | 
					 | 
				
			||||||
# by lvmdbusd daemon which utilizes LVM shell to execute LVM commands.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Do not edit this file in any way. This profile is distributed together with
 | 
					 | 
				
			||||||
# lvmdbusd and it contains configuration that is important for lvmdbusd to
 | 
					 | 
				
			||||||
# cooperate and interface with LVM correctly.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
global {
 | 
					 | 
				
			||||||
	# use bytes for expected and deterministic output
 | 
					 | 
				
			||||||
	units=b
 | 
					 | 
				
			||||||
	# no need for suffix if we have units set
 | 
					 | 
				
			||||||
	suffix=0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
report {
 | 
					 | 
				
			||||||
	compact_output=0
 | 
					 | 
				
			||||||
	compact_output_cols=""
 | 
					 | 
				
			||||||
	binary_values_as_numeric=0
 | 
					 | 
				
			||||||
	# time in number of seconds since the Epoch
 | 
					 | 
				
			||||||
	time_format="%s"
 | 
					 | 
				
			||||||
	mark_hidden_devices=1
 | 
					 | 
				
			||||||
	# lvmdbusd expects JSON output
 | 
					 | 
				
			||||||
	output_format=json
 | 
					 | 
				
			||||||
	# *_cols_full for lvm fullreport's fields which lvmdbusd relies on to update its state
 | 
					 | 
				
			||||||
	vgs_cols_full="vg_name,vg_uuid,vg_fmt,vg_size,vg_free,vg_sysid,vg_extent_size,vg_extent_count,vg_free_count,vg_profile,max_lv,max_pv,pv_count,lv_count,snap_count,vg_seqno,vg_mda_count,vg_mda_free,vg_mda_size,vg_mda_used_count,vg_attr,vg_tags"
 | 
					 | 
				
			||||||
	pvs_cols_full="pv_name,pv_uuid,pv_fmt,pv_size,pv_free,pv_used,dev_size,pv_mda_size,pv_mda_free,pv_ba_start,pv_ba_size,pe_start,pv_pe_count,pv_pe_alloc_count,pv_attr,pv_tags,vg_name,vg_uuid"
 | 
					 | 
				
			||||||
	lvs_cols_full="lv_uuid,lv_name,lv_path,lv_size,vg_name,pool_lv_uuid,pool_lv,origin_uuid,origin,data_percent,lv_attr,lv_tags,vg_uuid,lv_active,data_lv,metadata_lv,lv_parent,lv_role,lv_layout"
 | 
					 | 
				
			||||||
	pvsegs_cols_full="pvseg_start,pvseg_size,segtype,pv_uuid,lv_uuid,pv_name"
 | 
					 | 
				
			||||||
	segs_cols_full="seg_pe_ranges,segtype,lv_uuid"
 | 
					 | 
				
			||||||
	vgs_sort_full="vg_name"
 | 
					 | 
				
			||||||
	pvs_sort_full="pv_name"
 | 
					 | 
				
			||||||
	lvs_sort_full="vg_name,lv_name"
 | 
					 | 
				
			||||||
	pvsegs_sort_full="pv_uuid,pvseg_start"
 | 
					 | 
				
			||||||
	segs_sort_full="lv_uuid,seg_start"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
log {
 | 
					 | 
				
			||||||
	# lvmdbusd relies on command log report to inspect LVM command's execution status
 | 
					 | 
				
			||||||
	report_command_log=1
 | 
					 | 
				
			||||||
	# display only outermost LVM shell-related log that lvmdbusd inspects first after LVM command execution (it calls 'lastlog' for more detailed log afterwards if needed)
 | 
					 | 
				
			||||||
	command_log_selection="log_context=shell"
 | 
					 | 
				
			||||||
	command_log_cols="log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code"
 | 
					 | 
				
			||||||
	command_log_sort="log_seq_num"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										19
									
								
								conf/lvmlocal.conf.base
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								conf/lvmlocal.conf.base
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					# This is a local configuration file template for the LVM2 system
 | 
				
			||||||
 | 
					# which should be installed as @DEFAULT_SYS_DIR@/lvmlocal.conf .
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Refer to 'man lvm.conf' for information about the file layout.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# To put this file in a different directory and override
 | 
				
			||||||
 | 
					# @DEFAULT_SYS_DIR@ set the environment variable LVM_SYSTEM_DIR before
 | 
				
			||||||
 | 
					# running the tools.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The lvmlocal.conf file is normally expected to contain only the
 | 
				
			||||||
 | 
					# "local" section which contains settings that should not be shared or
 | 
				
			||||||
 | 
					# repeated among different hosts.  (But if other sections are present,
 | 
				
			||||||
 | 
					# they *will* get processed.  Settings in this file override equivalent
 | 
				
			||||||
 | 
					# ones in lvm.conf and are in turn overridden by ones in any enabled
 | 
				
			||||||
 | 
					# lvm_<tag>.conf files.)
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Please take care that each setting only appears once if uncommenting
 | 
				
			||||||
 | 
					# example settings in this file and never copy this file between hosts.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -51,7 +51,6 @@ local {
 | 
				
			|||||||
	# Configuration option local/host_id.
 | 
						# Configuration option local/host_id.
 | 
				
			||||||
	# The lvmlockd sanlock host_id.
 | 
						# The lvmlockd sanlock host_id.
 | 
				
			||||||
	# This must be unique among all hosts, and must be between 1 and 2000.
 | 
						# This must be unique among all hosts, and must be between 1 and 2000.
 | 
				
			||||||
	# Applicable only if LVM is compiled with lockd support
 | 
					 | 
				
			||||||
	# This configuration option has an automatic default value.
 | 
						# This configuration option has an automatic default value.
 | 
				
			||||||
	# host_id = 0
 | 
						# host_id = 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,146 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2015 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
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Coverity usage:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * translate model into xml
 | 
					 | 
				
			||||||
 * cov-make-library -of coverity_model.xml coverity_model.c
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * compile (using outdir 'cov'):
 | 
					 | 
				
			||||||
 * cov-build --dir=cov make CC=gcc
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * analyze (agressively, using 'cov')
 | 
					 | 
				
			||||||
 * cov-analyze --dir cov --wait-for-license --hfa --concurrency --enable-fnptr --enable-constraint-fpp --security --all --aggressiveness-level=high --field-offset-escape --user-model-file=coverity/coverity_model.xml
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * generate html output (to 'html' from 'cov'):
 | 
					 | 
				
			||||||
 * cov-format-errors --dir cov  --html-output html
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct lv_segment;
 | 
					 | 
				
			||||||
struct logical_volume;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct lv_segment *first_seg(const struct logical_volume *lv)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return ((struct lv_segment **)lv)[0];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct lv_segment *last_seg(const struct logical_volume *lv)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return ((struct lv_segment **)lv)[0];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return "STRING";
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct logical_volume *origin_from_cow(const struct logical_volume *lv)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (lv)
 | 
					 | 
				
			||||||
		return lv;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	__coverity_panic__();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* simple_memccpy() from glibc */
 | 
					 | 
				
			||||||
void *memccpy(void *dest, const void *src, int c, size_t n)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const char *s = src;
 | 
					 | 
				
			||||||
	char *d = dest;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	while (n-- > 0)
 | 
					 | 
				
			||||||
		if ((*d++ = *s++) == (char) c)
 | 
					 | 
				
			||||||
			return d;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * 2 lines bellow needs to be placed in coverity/config/user_nodefs.h
 | 
					 | 
				
			||||||
 * Not sure about any other way.
 | 
					 | 
				
			||||||
 * Without them, coverity shows warning since x86 system header files
 | 
					 | 
				
			||||||
 * are using inline assembly to reset fdset
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
//#nodef FD_ZERO model_FD_ZERO
 | 
					 | 
				
			||||||
//void model_FD_ZERO(void *fdset);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void model_FD_ZERO(void *fdset)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < 1024 / 8 / sizeof(long); ++i)
 | 
					 | 
				
			||||||
		((long*)fdset)[i] = 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Resent Coverity reports quite weird errors... */
 | 
					 | 
				
			||||||
int *__errno_location(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
const unsigned short **__ctype_b_loc (void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Added extra pointer check to not need these models,
 | 
					 | 
				
			||||||
 * for now just keep then in file
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
struct cmd_context;
 | 
					 | 
				
			||||||
struct profile;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
        return "text";
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, struct profile *profile)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
        return "text";
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Until fixed coverity case# 00531860:
 | 
					 | 
				
			||||||
 *   A FORWARD_NULL false positive on a recursive function call
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * model also these functions:
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
const struct dm_config_node;
 | 
					 | 
				
			||||||
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const struct dm_config_node *cn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return cn;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, int id, struct profile *profile)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const struct dm_config_node *cn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return cn;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int b;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return b;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
@@ -9,13 +9,17 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
# along with this program; if not, write to the Free Software Foundation,
 | 
					# along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
srcdir = @srcdir@
 | 
					srcdir = @srcdir@
 | 
				
			||||||
top_srcdir = @top_srcdir@
 | 
					top_srcdir = @top_srcdir@
 | 
				
			||||||
top_builddir = @top_builddir@
 | 
					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")
 | 
					ifeq ("@BUILD_CMIRRORD@", "yes")
 | 
				
			||||||
  SUBDIRS += cmirrord
 | 
					  SUBDIRS += cmirrord
 | 
				
			||||||
@@ -28,20 +32,20 @@ daemons.cflow: dmeventd.cflow
 | 
				
			|||||||
endif
 | 
					endif
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ("@BUILD_LVMETAD@", "yes")
 | 
				
			||||||
 | 
					  SUBDIRS += lvmetad
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ("@BUILD_LVMPOLLD@", "yes")
 | 
					ifeq ("@BUILD_LVMPOLLD@", "yes")
 | 
				
			||||||
  SUBDIRS += lvmpolld
 | 
					  SUBDIRS += lvmpolld
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ("@BUILD_LVMLOCKD@", "yes")
 | 
					ifeq ("@BUILD_LVMLOCKD@", "yes")
 | 
				
			||||||
  SUBDIRS += lvmlockd
 | 
					  SUBDIRS += lvmlockd 
 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ifeq ("@BUILD_LVMDBUSD@", "yes")
 | 
					 | 
				
			||||||
  SUBDIRS += lvmdbusd
 | 
					 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(MAKECMDGOALS),distclean)
 | 
					ifeq ($(MAKECMDGOALS),distclean)
 | 
				
			||||||
  SUBDIRS = cmirrord dmeventd lvmpolld lvmlockd lvmdbusd
 | 
					  SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include $(top_builddir)/make.tmpl
 | 
					include $(top_builddir)/make.tmpl
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								daemons/clvmd/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								daemons/clvmd/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					clvmd
 | 
				
			||||||
							
								
								
									
										103
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								daemons/clvmd/Makefile.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					#
 | 
				
			||||||
 | 
					# 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LVMLIBS = $(LVMINTERNAL_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ("@DMEVENTD@", "yes")
 | 
				
			||||||
 | 
						LVMLIBS += -ldevmapper-event
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					include $(top_builddir)/make.tmpl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LVMLIBS += -ldevmapper
 | 
				
			||||||
 | 
					LIBS += $(PTHREAD_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
 | 
				
			||||||
 | 
					LDFLAGS += $(EXTRA_EXEC_LDFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INSTALL_TARGETS = \
 | 
				
			||||||
 | 
						install_clvmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clvmd: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
 | 
				
			||||||
 | 
						$(CC) $(CFLAGS) $(LDFLAGS) -o clvmd $(OBJECTS) \
 | 
				
			||||||
 | 
							$(LVMLIBS) $(LMLIBS) $(LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: install_clvmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install_clvmd: $(TARGETS)
 | 
				
			||||||
 | 
						$(INSTALL_PROGRAM) -D clvmd $(usrsbindir)/clvmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install: $(INSTALL_TARGETS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install_cluster: $(INSTALL_TARGETS)
 | 
				
			||||||
							
								
								
									
										83
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								daemons/clvmd/clvm.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 */
 | 
				
			||||||
 | 
					static const char 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.*/
 | 
				
			||||||
 | 
					#define NODE_ALL	"*"
 | 
				
			||||||
 | 
					#define NODE_LOCAL	"."
 | 
				
			||||||
 | 
					#define NODE_REMOTE	"^"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										414
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										414
									
								
								daemons/clvmd/clvmd-command.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,414 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 */
 | 
				
			||||||
 | 
							status = do_check_lvm1(lockname);
 | 
				
			||||||
 | 
							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) {
 | 
				
			||||||
 | 
							*retlen = 1 + ((*buf) ? dm_snprintf(*buf, buflen, "%s",
 | 
				
			||||||
 | 
											    strerror(status)) : -1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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("Client thread cleanup (%p)\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("Cleanup (%p): 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,6 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
 | 
					 * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
 | 
				
			||||||
 * Copyright (C) 2004-2017 Red Hat, Inc. All rights reserved.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This file is part of LVM2.
 | 
					 * This file is part of LVM2.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -10,5 +9,19 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This file must be included first by every clvmd source file.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef _LVM_CLVMD_COMMON_H
 | 
				
			||||||
 | 
					#define _LVM_CLVMD_COMMON_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
 | 
				
			||||||
							
								
								
									
										658
									
								
								daemons/clvmd/clvmd-corosync.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										658
									
								
								daemons/clvmd/clvmd-corosync.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,658 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										689
									
								
								daemons/clvmd/clvmd-openais.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										689
									
								
								daemons/clvmd/clvmd-openais.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,689 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
						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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2378
									
								
								daemons/clvmd/clvmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2378
									
								
								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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
 | 
				
			||||||
							
								
								
									
										932
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										932
									
								
								daemons/clvmd/lvm-functions.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,932 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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;
 | 
				
			||||||
 | 
							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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if a VG is in use by LVM1 so we don't stomp on it */
 | 
				
			||||||
 | 
					int do_check_lvm1(const char *vgname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = check_lvm1_vg_inactive(cmd, vgname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return status == 1 ? 0 : EBUSY;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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_full_scan_done(0);
 | 
				
			||||||
 | 
						init_ignore_suspended_devices(1);
 | 
				
			||||||
 | 
						lvmcache_label_scan(cmd, 2);
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strncpy(last_error, message, sizeof(last_error));
 | 
				
			||||||
 | 
						last_error[sizeof(last_error)-1] = '\0';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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*/, 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 (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
 | 
				
			||||||
 | 
							log_error("Failed to allocate command 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);
 | 
				
			||||||
 | 
							cmd = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										41
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								daemons/clvmd/lvm-functions.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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_check_lvm1(const char *vgname);
 | 
				
			||||||
 | 
					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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int refresh_clvmd(int all_nodes);
 | 
				
			||||||
 | 
					int restart_clvmd(int all_nodes);
 | 
				
			||||||
 | 
					int debug_clvmd(int level, int clusterwide);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -9,7 +9,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
# along with this program; if not, write to the Free Software Foundation,
 | 
					# along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
srcdir = @srcdir@
 | 
					srcdir = @srcdir@
 | 
				
			||||||
top_srcdir = @top_srcdir@
 | 
					top_srcdir = @top_srcdir@
 | 
				
			||||||
@@ -17,6 +17,8 @@ top_builddir = @top_builddir@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CPG_LIBS = @CPG_LIBS@
 | 
					CPG_LIBS = @CPG_LIBS@
 | 
				
			||||||
CPG_CFLAGS = @CPG_CFLAGS@
 | 
					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
 | 
					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
 | 
					include $(top_builddir)/make.tmpl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LMLIBS += $(CPG_LIBS)
 | 
					LIBS += -ldevmapper
 | 
				
			||||||
CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS)
 | 
					LMLIBS += $(CPG_LIBS) $(SACKPT_LIBS)
 | 
				
			||||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
 | 
					CFLAGS += $(CPG_CFLAGS) $(SACKPT_CFLAGS) $(EXTRA_EXEC_CFLAGS)
 | 
				
			||||||
 | 
					LDFLAGS += $(EXTRA_EXEC_LDFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cmirrord: $(OBJECTS)
 | 
					cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
 | 
				
			||||||
	@echo "    [CC] $@"
 | 
						$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
 | 
				
			||||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
 | 
							$(LVMLIBS) $(LMLIBS) $(LIBS)
 | 
				
			||||||
		$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
install: $(TARGETS)
 | 
					install: $(TARGETS)
 | 
				
			||||||
	@echo "    [INSTALL] $<"
 | 
						$(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord
 | 
				
			||||||
	$(Q) $(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU General Public License
 | 
					 * You should have received a copy of the GNU General Public License
 | 
				
			||||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include "logging.h"
 | 
					#include "logging.h"
 | 
				
			||||||
#include "common.h"
 | 
					#include "common.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include "logging.h"
 | 
					#include "logging.h"
 | 
				
			||||||
#include "cluster.h"
 | 
					#include "cluster.h"
 | 
				
			||||||
@@ -16,11 +16,7 @@
 | 
				
			|||||||
#include "functions.h"
 | 
					#include "functions.h"
 | 
				
			||||||
#include "link_mon.h"
 | 
					#include "link_mon.h"
 | 
				
			||||||
#include "local.h"
 | 
					#include "local.h"
 | 
				
			||||||
#include "lib/mm/xlate.h"
 | 
					#include "xlate.h"
 | 
				
			||||||
#include "base/memory/zalloc.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* FIXME: remove this and the code */
 | 
					 | 
				
			||||||
#define CMIRROR_HAS_CHECKPOINT 0
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <corosync/cpg.h>
 | 
					#include <corosync/cpg.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
@@ -170,9 +166,6 @@ int cluster_send(struct clog_request *rq)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int r;
 | 
						int r;
 | 
				
			||||||
	int found = 0;
 | 
						int found = 0;
 | 
				
			||||||
#if CMIRROR_HAS_CHECKPOINT
 | 
					 | 
				
			||||||
	int count = 0;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	struct iovec iov;
 | 
						struct iovec iov;
 | 
				
			||||||
	struct clog_cpg *entry;
 | 
						struct clog_cpg *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -189,7 +182,7 @@ int cluster_send(struct clog_request *rq)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Once the request heads for the cluster, the luid loses
 | 
						 * Once the request heads for the cluster, the luid looses
 | 
				
			||||||
	 * all its meaning.
 | 
						 * all its meaning.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	rq->u_rq.luid = 0;
 | 
						rq->u_rq.luid = 0;
 | 
				
			||||||
@@ -210,6 +203,8 @@ int cluster_send(struct clog_request *rq)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#if CMIRROR_HAS_CHECKPOINT
 | 
					#if CMIRROR_HAS_CHECKPOINT
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
 | 
							int count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		r = cpg_mcast_joined(entry->handle, CPG_TYPE_AGREED, &iov, 1);
 | 
							r = cpg_mcast_joined(entry->handle, CPG_TYPE_AGREED, &iov, 1);
 | 
				
			||||||
		if (r != SA_AIS_ERR_TRY_AGAIN)
 | 
							if (r != SA_AIS_ERR_TRY_AGAIN)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -403,12 +398,13 @@ static struct checkpoint_data *prepare_checkpoint(struct clog_cpg *entry,
 | 
				
			|||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	new = zalloc(sizeof(*new));
 | 
						new = malloc(sizeof(*new));
 | 
				
			||||||
	if (!new) {
 | 
						if (!new) {
 | 
				
			||||||
		LOG_ERROR("Unable to create checkpoint data for %u",
 | 
							LOG_ERROR("Unable to create checkpoint data for %u",
 | 
				
			||||||
			  cp_requester);
 | 
								  cp_requester);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						memset(new, 0, sizeof(*new));
 | 
				
			||||||
	new->requester = cp_requester;
 | 
						new->requester = cp_requester;
 | 
				
			||||||
	strncpy(new->uuid, entry->name.value, entry->name.length);
 | 
						strncpy(new->uuid, entry->name.value, entry->name.length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -643,12 +639,13 @@ static int export_checkpoint(struct checkpoint_data *cp)
 | 
				
			|||||||
	rq_size += RECOVERING_REGION_SECTION_SIZE;
 | 
						rq_size += RECOVERING_REGION_SECTION_SIZE;
 | 
				
			||||||
	rq_size += cp->bitmap_size * 2; /* clean|sync_bits */
 | 
						rq_size += cp->bitmap_size * 2; /* clean|sync_bits */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rq = zalloc(rq_size);
 | 
						rq = malloc(rq_size);
 | 
				
			||||||
	if (!rq) {
 | 
						if (!rq) {
 | 
				
			||||||
		LOG_ERROR("export_checkpoint: "
 | 
							LOG_ERROR("export_checkpoint: "
 | 
				
			||||||
			  "Unable to allocate transfer structs");
 | 
								  "Unable to allocate transfer structs");
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						memset(rq, 0, rq_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dm_list_init(&rq->u.list);
 | 
						dm_list_init(&rq->u.list);
 | 
				
			||||||
	rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY;
 | 
						rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY;
 | 
				
			||||||
@@ -1443,7 +1440,7 @@ static void cpg_leave_callback(struct clog_cpg *match,
 | 
				
			|||||||
			free(rq);
 | 
								free(rq);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (i = 0, j = 0; (int) i < match->checkpoints_needed; i++, j++) {
 | 
						for (i = 0, j = 0; i < match->checkpoints_needed; i++, j++) {
 | 
				
			||||||
		match->checkpoint_requesters[j] = match->checkpoint_requesters[i];
 | 
							match->checkpoint_requesters[j] = match->checkpoint_requesters[i];
 | 
				
			||||||
		if (match->checkpoint_requesters[i] == left->nodeid) {
 | 
							if (match->checkpoint_requesters[i] == left->nodeid) {
 | 
				
			||||||
			LOG_ERROR("[%s] Removing pending ckpt from needed list (%u is leaving)",
 | 
								LOG_ERROR("[%s] Removing pending ckpt from needed list (%u is leaving)",
 | 
				
			||||||
@@ -1620,11 +1617,12 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
 | 
				
			|||||||
			return -EEXIST;
 | 
								return -EEXIST;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	new = zalloc(sizeof(*new));
 | 
						new = malloc(sizeof(*new));
 | 
				
			||||||
	if (!new) {
 | 
						if (!new) {
 | 
				
			||||||
		LOG_ERROR("Unable to allocate memory for clog_cpg");
 | 
							LOG_ERROR("Unable to allocate memory for clog_cpg");
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						memset(new, 0, sizeof(*new));
 | 
				
			||||||
	dm_list_init(&new->list);
 | 
						dm_list_init(&new->list);
 | 
				
			||||||
	new->lowest_id = 0xDEAD;
 | 
						new->lowest_id = 0xDEAD;
 | 
				
			||||||
	dm_list_init(&new->startup_list);
 | 
						dm_list_init(&new->startup_list);
 | 
				
			||||||
@@ -1632,7 +1630,7 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	size = ((strlen(uuid) + 1) > CPG_MAX_NAME_LENGTH) ?
 | 
						size = ((strlen(uuid) + 1) > CPG_MAX_NAME_LENGTH) ?
 | 
				
			||||||
		CPG_MAX_NAME_LENGTH : (strlen(uuid) + 1);
 | 
							CPG_MAX_NAME_LENGTH : (strlen(uuid) + 1);
 | 
				
			||||||
	(void) dm_strncpy(new->name.value, uuid, size);
 | 
						strncpy(new->name.value, uuid, size);
 | 
				
			||||||
	new->name.length = (uint32_t)size;
 | 
						new->name.length = (uint32_t)size;
 | 
				
			||||||
	new->luid = luid;
 | 
						new->luid = luid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,13 +7,13 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifndef _LVM_CLOG_CLUSTER_H
 | 
					#ifndef _LVM_CLOG_CLUSTER_H
 | 
				
			||||||
#define _LVM_CLOG_CLUSTER_H
 | 
					#define _LVM_CLOG_CLUSTER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "libdm/libdevmapper.h"
 | 
					#include "dm-log-userspace.h"
 | 
				
			||||||
#include "libdm/misc/dm-log-userspace.h"
 | 
					#include "libdevmapper.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */
 | 
					#define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */
 | 
				
			||||||
#define DM_ULOG_CHECKPOINT_READY 21
 | 
					#define DM_ULOG_CHECKPOINT_READY 21
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifndef _LVM_CLOG_COMMON_H
 | 
					#ifndef _LVM_CLOG_COMMON_H
 | 
				
			||||||
#define _LVM_CLOG_COMMON_H
 | 
					#define _LVM_CLOG_COMMON_H
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
#include "logging.h"
 | 
					#include "logging.h"
 | 
				
			||||||
#include "cluster.h"
 | 
					#include "cluster.h"
 | 
				
			||||||
#include "compat.h"
 | 
					#include "compat.h"
 | 
				
			||||||
#include "lib/mm/xlate.h"
 | 
					#include "xlate.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,13 +7,11 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include "logging.h"
 | 
					#include "logging.h"
 | 
				
			||||||
#include "functions.h"
 | 
					#include "functions.h"
 | 
				
			||||||
#include "base/memory/zalloc.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <sys/sysmacros.h>
 | 
					 | 
				
			||||||
#include <dirent.h>
 | 
					#include <dirent.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
@@ -378,7 +376,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
 | 
				
			|||||||
	uint32_t block_on_error = 0;
 | 
						uint32_t block_on_error = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int disk_log;
 | 
						int disk_log;
 | 
				
			||||||
	char disk_path[PATH_MAX];
 | 
						char disk_path[128];
 | 
				
			||||||
	int unlink_path = 0;
 | 
						int unlink_path = 0;
 | 
				
			||||||
	long page_size;
 | 
						long page_size;
 | 
				
			||||||
	int pages;
 | 
						int pages;
 | 
				
			||||||
@@ -436,7 +434,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
 | 
				
			|||||||
			block_on_error = 1;
 | 
								block_on_error = 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lc = zalloc(sizeof(*lc));
 | 
						lc = dm_zalloc(sizeof(*lc));
 | 
				
			||||||
	if (!lc) {
 | 
						if (!lc) {
 | 
				
			||||||
		LOG_ERROR("Unable to allocate cluster log context");
 | 
							LOG_ERROR("Unable to allocate cluster log context");
 | 
				
			||||||
		r = -ENOMEM;
 | 
							r = -ENOMEM;
 | 
				
			||||||
@@ -452,19 +450,15 @@ static int _clog_ctr(char *uuid, uint64_t luid,
 | 
				
			|||||||
	lc->skip_bit_warning = region_count;
 | 
						lc->skip_bit_warning = region_count;
 | 
				
			||||||
	lc->disk_fd = -1;
 | 
						lc->disk_fd = -1;
 | 
				
			||||||
	lc->log_dev_failed = 0;
 | 
						lc->log_dev_failed = 0;
 | 
				
			||||||
	if (!dm_strncpy(lc->uuid, uuid, DM_UUID_LEN)) {
 | 
						strncpy(lc->uuid, uuid, DM_UUID_LEN);
 | 
				
			||||||
		LOG_ERROR("Cannot use too long UUID %s.", uuid);
 | 
					 | 
				
			||||||
		r = -EINVAL;
 | 
					 | 
				
			||||||
		goto fail;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	lc->luid = luid;
 | 
						lc->luid = luid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (get_log(lc->uuid, lc->luid) ||
 | 
						if (get_log(lc->uuid, lc->luid) ||
 | 
				
			||||||
	    get_pending_log(lc->uuid, lc->luid)) {
 | 
						    get_pending_log(lc->uuid, lc->luid)) {
 | 
				
			||||||
		LOG_ERROR("[%s/%" PRIu64 "u] Log already exists, unable to create.",
 | 
							LOG_ERROR("[%s/%" PRIu64 "u] Log already exists, unable to create.",
 | 
				
			||||||
			  SHORT_UUID(lc->uuid), lc->luid);
 | 
								  SHORT_UUID(lc->uuid), lc->luid);
 | 
				
			||||||
		r = -EINVAL;
 | 
							dm_free(lc);
 | 
				
			||||||
		goto fail;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dm_list_init(&lc->mark_list);
 | 
						dm_list_init(&lc->mark_list);
 | 
				
			||||||
@@ -533,9 +527,9 @@ fail:
 | 
				
			|||||||
			LOG_ERROR("Close device error, %s: %s",
 | 
								LOG_ERROR("Close device error, %s: %s",
 | 
				
			||||||
				  disk_path, strerror(errno));
 | 
									  disk_path, strerror(errno));
 | 
				
			||||||
		free(lc->disk_buffer);
 | 
							free(lc->disk_buffer);
 | 
				
			||||||
		free(lc->sync_bits);
 | 
							dm_free(lc->sync_bits);
 | 
				
			||||||
		free(lc->clean_bits);
 | 
							dm_free(lc->clean_bits);
 | 
				
			||||||
		free(lc);
 | 
							dm_free(lc);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return r;
 | 
						return r;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -579,12 +573,6 @@ static int clog_ctr(struct dm_ulog_request *rq)
 | 
				
			|||||||
	for (argc = 0, p = rq->data; (p = strstr(p, " ")); p++, argc++)
 | 
						for (argc = 0, p = rq->data; (p = strstr(p, " ")); p++, argc++)
 | 
				
			||||||
		*p = '\0';
 | 
							*p = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!argc) {
 | 
					 | 
				
			||||||
		LOG_ERROR("Received constructor request with bad data %s",
 | 
					 | 
				
			||||||
			  rq->data);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	argv = malloc(argc * sizeof(char *));
 | 
						argv = malloc(argc * sizeof(char *));
 | 
				
			||||||
	if (!argv)
 | 
						if (!argv)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
@@ -660,9 +648,9 @@ static int clog_dtr(struct dm_ulog_request *rq)
 | 
				
			|||||||
			  strerror(errno));
 | 
								  strerror(errno));
 | 
				
			||||||
	if (lc->disk_buffer)
 | 
						if (lc->disk_buffer)
 | 
				
			||||||
		free(lc->disk_buffer);
 | 
							free(lc->disk_buffer);
 | 
				
			||||||
	free(lc->clean_bits);
 | 
						dm_free(lc->clean_bits);
 | 
				
			||||||
	free(lc->sync_bits);
 | 
						dm_free(lc->sync_bits);
 | 
				
			||||||
	free(lc);
 | 
						dm_free(lc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1457,7 +1445,7 @@ static int disk_status_info(struct log_c *lc, struct dm_ulog_request *rq)
 | 
				
			|||||||
	char *data = (char *)rq->data;
 | 
						char *data = (char *)rq->data;
 | 
				
			||||||
	struct stat statbuf;
 | 
						struct stat statbuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fstat(lc->disk_fd, &statbuf)) {
 | 
						if(fstat(lc->disk_fd, &statbuf)) {
 | 
				
			||||||
		rq->error = -errno;
 | 
							rq->error = -errno;
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1520,7 +1508,7 @@ static int disk_status_table(struct log_c *lc, struct dm_ulog_request *rq)
 | 
				
			|||||||
	char *data = (char *)rq->data;
 | 
						char *data = (char *)rq->data;
 | 
				
			||||||
	struct stat statbuf;
 | 
						struct stat statbuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fstat(lc->disk_fd, &statbuf)) {
 | 
						if(fstat(lc->disk_fd, &statbuf)) {
 | 
				
			||||||
		rq->error = -errno;
 | 
							rq->error = -errno;
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,13 +7,12 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifndef _LVM_CLOG_FUNCTIONS_H
 | 
					#ifndef _LVM_CLOG_FUNCTIONS_H
 | 
				
			||||||
#define _LVM_CLOG_FUNCTIONS_H
 | 
					#define _LVM_CLOG_FUNCTIONS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "libdm/libdevmapper.h"
 | 
					#include "dm-log-userspace.h"
 | 
				
			||||||
#include "libdm/misc/dm-log-userspace.h"
 | 
					 | 
				
			||||||
#include "cluster.h"
 | 
					#include "cluster.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LOG_RESUMED   1
 | 
					#define LOG_RESUMED   1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include "logging.h"
 | 
					#include "logging.h"
 | 
				
			||||||
#include "link_mon.h"
 | 
					#include "link_mon.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifndef _LVM_CLOG_LINK_MON_H
 | 
					#ifndef _LVM_CLOG_LINK_MON_H
 | 
				
			||||||
#define _LVM_CLOG_LINK_MON_H
 | 
					#define _LVM_CLOG_LINK_MON_H
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include "logging.h"
 | 
					#include "logging.h"
 | 
				
			||||||
#include "common.h"
 | 
					#include "common.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifndef _LVM_CLOG_LOCAL_H
 | 
					#ifndef _LVM_CLOG_LOCAL_H
 | 
				
			||||||
#define _LVM_CLOG_LOCAL_H
 | 
					#define _LVM_CLOG_LOCAL_H
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include "logging.h"
 | 
					#include "logging.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,12 +7,16 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef _LVM_CLOG_LOGGING_H
 | 
					#ifndef _LVM_CLOG_LOGGING_H
 | 
				
			||||||
#define _LVM_CLOG_LOGGING_H
 | 
					#define _LVM_CLOG_LOGGING_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define _GNU_SOURCE
 | 
				
			||||||
 | 
					#define _FILE_OFFSET_BITS 64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "configure.h"
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <syslog.h>
 | 
					#include <syslog.h>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# You should have received a copy of the GNU Lesser General Public License
 | 
					# 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,
 | 
					# along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
srcdir = @srcdir@
 | 
					srcdir = @srcdir@
 | 
				
			||||||
top_srcdir = @top_srcdir@
 | 
					top_srcdir = @top_srcdir@
 | 
				
			||||||
@@ -56,18 +56,18 @@ include $(top_builddir)/make.tmpl
 | 
				
			|||||||
all: device-mapper
 | 
					all: device-mapper
 | 
				
			||||||
device-mapper: $(TARGETS)
 | 
					device-mapper: $(TARGETS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LIBS += -ldevmapper
 | 
				
			||||||
 | 
					LVMLIBS += -ldevmapper-event $(PTHREAD_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
 | 
					CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
 | 
				
			||||||
LIBS += $(PTHREAD_LIBS) -L$(top_builddir)/libdm -ldevmapper
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
dmeventd: $(LIB_SHARED) dmeventd.o
 | 
					dmeventd: $(LIB_SHARED) dmeventd.o
 | 
				
			||||||
	@echo "    [CC] $@"
 | 
						$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -L. -o $@ dmeventd.o \
 | 
				
			||||||
	$(Q) $(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
 | 
						$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
 | 
				
			||||||
		-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) -lm
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
dmeventd.static: $(LIB_STATIC) dmeventd.o
 | 
					dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a
 | 
				
			||||||
	@echo "    [CC] $@"
 | 
						$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L. -L$(interfacebuilddir) -o $@ \
 | 
				
			||||||
	$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
 | 
						dmeventd.o $(DL_LIBS) $(LVMLIBS) $(LIBS) $(STATIC_LIBS)
 | 
				
			||||||
		-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ("@PKGCONFIG@", "yes")
 | 
					ifeq ("@PKGCONFIG@", "yes")
 | 
				
			||||||
  INSTALL_LIB_TARGETS += install_pkgconfig
 | 
					  INSTALL_LIB_TARGETS += install_pkgconfig
 | 
				
			||||||
@@ -75,6 +75,7 @@ endif
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
ifneq ("$(CFLOW_CMD)", "")
 | 
					ifneq ("$(CFLOW_CMD)", "")
 | 
				
			||||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
 | 
					CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
 | 
				
			||||||
 | 
					-include $(top_builddir)/libdm/libdevmapper.cflow
 | 
				
			||||||
-include $(top_builddir)/lib/liblvm-internal.cflow
 | 
					-include $(top_builddir)/lib/liblvm-internal.cflow
 | 
				
			||||||
-include $(top_builddir)/lib/liblvm2cmd.cflow
 | 
					-include $(top_builddir)/lib/liblvm2cmd.cflow
 | 
				
			||||||
-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
 | 
					-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
 | 
				
			||||||
@@ -82,28 +83,23 @@ CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
 | 
				
			|||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_include: $(srcdir)/libdevmapper-event.h
 | 
					install_include: $(srcdir)/libdevmapper-event.h
 | 
				
			||||||
	@echo "    [INSTALL] $<"
 | 
						$(INSTALL_DATA) -D $< $(includedir)/$(<F)
 | 
				
			||||||
	$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_pkgconfig: libdevmapper-event.pc
 | 
					install_pkgconfig: libdevmapper-event.pc
 | 
				
			||||||
	@echo "    [INSTALL] $<"
 | 
						$(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
 | 
				
			||||||
	$(Q) $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_lib_dynamic: install_lib_shared
 | 
					install_lib_dynamic: install_lib_shared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_lib_static: $(LIB_STATIC)
 | 
					install_lib_static: $(LIB_STATIC)
 | 
				
			||||||
	@echo "    [INSTALL] $<"
 | 
						$(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
 | 
				
			||||||
	$(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_lib: $(INSTALL_LIB_TARGETS)
 | 
					install_lib: $(INSTALL_LIB_TARGETS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_dmeventd_dynamic: dmeventd
 | 
					install_dmeventd_dynamic: dmeventd
 | 
				
			||||||
	@echo "    [INSTALL] $<"
 | 
						$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
				
			||||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_dmeventd_static: dmeventd.static
 | 
					install_dmeventd_static: dmeventd.static
 | 
				
			||||||
	@echo "    [INSTALL] $<"
 | 
						$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
 | 
				
			||||||
	$(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
 | 
					install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -9,7 +9,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef __DMEVENTD_DOT_H__
 | 
					#ifndef __DMEVENTD_DOT_H__
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
 | 
					 * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This file is part of the device-mapper userspace tools.
 | 
					 * This file is part of the device-mapper userspace tools.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -9,15 +9,13 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "dmlib.h"
 | 
				
			||||||
#include "libdevmapper-event.h"
 | 
					#include "libdevmapper-event.h"
 | 
				
			||||||
 | 
					//#include "libmultilog.h"
 | 
				
			||||||
#include "dmeventd.h"
 | 
					#include "dmeventd.h"
 | 
				
			||||||
#include "libdm/misc/dm-logging.h"
 | 
					 | 
				
			||||||
#include "base/memory/zalloc.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "lib/misc/intl.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
#include <sys/file.h>
 | 
					#include <sys/file.h>
 | 
				
			||||||
@@ -25,12 +23,7 @@
 | 
				
			|||||||
#include <sys/stat.h>
 | 
					#include <sys/stat.h>
 | 
				
			||||||
#include <sys/wait.h>
 | 
					#include <sys/wait.h>
 | 
				
			||||||
#include <arpa/inet.h>		/* for htonl, ntohl */
 | 
					#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;
 | 
					 | 
				
			||||||
static int _sequence_nr = 0;
 | 
					static int _sequence_nr = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct dm_event_handler {
 | 
					struct dm_event_handler {
 | 
				
			||||||
@@ -50,8 +43,8 @@ struct dm_event_handler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
 | 
					static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	free(dmevh->dev_name);
 | 
						dm_free(dmevh->dev_name);
 | 
				
			||||||
	free(dmevh->uuid);
 | 
						dm_free(dmevh->uuid);
 | 
				
			||||||
	dmevh->dev_name = dmevh->uuid = NULL;
 | 
						dmevh->dev_name = dmevh->uuid = NULL;
 | 
				
			||||||
	dmevh->major = dmevh->minor = 0;
 | 
						dmevh->major = dmevh->minor = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -60,7 +53,7 @@ struct dm_event_handler *dm_event_handler_create(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct dm_event_handler *dmevh;
 | 
						struct dm_event_handler *dmevh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(dmevh = zalloc(sizeof(*dmevh)))) {
 | 
						if (!(dmevh = dm_zalloc(sizeof(*dmevh)))) {
 | 
				
			||||||
		log_error("Failed to allocate event handler.");
 | 
							log_error("Failed to allocate event handler.");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -71,9 +64,9 @@ struct dm_event_handler *dm_event_handler_create(void)
 | 
				
			|||||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh)
 | 
					void dm_event_handler_destroy(struct dm_event_handler *dmevh)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
						_dm_event_handler_clear_dev_info(dmevh);
 | 
				
			||||||
	free(dmevh->dso);
 | 
						dm_free(dmevh->dso);
 | 
				
			||||||
	free(dmevh->dmeventd_path);
 | 
						dm_free(dmevh->dmeventd_path);
 | 
				
			||||||
	free(dmevh);
 | 
						dm_free(dmevh);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path)
 | 
					int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path)
 | 
				
			||||||
@@ -81,9 +74,9 @@ int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const cha
 | 
				
			|||||||
	if (!dmeventd_path) /* noop */
 | 
						if (!dmeventd_path) /* noop */
 | 
				
			||||||
		return 0;
 | 
							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 -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -94,9 +87,9 @@ int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path)
 | 
				
			|||||||
	if (!path) /* noop */
 | 
						if (!path) /* noop */
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(dmevh->dso);
 | 
						dm_free(dmevh->dso);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(dmevh->dso = strdup(path)))
 | 
						if (!(dmevh->dso = dm_strdup(path)))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -109,7 +102,7 @@ int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *de
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
						_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 -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -122,7 +115,7 @@ int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
						_dm_event_handler_clear_dev_info(dmevh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(dmevh->uuid = strdup(uuid)))
 | 
						if (!(dmevh->uuid = dm_strdup(uuid)))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -201,7 +194,7 @@ static int _check_message_id(struct dm_event_daemon_message *msg)
 | 
				
			|||||||
	if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
 | 
						if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
 | 
				
			||||||
	    (pid != getpid()) || (seq_nr != _sequence_nr)) {
 | 
						    (pid != getpid()) || (seq_nr != _sequence_nr)) {
 | 
				
			||||||
		log_error("Ignoring out-of-sequence reply from dmeventd. "
 | 
							log_error("Ignoring out-of-sequence reply from dmeventd. "
 | 
				
			||||||
			  "Expected %d:%d but received %s.", getpid(),
 | 
								  "Expected %d:%d but received %s", getpid(),
 | 
				
			||||||
			  _sequence_nr, msg->data);
 | 
								  _sequence_nr, msg->data);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -236,51 +229,45 @@ static int _daemon_read(struct dm_event_fifos *fifos,
 | 
				
			|||||||
			FD_SET(fifos->server, &fds);
 | 
								FD_SET(fifos->server, &fds);
 | 
				
			||||||
			ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
 | 
								ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
 | 
				
			||||||
			if (ret < 0 && errno != EINTR) {
 | 
								if (ret < 0 && errno != EINTR) {
 | 
				
			||||||
				log_error("Unable to read from event server.");
 | 
									log_error("Unable to read from event server");
 | 
				
			||||||
				goto bad;
 | 
									return 0;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if ((ret == 0) && (i > 4) && !bytes) {
 | 
								if ((ret == 0) && (i > 4) && !bytes) {
 | 
				
			||||||
				log_error("No input from event server.");
 | 
									log_error("No input from event server.");
 | 
				
			||||||
				goto bad;
 | 
									return 0;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (ret < 1) {
 | 
							if (ret < 1) {
 | 
				
			||||||
			log_error("Unable to read from event server.");
 | 
								log_error("Unable to read from event server.");
 | 
				
			||||||
			goto bad;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = read(fifos->server, buf + bytes, size);
 | 
							ret = read(fifos->server, buf + bytes, size);
 | 
				
			||||||
		if (ret < 0) {
 | 
							if (ret < 0) {
 | 
				
			||||||
			if ((errno == EINTR) || (errno == EAGAIN))
 | 
								if ((errno == EINTR) || (errno == EAGAIN))
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
			log_error("Unable to read from event server.");
 | 
									log_error("Unable to read from event server.");
 | 
				
			||||||
			goto bad;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		bytes += ret;
 | 
					 | 
				
			||||||
		if (!msg->data && (bytes == 2 * sizeof(uint32_t))) {
 | 
					 | 
				
			||||||
			msg->cmd = ntohl(header[0]);
 | 
					 | 
				
			||||||
			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;
 | 
									return 0;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bytes += ret;
 | 
				
			||||||
 | 
							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;
 | 
				
			||||||
 | 
								header = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bytes == size)
 | 
						if (bytes != size) {
 | 
				
			||||||
		return 1;
 | 
							dm_free(msg->data);
 | 
				
			||||||
 | 
							msg->data = NULL;
 | 
				
			||||||
bad:
 | 
						}
 | 
				
			||||||
	free(msg->data);
 | 
						return bytes == size;
 | 
				
			||||||
	msg->data = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Write message to daemon. */
 | 
					/* Write message to daemon. */
 | 
				
			||||||
@@ -308,7 +295,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
 | 
				
			|||||||
		if (ret < 0) {
 | 
							if (ret < 0) {
 | 
				
			||||||
			if (errno == EINTR)
 | 
								if (errno == EINTR)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			log_error("Unable to talk to event daemon.");
 | 
								log_error("Unable to talk to event daemon");
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (ret == 0)
 | 
							if (ret == 0)
 | 
				
			||||||
@@ -317,7 +304,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
 | 
				
			|||||||
		if (ret < 0) {
 | 
							if (ret < 0) {
 | 
				
			||||||
			if ((errno == EINTR) || (errno == EAGAIN))
 | 
								if ((errno == EINTR) || (errno == EAGAIN))
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			log_error("Unable to talk to event daemon.");
 | 
								log_error("Unable to talk to event daemon");
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -329,7 +316,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
 | 
				
			|||||||
			FD_SET(fifos->client, &fds);
 | 
								FD_SET(fifos->client, &fds);
 | 
				
			||||||
			ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
 | 
								ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
 | 
				
			||||||
			if ((ret < 0) && (errno != EINTR)) {
 | 
								if ((ret < 0) && (errno != EINTR)) {
 | 
				
			||||||
				log_error("Unable to talk to event daemon.");
 | 
									log_error("Unable to talk to event daemon");
 | 
				
			||||||
				return 0;
 | 
									return 0;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} while (ret < 1);
 | 
							} while (ret < 1);
 | 
				
			||||||
@@ -338,9 +325,10 @@ static int _daemon_write(struct dm_event_fifos *fifos,
 | 
				
			|||||||
		if (ret < 0) {
 | 
							if (ret < 0) {
 | 
				
			||||||
			if ((errno == EINTR) || (errno == EAGAIN))
 | 
								if ((errno == EINTR) || (errno == EAGAIN))
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
			log_error("Unable to talk to event daemon.");
 | 
									log_error("Unable to talk to event daemon");
 | 
				
			||||||
			return 0;
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bytes += ret;
 | 
							bytes += ret;
 | 
				
			||||||
@@ -368,7 +356,7 @@ int daemon_talk(struct dm_event_fifos *fifos,
 | 
				
			|||||||
			  getpid(), _sequence_nr,
 | 
								  getpid(), _sequence_nr,
 | 
				
			||||||
			  dso_name ? : "-", dev_name ? : "-", evmask, timeout)))
 | 
								  dso_name ? : "-", dev_name ? : "-", evmask, timeout)))
 | 
				
			||||||
	    < 0) {
 | 
						    < 0) {
 | 
				
			||||||
		log_error("_daemon_talk: message allocation failed.");
 | 
							log_error("_daemon_talk: message allocation failed");
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	msg->cmd = cmd;
 | 
						msg->cmd = cmd;
 | 
				
			||||||
@@ -380,13 +368,13 @@ int daemon_talk(struct dm_event_fifos *fifos,
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (!_daemon_write(fifos, msg)) {
 | 
						if (!_daemon_write(fifos, msg)) {
 | 
				
			||||||
		stack;
 | 
							stack;
 | 
				
			||||||
		free(msg->data);
 | 
							dm_free(msg->data);
 | 
				
			||||||
		msg->data = NULL;
 | 
							msg->data = NULL;
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		free(msg->data);
 | 
							dm_free(msg->data);
 | 
				
			||||||
		msg->data = NULL;
 | 
							msg->data = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!_daemon_read(fifos, msg)) {
 | 
							if (!_daemon_read(fifos, msg)) {
 | 
				
			||||||
@@ -420,56 +408,28 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
 | 
				
			|||||||
	char default_dmeventd_path[] = DMEVENTD_PATH;
 | 
						char default_dmeventd_path[] = DMEVENTD_PATH;
 | 
				
			||||||
	char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
 | 
						char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						if (stat(fifos->client_path, &statbuf))
 | 
				
			||||||
	 * FIXME Explicitly verify the code's requirement that client_path is secure:
 | 
							goto start_server;
 | 
				
			||||||
	 * - All parent directories owned by root without group/other write access unless sticky.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If client fifo path exists, only use it if it is root-owned fifo mode 0600 */
 | 
						if (!S_ISFIFO(statbuf.st_mode)) {
 | 
				
			||||||
	if ((lstat(fifos->client_path, &statbuf) < 0)) {
 | 
							log_error("%s is not a fifo.", fifos->client_path);
 | 
				
			||||||
		if (errno == ENOENT)
 | 
					 | 
				
			||||||
			/* Jump ahead if fifo does not already exist. */
 | 
					 | 
				
			||||||
			goto start_server;
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			log_sys_error("stat", fifos->client_path);
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (!S_ISFIFO(statbuf.st_mode)) {
 | 
					 | 
				
			||||||
		log_error("%s must be a fifo.", fifos->client_path);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	} else if (statbuf.st_uid) {
 | 
					 | 
				
			||||||
		log_error("%s must be owned by uid 0.", fifos->client_path);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	} else if (statbuf.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO)) {
 | 
					 | 
				
			||||||
		log_error("%s must have mode 0600.", fifos->client_path);
 | 
					 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Anyone listening?  If not, errno will be ENXIO */
 | 
						/* Anyone listening?  If not, errno will be ENXIO */
 | 
				
			||||||
	fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
 | 
						fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
 | 
				
			||||||
	if (fifos->client >= 0) {
 | 
						if (fifos->client >= 0) {
 | 
				
			||||||
		/* Should never happen if all the above checks passed. */
 | 
					 | 
				
			||||||
		if ((fstat(fifos->client, &statbuf) < 0) ||
 | 
					 | 
				
			||||||
		    !S_ISFIFO(statbuf.st_mode) || statbuf.st_uid ||
 | 
					 | 
				
			||||||
		    (statbuf.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO))) {
 | 
					 | 
				
			||||||
			log_error("%s is no longer a secure root-owned fifo with mode 0600.", fifos->client_path);
 | 
					 | 
				
			||||||
			if (close(fifos->client))
 | 
					 | 
				
			||||||
				log_sys_debug("close", fifos->client_path);
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* server is running and listening */
 | 
							/* server is running and listening */
 | 
				
			||||||
		if (close(fifos->client))
 | 
							if (close(fifos->client))
 | 
				
			||||||
			log_sys_debug("close", fifos->client_path);
 | 
								log_sys_debug("close", fifos->client_path);
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						} else if (errno != ENXIO) {
 | 
				
			||||||
	if (errno != ENXIO && errno != ENOENT)  {
 | 
					 | 
				
			||||||
		/* problem */
 | 
							/* problem */
 | 
				
			||||||
		log_sys_error("open", fifos->client_path);
 | 
							log_sys_error("open", fifos->client_path);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
start_server:
 | 
					      start_server:
 | 
				
			||||||
	/* server is not running */
 | 
						/* server is not running */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
 | 
						if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
 | 
				
			||||||
@@ -484,11 +444,11 @@ start_server:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	else if (!pid) {
 | 
						else if (!pid) {
 | 
				
			||||||
		execvp(args[0], args);
 | 
							execvp(args[0], args);
 | 
				
			||||||
		log_error("Unable to exec dmeventd: %s.", strerror(errno));
 | 
							log_error("Unable to exec dmeventd: %s", strerror(errno));
 | 
				
			||||||
		_exit(EXIT_FAILURE);
 | 
							_exit(EXIT_FAILURE);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (waitpid(pid, &status, 0) < 0)
 | 
							if (waitpid(pid, &status, 0) < 0)
 | 
				
			||||||
			log_error("Unable to start dmeventd: %s.",
 | 
								log_error("Unable to start dmeventd: %s",
 | 
				
			||||||
				  strerror(errno));
 | 
									  strerror(errno));
 | 
				
			||||||
		else if (WEXITSTATUS(status))
 | 
							else if (WEXITSTATUS(status))
 | 
				
			||||||
			log_error("Unable to start dmeventd.");
 | 
								log_error("Unable to start dmeventd.");
 | 
				
			||||||
@@ -561,7 +521,7 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
 | 
				
			|||||||
	struct dm_info info;
 | 
						struct dm_info info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
 | 
						if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
 | 
				
			||||||
		log_error("_get_device_info: dm_task creation for info failed.");
 | 
							log_error("_get_device_info: dm_task creation for info failed");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -579,17 +539,17 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* FIXME Add name or uuid or devno to messages */
 | 
						/* FIXME Add name or uuid or devno to messages */
 | 
				
			||||||
	if (!dm_task_run(dmt)) {
 | 
						if (!dm_task_run(dmt)) {
 | 
				
			||||||
		log_error("_get_device_info: dm_task_run() failed.");
 | 
							log_error("_get_device_info: dm_task_run() failed");
 | 
				
			||||||
		goto bad;
 | 
							goto bad;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dm_task_get_info(dmt, &info)) {
 | 
						if (!dm_task_get_info(dmt, &info)) {
 | 
				
			||||||
		log_error("_get_device_info: failed to get info for device.");
 | 
							log_error("_get_device_info: failed to get info for device");
 | 
				
			||||||
		goto bad;
 | 
							goto bad;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!info.exists) {
 | 
						if (!info.exists) {
 | 
				
			||||||
		log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found.",
 | 
							log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found",
 | 
				
			||||||
			  dmevh->uuid ? : "",
 | 
								  dmevh->uuid ? : "",
 | 
				
			||||||
			  (!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "",
 | 
								  (!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "",
 | 
				
			||||||
			  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "",
 | 
								  (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "",
 | 
				
			||||||
@@ -623,18 +583,18 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!_init_client(dmeventd_path, &fifos)) {
 | 
						if (!_init_client(dmeventd_path, &fifos)) {
 | 
				
			||||||
		ret = -ESRCH;
 | 
							stack;
 | 
				
			||||||
		goto_out;
 | 
							return -ESRCH;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
 | 
						ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(msg->data);
 | 
						dm_free(msg->data);
 | 
				
			||||||
	msg->data = 0;
 | 
						msg->data = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ret)
 | 
						if (!ret)
 | 
				
			||||||
		ret = daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
 | 
							ret = daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
 | 
				
			||||||
out:
 | 
					
 | 
				
			||||||
	/* what is the opposite of init? */
 | 
						/* what is the opposite of init? */
 | 
				
			||||||
	fini_fifos(&fifos);
 | 
						fini_fifos(&fifos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -655,22 +615,21 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
 | 
				
			|||||||
	uuid = dm_task_get_uuid(dmt);
 | 
						uuid = dm_task_get_uuid(dmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!strstr(dmevh->dso, "libdevmapper-event-lvm2thin.so") &&
 | 
						if (!strstr(dmevh->dso, "libdevmapper-event-lvm2thin.so") &&
 | 
				
			||||||
	    !strstr(dmevh->dso, "libdevmapper-event-lvm2vdo.so") &&
 | 
					 | 
				
			||||||
	    !strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
 | 
						    !strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
 | 
				
			||||||
	    !strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") &&
 | 
						    !strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") &&
 | 
				
			||||||
	    !strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so"))
 | 
						    !strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so"))
 | 
				
			||||||
		log_warn("WARNING: %s: dmeventd plugins are deprecated.", dmevh->dso);
 | 
							log_warn("WARNING: %s: dmeventd plugins are deprecated", dmevh->dso);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
 | 
						if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
 | 
				
			||||||
			     dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
 | 
								     dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
 | 
				
			||||||
		log_error("%s: event registration failed: %s.",
 | 
							log_error("%s: event registration failed: %s",
 | 
				
			||||||
			  dm_task_get_name(dmt),
 | 
								  dm_task_get_name(dmt),
 | 
				
			||||||
			  msg.data ? msg.data : strerror(-err));
 | 
								  msg.data ? msg.data : strerror(-err));
 | 
				
			||||||
		ret = 0;
 | 
							ret = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(msg.data);
 | 
						dm_free(msg.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dm_task_destroy(dmt);
 | 
						dm_task_destroy(dmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -691,13 +650,13 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
 | 
						if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
 | 
				
			||||||
			    dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
 | 
								    dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
 | 
				
			||||||
		log_error("%s: event deregistration failed: %s.",
 | 
							log_error("%s: event deregistration failed: %s",
 | 
				
			||||||
			  dm_task_get_name(dmt),
 | 
								  dm_task_get_name(dmt),
 | 
				
			||||||
			  msg.data ? msg.data : strerror(-err));
 | 
								  msg.data ? msg.data : strerror(-err));
 | 
				
			||||||
		ret = 0;
 | 
							ret = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(msg.data);
 | 
						dm_free(msg.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dm_task_destroy(dmt);
 | 
						dm_task_destroy(dmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -713,7 +672,7 @@ static char *_fetch_string(char **src, const int delimiter)
 | 
				
			|||||||
	if ((p = strchr(*src, delimiter)))
 | 
						if ((p = strchr(*src, delimiter)))
 | 
				
			||||||
		*p = 0;
 | 
							*p = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((ret = strdup(*src)))
 | 
						if ((ret = dm_strdup(*src)))
 | 
				
			||||||
		*src += strlen(ret) + 1;
 | 
							*src += strlen(ret) + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (p)
 | 
						if (p)
 | 
				
			||||||
@@ -733,11 +692,11 @@ static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
 | 
				
			|||||||
	    (*dso_name = _fetch_string(&p, ' ')) &&
 | 
						    (*dso_name = _fetch_string(&p, ' ')) &&
 | 
				
			||||||
	    (*uuid = _fetch_string(&p, ' '))) {
 | 
						    (*uuid = _fetch_string(&p, ' '))) {
 | 
				
			||||||
		*evmask = atoi(p);
 | 
							*evmask = atoi(p);
 | 
				
			||||||
		free(id);
 | 
							dm_free(id);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(id);
 | 
						dm_free(id);
 | 
				
			||||||
	return -ENOMEM;
 | 
						return -ENOMEM;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -764,11 +723,11 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	uuid = dm_task_get_uuid(dmt);
 | 
						uuid = dm_task_get_uuid(dmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME Distinguish errors connecting to daemon */
 | 
						if (_do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
 | 
				
			||||||
	if ((ret = _do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
 | 
							      DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
 | 
				
			||||||
			    DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
 | 
							      &msg, dmevh->dso, uuid, dmevh->mask, 0)) {
 | 
				
			||||||
			    &msg, dmevh->dso, uuid, dmevh->mask, 0))) {
 | 
					 | 
				
			||||||
		log_debug("%s: device not registered.", dm_task_get_name(dmt));
 | 
							log_debug("%s: device not registered.", dm_task_get_name(dmt));
 | 
				
			||||||
 | 
							ret = -ENOENT;
 | 
				
			||||||
		goto fail;
 | 
							goto fail;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -779,7 +738,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 | 
				
			|||||||
	dm_task_destroy(dmt);
 | 
						dm_task_destroy(dmt);
 | 
				
			||||||
	dmt = NULL;
 | 
						dmt = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(msg.data);
 | 
						dm_free(msg.data);
 | 
				
			||||||
	msg.data = NULL;
 | 
						msg.data = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
						_dm_event_handler_clear_dev_info(dmevh);
 | 
				
			||||||
@@ -788,7 +747,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 | 
				
			|||||||
		goto fail;
 | 
							goto fail;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(dmevh->uuid = strdup(reply_uuid))) {
 | 
						if (!(dmevh->uuid = dm_strdup(reply_uuid))) {
 | 
				
			||||||
		ret = -ENOMEM;
 | 
							ret = -ENOMEM;
 | 
				
			||||||
		goto fail;
 | 
							goto fail;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -801,13 +760,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_dso(dmevh, reply_dso);
 | 
				
			||||||
	dm_event_handler_set_event_mask(dmevh, reply_mask);
 | 
						dm_event_handler_set_event_mask(dmevh, reply_mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(reply_dso);
 | 
						dm_free(reply_dso);
 | 
				
			||||||
	reply_dso = NULL;
 | 
						reply_dso = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free(reply_uuid);
 | 
						dm_free(reply_uuid);
 | 
				
			||||||
	reply_uuid = NULL;
 | 
						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;
 | 
							ret = -ENOMEM;
 | 
				
			||||||
		goto fail;
 | 
							goto fail;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -825,9 +784,9 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 | 
				
			|||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 fail:
 | 
					 fail:
 | 
				
			||||||
	free(msg.data);
 | 
						dm_free(msg.data);
 | 
				
			||||||
	free(reply_dso);
 | 
						dm_free(reply_dso);
 | 
				
			||||||
	free(reply_uuid);
 | 
						dm_free(reply_uuid);
 | 
				
			||||||
	_dm_event_handler_clear_dev_info(dmevh);
 | 
						_dm_event_handler_clear_dev_info(dmevh);
 | 
				
			||||||
	if (dmt)
 | 
						if (dmt)
 | 
				
			||||||
		dm_task_destroy(dmt);
 | 
							dm_task_destroy(dmt);
 | 
				
			||||||
@@ -864,99 +823,6 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
 | 
				
			|||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dm_event_log_set(int debug_log_level, int use_syslog)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	_debug_level = debug_log_level;
 | 
					 | 
				
			||||||
	_use_syslog = use_syslog;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void dm_event_log(const char *subsys, int level, const char *file,
 | 
					 | 
				
			||||||
		  int line, int dm_errno_or_class,
 | 
					 | 
				
			||||||
		  const char *format, va_list ap)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static int _abort_on_internal_errors = -1;
 | 
					 | 
				
			||||||
	static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
 | 
					 | 
				
			||||||
	static time_t start = 0;
 | 
					 | 
				
			||||||
	const char *indent = "";
 | 
					 | 
				
			||||||
	FILE *stream = log_stderr(level) ? stderr : stdout;
 | 
					 | 
				
			||||||
	int prio;
 | 
					 | 
				
			||||||
	time_t now;
 | 
					 | 
				
			||||||
	int log_with_debug = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (subsys[0] == '#') {
 | 
					 | 
				
			||||||
		/* Subsystems starting with '#' are logged
 | 
					 | 
				
			||||||
		 * only when debugging is enabled. */
 | 
					 | 
				
			||||||
		log_with_debug++;
 | 
					 | 
				
			||||||
		subsys++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (log_level(level)) {
 | 
					 | 
				
			||||||
	case _LOG_DEBUG:
 | 
					 | 
				
			||||||
		/* Never shown without -ddd */
 | 
					 | 
				
			||||||
		if (_debug_level < 3)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		prio = LOG_DEBUG;
 | 
					 | 
				
			||||||
		indent = "      ";
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case _LOG_INFO:
 | 
					 | 
				
			||||||
		if (log_with_debug && _debug_level < 2)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		prio = LOG_INFO;
 | 
					 | 
				
			||||||
		indent = "    ";
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case _LOG_NOTICE:
 | 
					 | 
				
			||||||
		if (log_with_debug && _debug_level < 1)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		prio = LOG_NOTICE;
 | 
					 | 
				
			||||||
		indent = "  ";
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case _LOG_WARN:
 | 
					 | 
				
			||||||
		prio = LOG_WARNING;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case _LOG_ERR:
 | 
					 | 
				
			||||||
		prio = LOG_ERR;
 | 
					 | 
				
			||||||
		stream = stderr;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		prio = LOG_CRIT;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Serialize to keep lines readable */
 | 
					 | 
				
			||||||
	pthread_mutex_lock(&_log_mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (_use_syslog) {
 | 
					 | 
				
			||||||
		vsyslog(prio, format, ap);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		now = time(NULL);
 | 
					 | 
				
			||||||
		if (!start)
 | 
					 | 
				
			||||||
			start = now;
 | 
					 | 
				
			||||||
		now -= start;
 | 
					 | 
				
			||||||
		if (_debug_level)
 | 
					 | 
				
			||||||
			fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
 | 
					 | 
				
			||||||
				(int)now / 60, (int)now % 60,
 | 
					 | 
				
			||||||
				// TODO: Maybe use shorter ID
 | 
					 | 
				
			||||||
				// ((int)(pthread_self()) >> 6) & 0xffff,
 | 
					 | 
				
			||||||
				(int)pthread_self(), subsys,
 | 
					 | 
				
			||||||
				(_debug_level > 3) ? "" : indent);
 | 
					 | 
				
			||||||
		if (_debug_level > 3)
 | 
					 | 
				
			||||||
			fprintf(stream, "%28s:%4d %s", file, line, indent);
 | 
					 | 
				
			||||||
		vfprintf(stream, _(format), ap);
 | 
					 | 
				
			||||||
		fputc('\n', stream);
 | 
					 | 
				
			||||||
		fflush(stream);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pthread_mutex_unlock(&_log_mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (_abort_on_internal_errors < 0)
 | 
					 | 
				
			||||||
		/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
 | 
					 | 
				
			||||||
		_abort_on_internal_errors =
 | 
					 | 
				
			||||||
			strcmp(getenv("DM_ABORT_ON_INTERNAL_ERRORS") ? : "0", "0");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (_abort_on_internal_errors &&
 | 
					 | 
				
			||||||
	    !strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1))
 | 
					 | 
				
			||||||
		abort();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if 0				/* left out for now */
 | 
					#if 0				/* left out for now */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *_skip_string(char *src, const int delimiter)
 | 
					static char *_skip_string(char *src, const int delimiter)
 | 
				
			||||||
@@ -990,14 +856,14 @@ int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
 | 
				
			|||||||
			     0, 0))) {
 | 
								     0, 0))) {
 | 
				
			||||||
		char *p = _skip_string(msg.data, ' ');
 | 
							char *p = _skip_string(msg.data, ' ');
 | 
				
			||||||
		if (!p) {
 | 
							if (!p) {
 | 
				
			||||||
			log_error("Malformed reply from dmeventd '%s'.",
 | 
								log_error("malformed reply from dmeventd '%s'\n",
 | 
				
			||||||
				  msg.data);
 | 
									  msg.data);
 | 
				
			||||||
			free(msg.data);
 | 
								dm_free(msg.data);
 | 
				
			||||||
			return -EIO;
 | 
								return -EIO;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		*timeout = atoi(p);
 | 
							*timeout = atoi(p);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	free(msg.data);
 | 
						dm_free(msg.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
 | 
					 * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This file is part of the device-mapper userspace tools.
 | 
					 * This file is part of the device-mapper userspace tools.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -9,7 +9,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -21,7 +21,6 @@
 | 
				
			|||||||
#ifndef LIB_DMEVENT_H
 | 
					#ifndef LIB_DMEVENT_H
 | 
				
			||||||
#define LIB_DMEVENT_H
 | 
					#define LIB_DMEVENT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdarg.h>
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -106,25 +105,6 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next);
 | 
				
			|||||||
int dm_event_register_handler(const struct dm_event_handler *dmevh);
 | 
					int dm_event_register_handler(const struct dm_event_handler *dmevh);
 | 
				
			||||||
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
 | 
					int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Set debug level for logging, and whether to log on stdout/stderr or syslog */
 | 
					 | 
				
			||||||
void dm_event_log_set(int debug_log_level, int use_syslog);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Log messages acroding to current debug level  */
 | 
					 | 
				
			||||||
__attribute__((format(printf, 6, 0)))
 | 
					 | 
				
			||||||
void dm_event_log(const char *subsys, int level, const char *file,
 | 
					 | 
				
			||||||
		  int line, int dm_errno_or_class,
 | 
					 | 
				
			||||||
		  const char *format, va_list ap);
 | 
					 | 
				
			||||||
/* Macro to route print_log do dm_event_log() */
 | 
					 | 
				
			||||||
#define DM_EVENT_LOG_FN(subsys) \
 | 
					 | 
				
			||||||
void print_log(int level, const char *file, int line, int dm_errno_or_class,\
 | 
					 | 
				
			||||||
	       const char *format, ...)\
 | 
					 | 
				
			||||||
{\
 | 
					 | 
				
			||||||
	va_list ap;\
 | 
					 | 
				
			||||||
	va_start(ap, format);\
 | 
					 | 
				
			||||||
	dm_event_log(subsys, level, file, line, dm_errno_or_class, format, ap);\
 | 
					 | 
				
			||||||
	va_end(ap);\
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
 | 
					/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
 | 
				
			||||||
   detailed descriptions. */
 | 
					   detailed descriptions. */
 | 
				
			||||||
// FIXME  misuse of bitmask as enum
 | 
					// FIXME  misuse of bitmask as enum
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,3 +8,4 @@ Description: device-mapper event library
 | 
				
			|||||||
Version: @DM_LIB_PATCHLEVEL@
 | 
					Version: @DM_LIB_PATCHLEVEL@
 | 
				
			||||||
Cflags: -I${includedir}
 | 
					Cflags: -I${includedir}
 | 
				
			||||||
Libs: -L${libdir} -ldevmapper-event
 | 
					Libs: -L${libdir} -ldevmapper-event
 | 
				
			||||||
 | 
					Requires.private: devmapper
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
 | 
					# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
 | 
				
			||||||
# Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
 | 
					# Copyright (C) 2004-2005, 2011 Red Hat, Inc. All rights reserved.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# This file is part of LVM2.
 | 
					# This file is part of LVM2.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -10,13 +10,33 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
# along with this program; if not, write to the Free Software Foundation,
 | 
					# along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
srcdir = @srcdir@
 | 
					srcdir = @srcdir@
 | 
				
			||||||
top_srcdir = @top_srcdir@
 | 
					top_srcdir = @top_srcdir@
 | 
				
			||||||
top_builddir = @top_builddir@
 | 
					top_builddir = @top_builddir@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SUBDIRS += lvm2 snapshot raid thin mirror vdo
 | 
					SUBDIRS += lvm2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifneq ("@MIRRORS@", "none")
 | 
				
			||||||
 | 
					  SUBDIRS += mirror
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifneq ("@SNAPSHOTS@", "none")
 | 
				
			||||||
 | 
					  SUBDIRS += snapshot
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifneq ("@RAID@", "none")
 | 
				
			||||||
 | 
					  SUBDIRS += raid
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifneq ("@THIN@", "none")
 | 
				
			||||||
 | 
					  SUBDIRS += thin
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(MAKECMDGOALS),distclean)
 | 
				
			||||||
 | 
					  SUBDIRS = lvm2 mirror snapshot raid thin
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include $(top_builddir)/make.tmpl
 | 
					include $(top_builddir)/make.tmpl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,4 +44,3 @@ snapshot: lvm2
 | 
				
			|||||||
mirror: lvm2
 | 
					mirror: lvm2
 | 
				
			||||||
raid: lvm2
 | 
					raid: lvm2
 | 
				
			||||||
thin: lvm2
 | 
					thin: lvm2
 | 
				
			||||||
vdo: lvm2
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,14 +9,13 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
# along with this program; if not, write to the Free Software Foundation,
 | 
					# along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
srcdir = @srcdir@
 | 
					srcdir = @srcdir@
 | 
				
			||||||
top_srcdir = @top_srcdir@
 | 
					top_srcdir = @top_srcdir@
 | 
				
			||||||
top_builddir = @top_builddir@
 | 
					top_builddir = @top_builddir@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CLDFLAGS += -L$(top_builddir)/tools
 | 
					CLDFLAGS += -L$(top_builddir)/tools
 | 
				
			||||||
LIBS += $(DMEVENT_LIBS) $(PTHREAD_LIBS) @LVM2CMD_LIB@
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
SOURCES = dmeventd_lvm.c
 | 
					SOURCES = dmeventd_lvm.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,6 +24,8 @@ LIB_VERSION = $(LIB_VERSION_LVM)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
include $(top_builddir)/make.tmpl
 | 
					include $(top_builddir)/make.tmpl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_lvm2: install_lib_shared
 | 
					install_lvm2: install_lib_shared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install: install_lvm2
 | 
					install: install_lvm2
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
 | 
					 * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This file is part of LVM2.
 | 
					 * This file is part of LVM2.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -9,15 +9,19 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lib/misc/lib.h"
 | 
					#include "lib.h"
 | 
				
			||||||
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "lvm2cmd.h"
 | 
				
			||||||
#include "dmeventd_lvm.h"
 | 
					#include "dmeventd_lvm.h"
 | 
				
			||||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
					 | 
				
			||||||
#include "tools/lvm2cmd.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pthread.h>
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					#include <syslog.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int dmeventd_debug;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * register_device() is called first and performs initialisation.
 | 
					 * register_device() is called first and performs initialisation.
 | 
				
			||||||
@@ -31,27 +35,49 @@ static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
 | 
				
			|||||||
static int _register_count = 0;
 | 
					static int _register_count = 0;
 | 
				
			||||||
static struct dm_pool *_mem_pool = NULL;
 | 
					static struct dm_pool *_mem_pool = NULL;
 | 
				
			||||||
static void *_lvm_handle = NULL;
 | 
					static void *_lvm_handle = NULL;
 | 
				
			||||||
static DM_LIST_INIT(_env_registry);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct env_data {
 | 
					 | 
				
			||||||
	struct dm_list list;
 | 
					 | 
				
			||||||
	const char *cmd;
 | 
					 | 
				
			||||||
	const char *data;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DM_EVENT_LOG_FN("#lvm")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void _lvm2_print_log(int level, const char *file, int line,
 | 
					 | 
				
			||||||
			    int dm_errno_or_class, const char *msg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	print_log(level, file, line, dm_errno_or_class, "%s", msg);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Currently only one event can be processed at a time.
 | 
					 * Currently only one event can be processed at a time.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
 | 
					static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * FIXME Do not pass things directly to syslog, rather use the existing logging
 | 
				
			||||||
 | 
					 * facilities to sort logging ... however that mechanism needs to be somehow
 | 
				
			||||||
 | 
					 * configurable and we don't have that option yet
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void _temporary_log_fn(int level,
 | 
				
			||||||
 | 
								      const char *file __attribute__((unused)),
 | 
				
			||||||
 | 
								      int line __attribute__((unused)),
 | 
				
			||||||
 | 
								      int dm_errno __attribute__((unused)),
 | 
				
			||||||
 | 
								      const char *message)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						level &= ~(_LOG_STDERR | _LOG_ONCE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (level) {
 | 
				
			||||||
 | 
						case _LOG_DEBUG:
 | 
				
			||||||
 | 
							if (dmeventd_debug >= 3)
 | 
				
			||||||
 | 
								syslog(LOG_DEBUG, "%s", message);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case _LOG_INFO:
 | 
				
			||||||
 | 
							if (dmeventd_debug >= 2)
 | 
				
			||||||
 | 
								syslog(LOG_INFO, "%s", message);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case _LOG_NOTICE:
 | 
				
			||||||
 | 
							if (dmeventd_debug >= 1)
 | 
				
			||||||
 | 
								syslog(LOG_NOTICE, "%s", message);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case _LOG_WARN:
 | 
				
			||||||
 | 
							syslog(LOG_WARNING, "%s", message);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case _LOG_ERR:
 | 
				
			||||||
 | 
							syslog(LOG_ERR, "%s", message);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							syslog(LOG_CRIT, "%s", message);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dmeventd_lvm2_lock(void)
 | 
					void dmeventd_lvm2_lock(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pthread_mutex_lock(&_event_mutex);
 | 
						pthread_mutex_lock(&_event_mutex);
 | 
				
			||||||
@@ -68,26 +94,24 @@ int dmeventd_lvm2_init(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_lock(&_register_mutex);
 | 
						pthread_mutex_lock(&_register_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Need some space for allocations.  1024 should be more
 | 
				
			||||||
 | 
						 * than enough for what we need (device mapper name splitting)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!_lvm_handle) {
 | 
						if (!_lvm_handle) {
 | 
				
			||||||
		lvm2_log_fn(_lvm2_print_log);
 | 
							if (!getenv("LVM_LOG_FILE_EPOCH"))
 | 
				
			||||||
 | 
								lvm2_log_fn(_temporary_log_fn);
 | 
				
			||||||
		if (!(_lvm_handle = lvm2_init()))
 | 
							if (!(_lvm_handle = lvm2_init())) {
 | 
				
			||||||
			goto out;
 | 
								dm_pool_destroy(_mem_pool);
 | 
				
			||||||
 | 
								_mem_pool = NULL;
 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * Need some space for allocations.  1024 should be more
 | 
					 | 
				
			||||||
		 * than enough for what we need (device mapper name splitting)
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024))) {
 | 
					 | 
				
			||||||
			lvm2_exit(_lvm_handle);
 | 
					 | 
				
			||||||
			_lvm_handle = NULL;
 | 
					 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		lvm2_disable_dmeventd_monitoring(_lvm_handle);
 | 
							lvm2_disable_dmeventd_monitoring(_lvm_handle);
 | 
				
			||||||
		/* FIXME Temporary: move to dmeventd core */
 | 
							/* FIXME Temporary: move to dmeventd core */
 | 
				
			||||||
		lvm2_run(_lvm_handle, "_memlock_inc");
 | 
							lvm2_run(_lvm_handle, "_memlock_inc");
 | 
				
			||||||
		log_debug("lvm plugin initilized.");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_register_count++;
 | 
						_register_count++;
 | 
				
			||||||
@@ -103,14 +127,11 @@ void dmeventd_lvm2_exit(void)
 | 
				
			|||||||
	pthread_mutex_lock(&_register_mutex);
 | 
						pthread_mutex_lock(&_register_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!--_register_count) {
 | 
						if (!--_register_count) {
 | 
				
			||||||
		log_debug("lvm plugin shuting down.");
 | 
					 | 
				
			||||||
		lvm2_run(_lvm_handle, "_memlock_dec");
 | 
							lvm2_run(_lvm_handle, "_memlock_dec");
 | 
				
			||||||
		dm_pool_destroy(_mem_pool);
 | 
							dm_pool_destroy(_mem_pool);
 | 
				
			||||||
		_mem_pool = NULL;
 | 
							_mem_pool = NULL;
 | 
				
			||||||
		dm_list_init(&_env_registry);
 | 
					 | 
				
			||||||
		lvm2_exit(_lvm_handle);
 | 
							lvm2_exit(_lvm_handle);
 | 
				
			||||||
		_lvm_handle = NULL;
 | 
							_lvm_handle = NULL;
 | 
				
			||||||
		log_debug("lvm plugin exited.");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pthread_mutex_unlock(&_register_mutex);
 | 
						pthread_mutex_unlock(&_register_mutex);
 | 
				
			||||||
@@ -129,15 +150,12 @@ int dmeventd_lvm2_run(const char *cmdline)
 | 
				
			|||||||
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
 | 
					int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
 | 
				
			||||||
			  const char *cmd, const char *device)
 | 
								  const char *cmd, const char *device)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static char _internal_prefix[] =  "_dmeventd_";
 | 
					 | 
				
			||||||
	char *vg = NULL, *lv = NULL, *layer;
 | 
						char *vg = NULL, *lv = NULL, *layer;
 | 
				
			||||||
	int r;
 | 
						int r;
 | 
				
			||||||
	struct env_data *env_data;
 | 
					 | 
				
			||||||
	const char *env = NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
 | 
						if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
 | 
				
			||||||
		log_error("Unable to determine VG name from %s.",
 | 
							syslog(LOG_ERR, "Unable to determine VG name from %s.\n",
 | 
				
			||||||
			  device);
 | 
							       device);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -146,45 +164,12 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
 | 
				
			|||||||
	    (layer = strstr(lv, "_mlog")))
 | 
						    (layer = strstr(lv, "_mlog")))
 | 
				
			||||||
		*layer = '\0';
 | 
							*layer = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!strncmp(cmd, _internal_prefix, sizeof(_internal_prefix) - 1)) {
 | 
					 | 
				
			||||||
		/* check if ENVVAR wasn't already resolved */
 | 
					 | 
				
			||||||
		dm_list_iterate_items(env_data, &_env_registry)
 | 
					 | 
				
			||||||
			if (!strcmp(cmd, env_data->cmd)) {
 | 
					 | 
				
			||||||
				env = env_data->data;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!env) {
 | 
					 | 
				
			||||||
			/* run lvm2 command to find out setting value */
 | 
					 | 
				
			||||||
			dmeventd_lvm2_lock();
 | 
					 | 
				
			||||||
			if (!dmeventd_lvm2_run(cmd) ||
 | 
					 | 
				
			||||||
			    !(env = getenv(cmd))) {
 | 
					 | 
				
			||||||
				dmeventd_lvm2_unlock();
 | 
					 | 
				
			||||||
				log_error("Unable to find configured command.");
 | 
					 | 
				
			||||||
				return 0;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			/* output of internal command passed via env var */
 | 
					 | 
				
			||||||
			env = dm_pool_strdup(_mem_pool, env); /* copy with lock */
 | 
					 | 
				
			||||||
			dmeventd_lvm2_unlock();
 | 
					 | 
				
			||||||
			if (!env ||
 | 
					 | 
				
			||||||
			    !(env_data = dm_pool_zalloc(_mem_pool, sizeof(*env_data))) ||
 | 
					 | 
				
			||||||
			    !(env_data->cmd = dm_pool_strdup(_mem_pool, cmd))) {
 | 
					 | 
				
			||||||
				log_error("Unable to allocate env memory.");
 | 
					 | 
				
			||||||
				return 0;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			env_data->data = env;
 | 
					 | 
				
			||||||
			/* add to ENVVAR registry */
 | 
					 | 
				
			||||||
			dm_list_add(&_env_registry, &env_data->list);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		cmd = env;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv);
 | 
						r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dm_pool_free(mem, vg);
 | 
						dm_pool_free(mem, vg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (r < 0) {
 | 
						if (r < 0) {
 | 
				
			||||||
		log_error("Unable to form LVM command. (too long).");
 | 
							syslog(LOG_ERR, "Unable to form LVM command. (too long).\n");
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
 | 
					 * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This file is part of LVM2.
 | 
					 * This file is part of LVM2.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -9,7 +9,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -39,36 +39,4 @@ struct dm_pool *dmeventd_lvm2_pool(void);
 | 
				
			|||||||
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
 | 
					int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
 | 
				
			||||||
			  const char *cmd, const char *device);
 | 
								  const char *cmd, const char *device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define dmeventd_lvm2_run_with_lock(cmdline) \
 | 
					 | 
				
			||||||
	({\
 | 
					 | 
				
			||||||
		int rc;\
 | 
					 | 
				
			||||||
		dmeventd_lvm2_lock();\
 | 
					 | 
				
			||||||
		rc = dmeventd_lvm2_run(cmdline);\
 | 
					 | 
				
			||||||
		dmeventd_lvm2_unlock();\
 | 
					 | 
				
			||||||
		rc;\
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define dmeventd_lvm2_init_with_pool(name, st) \
 | 
					 | 
				
			||||||
	({\
 | 
					 | 
				
			||||||
		struct dm_pool *mem;\
 | 
					 | 
				
			||||||
		st = NULL;\
 | 
					 | 
				
			||||||
		if (dmeventd_lvm2_init()) {\
 | 
					 | 
				
			||||||
			if ((mem = dm_pool_create(name, 2048)) &&\
 | 
					 | 
				
			||||||
			    (st = dm_pool_zalloc(mem, sizeof(*st))))\
 | 
					 | 
				
			||||||
				st->mem = mem;\
 | 
					 | 
				
			||||||
			else {\
 | 
					 | 
				
			||||||
				if (mem)\
 | 
					 | 
				
			||||||
					dm_pool_destroy(mem);\
 | 
					 | 
				
			||||||
				dmeventd_lvm2_exit();\
 | 
					 | 
				
			||||||
			}\
 | 
					 | 
				
			||||||
		}\
 | 
					 | 
				
			||||||
		st;\
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define dmeventd_lvm2_exit_with_pool(pool) \
 | 
					 | 
				
			||||||
	do {\
 | 
					 | 
				
			||||||
		dm_pool_destroy(pool->mem);\
 | 
					 | 
				
			||||||
		dmeventd_lvm2_exit();\
 | 
					 | 
				
			||||||
	} while(0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* _DMEVENTD_LVMWRAP_H */
 | 
					#endif /* _DMEVENTD_LVMWRAP_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,14 +10,14 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
# along with this program; if not, write to the Free Software Foundation,
 | 
					# along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
srcdir = @srcdir@
 | 
					srcdir = @srcdir@
 | 
				
			||||||
top_srcdir = @top_srcdir@
 | 
					top_srcdir = @top_srcdir@
 | 
				
			||||||
top_builddir = @top_builddir@
 | 
					top_builddir = @top_builddir@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
				
			||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
					CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
				
			||||||
LIBS += -ldevmapper-event-lvm2
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
SOURCES = dmeventd_mirror.c
 | 
					SOURCES = dmeventd_mirror.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,6 +30,8 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
include $(top_builddir)/make.tmpl
 | 
					include $(top_builddir)/make.tmpl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_lvm2: install_dm_plugin
 | 
					install_lvm2: install_dm_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install: install_lvm2
 | 
					install: install_lvm2
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (C) 2005-2017 Red Hat, Inc. All rights reserved.
 | 
					 * Copyright (C) 2005-2012 Red Hat, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This file is part of LVM2.
 | 
					 * This file is part of LVM2.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -9,30 +9,26 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lib/misc/lib.h"
 | 
					#include "lib.h"
 | 
				
			||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
 | 
					 | 
				
			||||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
					 | 
				
			||||||
#include "lib/activate/activate.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libdevmapper-event.h"
 | 
				
			||||||
 | 
					#include "dmeventd_lvm.h"
 | 
				
			||||||
 | 
					#include "defaults.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <syslog.h> /* FIXME Replace syslog with multilog */
 | 
				
			||||||
 | 
					/* FIXME Missing openlog? */
 | 
				
			||||||
 | 
					/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
 | 
				
			||||||
/* FIXME Reformat to 80 char lines. */
 | 
					/* FIXME Reformat to 80 char lines. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ME_IGNORE    0
 | 
					#define ME_IGNORE    0
 | 
				
			||||||
#define ME_INSYNC    1
 | 
					#define ME_INSYNC    1
 | 
				
			||||||
#define ME_FAILURE   2
 | 
					#define ME_FAILURE   2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct dso_state {
 | 
					static int _process_status_code(const char status_code, const char *dev_name,
 | 
				
			||||||
	struct dm_pool *mem;
 | 
									const char *dev_type, int r)
 | 
				
			||||||
	char cmd_lvconvert[512];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DM_EVENT_LOG_FN("mirr")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void _process_status_code(dm_status_mirror_health_t health,
 | 
					 | 
				
			||||||
				 uint32_t major, uint32_t minor,
 | 
					 | 
				
			||||||
				 const char *dev_type, int *r)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 *    A => Alive - No failures
 | 
						 *    A => Alive - No failures
 | 
				
			||||||
@@ -42,170 +38,206 @@ static void _process_status_code(dm_status_mirror_health_t health,
 | 
				
			|||||||
	 *    R => Read - A read failure occurred, mirror data unaffected
 | 
						 *    R => Read - A read failure occurred, mirror data unaffected
 | 
				
			||||||
	 *    U => Unclassified failure (bug)
 | 
						 *    U => Unclassified failure (bug)
 | 
				
			||||||
	 */ 
 | 
						 */ 
 | 
				
			||||||
	switch (health) {
 | 
						if (status_code == 'F') {
 | 
				
			||||||
	case DM_STATUS_MIRROR_ALIVE:
 | 
							syslog(LOG_ERR, "%s device %s flush failed.",
 | 
				
			||||||
		return;
 | 
							       dev_type, dev_name);
 | 
				
			||||||
	case DM_STATUS_MIRROR_FLUSH_FAILED:
 | 
							r = ME_FAILURE;
 | 
				
			||||||
		log_error("%s device %u:%u flush failed.",
 | 
						} else if (status_code == 'S')
 | 
				
			||||||
			  dev_type, major, minor);
 | 
							syslog(LOG_ERR, "%s device %s sync failed.",
 | 
				
			||||||
		*r = ME_FAILURE;
 | 
							       dev_type, dev_name);
 | 
				
			||||||
		break;
 | 
						else if (status_code == 'R')
 | 
				
			||||||
	case DM_STATUS_MIRROR_SYNC_FAILED:
 | 
							syslog(LOG_ERR, "%s device %s read failed.",
 | 
				
			||||||
		log_error("%s device %u:%u sync failed.",
 | 
							       dev_type, dev_name);
 | 
				
			||||||
			  dev_type, major, minor);
 | 
						else if (status_code != 'A') {
 | 
				
			||||||
		break;
 | 
							syslog(LOG_ERR, "%s device %s has failed (%c).",
 | 
				
			||||||
	case DM_STATUS_MIRROR_READ_FAILED:
 | 
							       dev_type, dev_name, status_code);
 | 
				
			||||||
		log_error("%s device %u:%u read failed.",
 | 
							r = ME_FAILURE;
 | 
				
			||||||
			  dev_type, major, minor);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		log_error("%s device %u:%u has failed (%c).",
 | 
					 | 
				
			||||||
			  dev_type, major, minor, (char)health);
 | 
					 | 
				
			||||||
		*r = ME_FAILURE;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int _get_mirror_event(struct dso_state *state, char *params)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int r = ME_INSYNC;
 | 
					 | 
				
			||||||
	unsigned i;
 | 
					 | 
				
			||||||
	struct dm_status_mirror *ms;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!dm_get_status_mirror(state->mem, params, &ms)) {
 | 
					 | 
				
			||||||
		log_error("Unable to parse mirror status string.");
 | 
					 | 
				
			||||||
		return ME_IGNORE;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Check for bad mirror devices */
 | 
					 | 
				
			||||||
	for (i = 0; i < ms->dev_count; ++i)
 | 
					 | 
				
			||||||
		_process_status_code(ms->devs[i].health,
 | 
					 | 
				
			||||||
				     ms->devs[i].major, ms->devs[i].minor,
 | 
					 | 
				
			||||||
				     i ? "Secondary mirror" : "Primary mirror", &r);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Check for bad disk log device */
 | 
					 | 
				
			||||||
	for (i = 0; i < ms->log_count; ++i)
 | 
					 | 
				
			||||||
		_process_status_code(ms->logs[i].health,
 | 
					 | 
				
			||||||
				     ms->logs[i].major, ms->logs[i].minor,
 | 
					 | 
				
			||||||
				     "Log", &r);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Ignore if not in-sync */
 | 
					 | 
				
			||||||
	if ((r == ME_INSYNC) && (ms->insync_regions != ms->total_regions))
 | 
					 | 
				
			||||||
		r = ME_IGNORE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dm_pool_free(state->mem, ms);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return r;
 | 
						return r;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int _remove_failed_devices(const char *cmd_lvconvert, const char *device)
 | 
					static int _get_mirror_event(char *params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						int i, r = ME_INSYNC;
 | 
				
			||||||
 | 
						char **args = NULL;
 | 
				
			||||||
 | 
						char *dev_status_str;
 | 
				
			||||||
 | 
						char *log_status_str;
 | 
				
			||||||
 | 
						char *sync_str;
 | 
				
			||||||
 | 
						char *p = NULL;
 | 
				
			||||||
 | 
						int log_argc, num_devs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * dm core parms:	     0 409600 mirror
 | 
				
			||||||
 | 
						 * Mirror core parms:	     2 253:4 253:5 400/400
 | 
				
			||||||
 | 
						 * New-style failure params: 1 AA
 | 
				
			||||||
 | 
						 * New-style log params:     3 cluster 253:3 A
 | 
				
			||||||
 | 
						 *			 or  3 disk 253:3 A
 | 
				
			||||||
 | 
						 *			 or  1 core
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* number of devices */
 | 
				
			||||||
 | 
						if (!dm_split_words(params, 1, 0, &p))
 | 
				
			||||||
 | 
							goto out_parse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(num_devs = atoi(p)) ||
 | 
				
			||||||
 | 
						    (num_devs > DEFAULT_MIRROR_MAX_IMAGES) || (num_devs < 0))
 | 
				
			||||||
 | 
							goto out_parse;
 | 
				
			||||||
 | 
						p += strlen(p) + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
 | 
				
			||||||
 | 
						args = dm_malloc((num_devs + 7) * sizeof(char *));
 | 
				
			||||||
 | 
						if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
 | 
				
			||||||
 | 
							goto out_parse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* FIXME: Code differs from lib/mirror/mirrored.c */
 | 
				
			||||||
 | 
						dev_status_str = args[2 + num_devs];
 | 
				
			||||||
 | 
						log_argc = atoi(args[3 + num_devs]);
 | 
				
			||||||
 | 
						log_status_str = args[3 + num_devs + log_argc];
 | 
				
			||||||
 | 
						sync_str = args[num_devs];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check for bad mirror devices */
 | 
				
			||||||
 | 
						for (i = 0; i < num_devs; i++)
 | 
				
			||||||
 | 
							r = _process_status_code(dev_status_str[i], args[i],
 | 
				
			||||||
 | 
								i ? "Secondary mirror" : "Primary mirror", r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check for bad disk log device */
 | 
				
			||||||
 | 
						if (log_argc > 1)
 | 
				
			||||||
 | 
							r = _process_status_code(log_status_str[0],
 | 
				
			||||||
 | 
										 args[2 + num_devs + log_argc],
 | 
				
			||||||
 | 
										 "Log", r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (r == ME_FAILURE)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p = strstr(sync_str, "/");
 | 
				
			||||||
 | 
						if (p) {
 | 
				
			||||||
 | 
							p[0] = '\0';
 | 
				
			||||||
 | 
							if (strcmp(sync_str, p+1))
 | 
				
			||||||
 | 
								r = ME_IGNORE;
 | 
				
			||||||
 | 
							p[0] = '/';
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							goto out_parse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						dm_free(args);
 | 
				
			||||||
 | 
						return r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_parse:
 | 
				
			||||||
 | 
						dm_free(args);
 | 
				
			||||||
 | 
						syslog(LOG_ERR, "Unable to parse mirror status string.");
 | 
				
			||||||
 | 
						return ME_IGNORE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int _remove_failed_devices(const char *device)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int r;
 | 
				
			||||||
 | 
					#define CMD_SIZE 256	/* FIXME Use system restriction */
 | 
				
			||||||
 | 
						char cmd_str[CMD_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
 | 
				
			||||||
 | 
									   "lvscan --cache", device))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r = dmeventd_lvm2_run(cmd_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!r)
 | 
				
			||||||
 | 
							syslog(LOG_INFO, "Re-scan of mirror device %s failed.", device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
 | 
				
			||||||
 | 
									  "lvconvert --config devices{ignore_suspended_devices=1} "
 | 
				
			||||||
 | 
									  "--repair --use-policies", device))
 | 
				
			||||||
 | 
							return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* if repair goes OK, report success even if lvscan has failed */
 | 
						/* if repair goes OK, report success even if lvscan has failed */
 | 
				
			||||||
	if (!dmeventd_lvm2_run_with_lock(cmd_lvconvert)) {
 | 
						r = dmeventd_lvm2_run(cmd_str);
 | 
				
			||||||
		log_error("Repair of mirrored device %s failed.", device);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log_info("Repair of mirrored device %s finished successfully.", device);
 | 
						syslog(LOG_INFO, "Repair of mirrored device %s %s.", device,
 | 
				
			||||||
 | 
						       (r) ? "finished successfully" : "failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return (r) ? 0 : -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void process_event(struct dm_task *dmt,
 | 
					void process_event(struct dm_task *dmt,
 | 
				
			||||||
		   enum dm_event_mask event __attribute__((unused)),
 | 
							   enum dm_event_mask event __attribute__((unused)),
 | 
				
			||||||
		   void **user)
 | 
							   void **unused __attribute__((unused)))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dso_state *state = *user;
 | 
					 | 
				
			||||||
	void *next = NULL;
 | 
						void *next = NULL;
 | 
				
			||||||
	uint64_t start, length;
 | 
						uint64_t start, length;
 | 
				
			||||||
	char *target_type = NULL;
 | 
						char *target_type = NULL;
 | 
				
			||||||
	char *params;
 | 
						char *params;
 | 
				
			||||||
	const char *device = dm_task_get_name(dmt);
 | 
						const char *device = dm_task_get_name(dmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dmeventd_lvm2_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		next = dm_get_next_target(dmt, next, &start, &length,
 | 
							next = dm_get_next_target(dmt, next, &start, &length,
 | 
				
			||||||
					  &target_type, ¶ms);
 | 
										  &target_type, ¶ms);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!target_type) {
 | 
							if (!target_type) {
 | 
				
			||||||
			log_info("%s mapping lost.", device);
 | 
								syslog(LOG_INFO, "%s mapping lost.", device);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (strcmp(target_type, TARGET_NAME_MIRROR)) {
 | 
							if (strcmp(target_type, "mirror")) {
 | 
				
			||||||
			log_info("%s has unmirrored portion.", device);
 | 
								syslog(LOG_INFO, "%s has unmirrored portion.", device);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch(_get_mirror_event(state, params)) {
 | 
							switch(_get_mirror_event(params)) {
 | 
				
			||||||
		case ME_INSYNC:
 | 
							case ME_INSYNC:
 | 
				
			||||||
			/* FIXME: all we really know is that this
 | 
								/* FIXME: all we really know is that this
 | 
				
			||||||
			   _part_ of the device is in sync
 | 
								   _part_ of the device is in sync
 | 
				
			||||||
			   Also, this is not an error
 | 
								   Also, this is not an error
 | 
				
			||||||
			*/
 | 
								*/
 | 
				
			||||||
			log_notice("%s is now in-sync.", device);
 | 
								syslog(LOG_NOTICE, "%s is now in-sync.", device);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case ME_FAILURE:
 | 
							case ME_FAILURE:
 | 
				
			||||||
			log_error("Device failure in %s.", device);
 | 
								syslog(LOG_ERR, "Device failure in %s.", device);
 | 
				
			||||||
			if (!_remove_failed_devices(state->cmd_lvconvert, device))
 | 
								if (_remove_failed_devices(device))
 | 
				
			||||||
				/* FIXME Why are all the error return codes unused? Get rid of them? */
 | 
									/* FIXME Why are all the error return codes unused? Get rid of them? */
 | 
				
			||||||
				log_error("Failed to remove faulty devices in %s.",
 | 
									syslog(LOG_ERR, "Failed to remove faulty devices in %s.",
 | 
				
			||||||
					  device);
 | 
									       device);
 | 
				
			||||||
			/* Should check before warning user that device is now linear
 | 
								/* Should check before warning user that device is now linear
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				log_notice("%s is now a linear device.",
 | 
									syslog(LOG_NOTICE, "%s is now a linear device.\n",
 | 
				
			||||||
					   device);
 | 
										device);
 | 
				
			||||||
			*/
 | 
								*/
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case ME_IGNORE:
 | 
							case ME_IGNORE:
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			/* FIXME Provide value then! */
 | 
								/* FIXME Provide value then! */
 | 
				
			||||||
			log_warn("WARNING: %s received unknown event.", device);
 | 
								syslog(LOG_INFO, "Unknown event received.");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} while (next);
 | 
						} while (next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dmeventd_lvm2_unlock();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int register_device(const char *device,
 | 
					int register_device(const char *device,
 | 
				
			||||||
		    const char *uuid __attribute__((unused)),
 | 
							    const char *uuid __attribute__((unused)),
 | 
				
			||||||
		    int major __attribute__((unused)),
 | 
							    int major __attribute__((unused)),
 | 
				
			||||||
		    int minor __attribute__((unused)),
 | 
							    int minor __attribute__((unused)),
 | 
				
			||||||
		    void **user)
 | 
							    void **unused __attribute__((unused)))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dso_state *state;
 | 
						if (!dmeventd_lvm2_init())
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dmeventd_lvm2_init_with_pool("mirror_state", state))
 | 
						syslog(LOG_INFO, "Monitoring mirror device %s for events.", device);
 | 
				
			||||||
		goto_bad;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* CANNOT use --config as this disables cached content */
 | 
					 | 
				
			||||||
	if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
 | 
					 | 
				
			||||||
				   "lvconvert --repair --use-policies", device))
 | 
					 | 
				
			||||||
		goto_bad;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	*user = state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	log_info("Monitoring mirror device %s for events.", device);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
bad:
 | 
					 | 
				
			||||||
	log_error("Failed to monitor mirror %s.", device);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state)
 | 
					 | 
				
			||||||
		dmeventd_lvm2_exit_with_pool(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int unregister_device(const char *device,
 | 
					int unregister_device(const char *device,
 | 
				
			||||||
		      const char *uuid __attribute__((unused)),
 | 
							      const char *uuid __attribute__((unused)),
 | 
				
			||||||
		      int major __attribute__((unused)),
 | 
							      int major __attribute__((unused)),
 | 
				
			||||||
		      int minor __attribute__((unused)),
 | 
							      int minor __attribute__((unused)),
 | 
				
			||||||
		      void **user)
 | 
							      void **unused __attribute__((unused)))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dso_state *state = *user;
 | 
						syslog(LOG_INFO, "No longer monitoring mirror device %s for events.",
 | 
				
			||||||
 | 
						       device);
 | 
				
			||||||
	dmeventd_lvm2_exit_with_pool(state);
 | 
						dmeventd_lvm2_exit();
 | 
				
			||||||
	log_info("No longer monitoring mirror device %s for events.",
 | 
					 | 
				
			||||||
		 device);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,14 +9,14 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
# along with this program; if not, write to the Free Software Foundation,
 | 
					# along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
srcdir = @srcdir@
 | 
					srcdir = @srcdir@
 | 
				
			||||||
top_srcdir = @top_srcdir@
 | 
					top_srcdir = @top_srcdir@
 | 
				
			||||||
top_builddir = @top_builddir@
 | 
					top_builddir = @top_builddir@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
				
			||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
					CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
				
			||||||
LIBS += -ldevmapper-event-lvm2
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
SOURCES = dmeventd_raid.c
 | 
					SOURCES = dmeventd_raid.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,6 +29,8 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
include $(top_builddir)/make.tmpl
 | 
					include $(top_builddir)/make.tmpl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_lvm2: install_dm_plugin
 | 
					install_lvm2: install_dm_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install: install_lvm2
 | 
					install: install_lvm2
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (C) 2005-2017 Red Hat, Inc. All rights reserved.
 | 
					 * Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This file is part of LVM2.
 | 
					 * This file is part of LVM2.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -9,181 +9,172 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lib/misc/lib.h"
 | 
					#include "lib.h"
 | 
				
			||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
 | 
					 | 
				
			||||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
					 | 
				
			||||||
#include "lib/config/defaults.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Hold enough elements for the mximum number of RAID images */
 | 
					#include "libdevmapper-event.h"
 | 
				
			||||||
#define	RAID_DEVS_ELEMS	((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
 | 
					#include "dmeventd_lvm.h"
 | 
				
			||||||
 | 
					 | 
				
			||||||
struct dso_state {
 | 
					 | 
				
			||||||
	struct dm_pool *mem;
 | 
					 | 
				
			||||||
	char cmd_lvconvert[512];
 | 
					 | 
				
			||||||
	uint64_t raid_devs[RAID_DEVS_ELEMS];
 | 
					 | 
				
			||||||
	int failed;
 | 
					 | 
				
			||||||
	int warned;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DM_EVENT_LOG_FN("raid")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <syslog.h> /* FIXME Replace syslog with multilog */
 | 
				
			||||||
 | 
					/* FIXME Missing openlog? */
 | 
				
			||||||
 | 
					/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
 | 
				
			||||||
/* FIXME Reformat to 80 char lines. */
 | 
					/* FIXME Reformat to 80 char lines. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int _process_raid_event(struct dso_state *state, char *params, const char *device)
 | 
					/*
 | 
				
			||||||
 | 
					 * run_repair is a close copy to
 | 
				
			||||||
 | 
					 * plugins/mirror/dmeventd_mirror.c:_remove_failed_devices()
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int run_repair(const char *device)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dm_status_raid *status;
 | 
						int r;
 | 
				
			||||||
	const char *d;
 | 
					#define CMD_SIZE 256	/* FIXME Use system restriction */
 | 
				
			||||||
	int dead = 0, r = 1;
 | 
						char cmd_str[CMD_SIZE];
 | 
				
			||||||
	uint32_t dev;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dm_get_status_raid(state->mem, params, &status)) {
 | 
						if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
 | 
				
			||||||
		log_error("Failed to process status line for %s.", device);
 | 
									  "lvscan --cache", device))
 | 
				
			||||||
		return 0;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	d = status->dev_health;
 | 
						r = dmeventd_lvm2_run(cmd_str);
 | 
				
			||||||
	while ((d = strchr(d, 'D'))) {
 | 
					 | 
				
			||||||
		dev = (uint32_t)(d - status->dev_health);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!(state->raid_devs[dev / 64] & (UINT64_C(1) << (dev % 64)))) {
 | 
						if (!r)
 | 
				
			||||||
			state->raid_devs[dev / 64] |= (UINT64_C(1) << (dev % 64));
 | 
							syslog(LOG_INFO, "Re-scan of RAID device %s failed.", device);
 | 
				
			||||||
			log_warn("WARNING: Device #%u of %s array, %s, has failed.",
 | 
					 | 
				
			||||||
				 dev, status->raid_type, device);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		d++;
 | 
						if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
 | 
				
			||||||
		dead = 1;
 | 
									  "lvconvert --config devices{ignore_suspended_devices=1} "
 | 
				
			||||||
	}
 | 
									  "--repair --use-policies", device))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* if repair goes OK, report success even if lvscan has failed */
 | 
				
			||||||
 | 
						r = dmeventd_lvm2_run(cmd_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!r)
 | 
				
			||||||
 | 
							syslog(LOG_INFO, "Repair of RAID device %s failed.", device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (r) ? 0 : -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int _process_raid_event(char *params, const char *device)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i, n, failure = 0;
 | 
				
			||||||
 | 
						char *p, *a[4];
 | 
				
			||||||
 | 
						char *raid_type;
 | 
				
			||||||
 | 
						char *num_devices;
 | 
				
			||||||
 | 
						char *health_chars;
 | 
				
			||||||
 | 
						char *resync_ratio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * if we are converting from non-RAID to RAID (e.g. linear -> raid1)
 | 
						 * RAID parms:     <raid_type> <#raid_disks> \
 | 
				
			||||||
	 * and too many original devices die, such that we cannot continue
 | 
						 *                 <health chars> <resync ratio>
 | 
				
			||||||
	 * the "recover" operation, the sync action will go to "idle", the
 | 
					 | 
				
			||||||
	 * unsynced devs will remain at 'a', and the original devices will
 | 
					 | 
				
			||||||
	 * NOT SWITCH TO 'D', but will remain at 'A' - hoping to be revived.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * This is simply the way the kernel works...
 | 
					 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (!strcmp(status->sync_action, "idle") &&
 | 
						if (!dm_split_words(params, 4, 0, a)) {
 | 
				
			||||||
	    (status->dev_health[0] == 'a') &&
 | 
							syslog(LOG_ERR, "Failed to process status line for %s\n",
 | 
				
			||||||
	    (status->insync_regions < status->total_regions)) {
 | 
							       device);
 | 
				
			||||||
		log_error("Primary sources for new RAID, %s, have failed.",
 | 
							return -EINVAL;
 | 
				
			||||||
			  device);
 | 
						}
 | 
				
			||||||
		dead = 1; /* run it through LVM repair */
 | 
						raid_type = a[0];
 | 
				
			||||||
 | 
						num_devices = a[1];
 | 
				
			||||||
 | 
						health_chars = a[2];
 | 
				
			||||||
 | 
						resync_ratio = a[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(n = atoi(num_devices))) {
 | 
				
			||||||
 | 
							syslog(LOG_ERR, "Failed to parse number of devices for %s: %s",
 | 
				
			||||||
 | 
							       device, num_devices);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dead) {
 | 
						for (i = 0; i < n; i++) {
 | 
				
			||||||
		/*
 | 
							switch (health_chars[i]) {
 | 
				
			||||||
		 * Use the first event to run a repair ignoring any additonal ones.
 | 
							case 'A':
 | 
				
			||||||
		 *
 | 
								/* Device is 'A'live and well */
 | 
				
			||||||
		 * We presume lvconvert to do pre-repair
 | 
							case 'a':
 | 
				
			||||||
		 * checks to avoid bloat in this plugin.
 | 
								/* Device is 'a'live, but not yet in-sync */
 | 
				
			||||||
		 */
 | 
								break;
 | 
				
			||||||
		if (!state->warned && status->insync_regions < status->total_regions) {
 | 
							case 'D':
 | 
				
			||||||
			state->warned = 1;
 | 
								syslog(LOG_ERR,
 | 
				
			||||||
			log_warn("WARNING: waiting for resynchronization to finish "
 | 
								       "Device #%d of %s array, %s, has failed.",
 | 
				
			||||||
				 "before initiating repair on RAID device %s.", device);
 | 
								       i, raid_type, device);
 | 
				
			||||||
			/* Fall through to allow lvconvert to run. */
 | 
								failure++;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								/* Unhandled character returned from kernel */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (failure)
 | 
				
			||||||
		if (state->failed)
 | 
								return run_repair(device);
 | 
				
			||||||
			goto out; /* already reported */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		state->failed = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* if repair goes OK, report success even if lvscan has failed */
 | 
					 | 
				
			||||||
		if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
 | 
					 | 
				
			||||||
			log_error("Repair of RAID device %s failed.", device);
 | 
					 | 
				
			||||||
			r = 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		state->failed = 0;
 | 
					 | 
				
			||||||
		if (status->insync_regions == status->total_regions)
 | 
					 | 
				
			||||||
			memset(&state->raid_devs, 0, sizeof(state->raid_devs));
 | 
					 | 
				
			||||||
		log_info("%s array, %s, is %s in-sync.",
 | 
					 | 
				
			||||||
			 status->raid_type, device,
 | 
					 | 
				
			||||||
			 (status->insync_regions == status->total_regions) ? "now" : "not");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	dm_pool_free(state->mem, status);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return r;
 | 
						p = strstr(resync_ratio, "/");
 | 
				
			||||||
 | 
						if (!p) {
 | 
				
			||||||
 | 
							syslog(LOG_ERR, "Failed to parse resync_ratio for %s: %s",
 | 
				
			||||||
 | 
							       device, resync_ratio);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p[0] = '\0';
 | 
				
			||||||
 | 
						syslog(LOG_INFO, "%s array, %s, is %s in-sync.",
 | 
				
			||||||
 | 
						       raid_type, device, strcmp(resync_ratio, p+1) ? "not" : "now");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void process_event(struct dm_task *dmt,
 | 
					void process_event(struct dm_task *dmt,
 | 
				
			||||||
		   enum dm_event_mask event __attribute__((unused)),
 | 
							   enum dm_event_mask event __attribute__((unused)),
 | 
				
			||||||
		   void **user)
 | 
							   void **unused __attribute__((unused)))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dso_state *state = *user;
 | 
					 | 
				
			||||||
	void *next = NULL;
 | 
						void *next = NULL;
 | 
				
			||||||
	uint64_t start, length;
 | 
						uint64_t start, length;
 | 
				
			||||||
	char *target_type = NULL;
 | 
						char *target_type = NULL;
 | 
				
			||||||
	char *params;
 | 
						char *params;
 | 
				
			||||||
	const char *device = dm_task_get_name(dmt);
 | 
						const char *device = dm_task_get_name(dmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dmeventd_lvm2_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		next = dm_get_next_target(dmt, next, &start, &length,
 | 
							next = dm_get_next_target(dmt, next, &start, &length,
 | 
				
			||||||
					  &target_type, ¶ms);
 | 
										  &target_type, ¶ms);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!target_type) {
 | 
							if (!target_type) {
 | 
				
			||||||
			log_info("%s mapping lost.", device);
 | 
								syslog(LOG_INFO, "%s mapping lost.", device);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (strcmp(target_type, "raid")) {
 | 
							if (strcmp(target_type, "raid")) {
 | 
				
			||||||
			log_info("%s has non-raid portion.", device);
 | 
								syslog(LOG_INFO, "%s has non-raid portion.", device);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!_process_raid_event(state, params, device))
 | 
							if (_process_raid_event(params, device))
 | 
				
			||||||
			log_error("Failed to process event for %s.",
 | 
								syslog(LOG_ERR, "Failed to process event for %s",
 | 
				
			||||||
				  device);
 | 
								       device);
 | 
				
			||||||
	} while (next);
 | 
						} while (next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dmeventd_lvm2_unlock();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int register_device(const char *device,
 | 
					int register_device(const char *device,
 | 
				
			||||||
		    const char *uuid __attribute__((unused)),
 | 
							    const char *uuid __attribute__((unused)),
 | 
				
			||||||
		    int major __attribute__((unused)),
 | 
							    int major __attribute__((unused)),
 | 
				
			||||||
		    int minor __attribute__((unused)),
 | 
							    int minor __attribute__((unused)),
 | 
				
			||||||
		    void **user)
 | 
							    void **unused __attribute__((unused)))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dso_state *state;
 | 
						if (!dmeventd_lvm2_init())
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dmeventd_lvm2_init_with_pool("raid_state", state))
 | 
						syslog(LOG_INFO, "Monitoring RAID device %s for events.", device);
 | 
				
			||||||
		goto_bad;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
 | 
					 | 
				
			||||||
				   "lvconvert --repair --use-policies", device))
 | 
					 | 
				
			||||||
		goto_bad;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	*user = state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	log_info("Monitoring RAID device %s for events.", device);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
bad:
 | 
					 | 
				
			||||||
	log_error("Failed to monitor RAID %s.", device);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state)
 | 
					 | 
				
			||||||
		dmeventd_lvm2_exit_with_pool(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int unregister_device(const char *device,
 | 
					int unregister_device(const char *device,
 | 
				
			||||||
		      const char *uuid __attribute__((unused)),
 | 
							      const char *uuid __attribute__((unused)),
 | 
				
			||||||
		      int major __attribute__((unused)),
 | 
							      int major __attribute__((unused)),
 | 
				
			||||||
		      int minor __attribute__((unused)),
 | 
							      int minor __attribute__((unused)),
 | 
				
			||||||
		      void **user)
 | 
							      void **unused __attribute__((unused)))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dso_state *state = *user;
 | 
						syslog(LOG_INFO, "No longer monitoring RAID device %s for events.",
 | 
				
			||||||
 | 
						       device);
 | 
				
			||||||
	dmeventd_lvm2_exit_with_pool(state);
 | 
						dmeventd_lvm2_exit();
 | 
				
			||||||
	log_info("No longer monitoring RAID device %s for events.",
 | 
					 | 
				
			||||||
		 device);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,14 +10,14 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
# along with this program; if not, write to the Free Software Foundation,
 | 
					# along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
srcdir = @srcdir@
 | 
					srcdir = @srcdir@
 | 
				
			||||||
top_srcdir = @top_srcdir@
 | 
					top_srcdir = @top_srcdir@
 | 
				
			||||||
top_builddir = @top_builddir@
 | 
					top_builddir = @top_builddir@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
				
			||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
					CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
				
			||||||
LIBS += -ldevmapper-event-lvm2
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
SOURCES = dmeventd_snapshot.c
 | 
					SOURCES = dmeventd_snapshot.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,6 +26,8 @@ LIB_VERSION = $(LIB_VERSION_LVM)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
include $(top_builddir)/make.tmpl
 | 
					include $(top_builddir)/make.tmpl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_lvm2: install_dm_plugin
 | 
					install_lvm2: install_dm_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install: install_lvm2
 | 
					install: install_lvm2
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (C) 2007-2015 Red Hat, Inc. All rights reserved.
 | 
					 * Copyright (C) 2007-2011 Red Hat, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This file is part of LVM2.
 | 
					 * This file is part of LVM2.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -9,36 +9,35 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lib/misc/lib.h"
 | 
					#include "lib.h"
 | 
				
			||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
 | 
					
 | 
				
			||||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
					#include "libdevmapper-event.h"
 | 
				
			||||||
 | 
					#include "dmeventd_lvm.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <sys/sysmacros.h>
 | 
					 | 
				
			||||||
#include <sys/wait.h>
 | 
					#include <sys/wait.h>
 | 
				
			||||||
 | 
					#include <syslog.h> /* FIXME Replace syslog with multilog */
 | 
				
			||||||
#include <stdarg.h>
 | 
					#include <stdarg.h>
 | 
				
			||||||
#include <pthread.h>
 | 
					/* FIXME Missing openlog? */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* First warning when snapshot is 80% full. */
 | 
					/* First warning when snapshot is 80% full. */
 | 
				
			||||||
#define WARNING_THRESH	(DM_PERCENT_1 * 80)
 | 
					#define WARNING_THRESH 80
 | 
				
			||||||
/* Run a check every 5%. */
 | 
					/* Run a check every 5%. */
 | 
				
			||||||
#define CHECK_STEP	(DM_PERCENT_1 *  5)
 | 
					#define CHECK_STEP 5
 | 
				
			||||||
/* Do not bother checking snapshots less than 50% full. */
 | 
					/* Do not bother checking snapshots less than 50% full. */
 | 
				
			||||||
#define CHECK_MINIMUM	(DM_PERCENT_1 * 50)
 | 
					#define CHECK_MINIMUM 50
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define UMOUNT_COMMAND "/bin/umount"
 | 
					#define UMOUNT_COMMAND "/bin/umount"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct dso_state {
 | 
					struct dso_state {
 | 
				
			||||||
	struct dm_pool *mem;
 | 
						struct dm_pool *mem;
 | 
				
			||||||
	dm_percent_t percent_check;
 | 
						int percent_check;
 | 
				
			||||||
	uint64_t known_size;
 | 
						uint64_t known_size;
 | 
				
			||||||
	char cmd_lvextend[512];
 | 
						char cmd_str[1024];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DM_EVENT_LOG_FN("snap")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int _run(const char *cmd, ...)
 | 
					static int _run(const char *cmd, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        va_list ap;
 | 
					        va_list ap;
 | 
				
			||||||
@@ -63,7 +62,7 @@ static int _run(const char *cmd, ...)
 | 
				
			|||||||
                va_end(ap);
 | 
					                va_end(ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                execvp(cmd, (char **)argv);
 | 
					                execvp(cmd, (char **)argv);
 | 
				
			||||||
                log_sys_error("exec", cmd);
 | 
					                syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
 | 
				
			||||||
                exit(127);
 | 
					                exit(127);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -82,56 +81,18 @@ static int _run(const char *cmd, ...)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int _extend(const char *cmd)
 | 
					static int _extend(const char *cmd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	log_debug("Extending snapshot via %s.", cmd);
 | 
						return dmeventd_lvm2_run(cmd);
 | 
				
			||||||
	return dmeventd_lvm2_run_with_lock(cmd);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef SNAPSHOT_REMOVE
 | 
					 | 
				
			||||||
/* Remove invalid snapshot from dm-table */
 | 
					 | 
				
			||||||
/* Experimental for now and not used by default */
 | 
					 | 
				
			||||||
static int _remove(const char *uuid)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int r = 1;
 | 
					 | 
				
			||||||
	uint32_t cookie = 0;
 | 
					 | 
				
			||||||
	struct dm_task *dmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!dm_task_set_uuid(dmt, uuid)) {
 | 
					 | 
				
			||||||
		r = 0;
 | 
					 | 
				
			||||||
		goto_out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dm_task_retry_remove(dmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!dm_task_set_cookie(dmt, &cookie, 0)) {
 | 
					 | 
				
			||||||
		r = 0;
 | 
					 | 
				
			||||||
		goto_out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!dm_task_run(dmt)) {
 | 
					 | 
				
			||||||
		r = 0;
 | 
					 | 
				
			||||||
		goto_out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	dm_task_destroy(dmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return r;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif /* SNAPSHOT_REMOVE */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void _umount(const char *device, int major, int minor)
 | 
					static void _umount(const char *device, int major, int minor)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	FILE *mounts;
 | 
						FILE *mounts;
 | 
				
			||||||
	char buffer[4096];
 | 
						char buffer[4096];
 | 
				
			||||||
	char *words[3];
 | 
						char *words[3];
 | 
				
			||||||
	struct stat st;
 | 
						struct stat st;
 | 
				
			||||||
	const char procmounts[] = "/proc/mounts";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(mounts = fopen(procmounts, "r"))) {
 | 
						if (!(mounts = fopen("/proc/mounts", "r"))) {
 | 
				
			||||||
		log_sys_error("fopen", procmounts);
 | 
							syslog(LOG_ERR, "Could not read /proc/mounts. Not umounting %s.\n", device);
 | 
				
			||||||
		log_error("Not umounting %s.", device);
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -149,24 +110,23 @@ static void _umount(const char *device, int major, int minor)
 | 
				
			|||||||
			continue; /* can't stat, skip this one */
 | 
								continue; /* can't stat, skip this one */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (S_ISBLK(st.st_mode) &&
 | 
							if (S_ISBLK(st.st_mode) &&
 | 
				
			||||||
		    (int) major(st.st_rdev) == major &&
 | 
							    major(st.st_rdev) == major &&
 | 
				
			||||||
		    (int) minor(st.st_rdev) == minor) {
 | 
							    minor(st.st_rdev) == minor) {
 | 
				
			||||||
			log_error("Unmounting invalid snapshot %s from %s.", device, words[1]);
 | 
								syslog(LOG_ERR, "Unmounting invalid snapshot %s from %s.\n", device, words[1]);
 | 
				
			||||||
			if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
 | 
					                        if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
 | 
				
			||||||
				log_error("Failed to umount snapshot %s from %s: %s.",
 | 
					                                syslog(LOG_ERR, "Failed to umount snapshot %s from %s: %s.\n",
 | 
				
			||||||
					  device, words[1], strerror(errno));
 | 
					                                       device, words[1], strerror(errno));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fclose(mounts))
 | 
						if (fclose(mounts))
 | 
				
			||||||
		log_sys_error("close", procmounts);
 | 
							syslog(LOG_ERR, "Failed to close /proc/mounts.\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void process_event(struct dm_task *dmt,
 | 
					void process_event(struct dm_task *dmt,
 | 
				
			||||||
		   enum dm_event_mask event __attribute__((unused)),
 | 
							   enum dm_event_mask event __attribute__((unused)),
 | 
				
			||||||
		   void **user)
 | 
							   void **private)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dso_state *state = *user;
 | 
					 | 
				
			||||||
	void *next = NULL;
 | 
						void *next = NULL;
 | 
				
			||||||
	uint64_t start, length;
 | 
						uint64_t start, length;
 | 
				
			||||||
	char *target_type = NULL;
 | 
						char *target_type = NULL;
 | 
				
			||||||
@@ -174,50 +134,28 @@ void process_event(struct dm_task *dmt,
 | 
				
			|||||||
	struct dm_status_snapshot *status = NULL;
 | 
						struct dm_status_snapshot *status = NULL;
 | 
				
			||||||
	const char *device = dm_task_get_name(dmt);
 | 
						const char *device = dm_task_get_name(dmt);
 | 
				
			||||||
	int percent;
 | 
						int percent;
 | 
				
			||||||
	struct dm_info info;
 | 
						struct dso_state *state = *private;
 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* No longer monitoring, waiting for remove */
 | 
						/* No longer monitoring, waiting for remove */
 | 
				
			||||||
	if (!state->percent_check)
 | 
						if (!state->percent_check)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dmeventd_lvm2_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
 | 
						dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
 | 
				
			||||||
	if (!target_type || strcmp(target_type, "snapshot")) {
 | 
						if (!target_type)
 | 
				
			||||||
		log_error("Target %s is not snapshot.", target_type);
 | 
							goto out;
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dm_get_status_snapshot(state->mem, params, &status)) {
 | 
						if (!dm_get_status_snapshot(state->mem, params, &status))
 | 
				
			||||||
		log_error("Cannot parse snapshot %s state: %s.", device, params);
 | 
							goto out;
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						if (status->invalid) {
 | 
				
			||||||
	 * If the snapshot has been invalidated or we failed to parse
 | 
							struct dm_info info;
 | 
				
			||||||
	 * the status string. Report the full status string to syslog.
 | 
							if (dm_task_get_info(dmt, &info)) {
 | 
				
			||||||
	 */
 | 
								dmeventd_lvm2_unlock();
 | 
				
			||||||
	if (status->invalid || status->overflow || !status->total_sectors) {
 | 
					 | 
				
			||||||
		log_warn("WARNING: Snapshot %s changed state to: %s and should be removed.",
 | 
					 | 
				
			||||||
			 device, params);
 | 
					 | 
				
			||||||
		state->percent_check = 0;
 | 
					 | 
				
			||||||
		if (dm_task_get_info(dmt, &info))
 | 
					 | 
				
			||||||
			_umount(device, info.major, info.minor);
 | 
								_umount(device, info.major, info.minor);
 | 
				
			||||||
#ifdef SNAPSHOT_REMOVE
 | 
								return;
 | 
				
			||||||
		/* Maybe configurable ? */
 | 
							} /* else; too bad, but this is best-effort thing... */
 | 
				
			||||||
		_remove(dm_task_get_uuid(dmt));
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		if ((ret = pthread_kill(pthread_self(), SIGALRM)) && (ret != ESRCH))
 | 
					 | 
				
			||||||
			log_sys_error("pthread_kill", "self");
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (length <= (status->used_sectors - status->metadata_sectors)) {
 | 
					 | 
				
			||||||
		/* 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");
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Snapshot size had changed. Clear the threshold. */
 | 
						/* Snapshot size had changed. Clear the threshold. */
 | 
				
			||||||
@@ -226,51 +164,69 @@ void process_event(struct dm_task *dmt,
 | 
				
			|||||||
		state->known_size = status->total_sectors;
 | 
							state->known_size = status->total_sectors;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	percent = dm_make_percent(status->used_sectors, status->total_sectors);
 | 
						/*
 | 
				
			||||||
 | 
						 * If the snapshot has been invalidated or we failed to parse
 | 
				
			||||||
 | 
						 * the status string. Report the full status string to syslog.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (status->invalid || !status->total_sectors) {
 | 
				
			||||||
 | 
							syslog(LOG_ERR, "Snapshot %s changed state to: %s\n", device, params);
 | 
				
			||||||
 | 
							state->percent_check = 0;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						percent = (int) (100 * status->used_sectors / status->total_sectors);
 | 
				
			||||||
	if (percent >= state->percent_check) {
 | 
						if (percent >= state->percent_check) {
 | 
				
			||||||
		/* Usage has raised more than CHECK_STEP since the last
 | 
							/* Usage has raised more than CHECK_STEP since the last
 | 
				
			||||||
		   time. Run actions. */
 | 
							   time. Run actions. */
 | 
				
			||||||
		state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
 | 
							state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
 | 
							if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
 | 
				
			||||||
			log_warn("WARNING: Snapshot %s is now %.2f%% full.",
 | 
								syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent);
 | 
				
			||||||
				 device, dm_percent_to_round_float(percent, 2));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Try to extend the snapshot, in accord with user-set policies */
 | 
							/* Try to extend the snapshot, in accord with user-set policies */
 | 
				
			||||||
		if (!_extend(state->cmd_lvextend))
 | 
							if (!_extend(state->cmd_str))
 | 
				
			||||||
			log_error("Failed to extend snapshot %s.", device);
 | 
								syslog(LOG_ERR, "Failed to extend snapshot %s.\n", device);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	dm_pool_free(state->mem, status);
 | 
						if (status)
 | 
				
			||||||
 | 
							dm_pool_free(state->mem, status);
 | 
				
			||||||
 | 
						dmeventd_lvm2_unlock();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int register_device(const char *device,
 | 
					int register_device(const char *device,
 | 
				
			||||||
		    const char *uuid __attribute__((unused)),
 | 
							    const char *uuid __attribute__((unused)),
 | 
				
			||||||
		    int major __attribute__((unused)),
 | 
							    int major __attribute__((unused)),
 | 
				
			||||||
		    int minor __attribute__((unused)),
 | 
							    int minor __attribute__((unused)),
 | 
				
			||||||
		    void **user)
 | 
							    void **private)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct dm_pool *statemem = NULL;
 | 
				
			||||||
	struct dso_state *state;
 | 
						struct dso_state *state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dmeventd_lvm2_init_with_pool("snapshot_state", state))
 | 
						if (!dmeventd_lvm2_init())
 | 
				
			||||||
		goto_bad;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dmeventd_lvm2_command(state->mem, state->cmd_lvextend,
 | 
						if (!(statemem = dm_pool_create("snapshot_state", 512)) ||
 | 
				
			||||||
				   sizeof(state->cmd_lvextend),
 | 
						    !(state = dm_pool_zalloc(statemem, sizeof(*state))))
 | 
				
			||||||
 | 
							goto bad;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dmeventd_lvm2_command(statemem, state->cmd_str,
 | 
				
			||||||
 | 
									   sizeof(state->cmd_str),
 | 
				
			||||||
				   "lvextend --use-policies", device))
 | 
									   "lvextend --use-policies", device))
 | 
				
			||||||
		goto_bad;
 | 
							goto bad;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						state->mem = statemem;
 | 
				
			||||||
	state->percent_check = CHECK_MINIMUM;
 | 
						state->percent_check = CHECK_MINIMUM;
 | 
				
			||||||
	*user = state;
 | 
						*private = state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log_info("Monitoring snapshot %s.", device);
 | 
						syslog(LOG_INFO, "Monitoring snapshot %s\n", device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
bad:
 | 
					bad:
 | 
				
			||||||
	log_error("Failed to monitor snapshot %s.", device);
 | 
						if (statemem)
 | 
				
			||||||
 | 
							dm_pool_destroy(statemem);
 | 
				
			||||||
	if (state)
 | 
						dmeventd_lvm2_exit();
 | 
				
			||||||
		dmeventd_lvm2_exit_with_pool(state);
 | 
					out:
 | 
				
			||||||
 | 
						syslog(LOG_ERR, "Failed to monitor snapshot %s.\n", device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -279,12 +235,13 @@ int unregister_device(const char *device,
 | 
				
			|||||||
		      const char *uuid __attribute__((unused)),
 | 
							      const char *uuid __attribute__((unused)),
 | 
				
			||||||
		      int major __attribute__((unused)),
 | 
							      int major __attribute__((unused)),
 | 
				
			||||||
		      int minor __attribute__((unused)),
 | 
							      int minor __attribute__((unused)),
 | 
				
			||||||
		      void **user)
 | 
							      void **private)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dso_state *state = *user;
 | 
						struct dso_state *state = *private;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dmeventd_lvm2_exit_with_pool(state);
 | 
						syslog(LOG_INFO, "No longer monitoring snapshot %s\n", device);
 | 
				
			||||||
	log_info("No longer monitoring snapshot %s.", device);
 | 
						dm_pool_destroy(state->mem);
 | 
				
			||||||
 | 
						dmeventd_lvm2_exit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,14 +9,14 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
# along with this program; if not, write to the Free Software Foundation,
 | 
					# along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
srcdir = @srcdir@
 | 
					srcdir = @srcdir@
 | 
				
			||||||
top_srcdir = @top_srcdir@
 | 
					top_srcdir = @top_srcdir@
 | 
				
			||||||
top_builddir = @top_builddir@
 | 
					top_builddir = @top_builddir@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
 | 
				
			||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
					CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
 | 
				
			||||||
LIBS += -ldevmapper-event-lvm2
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
SOURCES = dmeventd_thin.c
 | 
					SOURCES = dmeventd_thin.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,6 +29,8 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
include $(top_builddir)/make.tmpl
 | 
					include $(top_builddir)/make.tmpl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LIBS += -ldevmapper-event-lvm2 -ldevmapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_lvm2: install_dm_plugin
 | 
					install_lvm2: install_dm_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install: install_lvm2
 | 
					install: install_lvm2
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
 | 
					 * Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This file is part of LVM2.
 | 
					 * This file is part of LVM2.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -9,392 +9,378 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
					 * 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,
 | 
					 * along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
					 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lib/misc/lib.h"
 | 
					#include "lib.h"
 | 
				
			||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
 | 
					
 | 
				
			||||||
#include "daemons/dmeventd/libdevmapper-event.h"
 | 
					#include "libdevmapper-event.h"
 | 
				
			||||||
 | 
					#include "dmeventd_lvm.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <sys/wait.h>
 | 
					#include <sys/wait.h>
 | 
				
			||||||
 | 
					#include <syslog.h> /* FIXME Replace syslog with multilog */
 | 
				
			||||||
#include <stdarg.h>
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					/* FIXME Missing openlog? */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* TODO - move this mountinfo code into library to be reusable */
 | 
					/* First warning when thin is 80% full. */
 | 
				
			||||||
#ifdef __linux__
 | 
					#define WARNING_THRESH 80
 | 
				
			||||||
#  include "libdm/misc/kdev_t.h"
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#  define MAJOR(x) major((x))
 | 
					 | 
				
			||||||
#  define MINOR(x) minor((x))
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* First warning when thin data or metadata is 80% full. */
 | 
					 | 
				
			||||||
#define WARNING_THRESH	(DM_PERCENT_1 * 80)
 | 
					 | 
				
			||||||
/* Umount thin LVs when thin data or metadata LV is >=
 | 
					 | 
				
			||||||
 * and lvextend --use-policies has failed. */
 | 
					 | 
				
			||||||
#define UMOUNT_THRESH	(DM_PERCENT_1 * 95)
 | 
					 | 
				
			||||||
/* Run a check every 5%. */
 | 
					/* Run a check every 5%. */
 | 
				
			||||||
#define CHECK_STEP	(DM_PERCENT_1 *  5)
 | 
					#define CHECK_STEP 5
 | 
				
			||||||
/* Do not bother checking thin data or metadata is less than 50% full. */
 | 
					/* Do not bother checking thins less than 50% full. */
 | 
				
			||||||
#define CHECK_MINIMUM	(DM_PERCENT_1 * 50)
 | 
					#define CHECK_MINIMUM 50
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define UMOUNT_COMMAND "/bin/umount"
 | 
					#define UMOUNT_COMMAND "/bin/umount"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_FAILS	(256)  /* ~42 mins between cmd call retry with 10s delay */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define THIN_DEBUG 0
 | 
					#define THIN_DEBUG 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct dso_state {
 | 
					struct dso_state {
 | 
				
			||||||
	struct dm_pool *mem;
 | 
						struct dm_pool *mem;
 | 
				
			||||||
	int metadata_percent_check;
 | 
						int metadata_percent_check;
 | 
				
			||||||
	int metadata_percent;
 | 
					 | 
				
			||||||
	int data_percent_check;
 | 
						int data_percent_check;
 | 
				
			||||||
	int data_percent;
 | 
					 | 
				
			||||||
	uint64_t known_metadata_size;
 | 
						uint64_t known_metadata_size;
 | 
				
			||||||
	uint64_t known_data_size;
 | 
						uint64_t known_data_size;
 | 
				
			||||||
	unsigned fails;
 | 
						char cmd_str[1024];
 | 
				
			||||||
	unsigned max_fails;
 | 
					 | 
				
			||||||
	int restore_sigset;
 | 
					 | 
				
			||||||
	sigset_t old_sigset;
 | 
					 | 
				
			||||||
	pid_t pid;
 | 
					 | 
				
			||||||
	char *argv[3];
 | 
					 | 
				
			||||||
	char *cmd_str;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DM_EVENT_LOG_FN("thin")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int _run_command(struct dso_state *state)
 | 
					/* TODO - move this mountinfo code into library to be reusable */
 | 
				
			||||||
 | 
					#ifdef __linux__
 | 
				
			||||||
 | 
					#  include "kdev_t.h"
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#  define MAJOR(x) major((x))
 | 
				
			||||||
 | 
					#  define MINOR(x) minor((x))
 | 
				
			||||||
 | 
					#  define MKDEV(x,y) makedev((x),(y))
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get dependencies for device, and try to find matching device */
 | 
				
			||||||
 | 
					static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char val[16];
 | 
						struct dm_task *dmt;
 | 
				
			||||||
	int i;
 | 
						const struct dm_deps *deps;
 | 
				
			||||||
 | 
						struct dm_info info;
 | 
				
			||||||
 | 
						int major, minor;
 | 
				
			||||||
 | 
						int r = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Mark for possible lvm2 command we are running from dmeventd
 | 
						if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
 | 
				
			||||||
	 * lvm2 will not try to talk back to dmeventd while processing it */
 | 
					 | 
				
			||||||
	(void) setenv("LVM_RUN_BY_DMEVENTD", "1", 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state->data_percent) {
 | 
					 | 
				
			||||||
		/* Prepare some known data to env vars for easy use */
 | 
					 | 
				
			||||||
		if (dm_snprintf(val, sizeof(val), "%d",
 | 
					 | 
				
			||||||
				state->data_percent / DM_PERCENT_1) != -1)
 | 
					 | 
				
			||||||
			(void) setenv("DMEVENTD_THIN_POOL_DATA", val, 1);
 | 
					 | 
				
			||||||
		if (dm_snprintf(val, sizeof(val), "%d",
 | 
					 | 
				
			||||||
				state->metadata_percent / DM_PERCENT_1) != -1)
 | 
					 | 
				
			||||||
			(void) setenv("DMEVENTD_THIN_POOL_METADATA", val, 1);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		/* For an error event it's for a user to check status and decide */
 | 
					 | 
				
			||||||
		log_debug("Error event processing.");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	log_verbose("Executing command: %s", state->cmd_str);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* TODO:
 | 
					 | 
				
			||||||
	 *   Support parallel run of 'task' and it's waitpid maintainence
 | 
					 | 
				
			||||||
	 *   ATM we can't handle signaling of  SIGALRM
 | 
					 | 
				
			||||||
	 *   as signalling is not allowed while 'process_event()' is running
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (!(state->pid = fork())) {
 | 
					 | 
				
			||||||
		/* child */
 | 
					 | 
				
			||||||
		(void) close(0);
 | 
					 | 
				
			||||||
		for (i = 3; i < 255; ++i) (void) close(i);
 | 
					 | 
				
			||||||
		execvp(state->argv[0], state->argv);
 | 
					 | 
				
			||||||
		_exit(errno);
 | 
					 | 
				
			||||||
	} else if (state->pid == -1) {
 | 
					 | 
				
			||||||
		log_error("Can't fork command %s.", state->cmd_str);
 | 
					 | 
				
			||||||
		state->fails = 1;
 | 
					 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						if (!dm_task_set_name(dmt, name))
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dm_task_no_open_count(dmt))
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dm_task_run(dmt))
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dm_task_get_info(dmt, &info))
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(deps = dm_task_get_deps(dmt)))
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!info.exists || deps->count != 1)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						major = (int) MAJOR(deps->device[0]);
 | 
				
			||||||
 | 
						minor = (int) MINOR(deps->device[0]);
 | 
				
			||||||
 | 
						if ((major != tp_major) || (minor != tp_minor))
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*dev_minor = info.minor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if THIN_DEBUG
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							char dev_name[PATH_MAX];
 | 
				
			||||||
 | 
							if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
 | 
				
			||||||
 | 
								syslog(LOG_DEBUG, "Found %s (%u:%u) depends on %s",
 | 
				
			||||||
 | 
								       name, major, *dev_minor, dev_name);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						r = 1;
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						dm_task_destroy(dmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return r;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int _use_policy(struct dm_task *dmt, struct dso_state *state)
 | 
					/* Get all active devices */
 | 
				
			||||||
 | 
					static int _find_all_devs(dm_bitset_t bs, int tp_major, int tp_minor)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct dm_task *dmt;
 | 
				
			||||||
 | 
						struct dm_names *names;
 | 
				
			||||||
 | 
						unsigned next = 0;
 | 
				
			||||||
 | 
						int minor, r = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dm_task_run(dmt)) {
 | 
				
			||||||
 | 
							r = 0;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(names = dm_task_get_names(dmt))) {
 | 
				
			||||||
 | 
							r = 0;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!names->dev)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							names = (struct dm_names *)((char *) names + next);
 | 
				
			||||||
 | 
							if (_has_deps(names->name, tp_major, tp_minor, &minor))
 | 
				
			||||||
 | 
								dm_bit_set(bs, minor);
 | 
				
			||||||
 | 
							next = names->next;
 | 
				
			||||||
 | 
						} while (next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						dm_task_destroy(dmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int _extend(struct dso_state *state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#if THIN_DEBUG
 | 
					#if THIN_DEBUG
 | 
				
			||||||
	log_debug("dmeventd executes: %s.", state->cmd_str);
 | 
						syslog(LOG_INFO, "dmeventd executes: %s.\n", state->cmd_str);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	if (state->argv[0])
 | 
						return dmeventd_lvm2_run(state->cmd_str);
 | 
				
			||||||
		return _run_command(state);
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
 | 
					static int _run(const char *cmd, ...)
 | 
				
			||||||
		log_error("Failed command for %s.", dm_task_get_name(dmt));
 | 
					{
 | 
				
			||||||
		state->fails = 1;
 | 
						va_list ap;
 | 
				
			||||||
		return 0;
 | 
						int argc = 1; /* for argv[0], i.e. cmd */
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
						const char **argv;
 | 
				
			||||||
 | 
						pid_t pid = fork();
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pid == 0) { /* child */
 | 
				
			||||||
 | 
							va_start(ap, cmd);
 | 
				
			||||||
 | 
							while (va_arg(ap, const char *))
 | 
				
			||||||
 | 
								++argc;
 | 
				
			||||||
 | 
							va_end(ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* + 1 for the terminating NULL */
 | 
				
			||||||
 | 
							argv = alloca(sizeof(const char *) * (argc + 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							argv[0] = cmd;
 | 
				
			||||||
 | 
					                va_start(ap, cmd);
 | 
				
			||||||
 | 
							while ((argv[++i] = va_arg(ap, const char *)));
 | 
				
			||||||
 | 
							va_end(ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							execvp(cmd, (char **)argv);
 | 
				
			||||||
 | 
							syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
 | 
				
			||||||
 | 
							exit(127);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	state->fails = 0;
 | 
						if (pid > 0) { /* parent */
 | 
				
			||||||
 | 
							if (waitpid(pid, &status, 0) != pid)
 | 
				
			||||||
 | 
								return 0; /* waitpid failed */
 | 
				
			||||||
 | 
							if (!WIFEXITED(status) || WEXITSTATUS(status))
 | 
				
			||||||
 | 
								return 0; /* the child failed */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pid < 0)
 | 
				
			||||||
 | 
							return 0; /* fork failed */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 1; /* all good */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mountinfo_s {
 | 
				
			||||||
 | 
						struct dm_info info;
 | 
				
			||||||
 | 
						dm_bitset_t minors; /* Bitset for active thin pool minors */
 | 
				
			||||||
 | 
						const char *device;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int _umount_device(char *buffer, unsigned major, unsigned minor,
 | 
				
			||||||
 | 
								  char *target, void *cb_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mountinfo_s *data = cb_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((major == data->info.major) && dm_bit(data->minors, minor)) {
 | 
				
			||||||
 | 
							syslog(LOG_INFO, "Unmounting thin volume %s from %s.\n",
 | 
				
			||||||
 | 
							       data->device, target);
 | 
				
			||||||
 | 
							if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
 | 
				
			||||||
 | 
								syslog(LOG_ERR, "Failed to umount thin %s from %s: %s.\n",
 | 
				
			||||||
 | 
								       data->device, target, strerror(errno));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check if executed command has finished
 | 
					/*
 | 
				
			||||||
 * Only 1 command may run */
 | 
					 * Find all thin pool users and try to umount them.
 | 
				
			||||||
static int _wait_for_pid(struct dso_state *state)
 | 
					 * TODO: work with read-only thin pool support
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void _umount(struct dm_task *dmt, const char *device)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int status = 0;
 | 
						/* TODO: Convert to use hash to reduce memory usage */
 | 
				
			||||||
 | 
						static const size_t MINORS = (1U << 20); /* 20 bit */
 | 
				
			||||||
 | 
						struct mountinfo_s data = {
 | 
				
			||||||
 | 
							.device = device,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (state->pid == -1)
 | 
						if (!dm_task_get_info(dmt, &data.info))
 | 
				
			||||||
		return 1;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!waitpid(state->pid, &status, WNOHANG))
 | 
						dmeventd_lvm2_unlock();
 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Wait for finish */
 | 
						if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
 | 
				
			||||||
	if (WIFEXITED(status)) {
 | 
							syslog(LOG_ERR, "Failed to allocate bitset. Not unmounting %s.\n", device);
 | 
				
			||||||
		log_verbose("Child %d exited with status %d.",
 | 
							goto out;
 | 
				
			||||||
			    state->pid, WEXITSTATUS(status));
 | 
					 | 
				
			||||||
		state->fails = WEXITSTATUS(status) ? 1 : 0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		if (WIFSIGNALED(status))
 | 
					 | 
				
			||||||
			log_verbose("Child %d was terminated with status %d.",
 | 
					 | 
				
			||||||
				    state->pid, WTERMSIG(status));
 | 
					 | 
				
			||||||
		state->fails = 1;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	state->pid = -1;
 | 
						if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
 | 
				
			||||||
 | 
							syslog(LOG_ERR, "Failed to detect mounted volumes for %s.\n", device);
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						if (!dm_mountinfo_read(_umount_device, &data)) {
 | 
				
			||||||
 | 
							syslog(LOG_ERR, "Could not parse mountinfo file.\n");
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						if (data.minors)
 | 
				
			||||||
 | 
							dm_bitset_destroy(data.minors);
 | 
				
			||||||
 | 
						dmeventd_lvm2_lock();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void process_event(struct dm_task *dmt,
 | 
					void process_event(struct dm_task *dmt,
 | 
				
			||||||
		   enum dm_event_mask event __attribute__((unused)),
 | 
							   enum dm_event_mask event __attribute__((unused)),
 | 
				
			||||||
		   void **user)
 | 
							   void **private)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *device = dm_task_get_name(dmt);
 | 
						const char *device = dm_task_get_name(dmt);
 | 
				
			||||||
	struct dso_state *state = *user;
 | 
						int percent;
 | 
				
			||||||
 | 
						struct dso_state *state = *private;
 | 
				
			||||||
	struct dm_status_thin_pool *tps = NULL;
 | 
						struct dm_status_thin_pool *tps = NULL;
 | 
				
			||||||
	void *next = NULL;
 | 
						void *next = NULL;
 | 
				
			||||||
	uint64_t start, length;
 | 
						uint64_t start, length;
 | 
				
			||||||
	char *target_type = NULL;
 | 
						char *target_type = NULL;
 | 
				
			||||||
	char *params;
 | 
						char *params;
 | 
				
			||||||
	int needs_policy = 0;
 | 
					 | 
				
			||||||
	struct dm_task *new_dmt = NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if THIN_DEBUG
 | 
					#if 0
 | 
				
			||||||
	log_debug("Watch for tp-data:%.2f%%  tp-metadata:%.2f%%.",
 | 
						/* No longer monitoring, waiting for remove */
 | 
				
			||||||
		  dm_percent_to_round_float(state->data_percent_check, 2),
 | 
						if (!state->meta_percent_check && !state->data_percent_check)
 | 
				
			||||||
		  dm_percent_to_round_float(state->metadata_percent_check, 2));
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	if (!_wait_for_pid(state)) {
 | 
					 | 
				
			||||||
		log_warn("WARNING: Skipping event, child %d is still running (%s).",
 | 
					 | 
				
			||||||
			 state->pid, state->cmd_str);
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
					#endif
 | 
				
			||||||
 | 
						dmeventd_lvm2_lock();
 | 
				
			||||||
	if (event & DM_EVENT_DEVICE_ERROR) {
 | 
					 | 
				
			||||||
		/* Error -> no need to check and do instant resize */
 | 
					 | 
				
			||||||
		state->data_percent = state->metadata_percent = 0;
 | 
					 | 
				
			||||||
		if (_use_policy(dmt, state))
 | 
					 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		stack;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * Rather update oldish status
 | 
					 | 
				
			||||||
		 * since after 'command' processing
 | 
					 | 
				
			||||||
		 * percentage info could have changed a lot.
 | 
					 | 
				
			||||||
		 * If we would get above UMOUNT_THRESH
 | 
					 | 
				
			||||||
		 * we would wait for next sigalarm.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS)))
 | 
					 | 
				
			||||||
			goto_out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt)))
 | 
					 | 
				
			||||||
			goto_out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Non-blocking status read */
 | 
					 | 
				
			||||||
		if (!dm_task_no_flush(new_dmt))
 | 
					 | 
				
			||||||
			log_warn("WARNING: Can't set no_flush for dm status.");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!dm_task_run(new_dmt))
 | 
					 | 
				
			||||||
			goto_out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		dmt = new_dmt;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
 | 
						dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!target_type || (strcmp(target_type, "thin-pool") != 0)) {
 | 
						if (!target_type || (strcmp(target_type, "thin-pool") != 0)) {
 | 
				
			||||||
		log_error("Invalid target type.");
 | 
							syslog(LOG_ERR, "Invalid target type.\n");
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
 | 
						if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
 | 
				
			||||||
		log_error("Failed to parse status.");
 | 
							syslog(LOG_ERR, "Failed to parse status.\n");
 | 
				
			||||||
 | 
							_umount(dmt, device);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if THIN_DEBUG
 | 
					#if THIN_DEBUG
 | 
				
			||||||
	log_debug("Thin pool status " FMTu64 "/" FMTu64 "  "
 | 
						syslog(LOG_INFO, "%p: Got status %" PRIu64 " / %" PRIu64
 | 
				
			||||||
		  FMTu64 "/" FMTu64 ".",
 | 
						       " %" PRIu64  " / %" PRIu64 ".\n", state,
 | 
				
			||||||
		  tps->used_metadata_blocks, tps->total_metadata_blocks,
 | 
						       tps->used_metadata_blocks, tps->total_metadata_blocks,
 | 
				
			||||||
		  tps->used_data_blocks, tps->total_data_blocks);
 | 
						       tps->used_data_blocks, tps->total_data_blocks);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Thin pool size had changed. Clear the threshold. */
 | 
						/* Thin pool size had changed. Clear the threshold. */
 | 
				
			||||||
	if (state->known_metadata_size != tps->total_metadata_blocks) {
 | 
						if (state->known_metadata_size != tps->total_metadata_blocks) {
 | 
				
			||||||
		state->metadata_percent_check = CHECK_MINIMUM;
 | 
							state->metadata_percent_check = CHECK_MINIMUM;
 | 
				
			||||||
		state->known_metadata_size = tps->total_metadata_blocks;
 | 
							state->known_metadata_size = tps->total_metadata_blocks;
 | 
				
			||||||
		state->fails = 0;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (state->known_data_size != tps->total_data_blocks) {
 | 
						if (state->known_data_size != tps->total_data_blocks) {
 | 
				
			||||||
		state->data_percent_check = CHECK_MINIMUM;
 | 
							state->data_percent_check = CHECK_MINIMUM;
 | 
				
			||||||
		state->known_data_size = tps->total_data_blocks;
 | 
							state->known_data_size = tps->total_data_blocks;
 | 
				
			||||||
		state->fails = 0;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						percent = 100 * tps->used_metadata_blocks / tps->total_metadata_blocks;
 | 
				
			||||||
	 * Trigger action when threshold boundary is exceeded.
 | 
						if (percent >= state->metadata_percent_check) {
 | 
				
			||||||
	 * Report 80% threshold warning when it's used above 80%.
 | 
							/*
 | 
				
			||||||
	 * Only 100% is exception as it cannot be surpased so policy
 | 
							 * Usage has raised more than CHECK_STEP since the last
 | 
				
			||||||
	 * action is called for:  >50%, >55% ... >95%, 100%
 | 
							 * time. Run actions.
 | 
				
			||||||
	 */
 | 
							 */
 | 
				
			||||||
	state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
 | 
							state->metadata_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
 | 
				
			||||||
	if ((state->metadata_percent > WARNING_THRESH) &&
 | 
					 | 
				
			||||||
	    (state->metadata_percent > state->metadata_percent_check))
 | 
					 | 
				
			||||||
		log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
 | 
					 | 
				
			||||||
			 device, dm_percent_to_round_float(state->metadata_percent, 2));
 | 
					 | 
				
			||||||
	if (state->metadata_percent > CHECK_MINIMUM) {
 | 
					 | 
				
			||||||
		/* Run action when usage raised more than CHECK_STEP since the last time */
 | 
					 | 
				
			||||||
		if (state->metadata_percent > state->metadata_percent_check)
 | 
					 | 
				
			||||||
			needs_policy = 1;
 | 
					 | 
				
			||||||
		state->metadata_percent_check = (state->metadata_percent / CHECK_STEP + 1) * CHECK_STEP;
 | 
					 | 
				
			||||||
		if (state->metadata_percent_check == DM_PERCENT_100)
 | 
					 | 
				
			||||||
			state->metadata_percent_check--; /* Can't get bigger then 100% */
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		state->metadata_percent_check = CHECK_MINIMUM;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	state->data_percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
 | 
							/* FIXME: extension of metadata needs to be written! */
 | 
				
			||||||
	if ((state->data_percent > WARNING_THRESH) &&
 | 
							if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
 | 
				
			||||||
	    (state->data_percent > state->data_percent_check))
 | 
								syslog(LOG_WARNING, "Thin metadata %s is now %i%% full.\n",
 | 
				
			||||||
		log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
 | 
								       device, percent);
 | 
				
			||||||
			 device, dm_percent_to_round_float(state->data_percent, 2));
 | 
							 /* Try to extend the metadata, in accord with user-set policies */
 | 
				
			||||||
	if (state->data_percent > CHECK_MINIMUM) {
 | 
							if (!_extend(state)) {
 | 
				
			||||||
		/* Run action when usage raised more than CHECK_STEP since the last time */
 | 
								syslog(LOG_ERR, "Failed to extend thin metadata %s.\n",
 | 
				
			||||||
		if (state->data_percent > state->data_percent_check)
 | 
								       device);
 | 
				
			||||||
			needs_policy = 1;
 | 
								_umount(dmt, device);
 | 
				
			||||||
		state->data_percent_check = (state->data_percent / CHECK_STEP + 1) * CHECK_STEP;
 | 
					 | 
				
			||||||
		if (state->data_percent_check == DM_PERCENT_100)
 | 
					 | 
				
			||||||
			state->data_percent_check--; /* Can't get bigger then 100% */
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		state->data_percent_check = CHECK_MINIMUM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached.
 | 
					 | 
				
			||||||
	 * Avoids too high number of error retries, yet shows some status messages in log regularly.
 | 
					 | 
				
			||||||
	 * i.e. PV could have been pvmoved and VG/LV was locked for a while...
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (state->fails) {
 | 
					 | 
				
			||||||
		if (state->fails++ <= state->max_fails) {
 | 
					 | 
				
			||||||
			log_debug("Postponing frequently failing policy (%u <= %u).",
 | 
					 | 
				
			||||||
				  state->fails - 1, state->max_fails);
 | 
					 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (state->max_fails < MAX_FAILS)
 | 
							/* FIXME: hmm READ-ONLY switch should happen in error path */
 | 
				
			||||||
			state->max_fails <<= 1;
 | 
						}
 | 
				
			||||||
		state->fails = needs_policy = 1; /* Retry failing command */
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		state->max_fails = 1; /* Reset on success */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (needs_policy)
 | 
						percent = 100 * tps->used_data_blocks / tps->total_data_blocks;
 | 
				
			||||||
		_use_policy(dmt, state);
 | 
						if (percent >= state->data_percent_check) {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Usage has raised more than CHECK_STEP since
 | 
				
			||||||
 | 
							 * the last time. Run actions.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
 | 
				
			||||||
 | 
								syslog(LOG_WARNING, "Thin %s is now %i%% full.\n", device, percent);
 | 
				
			||||||
 | 
							/* Try to extend the thin data, in accord with user-set policies */
 | 
				
			||||||
 | 
							if (!_extend(state)) {
 | 
				
			||||||
 | 
								syslog(LOG_ERR, "Failed to extend thin %s.\n", device);
 | 
				
			||||||
 | 
								state->data_percent_check = 0;
 | 
				
			||||||
 | 
								_umount(dmt, device);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							/* FIXME: hmm READ-ONLY switch should happen in error path */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	if (tps)
 | 
						if (tps)
 | 
				
			||||||
		dm_pool_free(state->mem, tps);
 | 
							dm_pool_free(state->mem, tps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (new_dmt)
 | 
						dmeventd_lvm2_unlock();
 | 
				
			||||||
		dm_task_destroy(new_dmt);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Handle SIGCHLD for a thread */
 | 
					 | 
				
			||||||
static void _sig_child(int signum __attribute__((unused)))
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* empty SIG_IGN */;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Setup handler for SIGCHLD when executing external command
 | 
					 | 
				
			||||||
 * to get quick 'waitpid()' reaction
 | 
					 | 
				
			||||||
 * It will interrupt syscall just like SIGALRM and
 | 
					 | 
				
			||||||
 * invoke process_event().
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void _init_thread_signals(struct dso_state *state)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct sigaction act = { .sa_handler = _sig_child };
 | 
					 | 
				
			||||||
	sigset_t my_sigset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sigemptyset(&my_sigset);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (sigaction(SIGCHLD, &act, NULL))
 | 
					 | 
				
			||||||
		log_warn("WARNING: Failed to set SIGCHLD action.");
 | 
					 | 
				
			||||||
	else if (sigaddset(&my_sigset, SIGCHLD))
 | 
					 | 
				
			||||||
		log_warn("WARNING: Failed to add SIGCHLD to set.");
 | 
					 | 
				
			||||||
	else if (pthread_sigmask(SIG_UNBLOCK, &my_sigset, &state->old_sigset))
 | 
					 | 
				
			||||||
		log_warn("WARNING: Failed to unblock SIGCHLD.");
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		state->restore_sigset = 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void _restore_thread_signals(struct dso_state *state)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (state->restore_sigset &&
 | 
					 | 
				
			||||||
	    pthread_sigmask(SIG_SETMASK, &state->old_sigset, NULL))
 | 
					 | 
				
			||||||
		log_warn("WARNING: Failed to block SIGCHLD.");
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int register_device(const char *device,
 | 
					int register_device(const char *device,
 | 
				
			||||||
		    const char *uuid __attribute__((unused)),
 | 
							    const char *uuid __attribute__((unused)),
 | 
				
			||||||
		    int major __attribute__((unused)),
 | 
							    int major __attribute__((unused)),
 | 
				
			||||||
		    int minor __attribute__((unused)),
 | 
							    int minor __attribute__((unused)),
 | 
				
			||||||
		    void **user)
 | 
							    void **private)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct dm_pool *statemem = NULL;
 | 
				
			||||||
	struct dso_state *state;
 | 
						struct dso_state *state;
 | 
				
			||||||
	char *str;
 | 
					 | 
				
			||||||
	char cmd_str[PATH_MAX + 128 + 2]; /* cmd ' ' vg/lv \0 */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
 | 
						if (!dmeventd_lvm2_init())
 | 
				
			||||||
		goto_bad;
 | 
							goto bad;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dmeventd_lvm2_command(state->mem, cmd_str, sizeof(cmd_str),
 | 
						if (!(statemem = dm_pool_create("thin_pool_state", 2048)) ||
 | 
				
			||||||
				   "_dmeventd_thin_command", device))
 | 
						    !(state = dm_pool_zalloc(statemem, sizeof(*state))) ||
 | 
				
			||||||
		goto_bad;
 | 
						    !dmeventd_lvm2_command(statemem, state->cmd_str,
 | 
				
			||||||
 | 
									   sizeof(state->cmd_str),
 | 
				
			||||||
 | 
									   "lvextend --use-policies",
 | 
				
			||||||
 | 
									   device)) {
 | 
				
			||||||
 | 
							if (statemem)
 | 
				
			||||||
 | 
								dm_pool_destroy(statemem);
 | 
				
			||||||
 | 
							dmeventd_lvm2_exit();
 | 
				
			||||||
 | 
							goto bad;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strncmp(cmd_str, "lvm ", 4) == 0) {
 | 
						state->mem = statemem;
 | 
				
			||||||
		if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str + 4))) {
 | 
						state->metadata_percent_check = CHECK_MINIMUM;
 | 
				
			||||||
			log_error("Failed to copy lvm command.");
 | 
						state->data_percent_check = CHECK_MINIMUM;
 | 
				
			||||||
			goto bad;
 | 
						*private = state;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (cmd_str[0] == '/') {
 | 
					 | 
				
			||||||
		if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str))) {
 | 
					 | 
				
			||||||
			log_error("Failed to copy thin command.");
 | 
					 | 
				
			||||||
			goto bad;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Find last space before 'vg/lv' */
 | 
						syslog(LOG_INFO, "Monitoring thin %s.\n", device);
 | 
				
			||||||
		if (!(str = strrchr(state->cmd_str, ' ')))
 | 
					 | 
				
			||||||
			goto inval;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!(state->argv[0] = dm_pool_strndup(state->mem, state->cmd_str,
 | 
					 | 
				
			||||||
						       str - state->cmd_str))) {
 | 
					 | 
				
			||||||
			log_error("Failed to copy command.");
 | 
					 | 
				
			||||||
			goto bad;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		state->argv[1] = str + 1;  /* 1 argument - vg/lv */
 | 
					 | 
				
			||||||
		_init_thread_signals(state);
 | 
					 | 
				
			||||||
	} else /* Unuspported command format */
 | 
					 | 
				
			||||||
		goto inval;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	state->pid = -1;
 | 
					 | 
				
			||||||
	*user = state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	log_info("Monitoring thin pool %s.", device);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
inval:
 | 
					 | 
				
			||||||
	log_error("Invalid command for monitoring: %s.", cmd_str);
 | 
					 | 
				
			||||||
bad:
 | 
					bad:
 | 
				
			||||||
	log_error("Failed to monitor thin pool %s.", device);
 | 
						syslog(LOG_ERR, "Failed to monitor thin %s.\n", device);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state)
 | 
					 | 
				
			||||||
		dmeventd_lvm2_exit_with_pool(state);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -403,34 +389,13 @@ int unregister_device(const char *device,
 | 
				
			|||||||
		      const char *uuid __attribute__((unused)),
 | 
							      const char *uuid __attribute__((unused)),
 | 
				
			||||||
		      int major __attribute__((unused)),
 | 
							      int major __attribute__((unused)),
 | 
				
			||||||
		      int minor __attribute__((unused)),
 | 
							      int minor __attribute__((unused)),
 | 
				
			||||||
		      void **user)
 | 
							      void **private)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dso_state *state = *user;
 | 
						struct dso_state *state = *private;
 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; !_wait_for_pid(state) && (i < 6); ++i) {
 | 
						syslog(LOG_INFO, "No longer monitoring thin %s.\n", device);
 | 
				
			||||||
		if (i == 0)
 | 
						dm_pool_destroy(state->mem);
 | 
				
			||||||
			/* Give it 2 seconds, then try to terminate & kill it */
 | 
						dmeventd_lvm2_exit();
 | 
				
			||||||
			log_verbose("Child %d still not finished (%s) waiting.",
 | 
					 | 
				
			||||||
				    state->pid, state->cmd_str);
 | 
					 | 
				
			||||||
		else if (i == 3) {
 | 
					 | 
				
			||||||
			log_warn("WARNING: Terminating child %d.", state->pid);
 | 
					 | 
				
			||||||
			kill(state->pid, SIGINT);
 | 
					 | 
				
			||||||
			kill(state->pid, SIGTERM);
 | 
					 | 
				
			||||||
		} else if (i == 5) {
 | 
					 | 
				
			||||||
			log_warn("WARNING: Killing child %d.", state->pid);
 | 
					 | 
				
			||||||
			kill(state->pid, SIGKILL);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sleep(1);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state->pid != -1)
 | 
					 | 
				
			||||||
		log_warn("WARNING: Cannot kill child %d!", state->pid);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	_restore_thread_signals(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dmeventd_lvm2_exit_with_pool(state);
 | 
					 | 
				
			||||||
	log_info("No longer monitoring thin pool %s.", device);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +0,0 @@
 | 
				
			|||||||
process_event
 | 
					 | 
				
			||||||
register_device
 | 
					 | 
				
			||||||
unregister_device
 | 
					 | 
				
			||||||
@@ -1,412 +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 "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 <sys/wait.h>
 | 
					 | 
				
			||||||
#include <stdarg.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* First warning when VDO pool is 80% full. */
 | 
					 | 
				
			||||||
#define WARNING_THRESH	(DM_PERCENT_1 * 80)
 | 
					 | 
				
			||||||
/* Run a check every 5%. */
 | 
					 | 
				
			||||||
#define CHECK_STEP	(DM_PERCENT_1 *  5)
 | 
					 | 
				
			||||||
/* Do not bother checking VDO pool is less than 50% full. */
 | 
					 | 
				
			||||||
#define CHECK_MINIMUM	(DM_PERCENT_1 * 50)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define MAX_FAILS	(256)  /* ~42 mins between cmd call retry with 10s delay */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define VDO_DEBUG 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct dso_state {
 | 
					 | 
				
			||||||
	struct dm_pool *mem;
 | 
					 | 
				
			||||||
	int percent_check;
 | 
					 | 
				
			||||||
	int percent;
 | 
					 | 
				
			||||||
	uint64_t known_data_size;
 | 
					 | 
				
			||||||
	unsigned fails;
 | 
					 | 
				
			||||||
	unsigned max_fails;
 | 
					 | 
				
			||||||
	int restore_sigset;
 | 
					 | 
				
			||||||
	sigset_t old_sigset;
 | 
					 | 
				
			||||||
	pid_t pid;
 | 
					 | 
				
			||||||
	char *argv[3];
 | 
					 | 
				
			||||||
	const char *cmd_str;
 | 
					 | 
				
			||||||
	const char *name;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DM_EVENT_LOG_FN("vdo")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int _run_command(struct dso_state *state)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	char val[16];
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Mark for possible lvm2 command we are running from dmeventd
 | 
					 | 
				
			||||||
	 * lvm2 will not try to talk back to dmeventd while processing it */
 | 
					 | 
				
			||||||
	(void) setenv("LVM_RUN_BY_DMEVENTD", "1", 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state->percent) {
 | 
					 | 
				
			||||||
		/* Prepare some known data to env vars for easy use */
 | 
					 | 
				
			||||||
		if (dm_snprintf(val, sizeof(val), "%d",
 | 
					 | 
				
			||||||
				state->percent / DM_PERCENT_1) != -1)
 | 
					 | 
				
			||||||
			(void) setenv("DMEVENTD_VDO_POOL", val, 1);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		/* For an error event it's for a user to check status and decide */
 | 
					 | 
				
			||||||
		log_debug("Error event processing.");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	log_verbose("Executing command: %s", state->cmd_str);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* TODO:
 | 
					 | 
				
			||||||
	 *   Support parallel run of 'task' and it's waitpid maintainence
 | 
					 | 
				
			||||||
	 *   ATM we can't handle signaling of  SIGALRM
 | 
					 | 
				
			||||||
	 *   as signalling is not allowed while 'process_event()' is running
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (!(state->pid = fork())) {
 | 
					 | 
				
			||||||
		/* child */
 | 
					 | 
				
			||||||
		(void) close(0);
 | 
					 | 
				
			||||||
		for (i = 3; i < 255; ++i) (void) close(i);
 | 
					 | 
				
			||||||
		execvp(state->argv[0], state->argv);
 | 
					 | 
				
			||||||
		_exit(errno);
 | 
					 | 
				
			||||||
	} else if (state->pid == -1) {
 | 
					 | 
				
			||||||
		log_error("Can't fork command %s.", state->cmd_str);
 | 
					 | 
				
			||||||
		state->fails = 1;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int _use_policy(struct dm_task *dmt, struct dso_state *state)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#if VDO_DEBUG
 | 
					 | 
				
			||||||
	log_debug("dmeventd executes: %s.", state->cmd_str);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	if (state->argv[0])
 | 
					 | 
				
			||||||
		return _run_command(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
 | 
					 | 
				
			||||||
		log_error("Failed command for %s.", dm_task_get_name(dmt));
 | 
					 | 
				
			||||||
		state->fails = 1;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	state->fails = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Check if executed command has finished
 | 
					 | 
				
			||||||
 * Only 1 command may run */
 | 
					 | 
				
			||||||
static int _wait_for_pid(struct dso_state *state)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int status = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state->pid == -1)
 | 
					 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!waitpid(state->pid, &status, WNOHANG))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Wait for finish */
 | 
					 | 
				
			||||||
	if (WIFEXITED(status)) {
 | 
					 | 
				
			||||||
		log_verbose("Child %d exited with status %d.",
 | 
					 | 
				
			||||||
			    state->pid, WEXITSTATUS(status));
 | 
					 | 
				
			||||||
		state->fails = WEXITSTATUS(status) ? 1 : 0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		if (WIFSIGNALED(status))
 | 
					 | 
				
			||||||
			log_verbose("Child %d was terminated with status %d.",
 | 
					 | 
				
			||||||
				    state->pid, WTERMSIG(status));
 | 
					 | 
				
			||||||
		state->fails = 1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	state->pid = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void process_event(struct dm_task *dmt,
 | 
					 | 
				
			||||||
		   enum dm_event_mask event __attribute__((unused)),
 | 
					 | 
				
			||||||
		   void **user)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const char *device = dm_task_get_name(dmt);
 | 
					 | 
				
			||||||
	struct dso_state *state = *user;
 | 
					 | 
				
			||||||
	void *next = NULL;
 | 
					 | 
				
			||||||
	uint64_t start, length;
 | 
					 | 
				
			||||||
	char *target_type = NULL;
 | 
					 | 
				
			||||||
	char *params;
 | 
					 | 
				
			||||||
	int needs_policy = 0;
 | 
					 | 
				
			||||||
	struct dm_task *new_dmt = NULL;
 | 
					 | 
				
			||||||
	struct dm_vdo_status_parse_result vdop = { .status = NULL };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if VDO_DEBUG
 | 
					 | 
				
			||||||
	log_debug("Watch for VDO %s:%.2f%%.", state->name,
 | 
					 | 
				
			||||||
		  dm_percent_to_round_float(state->percent_check, 2));
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	if (!_wait_for_pid(state)) {
 | 
					 | 
				
			||||||
		log_warn("WARNING: Skipping event, child %d is still running (%s).",
 | 
					 | 
				
			||||||
			 state->pid, state->cmd_str);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (event & DM_EVENT_DEVICE_ERROR) {
 | 
					 | 
				
			||||||
#if VDO_DEBUG
 | 
					 | 
				
			||||||
		log_debug("VDO event error.");
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		/* Error -> no need to check and do instant resize */
 | 
					 | 
				
			||||||
		state->percent = 0;
 | 
					 | 
				
			||||||
		if (_use_policy(dmt, state))
 | 
					 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		stack;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS)))
 | 
					 | 
				
			||||||
			goto_out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt)))
 | 
					 | 
				
			||||||
			goto_out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Non-blocking status read */
 | 
					 | 
				
			||||||
		if (!dm_task_no_flush(new_dmt))
 | 
					 | 
				
			||||||
			log_warn("WARNING: Can't set no_flush for dm status.");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!dm_task_run(new_dmt))
 | 
					 | 
				
			||||||
			goto_out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		dmt = new_dmt;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!target_type || (strcmp(target_type, "vdo") != 0)) {
 | 
					 | 
				
			||||||
		log_error("Invalid target type.");
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!dm_vdo_status_parse(state->mem, params, &vdop)) {
 | 
					 | 
				
			||||||
		log_error("Failed to parse status.");
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	state->percent = dm_make_percent(vdop.status->used_blocks,
 | 
					 | 
				
			||||||
					 vdop.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);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* VDO pool size had changed. Clear the threshold. */
 | 
					 | 
				
			||||||
	if (state->known_data_size != vdop.status->total_blocks) {
 | 
					 | 
				
			||||||
		state->percent_check = CHECK_MINIMUM;
 | 
					 | 
				
			||||||
		state->known_data_size = vdop.status->total_blocks;
 | 
					 | 
				
			||||||
		state->fails = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Trigger action when threshold boundary is exceeded.
 | 
					 | 
				
			||||||
	 * Report 80% threshold warning when it's used above 80%.
 | 
					 | 
				
			||||||
	 * Only 100% is exception as it cannot be surpased so policy
 | 
					 | 
				
			||||||
	 * action is called for:  >50%, >55% ... >95%, 100%
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if ((state->percent > WARNING_THRESH) &&
 | 
					 | 
				
			||||||
	    (state->percent > state->percent_check))
 | 
					 | 
				
			||||||
		log_warn("WARNING: VDO %s %s is now %.2f%% full.",
 | 
					 | 
				
			||||||
			 state->name, device,
 | 
					 | 
				
			||||||
			 dm_percent_to_round_float(state->percent, 2));
 | 
					 | 
				
			||||||
	if (state->percent > CHECK_MINIMUM) {
 | 
					 | 
				
			||||||
		/* Run action when usage raised more than CHECK_STEP since the last time */
 | 
					 | 
				
			||||||
		if (state->percent > state->percent_check)
 | 
					 | 
				
			||||||
			needs_policy = 1;
 | 
					 | 
				
			||||||
		state->percent_check = (state->percent / CHECK_STEP + 1) * CHECK_STEP;
 | 
					 | 
				
			||||||
		if (state->percent_check == DM_PERCENT_100)
 | 
					 | 
				
			||||||
			state->percent_check--; /* Can't get bigger then 100% */
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		state->percent_check = CHECK_MINIMUM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached.
 | 
					 | 
				
			||||||
	 * Avoids too high number of error retries, yet shows some status messages in log regularly.
 | 
					 | 
				
			||||||
	 * i.e. PV could have been pvmoved and VG/LV was locked for a while...
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (state->fails) {
 | 
					 | 
				
			||||||
		if (state->fails++ <= state->max_fails) {
 | 
					 | 
				
			||||||
			log_debug("Postponing frequently failing policy (%u <= %u).",
 | 
					 | 
				
			||||||
				  state->fails - 1, state->max_fails);
 | 
					 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (state->max_fails < MAX_FAILS)
 | 
					 | 
				
			||||||
			state->max_fails <<= 1;
 | 
					 | 
				
			||||||
		state->fails = needs_policy = 1; /* Retry failing command */
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		state->max_fails = 1; /* Reset on success */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Handle SIGCHLD for a thread */
 | 
					 | 
				
			||||||
static void _sig_child(int signum __attribute__((unused)))
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* empty SIG_IGN */;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Setup handler for SIGCHLD when executing external command
 | 
					 | 
				
			||||||
 * to get quick 'waitpid()' reaction
 | 
					 | 
				
			||||||
 * It will interrupt syscall just like SIGALRM and
 | 
					 | 
				
			||||||
 * invoke process_event().
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void _init_thread_signals(struct dso_state *state)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct sigaction act = { .sa_handler = _sig_child };
 | 
					 | 
				
			||||||
	sigset_t my_sigset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sigemptyset(&my_sigset);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (sigaction(SIGCHLD, &act, NULL))
 | 
					 | 
				
			||||||
		log_warn("WARNING: Failed to set SIGCHLD action.");
 | 
					 | 
				
			||||||
	else if (sigaddset(&my_sigset, SIGCHLD))
 | 
					 | 
				
			||||||
		log_warn("WARNING: Failed to add SIGCHLD to set.");
 | 
					 | 
				
			||||||
	else if (pthread_sigmask(SIG_UNBLOCK, &my_sigset, &state->old_sigset))
 | 
					 | 
				
			||||||
		log_warn("WARNING: Failed to unblock SIGCHLD.");
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		state->restore_sigset = 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void _restore_thread_signals(struct dso_state *state)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (state->restore_sigset &&
 | 
					 | 
				
			||||||
	    pthread_sigmask(SIG_SETMASK, &state->old_sigset, NULL))
 | 
					 | 
				
			||||||
		log_warn("WARNING: Failed to block SIGCHLD.");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int register_device(const char *device,
 | 
					 | 
				
			||||||
		    const char *uuid,
 | 
					 | 
				
			||||||
		    int major __attribute__((unused)),
 | 
					 | 
				
			||||||
		    int minor __attribute__((unused)),
 | 
					 | 
				
			||||||
		    void **user)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct dso_state *state;
 | 
					 | 
				
			||||||
	const char *cmd;
 | 
					 | 
				
			||||||
	char *str;
 | 
					 | 
				
			||||||
	char cmd_str[PATH_MAX + 128 + 2]; /* cmd ' ' vg/lv \0 */
 | 
					 | 
				
			||||||
        const char *name = "pool";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!dmeventd_lvm2_init_with_pool("vdo_pool_state", state))
 | 
					 | 
				
			||||||
		goto_bad;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	state->cmd_str = "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Search for command for LVM- prefixed devices only */
 | 
					 | 
				
			||||||
	cmd = (strncmp(uuid, "LVM-", 4) == 0) ? "_dmeventd_vdo_command" : "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!dmeventd_lvm2_command(state->mem, cmd_str, sizeof(cmd_str), cmd, device))
 | 
					 | 
				
			||||||
		goto_bad;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (strncmp(cmd_str, "lvm ", 4) == 0) {
 | 
					 | 
				
			||||||
		if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str + 4))) {
 | 
					 | 
				
			||||||
			log_error("Failed to copy lvm VDO command.");
 | 
					 | 
				
			||||||
				goto bad;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (cmd_str[0] == '/') {
 | 
					 | 
				
			||||||
		if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str))) {
 | 
					 | 
				
			||||||
			log_error("Failed to copy VDO command.");
 | 
					 | 
				
			||||||
			goto bad;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Find last space before 'vg/lv' */
 | 
					 | 
				
			||||||
		if (!(str = strrchr(state->cmd_str, ' ')))
 | 
					 | 
				
			||||||
			goto inval;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!(state->argv[0] = dm_pool_strndup(state->mem, state->cmd_str,
 | 
					 | 
				
			||||||
						       str - state->cmd_str))) {
 | 
					 | 
				
			||||||
			log_error("Failed to copy command.");
 | 
					 | 
				
			||||||
			goto bad;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		state->argv[1] = str + 1;  /* 1 argument - vg/lv */
 | 
					 | 
				
			||||||
		_init_thread_signals(state);
 | 
					 | 
				
			||||||
	} else if (cmd[0] == 0) {
 | 
					 | 
				
			||||||
		state->name = "volume"; /* What to use with 'others?' */
 | 
					 | 
				
			||||||
	} else/* Unuspported command format */
 | 
					 | 
				
			||||||
		goto inval;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	state->pid = -1;
 | 
					 | 
				
			||||||
	state->name = name;
 | 
					 | 
				
			||||||
	*user = state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	log_info("Monitoring VDO %s %s.", name, device);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
inval:
 | 
					 | 
				
			||||||
	log_error("Invalid command for monitoring: %s.", cmd_str);
 | 
					 | 
				
			||||||
bad:
 | 
					 | 
				
			||||||
	log_error("Failed to monitor VDO %s %s.", name, device);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state)
 | 
					 | 
				
			||||||
		dmeventd_lvm2_exit_with_pool(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int unregister_device(const char *device,
 | 
					 | 
				
			||||||
		      const char *uuid __attribute__((unused)),
 | 
					 | 
				
			||||||
		      int major __attribute__((unused)),
 | 
					 | 
				
			||||||
		      int minor __attribute__((unused)),
 | 
					 | 
				
			||||||
		      void **user)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct dso_state *state = *user;
 | 
					 | 
				
			||||||
	const char *name = state->name;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; !_wait_for_pid(state) && (i < 6); ++i) {
 | 
					 | 
				
			||||||
		if (i == 0)
 | 
					 | 
				
			||||||
			/* Give it 2 seconds, then try to terminate & kill it */
 | 
					 | 
				
			||||||
			log_verbose("Child %d still not finished (%s) waiting.",
 | 
					 | 
				
			||||||
				    state->pid, state->cmd_str);
 | 
					 | 
				
			||||||
		else if (i == 3) {
 | 
					 | 
				
			||||||
			log_warn("WARNING: Terminating child %d.", state->pid);
 | 
					 | 
				
			||||||
			kill(state->pid, SIGINT);
 | 
					 | 
				
			||||||
			kill(state->pid, SIGTERM);
 | 
					 | 
				
			||||||
		} else if (i == 5) {
 | 
					 | 
				
			||||||
			log_warn("WARNING: Killing child %d.", state->pid);
 | 
					 | 
				
			||||||
			kill(state->pid, SIGKILL);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sleep(1);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state->pid != -1)
 | 
					 | 
				
			||||||
		log_warn("WARNING: Cannot kill child %d!", state->pid);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	_restore_thread_signals(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dmeventd_lvm2_exit_with_pool(state);
 | 
					 | 
				
			||||||
	log_info("No longer monitoring VDO %s %s.", name, device);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										4
									
								
								daemons/lvmdbusd/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								daemons/lvmdbusd/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +0,0 @@
 | 
				
			|||||||
path.py
 | 
					 | 
				
			||||||
lvmdbusd
 | 
					 | 
				
			||||||
lvmdb.py
 | 
					 | 
				
			||||||
lvm_shell_proxy.py
 | 
					 | 
				
			||||||
@@ -1,73 +0,0 @@
 | 
				
			|||||||
#
 | 
					 | 
				
			||||||
# Copyright (C) 2016 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@
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
lvmdbusdir = $(python3dir)/lvmdbusd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
LVMDBUS_SRCDIR_FILES = \
 | 
					 | 
				
			||||||
	automatedproperties.py \
 | 
					 | 
				
			||||||
	background.py \
 | 
					 | 
				
			||||||
	cfg.py \
 | 
					 | 
				
			||||||
	cmdhandler.py \
 | 
					 | 
				
			||||||
	fetch.py \
 | 
					 | 
				
			||||||
	job.py \
 | 
					 | 
				
			||||||
	loader.py \
 | 
					 | 
				
			||||||
	lv.py \
 | 
					 | 
				
			||||||
	main.py \
 | 
					 | 
				
			||||||
	manager.py \
 | 
					 | 
				
			||||||
	objectmanager.py \
 | 
					 | 
				
			||||||
	pv.py \
 | 
					 | 
				
			||||||
	request.py \
 | 
					 | 
				
			||||||
	state.py \
 | 
					 | 
				
			||||||
	udevwatch.py \
 | 
					 | 
				
			||||||
	utils.py \
 | 
					 | 
				
			||||||
	vg.py \
 | 
					 | 
				
			||||||
	__init__.py
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
LVMDBUS_BUILDDIR_FILES = \
 | 
					 | 
				
			||||||
	lvmdb.py \
 | 
					 | 
				
			||||||
	lvm_shell_proxy.py \
 | 
					 | 
				
			||||||
	path.py
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
LVMDBUSD = lvmdbusd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CLEAN_DIRS += __pycache__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
include $(top_builddir)/make.tmpl
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.PHONY: install_lvmdbusd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
all:
 | 
					 | 
				
			||||||
	$(Q) 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_lvm2: install_lvmdbusd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install: install_lvm2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DISTCLEAN_TARGETS+= \
 | 
					 | 
				
			||||||
	$(LVMDBUS_BUILDDIR_FILES) \
 | 
					 | 
				
			||||||
	$(LVMDBUSD)
 | 
					 | 
				
			||||||
@@ -1,10 +0,0 @@
 | 
				
			|||||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This copyrighted material is made available to anyone wishing to use,
 | 
					 | 
				
			||||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
					 | 
				
			||||||
# 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, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from .main import main
 | 
					 | 
				
			||||||
@@ -1,194 +0,0 @@
 | 
				
			|||||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This copyrighted material is made available to anyone wishing to use,
 | 
					 | 
				
			||||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
					 | 
				
			||||||
# 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, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dbus
 | 
					 | 
				
			||||||
import dbus.service
 | 
					 | 
				
			||||||
from . import cfg
 | 
					 | 
				
			||||||
from .utils import get_properties, add_properties, get_object_property_diff, \
 | 
					 | 
				
			||||||
	log_debug
 | 
					 | 
				
			||||||
from .state import State
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# noinspection PyPep8Naming,PyUnresolvedReferences
 | 
					 | 
				
			||||||
class AutomatedProperties(dbus.service.Object):
 | 
					 | 
				
			||||||
	"""
 | 
					 | 
				
			||||||
	This class implements the needed interfaces for:
 | 
					 | 
				
			||||||
	org.freedesktop.DBus.Properties
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Other classes inherit from it to get the same behavior
 | 
					 | 
				
			||||||
	"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __init__(self, object_path, search_method=None):
 | 
					 | 
				
			||||||
		dbus.service.Object.__init__(self, cfg.bus, object_path)
 | 
					 | 
				
			||||||
		self._ap_interface = []
 | 
					 | 
				
			||||||
		self._ap_o_path = object_path
 | 
					 | 
				
			||||||
		self._ap_search_method = search_method
 | 
					 | 
				
			||||||
		self.state = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def dbus_object_path(self):
 | 
					 | 
				
			||||||
		return self._ap_o_path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def emit_data(self):
 | 
					 | 
				
			||||||
		props = {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for i in self.interface():
 | 
					 | 
				
			||||||
			props[i] = AutomatedProperties._get_all_prop(self, i)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return self._ap_o_path, props
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def set_interface(self, interface):
 | 
					 | 
				
			||||||
		"""
 | 
					 | 
				
			||||||
		With inheritance we can't easily tell what interfaces a class provides
 | 
					 | 
				
			||||||
		so we will have each class that implements an interface tell the
 | 
					 | 
				
			||||||
		base AutomatedProperties what it is they do provide.  This is kind of
 | 
					 | 
				
			||||||
		clunky and perhaps we can figure out a better way to do this later.
 | 
					 | 
				
			||||||
		:param interface:       An interface the object supports
 | 
					 | 
				
			||||||
		:return:
 | 
					 | 
				
			||||||
		"""
 | 
					 | 
				
			||||||
		if interface not in self._ap_interface:
 | 
					 | 
				
			||||||
			self._ap_interface.append(interface)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# noinspection PyUnusedLocal
 | 
					 | 
				
			||||||
	def interface(self, all_interfaces=False):
 | 
					 | 
				
			||||||
		if all_interfaces:
 | 
					 | 
				
			||||||
			cpy = list(self._ap_interface)
 | 
					 | 
				
			||||||
			cpy.extend(
 | 
					 | 
				
			||||||
				["org.freedesktop.DBus.Introspectable",
 | 
					 | 
				
			||||||
					"org.freedesktop.DBus.Properties"])
 | 
					 | 
				
			||||||
			return cpy
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return self._ap_interface
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@staticmethod
 | 
					 | 
				
			||||||
	def _get_prop(obj, interface_name, property_name):
 | 
					 | 
				
			||||||
		value = getattr(obj, property_name)
 | 
					 | 
				
			||||||
		# Note: If we get an exception in this handler we won't know about it,
 | 
					 | 
				
			||||||
		# only the side effect of no returned value!
 | 
					 | 
				
			||||||
		log_debug('Get (%s), type (%s), value(%s)' %
 | 
					 | 
				
			||||||
					(property_name, str(type(value)), str(value)))
 | 
					 | 
				
			||||||
		return value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# Properties
 | 
					 | 
				
			||||||
	# noinspection PyUnusedLocal
 | 
					 | 
				
			||||||
	@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
 | 
					 | 
				
			||||||
							in_signature='ss', out_signature='v',
 | 
					 | 
				
			||||||
							async_callbacks=('cb', 'cbe'))
 | 
					 | 
				
			||||||
	def Get(self, interface_name, property_name, cb, cbe):
 | 
					 | 
				
			||||||
		# Note: If we get an exception in this handler we won't know about it,
 | 
					 | 
				
			||||||
		# only the side effect of no returned value!
 | 
					 | 
				
			||||||
		r = cfg.create_request_entry(
 | 
					 | 
				
			||||||
			-1, AutomatedProperties._get_prop,
 | 
					 | 
				
			||||||
			(self, interface_name, property_name),
 | 
					 | 
				
			||||||
			cb, cbe, False)
 | 
					 | 
				
			||||||
		cfg.worker_q.put(r)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@staticmethod
 | 
					 | 
				
			||||||
	def _get_all_prop(obj, interface_name):
 | 
					 | 
				
			||||||
		if interface_name in obj.interface(True):
 | 
					 | 
				
			||||||
			# Using introspection, lets build this dynamically
 | 
					 | 
				
			||||||
			properties = get_properties(obj)
 | 
					 | 
				
			||||||
			if interface_name in properties:
 | 
					 | 
				
			||||||
				return properties[interface_name][1]
 | 
					 | 
				
			||||||
			return {}
 | 
					 | 
				
			||||||
		raise dbus.exceptions.DBusException(
 | 
					 | 
				
			||||||
			obj._ap_interface,
 | 
					 | 
				
			||||||
			'The object %s does not implement the %s interface'
 | 
					 | 
				
			||||||
			% (obj.__class__, interface_name))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
 | 
					 | 
				
			||||||
							in_signature='s', out_signature='a{sv}',
 | 
					 | 
				
			||||||
							async_callbacks=('cb', 'cbe'))
 | 
					 | 
				
			||||||
	def GetAll(self, interface_name, cb, cbe):
 | 
					 | 
				
			||||||
		r = cfg.create_request_entry(
 | 
					 | 
				
			||||||
			-1, AutomatedProperties._get_all_prop,
 | 
					 | 
				
			||||||
			(self, interface_name),
 | 
					 | 
				
			||||||
			cb, cbe, False)
 | 
					 | 
				
			||||||
		cfg.worker_q.put(r)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
 | 
					 | 
				
			||||||
							in_signature='ssv')
 | 
					 | 
				
			||||||
	def Set(self, interface_name, property_name, new_value):
 | 
					 | 
				
			||||||
		setattr(self, property_name, new_value)
 | 
					 | 
				
			||||||
		self.PropertiesChanged(interface_name,
 | 
					 | 
				
			||||||
								{property_name: new_value}, [])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# As dbus-python does not support introspection for properties we will
 | 
					 | 
				
			||||||
	# get the autogenerated xml and then add our wanted properties to it.
 | 
					 | 
				
			||||||
	@dbus.service.method(dbus_interface=dbus.INTROSPECTABLE_IFACE,
 | 
					 | 
				
			||||||
							out_signature='s')
 | 
					 | 
				
			||||||
	def Introspect(self):
 | 
					 | 
				
			||||||
		r = dbus.service.Object.Introspect(self, self._ap_o_path, cfg.bus)
 | 
					 | 
				
			||||||
		# Look at the properties in the class
 | 
					 | 
				
			||||||
		props = get_properties(self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for int_f, v in props.items():
 | 
					 | 
				
			||||||
			r = add_properties(r, int_f, v[0])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return r
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@dbus.service.signal(dbus_interface=dbus.PROPERTIES_IFACE,
 | 
					 | 
				
			||||||
							signature='sa{sv}as')
 | 
					 | 
				
			||||||
	def PropertiesChanged(self, interface_name, changed_properties,
 | 
					 | 
				
			||||||
							invalidated_properties):
 | 
					 | 
				
			||||||
		log_debug(('SIGNAL: PropertiesChanged(%s, %s, %s, %s)' %
 | 
					 | 
				
			||||||
					(str(self._ap_o_path), str(interface_name),
 | 
					 | 
				
			||||||
					str(changed_properties), str(invalidated_properties))))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def refresh(self, search_key=None, object_state=None):
 | 
					 | 
				
			||||||
		"""
 | 
					 | 
				
			||||||
		Take the values (properties) of an object and update them with what
 | 
					 | 
				
			||||||
		lvm currently has.  You can either fetch the new ones or supply the
 | 
					 | 
				
			||||||
		new state to be updated with
 | 
					 | 
				
			||||||
		:param search_key: The value to use to search for
 | 
					 | 
				
			||||||
		:param object_state: Use this as the new object state
 | 
					 | 
				
			||||||
		"""
 | 
					 | 
				
			||||||
		num_changed = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# If we can't do a lookup, bail now, this happens if we blindly walk
 | 
					 | 
				
			||||||
		# through all dbus objects as some don't have a search method, like
 | 
					 | 
				
			||||||
		# 'Manager' object.
 | 
					 | 
				
			||||||
		if not self._ap_search_method:
 | 
					 | 
				
			||||||
			return 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		search = self.lvm_id
 | 
					 | 
				
			||||||
		if search_key:
 | 
					 | 
				
			||||||
			search = search_key
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Either we have the new object state or we need to go fetch it
 | 
					 | 
				
			||||||
		if object_state:
 | 
					 | 
				
			||||||
			new_state = object_state
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			new_state = self._ap_search_method([search])[0]
 | 
					 | 
				
			||||||
			assert isinstance(new_state, State)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		assert new_state
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# When we refresh an object the object identifiers might have changed
 | 
					 | 
				
			||||||
		# because LVM allows the user to change them (name & uuid), thus if
 | 
					 | 
				
			||||||
		# they have changed we need to update the object manager so that
 | 
					 | 
				
			||||||
		# look-ups will happen correctly
 | 
					 | 
				
			||||||
		old_id = self.state.identifiers()
 | 
					 | 
				
			||||||
		new_id = new_state.identifiers()
 | 
					 | 
				
			||||||
		if old_id[0] != new_id[0] or old_id[1] != new_id[1]:
 | 
					 | 
				
			||||||
			cfg.om.lookup_update(self, new_id[0], new_id[1])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Grab the properties values, then replace the state of the object
 | 
					 | 
				
			||||||
		# and retrieve the new values.
 | 
					 | 
				
			||||||
		o_prop = get_properties(self)
 | 
					 | 
				
			||||||
		self.state = new_state
 | 
					 | 
				
			||||||
		n_prop = get_properties(self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		changed = get_object_property_diff(o_prop, n_prop)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if changed:
 | 
					 | 
				
			||||||
			for int_f, v in changed.items():
 | 
					 | 
				
			||||||
				self.PropertiesChanged(int_f, v, [])
 | 
					 | 
				
			||||||
			num_changed += 1
 | 
					 | 
				
			||||||
		return num_changed
 | 
					 | 
				
			||||||
@@ -1,163 +0,0 @@
 | 
				
			|||||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This copyrighted material is made available to anyone wishing to use,
 | 
					 | 
				
			||||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
					 | 
				
			||||||
# 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, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import subprocess
 | 
					 | 
				
			||||||
from . import cfg
 | 
					 | 
				
			||||||
from .cmdhandler import options_to_cli_args, LvmExecutionMeta
 | 
					 | 
				
			||||||
import dbus
 | 
					 | 
				
			||||||
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
 | 
					 | 
				
			||||||
	add_no_notify
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
import threading
 | 
					 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def pv_move_lv_cmd(move_options, lv_full_name,
 | 
					 | 
				
			||||||
					pv_source, pv_source_range, pv_dest_range_list):
 | 
					 | 
				
			||||||
	cmd = ['pvmove', '-i', '1']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(move_options))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if lv_full_name:
 | 
					 | 
				
			||||||
		cmd.extend(['-n', lv_full_name])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pv_range_append(cmd, pv_source, *pv_source_range)
 | 
					 | 
				
			||||||
	pv_dest_ranges(cmd, pv_dest_range_list)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return cmd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def lv_merge_cmd(merge_options, lv_full_name):
 | 
					 | 
				
			||||||
	cmd = ['lvconvert', '--merge', '-i', '1']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(merge_options))
 | 
					 | 
				
			||||||
	cmd.append(lv_full_name)
 | 
					 | 
				
			||||||
	return cmd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _move_merge(interface_name, command, job_state):
 | 
					 | 
				
			||||||
	# We need to execute these command stand alone by forking & exec'ing
 | 
					 | 
				
			||||||
	# the command always as we will be getting periodic output from them on
 | 
					 | 
				
			||||||
	# the status of the long running operation.
 | 
					 | 
				
			||||||
	command.insert(0, cfg.LVM_CMD)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# Instruct lvm to not register an event with us
 | 
					 | 
				
			||||||
	command = add_no_notify(command)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	#(self, start, ended, cmd, ec, stdout_txt, stderr_txt)
 | 
					 | 
				
			||||||
	meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cfg.blackbox.add(meta)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	process = subprocess.Popen(command, stdout=subprocess.PIPE,
 | 
					 | 
				
			||||||
								env=os.environ,
 | 
					 | 
				
			||||||
								stderr=subprocess.PIPE, close_fds=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	log_debug("Background process for %s is %d" %
 | 
					 | 
				
			||||||
				(str(command), process.pid))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	lines_iterator = iter(process.stdout.readline, b"")
 | 
					 | 
				
			||||||
	for line in lines_iterator:
 | 
					 | 
				
			||||||
		line_str = line.decode("utf-8")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Check to see if the line has the correct number of separators
 | 
					 | 
				
			||||||
		try:
 | 
					 | 
				
			||||||
			if line_str.count(':') == 2:
 | 
					 | 
				
			||||||
				(device, ignore, percentage) = line_str.split(':')
 | 
					 | 
				
			||||||
				job_state.Percent = round(
 | 
					 | 
				
			||||||
					float(percentage.strip()[:-1]), 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				# While the move is in progress we need to periodically update
 | 
					 | 
				
			||||||
				# the state to reflect where everything is at.
 | 
					 | 
				
			||||||
				cfg.load()
 | 
					 | 
				
			||||||
		except ValueError:
 | 
					 | 
				
			||||||
			log_error("Trying to parse percentage which failed for %s" %
 | 
					 | 
				
			||||||
				line_str)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	out = process.communicate()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	with meta.lock:
 | 
					 | 
				
			||||||
		meta.ended = time.time()
 | 
					 | 
				
			||||||
		meta.ec = process.returncode
 | 
					 | 
				
			||||||
		meta.stderr_txt = out[1]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if process.returncode == 0:
 | 
					 | 
				
			||||||
		job_state.Percent = 100
 | 
					 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		raise dbus.exceptions.DBusException(
 | 
					 | 
				
			||||||
			interface_name,
 | 
					 | 
				
			||||||
			'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cfg.load()
 | 
					 | 
				
			||||||
	return '/'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def move(interface_name, lv_name, pv_src_obj, pv_source_range,
 | 
					 | 
				
			||||||
			pv_dests_and_ranges, move_options, job_state):
 | 
					 | 
				
			||||||
	"""
 | 
					 | 
				
			||||||
	Common code for the pvmove handling.
 | 
					 | 
				
			||||||
	:param interface_name:  What dbus interface we are providing for
 | 
					 | 
				
			||||||
	:param lv_name:     Optional (None or name of LV to move)
 | 
					 | 
				
			||||||
	:param pv_src_obj:  dbus object patch for source PV
 | 
					 | 
				
			||||||
	:param pv_source_range: (0,0 to ignore, else start, end segments)
 | 
					 | 
				
			||||||
	:param pv_dests_and_ranges: Array of PV object paths and start/end segs
 | 
					 | 
				
			||||||
	:param move_options: Hash with optional arguments
 | 
					 | 
				
			||||||
	:param job_state: Used to convey information about jobs between processes
 | 
					 | 
				
			||||||
	:return: '/' When complete, the empty object path
 | 
					 | 
				
			||||||
	"""
 | 
					 | 
				
			||||||
	pv_dests = []
 | 
					 | 
				
			||||||
	pv_src = cfg.om.get_object_by_path(pv_src_obj)
 | 
					 | 
				
			||||||
	if pv_src:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Check to see if we are handling a move to a specific
 | 
					 | 
				
			||||||
		# destination(s)
 | 
					 | 
				
			||||||
		if len(pv_dests_and_ranges):
 | 
					 | 
				
			||||||
			for pr in pv_dests_and_ranges:
 | 
					 | 
				
			||||||
				pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
 | 
					 | 
				
			||||||
				if not pv_dbus_obj:
 | 
					 | 
				
			||||||
					raise dbus.exceptions.DBusException(
 | 
					 | 
				
			||||||
						interface_name,
 | 
					 | 
				
			||||||
						'PV Destination (%s) not found' % pr[0])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		cmd = pv_move_lv_cmd(move_options,
 | 
					 | 
				
			||||||
								lv_name,
 | 
					 | 
				
			||||||
								pv_src.lvm_id,
 | 
					 | 
				
			||||||
								pv_source_range,
 | 
					 | 
				
			||||||
								pv_dests)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return _move_merge(interface_name, cmd, job_state)
 | 
					 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		raise dbus.exceptions.DBusException(
 | 
					 | 
				
			||||||
			interface_name, 'pv_src_obj (%s) not found' % pv_src_obj)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def merge(interface_name, lv_uuid, lv_name, merge_options, job_state):
 | 
					 | 
				
			||||||
	# Make sure we have a dbus object representing it
 | 
					 | 
				
			||||||
	dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
 | 
					 | 
				
			||||||
	if dbo:
 | 
					 | 
				
			||||||
		cmd = lv_merge_cmd(merge_options, dbo.lvm_id)
 | 
					 | 
				
			||||||
		return _move_merge(interface_name, cmd, job_state)
 | 
					 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		raise dbus.exceptions.DBusException(
 | 
					 | 
				
			||||||
			interface_name,
 | 
					 | 
				
			||||||
			'LV with uuid %s and name %s not present!' % (lv_uuid, lv_name))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _run_cmd(req):
 | 
					 | 
				
			||||||
	log_debug(
 | 
					 | 
				
			||||||
		"_run_cmd: Running method: %s with args %s" %
 | 
					 | 
				
			||||||
		(str(req.method), str(req.arguments)))
 | 
					 | 
				
			||||||
	req.run_cmd()
 | 
					 | 
				
			||||||
	log_debug("_run_cmd: complete!")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def cmd_runner(request):
 | 
					 | 
				
			||||||
	t = threading.Thread(target=_run_cmd, args=(request,),
 | 
					 | 
				
			||||||
							name="cmd_runner %s" % str(request.method))
 | 
					 | 
				
			||||||
	t.start()
 | 
					 | 
				
			||||||
@@ -1,106 +0,0 @@
 | 
				
			|||||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This copyrighted material is made available to anyone wishing to use,
 | 
					 | 
				
			||||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
					 | 
				
			||||||
# 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, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
import multiprocessing
 | 
					 | 
				
			||||||
import queue
 | 
					 | 
				
			||||||
import itertools
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from lvmdbusd import path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# This is the global object manager
 | 
					 | 
				
			||||||
om = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# This is the global bus connection
 | 
					 | 
				
			||||||
bus = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Command line args
 | 
					 | 
				
			||||||
args = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Set to true if we are depending on external events for updates
 | 
					 | 
				
			||||||
got_external_event = False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Shared state variable across all processes
 | 
					 | 
				
			||||||
run = multiprocessing.Value('i', 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# If this is set to true, the current setup support lvm shell and we are
 | 
					 | 
				
			||||||
# running in that mode of operation
 | 
					 | 
				
			||||||
SHELL_IN_USE = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Lock used by pprint
 | 
					 | 
				
			||||||
stdout_lock = multiprocessing.Lock()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
worker_q = queue.Queue()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Main event loop
 | 
					 | 
				
			||||||
loop = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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'
 | 
					 | 
				
			||||||
MANAGER_INTERFACE = BASE_INTERFACE + '.Manager'
 | 
					 | 
				
			||||||
JOB_INTERFACE = BASE_INTERFACE + '.Job'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
BASE_OBJ_PATH = '/' + BASE_INTERFACE.replace('.', '/')
 | 
					 | 
				
			||||||
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'
 | 
					 | 
				
			||||||
JOB_OBJ_PATH = BASE_OBJ_PATH + '/Job'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Counters for object path generation
 | 
					 | 
				
			||||||
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()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Used to prevent circular imports...
 | 
					 | 
				
			||||||
load = None
 | 
					 | 
				
			||||||
event = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Boolean to denote if lvm supports VDO integration
 | 
					 | 
				
			||||||
vdo_support = False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Global cached state
 | 
					 | 
				
			||||||
db = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# lvm flight recorder
 | 
					 | 
				
			||||||
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()
 | 
					 | 
				
			||||||
@@ -1,825 +0,0 @@
 | 
				
			|||||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This copyrighted material is made available to anyone wishing to use,
 | 
					 | 
				
			||||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
					 | 
				
			||||||
# 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, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from subprocess import Popen, PIPE
 | 
					 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
import threading
 | 
					 | 
				
			||||||
from itertools import chain
 | 
					 | 
				
			||||||
import collections
 | 
					 | 
				
			||||||
import traceback
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from lvmdbusd import cfg
 | 
					 | 
				
			||||||
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify
 | 
					 | 
				
			||||||
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
try:
 | 
					 | 
				
			||||||
	import simplejson as json
 | 
					 | 
				
			||||||
except ImportError:
 | 
					 | 
				
			||||||
	import json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SEP = '{|}'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
total_time = 0.0
 | 
					 | 
				
			||||||
total_count = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# We need to prevent different threads from using the same lvm shell
 | 
					 | 
				
			||||||
# at the same time.
 | 
					 | 
				
			||||||
cmd_lock = threading.RLock()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class LvmExecutionMeta(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
 | 
					 | 
				
			||||||
		self.lock = threading.RLock()
 | 
					 | 
				
			||||||
		self.start = start
 | 
					 | 
				
			||||||
		self.ended = ended
 | 
					 | 
				
			||||||
		self.cmd = cmd
 | 
					 | 
				
			||||||
		self.ec = ec
 | 
					 | 
				
			||||||
		self.stdout_txt = stdout_txt
 | 
					 | 
				
			||||||
		self.stderr_txt = stderr_txt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __str__(self):
 | 
					 | 
				
			||||||
		with self.lock:
 | 
					 | 
				
			||||||
			return "EC= %d for %s\n" \
 | 
					 | 
				
			||||||
				"STARTED: %f, ENDED: %f\n" \
 | 
					 | 
				
			||||||
				"STDOUT=%s\n" \
 | 
					 | 
				
			||||||
				"STDERR=%s\n" % \
 | 
					 | 
				
			||||||
				(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
 | 
					 | 
				
			||||||
				self.stderr_txt)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class LvmFlightRecorder(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __init__(self, size=16):
 | 
					 | 
				
			||||||
		self.queue = collections.deque(maxlen=size)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def add(self, lvm_exec_meta):
 | 
					 | 
				
			||||||
		self.queue.append(lvm_exec_meta)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def dump(self):
 | 
					 | 
				
			||||||
		with cmd_lock:
 | 
					 | 
				
			||||||
			if len(self.queue):
 | 
					 | 
				
			||||||
				log_error("LVM dbus flight recorder START")
 | 
					 | 
				
			||||||
				for c in reversed(self.queue):
 | 
					 | 
				
			||||||
					log_error(str(c))
 | 
					 | 
				
			||||||
				log_error("LVM dbus flight recorder END")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cfg.blackbox = LvmFlightRecorder()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _debug_c(cmd, exit_code, out):
 | 
					 | 
				
			||||||
	log_error('CMD= %s' % ' '.join(cmd))
 | 
					 | 
				
			||||||
	log_error(("EC= %d" % exit_code))
 | 
					 | 
				
			||||||
	log_error(("STDOUT=\n %s\n" % out[0]))
 | 
					 | 
				
			||||||
	log_error(("STDERR=\n %s\n" % out[1]))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def call_lvm(command, debug=False):
 | 
					 | 
				
			||||||
	"""
 | 
					 | 
				
			||||||
	Call an executable and return a tuple of exitcode, stdout, stderr
 | 
					 | 
				
			||||||
	:param command:     Command to execute
 | 
					 | 
				
			||||||
	:param debug:       Dump debug to stdout
 | 
					 | 
				
			||||||
	"""
 | 
					 | 
				
			||||||
	# print 'STACK:'
 | 
					 | 
				
			||||||
	# for line in traceback.format_stack():
 | 
					 | 
				
			||||||
	#    print line.strip()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# Prepend the full lvm executable so that we can run different versions
 | 
					 | 
				
			||||||
	# in different locations on the same box
 | 
					 | 
				
			||||||
	command.insert(0, cfg.LVM_CMD)
 | 
					 | 
				
			||||||
	command = add_no_notify(command)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
 | 
					 | 
				
			||||||
					env=os.environ)
 | 
					 | 
				
			||||||
	out = process.communicate()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stdout_text = bytes(out[0]).decode("utf-8")
 | 
					 | 
				
			||||||
	stderr_text = bytes(out[1]).decode("utf-8")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if debug or process.returncode != 0:
 | 
					 | 
				
			||||||
		_debug_c(command, process.returncode, (stdout_text, stderr_text))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return process.returncode, stdout_text, stderr_text
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# The actual method which gets called to invoke the lvm command, can vary
 | 
					 | 
				
			||||||
# from forking a new process to using lvm shell
 | 
					 | 
				
			||||||
_t_call = call_lvm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _shell_cfg():
 | 
					 | 
				
			||||||
	global _t_call
 | 
					 | 
				
			||||||
	# noinspection PyBroadException
 | 
					 | 
				
			||||||
	try:
 | 
					 | 
				
			||||||
		lvm_shell = LVMShellProxy()
 | 
					 | 
				
			||||||
		_t_call = lvm_shell.call_lvm
 | 
					 | 
				
			||||||
		cfg.SHELL_IN_USE = lvm_shell
 | 
					 | 
				
			||||||
		return True
 | 
					 | 
				
			||||||
	except Exception:
 | 
					 | 
				
			||||||
		_t_call = call_lvm
 | 
					 | 
				
			||||||
		cfg.SHELL_IN_USE = None
 | 
					 | 
				
			||||||
		log_error(traceback.format_exc())
 | 
					 | 
				
			||||||
		log_error("Unable to utilize lvm shell, dropping back to fork & exec")
 | 
					 | 
				
			||||||
		return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def set_execution(shell):
 | 
					 | 
				
			||||||
	global _t_call
 | 
					 | 
				
			||||||
	with cmd_lock:
 | 
					 | 
				
			||||||
		# If the user requested lvm shell and we are currently setup that
 | 
					 | 
				
			||||||
		# way, just return
 | 
					 | 
				
			||||||
		if cfg.SHELL_IN_USE and shell:
 | 
					 | 
				
			||||||
			return True
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			if not shell and cfg.SHELL_IN_USE:
 | 
					 | 
				
			||||||
				cfg.SHELL_IN_USE.exit_shell()
 | 
					 | 
				
			||||||
				cfg.SHELL_IN_USE = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		_t_call = call_lvm
 | 
					 | 
				
			||||||
		if shell:
 | 
					 | 
				
			||||||
			if cfg.args.use_json:
 | 
					 | 
				
			||||||
				return _shell_cfg()
 | 
					 | 
				
			||||||
			else:
 | 
					 | 
				
			||||||
				return False
 | 
					 | 
				
			||||||
		return True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def time_wrapper(command, debug=False):
 | 
					 | 
				
			||||||
	global total_time
 | 
					 | 
				
			||||||
	global total_count
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	with cmd_lock:
 | 
					 | 
				
			||||||
		start = time.time()
 | 
					 | 
				
			||||||
		results = _t_call(command, debug)
 | 
					 | 
				
			||||||
		ended = time.time()
 | 
					 | 
				
			||||||
		total_time += (ended - start)
 | 
					 | 
				
			||||||
		total_count += 1
 | 
					 | 
				
			||||||
		cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
 | 
					 | 
				
			||||||
	return results
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
call = time_wrapper
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Default cmd
 | 
					 | 
				
			||||||
# Place default arguments for every command here.
 | 
					 | 
				
			||||||
def _dc(cmd, args):
 | 
					 | 
				
			||||||
	c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
 | 
					 | 
				
			||||||
		'--unbuffered', '--units', 'b']
 | 
					 | 
				
			||||||
	c.extend(args)
 | 
					 | 
				
			||||||
	return c
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def parse(out):
 | 
					 | 
				
			||||||
	rc = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for line in out.split('\n'):
 | 
					 | 
				
			||||||
		# This line includes separators, so process them
 | 
					 | 
				
			||||||
		if SEP in line:
 | 
					 | 
				
			||||||
			elem = line.split(SEP)
 | 
					 | 
				
			||||||
			cleaned_elem = []
 | 
					 | 
				
			||||||
			for e in elem:
 | 
					 | 
				
			||||||
				e = e.strip()
 | 
					 | 
				
			||||||
				cleaned_elem.append(e)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if len(cleaned_elem) > 1:
 | 
					 | 
				
			||||||
				rc.append(cleaned_elem)
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			t = line.strip()
 | 
					 | 
				
			||||||
			if len(t) > 0:
 | 
					 | 
				
			||||||
				rc.append(t)
 | 
					 | 
				
			||||||
	return rc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def parse_column_names(out, column_names):
 | 
					 | 
				
			||||||
	lines = parse(out)
 | 
					 | 
				
			||||||
	rc = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for i in range(0, len(lines)):
 | 
					 | 
				
			||||||
		d = dict(list(zip(column_names, lines[i])))
 | 
					 | 
				
			||||||
		rc.append(d)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return rc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def options_to_cli_args(options):
 | 
					 | 
				
			||||||
	rc = []
 | 
					 | 
				
			||||||
	for k, v in list(dict(options).items()):
 | 
					 | 
				
			||||||
		if k.startswith("-"):
 | 
					 | 
				
			||||||
			rc.append(k)
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			rc.append("--%s" % k)
 | 
					 | 
				
			||||||
		if v != "":
 | 
					 | 
				
			||||||
			if isinstance(v, int):
 | 
					 | 
				
			||||||
				rc.append(str(int(v)))
 | 
					 | 
				
			||||||
			else:
 | 
					 | 
				
			||||||
				rc.append(str(v))
 | 
					 | 
				
			||||||
	return rc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def pv_remove(device, remove_options):
 | 
					 | 
				
			||||||
	cmd = ['pvremove']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(remove_options))
 | 
					 | 
				
			||||||
	cmd.append(device)
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _qt(tag_name):
 | 
					 | 
				
			||||||
	return '@%s' % tag_name
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _tag(operation, what, add, rm, tag_options):
 | 
					 | 
				
			||||||
	cmd = [operation]
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(tag_options))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if isinstance(what, list):
 | 
					 | 
				
			||||||
		cmd.extend(what)
 | 
					 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		cmd.append(what)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if add:
 | 
					 | 
				
			||||||
		cmd.extend(list(chain.from_iterable(
 | 
					 | 
				
			||||||
			('--addtag', _qt(x)) for x in add)))
 | 
					 | 
				
			||||||
	if rm:
 | 
					 | 
				
			||||||
		cmd.extend(list(chain.from_iterable(
 | 
					 | 
				
			||||||
			('--deltag', _qt(x)) for x in rm)))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return call(cmd, False)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def pv_tag(pv_devices, add, rm, tag_options):
 | 
					 | 
				
			||||||
	return _tag('pvchange', pv_devices, add, rm, tag_options)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_tag(vg_name, add, rm, tag_options):
 | 
					 | 
				
			||||||
	return _tag('vgchange', vg_name, add, rm, tag_options)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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):
 | 
					 | 
				
			||||||
	cmd = ['vgrename']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(rename_options))
 | 
					 | 
				
			||||||
	cmd.extend([vg_uuid, new_name])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_remove(vg_name, remove_options):
 | 
					 | 
				
			||||||
	cmd = ['vgremove']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(remove_options))
 | 
					 | 
				
			||||||
	cmd.extend(['-f', vg_name])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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(['--name', name, vg_name, '--yes'])
 | 
					 | 
				
			||||||
	pv_dest_ranges(cmd, pv_dests)
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_lv_snapshot(vg_name, snapshot_options, name, size_bytes):
 | 
					 | 
				
			||||||
	cmd = ['lvcreate']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(snapshot_options))
 | 
					 | 
				
			||||||
	cmd.extend(["-s"])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if size_bytes != 0:
 | 
					 | 
				
			||||||
		cmd.extend(['--size', '%dB' % size_bytes])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.extend(['--name', name, vg_name])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool):
 | 
					 | 
				
			||||||
	cmd = ['lvcreate']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(create_options))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if not thin_pool:
 | 
					 | 
				
			||||||
		cmd.extend(['--size', '%dB' % size_bytes])
 | 
					 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		cmd.extend(['--thin', '--size', '%dB' % size_bytes])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.extend(['--yes'])
 | 
					 | 
				
			||||||
	return cmd
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
 | 
					 | 
				
			||||||
	cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool)
 | 
					 | 
				
			||||||
	cmd.extend(['--name', name, vg_name])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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))])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if stripe_size_kb != 0:
 | 
					 | 
				
			||||||
		cmd.extend(['--stripesize', str(int(stripe_size_kb))])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.extend(['--name', name, vg_name])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
 | 
					 | 
				
			||||||
						num_stripes, stripe_size_kb):
 | 
					 | 
				
			||||||
	cmd = ['lvcreate']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(create_options))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.extend(['--type', raid_type])
 | 
					 | 
				
			||||||
	cmd.extend(['--size', '%dB' % size_bytes])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if num_stripes != 0:
 | 
					 | 
				
			||||||
		cmd.extend(['--stripes', str(int(num_stripes))])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if stripe_size_kb != 0:
 | 
					 | 
				
			||||||
		cmd.extend(['--stripesize', str(int(stripe_size_kb))])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.extend(['--name', name, vg_name, '--yes'])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
 | 
					 | 
				
			||||||
						num_stripes, stripe_size_kb):
 | 
					 | 
				
			||||||
	cmd = ['lvcreate']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(create_options))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return _vg_lv_create_raid(vg_name, create_options, name, raid_type,
 | 
					 | 
				
			||||||
								size_bytes, num_stripes, stripe_size_kb)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_lv_create_mirror(
 | 
					 | 
				
			||||||
		vg_name, create_options, name, size_bytes, num_copies):
 | 
					 | 
				
			||||||
	cmd = ['lvcreate']
 | 
					 | 
				
			||||||
	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(['--name', name, vg_name, '--yes'])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_create_cache_pool(md_full_name, data_full_name, create_options):
 | 
					 | 
				
			||||||
	cmd = ['lvconvert']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(create_options))
 | 
					 | 
				
			||||||
	cmd.extend(['--type', 'cache-pool', '--force', '-y',
 | 
					 | 
				
			||||||
				'--poolmetadata', md_full_name, data_full_name])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_create_thin_pool(md_full_name, data_full_name, create_options):
 | 
					 | 
				
			||||||
	cmd = ['lvconvert']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(create_options))
 | 
					 | 
				
			||||||
	cmd.extend(['--type', 'thin-pool', '--force', '-y',
 | 
					 | 
				
			||||||
				'--poolmetadata', md_full_name, data_full_name])
 | 
					 | 
				
			||||||
	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))
 | 
					 | 
				
			||||||
	cmd.extend(['-f', lv_path])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def lv_rename(lv_path, new_name, rename_options):
 | 
					 | 
				
			||||||
	cmd = ['lvrename']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(rename_options))
 | 
					 | 
				
			||||||
	cmd.extend([lv_path, new_name])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def lv_resize(lv_full_name, size_change, pv_dests,
 | 
					 | 
				
			||||||
				resize_options):
 | 
					 | 
				
			||||||
	cmd = ['lvresize', '--force']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(resize_options))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if size_change < 0:
 | 
					 | 
				
			||||||
		cmd.append("-L-%dB" % (-size_change))
 | 
					 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		cmd.append("-L+%dB" % (size_change))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.append(lv_full_name)
 | 
					 | 
				
			||||||
	pv_dest_ranges(cmd, pv_dests)
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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(['--name', name, lv_full_name, '--yes'])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def lv_cache_lv(cache_pool_full_name, lv_full_name, cache_options):
 | 
					 | 
				
			||||||
	# lvconvert --type cache --cachepool VG/CachePoolLV VG/OriginLV
 | 
					 | 
				
			||||||
	cmd = ['lvconvert']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(cache_options))
 | 
					 | 
				
			||||||
	cmd.extend(['-y', '--type', 'cache', '--cachepool',
 | 
					 | 
				
			||||||
				cache_pool_full_name, lv_full_name])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
 | 
					 | 
				
			||||||
	cmd = ['lvconvert']
 | 
					 | 
				
			||||||
	if destroy_cache:
 | 
					 | 
				
			||||||
		option = '--uncache'
 | 
					 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		# Currently fairly dangerous
 | 
					 | 
				
			||||||
		# see: https://bugzilla.redhat.com/show_bug.cgi?id=1248972
 | 
					 | 
				
			||||||
		option = '--splitcache'
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(detach_options))
 | 
					 | 
				
			||||||
	# needed to prevent interactive questions
 | 
					 | 
				
			||||||
	cmd.extend(["--yes", "--force"])
 | 
					 | 
				
			||||||
	cmd.extend([option, lv_full_name])
 | 
					 | 
				
			||||||
	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)
 | 
					 | 
				
			||||||
	if rc == 0:
 | 
					 | 
				
			||||||
		if cfg.SHELL_IN_USE:
 | 
					 | 
				
			||||||
			return True
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			if 'fullreport' in err:
 | 
					 | 
				
			||||||
				return True
 | 
					 | 
				
			||||||
	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',
 | 
					 | 
				
			||||||
					'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
 | 
					 | 
				
			||||||
					'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
 | 
					 | 
				
			||||||
					'vg_uuid', 'pv_missing']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pv_seg_columns = ['pvseg_start', 'pvseg_size', 'segtype',
 | 
					 | 
				
			||||||
						'pv_uuid', 'lv_uuid', 'pv_name']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vg_columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free',
 | 
					 | 
				
			||||||
					'vg_sysid', 'vg_extent_size', 'vg_extent_count',
 | 
					 | 
				
			||||||
					'vg_free_count', 'vg_profile', 'max_lv', 'max_pv',
 | 
					 | 
				
			||||||
					'pv_count', 'lv_count', 'snap_count', 'vg_seqno',
 | 
					 | 
				
			||||||
					'vg_mda_count', 'vg_mda_free', 'vg_mda_size',
 | 
					 | 
				
			||||||
					'vg_mda_used_count', 'vg_attr', 'vg_tags']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	lv_columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size',
 | 
					 | 
				
			||||||
				'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid',
 | 
					 | 
				
			||||||
				'origin', 'data_percent',
 | 
					 | 
				
			||||||
				'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
 | 
					 | 
				
			||||||
				'metadata_lv', 'lv_parent', 'lv_role', 'lv_layout',
 | 
					 | 
				
			||||||
				'snap_percent', 'metadata_percent', 'copy_percent',
 | 
					 | 
				
			||||||
				'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	lv_seg_columns = ['seg_pe_ranges', 'segtype', 'lv_uuid']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if cfg.vdo_support:
 | 
					 | 
				
			||||||
		lv_columns.extend(
 | 
					 | 
				
			||||||
			['vdo_operating_mode', 'vdo_compression_state', 'vdo_index_state',
 | 
					 | 
				
			||||||
				'vdo_used_size', 'vdo_saving_percent']
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		lv_seg_columns.extend(
 | 
					 | 
				
			||||||
			['vdo_compression', 'vdo_deduplication',
 | 
					 | 
				
			||||||
				'vdo_use_metadata_hints', 'vdo_minimum_io_size',
 | 
					 | 
				
			||||||
				'vdo_block_map_cache_size', 'vdo_block_map_era_length',
 | 
					 | 
				
			||||||
				'vdo_use_sparse_index', 'vdo_index_memory_size',
 | 
					 | 
				
			||||||
				'vdo_slab_size', 'vdo_ack_threads', 'vdo_bio_threads',
 | 
					 | 
				
			||||||
				'vdo_bio_rotation', 'vdo_cpu_threads', 'vdo_hash_zone_threads',
 | 
					 | 
				
			||||||
				'vdo_logical_threads', 'vdo_physical_threads',
 | 
					 | 
				
			||||||
				'vdo_max_discard', 'vdo_write_policy', 'vdo_header_size'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd = _dc('fullreport', [
 | 
					 | 
				
			||||||
		'-a',		# Need hidden too
 | 
					 | 
				
			||||||
		'--configreport', 'pv', '-o', ','.join(pv_columns),
 | 
					 | 
				
			||||||
		'--configreport', 'vg', '-o', ','.join(vg_columns),
 | 
					 | 
				
			||||||
		'--configreport', 'lv', '-o', ','.join(lv_columns),
 | 
					 | 
				
			||||||
		'--configreport', 'seg', '-o', ','.join(lv_seg_columns),
 | 
					 | 
				
			||||||
		'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns),
 | 
					 | 
				
			||||||
		'--reportformat', '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:
 | 
					 | 
				
			||||||
		# With the current implementation, if we are using the shell then we
 | 
					 | 
				
			||||||
		# are using JSON and JSON is returned back to us as it was parsed to
 | 
					 | 
				
			||||||
		# figure out if we completed OK or not
 | 
					 | 
				
			||||||
		if cfg.SHELL_IN_USE:
 | 
					 | 
				
			||||||
			assert(type(out) == dict)
 | 
					 | 
				
			||||||
			return out
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			return json.loads(out)
 | 
					 | 
				
			||||||
	return None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def pv_retrieve_with_segs(device=None):
 | 
					 | 
				
			||||||
	d = []
 | 
					 | 
				
			||||||
	err = ""
 | 
					 | 
				
			||||||
	out = ""
 | 
					 | 
				
			||||||
	rc = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
 | 
					 | 
				
			||||||
				'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
 | 
					 | 
				
			||||||
				'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
 | 
					 | 
				
			||||||
				'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
 | 
					 | 
				
			||||||
				'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# Lvm has some issues where it returns failure when querying pvs when other
 | 
					 | 
				
			||||||
	# operations are in process, see:
 | 
					 | 
				
			||||||
	# https://bugzilla.redhat.com/show_bug.cgi?id=1274085
 | 
					 | 
				
			||||||
	for i in range(0, 10):
 | 
					 | 
				
			||||||
		cmd = _dc('pvs', ['-o', ','.join(columns)])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if device:
 | 
					 | 
				
			||||||
			cmd.extend(device)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rc, out, err = call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if rc == 0:
 | 
					 | 
				
			||||||
			d = parse_column_names(out, columns)
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			time.sleep(0.2)
 | 
					 | 
				
			||||||
			log_debug("LVM Bug workaround, retrying pvs command...")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if rc != 0:
 | 
					 | 
				
			||||||
		msg = "We were unable to get pvs to return without error after " \
 | 
					 | 
				
			||||||
			"trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \
 | 
					 | 
				
			||||||
			(rc, err, out)
 | 
					 | 
				
			||||||
		log_error(msg)
 | 
					 | 
				
			||||||
		raise RuntimeError(msg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return d
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def pv_resize(device, size_bytes, create_options):
 | 
					 | 
				
			||||||
	cmd = ['pvresize']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(create_options))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if size_bytes != 0:
 | 
					 | 
				
			||||||
		cmd.extend(['--yes', '--setphysicalvolumesize', '%dB' % size_bytes])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.extend([device])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def pv_create(create_options, devices):
 | 
					 | 
				
			||||||
	cmd = ['pvcreate', '-ff']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(create_options))
 | 
					 | 
				
			||||||
	cmd.extend(devices)
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def pv_allocatable(device, yes, allocation_options):
 | 
					 | 
				
			||||||
	yn = 'n'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if yes:
 | 
					 | 
				
			||||||
		yn = 'y'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd = ['pvchange']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(allocation_options))
 | 
					 | 
				
			||||||
	cmd.extend(['-x', yn, device])
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def pv_scan(activate, cache, device_paths, major_minors, scan_options):
 | 
					 | 
				
			||||||
	cmd = ['pvscan']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(scan_options))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if activate:
 | 
					 | 
				
			||||||
		cmd.extend(['--activate', "ay"])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if cache:
 | 
					 | 
				
			||||||
		cmd.append('--cache')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if len(device_paths) > 0:
 | 
					 | 
				
			||||||
			for d in device_paths:
 | 
					 | 
				
			||||||
				cmd.append(d)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if len(major_minors) > 0:
 | 
					 | 
				
			||||||
			for mm in major_minors:
 | 
					 | 
				
			||||||
				cmd.append("%s:%s" % (mm))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_create(create_options, pv_devices, name):
 | 
					 | 
				
			||||||
	cmd = ['vgcreate']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(create_options))
 | 
					 | 
				
			||||||
	cmd.append(name)
 | 
					 | 
				
			||||||
	cmd.extend(pv_devices)
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_change(change_options, name):
 | 
					 | 
				
			||||||
	cmd = ['vgchange']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(change_options))
 | 
					 | 
				
			||||||
	cmd.append(name)
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_reduce(vg_name, missing, pv_devices, reduce_options):
 | 
					 | 
				
			||||||
	cmd = ['vgreduce']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(reduce_options))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if missing:
 | 
					 | 
				
			||||||
		cmd.append('--removemissing')
 | 
					 | 
				
			||||||
	elif len(pv_devices) == 0:
 | 
					 | 
				
			||||||
		cmd.append('--all')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.append(vg_name)
 | 
					 | 
				
			||||||
	cmd.extend(pv_devices)
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_extend(vg_name, extend_devices, extend_options):
 | 
					 | 
				
			||||||
	cmd = ['vgextend']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(extend_options))
 | 
					 | 
				
			||||||
	cmd.append(vg_name)
 | 
					 | 
				
			||||||
	cmd.extend(extend_devices)
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _vg_value_set(name, arguments, options):
 | 
					 | 
				
			||||||
	cmd = ['vgchange']
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(options))
 | 
					 | 
				
			||||||
	cmd.append(name)
 | 
					 | 
				
			||||||
	cmd.extend(arguments)
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_allocation_policy(vg_name, policy, policy_options):
 | 
					 | 
				
			||||||
	return _vg_value_set(vg_name, ['--alloc', policy], policy_options)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_max_pv(vg_name, number, max_options):
 | 
					 | 
				
			||||||
	return _vg_value_set(vg_name, ['--maxphysicalvolumes', str(int(number))],
 | 
					 | 
				
			||||||
							max_options)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_max_lv(vg_name, number, max_options):
 | 
					 | 
				
			||||||
	return _vg_value_set(vg_name, ['-l', str(int(number))], max_options)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_uuid_gen(vg_name, ignore, options):
 | 
					 | 
				
			||||||
	assert ignore is None
 | 
					 | 
				
			||||||
	return _vg_value_set(vg_name, ['--uuid'], options)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def activate_deactivate(op, name, activate, control_flags, options):
 | 
					 | 
				
			||||||
	cmd = [op]
 | 
					 | 
				
			||||||
	cmd.extend(options_to_cli_args(options))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	op = '-a'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if control_flags:
 | 
					 | 
				
			||||||
		# Autoactivation
 | 
					 | 
				
			||||||
		if (1 << 0) & control_flags:
 | 
					 | 
				
			||||||
			op += 'a'
 | 
					 | 
				
			||||||
		# Exclusive locking (Cluster)
 | 
					 | 
				
			||||||
		if (1 << 1) & control_flags:
 | 
					 | 
				
			||||||
			op += 'e'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Local node activation
 | 
					 | 
				
			||||||
		if (1 << 2) & control_flags:
 | 
					 | 
				
			||||||
			op += 'l'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Activation modes
 | 
					 | 
				
			||||||
		if (1 << 3) & control_flags:
 | 
					 | 
				
			||||||
			cmd.extend(['--activationmode', 'complete'])
 | 
					 | 
				
			||||||
		elif (1 << 4) & control_flags:
 | 
					 | 
				
			||||||
			cmd.extend(['--activationmode', 'partial'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Ignore activation skip
 | 
					 | 
				
			||||||
		if (1 << 5) & control_flags:
 | 
					 | 
				
			||||||
			cmd.append('--ignoreactivationskip')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if activate:
 | 
					 | 
				
			||||||
		op += 'y'
 | 
					 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		op += 'n'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd.append(op)
 | 
					 | 
				
			||||||
	cmd.append("-y")
 | 
					 | 
				
			||||||
	cmd.append(name)
 | 
					 | 
				
			||||||
	return call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def vg_retrieve(vg_specific):
 | 
					 | 
				
			||||||
	if vg_specific:
 | 
					 | 
				
			||||||
		assert isinstance(vg_specific, list)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free',
 | 
					 | 
				
			||||||
				'vg_sysid', 'vg_extent_size', 'vg_extent_count',
 | 
					 | 
				
			||||||
				'vg_free_count', 'vg_profile', 'max_lv', 'max_pv',
 | 
					 | 
				
			||||||
				'pv_count', 'lv_count', 'snap_count', 'vg_seqno',
 | 
					 | 
				
			||||||
				'vg_mda_count', 'vg_mda_free', 'vg_mda_size',
 | 
					 | 
				
			||||||
				'vg_mda_used_count', 'vg_attr', 'vg_tags']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd = _dc('vgs', ['-o', ','.join(columns)])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if vg_specific:
 | 
					 | 
				
			||||||
		cmd.extend(vg_specific)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d = []
 | 
					 | 
				
			||||||
	rc, out, err = call(cmd)
 | 
					 | 
				
			||||||
	if rc == 0:
 | 
					 | 
				
			||||||
		d = parse_column_names(out, columns)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return d
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def lv_retrieve_with_segments():
 | 
					 | 
				
			||||||
	columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size',
 | 
					 | 
				
			||||||
				'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid',
 | 
					 | 
				
			||||||
				'origin', 'data_percent',
 | 
					 | 
				
			||||||
				'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
 | 
					 | 
				
			||||||
				'metadata_lv', 'seg_pe_ranges', 'segtype', 'lv_parent',
 | 
					 | 
				
			||||||
				'lv_role', 'lv_layout',
 | 
					 | 
				
			||||||
				'snap_percent', 'metadata_percent', 'copy_percent',
 | 
					 | 
				
			||||||
				'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd = _dc('lvs', ['-a', '-o', ','.join(columns)])
 | 
					 | 
				
			||||||
	rc, out, err = call(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if rc == 0:
 | 
					 | 
				
			||||||
		d = parse_column_names(out, columns)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return d
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					 | 
				
			||||||
	pv_data = pv_retrieve_with_segs()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for p in pv_data:
 | 
					 | 
				
			||||||
		print(str(p))
 | 
					 | 
				
			||||||
@@ -1,200 +0,0 @@
 | 
				
			|||||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This copyrighted material is made available to anyone wishing to use,
 | 
					 | 
				
			||||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
					 | 
				
			||||||
# 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, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from .pv import load_pvs
 | 
					 | 
				
			||||||
from .vg import load_vgs
 | 
					 | 
				
			||||||
from .lv import load_lvs
 | 
					 | 
				
			||||||
from . import cfg
 | 
					 | 
				
			||||||
from .utils import MThreadRunner, log_debug, log_error
 | 
					 | 
				
			||||||
import threading
 | 
					 | 
				
			||||||
import queue
 | 
					 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
import traceback
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _main_thread_load(refresh=True, emit_signal=True):
 | 
					 | 
				
			||||||
	num_total_changes = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	num_total_changes += load_pvs(
 | 
					 | 
				
			||||||
		refresh=refresh,
 | 
					 | 
				
			||||||
		emit_signal=emit_signal,
 | 
					 | 
				
			||||||
		cache_refresh=False)[1]
 | 
					 | 
				
			||||||
	num_total_changes += load_vgs(
 | 
					 | 
				
			||||||
		refresh=refresh,
 | 
					 | 
				
			||||||
		emit_signal=emit_signal,
 | 
					 | 
				
			||||||
		cache_refresh=False)[1]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	lv_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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def load(refresh=True, emit_signal=True, cache_refresh=True, log=True,
 | 
					 | 
				
			||||||
			need_main_thread=True):
 | 
					 | 
				
			||||||
	# Go through and load all the PVs, VGs and LVs
 | 
					 | 
				
			||||||
	if cache_refresh:
 | 
					 | 
				
			||||||
		cfg.db.refresh(log)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if need_main_thread:
 | 
					 | 
				
			||||||
		rc = MThreadRunner(_main_thread_load, refresh, emit_signal).done()
 | 
					 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		rc = _main_thread_load(refresh, emit_signal)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return rc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Even though lvm can handle multiple changes concurrently it really doesn't
 | 
					 | 
				
			||||||
# make sense to make a 1-1 fetch of data for each change of lvm because when
 | 
					 | 
				
			||||||
# we fetch the data once all previous changes are reflected.
 | 
					 | 
				
			||||||
class StateUpdate(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	class UpdateRequest(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		def __init__(self, refresh, emit_signal, cache_refresh, log,
 | 
					 | 
				
			||||||
						need_main_thread):
 | 
					 | 
				
			||||||
			self.is_done = False
 | 
					 | 
				
			||||||
			self.refresh = refresh
 | 
					 | 
				
			||||||
			self.emit_signal = emit_signal
 | 
					 | 
				
			||||||
			self.cache_refresh = cache_refresh
 | 
					 | 
				
			||||||
			self.log = log
 | 
					 | 
				
			||||||
			self.need_main_thread = need_main_thread
 | 
					 | 
				
			||||||
			self.result = None
 | 
					 | 
				
			||||||
			self.cond = threading.Condition(threading.Lock())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		def done(self):
 | 
					 | 
				
			||||||
			with self.cond:
 | 
					 | 
				
			||||||
				if not self.is_done:
 | 
					 | 
				
			||||||
					self.cond.wait()
 | 
					 | 
				
			||||||
			return self.result
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		def set_result(self, result):
 | 
					 | 
				
			||||||
			with self.cond:
 | 
					 | 
				
			||||||
				self.result = result
 | 
					 | 
				
			||||||
				self.is_done = True
 | 
					 | 
				
			||||||
				self.cond.notify_all()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@staticmethod
 | 
					 | 
				
			||||||
	def update_thread(obj):
 | 
					 | 
				
			||||||
		exception_count = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		queued_requests = []
 | 
					 | 
				
			||||||
		while cfg.run.value != 0:
 | 
					 | 
				
			||||||
			# noinspection PyBroadException
 | 
					 | 
				
			||||||
			try:
 | 
					 | 
				
			||||||
				refresh = True
 | 
					 | 
				
			||||||
				emit_signal = True
 | 
					 | 
				
			||||||
				cache_refresh = True
 | 
					 | 
				
			||||||
				log = True
 | 
					 | 
				
			||||||
				need_main_thread = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				with obj.lock:
 | 
					 | 
				
			||||||
					wait = not obj.deferred
 | 
					 | 
				
			||||||
					obj.deferred = False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if len(queued_requests) == 0 and wait:
 | 
					 | 
				
			||||||
					queued_requests.append(obj.queue.get(True, 2))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				# Ok we have one or the deferred queue has some,
 | 
					 | 
				
			||||||
				# check if any others
 | 
					 | 
				
			||||||
				try:
 | 
					 | 
				
			||||||
					while True:
 | 
					 | 
				
			||||||
						queued_requests.append(obj.queue.get(False))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				except queue.Empty:
 | 
					 | 
				
			||||||
					pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if len(queued_requests) > 1:
 | 
					 | 
				
			||||||
					log_debug("Processing %d updates!" % len(queued_requests),
 | 
					 | 
				
			||||||
							'bg_black', 'fg_light_green')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				# We have what we can, run the update with the needed options
 | 
					 | 
				
			||||||
				for i in queued_requests:
 | 
					 | 
				
			||||||
					if not i.refresh:
 | 
					 | 
				
			||||||
						refresh = False
 | 
					 | 
				
			||||||
					if not i.emit_signal:
 | 
					 | 
				
			||||||
						emit_signal = False
 | 
					 | 
				
			||||||
					if not i.cache_refresh:
 | 
					 | 
				
			||||||
						cache_refresh = False
 | 
					 | 
				
			||||||
					if not i.log:
 | 
					 | 
				
			||||||
						log = False
 | 
					 | 
				
			||||||
					if not i.need_main_thread:
 | 
					 | 
				
			||||||
						need_main_thread = False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				num_changes = load(refresh, emit_signal, cache_refresh, log,
 | 
					 | 
				
			||||||
									need_main_thread)
 | 
					 | 
				
			||||||
				# Update is done, let everyone know!
 | 
					 | 
				
			||||||
				for i in queued_requests:
 | 
					 | 
				
			||||||
					i.set_result(num_changes)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				# Only clear out the requests after we have given them a result
 | 
					 | 
				
			||||||
				# otherwise we can orphan the waiting threads and they never
 | 
					 | 
				
			||||||
				# wake up if we get an exception
 | 
					 | 
				
			||||||
				queued_requests = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				# We retrieved OK, clear exception count
 | 
					 | 
				
			||||||
				exception_count = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			except queue.Empty:
 | 
					 | 
				
			||||||
				pass
 | 
					 | 
				
			||||||
			except Exception as e:
 | 
					 | 
				
			||||||
				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()
 | 
					 | 
				
			||||||
		self.queue = queue.Queue()
 | 
					 | 
				
			||||||
		self.deferred = False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Do initial load
 | 
					 | 
				
			||||||
		load(refresh=False, emit_signal=False, need_main_thread=False)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		self.thread = threading.Thread(target=StateUpdate.update_thread,
 | 
					 | 
				
			||||||
										args=(self,),
 | 
					 | 
				
			||||||
										name="StateUpdate.update_thread")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def load(self, refresh=True, emit_signal=True, cache_refresh=True,
 | 
					 | 
				
			||||||
					log=True, need_main_thread=True):
 | 
					 | 
				
			||||||
		# Place this request on the queue and wait for it to be completed
 | 
					 | 
				
			||||||
		req = StateUpdate.UpdateRequest(refresh, emit_signal, cache_refresh,
 | 
					 | 
				
			||||||
										log, need_main_thread)
 | 
					 | 
				
			||||||
		self.queue.put(req)
 | 
					 | 
				
			||||||
		return req.done()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def event(self):
 | 
					 | 
				
			||||||
		with self.lock:
 | 
					 | 
				
			||||||
			self.deferred = True
 | 
					 | 
				
			||||||
@@ -1,228 +0,0 @@
 | 
				
			|||||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This copyrighted material is made available to anyone wishing to use,
 | 
					 | 
				
			||||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
					 | 
				
			||||||
# 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, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from .automatedproperties import AutomatedProperties
 | 
					 | 
				
			||||||
from .utils import job_obj_path_generate, mt_async_call
 | 
					 | 
				
			||||||
from . import cfg
 | 
					 | 
				
			||||||
from .cfg import JOB_INTERFACE
 | 
					 | 
				
			||||||
import dbus
 | 
					 | 
				
			||||||
import threading
 | 
					 | 
				
			||||||
# noinspection PyUnresolvedReferences
 | 
					 | 
				
			||||||
from gi.repository import GLib
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Class that handles a client waiting for something to be complete.  We either
 | 
					 | 
				
			||||||
# get a timeout or the operation is done.
 | 
					 | 
				
			||||||
class WaitingClient(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# A timeout occurred
 | 
					 | 
				
			||||||
	@staticmethod
 | 
					 | 
				
			||||||
	def _timeout(wc):
 | 
					 | 
				
			||||||
		with wc.rlock:
 | 
					 | 
				
			||||||
			if wc.in_use:
 | 
					 | 
				
			||||||
				wc.in_use = False
 | 
					 | 
				
			||||||
				# Remove ourselves from waiting client
 | 
					 | 
				
			||||||
				wc.job_state.remove_waiting_client(wc)
 | 
					 | 
				
			||||||
				wc.timer_id = -1
 | 
					 | 
				
			||||||
				mt_async_call(wc.cb, wc.job_state.Complete)
 | 
					 | 
				
			||||||
				wc.job_state = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __init__(self, job_state, tmo, cb, cbe):
 | 
					 | 
				
			||||||
		self.rlock = threading.RLock()
 | 
					 | 
				
			||||||
		self.job_state = job_state
 | 
					 | 
				
			||||||
		self.cb = cb
 | 
					 | 
				
			||||||
		self.cbe = cbe
 | 
					 | 
				
			||||||
		self.in_use = True		# Indicates if object is in play
 | 
					 | 
				
			||||||
		self.timer_id = -1
 | 
					 | 
				
			||||||
		if tmo > 0:
 | 
					 | 
				
			||||||
			self.timer_id = GLib.timeout_add_seconds(
 | 
					 | 
				
			||||||
				tmo, WaitingClient._timeout, self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# The job finished before the timer popped and we are being notified that
 | 
					 | 
				
			||||||
	# it's done
 | 
					 | 
				
			||||||
	def notify(self):
 | 
					 | 
				
			||||||
		with self.rlock:
 | 
					 | 
				
			||||||
			if self.in_use:
 | 
					 | 
				
			||||||
				self.in_use = False
 | 
					 | 
				
			||||||
				# Clear timer
 | 
					 | 
				
			||||||
				if self.timer_id != -1:
 | 
					 | 
				
			||||||
					GLib.source_remove(self.timer_id)
 | 
					 | 
				
			||||||
					self.timer_id = -1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				mt_async_call(self.cb, self.job_state.Complete)
 | 
					 | 
				
			||||||
				self.job_state = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# noinspection PyPep8Naming
 | 
					 | 
				
			||||||
class JobState(object):
 | 
					 | 
				
			||||||
	def __init__(self, request=None):
 | 
					 | 
				
			||||||
		self.rlock = threading.RLock()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		self._percent = 0
 | 
					 | 
				
			||||||
		self._complete = False
 | 
					 | 
				
			||||||
		self._request = request
 | 
					 | 
				
			||||||
		self._ec = 0
 | 
					 | 
				
			||||||
		self._stderr = ''
 | 
					 | 
				
			||||||
		self._waiting_clients = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# This is an lvm command that is just taking too long and doesn't
 | 
					 | 
				
			||||||
		# support background operation
 | 
					 | 
				
			||||||
		if self._request:
 | 
					 | 
				
			||||||
			# Faking the percentage when we don't have one
 | 
					 | 
				
			||||||
			self._percent = 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@property
 | 
					 | 
				
			||||||
	def Percent(self):
 | 
					 | 
				
			||||||
		with self.rlock:
 | 
					 | 
				
			||||||
			return self._percent
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Percent.setter
 | 
					 | 
				
			||||||
	def Percent(self, value):
 | 
					 | 
				
			||||||
		with self.rlock:
 | 
					 | 
				
			||||||
			self._percent = value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@property
 | 
					 | 
				
			||||||
	def Complete(self):
 | 
					 | 
				
			||||||
		with self.rlock:
 | 
					 | 
				
			||||||
			if self._request:
 | 
					 | 
				
			||||||
				self._complete = self._request.is_done()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return self._complete
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Complete.setter
 | 
					 | 
				
			||||||
	def Complete(self, value):
 | 
					 | 
				
			||||||
		with self.rlock:
 | 
					 | 
				
			||||||
			self._complete = value
 | 
					 | 
				
			||||||
			self._percent = 100
 | 
					 | 
				
			||||||
			self.notify_waiting_clients()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@property
 | 
					 | 
				
			||||||
	def GetError(self):
 | 
					 | 
				
			||||||
		with self.rlock:
 | 
					 | 
				
			||||||
			if self.Complete:
 | 
					 | 
				
			||||||
				if self._request:
 | 
					 | 
				
			||||||
					(rc, error) = self._request.get_errors()
 | 
					 | 
				
			||||||
					return (rc, str(error))
 | 
					 | 
				
			||||||
				else:
 | 
					 | 
				
			||||||
					return (self._ec, self._stderr)
 | 
					 | 
				
			||||||
			else:
 | 
					 | 
				
			||||||
				return (-1, 'Job is not complete!')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def dtor(self):
 | 
					 | 
				
			||||||
		with self.rlock:
 | 
					 | 
				
			||||||
			self._request = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@property
 | 
					 | 
				
			||||||
	def Result(self):
 | 
					 | 
				
			||||||
		with self.rlock:
 | 
					 | 
				
			||||||
			if self._request:
 | 
					 | 
				
			||||||
				return self._request.result()
 | 
					 | 
				
			||||||
			return '/'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def add_waiting_client(self, client):
 | 
					 | 
				
			||||||
		with self.rlock:
 | 
					 | 
				
			||||||
			# Avoid race condition where it goes complete before we get added
 | 
					 | 
				
			||||||
			# to the list of waiting clients
 | 
					 | 
				
			||||||
			if self.Complete:
 | 
					 | 
				
			||||||
				client.notify()
 | 
					 | 
				
			||||||
			else:
 | 
					 | 
				
			||||||
				self._waiting_clients.append(client)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def remove_waiting_client(self, client):
 | 
					 | 
				
			||||||
		# If a waiting client timer pops before the job is done we will allow
 | 
					 | 
				
			||||||
		# the client to remove themselves from the list.  As we have a lock
 | 
					 | 
				
			||||||
		# here and a lock in the waiting client too, and they can be obtained
 | 
					 | 
				
			||||||
		# in different orders, a dead lock can occur.
 | 
					 | 
				
			||||||
		# As this remove is really optional, we will try to acquire the lock
 | 
					 | 
				
			||||||
		# and remove.  If we are unsuccessful it's not fatal, we just delay
 | 
					 | 
				
			||||||
		# the time when the objects can be garbage collected by python
 | 
					 | 
				
			||||||
		if self.rlock.acquire(False):
 | 
					 | 
				
			||||||
			try:
 | 
					 | 
				
			||||||
				self._waiting_clients.remove(client)
 | 
					 | 
				
			||||||
			finally:
 | 
					 | 
				
			||||||
				self.rlock.release()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def notify_waiting_clients(self):
 | 
					 | 
				
			||||||
		with self.rlock:
 | 
					 | 
				
			||||||
			for c in self._waiting_clients:
 | 
					 | 
				
			||||||
				c.notify()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			self._waiting_clients = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# noinspection PyPep8Naming
 | 
					 | 
				
			||||||
class Job(AutomatedProperties):
 | 
					 | 
				
			||||||
	_Percent_meta = ('d', JOB_INTERFACE)
 | 
					 | 
				
			||||||
	_Complete_meta = ('b', JOB_INTERFACE)
 | 
					 | 
				
			||||||
	_Result_meta = ('o', JOB_INTERFACE)
 | 
					 | 
				
			||||||
	_GetError_meta = ('(is)', JOB_INTERFACE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __init__(self, request, job_state=None):
 | 
					 | 
				
			||||||
		super(Job, self).__init__(job_obj_path_generate())
 | 
					 | 
				
			||||||
		self.set_interface(JOB_INTERFACE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if job_state:
 | 
					 | 
				
			||||||
			self.state = job_state
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			self.state = JobState(request)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@property
 | 
					 | 
				
			||||||
	def Percent(self):
 | 
					 | 
				
			||||||
		return dbus.Double(float(self.state.Percent))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@property
 | 
					 | 
				
			||||||
	def Complete(self):
 | 
					 | 
				
			||||||
		return dbus.Boolean(self.state.Complete)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@staticmethod
 | 
					 | 
				
			||||||
	def _signal_complete(obj):
 | 
					 | 
				
			||||||
		obj.PropertiesChanged(
 | 
					 | 
				
			||||||
			JOB_INTERFACE, dict(Complete=dbus.Boolean(obj.state.Complete)), [])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Complete.setter
 | 
					 | 
				
			||||||
	def Complete(self, value):
 | 
					 | 
				
			||||||
		self.state.Complete = value
 | 
					 | 
				
			||||||
		mt_async_call(Job._signal_complete, self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@property
 | 
					 | 
				
			||||||
	def GetError(self):
 | 
					 | 
				
			||||||
		return dbus.Struct(self.state.GetError, signature="(is)")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@dbus.service.method(dbus_interface=JOB_INTERFACE)
 | 
					 | 
				
			||||||
	def Remove(self):
 | 
					 | 
				
			||||||
		if self.state.Complete:
 | 
					 | 
				
			||||||
			cfg.om.remove_object(self, True)
 | 
					 | 
				
			||||||
			self.state.dtor()
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			raise dbus.exceptions.DBusException(
 | 
					 | 
				
			||||||
				JOB_INTERFACE, 'Job is not complete!')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@dbus.service.method(dbus_interface=JOB_INTERFACE,
 | 
					 | 
				
			||||||
							in_signature='i',
 | 
					 | 
				
			||||||
							out_signature='b',
 | 
					 | 
				
			||||||
							async_callbacks=('cb', 'cbe'))
 | 
					 | 
				
			||||||
	def Wait(self, timeout, cb, cbe):
 | 
					 | 
				
			||||||
		if timeout == 0 or self.state.Complete:
 | 
					 | 
				
			||||||
			cb(dbus.Boolean(self.state.Complete))
 | 
					 | 
				
			||||||
		else:
 | 
					 | 
				
			||||||
			self.state.add_waiting_client(
 | 
					 | 
				
			||||||
				WaitingClient(self.state, timeout, cb, cbe))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@property
 | 
					 | 
				
			||||||
	def Result(self):
 | 
					 | 
				
			||||||
		return dbus.ObjectPath(self.state.Result)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@property
 | 
					 | 
				
			||||||
	def lvm_id(self):
 | 
					 | 
				
			||||||
		return str(id(self))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@property
 | 
					 | 
				
			||||||
	def Uuid(self):
 | 
					 | 
				
			||||||
		import uuid
 | 
					 | 
				
			||||||
		return uuid.uuid1()
 | 
					 | 
				
			||||||
@@ -1,85 +0,0 @@
 | 
				
			|||||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This copyrighted material is made available to anyone wishing to use,
 | 
					 | 
				
			||||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
					 | 
				
			||||||
# 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, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from . import cfg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _compare_construction(o_state, new_state):
 | 
					 | 
				
			||||||
	# We need to check to see if the objects would get constructed
 | 
					 | 
				
			||||||
	# the same
 | 
					 | 
				
			||||||
	existing_ctor, existing_path = o_state.creation_signature()
 | 
					 | 
				
			||||||
	new_ctor, new_path = new_state.creation_signature()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# print("%s == %s and %s == %s" % (str(existing_ctor), str(new_ctor),
 | 
					 | 
				
			||||||
	#      str(existing_path), str(new_path)))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ((existing_ctor == new_ctor) and (existing_path == new_path))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def common(retrieve, o_type, search_keys,
 | 
					 | 
				
			||||||
			object_path, refresh, emit_signal, cache_refresh):
 | 
					 | 
				
			||||||
	num_changes = 0
 | 
					 | 
				
			||||||
	existing_paths = []
 | 
					 | 
				
			||||||
	rc = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if search_keys:
 | 
					 | 
				
			||||||
		assert isinstance(search_keys, list)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if cache_refresh:
 | 
					 | 
				
			||||||
		cfg.db.refresh()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	objects = retrieve(search_keys, cache_refresh=False)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# If we are doing a refresh we need to know what we have in memory, what's
 | 
					 | 
				
			||||||
	# in lvm and add those that are new and remove those that are gone!
 | 
					 | 
				
			||||||
	if refresh:
 | 
					 | 
				
			||||||
		existing_paths = cfg.om.object_paths_by_type(o_type)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for o in objects:
 | 
					 | 
				
			||||||
		# Assume we need to add this one to dbus, unless we are refreshing
 | 
					 | 
				
			||||||
		# and it's already present
 | 
					 | 
				
			||||||
		return_object = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if refresh:
 | 
					 | 
				
			||||||
			# We are refreshing all the PVs from LVM, if this one exists
 | 
					 | 
				
			||||||
			# we need to refresh our state.
 | 
					 | 
				
			||||||
			dbus_object = cfg.om.get_object_by_uuid_lvm_id(*o.identifiers())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if dbus_object:
 | 
					 | 
				
			||||||
				del existing_paths[dbus_object.dbus_object_path()]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				# If the old object state and new object state wouldn't be
 | 
					 | 
				
			||||||
				# created with the same path and same object constructor we
 | 
					 | 
				
			||||||
				# need to remove the old object and construct the new one
 | 
					 | 
				
			||||||
				# instead!
 | 
					 | 
				
			||||||
				if not _compare_construction(dbus_object.state, o):
 | 
					 | 
				
			||||||
					# Remove existing and construct new one
 | 
					 | 
				
			||||||
					cfg.om.remove_object(dbus_object, emit_signal)
 | 
					 | 
				
			||||||
					dbus_object = o.create_dbus_object(None)
 | 
					 | 
				
			||||||
					cfg.om.register_object(dbus_object, emit_signal)
 | 
					 | 
				
			||||||
					num_changes += 1
 | 
					 | 
				
			||||||
				else:
 | 
					 | 
				
			||||||
					num_changes += dbus_object.refresh(object_state=o)
 | 
					 | 
				
			||||||
				return_object = False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if return_object:
 | 
					 | 
				
			||||||
			dbus_object = o.create_dbus_object(object_path)
 | 
					 | 
				
			||||||
			cfg.om.register_object(dbus_object, emit_signal)
 | 
					 | 
				
			||||||
			rc.append(dbus_object)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		object_path = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if refresh:
 | 
					 | 
				
			||||||
		for k in list(existing_paths.keys()):
 | 
					 | 
				
			||||||
			cfg.om.remove_object(cfg.om.get_object_by_path(k), True)
 | 
					 | 
				
			||||||
			num_changes += 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	num_changes += len(rc)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return rc, num_changes
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,272 +0,0 @@
 | 
				
			|||||||
#!@PYTHON3@
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This copyrighted material is made available to anyone wishing to use,
 | 
					 | 
				
			||||||
# modify, copy, or redistribute it subject to the terms and conditions
 | 
					 | 
				
			||||||
# 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, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Copyright 2015-2016, Vratislav Podzimek <vpodzime@redhat.com>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import subprocess
 | 
					 | 
				
			||||||
import shlex
 | 
					 | 
				
			||||||
from fcntl import fcntl, F_GETFL, F_SETFL
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
import traceback
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
import tempfile
 | 
					 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
import select
 | 
					 | 
				
			||||||
import copy
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
try:
 | 
					 | 
				
			||||||
	import simplejson as json
 | 
					 | 
				
			||||||
except ImportError:
 | 
					 | 
				
			||||||
	import json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from lvmdbusd.cfg import LVM_CMD
 | 
					 | 
				
			||||||
from lvmdbusd.utils import log_debug, log_error, add_no_notify
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SHELL_PROMPT = "lvm> "
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _quote_arg(arg):
 | 
					 | 
				
			||||||
	if len(shlex.split(arg)) > 1:
 | 
					 | 
				
			||||||
		return '"%s"' % arg
 | 
					 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		return arg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class LVMShellProxy(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@staticmethod
 | 
					 | 
				
			||||||
	def _read(stream):
 | 
					 | 
				
			||||||
		tmp = stream.read()
 | 
					 | 
				
			||||||
		if tmp:
 | 
					 | 
				
			||||||
			return tmp.decode("utf-8")
 | 
					 | 
				
			||||||
		return ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# Read until we get prompt back and a result
 | 
					 | 
				
			||||||
	# @param: no_output	Caller expects no output to report FD
 | 
					 | 
				
			||||||
	# Returns stdout, report, stderr (report is JSON!)
 | 
					 | 
				
			||||||
	def _read_until_prompt(self, no_output=False):
 | 
					 | 
				
			||||||
		stdout = ""
 | 
					 | 
				
			||||||
		report = ""
 | 
					 | 
				
			||||||
		stderr = ""
 | 
					 | 
				
			||||||
		keep_reading = True
 | 
					 | 
				
			||||||
		extra_passes = 3
 | 
					 | 
				
			||||||
		report_json = {}
 | 
					 | 
				
			||||||
		prev_report_len = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Try reading from all FDs to prevent one from filling up and causing
 | 
					 | 
				
			||||||
		# a hang.  Keep reading until we get the prompt back and the report
 | 
					 | 
				
			||||||
		# FD does not contain valid JSON
 | 
					 | 
				
			||||||
		while keep_reading:
 | 
					 | 
				
			||||||
			try:
 | 
					 | 
				
			||||||
				rd_fd = [
 | 
					 | 
				
			||||||
					self.lvm_shell.stdout.fileno(),
 | 
					 | 
				
			||||||
					self.report_stream.fileno(),
 | 
					 | 
				
			||||||
					self.lvm_shell.stderr.fileno()]
 | 
					 | 
				
			||||||
				ready = select.select(rd_fd, [], [], 2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				for r in ready[0]:
 | 
					 | 
				
			||||||
					if r == self.lvm_shell.stdout.fileno():
 | 
					 | 
				
			||||||
						stdout += LVMShellProxy._read(self.lvm_shell.stdout)
 | 
					 | 
				
			||||||
					elif r == self.report_stream.fileno():
 | 
					 | 
				
			||||||
						report += LVMShellProxy._read(self.report_stream)
 | 
					 | 
				
			||||||
					elif r == self.lvm_shell.stderr.fileno():
 | 
					 | 
				
			||||||
						stderr += LVMShellProxy._read(self.lvm_shell.stderr)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				# Check to see if the lvm process died on us
 | 
					 | 
				
			||||||
				if self.lvm_shell.poll():
 | 
					 | 
				
			||||||
					raise Exception(self.lvm_shell.returncode, "%s" % stderr)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if stdout.endswith(SHELL_PROMPT):
 | 
					 | 
				
			||||||
					if no_output:
 | 
					 | 
				
			||||||
						keep_reading = False
 | 
					 | 
				
			||||||
					else:
 | 
					 | 
				
			||||||
						cur_report_len = len(report)
 | 
					 | 
				
			||||||
						if cur_report_len != 0:
 | 
					 | 
				
			||||||
							# Only bother to parse if we have more data
 | 
					 | 
				
			||||||
							if prev_report_len != cur_report_len:
 | 
					 | 
				
			||||||
								prev_report_len = cur_report_len
 | 
					 | 
				
			||||||
								# Parse the JSON if it's good we are done,
 | 
					 | 
				
			||||||
								# if not we will try to read some more.
 | 
					 | 
				
			||||||
								try:
 | 
					 | 
				
			||||||
									report_json = json.loads(report)
 | 
					 | 
				
			||||||
									keep_reading = False
 | 
					 | 
				
			||||||
								except ValueError:
 | 
					 | 
				
			||||||
									pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						if keep_reading:
 | 
					 | 
				
			||||||
							extra_passes -= 1
 | 
					 | 
				
			||||||
							if extra_passes <= 0:
 | 
					 | 
				
			||||||
								if len(report):
 | 
					 | 
				
			||||||
									raise ValueError("Invalid json: %s" %
 | 
					 | 
				
			||||||
														report)
 | 
					 | 
				
			||||||
								else:
 | 
					 | 
				
			||||||
									raise ValueError(
 | 
					 | 
				
			||||||
										"lvm returned no JSON output!")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			except IOError as ioe:
 | 
					 | 
				
			||||||
				log_debug(str(ioe))
 | 
					 | 
				
			||||||
				pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return stdout, report_json, stderr
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def _write_cmd(self, cmd):
 | 
					 | 
				
			||||||
		cmd_bytes = bytes(cmd, "utf-8")
 | 
					 | 
				
			||||||
		num_written = self.lvm_shell.stdin.write(cmd_bytes)
 | 
					 | 
				
			||||||
		assert (num_written == len(cmd_bytes))
 | 
					 | 
				
			||||||
		self.lvm_shell.stdin.flush()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@staticmethod
 | 
					 | 
				
			||||||
	def _make_non_block(stream):
 | 
					 | 
				
			||||||
		flags = fcntl(stream, F_GETFL)
 | 
					 | 
				
			||||||
		fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __init__(self):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Create a temp directory
 | 
					 | 
				
			||||||
		tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
 | 
					 | 
				
			||||||
		tmp_file = "%s/lvmdbus_report" % (tmp_dir)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		try:
 | 
					 | 
				
			||||||
			# Lets create fifo for the report output
 | 
					 | 
				
			||||||
			os.mkfifo(tmp_file, 0o600)
 | 
					 | 
				
			||||||
		except FileExistsError:
 | 
					 | 
				
			||||||
			pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# We have to open non-blocking as the other side isn't open until
 | 
					 | 
				
			||||||
		# we actually fork the process.
 | 
					 | 
				
			||||||
		self.report_fd = os.open(tmp_file, os.O_NONBLOCK)
 | 
					 | 
				
			||||||
		self.report_stream = os.fdopen(self.report_fd, 'rb', 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Setup the environment for using our own socket for reporting
 | 
					 | 
				
			||||||
		local_env = copy.deepcopy(os.environ)
 | 
					 | 
				
			||||||
		local_env["LVM_REPORT_FD"] = "32"
 | 
					 | 
				
			||||||
		local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Disable the abort logic if lvm logs too much, which easily happens
 | 
					 | 
				
			||||||
		# when utilizing the lvm shell.
 | 
					 | 
				
			||||||
		local_env["LVM_LOG_FILE_MAX_LINES"] = "0"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# run the lvm shell
 | 
					 | 
				
			||||||
		self.lvm_shell = subprocess.Popen(
 | 
					 | 
				
			||||||
			[LVM_CMD + " 32>%s" % tmp_file],
 | 
					 | 
				
			||||||
			stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env,
 | 
					 | 
				
			||||||
			stderr=subprocess.PIPE, close_fds=True, shell=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		try:
 | 
					 | 
				
			||||||
			LVMShellProxy._make_non_block(self.lvm_shell.stdout)
 | 
					 | 
				
			||||||
			LVMShellProxy._make_non_block(self.lvm_shell.stderr)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			# wait for the first prompt
 | 
					 | 
				
			||||||
			errors = self._read_until_prompt(no_output=True)[2]
 | 
					 | 
				
			||||||
			if errors and len(errors):
 | 
					 | 
				
			||||||
				raise RuntimeError(errors)
 | 
					 | 
				
			||||||
		except:
 | 
					 | 
				
			||||||
			raise
 | 
					 | 
				
			||||||
		finally:
 | 
					 | 
				
			||||||
			# These will get deleted when the FD count goes to zero so we
 | 
					 | 
				
			||||||
			# can be sure to clean up correctly no matter how we finish
 | 
					 | 
				
			||||||
			os.unlink(tmp_file)
 | 
					 | 
				
			||||||
			os.rmdir(tmp_dir)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def get_error_msg(self):
 | 
					 | 
				
			||||||
		# We got an error, lets go fetch the error message
 | 
					 | 
				
			||||||
		self._write_cmd('lastlog\n')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# read everything from the STDOUT to the next prompt
 | 
					 | 
				
			||||||
		stdout, report_json, stderr = self._read_until_prompt()
 | 
					 | 
				
			||||||
		if 'log' in report_json:
 | 
					 | 
				
			||||||
			error_msg = ""
 | 
					 | 
				
			||||||
			# Walk the entire log array and build an error string
 | 
					 | 
				
			||||||
			for log_entry in report_json['log']:
 | 
					 | 
				
			||||||
				if log_entry['log_type'] == "error":
 | 
					 | 
				
			||||||
					if error_msg:
 | 
					 | 
				
			||||||
						error_msg += ', ' + log_entry['log_message']
 | 
					 | 
				
			||||||
					else:
 | 
					 | 
				
			||||||
						error_msg = log_entry['log_message']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return error_msg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return 'No error reason provided! (missing "log" section)'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def call_lvm(self, argv, debug=False):
 | 
					 | 
				
			||||||
		rc = 1
 | 
					 | 
				
			||||||
		error_msg = ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if self.lvm_shell.poll():
 | 
					 | 
				
			||||||
			raise Exception(
 | 
					 | 
				
			||||||
				self.lvm_shell.returncode,
 | 
					 | 
				
			||||||
				"Underlying lvm shell process is not present!")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		argv = add_no_notify(argv)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# create the command string
 | 
					 | 
				
			||||||
		cmd = " ".join(_quote_arg(arg) for arg in argv)
 | 
					 | 
				
			||||||
		cmd += "\n"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# run the command by writing it to the shell's STDIN
 | 
					 | 
				
			||||||
		self._write_cmd(cmd)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# read everything from the STDOUT to the next prompt
 | 
					 | 
				
			||||||
		stdout, report_json, stderr = self._read_until_prompt()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Parse the report to see what happened
 | 
					 | 
				
			||||||
		if 'log' in report_json:
 | 
					 | 
				
			||||||
			ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
 | 
					 | 
				
			||||||
			# If we have an exported vg we get a log_ret_code == 5 when
 | 
					 | 
				
			||||||
			# we do a 'fullreport'
 | 
					 | 
				
			||||||
			if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
 | 
					 | 
				
			||||||
				rc = 0
 | 
					 | 
				
			||||||
			else:
 | 
					 | 
				
			||||||
				error_msg = self.get_error_msg()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if debug or rc != 0:
 | 
					 | 
				
			||||||
			log_error(('CMD: %s' % cmd))
 | 
					 | 
				
			||||||
			log_error(("EC = %d" % rc))
 | 
					 | 
				
			||||||
			log_error(("ERROR_MSG=\n %s\n" % error_msg))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return rc, report_json, error_msg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def exit_shell(self):
 | 
					 | 
				
			||||||
		try:
 | 
					 | 
				
			||||||
			self._write_cmd('exit\n')
 | 
					 | 
				
			||||||
		except Exception as e:
 | 
					 | 
				
			||||||
			log_error(str(e))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def __del__(self):
 | 
					 | 
				
			||||||
		try:
 | 
					 | 
				
			||||||
			self.lvm_shell.terminate()
 | 
					 | 
				
			||||||
		except:
 | 
					 | 
				
			||||||
			pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == "__main__":
 | 
					 | 
				
			||||||
	shell = LVMShellProxy()
 | 
					 | 
				
			||||||
	in_line = "start"
 | 
					 | 
				
			||||||
	try:
 | 
					 | 
				
			||||||
		while in_line:
 | 
					 | 
				
			||||||
			in_line = input("lvm> ")
 | 
					 | 
				
			||||||
			if in_line:
 | 
					 | 
				
			||||||
				start = time.time()
 | 
					 | 
				
			||||||
				ret, out, err = shell.call_lvm(in_line.split())
 | 
					 | 
				
			||||||
				end = time.time()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				print(("RC: %d" % ret))
 | 
					 | 
				
			||||||
				print(("OUT:\n%s" % out))
 | 
					 | 
				
			||||||
				print(("ERR:\n%s" % err))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				print("Command     = %f seconds" % (end - start))
 | 
					 | 
				
			||||||
	except KeyboardInterrupt:
 | 
					 | 
				
			||||||
		pass
 | 
					 | 
				
			||||||
	except EOFError:
 | 
					 | 
				
			||||||
		pass
 | 
					 | 
				
			||||||
	except Exception:
 | 
					 | 
				
			||||||
		traceback.print_exc(file=sys.stdout)
 | 
					 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user