mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-23 23:33:15 +03:00
Compare commits
243 Commits
stable-2.0
...
dev-dct-wr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0791eed33d | ||
|
|
19637a8d72 | ||
|
|
4fc2bdb0ba | ||
|
|
7ac01dc7fa | ||
|
|
2f43f0393e | ||
|
|
706606627f | ||
|
|
5ff18f51b9 | ||
|
|
279f3bfdc0 | ||
|
|
97506a7e2a | ||
|
|
7709b70f97 | ||
|
|
86c3940537 | ||
|
|
bf4be80669 | ||
|
|
2214dc12c3 | ||
|
|
778ce8d808 | ||
|
|
8a66c81b9b | ||
|
|
63ec42f428 | ||
|
|
117160b27e | ||
|
|
edf3f86184 | ||
|
|
06439a2562 | ||
|
|
db741e75a2 | ||
|
|
c47655f231 | ||
|
|
faa126882a | ||
|
|
12213445b5 | ||
|
|
7b8aa4af57 | ||
|
|
6206bd0e79 | ||
|
|
c58733ca15 | ||
|
|
6945bbdbc6 | ||
|
|
96e9929f2f | ||
|
|
a821b88a43 | ||
|
|
44c99a8822 | ||
|
|
5807993bbf | ||
|
|
4f708e8709 | ||
|
|
493ffe7a0f | ||
|
|
00990ed53e | ||
|
|
0dafd159a8 | ||
|
|
aa63dfbe39 | ||
|
|
aff69ecf39 | ||
|
|
4b7a57c9ed | ||
|
|
a8f84f7801 | ||
|
|
c66a960149 | ||
|
|
d8a41f22e9 | ||
|
|
0d9a4c6989 | ||
|
|
4a90b0c4c9 | ||
|
|
2e05f6018b | ||
|
|
80e6097ea6 | ||
|
|
b98846998b | ||
|
|
5f3eff8eae | ||
|
|
9b6b4f14d8 | ||
|
|
4a64bb9573 | ||
|
|
5cf0923e18 | ||
|
|
e9d1f676b3 | ||
|
|
333eb8667e | ||
|
|
6d1c983122 | ||
|
|
a55d4b6051 | ||
|
|
c8b4f9414c | ||
|
|
b697aa9646 | ||
|
|
c96400b6c7 | ||
|
|
c1a6b10d09 | ||
|
|
d56e400d44 | ||
|
|
f2b856c994 | ||
|
|
2bb9627d01 | ||
|
|
ed3428b7ed | ||
|
|
0bae9a1bff | ||
|
|
b55d30956d | ||
|
|
52b07672f8 | ||
|
|
29b9ccd261 | ||
|
|
f96fd9961d | ||
|
|
163a30d784 | ||
|
|
a14f21bf1d | ||
|
|
4194fc9bbd | ||
|
|
739a213d2e | ||
|
|
a1c81c009a | ||
|
|
19b92ae3f3 | ||
|
|
cea88a9e4e | ||
|
|
357e9f9572 | ||
|
|
9c0d92d957 | ||
|
|
8949903fbb | ||
|
|
6b3a4aac09 | ||
|
|
106ee05ba0 | ||
|
|
6c84a36b53 | ||
|
|
8215e3503d | ||
|
|
fa58fc3257 | ||
|
|
c728d88e11 | ||
|
|
086f1ef4a0 | ||
|
|
254e5c5d11 | ||
|
|
18528180d9 | ||
|
|
72e2e92f4c | ||
|
|
dd7ebec120 | ||
|
|
15826214f9 | ||
|
|
e166d2b14c | ||
|
|
40c1f7889f | ||
|
|
c8cfbfa605 | ||
|
|
20b9746c5d | ||
|
|
42f7caf1c2 | ||
|
|
f85a010a6b | ||
|
|
565df4e732 | ||
|
|
428514a07f | ||
|
|
ccab4a1994 | ||
|
|
328303d4d4 | ||
|
|
54f61e7dcc | ||
|
|
3fd75d1bcd | ||
|
|
8eab37593e | ||
|
|
27c647d6ce | ||
|
|
2a7f2a3a24 | ||
|
|
7d8bd97187 | ||
|
|
9d2b9e5bc6 | ||
|
|
52e7270e23 | ||
|
|
faf3cc8f71 | ||
|
|
b2cb8f846a | ||
|
|
b1729dbcdd | ||
|
|
f4abbafde7 | ||
|
|
b58160a191 | ||
|
|
a35098b110 | ||
|
|
218c57410c | ||
|
|
752c39d91d | ||
|
|
33703995ae | ||
|
|
f38a54227d | ||
|
|
70b159d145 | ||
|
|
3eff3aa4f8 | ||
|
|
5b515db71b | ||
|
|
52ab3c1584 | ||
|
|
a457566e91 | ||
|
|
c6be409609 | ||
|
|
327f62a255 | ||
|
|
b5f444d447 | ||
|
|
e84e9cd115 | ||
|
|
fededfbbbc | ||
|
|
0524829af6 | ||
|
|
e53cfc6a88 | ||
|
|
9b79f0244a | ||
|
|
fa00fce97c | ||
|
|
a163d5341a | ||
|
|
d067263f51 | ||
|
|
5fca75877d | ||
|
|
22c5467add | ||
|
|
17f5572bc9 | ||
|
|
9df6f601e0 | ||
|
|
885e57cb27 | ||
|
|
7824bb710d | ||
|
|
be3af7f93e | ||
|
|
981a3ba98e | ||
|
|
9a8c36b891 | ||
|
|
c4153a8dfc | ||
|
|
3b6b7f8f9b | ||
|
|
1c79cf9830 | ||
|
|
77d5caae90 | ||
|
|
75fed05d3e | ||
|
|
e82b70e739 | ||
|
|
9c7ee1e1c4 | ||
|
|
5c2f7f083c | ||
|
|
2a307ce33c | ||
|
|
b48e10d9e6 | ||
|
|
ebd147ff24 | ||
|
|
4ce9579099 | ||
|
|
1c59140f5f | ||
|
|
a8759dc7a6 | ||
|
|
5e672df6ae | ||
|
|
8266b7e951 | ||
|
|
ae961a192a | ||
|
|
669b1295ae | ||
|
|
dbc3e62cc0 | ||
|
|
73b7e6fde7 | ||
|
|
7c4b19c335 | ||
|
|
0ac89fb860 | ||
|
|
61e67e51e1 | ||
|
|
962a3eb3fa | ||
|
|
d5da55ed85 | ||
|
|
0e2a358da9 | ||
|
|
59dc9b445d | ||
|
|
f20e828ec2 | ||
|
|
bb7c064b23 | ||
|
|
c93e0932e8 | ||
|
|
8b111f28b0 | ||
|
|
bc8c8d2f87 | ||
|
|
5cb4b2a424 | ||
|
|
1f5f8382ae | ||
|
|
fb171edd45 | ||
|
|
0c62ae3f89 | ||
|
|
c78239d860 | ||
|
|
286c1ba336 | ||
|
|
88ae928ca3 | ||
|
|
9573ff3a3b | ||
|
|
b67ef90438 | ||
|
|
cc87f55e25 | ||
|
|
0d22b58172 | ||
|
|
e6bb780d24 | ||
|
|
c7c7017f0c | ||
|
|
60db97ae1d | ||
|
|
00befc04d0 | ||
|
|
6e6ef95ba6 | ||
|
|
e966752b86 | ||
|
|
229582c97c | ||
|
|
da30b4a786 | ||
|
|
616eeba6f2 | ||
|
|
e7aa51c70f | ||
|
|
18259d5559 | ||
|
|
e4d9099e19 | ||
|
|
d154dd6638 | ||
|
|
1539e51721 | ||
|
|
bd8c6cf862 | ||
|
|
f2ff06d675 | ||
|
|
55521be2cb | ||
|
|
802382e21f | ||
|
|
b7da704566 | ||
|
|
58a9254252 | ||
|
|
d2d8dd7f7f | ||
|
|
c157c43f7c | ||
|
|
eb60029245 | ||
|
|
3c657adc0a | ||
|
|
c67bd8b47b | ||
|
|
74460cd009 | ||
|
|
3e781ea446 | ||
|
|
11384637fb | ||
|
|
3810fd8d0d | ||
|
|
bd7cdd0b09 | ||
|
|
de66704253 | ||
|
|
2eda683a20 | ||
|
|
232918fb86 | ||
|
|
29abba3785 | ||
|
|
66b10275c5 | ||
|
|
f6eeb218b2 | ||
|
|
891f8dc19d | ||
|
|
1140d70893 | ||
|
|
eebf070d32 | ||
|
|
21a5be2364 | ||
|
|
6a1f458bb7 | ||
|
|
4d19321fd3 | ||
|
|
02c4901d89 | ||
|
|
7b5b1a9b6f | ||
|
|
0625c7f372 | ||
|
|
09177b53dd | ||
|
|
b6f0f20da2 | ||
|
|
c4497ee9e8 | ||
|
|
15a8142f6d | ||
|
|
dbba1e9b93 | ||
|
|
cb379c86c4 | ||
|
|
d4d39d0f90 | ||
|
|
7635df8cce | ||
|
|
272ec3fa73 | ||
|
|
89fdc0b588 | ||
|
|
ccc35e2647 | ||
|
|
7f97c7ea9a | ||
|
|
02b99be57e |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -28,9 +28,7 @@ make.tmpl
|
||||
/config.log
|
||||
/config.status
|
||||
/configure.scan
|
||||
/cscope.*
|
||||
/html/
|
||||
/reports/
|
||||
/cscope.out
|
||||
/tags
|
||||
/tmp/
|
||||
|
||||
|
||||
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.
|
||||
69
Makefile.in
69
Makefile.in
@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
|
||||
SUBDIRS = conf daemons include lib libdaemon libdm man scripts device_mapper tools
|
||||
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
|
||||
|
||||
ifeq ("@UDEV_RULES@", "yes")
|
||||
SUBDIRS += udev
|
||||
@@ -28,14 +28,6 @@ ifeq ("@INTL@", "yes")
|
||||
SUBDIRS += po
|
||||
endif
|
||||
|
||||
ifeq ("@APPLIB@", "yes")
|
||||
SUBDIRS += liblvm
|
||||
endif
|
||||
|
||||
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||
SUBDIRS += python
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),clean)
|
||||
SUBDIRS += test
|
||||
endif
|
||||
@@ -43,7 +35,7 @@ endif
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS = conf include man test scripts \
|
||||
libdaemon lib tools daemons libdm \
|
||||
udev po liblvm python device_mapper
|
||||
udev po
|
||||
tools.distclean: test.distclean
|
||||
endif
|
||||
DISTCLEAN_DIRS += lcov_reports*
|
||||
@@ -51,25 +43,19 @@ DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
|
||||
|
||||
include make.tmpl
|
||||
|
||||
include $(top_srcdir)/base/Makefile
|
||||
|
||||
libdm: include $(top_builddir)/base/libbase.a
|
||||
libdaemon: include $(top_builddir)/base/libbase.a
|
||||
lib: libdm libdaemon $(top_builddir)/base/libbase.a
|
||||
liblvm: lib $(top_builddir)/base/libbase.a
|
||||
daemons: lib libdaemon tools $(top_builddir)/base/libbase.a
|
||||
tools: lib libdaemon device-mapper $(top_builddir)/base/libbase.a
|
||||
libdm: include
|
||||
libdaemon: include
|
||||
lib: libdm libdaemon
|
||||
daemons: lib libdaemon tools
|
||||
tools: lib libdaemon device-mapper
|
||||
po: tools daemons
|
||||
man: tools
|
||||
all_man: tools
|
||||
scripts: liblvm libdm
|
||||
test: tools daemons $(top_builddir)/base/libbase.a
|
||||
unit-test: lib $(top_builddir)/base/libbase.a
|
||||
run-unit-test: unit-test
|
||||
scripts: libdm
|
||||
test: tools daemons
|
||||
|
||||
lib.device-mapper: include.device-mapper
|
||||
libdm.device-mapper: include.device-mapper
|
||||
liblvm.device-mapper: include.device-mapper
|
||||
daemons.device-mapper: libdm.device-mapper
|
||||
tools.device-mapper: libdm.device-mapper
|
||||
scripts.device-mapper: include.device-mapper
|
||||
@@ -83,10 +69,6 @@ po.pofile: tools.pofile daemons.pofile
|
||||
pofile: po.pofile
|
||||
endif
|
||||
|
||||
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||
python: liblvm
|
||||
endif
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
tools.cflow: libdm.cflow lib.cflow
|
||||
daemons.cflow: tools.cflow
|
||||
@@ -101,7 +83,7 @@ endif
|
||||
DISTCLEAN_TARGETS += cscope.out
|
||||
CLEAN_DIRS += autom4te.cache
|
||||
|
||||
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit-test run-unit-test: test
|
||||
check check_system check_cluster check_local check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock: test
|
||||
$(MAKE) -C test $(@)
|
||||
|
||||
conf.generate man.generate: tools
|
||||
@@ -126,11 +108,11 @@ rpm: dist
|
||||
$(LN_S) -f $(abs_top_srcdir)/spec/build.inc $(rpmbuilddir)/SOURCES
|
||||
$(LN_S) -f $(abs_top_srcdir)/spec/macros.inc $(rpmbuilddir)/SOURCES
|
||||
$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES
|
||||
DM_VER=$$(cut -d' ' -f1 $(top_srcdir)/VERSION_DM | cut -d- -f1);\
|
||||
GIT_VER=$$(cd $(top_srcdir); git describe | cut -s -d- --output-delimiter=. -f2,3);\
|
||||
DM_VER=$$(cut -d- -f1 $(top_srcdir)/VERSION_DM);\
|
||||
GIT_VER=$$(cd $(top_srcdir); git describe | cut -d- --output-delimiter=. -f2,3 || echo 0);\
|
||||
sed -e "s,\(device_mapper_version\) [0-9.]*$$,\1 $$DM_VER," \
|
||||
-e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \
|
||||
-e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $${GIT_VER:-"0"}," \
|
||||
-e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $$GIT_VER," \
|
||||
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
|
||||
rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
|
||||
|
||||
@@ -163,20 +145,14 @@ install_systemd_units:
|
||||
install_all_man:
|
||||
$(MAKE) -C man install_all_man
|
||||
|
||||
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||
install_python_bindings:
|
||||
$(MAKE) -C liblvm/python install_python_bindings
|
||||
endif
|
||||
|
||||
install_tmpfiles_configuration:
|
||||
$(MAKE) -C scripts install_tmpfiles_configuration
|
||||
|
||||
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
|
||||
LCOV_TRACES = libdm.info lib.info tools.info \
|
||||
libdaemon/client.info libdaemon/server.info \
|
||||
test/unit.info \
|
||||
daemons/clvmd.info \
|
||||
daemons/dmeventd.info \
|
||||
daemons/lvmetad.info \
|
||||
daemons/lvmlockd.info \
|
||||
daemons/lvmpolld.info
|
||||
|
||||
@@ -205,17 +181,22 @@ $(LCOV_TRACES):
|
||||
|
||||
ifneq ("$(GENHTML)", "")
|
||||
lcov: $(LCOV_TRACES)
|
||||
$(RM) -rf $(LCOV_REPORTS_DIR)
|
||||
$(RM) -r $(LCOV_REPORTS_DIR)
|
||||
$(MKDIR_P) $(LCOV_REPORTS_DIR)
|
||||
$(LCOV) --capture --directory $(top_builddir) --ignore-errors source \
|
||||
--output-file $(LCOV_REPORTS_DIR)/out.info
|
||||
-test ! -s $(LCOV_REPORTS_DIR)/out.info || \
|
||||
$(GENHTML) -o $(LCOV_REPORTS_DIR) --ignore-errors source \
|
||||
$(LCOV_REPORTS_DIR)/out.info
|
||||
for i in $(LCOV_TRACES); do \
|
||||
test -s $$i -a $$(wc -w <$$i) -ge 100 && lc="$$lc $$i"; \
|
||||
done; \
|
||||
test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \
|
||||
-o $(LCOV_REPORTS_DIR) $$lc
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
# FIXME: Drop once top-level make is resolved
|
||||
-include test/unit/Makefile
|
||||
include $(top_srcdir)/device_mapper/Makefile
|
||||
include $(top_srcdir)/base/Makefile
|
||||
|
||||
ifneq ($(shell which ctags),)
|
||||
.PHONY: tags
|
||||
tags:
|
||||
|
||||
8
README
8
README
@@ -7,6 +7,7 @@ There is no warranty - see COPYING and COPYING.LIB.
|
||||
|
||||
Tarballs are available from:
|
||||
ftp://sourceware.org/pub/lvm2/
|
||||
ftp://sources.redhat.com/pub/lvm2/
|
||||
https://github.com/lvmteam/lvm2/releases
|
||||
|
||||
The source code is stored in git:
|
||||
@@ -41,9 +42,6 @@ Report upstream bugs at:
|
||||
or open issues at:
|
||||
https://github.com/lvmteam/lvm2/issues
|
||||
|
||||
The source code repository used until 7th June 2012 is accessible using CVS:
|
||||
The source code repository used until 7th June 2012 is accessible here:
|
||||
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2.
|
||||
|
||||
cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 login cvs
|
||||
cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 checkout LVM2
|
||||
|
||||
The password is cvs.
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.02.174-git (2021-05-07)
|
||||
1.02.147-git (2018-05-24)
|
||||
|
||||
151
WHATS_NEW
151
WHATS_NEW
@@ -1,155 +1,20 @@
|
||||
Version 2.02.189 -
|
||||
================================
|
||||
|
||||
Version 2.02.188 - 07th May 2021
|
||||
================================
|
||||
Fix problem with unbound variable usage within fsadm.
|
||||
Avoid removing LVs on error path of lvconvert during creation volumes.
|
||||
Fix crashing lvdisplay when thin volume was waiting for merge.
|
||||
Support option --errorwhenfull when converting volume to thin-pool.
|
||||
Improve thin-performance profile support conversion to thin-pool.
|
||||
Support resize of cached volumes.
|
||||
Allocation prints better error when metadata cannot fit on a single PV.
|
||||
Pvmove can better resolve full thin-pool tree move.
|
||||
Limit pool metadata spare to 16GiB.
|
||||
Improves convertsion and allocation of pool metadata.
|
||||
Support thin pool metadata 15.88GiB, adds 64MiB, thin_pool_crop_metadata=0.
|
||||
Enhance lvdisplay to report raid availiable/partial.
|
||||
Enhance error handling for fsadm and hanled correct fsck result.
|
||||
Stop logging rename errors from persintent filter.
|
||||
Dmeventd lvm plugin ignores higher reserved_stack lvm.conf values.
|
||||
Support using BLKZEROOUT for clearing devices.
|
||||
Support interruption when wipping LVs.
|
||||
Add configure --enable-editline support as an alternative to readline.
|
||||
Zero pool metadata on allocation (disable with allocation/zero_metadata=0).
|
||||
Failure in zeroing or wiping will fail command (bypass with -Zn, -Wn).
|
||||
Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
|
||||
Support interruption for bcache waiting.
|
||||
Fix bcache when device has too many failing writes.
|
||||
Fix bcache waiting for IO completion with failing disks.
|
||||
Configure use own python path name order to prefer using python3.
|
||||
Enhance reporting and error handling when creating thin volumes.
|
||||
Use revert_lv() on reload error path after vg_revert().
|
||||
Improve estimation of needed extents when creating thin-pool.
|
||||
Use extra 1% when resizing thin-pool metadata LV with --use-policy.
|
||||
Enhance --use-policy percentage rounding.
|
||||
Switch code base to use flexible array syntax.
|
||||
Preserve uint32_t for seqno handling.
|
||||
Switch from mmap to plain read when loading regular files.
|
||||
Fix running out of free buffers for async writing for larger writes.
|
||||
Fix conversion to raid from striped lagging type.
|
||||
Fix conversion to 'mirrored' mirror log with larger regionsize.
|
||||
Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
|
||||
|
||||
Version 2.02.187 - 24th March 2020
|
||||
==================================
|
||||
Avoid running cache input arg validation when creating vdo pool.
|
||||
Prevent raid reshaping of stacked volumes.
|
||||
Ensure minimum required region size on striped RaidLV creation.
|
||||
Fix resize of thin-pool with data and metadata of different segtype.
|
||||
Fix splitting mirror leg in cluster.
|
||||
Fix activation order when removing merged snapshot.
|
||||
Add support for DM_DEVICE_GET_TARGET_VERSION into device_mapper.
|
||||
Add lvextend-raid.sh to check on RaidLV extensions synchronization.
|
||||
Fix lvmetad shutdown and avoid lenghty timeouts when rebooting system.
|
||||
Prevent creating VGs with PVs with different logical block sizes.
|
||||
Pvmove runs in exlusively activating mode for exclusively active LVs.
|
||||
Activate thin-pool layered volume as 'read-only' device.
|
||||
Ignore crypto devices with UUID signature CRYPT-SUBDEV.
|
||||
Enhance validation for thin and cache pool conversion and swapping.
|
||||
Fixed activation on boot - lvm2 no longer activates incomplete VGs.
|
||||
|
||||
Version 2.02.186 - 27th August 2019
|
||||
===================================
|
||||
Improve internal removal of cached devices.
|
||||
Synchronize with udev when dropping snapshot.
|
||||
Add missing device synchronization point before removing pvmove node.
|
||||
Correctly set read_ahead for LVs when pvmove is finished.
|
||||
Fix metadata writes from corrupting with large physical block size.
|
||||
Report no_discard_passdown for cache LVs with lvs -o+kernel_discards.
|
||||
Prevent shared active mirror LVs with lvmlockd.
|
||||
|
||||
Version 2.02.185 - 13th May 2019
|
||||
================================
|
||||
Fix change of monitoring in clustered volumes.
|
||||
Improve -lXXX%VG modifier which improves cache segment estimation.
|
||||
Add synchronization with udev before removing cached devices.
|
||||
Fix missing growth of _pmspare volume when extending _tmeta volume.
|
||||
Automatically grow thin metadata, when thin data gets too big.
|
||||
Add support for vgsplit with cached devices.
|
||||
Fix signal delivery checking race in libdaemon (lvmetad).
|
||||
Add missing Before=shutdown.target to LVM2 services to fix shutdown ordering.
|
||||
|
||||
Version 2.02.184 - 22nd March 2019
|
||||
==================================
|
||||
Fix (de)activation of RaidLVs with visible SubLVs
|
||||
Change scan_lvs default to 0 so LVs are not scanned for PVs.
|
||||
Add scan_lvs config setting to control if lvm scans LVs for PVs.
|
||||
Fix missing proper initialization of pv_list struct when adding pv.
|
||||
|
||||
Version 2.02.183 - 07th December 2018
|
||||
=====================================
|
||||
Avoid disabling lvmetad when repair does nothing.
|
||||
Fix component detection for md version 0.90.
|
||||
Use sync io if async io_setup fails, or use_aio=0 is set in config.
|
||||
Avoid opening devices to get block size by using existing open fd.
|
||||
|
||||
Version 2.02.182 - 30th October 2018
|
||||
====================================
|
||||
Fix possible write race between last metadata block and the first extent.
|
||||
Fix filtering of md 1.0 devices so they are not seen as duplicate PVs.
|
||||
Fix lvconvert striped/raid0/raid0_meta -> raid6 regression.
|
||||
Add After=rbdmap.service to {lvm2-activation-net,blk-availability}.service.
|
||||
Fix pvs with lvmetad to avoid too many open files from filter reads.
|
||||
Fix pvscan --cache to avoid too many open files from filter reads.
|
||||
Reduce max concurrent aios to avoid EMFILE with many devices.
|
||||
Fix lvconvert conversion attempts to linear.
|
||||
Fix lvconvert raid0/raid0_meta -> striped regression.
|
||||
Fix lvconvert --splitmirror for mirror type (2.02.178).
|
||||
Do not pair cache policy and cache metadata format.
|
||||
Fix mirrors honoring read_only_volume_list.
|
||||
|
||||
Version 2.02.181 - 01 August 2018
|
||||
=================================
|
||||
Reject conversions on raid1 LVs with split tracked SubLVs.
|
||||
Reject conversions on raid1 split tracked SubLVs.
|
||||
Fix dmstats list failing when no regions exist.
|
||||
Reject conversions of LVs under snapshot.
|
||||
Limit suggested options on incorrect option for lvconvert subcommand.
|
||||
|
||||
Version 2.02.180 - 19th July 2018
|
||||
=================================
|
||||
Version 3.0.0
|
||||
=============
|
||||
Add basic creation support for VDO target.
|
||||
Never send any discard ioctl with test mode.
|
||||
Fix thin-pool alloc which needs same PV for data and metadata.
|
||||
Extend list of non-memlocked areas with newly linked libs.
|
||||
Enhance vgcfgrestore to check for active LVs in restored VG.
|
||||
lvconvert: provide possible layouts between linear and striped/raid
|
||||
Configure supports --disable-silent-rules for verbose builds.
|
||||
Fix unmonitoring of merging snapshots.
|
||||
Add missing -l description in fsadm man page.
|
||||
Cache can uses metadata format 2 with cleaner policy.
|
||||
Avoid showing internal error in lvs output or pvmoved LVs.
|
||||
Fix check if resized PV can also fit metadata area.
|
||||
Reopen devices RDWR only before writing to avoid udev issues.
|
||||
Change pvresize output confusing when no resize took place.
|
||||
Fix lvmetad hanging on shutdown.
|
||||
Fix mem leak in clvmd and more coverity issues.
|
||||
|
||||
Version 2.02.179 - 18th June 2018
|
||||
=================================
|
||||
Allow forced vgchange to lock type none on clustered VG.
|
||||
Add the report field "shared".
|
||||
Enable automatic metadata consistency repair on a shared VG.
|
||||
Fix pvremove force on a PV with a shared VG.
|
||||
Fixed vgimportclone of a PV with a shared VG.
|
||||
Enable previously disallowed thin/cache commands in shared VGs.
|
||||
Enable metadata-related changes on LVs active with shared lock.
|
||||
Do not continue trying to use a device that cannot be opened.
|
||||
Fix problems opening a device that fails and returns.
|
||||
Avoid showing internal error in lvs output or pvmoved LVs.
|
||||
Remove clvmd
|
||||
Remove lvmlib (api)
|
||||
lvconvert: provide possible layouts between linear and striped/raid
|
||||
Use versionsort to fix archive file expiry beyond 100000 files.
|
||||
|
||||
Version 2.02.178 - 13th June 2018
|
||||
=================================
|
||||
|
||||
Version 2.02.178-rc1 - 24th May 2018
|
||||
====================================
|
||||
Add libaio dependency for build.
|
||||
|
||||
50
WHATS_NEW_DM
50
WHATS_NEW_DM
@@ -1,55 +1,7 @@
|
||||
Version 1.02.174 -
|
||||
================================
|
||||
|
||||
Version 1.02.172 - 07th May 2021
|
||||
================================
|
||||
Add dm_tree_node_add_thin_pool_target_v1 with crop_metadata support.
|
||||
Add support for VDO in blkdeactivate script.
|
||||
Try to remove all created devices on dm preload tree error path.
|
||||
Fix dm_list interators with gcc 10 optimization (-ftree-pta).
|
||||
Dmeventd handles timer without looping on short intervals.
|
||||
|
||||
Version 1.02.170 - 24th March 2020
|
||||
==================================
|
||||
Add support for DM_DEVICE_GET_TARGET_VERSION.
|
||||
|
||||
Version 1.02.164 - 27th August 2019
|
||||
===================================
|
||||
Add debug of dmsetup udevcomplete with hexa print DM_COOKIE_COMPLETED.
|
||||
Fix versioning of dm_stats_create_region and dm_stats_create_region.
|
||||
Parsing of cache status understand no_discard_passdown.
|
||||
|
||||
Version 1.02.158 - 13th May 2019
|
||||
================================
|
||||
|
||||
Version 1.02.156 - 22nd March 2019
|
||||
==================================
|
||||
Ensure migration_threshold for cache is at least 8 chunks.
|
||||
Enhance ioctl flattening and add parameters only when needed.
|
||||
Add DM_DEVICE_ARM_POLL for API completness matching kernel.
|
||||
|
||||
Version 1.02.154 - 07th December 2018
|
||||
=====================================
|
||||
Do not add parameters for RESUME with DM_DEVICE_CREATE dm task.
|
||||
Fix dmstats report printing no output.
|
||||
|
||||
Version 1.02.152 - 30th October 2018
|
||||
Version 1.02.147 -
|
||||
====================================
|
||||
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.
|
||||
|
||||
16
aclocal.m4
vendored
16
aclocal.m4
vendored
@@ -1,6 +1,6 @@
|
||||
# generated automatically by aclocal 1.16.2 -*- Autoconf -*-
|
||||
# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
||||
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
@@ -413,7 +413,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
|
||||
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
|
||||
])dnl PKG_HAVE_DEFINE_WITH_MODULES
|
||||
|
||||
# Copyright (C) 1999-2020 Free Software Foundation, Inc.
|
||||
# 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,
|
||||
@@ -446,12 +446,10 @@ 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 dnl
|
||||
python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 dnl
|
||||
python3.2 python3.1 python3.0 dnl
|
||||
python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl
|
||||
python2.0])
|
||||
[python python2 python3 python3.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])
|
||||
|
||||
@@ -651,7 +649,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
|
||||
sys.exit(sys.hexversion < minverhex)"
|
||||
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
|
||||
|
||||
# Copyright (C) 2001-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
||||
@@ -10,35 +10,22 @@
|
||||
# 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/radix-tree.c
|
||||
base/data-struct/radix-tree.c \
|
||||
base/data-struct/hash.c \
|
||||
base/data-struct/list.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_DEPENDS=$(addprefix $(top_builddir)/,$(subst .c,.d,$(BASE_SOURCE)))
|
||||
BASE_OBJECTS=$(addprefix $(top_builddir)/,$(subst .c,.o,$(BASE_SOURCE)))
|
||||
CLEAN_TARGETS+=$(BASE_DEPENDS) $(BASE_OBJECTS)
|
||||
|
||||
$(BASE_TARGET): $(BASE_OBJECTS)
|
||||
-include $(BASE_DEPENDS)
|
||||
|
||||
$(BASE_OBJECTS): INCLUDES+=-I$(top_srcdir)/base/
|
||||
|
||||
$(top_builddir)/base/libbase.a: $(BASE_OBJECTS)
|
||||
@echo " [AR] $@"
|
||||
$(Q) $(RM) $@
|
||||
$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null
|
||||
|
||||
ifneq (,$(findstring $(MAKECMDGOALS),clean distclean))
|
||||
BASE_SOURCE += \
|
||||
base/data-struct/hash.c \
|
||||
base/data-struct/list.c
|
||||
endif
|
||||
|
||||
ifeq ("$(DEPENDS)","yes")
|
||||
-include $(BASE_DEPENDS)
|
||||
endif
|
||||
CLEAN_TARGETS+=$(top_builddir)/base/libbase.a
|
||||
|
||||
394
base/data-struct/hash.c
Normal file
394
base/data-struct/hash.c
Normal file
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
94
base/data-struct/hash.h
Normal file
94
base/data-struct/hash.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#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
|
||||
170
base/data-struct/list.c
Normal file
170
base/data-struct/list.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
209
base/data-struct/list.h
Normal file
209
base/data-struct/list.h
Normal file
@@ -0,0 +1,209 @@
|
||||
#ifndef BASE_DATA_STRUCT_LIST_H
|
||||
#define BASE_DATA_STRUCT_LIST_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) \
|
||||
((t *)((const char *)(v) - (const char *)&((t *) 0)->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) - (uintptr_t)&((t *) 0)->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)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2018 - 2020 Red Hat, Inc. All rights reserved.
|
||||
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
//
|
||||
// This file is part of LVM2.
|
||||
//
|
||||
@@ -13,12 +13,10 @@
|
||||
#ifndef BASE_MEMORY_CONTAINER_OF_H
|
||||
#define BASE_MEMORY_CONTAINER_OF_H
|
||||
|
||||
#include <stddef.h> // offsetof
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#define container_of(v, t, head) \
|
||||
((t *)((char *)(v) - offsetof(t, head)))
|
||||
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
@@ -25,6 +25,7 @@ PROFILES=$(PROFILE_TEMPLATES) \
|
||||
$(srcdir)/cache-smq.profile \
|
||||
$(srcdir)/thin-generic.profile \
|
||||
$(srcdir)/thin-performance.profile \
|
||||
$(srcdir)/vdo-small.profile \
|
||||
$(srcdir)/lvmdbusd.profile
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
@@ -32,8 +33,8 @@ include $(top_builddir)/make.tmpl
|
||||
.PHONY: install_conf install_localconf install_profiles
|
||||
|
||||
generate:
|
||||
LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in
|
||||
LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --withcomments --withspaces local > lvmlocal.conf.in
|
||||
$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in
|
||||
$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --withcomments --withspaces local > lvmlocal.conf.in
|
||||
|
||||
install_conf: $(CONFSRC)
|
||||
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
||||
|
||||
@@ -151,21 +151,15 @@ devices {
|
||||
# global_filter = [ "a|.*/|" ]
|
||||
|
||||
# Configuration option devices/cache_dir.
|
||||
# Directory in which to store the device cache file.
|
||||
# The results of filtering are cached on disk to avoid rescanning dud
|
||||
# devices (which can take a very long time). By default this cache is
|
||||
# stored in a file named .cache. It is safe to delete this file; the
|
||||
# tools regenerate it. If obtain_device_list_from_udev is enabled, the
|
||||
# list of devices is obtained from udev and any existing .cache file
|
||||
# is removed.
|
||||
# This setting is no longer used.
|
||||
cache_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@"
|
||||
|
||||
# Configuration option devices/cache_file_prefix.
|
||||
# A prefix used before the .cache file name. See devices/cache_dir.
|
||||
# This setting is no longer used.
|
||||
cache_file_prefix = ""
|
||||
|
||||
# Configuration option devices/write_cache_state.
|
||||
# Enable/disable writing the cache file. See devices/cache_dir.
|
||||
# This setting is no longer used.
|
||||
write_cache_state = 1
|
||||
|
||||
# Configuration option devices/types.
|
||||
@@ -185,20 +179,6 @@ devices {
|
||||
# present on the system. sysfs must be part of the kernel and mounted.)
|
||||
sysfs_scan = 1
|
||||
|
||||
# Configuration option devices/scan_lvs.
|
||||
# Scan LVM LVs for layered PVs, allowing LVs to be used as PVs.
|
||||
# When 1, LVM will detect PVs layered on LVs, and caution must be
|
||||
# taken to avoid a host accessing a layered VG that may not belong
|
||||
# to it, e.g. from a guest image. This generally requires excluding
|
||||
# the LVs with device filters. Also, when this setting is enabled,
|
||||
# every LVM command will scan every active LV on the system (unless
|
||||
# filtered), which can cause performance problems on systems with
|
||||
# many active LVs. When this setting is 0, LVM will not detect or
|
||||
# use PVs that exist on LVs, and will not allow a PV to be created on
|
||||
# an LV. The LVs are ignored using a built in device filter that
|
||||
# identifies and excludes LVs.
|
||||
scan_lvs = 0
|
||||
|
||||
# Configuration option devices/multipath_component_detection.
|
||||
# Ignore devices that are components of DM multipath devices.
|
||||
multipath_component_detection = 1
|
||||
@@ -283,11 +263,7 @@ devices {
|
||||
ignore_lvm_mirrors = 1
|
||||
|
||||
# Configuration option devices/disable_after_error_count.
|
||||
# Number of I/O errors after which a device is skipped.
|
||||
# During each LVM operation, errors received from each device are
|
||||
# counted. If the counter of a device exceeds the limit set here,
|
||||
# no further I/O is sent to that device for the remainder of the
|
||||
# operation. Setting this to 0 disables the counters altogether.
|
||||
# This setting is no longer used.
|
||||
disable_after_error_count = 0
|
||||
|
||||
# Configuration option devices/require_restorefile_with_uuid.
|
||||
@@ -326,12 +302,6 @@ devices {
|
||||
# Enabling this setting allows the VG to be used as usual even with
|
||||
# uncertain devices.
|
||||
allow_changes_with_duplicate_pvs = 0
|
||||
|
||||
# Configuration option devices/allow_mixed_block_sizes.
|
||||
# Allow PVs in the same VG with different logical block sizes.
|
||||
# When allowed, the user is responsible to ensure that an LV is
|
||||
# using PVs with matching block sizes when necessary.
|
||||
allow_mixed_block_sizes = 1
|
||||
}
|
||||
|
||||
# Configuration section allocation.
|
||||
@@ -467,16 +437,9 @@ allocation {
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
|
||||
# Thin pool metadata and data will always use different PVs.
|
||||
# Thin pool metdata and data will always use different PVs.
|
||||
thin_pool_metadata_require_separate_pvs = 0
|
||||
|
||||
# Configuration option allocation/thin_pool_crop_metadata.
|
||||
# Older version of lvm2 cropped pool's metadata size to 15.81 GiB.
|
||||
# This is slightly less then the actual maximum 15.88 GiB.
|
||||
# For compatibility with older version and use of cropped size set to 1.
|
||||
# This configuration option has an automatic default value.
|
||||
# thin_pool_crop_metadata = 0
|
||||
|
||||
# Configuration option allocation/thin_pool_zero.
|
||||
# Thin pool data chunks are zeroed before they are first used.
|
||||
# Zeroing with a larger thin pool chunk size reduces performance.
|
||||
@@ -512,10 +475,6 @@ allocation {
|
||||
# This configuration option has an automatic default value.
|
||||
# thin_pool_chunk_size_policy = "generic"
|
||||
|
||||
# Configuration option allocation/zero_metadata.
|
||||
# Zero whole metadata area before use with thin or cache pool.
|
||||
zero_metadata = 1
|
||||
|
||||
# Configuration option allocation/thin_pool_chunk_size.
|
||||
# The minimal chunk size in KiB for thin pool volumes.
|
||||
# Larger chunk sizes may improve performance for plain thin volumes,
|
||||
@@ -529,6 +488,149 @@ allocation {
|
||||
# Default physical extent size in KiB to use for new VGs.
|
||||
# This configuration option has an automatic default value.
|
||||
# physical_extent_size = 4096
|
||||
|
||||
# Configuration option allocation/vdo_use_compression.
|
||||
# Enables or disables compression when creating a VDO volume.
|
||||
# Compression may be disabled if necessary to maximize performance
|
||||
# or to speed processing of data that is unlikely to compress.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_use_compression = 1
|
||||
|
||||
# Configuration option allocation/vdo_use_deduplication.
|
||||
# Enables or disables deduplication when creating a VDO volume.
|
||||
# Deduplication may be disabled in instances where data is not expected
|
||||
# to have good deduplication rates but compression is still desired.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_use_deduplication = 1
|
||||
|
||||
# Configuration option allocation/vdo_emulate_512_sectors.
|
||||
# Specifies that the VDO volume is to emulate a 512 byte block device.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_emulate_512_sectors = 0
|
||||
|
||||
# Configuration option allocation/vdo_block_map_cache_size_mb.
|
||||
# Specifies the amount of memory in MiB allocated for caching block map
|
||||
# pages for VDO volume. The value must be a multiple of 4096 and must be
|
||||
# at least 128MiB and less than 16TiB. The cache must be at least 16MiB
|
||||
# per logical thread. Note that there is a memory overhead of 15%.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_block_map_cache_size_mb = 128
|
||||
|
||||
# Configuration option allocation/vdo_block_map_period.
|
||||
# Tunes the quantity of block map updates that can accumulate
|
||||
# before cache pages are flushed to disk. The value must be
|
||||
# at least 1 and less then 16380.
|
||||
# A lower value means shorter recovery time but lower performance.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_block_map_period = 16380
|
||||
|
||||
# Configuration option allocation/vdo_check_point_frequency.
|
||||
# The default check point frequency for VDO volume.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_check_point_frequency = 0
|
||||
|
||||
# Configuration option allocation/vdo_use_sparse_index.
|
||||
# Enables sparse indexing for VDO volume.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_use_sparse_index = 0
|
||||
|
||||
# Configuration option allocation/vdo_index_memory_size_mb.
|
||||
# Specifies the amount of index memory in MiB for VDO volume.
|
||||
# The value must be at least 256MiB and at most 1TiB.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_index_memory_size_mb = 256
|
||||
|
||||
# Configuration option allocation/vdo_use_read_cache.
|
||||
# Enables or disables the read cache within the VDO volume.
|
||||
# The cache should be enabled if write workloads are expected
|
||||
# to have high levels of deduplication, or for read intensive
|
||||
# workloads of highly compressible data.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_use_read_cache = 0
|
||||
|
||||
# Configuration option allocation/vdo_read_cache_size_mb.
|
||||
# Specifies the extra VDO volume read cache size in MiB.
|
||||
# This space is in addition to a system-defined minimum.
|
||||
# The value must be less then 16TiB and 1.12 MiB of memory
|
||||
# will be used per MiB of read cache specified, per bio thread.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_read_cache_size_mb = 0
|
||||
|
||||
# Configuration option allocation/vdo_slab_size_mb.
|
||||
# Specifies the size in MiB of the increment by which a VDO is grown.
|
||||
# Using a smaller size constrains the total maximum physical size
|
||||
# that can be accommodated. Must be a power of two between 128MiB and 32GiB.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_slab_size_mb = 2048
|
||||
|
||||
# Configuration option allocation/vdo_ack_threads.
|
||||
# Specifies the number of threads to use for acknowledging
|
||||
# completion of requested VDO I/O operations.
|
||||
# The value must be at in range [0..100].
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_ack_threads = 1
|
||||
|
||||
# Configuration option allocation/vdo_bio_threads.
|
||||
# Specifies the number of threads to use for submitting I/O
|
||||
# operations to the storage device of VDO volume.
|
||||
# The value must be in range [1..100]
|
||||
# Each additional thread after the first will use an additional 18MiB of RAM,
|
||||
# plus 1.12 MiB of RAM per megabyte of configured read cache size.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_bio_threads = 1
|
||||
|
||||
# Configuration option allocation/vdo_bio_rotation.
|
||||
# Specifies the number of I/O operations to enqueue for each bio-submission
|
||||
# thread before directing work to the next. The value must be in range [1..1024].
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_bio_rotation = 64
|
||||
|
||||
# Configuration option allocation/vdo_cpu_threads.
|
||||
# Specifies the number of threads to use for CPU-intensive work such as
|
||||
# hashing or compression for VDO volume. The value must be in range [1..100]
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_cpu_threads = 2
|
||||
|
||||
# Configuration option allocation/vdo_hash_zone_threads.
|
||||
# Specifies the number of threads across which to subdivide parts of the VDO
|
||||
# processing based on the hash value computed from the block data.
|
||||
# The value must be at in range [0..100].
|
||||
# vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
|
||||
# either all zero or all non-zero.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_hash_zone_threads = 1
|
||||
|
||||
# Configuration option allocation/vdo_logical_threads.
|
||||
# Specifies the number of threads across which to subdivide parts of the VDO
|
||||
# processing based on the hash value computed from the block data.
|
||||
# A logical thread count of 9 or more will require explicitly specifying
|
||||
# a sufficiently large block map cache size, as well.
|
||||
# The value must be in range [0..100].
|
||||
# vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
|
||||
# either all zero or all non-zero.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_logical_threads = 1
|
||||
|
||||
# Configuration option allocation/vdo_physical_threads.
|
||||
# Specifies the number of threads across which to subdivide parts of the VDO
|
||||
# processing based on physical block addresses.
|
||||
# Each additional thread after the first will use an additional 10MiB of RAM.
|
||||
# The value must be in range [0..16].
|
||||
# vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
|
||||
# either all zero or all non-zero.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_physical_threads = 1
|
||||
|
||||
# Configuration option allocation/vdo_write_policy.
|
||||
# Specifies the write policy:
|
||||
# auto - VDO will check the storage device and determine whether it supports flushes.
|
||||
# If it does, VDO will run in async mode, otherwise it will run in sync mode.
|
||||
# sync - Writes are acknowledged only after data is stably written.
|
||||
# This policy is not supported if the underlying storage is not also synchronous.
|
||||
# async - Writes are acknowledged after data has been cached for writing to stable storage.
|
||||
# Data which has not been flushed is not guaranteed to persist in this mode.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_write_policy = "auto"
|
||||
}
|
||||
|
||||
# Configuration section log.
|
||||
@@ -759,34 +861,7 @@ global {
|
||||
etc = "@CONFDIR@"
|
||||
|
||||
# Configuration option global/locking_type.
|
||||
# Type of locking to use.
|
||||
#
|
||||
# Accepted values:
|
||||
# 0
|
||||
# Turns off locking. Warning: this risks metadata corruption if
|
||||
# commands run concurrently.
|
||||
# 1
|
||||
# LVM uses local file-based locking, the standard mode.
|
||||
# 2
|
||||
# LVM uses the external shared library locking_library.
|
||||
# 3
|
||||
# LVM uses built-in clustered locking with clvmd.
|
||||
# This is incompatible with lvmetad. If use_lvmetad is enabled,
|
||||
# LVM prints a warning and disables lvmetad use.
|
||||
# 4
|
||||
# LVM uses read-only locking which forbids any operations that
|
||||
# might change metadata.
|
||||
# 5
|
||||
# Offers dummy locking for tools that do not need any locks.
|
||||
# You should not need to set this directly; the tools will select
|
||||
# when to use it instead of the configured locking_type.
|
||||
# Do not use lvmetad or the kernel device-mapper driver with this
|
||||
# locking type. It is used by the --readonly option that offers
|
||||
# read-only access to Volume Group metadata that cannot be locked
|
||||
# safely because it belongs to an inaccessible domain and might be
|
||||
# in use, for example a virtual machine image or a disk that is
|
||||
# shared by a clustered machine.
|
||||
#
|
||||
# This setting is no longer used.
|
||||
locking_type = 1
|
||||
|
||||
# Configuration option global/wait_for_locks.
|
||||
@@ -794,19 +869,11 @@ global {
|
||||
wait_for_locks = 1
|
||||
|
||||
# Configuration option global/fallback_to_clustered_locking.
|
||||
# Attempt to use built-in cluster locking if locking_type 2 fails.
|
||||
# If using external locking (type 2) and initialisation fails, with
|
||||
# this enabled, an attempt will be made to use the built-in clustered
|
||||
# locking. Disable this if using a customised locking_library.
|
||||
# This setting is no longer used.
|
||||
fallback_to_clustered_locking = 1
|
||||
|
||||
# Configuration option global/fallback_to_local_locking.
|
||||
# Use locking_type 1 (local) if locking_type 2 or 3 fail.
|
||||
# If an attempt to initialise type 2 or type 3 locking failed, perhaps
|
||||
# because cluster components such as clvmd are not running, with this
|
||||
# enabled, an attempt will be made to use local file-based locking
|
||||
# (type 1). If this succeeds, only commands against local VGs will
|
||||
# proceed. VGs marked as clustered will be ignored.
|
||||
# This setting is no longer used.
|
||||
fallback_to_local_locking = 1
|
||||
|
||||
# Configuration option global/locking_dir.
|
||||
@@ -830,7 +897,7 @@ global {
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
# Configuration option global/locking_library.
|
||||
# The external locking library to use for locking_type 2.
|
||||
# This setting is no longer used.
|
||||
# This configuration option has an automatic default value.
|
||||
# locking_library = "liblvm2clusterlock.so"
|
||||
|
||||
@@ -922,11 +989,6 @@ global {
|
||||
# This configuration option has an automatic default value.
|
||||
# lvdisplay_shows_full_device_path = 0
|
||||
|
||||
# Configuration option global/use_aio.
|
||||
# Use async I/O when reading and writing devices.
|
||||
# This configuration option has an automatic default value.
|
||||
# use_aio = 1
|
||||
|
||||
# Configuration option global/use_lvmetad.
|
||||
# Use lvmetad to cache metadata and reduce disk scanning.
|
||||
# When enabled (and running), lvmetad provides LVM commands with VG
|
||||
@@ -1087,6 +1149,17 @@ global {
|
||||
# This configuration option has an automatic default value.
|
||||
# cache_repair_options = [ "" ]
|
||||
|
||||
# Configuration option global/vdo_format_executable.
|
||||
# The full path to the vdoformat command.
|
||||
# LVM uses this command to initial data volume for VDO type logical volume
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_format_executable = "@VDO_FORMAT_CMD@"
|
||||
|
||||
# Configuration option global/vdo_format_options.
|
||||
# List of options passed added to standard vdoformat command.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_format_options = [ "" ]
|
||||
|
||||
# Configuration option global/fsadm_executable.
|
||||
# The full path to the fsadm command.
|
||||
# LVM uses this command to help with lvresize -r operations.
|
||||
@@ -1144,16 +1217,6 @@ global {
|
||||
# When enabled, an LVM command that changes PVs, changes VG metadata,
|
||||
# or changes the activation state of an LV will send a notification.
|
||||
notify_dbus = 1
|
||||
|
||||
# Configuration option global/io_memory_size.
|
||||
# The amount of memory in KiB that LVM allocates to perform disk io.
|
||||
# LVM performance may benefit from more io memory when there are many
|
||||
# disks or VG metadata is large. Increasing this size may be necessary
|
||||
# when a single copy of VG metadata is larger than the current setting.
|
||||
# This value should usually not be decreased from the default; setting
|
||||
# it too low can result in lvm failing to read VGs.
|
||||
# This configuration option has an automatic default value.
|
||||
# io_memory_size = 8192
|
||||
}
|
||||
|
||||
# Configuration section activation.
|
||||
@@ -1470,6 +1533,33 @@ activation {
|
||||
#
|
||||
thin_pool_autoextend_percent = 20
|
||||
|
||||
# Configuration option activation/vdo_pool_autoextend_threshold.
|
||||
# Auto-extend a VDO pool when its usage exceeds this percent.
|
||||
# Setting this to 100 disables automatic extension.
|
||||
# The minimum value is 50 (a smaller value is treated as 50.)
|
||||
# Also see vdo_pool_autoextend_percent.
|
||||
# Automatic extension requires dmeventd to be monitoring the LV.
|
||||
#
|
||||
# Example
|
||||
# Using 70% autoextend threshold and 20% autoextend size, when a 10G
|
||||
# VDO pool exceeds 7G, it is extended to 12G, and when it exceeds
|
||||
# 8.4G, it is extended to 14.4G:
|
||||
# vdo_pool_autoextend_threshold = 70
|
||||
#
|
||||
vdo_pool_autoextend_threshold = 100
|
||||
|
||||
# Configuration option activation/vdo_pool_autoextend_percent.
|
||||
# Auto-extending a VDO pool adds this percent extra space.
|
||||
# The amount of additional space added to a VDO pool is this
|
||||
# percent of its current size.
|
||||
#
|
||||
# Example
|
||||
# Using 70% autoextend threshold and 20% autoextend size, when a 10G
|
||||
# VDO pool exceeds 7G, it is extended to 12G, and when it exceeds
|
||||
# 8.4G, it is extended to 14.4G:
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_pool_autoextend_percent = 20
|
||||
|
||||
# Configuration option activation/mlock_filter.
|
||||
# Do not mlock these memory areas.
|
||||
# While activating devices, I/O to devices being (re)configured is
|
||||
@@ -1638,20 +1728,7 @@ activation {
|
||||
# stripesize = 64
|
||||
|
||||
# Configuration option metadata/dirs.
|
||||
# Directories holding live copies of text format metadata.
|
||||
# These directories must not be on logical volumes!
|
||||
# It's possible to use LVM with a couple of directories here,
|
||||
# preferably on different (non-LV) filesystems, and with no other
|
||||
# on-disk metadata (pvmetadatacopies = 0). Or this can be in addition
|
||||
# to on-disk metadata areas. The feature was originally added to
|
||||
# simplify testing and is not supported under low memory situations -
|
||||
# the machine could lock up. Never edit any files in these directories
|
||||
# by hand unless you are absolutely sure you know what you are doing!
|
||||
# Use the supplied toolset to make changes (e.g. vgcfgrestore).
|
||||
#
|
||||
# Example
|
||||
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
|
||||
#
|
||||
# This setting is no longer used.
|
||||
# This configuration option is advanced.
|
||||
# This configuration option does not have a default value defined.
|
||||
# }
|
||||
@@ -2104,6 +2181,23 @@ dmeventd {
|
||||
# This configuration option has an automatic default value.
|
||||
# thin_command = "lvm lvextend --use-policies"
|
||||
|
||||
# Configuration option dmeventd/vdo_library.
|
||||
# The library dmeventd uses when monitoring a VDO pool device.
|
||||
# libdevmapper-event-lvm2vdo.so monitors the filling of a pool
|
||||
# and emits a warning through syslog when the usage exceeds 80%. The
|
||||
# warning is repeated when 85%, 90% and 95% of the pool is filled.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_library = "libdevmapper-event-lvm2vdo.so"
|
||||
|
||||
# Configuration option dmeventd/vdo_command.
|
||||
# The plugin runs command with each 5% increment when VDO pool volume
|
||||
# gets above 50%.
|
||||
# Command which starts with 'lvm ' prefix is internal lvm command.
|
||||
# You can write your own handler to customise behaviour in more details.
|
||||
# User handler is specified with the full path starting with '/'.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_command = "lvm lvextend --use-policies"
|
||||
|
||||
# Configuration option dmeventd/executable.
|
||||
# The full path to the dmeventd binary.
|
||||
# This configuration option has an automatic default value.
|
||||
|
||||
25
conf/vdo-small.profile
Normal file
25
conf/vdo-small.profile
Normal file
@@ -0,0 +1,25 @@
|
||||
# Demo configuration for 'VDO' using less memory.
|
||||
#
|
||||
|
||||
allocation {
|
||||
vdo_use_compression = 1
|
||||
vdo_use_deduplication = 1
|
||||
vdo_emulate_512_sectors = 0
|
||||
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_use_read_cache = 0
|
||||
vdo_read_cache_size_mb = 0
|
||||
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"
|
||||
}
|
||||
539
configure.ac
539
configure.ac
@@ -39,14 +39,12 @@ case "$host_os" in
|
||||
LDDEPS="$LDDEPS .export.sym"
|
||||
LIB_SUFFIX=so
|
||||
DEVMAPPER=yes
|
||||
BUILD_LVMETAD=no
|
||||
BUILD_LVMPOLLD=no
|
||||
LOCKDSANLOCK=no
|
||||
LOCKDDLM=no
|
||||
ODIRECT=yes
|
||||
DM_IOCTLS=yes
|
||||
SELINUX=yes
|
||||
CLUSTER=internal
|
||||
FSADM=yes
|
||||
BLKDEACTIVATE=yes
|
||||
;;
|
||||
@@ -61,7 +59,6 @@ case "$host_os" in
|
||||
ODIRECT=no
|
||||
DM_IOCTLS=no
|
||||
SELINUX=no
|
||||
CLUSTER=none
|
||||
FSADM=no
|
||||
BLKDEACTIVATE=no
|
||||
;;
|
||||
@@ -142,11 +139,12 @@ AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
AX_GCC_BUILTIN([__builtin_clz])
|
||||
AX_GCC_BUILTIN([__builtin_clzll])
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for functions
|
||||
AC_CHECK_FUNCS([ftruncate gethostname getpagesize gettimeofday localtime_r \
|
||||
memchr memset mkdir mkfifo munmap nl_langinfo pselect realpath rmdir setenv \
|
||||
memchr memset mkdir mkfifo munmap nl_langinfo realpath rmdir setenv \
|
||||
setlocale strcasecmp strchr strcspn strdup strerror strncasecmp strndup \
|
||||
strrchr strspn strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
|
||||
AC_FUNC_ALLOCA
|
||||
@@ -172,6 +170,15 @@ AC_ARG_ENABLE(dependency-tracking,
|
||||
USE_TRACKING=$enableval, USE_TRACKING=yes)
|
||||
AC_MSG_RESULT($USE_TRACKING)
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable silence rules
|
||||
AC_MSG_CHECKING(whether to build silently)
|
||||
AC_ARG_ENABLE(silent-rules,
|
||||
AC_HELP_STRING([--disable-silent-rules], [disable silent building]),
|
||||
SILENT_RULES=$enableval, SILENT_RULES=yes)
|
||||
AC_MSG_RESULT($SILENT_RULES)
|
||||
|
||||
|
||||
################################################################################
|
||||
dnl -- Enables statically-linked tools
|
||||
AC_MSG_CHECKING(whether to use static linking)
|
||||
@@ -282,22 +289,6 @@ esac
|
||||
AC_MSG_RESULT($MANGLING)
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_DM_NAME_MANGLING], $mangling, [Define default name mangling behaviour])
|
||||
|
||||
################################################################################
|
||||
dnl -- cluster_locking inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for cluster locking)
|
||||
AC_ARG_WITH(cluster,
|
||||
AC_HELP_STRING([--with-cluster=TYPE],
|
||||
[cluster LVM locking support: internal/shared/none [internal]]),
|
||||
CLUSTER=$withval)
|
||||
AC_MSG_RESULT($CLUSTER)
|
||||
|
||||
case "$CLUSTER" in
|
||||
none|shared) ;;
|
||||
internal) AC_DEFINE([CLUSTER_LOCKING_INTERNAL], 1,
|
||||
[Define to 1 to include built-in support for clustered LVM locking.]) ;;
|
||||
*) AC_MSG_ERROR([--with-cluster parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- snapshots inclusion type
|
||||
AC_MSG_CHECKING(whether to include snapshots)
|
||||
@@ -600,6 +591,53 @@ AC_DEFINE_UNQUOTED([CACHE_REPAIR_CMD], ["$CACHE_REPAIR_CMD"],
|
||||
AC_DEFINE_UNQUOTED([CACHE_RESTORE_CMD], ["$CACHE_RESTORE_CMD"],
|
||||
[The path to 'cache_restore', if available.])
|
||||
|
||||
################################################################################
|
||||
dnl -- cache inclusion type
|
||||
AC_MSG_CHECKING(whether to include vdo)
|
||||
AC_ARG_WITH(vdo,
|
||||
AC_HELP_STRING([--with-vdo=TYPE],
|
||||
[vdo support: internal/none [internal]]),
|
||||
VDO=$withval, VDO="none")
|
||||
|
||||
AC_MSG_RESULT($VDO)
|
||||
|
||||
AC_ARG_WITH(vdo-format,
|
||||
AC_HELP_STRING([--with-vdo-format=PATH],
|
||||
[vdoformat tool: [autodetect]]),
|
||||
VDO_FORMAT_CMD=$withval, VDO_FORMAT_CMD="autodetect")
|
||||
case "$VDO" in
|
||||
none) ;;
|
||||
internal)
|
||||
AC_DEFINE([VDO_INTERNAL], 1, [Define to 1 to include built-in support for vdo.])
|
||||
if test "$VDO_FORMAT_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(VDO_FORMAT_CMD, vdoformat, [], [$PATH])
|
||||
if test -z "$VDO_FORMAT_CMD"; then
|
||||
AC_MSG_WARN([vdoformat not found in path $PATH])
|
||||
VDO_FORMAT_CMD=/usr/bin/vdoformat
|
||||
VDO_CONFIGURE_WARN=y
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*) AC_MSG_ERROR([--with-vdo parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
AC_DEFINE_UNQUOTED([VDO_FORMAT_CMD], ["$VDO_FORMAT_CMD"],
|
||||
[The path to 'vdoformat', if available.])
|
||||
#
|
||||
# Do we need to use the API??
|
||||
# Do we want to link lvm2 with a big library for vdoformating ?
|
||||
#
|
||||
#AC_ARG_WITH(vdo-include,
|
||||
# AC_HELP_STRING([--with-vdo-include=PATH],
|
||||
# [vdo support: Path to utils headers: [/usr/include/vdo/utils]]),
|
||||
# VDO_INCLUDE=$withval, VDO_INCLUDE="/usr/include/vdo/utils")
|
||||
#AC_MSG_RESULT($VDO_INCLUDE)
|
||||
#
|
||||
#AC_ARG_WITH(vdo-lib,
|
||||
# AC_HELP_STRING([--with-vdo-lib=PATH],
|
||||
# [vdo support: Path to utils lib: [/usr/lib]]),
|
||||
# VDO_LIB=$withval, VDO_LIB="/usr/lib")
|
||||
#AC_MSG_RESULT($VDO_LIB)
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable readline
|
||||
@@ -607,12 +645,6 @@ AC_ARG_ENABLE([readline],
|
||||
AC_HELP_STRING([--disable-readline], [disable readline support]),
|
||||
READLINE=$enableval, READLINE=maybe)
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable editline
|
||||
AC_ARG_ENABLE([editline],
|
||||
AC_HELP_STRING([--enable-editline], [enable editline support]),
|
||||
EDITLINE=$enableval, EDITLINE=no)
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable realtime clock support
|
||||
AC_MSG_CHECKING(whether to enable realtime support)
|
||||
@@ -656,7 +688,7 @@ dnl -- Set up pidfile and run directory
|
||||
AH_TEMPLATE(DEFAULT_PID_DIR)
|
||||
AC_ARG_WITH(default-pid-dir,
|
||||
AC_HELP_STRING([--with-default-pid-dir=PID_DIR],
|
||||
[default directory to keep PID files in [autodetect]]),
|
||||
[Default directory to keep PID files in. [autodetect]]),
|
||||
DEFAULT_PID_DIR="$withval", DEFAULT_PID_DIR=$RUN_DIR)
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"],
|
||||
[Default directory to keep PID files in.])
|
||||
@@ -664,7 +696,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"],
|
||||
AH_TEMPLATE(DEFAULT_DM_RUN_DIR, [Name of default DM run directory.])
|
||||
AC_ARG_WITH(default-dm-run-dir,
|
||||
AC_HELP_STRING([--with-default-dm-run-dir=DM_RUN_DIR],
|
||||
[default DM run directory [autodetect]]),
|
||||
[ Default DM run directory. [autodetect]]),
|
||||
DEFAULT_DM_RUN_DIR="$withval", DEFAULT_DM_RUN_DIR=$RUN_DIR)
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"],
|
||||
[Default DM run directory.])
|
||||
@@ -672,246 +704,11 @@ AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"],
|
||||
AH_TEMPLATE(DEFAULT_RUN_DIR, [Name of default LVM run directory.])
|
||||
AC_ARG_WITH(default-run-dir,
|
||||
AC_HELP_STRING([--with-default-run-dir=RUN_DIR],
|
||||
[default LVM run directory [autodetect_run_dir/lvm]]),
|
||||
[Default LVM run directory. [autodetect_run_dir/lvm]]),
|
||||
DEFAULT_RUN_DIR="$withval", DEFAULT_RUN_DIR="$RUN_DIR/lvm")
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
|
||||
[Default LVM run directory.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Build cluster LVM daemon
|
||||
AC_MSG_CHECKING(whether to build cluster LVM daemon)
|
||||
AC_ARG_WITH(clvmd,
|
||||
[ --with-clvmd=TYPE build cluster LVM Daemon
|
||||
The following cluster manager combinations are valid:
|
||||
* cman (RHEL5 or equivalent)
|
||||
* cman,corosync,openais (or selection of them)
|
||||
* singlenode (localhost only)
|
||||
* all (autodetect)
|
||||
* none (disable build)
|
||||
[[none]]],
|
||||
CLVMD=$withval, CLVMD=none)
|
||||
test "$CLVMD" = yes && CLVMD=all
|
||||
AC_MSG_RESULT($CLVMD)
|
||||
|
||||
dnl -- If clvmd enabled without cluster locking, automagically include it
|
||||
test "$CLVMD" != none -a "$CLUSTER" = none && CLUSTER=internal
|
||||
|
||||
dnl -- init pkgconfig if required
|
||||
test "$CLVMD" != none && pkg_config_init
|
||||
|
||||
dnl -- Express clvmd init script Required-Start / Required-Stop
|
||||
CLVMD_CMANAGERS=""
|
||||
dnl -- On RHEL4/RHEL5, qdiskd is started from a separate init script.
|
||||
dnl -- Enable if we are build for cman.
|
||||
CLVMD_NEEDS_QDISKD=no
|
||||
|
||||
dnl -- define build types
|
||||
if [[ `expr x"$CLVMD" : '.*gulm.*'` != 0 ]]; then
|
||||
AC_MSG_ERROR([Since version 2.02.87 GULM locking is no longer supported.]);
|
||||
fi
|
||||
if [[ `expr x"$CLVMD" : '.*cman.*'` != 0 ]]; then
|
||||
BUILDCMAN=yes
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
|
||||
CLVMD_NEEDS_QDISKD=yes
|
||||
fi
|
||||
if [[ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]]; then
|
||||
BUILDCOROSYNC=yes
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
|
||||
fi
|
||||
if [[ `expr x"$CLVMD" : '.*openais.*'` != 0 ]]; then
|
||||
BUILDOPENAIS=yes
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
|
||||
fi
|
||||
test "$CLVMD_NEEDS_QDISKD" != no && CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
|
||||
|
||||
dnl -- define a soft bailout if we are autodetecting
|
||||
soft_bailout() {
|
||||
NOTFOUND=1
|
||||
}
|
||||
|
||||
hard_bailout() {
|
||||
AC_MSG_ERROR([bailing out])
|
||||
}
|
||||
|
||||
dnl -- if clvmd=all then set soft_bailout (we do not want to error)
|
||||
dnl -- and set all builds to yes. We need to do this here
|
||||
dnl -- to skip the openais|corosync sanity check above.
|
||||
if test "$CLVMD" = all; then
|
||||
bailout=soft_bailout
|
||||
BUILDCMAN=yes
|
||||
BUILDCOROSYNC=yes
|
||||
BUILDOPENAIS=yes
|
||||
else
|
||||
bailout=hard_bailout
|
||||
fi
|
||||
|
||||
dnl -- helper macro to check libs without adding them to LIBS
|
||||
check_lib_no_libs() {
|
||||
lib_no_libs_arg1=$1
|
||||
shift
|
||||
lib_no_libs_arg2=$1
|
||||
shift
|
||||
lib_no_libs_args=$@
|
||||
AC_CHECK_LIB([$lib_no_libs_arg1],
|
||||
[$lib_no_libs_arg2],,
|
||||
[$bailout],
|
||||
[$lib_no_libs_args])
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
}
|
||||
|
||||
dnl -- Look for cman libraries if required.
|
||||
if test "$BUILDCMAN" = yes; then
|
||||
PKG_CHECK_MODULES(CMAN, libcman, [HAVE_CMAN=yes],
|
||||
[NOTFOUND=0
|
||||
AC_CHECK_HEADERS(libcman.h,,$bailout)
|
||||
check_lib_no_libs cman cman_init
|
||||
if test $NOTFOUND = 0; then
|
||||
AC_MSG_RESULT([no pkg for libcman, using -lcman])
|
||||
CMAN_LIBS="-lcman"
|
||||
HAVE_CMAN=yes
|
||||
fi])
|
||||
CHECKCONFDB=yes
|
||||
CHECKDLM=yes
|
||||
fi
|
||||
|
||||
dnl -- Look for corosync that is required also for openais build
|
||||
dnl -- only enough recent version of corosync ship pkg-config files.
|
||||
dnl -- We can safely rely on that to detect the correct bits.
|
||||
if test "$BUILDCOROSYNC" = yes -o "$BUILDOPENAIS" = yes; then
|
||||
PKG_CHECK_MODULES(COROSYNC, corosync, [HAVE_COROSYNC=yes], $bailout)
|
||||
CHECKCONFDB=yes
|
||||
CHECKCMAP=yes
|
||||
fi
|
||||
|
||||
dnl -- Look for corosync libraries if required.
|
||||
if test "$BUILDCOROSYNC" = yes; then
|
||||
PKG_CHECK_MODULES(QUORUM, libquorum, [HAVE_QUORUM=yes], $bailout)
|
||||
CHECKCPG=yes
|
||||
CHECKDLM=yes
|
||||
fi
|
||||
|
||||
dnl -- Look for openais libraries if required.
|
||||
if test "$BUILDOPENAIS" = yes; then
|
||||
PKG_CHECK_MODULES(SALCK, libSaLck, [HAVE_SALCK=yes], $bailout)
|
||||
CHECKCPG=yes
|
||||
fi
|
||||
|
||||
dnl -- Below are checks for libraries common to more than one build.
|
||||
|
||||
dnl -- Check confdb library.
|
||||
dnl -- mandatory for corosync < 2.0 build.
|
||||
dnl -- optional for openais/cman build.
|
||||
|
||||
if test "$CHECKCONFDB" = yes; then
|
||||
PKG_CHECK_MODULES(CONFDB, libconfdb,
|
||||
[HAVE_CONFDB=yes], [HAVE_CONFDB=no])
|
||||
|
||||
AC_CHECK_HEADERS([corosync/confdb.h],
|
||||
[HAVE_CONFDB_H=yes], [HAVE_CONFDB_H=no])
|
||||
|
||||
if test "$HAVE_CONFDB" != yes -a "$HAVE_CONFDB_H" = yes; then
|
||||
check_lib_no_libs confdb confdb_initialize
|
||||
AC_MSG_RESULT([no pkg for confdb, using -lconfdb])
|
||||
CONFDB_LIBS="-lconfdb"
|
||||
HAVE_CONFDB=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl -- Check cmap library
|
||||
dnl -- mandatory for corosync >= 2.0 build.
|
||||
|
||||
if test "$CHECKCMAP" = yes; then
|
||||
PKG_CHECK_MODULES(CMAP, libcmap,
|
||||
[HAVE_CMAP=yes], [HAVE_CMAP=no])
|
||||
|
||||
AC_CHECK_HEADERS([corosync/cmap.h],
|
||||
[HAVE_CMAP_H=yes], [HAVE_CMAP_H=no])
|
||||
|
||||
if test "$HAVE_CMAP" != yes -a "$HAVE_CMAP_H" = yes; then
|
||||
check_lib_no_libs cmap cmap_initialize
|
||||
AC_MSG_RESULT([no pkg for cmap, using -lcmap])
|
||||
CMAP_LIBS="-lcmap"
|
||||
HAVE_CMAP=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$BUILDCOROSYNC" = yes -a \
|
||||
"$HAVE_CMAP" != yes -a "$HAVE_CONFDB" != yes -a "$CLVMD" != all; then
|
||||
AC_MSG_ERROR([bailing out... cmap (corosync >= 2.0) or confdb (corosync < 2.0) library is required])
|
||||
fi
|
||||
|
||||
dnl -- Check cpg library.
|
||||
if test "$CHECKCPG" = yes; then
|
||||
PKG_CHECK_MODULES(CPG, libcpg, [HAVE_CPG=yes], [$bailout])
|
||||
fi
|
||||
|
||||
dnl -- Check dlm library.
|
||||
if test "$CHECKDLM" = yes; then
|
||||
PKG_CHECK_MODULES(DLM, libdlm, [HAVE_DLM=yes],
|
||||
[NOTFOUND=0
|
||||
AC_CHECK_HEADERS(libdlm.h,,[$bailout])
|
||||
check_lib_no_libs dlm dlm_lock -lpthread
|
||||
if test $NOTFOUND = 0; then
|
||||
AC_MSG_RESULT([no pkg for libdlm, using -ldlm])
|
||||
DLM_LIBS="-ldlm -lpthread"
|
||||
HAVE_DLM=yes
|
||||
fi])
|
||||
fi
|
||||
|
||||
dnl -- If we are autodetecting, we need to re-create
|
||||
dnl -- the depedencies checks and set a proper CLVMD,
|
||||
dnl -- together with init script Required-Start/Stop entries.
|
||||
if test "$CLVMD" = all; then
|
||||
CLVMD=none
|
||||
CLVMD_CMANAGERS=""
|
||||
CLVMD_NEEDS_QDISKD=no
|
||||
if test "$HAVE_CMAN" = yes -a \
|
||||
"$HAVE_DLM" = yes; then
|
||||
AC_MSG_RESULT([Enabling clvmd cman cluster manager])
|
||||
CLVMD="$CLVMD,cman"
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
|
||||
CLVMD_NEEDS_QDISKD=yes
|
||||
fi
|
||||
if test "$HAVE_COROSYNC" = yes -a \
|
||||
"$HAVE_QUORUM" = yes -a \
|
||||
"$HAVE_CPG" = yes -a \
|
||||
"$HAVE_DLM" = yes; then
|
||||
if test "$HAVE_CONFDB" = yes -o "$HAVE_CMAP" = yes; then
|
||||
AC_MSG_RESULT([Enabling clvmd corosync cluster manager])
|
||||
CLVMD="$CLVMD,corosync"
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
|
||||
fi
|
||||
fi
|
||||
if test "$HAVE_COROSYNC" = yes -a \
|
||||
"$HAVE_CPG" = yes -a \
|
||||
"$HAVE_SALCK" = yes; then
|
||||
AC_MSG_RESULT([Enabling clvmd openais cluster manager])
|
||||
CLVMD="$CLVMD,openais"
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
|
||||
fi
|
||||
test "$CLVMD_NEEDS_QDISKD" != no && CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
|
||||
test "$CLVMD" = none && AC_MSG_RESULT([Disabling clvmd build. No cluster manager detected.])
|
||||
fi
|
||||
|
||||
dnl -- Fixup CLVMD_CMANAGERS with new corosync
|
||||
dnl -- clvmd built with corosync >= 2.0 needs dlm (either init or systemd service)
|
||||
dnl -- to be started.
|
||||
if [[ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]]; then
|
||||
test "$HAVE_CMAP" = yes && CLVMD_CMANAGERS="$CLVMD_CMANAGERS dlm"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- clvmd pidfile
|
||||
if test "$CLVMD" != none; then
|
||||
AC_ARG_WITH(clvmd-pidfile,
|
||||
AC_HELP_STRING([--with-clvmd-pidfile=PATH],
|
||||
[clvmd pidfile [PID_DIR/clvmd.pid]]),
|
||||
CLVMD_PIDFILE=$withval,
|
||||
CLVMD_PIDFILE="$DEFAULT_PID_DIR/clvmd.pid")
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PIDFILE, ["$CLVMD_PIDFILE"],
|
||||
[Path to clvmd pidfile.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build cluster mirror log daemon
|
||||
AC_MSG_CHECKING(whether to build cluster mirror log daemon)
|
||||
@@ -940,11 +737,6 @@ dnl -- Look for corosync libraries if required.
|
||||
if [[ "$BUILD_CMIRRORD" = yes ]]; then
|
||||
pkg_config_init
|
||||
|
||||
AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 1, [Define to 1 to include libSaCkpt.])
|
||||
PKG_CHECK_MODULES(SACKPT, libSaCkpt, [HAVE_SACKPT=yes],
|
||||
[AC_MSG_RESULT([no libSaCkpt, compiling without it])
|
||||
AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 0, [Define to 0 to exclude libSaCkpt.])])
|
||||
|
||||
if test "$HAVE_CPG" != yes; then
|
||||
PKG_CHECK_MODULES(CPG, libcpg)
|
||||
fi
|
||||
@@ -1050,16 +842,6 @@ if test "$DEVMAPPER" = yes; then
|
||||
AC_DEFINE([DEVMAPPER_SUPPORT], 1, [Define to 1 to enable LVM2 device-mapper interaction.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmetad
|
||||
AC_MSG_CHECKING(whether to build LVMetaD)
|
||||
AC_ARG_ENABLE(lvmetad,
|
||||
AC_HELP_STRING([--enable-lvmetad],
|
||||
[enable the LVM Metadata Daemon]),
|
||||
LVMETAD=$enableval)
|
||||
test -n "$LVMETAD" && BUILD_LVMETAD=$LVMETAD
|
||||
AC_MSG_RESULT($BUILD_LVMETAD)
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmpolld
|
||||
AC_MSG_CHECKING(whether to build lvmpolld)
|
||||
@@ -1115,9 +897,7 @@ AC_MSG_RESULT($BUILD_LVMLOCKD)
|
||||
|
||||
if test "$BUILD_LVMLOCKD" = yes; then
|
||||
AS_IF([test "$LVMPOLLD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmpolld.])])
|
||||
AS_IF([test "$LVMETAD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmetad.])])
|
||||
AS_IF([test "$BUILD_LVMPOLLD" = no], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
|
||||
AS_IF([test "$BUILD_LVMETAD" = no], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
|
||||
AC_MSG_CHECKING([defaults for use_lvmlockd])
|
||||
AC_ARG_ENABLE(use_lvmlockd,
|
||||
AC_HELP_STRING([--disable-use-lvmlockd],
|
||||
@@ -1142,33 +922,6 @@ fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMLOCKD, [$DEFAULT_USE_LVMLOCKD],
|
||||
[Use lvmlockd by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Check lvmetad
|
||||
if test "$BUILD_LVMETAD" = yes; then
|
||||
AC_MSG_CHECKING([defaults for use_lvmetad])
|
||||
AC_ARG_ENABLE(use_lvmetad,
|
||||
AC_HELP_STRING([--disable-use-lvmetad],
|
||||
[disable usage of LVM Metadata Daemon]),
|
||||
[case ${enableval} in
|
||||
yes) DEFAULT_USE_LVMETAD=1 ;;
|
||||
*) DEFAULT_USE_LVMETAD=0 ;;
|
||||
esac], DEFAULT_USE_LVMETAD=1)
|
||||
AC_MSG_RESULT($DEFAULT_USE_LVMETAD)
|
||||
AC_DEFINE([LVMETAD_SUPPORT], 1, [Define to 1 to include code that uses lvmetad.])
|
||||
|
||||
AC_ARG_WITH(lvmetad-pidfile,
|
||||
AC_HELP_STRING([--with-lvmetad-pidfile=PATH],
|
||||
[lvmetad pidfile [PID_DIR/lvmetad.pid]]),
|
||||
LVMETAD_PIDFILE=$withval,
|
||||
LVMETAD_PIDFILE="$DEFAULT_PID_DIR/lvmetad.pid")
|
||||
AC_DEFINE_UNQUOTED(LVMETAD_PIDFILE, ["$LVMETAD_PIDFILE"],
|
||||
[Path to lvmetad pidfile.])
|
||||
else
|
||||
DEFAULT_USE_LVMETAD=0
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMETAD, [$DEFAULT_USE_LVMETAD],
|
||||
[Use lvmetad by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Check lvmpolld
|
||||
if test "$BUILD_LVMPOLLD" = yes; then
|
||||
@@ -1372,20 +1125,6 @@ if test "$ODIRECT" = yes; then
|
||||
AC_DEFINE([O_DIRECT_SUPPORT], 1, [Define to 1 to enable O_DIRECT support.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable liblvm2app.so
|
||||
AC_MSG_CHECKING(whether to build liblvm2app.so application library)
|
||||
AC_ARG_ENABLE(applib,
|
||||
AC_HELP_STRING([--enable-applib], [build application library]),
|
||||
APPLIB=$enableval, APPLIB=no)
|
||||
AC_MSG_RESULT($APPLIB)
|
||||
AC_SUBST([LVM2APP_LIB])
|
||||
test "$APPLIB" = yes \
|
||||
&& LVM2APP_LIB=-llvm2app \
|
||||
|| LVM2APP_LIB=
|
||||
AS_IF([test "$APPLIB"],
|
||||
[AC_MSG_WARN([liblvm2app is deprecated. Use D-Bus API])])
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable cmdlib
|
||||
AC_MSG_CHECKING(whether to compile liblvm2cmd.so)
|
||||
@@ -1409,47 +1148,9 @@ AS_IF([test "$NOTIFYDBUS_SUPPORT" = yes && test "BUILD_LVMDBUSD" = yes],
|
||||
[AC_MSG_WARN([Building D-Bus support without D-Bus notifications.])])
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable Python liblvm2app bindings
|
||||
AC_MSG_CHECKING(whether to build Python wrapper for liblvm2app.so)
|
||||
AC_ARG_ENABLE(python_bindings,
|
||||
AC_HELP_STRING([--enable-python_bindings], [build default Python applib bindings]),
|
||||
PYTHON_BINDINGS=$enableval, PYTHON_BINDINGS=no)
|
||||
AC_MSG_RESULT($PYTHON_BINDINGS)
|
||||
dnl -- Enable Python dbus library
|
||||
|
||||
AC_MSG_CHECKING(whether to build Python2 wrapper for liblvm2app.so)
|
||||
AC_ARG_ENABLE(python2_bindings,
|
||||
AC_HELP_STRING([--enable-python2_bindings], [build Python2 applib bindings]),
|
||||
PYTHON2_BINDINGS=$enableval, PYTHON2_BINDINGS=no)
|
||||
AC_MSG_RESULT($PYTHON2_BINDINGS)
|
||||
|
||||
|
||||
AC_MSG_CHECKING(whether to build Python3 wrapper for liblvm2app.so)
|
||||
AC_ARG_ENABLE(python3_bindings,
|
||||
AC_HELP_STRING([--enable-python3_bindings], [build Python3 applib bindings]),
|
||||
PYTHON3_BINDINGS=$enableval, PYTHON3_BINDINGS=no)
|
||||
AC_MSG_RESULT($PYTHON3_BINDINGS)
|
||||
|
||||
if test "$PYTHON_BINDINGS" = yes; then
|
||||
AC_MSG_ERROR([--enable-python-bindings is replaced by --enable-python2-bindings and --enable-python3-bindings])
|
||||
fi
|
||||
|
||||
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],[ python3 python2 python dnl
|
||||
python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 dnl
|
||||
python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 ])
|
||||
if test "$PYTHON2_BINDINGS" = yes; then
|
||||
AM_PATH_PYTHON([2])
|
||||
AC_PATH_TOOL(PYTHON2, python2)
|
||||
test -z "$PYTHON2" && AC_MSG_ERROR([python2 is required for --enable-python2_bindings but cannot be found])
|
||||
AC_PATH_TOOL(PYTHON2_CONFIG, python2-config)
|
||||
test -z "$PYTHON2_CONFIG" && AC_PATH_TOOL(PYTHON2_CONFIG, python-config)
|
||||
test -z "$PYTHON2_CONFIG" && AC_MSG_ERROR([python headers are required for --enable-python2_bindings but cannot be found])
|
||||
PYTHON2_INCDIRS=`"$PYTHON2_CONFIG" --includes`
|
||||
PYTHON2_LIBDIRS=`"$PYTHON2_CONFIG" --libs`
|
||||
PYTHON2DIR=$pythondir
|
||||
PYTHON_BINDINGS=yes
|
||||
fi
|
||||
|
||||
if test "$PYTHON3_BINDINGS" = yes -o "$BUILD_LVMDBUSD" = yes; then
|
||||
if test "$BUILD_LVMDBUSD" = yes; then
|
||||
unset PYTHON PYTHON_CONFIG
|
||||
unset am_cv_pathless_PYTHON ac_cv_path_PYTHON am_cv_python_platform
|
||||
unset am_cv_python_pythondir am_cv_python_version am_cv_python_pyexecdir
|
||||
@@ -1463,19 +1164,12 @@ if test "$PYTHON3_BINDINGS" = yes -o "$BUILD_LVMDBUSD" = yes; then
|
||||
PYTHON3_LIBDIRS=`"$PYTHON3_CONFIG" --libs`
|
||||
PYTHON3DIR=$pythondir
|
||||
test "$PYTHON3_BINDINGS" = yes && PYTHON_BINDINGS=yes
|
||||
fi
|
||||
|
||||
if test "$BUILD_LVMDBUSD" = yes; then
|
||||
# To get this macro, install autoconf-archive package then run autoreconf
|
||||
AC_PYTHON_MODULE([pyudev], [Required], python3)
|
||||
AC_PYTHON_MODULE([dbus], [Required], python3)
|
||||
fi
|
||||
|
||||
if test "$PYTHON_BINDINGS" = yes -o "$PYTHON2_BINDINGS" = yes -o "$PYTHON3_BINDINGS" = yes; then
|
||||
AC_MSG_WARN([Python bindings are deprecated. Use D-Bus API])
|
||||
test "$APPLIB" != yes && AC_MSG_ERROR([Python_bindings require --enable-applib])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable pkg-config
|
||||
AC_ARG_ENABLE(pkgconfig,
|
||||
@@ -1547,7 +1241,7 @@ AC_CHECK_LIB(dl, dlopen,
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for shared/static conflicts
|
||||
if [[ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
|
||||
if [[ \( "$LVM1" = shared -o "$POOL" = shared \
|
||||
\) -a "$STATIC_LINK" = yes ]]; then
|
||||
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
|
||||
fi
|
||||
@@ -1588,33 +1282,6 @@ if test "$SELINUX" = yes; then
|
||||
HAVE_SELINUX=no ])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Check BLKZEROOUT support
|
||||
|
||||
AC_CACHE_CHECK([for BLKZEROOUT in sys/ioctl.h.],
|
||||
[ac_cv_have_blkzeroout],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||
[#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
int bar(void) { return ioctl(0, BLKZEROOUT, 0); }]
|
||||
)], [ac_cv_have_blkzeroout=yes], [ac_cv_have_blkzeroout=no])])
|
||||
|
||||
|
||||
AC_ARG_ENABLE(blkzeroout,
|
||||
AC_HELP_STRING([--disable-blkzeroout],
|
||||
[do not use BLKZEROOUT for device zeroing]),
|
||||
BLKZEROOUT=$enableval, BLKZEROOUT=yes)
|
||||
|
||||
AC_MSG_CHECKING(whether to use BLKZEROOUT for device zeroing)
|
||||
if test "$BLKZEROOUT" = yes; then
|
||||
AC_IF_YES(ac_cv_have_blkzeroout,
|
||||
AC_DEFINE(HAVE_BLKZEROOUT, 1,
|
||||
[Define if ioctl BLKZEROOUT can be used for device zeroing.]),
|
||||
BLKZEROOUT=no)
|
||||
fi
|
||||
AC_MSG_RESULT($BLKZEROOUT)
|
||||
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for realtime clock support
|
||||
RT_LIBS=
|
||||
@@ -1648,16 +1315,6 @@ AC_IF_YES(ac_cv_stat_st_ctim,
|
||||
dnl -- Check for getopt
|
||||
AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 if getopt_long is available.]))
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for editline
|
||||
if test "$EDITLINE" == yes; then
|
||||
PKG_CHECK_MODULES([EDITLINE], [libedit], [
|
||||
AC_DEFINE([EDITLINE_SUPPORT], 1,
|
||||
[Define to 1 to include the LVM editline shell.])], AC_MSG_ERROR(
|
||||
[libedit could not be found which is required for the --enable-readline option.])
|
||||
)
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for readline (Shamelessly copied from parted 1.4.17)
|
||||
if test "$READLINE" != no; then
|
||||
@@ -1790,12 +1447,6 @@ fi
|
||||
AC_MSG_CHECKING(whether to enable readline)
|
||||
AC_MSG_RESULT($READLINE)
|
||||
|
||||
if test "$EDITLINE" = yes; then
|
||||
AC_CHECK_HEADERS(editline/readline.h editline/history.h,,hard_bailout)
|
||||
fi
|
||||
AC_MSG_CHECKING(whether to enable editline)
|
||||
AC_MSG_RESULT($EDITLINE)
|
||||
|
||||
if test "$BUILD_CMIRRORD" = yes; then
|
||||
AC_CHECK_FUNCS(atexit,,hard_bailout)
|
||||
fi
|
||||
@@ -1810,18 +1461,6 @@ if test "$BUILD_LVMPOLLD" = yes; then
|
||||
AC_FUNC_STRERROR_R
|
||||
fi
|
||||
|
||||
if test "$CLVMD" != none; then
|
||||
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,hard_bailout)
|
||||
AC_FUNC_GETMNTENT
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
fi
|
||||
|
||||
if test "$CLUSTER" != none; then
|
||||
AC_CHECK_HEADERS(sys/socket.h sys/un.h,,hard_bailout)
|
||||
AC_CHECK_FUNCS(socket,,hard_bailout)
|
||||
fi
|
||||
|
||||
if test "$BUILD_DMEVENTD" = yes; then
|
||||
AC_CHECK_HEADERS(arpa/inet.h,,hard_bailout)
|
||||
fi
|
||||
@@ -1855,9 +1494,10 @@ SBINDIR="$(eval echo $(eval echo $sbindir))"
|
||||
LVM_PATH="$SBINDIR/lvm"
|
||||
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
|
||||
|
||||
LVMCONFIG_PATH="$$BINDIR/lvmconfig"
|
||||
AC_DEFINE_UNQUOTED(LVMCONFIG_PATH, ["$LVMCONFIG_PATH"], [Path to lvmconfig binary.])
|
||||
|
||||
USRSBINDIR="$(eval echo $(eval echo $usrsbindir))"
|
||||
CLVMD_PATH="$USRSBINDIR/clvmd"
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
||||
|
||||
FSADM_PATH="$SBINDIR/fsadm"
|
||||
AC_DEFINE_UNQUOTED(FSADM_PATH, ["$FSADM_PATH"], [Path to fsadm binary.])
|
||||
@@ -1977,13 +1617,11 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[[()]]' '{print $2}'`
|
||||
AC_DEFINE_UNQUOTED(LVM_CONFIGURE_LINE, "$CONFIGURE_LINE", [configure command line used])
|
||||
|
||||
################################################################################
|
||||
AC_SUBST(APPLIB)
|
||||
AC_SUBST(AWK)
|
||||
AC_SUBST(BLKID_PC)
|
||||
AC_SUBST(BUILD_CMIRRORD)
|
||||
AC_SUBST(BUILD_DMEVENTD)
|
||||
AC_SUBST(BUILD_LVMDBUSD)
|
||||
AC_SUBST(BUILD_LVMETAD)
|
||||
AC_SUBST(BUILD_LVMPOLLD)
|
||||
AC_SUBST(BUILD_LVMLOCKD)
|
||||
AC_SUBST(BUILD_LOCKDSANLOCK)
|
||||
@@ -1996,14 +1634,6 @@ AC_SUBST(CHMOD)
|
||||
AC_SUBST(CLDFLAGS)
|
||||
AC_SUBST(CLDNOWHOLEARCHIVE)
|
||||
AC_SUBST(CLDWHOLEARCHIVE)
|
||||
AC_SUBST(CLUSTER)
|
||||
AC_SUBST(CLVMD)
|
||||
AC_SUBST(CLVMD_CMANAGERS)
|
||||
AC_SUBST(CLVMD_PATH)
|
||||
AC_SUBST(CMAN_CFLAGS)
|
||||
AC_SUBST(CMAN_LIBS)
|
||||
AC_SUBST(CMAP_CFLAGS)
|
||||
AC_SUBST(CMAP_LIBS)
|
||||
AC_SUBST(CMDLIB)
|
||||
AC_SUBST(CONFDB_CFLAGS)
|
||||
AC_SUBST(CONFDB_LIBS)
|
||||
@@ -2028,7 +1658,6 @@ AC_SUBST(DEFAULT_SPARSE_SEGTYPE)
|
||||
AC_SUBST(DEFAULT_SYS_DIR)
|
||||
AC_SUBST(DEFAULT_SYS_LOCK_DIR)
|
||||
AC_SUBST(DEFAULT_USE_BLKID_WIPING)
|
||||
AC_SUBST(DEFAULT_USE_LVMETAD)
|
||||
AC_SUBST(DEFAULT_USE_LVMPOLLD)
|
||||
AC_SUBST(DEFAULT_USE_LVMLOCKD)
|
||||
AC_SUBST(DEVMAPPER)
|
||||
@@ -2082,7 +1711,6 @@ AC_SUBST(QUORUM_CFLAGS)
|
||||
AC_SUBST(QUORUM_LIBS)
|
||||
AC_SUBST(RT_LIBS)
|
||||
AC_SUBST(READLINE_LIBS)
|
||||
AC_SUBST(EDITLINE_LIBS)
|
||||
AC_SUBST(REPLICATORS)
|
||||
AC_SUBST(SACKPT_CFLAGS)
|
||||
AC_SUBST(SACKPT_LIBS)
|
||||
@@ -2113,14 +1741,17 @@ AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
|
||||
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
|
||||
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
|
||||
AC_SUBST(USE_TRACKING)
|
||||
AC_SUBST(SILENT_RULES)
|
||||
AC_SUBST(USRSBINDIR)
|
||||
AC_SUBST(VALGRIND_POOL)
|
||||
AC_SUBST(VDO)
|
||||
AC_SUBST(VDO_FORMAT_CMD)
|
||||
AC_SUBST(VDO_INCLUDE)
|
||||
AC_SUBST(VDO_LIB)
|
||||
AC_SUBST(WRITE_INSTALL)
|
||||
AC_SUBST(DMEVENTD_PIDFILE)
|
||||
AC_SUBST(LVMETAD_PIDFILE)
|
||||
AC_SUBST(LVMPOLLD_PIDFILE)
|
||||
AC_SUBST(LVMLOCKD_PIDFILE)
|
||||
AC_SUBST(CLVMD_PIDFILE)
|
||||
AC_SUBST(CMIRRORD_PIDFILE)
|
||||
AC_SUBST(interface)
|
||||
AC_SUBST(kerneldir)
|
||||
@@ -2141,8 +1772,8 @@ dnl -- keep utility scripts running properly
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
make.tmpl
|
||||
libdm/make.tmpl
|
||||
daemons/Makefile
|
||||
daemons/clvmd/Makefile
|
||||
daemons/cmirrord/Makefile
|
||||
daemons/dmeventd/Makefile
|
||||
daemons/dmeventd/libdevmapper-event.pc
|
||||
@@ -2153,58 +1784,42 @@ daemons/dmeventd/plugins/mirror/Makefile
|
||||
daemons/dmeventd/plugins/snapshot/Makefile
|
||||
daemons/dmeventd/plugins/thin/Makefile
|
||||
daemons/dmeventd/plugins/vdo/Makefile
|
||||
daemons/dmfilemapd/Makefile
|
||||
daemons/lvmdbusd/Makefile
|
||||
daemons/lvmdbusd/lvmdbusd
|
||||
daemons/lvmdbusd/lvmdb.py
|
||||
daemons/lvmdbusd/lvm_shell_proxy.py
|
||||
daemons/lvmdbusd/path.py
|
||||
daemons/lvmetad/Makefile
|
||||
daemons/lvmpolld/Makefile
|
||||
daemons/lvmlockd/Makefile
|
||||
device_mapper/Makefile
|
||||
conf/Makefile
|
||||
conf/example.conf
|
||||
conf/lvmlocal.conf
|
||||
conf/command_profile_template.profile
|
||||
conf/metadata_profile_template.profile
|
||||
include/.symlinks
|
||||
include/Makefile
|
||||
lib/Makefile
|
||||
lib/locking/Makefile
|
||||
include/lvm-version.h
|
||||
libdaemon/Makefile
|
||||
libdaemon/client/Makefile
|
||||
libdaemon/server/Makefile
|
||||
libdm/Makefile
|
||||
libdm/dm-tools/Makefile
|
||||
libdm/libdevmapper.pc
|
||||
liblvm/Makefile
|
||||
liblvm/liblvm2app.pc
|
||||
man/Makefile
|
||||
po/Makefile
|
||||
python/Makefile
|
||||
python/setup.py
|
||||
scripts/blkdeactivate.sh
|
||||
scripts/blk_availability_init_red_hat
|
||||
scripts/blk_availability_systemd_red_hat.service
|
||||
scripts/clvmd_init_red_hat
|
||||
scripts/cmirrord_init_red_hat
|
||||
scripts/com.redhat.lvmdbus1.service
|
||||
scripts/dm_event_systemd_red_hat.service
|
||||
scripts/dm_event_systemd_red_hat.socket
|
||||
scripts/lvm2_cluster_activation_red_hat.sh
|
||||
scripts/lvm2_cluster_activation_systemd_red_hat.service
|
||||
scripts/lvm2_clvmd_systemd_red_hat.service
|
||||
scripts/lvm2_cmirrord_systemd_red_hat.service
|
||||
scripts/lvm2_lvmdbusd_systemd_red_hat.service
|
||||
scripts/lvm2_lvmetad_init_red_hat
|
||||
scripts/lvm2_lvmetad_systemd_red_hat.service
|
||||
scripts/lvm2_lvmetad_systemd_red_hat.socket
|
||||
scripts/lvm2_lvmpolld_init_red_hat
|
||||
scripts/lvm2_lvmpolld_systemd_red_hat.service
|
||||
scripts/lvm2_lvmpolld_systemd_red_hat.socket
|
||||
scripts/lvm2_lvmlockd_systemd_red_hat.service
|
||||
scripts/lvm2_lvmlocking_systemd_red_hat.service
|
||||
scripts/lvm2_monitoring_init_red_hat
|
||||
scripts/lvm2_monitoring_systemd_red_hat.service
|
||||
scripts/lvm2_pvscan_systemd_red_hat@.service
|
||||
@@ -2212,9 +1827,6 @@ scripts/lvm2_tmpfiles_red_hat.conf
|
||||
scripts/lvmdump.sh
|
||||
scripts/Makefile
|
||||
test/Makefile
|
||||
test/api/Makefile
|
||||
test/api/python_lvm_unit.py
|
||||
test/unit/Makefile
|
||||
tools/Makefile
|
||||
udev/Makefile
|
||||
])
|
||||
@@ -2232,6 +1844,9 @@ AS_IF([test -n "$CACHE_CONFIGURE_WARN"],
|
||||
AS_IF([test -n "$CACHE_CHECK_VERSION_WARN"],
|
||||
[AC_MSG_WARN([You should install latest cache_check vsn 0.7.0 to use lvm2 cache metadata format 2])])
|
||||
|
||||
AS_IF([test -n "$VDO_CONFIGURE_WARN"],
|
||||
[AC_MSG_WARN([unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!])])
|
||||
|
||||
|
||||
AS_IF([test "$ODIRECT" != yes],
|
||||
[AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])])
|
||||
|
||||
@@ -46,7 +46,6 @@ const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile
|
||||
return "STRING";
|
||||
}
|
||||
|
||||
/*
|
||||
struct logical_volume *origin_from_cow(const struct logical_volume *lv)
|
||||
{
|
||||
if (lv)
|
||||
@@ -54,7 +53,6 @@ struct logical_volume *origin_from_cow(const struct logical_volume *lv)
|
||||
|
||||
__coverity_panic__();
|
||||
}
|
||||
*/
|
||||
|
||||
/* simple_memccpy() from glibc */
|
||||
void *memccpy(void *dest, const void *src, int c, size_t n)
|
||||
|
||||
@@ -15,11 +15,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld lvmlockd
|
||||
|
||||
ifneq ("@CLVMD@", "none")
|
||||
SUBDIRS += clvmd
|
||||
endif
|
||||
.PHONY: dmeventd cmirrord lvmpolld lvmlockd
|
||||
|
||||
ifeq ("@BUILD_CMIRRORD@", "yes")
|
||||
SUBDIRS += cmirrord
|
||||
@@ -32,10 +28,6 @@ daemons.cflow: dmeventd.cflow
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMETAD@", "yes")
|
||||
SUBDIRS += lvmetad
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||
SUBDIRS += lvmpolld
|
||||
endif
|
||||
@@ -48,12 +40,8 @@ ifeq ("@BUILD_LVMDBUSD@", "yes")
|
||||
SUBDIRS += lvmdbusd
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_DMFILEMAPD@", "yes")
|
||||
SUBDIRS += dmfilemapd
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd dmfilemapd
|
||||
SUBDIRS = cmirrord dmeventd lvmpolld lvmlockd lvmdbusd
|
||||
endif
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
1
daemons/clvmd/.gitignore
vendored
1
daemons/clvmd/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
clvmd
|
||||
@@ -1,94 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
CMAN_LIBS = @CMAN_LIBS@
|
||||
CMAN_CFLAGS = @CMAN_CFLAGS@
|
||||
CMAP_LIBS = @CMAP_LIBS@
|
||||
CMAP_CFLAGS = @CMAP_CFLAGS@
|
||||
CONFDB_LIBS = @CONFDB_LIBS@
|
||||
CONFDB_CFLAGS = @CONFDB_CFLAGS@
|
||||
CPG_LIBS = @CPG_LIBS@
|
||||
CPG_CFLAGS = @CPG_CFLAGS@
|
||||
DLM_LIBS = @DLM_LIBS@
|
||||
DLM_CFLAGS = @DLM_CFLAGS@
|
||||
QUORUM_LIBS = @QUORUM_LIBS@
|
||||
QUORUM_CFLAGS = @QUORUM_CFLAGS@
|
||||
SALCK_LIBS = @SALCK_LIBS@
|
||||
SALCK_CFLAGS = @SALCK_CFLAGS@
|
||||
|
||||
SOURCES = \
|
||||
clvmd-command.c\
|
||||
clvmd.c\
|
||||
lvm-functions.c\
|
||||
refresh_clvmd.c
|
||||
|
||||
ifneq (,$(findstring cman,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-cman.c
|
||||
LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS)
|
||||
CFLAGS += $(CMAN_CFLAGS) $(CONFDB_CFLAGS) $(DLM_CFLAGS)
|
||||
DEFS += -DUSE_CMAN
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring openais,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-openais.c
|
||||
LMLIBS += $(CONFDB_LIBS) $(CPG_LIBS) $(SALCK_LIBS)
|
||||
CFLAGS += $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(SALCK_CFLAGS)
|
||||
DEFS += -DUSE_OPENAIS
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring corosync,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-corosync.c
|
||||
LMLIBS += $(CMAP_LIBS) $(CONFDB_LIBS) $(CPG_LIBS) $(DLM_LIBS) $(QUORUM_LIBS)
|
||||
CFLAGS += $(CMAP_CFLAGS) $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(DLM_CFLAGS) $(QUORUM_CFLAGS)
|
||||
DEFS += -DUSE_COROSYNC
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring singlenode,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-singlenode.c
|
||||
DEFS += -DUSE_SINGLENODE
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SOURCES += clvmd-cman.c
|
||||
SOURCES += clvmd-openais.c
|
||||
SOURCES += clvmd-corosync.c
|
||||
SOURCES += clvmd-singlenode.c
|
||||
endif
|
||||
|
||||
TARGETS = \
|
||||
clvmd
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS) -laio
|
||||
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
|
||||
|
||||
INSTALL_TARGETS = \
|
||||
install_clvmd
|
||||
|
||||
clvmd: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
|
||||
-o clvmd $(OBJECTS) $(LMLIBS) $(LIBS)
|
||||
|
||||
.PHONY: install_clvmd
|
||||
|
||||
install_clvmd: $(TARGETS)
|
||||
$(INSTALL_PROGRAM) -D clvmd $(usrsbindir)/clvmd
|
||||
|
||||
install: $(INSTALL_TARGETS)
|
||||
|
||||
install_cluster: $(INSTALL_TARGETS)
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Definitions for CLVMD server and clients */
|
||||
|
||||
/*
|
||||
* The protocol spoken over the cluster and across the local socket.
|
||||
*/
|
||||
|
||||
#ifndef _CLVM_H
|
||||
#define _CLVM_H
|
||||
|
||||
#include "configure.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
struct clvm_header {
|
||||
uint8_t cmd; /* See below */
|
||||
uint8_t flags; /* See below */
|
||||
uint16_t xid; /* Transaction ID */
|
||||
uint32_t clientid; /* Only used in Daemon->Daemon comms */
|
||||
int32_t status; /* For replies, whether request succeeded */
|
||||
uint32_t arglen; /* Length of argument below.
|
||||
If >1500 then it will be passed
|
||||
around the cluster in the system LV */
|
||||
char node[1]; /* Actually a NUL-terminated string, node name.
|
||||
If this is empty then the command is
|
||||
forwarded to all cluster nodes unless
|
||||
FLAG_LOCAL or FLAG_REMOTE is also set. */
|
||||
char args[1]; /* Arguments for the command follow the
|
||||
node name, This member is only
|
||||
valid if the node name is empty */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Flags */
|
||||
#define CLVMD_FLAG_LOCAL 1 /* Only do this on the local node */
|
||||
#define CLVMD_FLAG_SYSTEMLV 2 /* Data in system LV under my node name */
|
||||
#define CLVMD_FLAG_NODEERRS 4 /* Reply has errors in node-specific portion */
|
||||
#define CLVMD_FLAG_REMOTE 8 /* Do this on all nodes except for the local node */
|
||||
|
||||
/* Name of the local socket to communicate between lvm and clvmd */
|
||||
#define CLVMD_SOCKNAME DEFAULT_RUN_DIR "/clvmd.sock"
|
||||
|
||||
/* Internal commands & replies */
|
||||
#define CLVMD_CMD_REPLY 1
|
||||
#define CLVMD_CMD_VERSION 2 /* Send version around cluster when we start */
|
||||
#define CLVMD_CMD_GOAWAY 3 /* Die if received this - we are running
|
||||
an incompatible version */
|
||||
#define CLVMD_CMD_TEST 4 /* Just for mucking about */
|
||||
|
||||
#define CLVMD_CMD_LOCK 30
|
||||
#define CLVMD_CMD_UNLOCK 31
|
||||
|
||||
/* Lock/Unlock commands */
|
||||
#define CLVMD_CMD_LOCK_LV 50
|
||||
#define CLVMD_CMD_LOCK_VG 51
|
||||
#define CLVMD_CMD_LOCK_QUERY 52
|
||||
|
||||
/* Misc functions */
|
||||
#define CLVMD_CMD_REFRESH 40
|
||||
#define CLVMD_CMD_GET_CLUSTERNAME 41
|
||||
#define CLVMD_CMD_SET_DEBUG 42
|
||||
#define CLVMD_CMD_VG_BACKUP 43
|
||||
#define CLVMD_CMD_RESTART 44
|
||||
#define CLVMD_CMD_SYNC_NAMES 45
|
||||
|
||||
/* Used internally by some callers, but not part of the protocol.*/
|
||||
#ifndef NODE_ALL
|
||||
# define NODE_ALL "*"
|
||||
# define NODE_LOCAL "."
|
||||
# define NODE_REMOTE "^"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,505 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* CMAN communication layer for clvmd.
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
#include <libdlm.h>
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#define LOCKSPACE_NAME "clvmd"
|
||||
|
||||
struct clvmd_node
|
||||
{
|
||||
struct cman_node *node;
|
||||
int clvmd_up;
|
||||
};
|
||||
|
||||
static int num_nodes;
|
||||
static struct cman_node *nodes = NULL;
|
||||
static struct cman_node this_node;
|
||||
static int count_nodes; /* size of allocated nodes array */
|
||||
static struct dm_hash_table *node_updown_hash;
|
||||
static dlm_lshandle_t *lockspace;
|
||||
static cman_handle_t c_handle;
|
||||
|
||||
static void count_clvmds_running(void);
|
||||
static void get_members(void);
|
||||
static int nodeid_from_csid(const char *csid);
|
||||
static int name_from_nodeid(int nodeid, char *name);
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg);
|
||||
static void data_callback(cman_handle_t handle, void *private,
|
||||
char *buf, int len, uint8_t port, int nodeid);
|
||||
|
||||
struct lock_wait {
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
struct dlm_lksb lksb;
|
||||
};
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
node_updown_hash = dm_hash_create(100);
|
||||
|
||||
/* Open the cluster communication socket */
|
||||
c_handle = cman_init(NULL);
|
||||
if (!c_handle) {
|
||||
syslog(LOG_ERR, "Can't open cluster manager socket: %m");
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("Connected to CMAN\n");
|
||||
|
||||
if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
|
||||
syslog(LOG_ERR, "Can't bind cluster socket: %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cman_start_notification(c_handle, event_callback)) {
|
||||
syslog(LOG_ERR, "Can't start cluster event listening");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the cluster members list */
|
||||
get_members();
|
||||
count_clvmds_running();
|
||||
|
||||
DEBUGLOG("CMAN initialisation complete\n");
|
||||
|
||||
/* Create a lockspace for LV & VG locks to live in */
|
||||
lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
|
||||
if (!lockspace) {
|
||||
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
|
||||
if (!lockspace) {
|
||||
syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("Created DLM lockspace for CLVMD.\n");
|
||||
} else
|
||||
DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
|
||||
|
||||
dlm_ls_pthread_init(lockspace);
|
||||
DEBUGLOG("DLM initialisation complete\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_init_completed(void)
|
||||
{
|
||||
clvmd_cluster_init_completed();
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
return cman_get_fd(c_handle);
|
||||
}
|
||||
|
||||
static int _get_num_nodes(void)
|
||||
{
|
||||
int i;
|
||||
int nnodes = 0;
|
||||
|
||||
/* return number of ACTIVE nodes */
|
||||
for (i=0; i<num_nodes; i++) {
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid)
|
||||
nnodes++;
|
||||
}
|
||||
return nnodes;
|
||||
}
|
||||
|
||||
/* send_message with the fd check removed */
|
||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
int nodeid = 0;
|
||||
|
||||
if (csid)
|
||||
memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
|
||||
|
||||
if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
|
||||
{
|
||||
log_error("%s", errtext);
|
||||
}
|
||||
return msglen;
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
if (this_node.cn_nodeid == 0) {
|
||||
cman_get_node(c_handle, 0, &this_node);
|
||||
}
|
||||
memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN);
|
||||
}
|
||||
|
||||
/* Call a callback routine for each node is that known (down means not running a clvmd) */
|
||||
static int _cluster_do_node_callback(struct local_client *client,
|
||||
void (*callback) (struct local_client *,
|
||||
const char *,
|
||||
int))
|
||||
{
|
||||
int i;
|
||||
int somedown = 0;
|
||||
|
||||
for (i = 0; i < _get_num_nodes(); i++) {
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid) {
|
||||
int up = (int)(long)dm_hash_lookup_binary(node_updown_hash, (char *)&nodes[i].cn_nodeid, sizeof(int));
|
||||
|
||||
callback(client, (char *)&nodes[i].cn_nodeid, up);
|
||||
if (!up)
|
||||
somedown = -1;
|
||||
}
|
||||
}
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Process OOB messages from the cluster socket */
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
|
||||
{
|
||||
char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
|
||||
switch (reason) {
|
||||
case CMAN_REASON_PORTCLOSED:
|
||||
name_from_nodeid(arg, namebuf);
|
||||
log_notice("clvmd on node %s has died\n", namebuf);
|
||||
DEBUGLOG("Got port closed message, removing node %s\n", namebuf);
|
||||
|
||||
dm_hash_insert_binary(node_updown_hash, (char *)&arg, sizeof(int), (void *)0);
|
||||
break;
|
||||
|
||||
case CMAN_REASON_STATECHANGE:
|
||||
DEBUGLOG("Got state change message, re-reading members list\n");
|
||||
get_members();
|
||||
break;
|
||||
|
||||
#if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2
|
||||
case CMAN_REASON_PORTOPENED:
|
||||
/* Ignore this, wait for startup message from clvmd itself */
|
||||
break;
|
||||
|
||||
case CMAN_REASON_TRY_SHUTDOWN:
|
||||
DEBUGLOG("Got try shutdown, sending OK\n");
|
||||
cman_replyto_shutdown(c_handle, 1);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* ERROR */
|
||||
DEBUGLOG("Got unknown event callback message: %d\n", reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct local_client *cman_client;
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
|
||||
/* Save this for data_callback */
|
||||
cman_client = fd;
|
||||
|
||||
/* We never return a new client */
|
||||
*new_client = NULL;
|
||||
|
||||
return cman_dispatch(c_handle, 0);
|
||||
}
|
||||
|
||||
|
||||
static void data_callback(cman_handle_t handle, void *private,
|
||||
char *buf, int len, uint8_t port, int nodeid)
|
||||
{
|
||||
/* Ignore looped back messages */
|
||||
if (nodeid == this_node.cn_nodeid)
|
||||
return;
|
||||
process_message(cman_client, buf, len, (char *)&nodeid);
|
||||
}
|
||||
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
/* It's up ! */
|
||||
int nodeid = nodeid_from_csid(csid);
|
||||
|
||||
dm_hash_insert_binary(node_updown_hash, (char *)&nodeid, sizeof(int), (void *)1);
|
||||
DEBUGLOG("Added new node %d to updown list\n", nodeid);
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
cman_finish(c_handle);
|
||||
}
|
||||
|
||||
static int is_listening(int nodeid)
|
||||
{
|
||||
int status;
|
||||
|
||||
do {
|
||||
status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD);
|
||||
if (status < 0 && errno == EBUSY) { /* Don't busywait */
|
||||
sleep(1);
|
||||
errno = EBUSY; /* In case sleep trashes it */
|
||||
}
|
||||
}
|
||||
while (status < 0 && errno == EBUSY);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Populate the list of CLVMDs running.
|
||||
called only at startup time */
|
||||
static void count_clvmds_running(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
int nodeid = nodes[i].cn_nodeid;
|
||||
|
||||
if (is_listening(nodeid) == 1)
|
||||
dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)1);
|
||||
else
|
||||
dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a list of active cluster members */
|
||||
static void get_members(void)
|
||||
{
|
||||
int retnodes;
|
||||
int status;
|
||||
int i;
|
||||
int high_nodeid = 0;
|
||||
|
||||
num_nodes = cman_get_node_count(c_handle);
|
||||
if (num_nodes == -1) {
|
||||
log_error("Unable to get node count");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not enough room for new nodes list ? */
|
||||
if (num_nodes > count_nodes && nodes) {
|
||||
free(nodes);
|
||||
nodes = NULL;
|
||||
}
|
||||
|
||||
if (nodes == NULL) {
|
||||
count_nodes = num_nodes + 10; /* Overallocate a little */
|
||||
nodes = malloc(count_nodes * sizeof(struct cman_node));
|
||||
if (!nodes) {
|
||||
log_error("Unable to allocate nodes array\n");
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
|
||||
if (status < 0) {
|
||||
log_error("Unable to get node details");
|
||||
exit(6);
|
||||
}
|
||||
|
||||
/* Get the highest nodeid */
|
||||
for (i=0; i<retnodes; i++) {
|
||||
if (nodes[i].cn_nodeid > high_nodeid)
|
||||
high_nodeid = nodes[i].cn_nodeid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Convert a node name to a CSID */
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (strcmp(name, nodes[i].cn_name) == 0) {
|
||||
memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node name */
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) {
|
||||
strcpy(name, nodes[i].cn_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Who?? */
|
||||
strcpy(name, "Unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a node ID to a node name */
|
||||
static int name_from_nodeid(int nodeid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (nodeid == nodes[i].cn_nodeid) {
|
||||
strcpy(name, nodes[i].cn_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Who?? */
|
||||
strcpy(name, "Unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node ID */
|
||||
static int nodeid_from_csid(const char *csid)
|
||||
{
|
||||
int nodeid;
|
||||
|
||||
memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
|
||||
|
||||
return nodeid;
|
||||
}
|
||||
|
||||
static int _is_quorate(void)
|
||||
{
|
||||
return cman_is_quorate(c_handle);
|
||||
}
|
||||
|
||||
static void sync_ast_routine(void *arg)
|
||||
{
|
||||
struct lock_wait *lwait = arg;
|
||||
|
||||
pthread_mutex_lock(&lwait->mutex);
|
||||
pthread_cond_signal(&lwait->cond);
|
||||
pthread_mutex_unlock(&lwait->mutex);
|
||||
}
|
||||
|
||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
if (!lockid) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags);
|
||||
/* Conversions need the lockid in the LKSB */
|
||||
if (flags & LKF_CONVERT)
|
||||
lwait.lksb.sb_lkid = *lockid;
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
status = dlm_ls_lock(lockspace,
|
||||
mode,
|
||||
&lwait.lksb,
|
||||
flags,
|
||||
resource,
|
||||
strlen(resource),
|
||||
0, sync_ast_routine, &lwait, NULL, NULL);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
*lockid = lwait.lksb.sb_lkid;
|
||||
|
||||
errno = lwait.lksb.sb_status;
|
||||
DEBUGLOG("sync_lock: returning lkid %x\n", *lockid);
|
||||
if (lwait.lksb.sb_status)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid);
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
errno = lwait.lksb.sb_status;
|
||||
if (lwait.lksb.sb_status != EUNLOCK)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
cman_cluster_t cluster_info;
|
||||
int status;
|
||||
|
||||
status = cman_get_cluster(c_handle, &cluster_info);
|
||||
if (!status) {
|
||||
strncpy(buf, cluster_info.ci_name, buflen);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_cman_ops = {
|
||||
.name = "cman",
|
||||
.cluster_init_completed = _cluster_init_completed,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_cman_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_cman_ops;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,415 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
CLVMD Cluster LVM daemon command processor.
|
||||
|
||||
To add commands to the daemon simply add a processor in do_command and return
|
||||
and messages back in buf and the length in *retlen. The initial value of
|
||||
buflen is the maximum size of the buffer. if buf is not large enough then it
|
||||
may be reallocated by the functions in here to a suitable size bearing in
|
||||
mind that anything larger than the passed-in size will have to be returned
|
||||
using the system LV and so performance will suffer.
|
||||
|
||||
The status return will be negated and passed back to the originating node.
|
||||
|
||||
pre- and post- command routines are called only on the local node. The
|
||||
purpose is primarily to get and release locks, though the pre- routine should
|
||||
also do any other local setups required by the command (if any) and can
|
||||
return a failure code that prevents the command from being distributed around
|
||||
the cluster
|
||||
|
||||
The pre- and post- routines are run in their own thread so can block as long
|
||||
they like, do_command is run in the main clvmd thread so should not block for
|
||||
too long. If the pre-command returns an error code (!=0) then the command
|
||||
will not be propogated around the cluster but the post-command WILL be called
|
||||
|
||||
Also note that the pre and post routine are *always* called on the local
|
||||
node, even if the command to be executed was only requested to run on a
|
||||
remote node. It may peek inside the client structure to check the status of
|
||||
the command.
|
||||
|
||||
The clients of the daemon must, naturally, understand the return messages and
|
||||
codes.
|
||||
|
||||
Routines in here may only READ the values in the client structure passed in
|
||||
apart from client->private which they are free to do what they like with.
|
||||
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-globals.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
#include "locking.h"
|
||||
|
||||
#include <sys/utsname.h>
|
||||
|
||||
extern struct cluster_ops *clops;
|
||||
static int restart_clvmd(void);
|
||||
|
||||
/* This is where all the real work happens:
|
||||
NOTE: client will be NULL when this is executed on a remote node */
|
||||
int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
char **buf, int buflen, int *retlen)
|
||||
{
|
||||
char *args = msg->node + strlen(msg->node) + 1;
|
||||
int arglen = msglen - sizeof(struct clvm_header) - strlen(msg->node);
|
||||
int status = 0;
|
||||
char *lockname;
|
||||
const char *locktype;
|
||||
struct utsname nodeinfo;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
|
||||
/* Do the command */
|
||||
switch (msg->cmd) {
|
||||
/* Just a test message */
|
||||
case CLVMD_CMD_TEST:
|
||||
if (arglen > buflen) {
|
||||
char *new_buf;
|
||||
buflen = arglen + 200;
|
||||
new_buf = realloc(*buf, buflen);
|
||||
if (new_buf == NULL) {
|
||||
status = errno;
|
||||
free (*buf);
|
||||
}
|
||||
*buf = new_buf;
|
||||
}
|
||||
if (*buf) {
|
||||
if (uname(&nodeinfo))
|
||||
memset(&nodeinfo, 0, sizeof(nodeinfo));
|
||||
|
||||
*retlen = 1 + dm_snprintf(*buf, buflen,
|
||||
"TEST from %s: %s v%s",
|
||||
nodeinfo.nodename, args,
|
||||
nodeinfo.release);
|
||||
}
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
/* Check to see if the VG is in use by LVM1 */
|
||||
do_lock_vg(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
/* This is the biggie */
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = do_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
/* Replace EIO with something less scary */
|
||||
if (status == EIO) {
|
||||
*retlen = 1 + dm_snprintf(*buf, buflen, "%s",
|
||||
get_last_lvm_error());
|
||||
return EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_QUERY:
|
||||
lockname = &args[2];
|
||||
if (buflen < 3)
|
||||
return EIO;
|
||||
if ((locktype = do_lock_query(lockname)))
|
||||
*retlen = 1 + dm_snprintf(*buf, buflen, "%s", locktype);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_REFRESH:
|
||||
do_refresh_cache();
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_SYNC_NAMES:
|
||||
lvm_do_fs_unlock();
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_SET_DEBUG:
|
||||
clvmd_set_debug((debug_t) args[0]);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_RESTART:
|
||||
status = restart_clvmd();
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_GET_CLUSTERNAME:
|
||||
status = clops->get_cluster_name(*buf, buflen);
|
||||
if (!status)
|
||||
*retlen = strlen(*buf)+1;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_VG_BACKUP:
|
||||
/*
|
||||
* Do not run backup on local node, caller should do that.
|
||||
*/
|
||||
if (!client)
|
||||
lvm_do_backup(&args[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Won't get here because command is validated in pre_command */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check the status of the command and return the error text */
|
||||
if (status) {
|
||||
if (*buf)
|
||||
*retlen = dm_snprintf(*buf, buflen, "%s", strerror(status)) + 1;
|
||||
else
|
||||
*retlen = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int lock_vg(struct local_client *client)
|
||||
{
|
||||
struct dm_hash_table *lock_hash;
|
||||
struct clvm_header *header =
|
||||
(struct clvm_header *) client->bits.localsock.cmd;
|
||||
unsigned char lock_cmd;
|
||||
int lock_mode;
|
||||
char *args = header->node + strlen(header->node) + 1;
|
||||
int lkid;
|
||||
int status;
|
||||
char *lockname;
|
||||
|
||||
/*
|
||||
* Keep a track of VG locks in our own hash table. In current
|
||||
* practice there should only ever be more than two VGs locked
|
||||
* if a user tries to merge lots of them at once
|
||||
*/
|
||||
if (!client->bits.localsock.private) {
|
||||
if (!(lock_hash = dm_hash_create(3)))
|
||||
return ENOMEM;
|
||||
client->bits.localsock.private = (void *) lock_hash;
|
||||
} else
|
||||
lock_hash = (struct dm_hash_table *) client->bits.localsock.private;
|
||||
|
||||
lock_cmd = args[0] & (LCK_NONBLOCK | LCK_HOLD | LCK_SCOPE_MASK | LCK_TYPE_MASK);
|
||||
lock_mode = ((int) lock_cmd & LCK_TYPE_MASK);
|
||||
/* lock_flags = args[1]; */
|
||||
lockname = &args[2];
|
||||
DEBUGLOG("(%p) doing PRE command LOCK_VG '%s' at %x\n", client, lockname, lock_cmd);
|
||||
|
||||
if (lock_mode == LCK_UNLOCK) {
|
||||
if (!(lkid = (int) (long) dm_hash_lookup(lock_hash, lockname)))
|
||||
return EINVAL;
|
||||
|
||||
if ((status = sync_unlock(lockname, lkid)))
|
||||
status = errno;
|
||||
else
|
||||
dm_hash_remove(lock_hash, lockname);
|
||||
} else {
|
||||
/* Read locks need to be PR; other modes get passed through */
|
||||
if (lock_mode == LCK_READ)
|
||||
lock_mode = LCK_PREAD;
|
||||
|
||||
if ((status = sync_lock(lockname, lock_mode, (lock_cmd & LCK_NONBLOCK) ? LCKF_NOQUEUE : 0, &lkid)))
|
||||
status = errno;
|
||||
else if (!dm_hash_insert(lock_hash, lockname, (void *) (long) lkid))
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Pre-command is a good place to get locks that are needed only for the duration
|
||||
of the commands around the cluster (don't forget to free them in post-command),
|
||||
and to sanity check the command arguments */
|
||||
int do_pre_command(struct local_client *client)
|
||||
{
|
||||
struct clvm_header *header =
|
||||
(struct clvm_header *) client->bits.localsock.cmd;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
char *args = header->node + strlen(header->node) + 1;
|
||||
int lockid = 0;
|
||||
int status = 0;
|
||||
char *lockname;
|
||||
|
||||
switch (header->cmd) {
|
||||
case CLVMD_CMD_TEST:
|
||||
status = sync_lock("CLVMD_TEST", LCK_EXCL, 0, &lockid);
|
||||
client->bits.localsock.private = (void *)(long)lockid;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
lockname = &args[2];
|
||||
/* We take out a real lock unless LCK_CACHE was set */
|
||||
if (!strncmp(lockname, "V_", 2) ||
|
||||
!strncmp(lockname, "P_#", 3))
|
||||
status = lock_vg(client);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = pre_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_REFRESH:
|
||||
case CLVMD_CMD_GET_CLUSTERNAME:
|
||||
case CLVMD_CMD_SET_DEBUG:
|
||||
case CLVMD_CMD_VG_BACKUP:
|
||||
case CLVMD_CMD_SYNC_NAMES:
|
||||
case CLVMD_CMD_LOCK_QUERY:
|
||||
case CLVMD_CMD_RESTART:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unknown command %d received\n", header->cmd);
|
||||
status = EINVAL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Note that the post-command routine is called even if the pre-command or the real command
|
||||
failed */
|
||||
int do_post_command(struct local_client *client)
|
||||
{
|
||||
struct clvm_header *header =
|
||||
(struct clvm_header *) client->bits.localsock.cmd;
|
||||
int status = 0;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
char *args = header->node + strlen(header->node) + 1;
|
||||
char *lockname;
|
||||
|
||||
switch (header->cmd) {
|
||||
case CLVMD_CMD_TEST:
|
||||
status = sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private);
|
||||
client->bits.localsock.private = NULL;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = post_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Nothing to do here */
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Called when the client is about to be deleted */
|
||||
void cmd_client_cleanup(struct local_client *client)
|
||||
{
|
||||
struct dm_hash_node *v;
|
||||
struct dm_hash_table *lock_hash;
|
||||
int lkid;
|
||||
char *lockname;
|
||||
|
||||
DEBUGLOG("(%p) Client thread cleanup\n", client);
|
||||
if (!client->bits.localsock.private)
|
||||
return;
|
||||
|
||||
lock_hash = (struct dm_hash_table *)client->bits.localsock.private;
|
||||
|
||||
dm_hash_iterate(v, lock_hash) {
|
||||
lkid = (int)(long)dm_hash_get_data(lock_hash, v);
|
||||
lockname = dm_hash_get_key(lock_hash, v);
|
||||
DEBUGLOG("(%p) Cleanup: Unlocking lock %s %x\n", client, lockname, lkid);
|
||||
(void) sync_unlock(lockname, lkid);
|
||||
}
|
||||
|
||||
dm_hash_destroy(lock_hash);
|
||||
client->bits.localsock.private = NULL;
|
||||
}
|
||||
|
||||
static int restart_clvmd(void)
|
||||
{
|
||||
const char **argv;
|
||||
char *lv_name;
|
||||
int argc = 0, max_locks = 0;
|
||||
struct dm_hash_node *hn = NULL;
|
||||
char debug_arg[16];
|
||||
const char *clvmd = getenv("LVM_CLVMD_BINARY") ? : CLVMD_PATH;
|
||||
|
||||
DEBUGLOG("clvmd restart requested\n");
|
||||
|
||||
/* Count exclusively-open LVs */
|
||||
do {
|
||||
hn = get_next_excl_lock(hn, &lv_name);
|
||||
if (lv_name) {
|
||||
max_locks++;
|
||||
if (!*lv_name)
|
||||
break; /* FIXME: Is this error ? */
|
||||
}
|
||||
} while (hn);
|
||||
|
||||
/* clvmd + locks (-E uuid) + debug (-d X) + NULL */
|
||||
if (!(argv = malloc((max_locks * 2 + 6) * sizeof(*argv))))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* Build the command-line
|
||||
*/
|
||||
argv[argc++] = "clvmd";
|
||||
|
||||
/* Propagate debug options */
|
||||
if (clvmd_get_debug()) {
|
||||
if (dm_snprintf(debug_arg, sizeof(debug_arg), "-d%u", clvmd_get_debug()) < 0)
|
||||
goto_out;
|
||||
argv[argc++] = debug_arg;
|
||||
}
|
||||
|
||||
/* Propagate foreground options */
|
||||
if (clvmd_get_foreground())
|
||||
argv[argc++] = "-f";
|
||||
|
||||
argv[argc++] = "-I";
|
||||
argv[argc++] = clops->name;
|
||||
|
||||
/* Now add the exclusively-open LVs */
|
||||
hn = NULL;
|
||||
do {
|
||||
hn = get_next_excl_lock(hn, &lv_name);
|
||||
if (lv_name) {
|
||||
if (!*lv_name)
|
||||
break; /* FIXME: Is this error ? */
|
||||
argv[argc++] = "-E";
|
||||
argv[argc++] = lv_name;
|
||||
DEBUGLOG("excl lock: %s\n", lv_name);
|
||||
}
|
||||
} while (hn);
|
||||
argv[argc] = NULL;
|
||||
|
||||
/* Exec new clvmd */
|
||||
DEBUGLOG("--- Restarting %s ---\n", clvmd);
|
||||
for (argc = 1; argv[argc]; argc++) DEBUGLOG("--- %d: %s\n", argc, argv[argc]);
|
||||
|
||||
/* NOTE: This will fail when downgrading! */
|
||||
execvp(clvmd, (char **)argv);
|
||||
out:
|
||||
/* We failed */
|
||||
DEBUGLOG("Restart of clvmd failed.\n");
|
||||
|
||||
free(argv);
|
||||
|
||||
return EIO;
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstraction layer for clvmd cluster communications
|
||||
*/
|
||||
|
||||
#ifndef _CLVMD_COMMS_H
|
||||
#define _CLVMD_COMMS_H
|
||||
|
||||
struct local_client;
|
||||
|
||||
struct cluster_ops {
|
||||
const char *name;
|
||||
void (*cluster_init_completed) (void);
|
||||
|
||||
int (*cluster_send_message) (const void *buf, int msglen,
|
||||
const char *csid,
|
||||
const char *errtext);
|
||||
int (*name_from_csid) (const char *csid, char *name);
|
||||
int (*csid_from_name) (char *csid, const char *name);
|
||||
int (*get_num_nodes) (void);
|
||||
int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client);
|
||||
int (*get_main_cluster_fd) (void); /* gets accept FD or cman cluster socket */
|
||||
int (*cluster_do_node_callback) (struct local_client *client,
|
||||
void (*callback) (struct local_client *,
|
||||
const char *csid,
|
||||
int node_up));
|
||||
int (*is_quorate) (void);
|
||||
|
||||
void (*get_our_csid) (char *csid);
|
||||
void (*add_up_node) (const char *csid);
|
||||
void (*reread_config) (void);
|
||||
void (*cluster_closedown) (void);
|
||||
|
||||
int (*get_cluster_name)(char *buf, int buflen);
|
||||
|
||||
int (*sync_lock) (const char *resource, int mode,
|
||||
int flags, int *lockid);
|
||||
int (*sync_unlock) (const char *resource, int lockid);
|
||||
|
||||
};
|
||||
|
||||
#ifdef USE_CMAN
|
||||
# include <netinet/in.h>
|
||||
# include "libcman.h"
|
||||
# define CMAN_MAX_CSID_LEN 4
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN CMAN_MAX_CSID_LEN
|
||||
# endif
|
||||
# undef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN CMAN_MAX_NODENAME_LEN
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE 1500
|
||||
# define CLUSTER_PORT_CLVMD 11
|
||||
struct cluster_ops *init_cman_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPENAIS
|
||||
# include <openais/saAis.h>
|
||||
# include <corosync/totem/totem.h>
|
||||
# define OPENAIS_CSID_LEN (sizeof(int))
|
||||
# define OPENAIS_MAX_CLUSTER_MESSAGE MESSAGE_SIZE_MAX
|
||||
# define OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
|
||||
# ifndef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
|
||||
# endif
|
||||
# ifndef CMAN_MAX_CLUSTER_MESSAGE
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE MESSAGE_SIZE_MAX
|
||||
# endif
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN sizeof(int)
|
||||
# endif
|
||||
struct cluster_ops *init_openais_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_COROSYNC
|
||||
# include <corosync/corotypes.h>
|
||||
# define COROSYNC_CSID_LEN (sizeof(int))
|
||||
# define COROSYNC_MAX_CLUSTER_MESSAGE 65535
|
||||
# define COROSYNC_MAX_CLUSTER_MEMBER_NAME_LEN CS_MAX_NAME_LENGTH
|
||||
# ifndef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN CS_MAX_NAME_LENGTH
|
||||
# endif
|
||||
# ifndef CMAN_MAX_CLUSTER_MESSAGE
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE 65535
|
||||
# endif
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN sizeof(int)
|
||||
# endif
|
||||
struct cluster_ops *init_corosync_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SINGLENODE
|
||||
# define SINGLENODE_CSID_LEN (sizeof(int))
|
||||
# ifndef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN 64
|
||||
# endif
|
||||
# define SINGLENODE_MAX_CLUSTER_MESSAGE 65535
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN sizeof(int)
|
||||
# endif
|
||||
struct cluster_ops *init_singlenode_cluster(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,662 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2012 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This provides the interface between clvmd and corosync/DLM as the cluster
|
||||
* and lock manager.
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
#include "locking.h"
|
||||
|
||||
#include <corosync/cpg.h>
|
||||
#include <corosync/quorum.h>
|
||||
|
||||
#ifdef HAVE_COROSYNC_CONFDB_H
|
||||
# include <corosync/confdb.h>
|
||||
#elif defined HAVE_COROSYNC_CMAP_H
|
||||
# include <corosync/cmap.h>
|
||||
#else
|
||||
# error "Either HAVE_COROSYNC_CONFDB_H or HAVE_COROSYNC_CMAP_H must be defined."
|
||||
#endif
|
||||
|
||||
#include <libdlm.h>
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
/* Timeout value for several corosync calls */
|
||||
#define LOCKSPACE_NAME "clvmd"
|
||||
|
||||
static void corosync_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len);
|
||||
static void corosync_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries);
|
||||
static void _cluster_closedown(void);
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct dm_hash_table *node_hash;
|
||||
|
||||
/* Number of active nodes */
|
||||
static int num_nodes;
|
||||
static unsigned int our_nodeid;
|
||||
|
||||
static struct local_client *cluster_client;
|
||||
|
||||
/* Corosync handles */
|
||||
static cpg_handle_t cpg_handle;
|
||||
static quorum_handle_t quorum_handle;
|
||||
|
||||
/* DLM Handle */
|
||||
static dlm_lshandle_t *lockspace;
|
||||
|
||||
static struct cpg_name cpg_group_name;
|
||||
|
||||
/* Corosync callback structs */
|
||||
cpg_callbacks_t corosync_cpg_callbacks = {
|
||||
.cpg_deliver_fn = corosync_cpg_deliver_callback,
|
||||
.cpg_confchg_fn = corosync_cpg_confchg_callback,
|
||||
};
|
||||
|
||||
quorum_callbacks_t quorum_callbacks = {
|
||||
.quorum_notify_fn = NULL,
|
||||
};
|
||||
|
||||
struct node_info
|
||||
{
|
||||
enum {NODE_DOWN, NODE_CLVMD} state;
|
||||
int nodeid;
|
||||
};
|
||||
|
||||
|
||||
/* Set errno to something approximating the right value and return 0 or -1 */
|
||||
static int cs_to_errno(cs_error_t err)
|
||||
{
|
||||
switch(err)
|
||||
{
|
||||
case CS_OK:
|
||||
return 0;
|
||||
case CS_ERR_LIBRARY:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_VERSION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_INIT:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_TIMEOUT:
|
||||
errno = ETIME;
|
||||
break;
|
||||
case CS_ERR_TRY_AGAIN:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
case CS_ERR_INVALID_PARAM:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_NO_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case CS_ERR_BAD_HANDLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_BUSY:
|
||||
errno = EBUSY;
|
||||
break;
|
||||
case CS_ERR_ACCESS:
|
||||
errno = EPERM;
|
||||
break;
|
||||
case CS_ERR_NOT_EXIST:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case CS_ERR_NAME_TOO_LONG:
|
||||
errno = ENAMETOOLONG;
|
||||
break;
|
||||
case CS_ERR_EXIST:
|
||||
errno = EEXIST;
|
||||
break;
|
||||
case CS_ERR_NO_SPACE:
|
||||
errno = ENOSPC;
|
||||
break;
|
||||
case CS_ERR_INTERRUPT:
|
||||
errno = EINTR;
|
||||
break;
|
||||
case CS_ERR_NAME_NOT_FOUND:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case CS_ERR_NO_RESOURCES:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case CS_ERR_NOT_SUPPORTED:
|
||||
errno = EOPNOTSUPP;
|
||||
break;
|
||||
case CS_ERR_BAD_OPERATION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_FAILED_OPERATION:
|
||||
errno = EIO;
|
||||
break;
|
||||
case CS_ERR_MESSAGE_ERROR:
|
||||
errno = EIO;
|
||||
break;
|
||||
case CS_ERR_QUEUE_FULL:
|
||||
errno = EXFULL;
|
||||
break;
|
||||
case CS_ERR_QUEUE_NOT_AVAILABLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_BAD_FLAGS:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_TOO_BIG:
|
||||
errno = E2BIG;
|
||||
break;
|
||||
case CS_ERR_NO_SECTIONS:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *print_corosync_csid(const char *csid)
|
||||
{
|
||||
static char buf[128];
|
||||
int id;
|
||||
|
||||
memcpy(&id, csid, sizeof(int));
|
||||
sprintf(buf, "%d", id);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void corosync_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len)
|
||||
{
|
||||
int target_nodeid;
|
||||
|
||||
memcpy(&target_nodeid, msg, COROSYNC_CSID_LEN);
|
||||
|
||||
DEBUGLOG("%u got message from nodeid %d for %d. len %zd\n",
|
||||
our_nodeid, nodeid, target_nodeid, msg_len-4);
|
||||
|
||||
if (nodeid != our_nodeid)
|
||||
if (target_nodeid == our_nodeid || target_nodeid == 0)
|
||||
process_message(cluster_client, (char *)msg+COROSYNC_CSID_LEN,
|
||||
msg_len-COROSYNC_CSID_LEN, (char*)&nodeid);
|
||||
}
|
||||
|
||||
static void corosync_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries)
|
||||
{
|
||||
int i;
|
||||
struct node_info *ninfo;
|
||||
|
||||
DEBUGLOG("confchg callback. %zd joined, %zd left, %zd members\n",
|
||||
joined_list_entries, left_list_entries, member_list_entries);
|
||||
|
||||
for (i=0; i<joined_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&joined_list[i].nodeid,
|
||||
COROSYNC_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ninfo->nodeid = joined_list[i].nodeid;
|
||||
dm_hash_insert_binary(node_hash,
|
||||
(char *)&ninfo->nodeid,
|
||||
COROSYNC_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
for (i=0; i<left_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&left_list[i].nodeid,
|
||||
COROSYNC_CSID_LEN);
|
||||
if (ninfo)
|
||||
ninfo->state = NODE_DOWN;
|
||||
}
|
||||
|
||||
num_nodes = member_list_entries;
|
||||
}
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
cs_error_t err;
|
||||
|
||||
#ifdef QUORUM_SET /* corosync/quorum.h */
|
||||
uint32_t quorum_type;
|
||||
#endif
|
||||
|
||||
node_hash = dm_hash_create(100);
|
||||
|
||||
err = cpg_initialize(&cpg_handle,
|
||||
&corosync_cpg_callbacks);
|
||||
if (err != CS_OK) {
|
||||
syslog(LOG_ERR, "Cannot initialise Corosync CPG service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise Corosync CPG service: %d", err);
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
#ifdef QUORUM_SET
|
||||
err = quorum_initialize(&quorum_handle,
|
||||
&quorum_callbacks,
|
||||
&quorum_type);
|
||||
|
||||
if (quorum_type != QUORUM_SET) {
|
||||
syslog(LOG_ERR, "Corosync quorum service is not configured");
|
||||
DEBUGLOG("Corosync quorum service is not configured");
|
||||
return EINVAL;
|
||||
}
|
||||
#else
|
||||
err = quorum_initialize(&quorum_handle,
|
||||
&quorum_callbacks);
|
||||
#endif
|
||||
|
||||
if (err != CS_OK) {
|
||||
syslog(LOG_ERR, "Cannot initialise Corosync quorum service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise Corosync quorum service: %d", err);
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
/* Create a lockspace for LV & VG locks to live in */
|
||||
lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
|
||||
if (!lockspace) {
|
||||
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
|
||||
if (!lockspace) {
|
||||
syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("Created DLM lockspace for CLVMD.\n");
|
||||
} else
|
||||
DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
|
||||
|
||||
dlm_ls_pthread_init(lockspace);
|
||||
DEBUGLOG("DLM initialisation complete\n");
|
||||
|
||||
/* Connect to the clvmd group */
|
||||
strcpy((char *)cpg_group_name.value, "clvmd");
|
||||
cpg_group_name.length = strlen((char *)cpg_group_name.value);
|
||||
err = cpg_join(cpg_handle, &cpg_group_name);
|
||||
if (err != CS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
quorum_finalize(quorum_handle);
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
syslog(LOG_ERR, "Cannot join clvmd process group");
|
||||
DEBUGLOG("Cannot join clvmd process group: %d\n", err);
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
err = cpg_local_get(cpg_handle,
|
||||
&our_nodeid);
|
||||
if (err != CS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
quorum_finalize(quorum_handle);
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
syslog(LOG_ERR, "Cannot get local node id\n");
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
DEBUGLOG("Our local node id is %d\n", our_nodeid);
|
||||
|
||||
DEBUGLOG("Connected to Corosync\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
cpg_finalize(cpg_handle);
|
||||
quorum_finalize(quorum_handle);
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
memcpy(csid, &our_nodeid, sizeof(int));
|
||||
}
|
||||
|
||||
/* Corosync doesn't really have nmode names so we
|
||||
just use the node ID in hex instead */
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
int nodeid;
|
||||
struct node_info *ninfo;
|
||||
|
||||
if (sscanf(name, "%x", &nodeid) == 1) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
|
||||
if (ninfo)
|
||||
return nodeid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
sprintf(name, "UNKNOWN %s", print_corosync_csid(csid));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(name, "%x", ninfo->nodeid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_num_nodes(void)
|
||||
{
|
||||
DEBUGLOG("num_nodes = %d\n", num_nodes);
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
DEBUGLOG("corosync_add_up_node no node_hash entry for csid %s\n",
|
||||
print_corosync_csid(csid));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGLOG("corosync_add_up_node %d\n", ninfo->nodeid);
|
||||
|
||||
ninfo->state = NODE_CLVMD;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *,
|
||||
const char *csid, int node_up))
|
||||
{
|
||||
struct dm_hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
|
||||
dm_hash_iterate(hn, node_hash)
|
||||
{
|
||||
char csid[COROSYNC_CSID_LEN];
|
||||
|
||||
ninfo = dm_hash_get_data(node_hash, hn);
|
||||
memcpy(csid, dm_hash_get_key(node_hash, hn), COROSYNC_CSID_LEN);
|
||||
|
||||
DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
|
||||
ninfo->state);
|
||||
|
||||
if (ninfo->state == NODE_CLVMD)
|
||||
callback(master_client, csid, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
struct dlm_lksb lksb;
|
||||
int err;
|
||||
|
||||
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
|
||||
|
||||
if (flags & LKF_CONVERT)
|
||||
lksb.sb_lkid = *lockid;
|
||||
|
||||
err = dlm_ls_lock_wait(lockspace,
|
||||
mode,
|
||||
&lksb,
|
||||
flags,
|
||||
resource,
|
||||
strlen(resource),
|
||||
0,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
DEBUGLOG("dlm_ls_lock returned %d\n", errno);
|
||||
return err;
|
||||
}
|
||||
if (lksb.sb_status != 0)
|
||||
{
|
||||
DEBUGLOG("dlm_ls_lock returns lksb.sb_status %d\n", lksb.sb_status);
|
||||
errno = lksb.sb_status;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGLOG("lock_resource returning %d, lock_id=%x\n", err, lksb.sb_lkid);
|
||||
|
||||
*lockid = lksb.sb_lkid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int _unlock_resource(const char *resource, int lockid)
|
||||
{
|
||||
struct dlm_lksb lksb;
|
||||
int err;
|
||||
|
||||
DEBUGLOG("unlock_resource: %s lockid: %x\n", resource, lockid);
|
||||
lksb.sb_lkid = lockid;
|
||||
|
||||
err = dlm_ls_unlock_wait(lockspace,
|
||||
lockid,
|
||||
0,
|
||||
&lksb);
|
||||
if (err != 0)
|
||||
{
|
||||
DEBUGLOG("Unlock returned %d\n", err);
|
||||
return err;
|
||||
}
|
||||
if (lksb.sb_status != EUNLOCK)
|
||||
{
|
||||
DEBUGLOG("dlm_ls_unlock_wait returns lksb.sb_status: %d\n", lksb.sb_status);
|
||||
errno = lksb.sb_status;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _is_quorate(void)
|
||||
{
|
||||
int quorate;
|
||||
if (quorum_getquorate(quorum_handle, &quorate) == CS_OK)
|
||||
return quorate;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
int select_fd;
|
||||
|
||||
cpg_fd_get(cpg_handle, &select_fd);
|
||||
return select_fd;
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
cluster_client = fd;
|
||||
*new_client = NULL;
|
||||
cpg_dispatch(cpg_handle, CS_DISPATCH_ONE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
struct iovec iov[2];
|
||||
cs_error_t err;
|
||||
int target_node;
|
||||
|
||||
if (csid)
|
||||
memcpy(&target_node, csid, COROSYNC_CSID_LEN);
|
||||
else
|
||||
target_node = 0;
|
||||
|
||||
iov[0].iov_base = &target_node;
|
||||
iov[0].iov_len = sizeof(int);
|
||||
iov[1].iov_base = (char *)buf;
|
||||
iov[1].iov_len = msglen;
|
||||
|
||||
pthread_mutex_lock(&_mutex);
|
||||
err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
|
||||
pthread_mutex_unlock(&_mutex);
|
||||
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
#ifdef HAVE_COROSYNC_CONFDB_H
|
||||
/*
|
||||
* We are not necessarily connected to a Red Hat Cluster system,
|
||||
* but if we are, this returns the cluster name from cluster.conf.
|
||||
* I've used confdb rather than ccs to reduce the inter-package
|
||||
* dependancies as well as to allow people to set a cluster name
|
||||
* for themselves even if they are not running on RH cluster.
|
||||
*/
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
confdb_handle_t handle;
|
||||
int result;
|
||||
size_t namelen = buflen;
|
||||
hdb_handle_t cluster_handle;
|
||||
confdb_callbacks_t callbacks = {
|
||||
.confdb_key_change_notify_fn = NULL,
|
||||
.confdb_object_create_change_notify_fn = NULL,
|
||||
.confdb_object_delete_change_notify_fn = NULL
|
||||
};
|
||||
|
||||
/* This is a default in case everything else fails */
|
||||
strncpy(buf, "Corosync", buflen);
|
||||
|
||||
/* Look for a cluster name in confdb */
|
||||
result = confdb_initialize (&handle, &callbacks);
|
||||
if (result != CS_OK)
|
||||
return 0;
|
||||
|
||||
result = confdb_object_find_start(handle, OBJECT_PARENT_HANDLE);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
result = confdb_object_find(handle, OBJECT_PARENT_HANDLE, (void *)"cluster", strlen("cluster"), &cluster_handle);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
result = confdb_key_get(handle, cluster_handle, (void *)"name", strlen("name"), buf, &namelen);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
buf[namelen] = '\0';
|
||||
|
||||
out:
|
||||
confdb_finalize(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined HAVE_COROSYNC_CMAP_H
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
cmap_handle_t cmap_handle = 0;
|
||||
int result;
|
||||
char *name = NULL;
|
||||
|
||||
/* This is a default in case everything else fails */
|
||||
strncpy(buf, "Corosync", buflen);
|
||||
|
||||
/* Look for a cluster name in cmap */
|
||||
result = cmap_initialize(&cmap_handle);
|
||||
if (result != CS_OK)
|
||||
return 0;
|
||||
|
||||
result = cmap_get_string(cmap_handle, "totem.cluster_name", &name);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
memset(buf, 0, buflen);
|
||||
strncpy(buf, name, buflen - 1);
|
||||
|
||||
out:
|
||||
if (name)
|
||||
free(name);
|
||||
cmap_finalize(cmap_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static struct cluster_ops _cluster_corosync_ops = {
|
||||
.name = "corosync",
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.reread_config = NULL,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _lock_resource,
|
||||
.sync_unlock = _unlock_resource,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_corosync_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_corosync_ops;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,687 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2009 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This provides the interface between clvmd and OpenAIS as the cluster
|
||||
* and lock manager.
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <openais/saAis.h>
|
||||
#include <openais/saLck.h>
|
||||
|
||||
#include <corosync/corotypes.h>
|
||||
#include <corosync/cpg.h>
|
||||
|
||||
#include "locking.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "lvm-functions.h"
|
||||
#include "clvmd.h"
|
||||
|
||||
/* Timeout value for several openais calls */
|
||||
#define TIMEOUT 10
|
||||
|
||||
static void openais_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len);
|
||||
static void openais_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries);
|
||||
|
||||
static void _cluster_closedown(void);
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct dm_hash_table *node_hash;
|
||||
|
||||
/* For associating lock IDs & resource handles */
|
||||
static struct dm_hash_table *lock_hash;
|
||||
|
||||
/* Number of active nodes */
|
||||
static int num_nodes;
|
||||
static unsigned int our_nodeid;
|
||||
|
||||
static struct local_client *cluster_client;
|
||||
|
||||
/* OpenAIS handles */
|
||||
static cpg_handle_t cpg_handle;
|
||||
static SaLckHandleT lck_handle;
|
||||
|
||||
static struct cpg_name cpg_group_name;
|
||||
|
||||
/* Openais callback structs */
|
||||
cpg_callbacks_t openais_cpg_callbacks = {
|
||||
.cpg_deliver_fn = openais_cpg_deliver_callback,
|
||||
.cpg_confchg_fn = openais_cpg_confchg_callback,
|
||||
};
|
||||
|
||||
struct node_info
|
||||
{
|
||||
enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
|
||||
int nodeid;
|
||||
};
|
||||
|
||||
struct lock_info
|
||||
{
|
||||
SaLckResourceHandleT res_handle;
|
||||
SaLckLockIdT lock_id;
|
||||
SaNameT lock_name;
|
||||
};
|
||||
|
||||
/* Set errno to something approximating the right value and return 0 or -1 */
|
||||
static int ais_to_errno(SaAisErrorT err)
|
||||
{
|
||||
switch(err)
|
||||
{
|
||||
case SA_AIS_OK:
|
||||
return 0;
|
||||
case SA_AIS_ERR_LIBRARY:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_VERSION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_INIT:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_TIMEOUT:
|
||||
errno = ETIME;
|
||||
break;
|
||||
case SA_AIS_ERR_TRY_AGAIN:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
case SA_AIS_ERR_INVALID_PARAM:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_HANDLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_BUSY:
|
||||
errno = EBUSY;
|
||||
break;
|
||||
case SA_AIS_ERR_ACCESS:
|
||||
errno = EPERM;
|
||||
break;
|
||||
case SA_AIS_ERR_NOT_EXIST:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case SA_AIS_ERR_NAME_TOO_LONG:
|
||||
errno = ENAMETOOLONG;
|
||||
break;
|
||||
case SA_AIS_ERR_EXIST:
|
||||
errno = EEXIST;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_SPACE:
|
||||
errno = ENOSPC;
|
||||
break;
|
||||
case SA_AIS_ERR_INTERRUPT:
|
||||
errno = EINTR;
|
||||
break;
|
||||
case SA_AIS_ERR_NAME_NOT_FOUND:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_RESOURCES:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case SA_AIS_ERR_NOT_SUPPORTED:
|
||||
errno = EOPNOTSUPP;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_OPERATION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_FAILED_OPERATION:
|
||||
errno = EIO;
|
||||
break;
|
||||
case SA_AIS_ERR_MESSAGE_ERROR:
|
||||
errno = EIO;
|
||||
break;
|
||||
case SA_AIS_ERR_QUEUE_FULL:
|
||||
errno = EXFULL;
|
||||
break;
|
||||
case SA_AIS_ERR_QUEUE_NOT_AVAILABLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_FLAGS:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_TOO_BIG:
|
||||
errno = E2BIG;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_SECTIONS:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *print_openais_csid(const char *csid)
|
||||
{
|
||||
static char buf[128];
|
||||
int id;
|
||||
|
||||
memcpy(&id, csid, sizeof(int));
|
||||
sprintf(buf, "%d", id);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int add_internal_client(int fd, fd_callback_t callback)
|
||||
{
|
||||
struct local_client *client;
|
||||
|
||||
DEBUGLOG("Add_internal_client, fd = %d\n", fd);
|
||||
|
||||
if (!(client = dm_zalloc(sizeof(*client)))) {
|
||||
DEBUGLOG("malloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
client->fd = fd;
|
||||
client->type = CLUSTER_INTERNAL;
|
||||
client->callback = callback;
|
||||
add_client(client);
|
||||
|
||||
/* Set Close-on-exec */
|
||||
fcntl(fd, F_SETFD, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void openais_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len)
|
||||
{
|
||||
int target_nodeid;
|
||||
|
||||
memcpy(&target_nodeid, msg, OPENAIS_CSID_LEN);
|
||||
|
||||
DEBUGLOG("%u got message from nodeid %d for %d. len %" PRIsize_t "\n",
|
||||
our_nodeid, nodeid, target_nodeid, msg_len-4);
|
||||
|
||||
if (nodeid != our_nodeid)
|
||||
if (target_nodeid == our_nodeid || target_nodeid == 0)
|
||||
process_message(cluster_client, (char *)msg+OPENAIS_CSID_LEN,
|
||||
msg_len-OPENAIS_CSID_LEN, (char*)&nodeid);
|
||||
}
|
||||
|
||||
static void openais_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries)
|
||||
{
|
||||
int i;
|
||||
struct node_info *ninfo;
|
||||
|
||||
DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
|
||||
FMTsize_t " left, %" PRIsize_t " members\n",
|
||||
joined_list_entries, left_list_entries, member_list_entries);
|
||||
|
||||
for (i=0; i<joined_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&joined_list[i].nodeid,
|
||||
OPENAIS_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ninfo->nodeid = joined_list[i].nodeid;
|
||||
dm_hash_insert_binary(node_hash,
|
||||
(char *)&ninfo->nodeid,
|
||||
OPENAIS_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
for (i=0; i<left_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&left_list[i].nodeid,
|
||||
OPENAIS_CSID_LEN);
|
||||
if (ninfo)
|
||||
ninfo->state = NODE_DOWN;
|
||||
}
|
||||
|
||||
for (i=0; i<member_list_entries; i++) {
|
||||
if (member_list[i].nodeid == 0) continue;
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&member_list[i].nodeid,
|
||||
OPENAIS_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ninfo->nodeid = member_list[i].nodeid;
|
||||
dm_hash_insert_binary(node_hash,
|
||||
(char *)&ninfo->nodeid,
|
||||
OPENAIS_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
num_nodes = member_list_entries;
|
||||
}
|
||||
|
||||
static int lck_dispatch(struct local_client *client, char *buf, int len,
|
||||
const char *csid, struct local_client **new_client)
|
||||
{
|
||||
*new_client = NULL;
|
||||
saLckDispatch(lck_handle, SA_DISPATCH_ONE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
SaAisErrorT err;
|
||||
SaVersionT ver = { 'B', 1, 1 };
|
||||
int select_fd;
|
||||
|
||||
node_hash = dm_hash_create(100);
|
||||
lock_hash = dm_hash_create(10);
|
||||
|
||||
err = cpg_initialize(&cpg_handle,
|
||||
&openais_cpg_callbacks);
|
||||
if (err != SA_AIS_OK) {
|
||||
syslog(LOG_ERR, "Cannot initialise OpenAIS CPG service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise OpenAIS CPG service: %d", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = saLckInitialize(&lck_handle,
|
||||
NULL,
|
||||
&ver);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_initialize(&cpg_handle, &openais_cpg_callbacks);
|
||||
syslog(LOG_ERR, "Cannot initialise OpenAIS lock service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise OpenAIS lock service: %d\n\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Connect to the clvmd group */
|
||||
strcpy((char *)cpg_group_name.value, "clvmd");
|
||||
cpg_group_name.length = strlen((char *)cpg_group_name.value);
|
||||
err = cpg_join(cpg_handle, &cpg_group_name);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
saLckFinalize(lck_handle);
|
||||
syslog(LOG_ERR, "Cannot join clvmd process group");
|
||||
DEBUGLOG("Cannot join clvmd process group: %d\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = cpg_local_get(cpg_handle,
|
||||
&our_nodeid);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
saLckFinalize(lck_handle);
|
||||
syslog(LOG_ERR, "Cannot get local node id\n");
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
DEBUGLOG("Our local node id is %d\n", our_nodeid);
|
||||
|
||||
saLckSelectionObjectGet(lck_handle, (SaSelectionObjectT *)&select_fd);
|
||||
add_internal_client(select_fd, lck_dispatch);
|
||||
|
||||
DEBUGLOG("Connected to OpenAIS\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
saLckFinalize(lck_handle);
|
||||
cpg_finalize(cpg_handle);
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
memcpy(csid, &our_nodeid, sizeof(int));
|
||||
}
|
||||
|
||||
/* OpenAIS doesn't really have nmode names so we
|
||||
just use the node ID in hex instead */
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
int nodeid;
|
||||
struct node_info *ninfo;
|
||||
|
||||
if (sscanf(name, "%x", &nodeid) == 1) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (ninfo)
|
||||
return nodeid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
sprintf(name, "UNKNOWN %s", print_openais_csid(csid));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(name, "%x", ninfo->nodeid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_num_nodes()
|
||||
{
|
||||
DEBUGLOG("num_nodes = %d\n", num_nodes);
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
DEBUGLOG("openais_add_up_node no node_hash entry for csid %s\n",
|
||||
print_openais_csid(csid));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGLOG("openais_add_up_node %d\n", ninfo->nodeid);
|
||||
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *,
|
||||
const char *csid, int node_up))
|
||||
{
|
||||
struct dm_hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
int somedown = 0;
|
||||
|
||||
dm_hash_iterate(hn, node_hash)
|
||||
{
|
||||
char csid[OPENAIS_CSID_LEN];
|
||||
|
||||
ninfo = dm_hash_get_data(node_hash, hn);
|
||||
memcpy(csid, dm_hash_get_key(node_hash, hn), OPENAIS_CSID_LEN);
|
||||
|
||||
DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
|
||||
ninfo->state);
|
||||
|
||||
if (ninfo->state != NODE_DOWN)
|
||||
callback(master_client, csid, ninfo->state == NODE_CLVMD);
|
||||
if (ninfo->state != NODE_CLVMD)
|
||||
somedown = -1;
|
||||
}
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
struct lock_info *linfo;
|
||||
SaLckResourceHandleT res_handle;
|
||||
SaAisErrorT err;
|
||||
SaLckLockIdT lock_id;
|
||||
SaLckLockStatusT lockStatus;
|
||||
|
||||
/* This needs to be converted from DLM/LVM2 value for OpenAIS LCK */
|
||||
if (flags & LCK_NONBLOCK) flags = SA_LCK_LOCK_NO_QUEUE;
|
||||
|
||||
linfo = malloc(sizeof(struct lock_info));
|
||||
if (!linfo)
|
||||
return -1;
|
||||
|
||||
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
|
||||
|
||||
linfo->lock_name.length = strlen(resource)+1;
|
||||
strcpy((char *)linfo->lock_name.value, resource);
|
||||
|
||||
err = saLckResourceOpen(lck_handle, &linfo->lock_name,
|
||||
SA_LCK_RESOURCE_CREATE, TIMEOUT, &res_handle);
|
||||
if (err != SA_AIS_OK)
|
||||
{
|
||||
DEBUGLOG("ResourceOpen returned %d\n", err);
|
||||
free(linfo);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = saLckResourceLock(
|
||||
res_handle,
|
||||
&lock_id,
|
||||
mode,
|
||||
flags,
|
||||
0,
|
||||
SA_TIME_END,
|
||||
&lockStatus);
|
||||
if (err != SA_AIS_OK && lockStatus != SA_LCK_LOCK_GRANTED)
|
||||
{
|
||||
free(linfo);
|
||||
saLckResourceClose(res_handle);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Wait for it to complete */
|
||||
|
||||
DEBUGLOG("lock_resource returning %d, lock_id=%" PRIx64 "\n",
|
||||
err, lock_id);
|
||||
|
||||
linfo->lock_id = lock_id;
|
||||
linfo->res_handle = res_handle;
|
||||
|
||||
dm_hash_insert(lock_hash, resource, linfo);
|
||||
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
|
||||
static int _unlock_resource(char *resource, int lockid)
|
||||
{
|
||||
SaAisErrorT err;
|
||||
struct lock_info *linfo;
|
||||
|
||||
DEBUGLOG("unlock_resource %s\n", resource);
|
||||
linfo = dm_hash_lookup(lock_hash, resource);
|
||||
if (!linfo)
|
||||
return 0;
|
||||
|
||||
DEBUGLOG("unlock_resource: lockid: %" PRIx64 "\n", linfo->lock_id);
|
||||
err = saLckResourceUnlock(linfo->lock_id, SA_TIME_END);
|
||||
if (err != SA_AIS_OK)
|
||||
{
|
||||
DEBUGLOG("Unlock returned %d\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Release the resource */
|
||||
dm_hash_remove(lock_hash, resource);
|
||||
saLckResourceClose(linfo->res_handle);
|
||||
free(linfo);
|
||||
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
char lock1[strlen(resource)+3];
|
||||
char lock2[strlen(resource)+3];
|
||||
|
||||
snprintf(lock1, sizeof(lock1), "%s-1", resource);
|
||||
snprintf(lock2, sizeof(lock2), "%s-2", resource);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case LCK_EXCL:
|
||||
status = _lock_resource(lock1, SA_LCK_EX_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* If we can't get this lock too then bail out */
|
||||
status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, LCK_NONBLOCK,
|
||||
lockid);
|
||||
if (status == SA_LCK_LOCK_NOT_QUEUED)
|
||||
{
|
||||
_unlock_resource(lock1, *lockid);
|
||||
status = -1;
|
||||
errno = EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case LCK_PREAD:
|
||||
case LCK_READ:
|
||||
status = _lock_resource(lock1, SA_LCK_PR_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
_unlock_resource(lock2, *lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
_unlock_resource(lock1, *lockid);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = -1;
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
*lockid = mode;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int _sync_unlock(const char *resource, int lockid)
|
||||
{
|
||||
int status = 0;
|
||||
char lock1[strlen(resource)+3];
|
||||
char lock2[strlen(resource)+3];
|
||||
|
||||
snprintf(lock1, sizeof(lock1), "%s-1", resource);
|
||||
snprintf(lock2, sizeof(lock2), "%s-2", resource);
|
||||
|
||||
_unlock_resource(lock1, lockid);
|
||||
_unlock_resource(lock2, lockid);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* We are always quorate ! */
|
||||
static int _is_quorate()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
int select_fd;
|
||||
|
||||
cpg_fd_get(cpg_handle, &select_fd);
|
||||
return select_fd;
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
cluster_client = fd;
|
||||
*new_client = NULL;
|
||||
cpg_dispatch(cpg_handle, SA_DISPATCH_ONE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
SaAisErrorT err;
|
||||
int target_node;
|
||||
|
||||
if (csid)
|
||||
memcpy(&target_node, csid, OPENAIS_CSID_LEN);
|
||||
else
|
||||
target_node = 0;
|
||||
|
||||
iov[0].iov_base = &target_node;
|
||||
iov[0].iov_len = sizeof(int);
|
||||
iov[1].iov_base = (char *)buf;
|
||||
iov[1].iov_len = msglen;
|
||||
|
||||
err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* We don't have a cluster name to report here */
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
strncpy(buf, "OpenAIS", buflen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_openais_ops = {
|
||||
.name = "openais",
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.reread_config = NULL,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_openais_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_openais_ops;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,382 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2013 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "locking.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
|
||||
#include <sys/un.h>
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static const char SINGLENODE_CLVMD_SOCKNAME[] = DEFAULT_RUN_DIR "/clvmd_singlenode.sock";
|
||||
static int listen_fd = -1;
|
||||
|
||||
static struct dm_hash_table *_locks;
|
||||
static int _lockid;
|
||||
|
||||
static pthread_mutex_t _lock_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
/* Using one common condition for all locks for simplicity */
|
||||
static pthread_cond_t _lock_cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
struct lock {
|
||||
struct dm_list list;
|
||||
int lockid;
|
||||
int mode;
|
||||
};
|
||||
|
||||
static void close_comms(void)
|
||||
{
|
||||
if (listen_fd != -1 && close(listen_fd))
|
||||
stack;
|
||||
(void)unlink(SINGLENODE_CLVMD_SOCKNAME);
|
||||
listen_fd = -1;
|
||||
}
|
||||
|
||||
static int init_comms(void)
|
||||
{
|
||||
mode_t old_mask;
|
||||
struct sockaddr_un addr = { .sun_family = AF_UNIX };
|
||||
|
||||
if (!dm_strncpy(addr.sun_path, SINGLENODE_CLVMD_SOCKNAME,
|
||||
sizeof(addr.sun_path))) {
|
||||
DEBUGLOG("%s: singlenode socket name too long.",
|
||||
SINGLENODE_CLVMD_SOCKNAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close_comms();
|
||||
|
||||
(void) dm_prepare_selinux_context(SINGLENODE_CLVMD_SOCKNAME, S_IFSOCK);
|
||||
old_mask = umask(0077);
|
||||
|
||||
listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0) {
|
||||
DEBUGLOG("Can't create local socket: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
/* Set Close-on-exec */
|
||||
if (fcntl(listen_fd, F_SETFD, 1)) {
|
||||
DEBUGLOG("Setting CLOEXEC on client fd failed: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
DEBUGLOG("Can't bind local socket: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
if (listen(listen_fd, 10) < 0) {
|
||||
DEBUGLOG("Can't listen local socket: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
umask(old_mask);
|
||||
(void) dm_prepare_selinux_context(NULL, 0);
|
||||
return 0;
|
||||
error:
|
||||
umask(old_mask);
|
||||
(void) dm_prepare_selinux_context(NULL, 0);
|
||||
close_comms();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!(_locks = dm_hash_create(128))) {
|
||||
DEBUGLOG("Failed to allocate single-node hash table.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = init_comms();
|
||||
if (r) {
|
||||
dm_hash_destroy(_locks);
|
||||
_locks = NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
DEBUGLOG("Single-node cluster initialised.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
close_comms();
|
||||
|
||||
/* If there is any awaited resource, kill it softly */
|
||||
pthread_mutex_lock(&_lock_mutex);
|
||||
dm_hash_destroy(_locks);
|
||||
_locks = NULL;
|
||||
_lockid = 0;
|
||||
pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
int nodeid = 1;
|
||||
memcpy(csid, &nodeid, sizeof(int));
|
||||
}
|
||||
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
strcpy(name, "SINGLENODE");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_num_nodes(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *,
|
||||
const char *csid, int node_up))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _lock_file(const char *file, uint32_t flags);
|
||||
|
||||
static const char *_get_mode(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case LCK_NULL: return "NULL";
|
||||
case LCK_READ: return "READ";
|
||||
case LCK_PREAD: return "PREAD";
|
||||
case LCK_WRITE: return "WRITE";
|
||||
case LCK_EXCL: return "EXCLUSIVE";
|
||||
case LCK_UNLOCK: return "UNLOCK";
|
||||
default: return "????";
|
||||
}
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
/* DLM table of allowed transition states */
|
||||
static const int _dlm_table[6][6] = {
|
||||
/* Mode NL CR CW PR PW EX */
|
||||
/* NL */ { 1, 1, 1, 1, 1, 1},
|
||||
/* CR */ { 1, 1, 1, 1, 1, 0},
|
||||
/* CW */ { 1, 1, 1, 0, 0, 0},
|
||||
/* PR */ { 1, 1, 0, 1, 0, 0},
|
||||
/* PW */ { 1, 1, 0, 0, 0, 0},
|
||||
/* EX */ { 1, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
struct lock *lck = NULL, *lckt;
|
||||
struct dm_list *head;
|
||||
|
||||
DEBUGLOG("Locking resource %s, flags=0x%02x (%s%s%s), mode=%s (%d)\n",
|
||||
resource, flags,
|
||||
(flags & LCKF_NOQUEUE) ? "NOQUEUE" : "",
|
||||
((flags & (LCKF_NOQUEUE | LCKF_CONVERT)) ==
|
||||
(LCKF_NOQUEUE | LCKF_CONVERT)) ? "|" : "",
|
||||
(flags & LCKF_CONVERT) ? "CONVERT" : "",
|
||||
_get_mode(mode), mode);
|
||||
|
||||
mode &= LCK_TYPE_MASK;
|
||||
pthread_mutex_lock(&_lock_mutex);
|
||||
|
||||
retry:
|
||||
if (!(head = dm_hash_lookup(_locks, resource))) {
|
||||
if (flags & LCKF_CONVERT) {
|
||||
/* In real DLM, lock is identified only by lockid, resource is not used */
|
||||
DEBUGLOG("Unlocked resource %s cannot be converted\n", resource);
|
||||
goto_bad;
|
||||
}
|
||||
/* Add new locked resource */
|
||||
if (!(head = dm_malloc(sizeof(struct dm_list))) ||
|
||||
!dm_hash_insert(_locks, resource, head)) {
|
||||
dm_free(head);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
dm_list_init(head);
|
||||
} else /* Update/convert locked resource */
|
||||
dm_list_iterate_items(lck, head) {
|
||||
/* Check is all locks are compatible with requested lock */
|
||||
if (flags & LCKF_CONVERT) {
|
||||
if (lck->lockid != *lockid)
|
||||
continue;
|
||||
|
||||
DEBUGLOG("Converting resource %s lockid=%d mode:%s -> %s...\n",
|
||||
resource, lck->lockid, _get_mode(lck->mode), _get_mode(mode));
|
||||
dm_list_iterate_items(lckt, head) {
|
||||
if ((lckt->lockid != *lockid) &&
|
||||
!_dlm_table[mode][lckt->mode]) {
|
||||
if (!(flags & LCKF_NOQUEUE) &&
|
||||
/* TODO: Real dlm uses here conversion queues */
|
||||
!pthread_cond_wait(&_lock_cond, &_lock_mutex) &&
|
||||
_locks) /* End of the game? */
|
||||
goto retry;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
lck->mode = mode; /* Lock is now converted */
|
||||
goto out;
|
||||
} else if (!_dlm_table[mode][lck->mode]) {
|
||||
DEBUGLOG("Resource %s already locked lockid=%d, mode:%s\n",
|
||||
resource, lck->lockid, _get_mode(lck->mode));
|
||||
if (!(flags & LCKF_NOQUEUE) &&
|
||||
!pthread_cond_wait(&_lock_cond, &_lock_mutex) &&
|
||||
_locks) { /* End of the game? */
|
||||
DEBUGLOG("Resource %s retrying lock in mode:%s...\n",
|
||||
resource, _get_mode(mode));
|
||||
goto retry;
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & LCKF_CONVERT)) {
|
||||
if (!(lck = dm_malloc(sizeof(struct lock))))
|
||||
goto_bad;
|
||||
|
||||
*lockid = lck->lockid = ++_lockid;
|
||||
lck->mode = mode;
|
||||
dm_list_add(head, &lck->list);
|
||||
}
|
||||
out:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Locked resource %s, lockid=%d, mode=%s\n",
|
||||
resource, lck->lockid, _get_mode(lck->mode));
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Failed to lock resource %s\n", resource);
|
||||
|
||||
return 1; /* fail */
|
||||
}
|
||||
|
||||
static int _unlock_resource(const char *resource, int lockid)
|
||||
{
|
||||
struct lock *lck;
|
||||
struct dm_list *head;
|
||||
int r = 1;
|
||||
|
||||
if (lockid < 0) {
|
||||
DEBUGLOG("Not tracking unlock of lockid -1: %s, lockid=%d\n",
|
||||
resource, lockid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUGLOG("Unlocking resource %s, lockid=%d\n", resource, lockid);
|
||||
pthread_mutex_lock(&_lock_mutex);
|
||||
pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
|
||||
|
||||
if (!(head = dm_hash_lookup(_locks, resource))) {
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Resource %s is not locked.\n", resource);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(lck, head)
|
||||
if (lck->lockid == lockid) {
|
||||
dm_list_del(&lck->list);
|
||||
dm_free(lck);
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUGLOG("Resource %s has wrong lockid %d.\n", resource, lockid);
|
||||
out:
|
||||
if (dm_list_empty(head)) {
|
||||
//DEBUGLOG("Resource %s is no longer hashed (lockid=%d).\n", resource, lockid);
|
||||
dm_hash_remove(_locks, resource);
|
||||
dm_free(head);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _is_quorate(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
return listen_fd;
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _cluster_send_message(const void *buf, int msglen,
|
||||
const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
return dm_strncpy(buf, "localcluster", buflen) ? 0 : 1;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_singlenode_ops = {
|
||||
.name = "singlenode",
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.reread_config = NULL,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _lock_resource,
|
||||
.sync_unlock = _unlock_resource,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_singlenode_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_singlenode_ops;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _CLVMD_H
|
||||
#define _CLVMD_H
|
||||
|
||||
#define CLVMD_MAJOR_VERSION 0
|
||||
#define CLVMD_MINOR_VERSION 2
|
||||
#define CLVMD_PATCH_VERSION 1
|
||||
|
||||
/* Default time (in seconds) we will wait for all remote commands to execute
|
||||
before declaring them dead */
|
||||
#define DEFAULT_CMD_TIMEOUT 60
|
||||
|
||||
/* One of these for each reply we get from command execution on a node */
|
||||
struct node_reply {
|
||||
char node[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
char *replymsg;
|
||||
int status;
|
||||
struct node_reply *next;
|
||||
};
|
||||
|
||||
typedef enum {DEBUG_OFF, DEBUG_STDERR, DEBUG_SYSLOG} debug_t;
|
||||
|
||||
/*
|
||||
* These exist for the use of local sockets only when we are
|
||||
* collecting responses from all cluster nodes
|
||||
*/
|
||||
struct localsock_bits {
|
||||
struct node_reply *replies;
|
||||
int num_replies;
|
||||
int expected_replies;
|
||||
time_t sent_time; /* So we can check for timeouts */
|
||||
int in_progress; /* Only execute one cmd at a time per client */
|
||||
int sent_out; /* Flag to indicate that a command was sent
|
||||
to remote nodes */
|
||||
void *private; /* Private area for command processor use */
|
||||
void *cmd; /* Whole command as passed down local socket */
|
||||
int cmd_len; /* Length of above */
|
||||
int pipe; /* Pipe to send PRE completion status down */
|
||||
int finished; /* Flag to tell subthread to exit */
|
||||
int all_success; /* Set to 0 if any node (or the pre_command)
|
||||
failed */
|
||||
int cleanup_needed; /* helper for cleanup_zombie */
|
||||
struct local_client *pipe_client;
|
||||
pthread_t threadid;
|
||||
enum { PRE_COMMAND, POST_COMMAND } state;
|
||||
pthread_mutex_t mutex; /* Main thread and worker synchronisation */
|
||||
pthread_cond_t cond;
|
||||
};
|
||||
|
||||
/* Entries for PIPE clients */
|
||||
struct pipe_bits {
|
||||
struct local_client *client; /* Actual (localsock) client */
|
||||
pthread_t threadid; /* Our own copy of the thread id */
|
||||
};
|
||||
|
||||
/* Entries for Network socket clients */
|
||||
struct netsock_bits {
|
||||
void *private;
|
||||
int flags;
|
||||
};
|
||||
|
||||
typedef int (*fd_callback_t) (struct local_client * fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client ** new_client);
|
||||
|
||||
/* One of these for each fd we are listening on */
|
||||
struct local_client {
|
||||
int fd;
|
||||
enum { CLUSTER_MAIN_SOCK, CLUSTER_DATA_SOCK, LOCAL_RENDEZVOUS,
|
||||
LOCAL_SOCK, THREAD_PIPE, CLUSTER_INTERNAL } type;
|
||||
struct local_client *next;
|
||||
unsigned short xid;
|
||||
fd_callback_t callback;
|
||||
uint8_t removeme;
|
||||
|
||||
union {
|
||||
struct localsock_bits localsock;
|
||||
struct pipe_bits pipe;
|
||||
struct netsock_bits net;
|
||||
} bits;
|
||||
};
|
||||
|
||||
#define DEBUGLOG(fmt, args...) debuglog(fmt, ## args)
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
/* The real command processor is in clvmd-command.c */
|
||||
extern int do_command(struct local_client *client, struct clvm_header *msg,
|
||||
int msglen, char **buf, int buflen, int *retlen);
|
||||
|
||||
/* Pre and post command routines are called only on the local node */
|
||||
extern int do_pre_command(struct local_client *client);
|
||||
extern int do_post_command(struct local_client *client);
|
||||
extern void cmd_client_cleanup(struct local_client *client);
|
||||
extern int add_client(struct local_client *new_client);
|
||||
|
||||
extern void clvmd_cluster_init_completed(void);
|
||||
extern void process_message(struct local_client *client, char *buf,
|
||||
int len, const char *csid);
|
||||
extern void debuglog(const char *fmt, ... )
|
||||
__attribute__ ((format(printf, 1, 2)));
|
||||
|
||||
void clvmd_set_debug(debug_t new_de);
|
||||
debug_t clvmd_get_debug(void);
|
||||
int clvmd_get_foreground(void);
|
||||
|
||||
int sync_lock(const char *resource, int mode, int flags, int *lockid);
|
||||
int sync_unlock(const char *resource, int lockid);
|
||||
|
||||
#endif
|
||||
@@ -1,927 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
/* LVM2 headers */
|
||||
#include "toolcontext.h"
|
||||
#include "lvmcache.h"
|
||||
#include "lvm-globals.h"
|
||||
#include "activate.h"
|
||||
#include "archiver.h"
|
||||
#include "memlock.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
static struct cmd_context *cmd = NULL;
|
||||
static struct dm_hash_table *lv_hash = NULL;
|
||||
static pthread_mutex_t lv_hash_lock;
|
||||
static pthread_mutex_t lvm_lock;
|
||||
static char last_error[1024];
|
||||
|
||||
struct lv_info {
|
||||
int lock_id;
|
||||
int lock_mode;
|
||||
};
|
||||
|
||||
static const char *decode_full_locking_cmd(uint32_t cmdl)
|
||||
{
|
||||
static char buf[128];
|
||||
const char *type;
|
||||
const char *scope;
|
||||
const char *command;
|
||||
|
||||
switch (cmdl & LCK_TYPE_MASK) {
|
||||
case LCK_NULL:
|
||||
type = "NULL";
|
||||
break;
|
||||
case LCK_READ:
|
||||
type = "READ";
|
||||
break;
|
||||
case LCK_PREAD:
|
||||
type = "PREAD";
|
||||
break;
|
||||
case LCK_WRITE:
|
||||
type = "WRITE";
|
||||
break;
|
||||
case LCK_EXCL:
|
||||
type = "EXCL";
|
||||
break;
|
||||
case LCK_UNLOCK:
|
||||
type = "UNLOCK";
|
||||
break;
|
||||
default:
|
||||
type = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cmdl & LCK_SCOPE_MASK) {
|
||||
case LCK_VG:
|
||||
scope = "VG";
|
||||
command = "LCK_VG";
|
||||
break;
|
||||
case LCK_LV:
|
||||
scope = "LV";
|
||||
switch (cmdl & LCK_MASK) {
|
||||
case LCK_LV_EXCLUSIVE & LCK_MASK:
|
||||
command = "LCK_LV_EXCLUSIVE";
|
||||
break;
|
||||
case LCK_LV_SUSPEND & LCK_MASK:
|
||||
command = "LCK_LV_SUSPEND";
|
||||
break;
|
||||
case LCK_LV_RESUME & LCK_MASK:
|
||||
command = "LCK_LV_RESUME";
|
||||
break;
|
||||
case LCK_LV_ACTIVATE & LCK_MASK:
|
||||
command = "LCK_LV_ACTIVATE";
|
||||
break;
|
||||
case LCK_LV_DEACTIVATE & LCK_MASK:
|
||||
command = "LCK_LV_DEACTIVATE";
|
||||
break;
|
||||
default:
|
||||
command = "unknown";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
scope = "unknown";
|
||||
command = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(buf, "0x%x %s (%s|%s%s%s%s%s)", cmdl, command, type, scope,
|
||||
cmdl & LCK_NONBLOCK ? "|NONBLOCK" : "",
|
||||
cmdl & LCK_HOLD ? "|HOLD" : "",
|
||||
cmdl & LCK_CLUSTER_VG ? "|CLUSTER_VG" : "",
|
||||
cmdl & LCK_CACHE ? "|CACHE" : "");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only processes 8 bits: excludes LCK_CACHE.
|
||||
*/
|
||||
static const char *decode_locking_cmd(unsigned char cmdl)
|
||||
{
|
||||
return decode_full_locking_cmd((uint32_t) cmdl);
|
||||
}
|
||||
|
||||
static const char *decode_flags(unsigned char flags)
|
||||
{
|
||||
static char buf[128];
|
||||
int len;
|
||||
|
||||
len = sprintf(buf, "0x%x ( %s%s%s%s%s%s%s%s)", flags,
|
||||
flags & LCK_PARTIAL_MODE ? "PARTIAL_MODE|" : "",
|
||||
flags & LCK_MIRROR_NOSYNC_MODE ? "MIRROR_NOSYNC|" : "",
|
||||
flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "",
|
||||
flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "",
|
||||
flags & LCK_TEST_MODE ? "TEST|" : "",
|
||||
flags & LCK_CONVERT_MODE ? "CONVERT|" : "",
|
||||
flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : "",
|
||||
flags & LCK_REVERT_MODE ? "REVERT|" : "");
|
||||
|
||||
if (len > 1)
|
||||
buf[len - 2] = ' ';
|
||||
else
|
||||
buf[0] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *get_last_lvm_error(void)
|
||||
{
|
||||
return last_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash lock info helpers
|
||||
*/
|
||||
static struct lv_info *lookup_info(const char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
lvi = dm_hash_lookup(lv_hash, resource);
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
|
||||
return lvi;
|
||||
}
|
||||
|
||||
static int insert_info(const char *resource, struct lv_info *lvi)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
ret = dm_hash_insert(lv_hash, resource, lvi);
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void remove_info(const char *resource)
|
||||
{
|
||||
int num_open;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
dm_hash_remove(lv_hash, resource);
|
||||
|
||||
/* When last lock is remove, validate there are not left opened devices */
|
||||
if (!dm_hash_get_first(lv_hash)) {
|
||||
if (critical_section())
|
||||
log_error(INTERNAL_ERROR "No volumes are locked however clvmd is in activation mode critical section.");
|
||||
if ((num_open = dev_cache_check_for_open_devices()))
|
||||
log_error(INTERNAL_ERROR "No volumes are locked however %d devices are still open.", num_open);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the mode a lock is currently held at (or -1 if not held)
|
||||
*/
|
||||
static int get_current_lock(char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
|
||||
if ((lvi = lookup_info(resource)))
|
||||
return lvi->lock_mode;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void init_lvhash(void)
|
||||
{
|
||||
/* Create hash table for keeping LV locks & status */
|
||||
lv_hash = dm_hash_create(1024);
|
||||
pthread_mutex_init(&lv_hash_lock, NULL);
|
||||
pthread_mutex_init(&lvm_lock, NULL);
|
||||
}
|
||||
|
||||
/* Called at shutdown to tidy the lockspace */
|
||||
void destroy_lvhash(void)
|
||||
{
|
||||
struct dm_hash_node *v;
|
||||
struct lv_info *lvi;
|
||||
char *resource;
|
||||
int status;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
|
||||
dm_hash_iterate(v, lv_hash) {
|
||||
lvi = dm_hash_get_data(lv_hash, v);
|
||||
resource = dm_hash_get_key(lv_hash, v);
|
||||
|
||||
if ((status = sync_unlock(resource, lvi->lock_id)))
|
||||
DEBUGLOG("unlock_all. unlock failed(%d): %s\n",
|
||||
status, strerror(errno));
|
||||
dm_free(lvi);
|
||||
}
|
||||
|
||||
dm_hash_destroy(lv_hash);
|
||||
lv_hash = NULL;
|
||||
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
}
|
||||
|
||||
/* Gets a real lock and keeps the info in the hash table */
|
||||
static int hold_lock(char *resource, int mode, int flags)
|
||||
{
|
||||
int status;
|
||||
int saved_errno;
|
||||
struct lv_info *lvi;
|
||||
|
||||
/* Mask off invalid options */
|
||||
flags &= LCKF_NOQUEUE | LCKF_CONVERT;
|
||||
|
||||
lvi = lookup_info(resource);
|
||||
|
||||
if (lvi) {
|
||||
if (lvi->lock_mode == mode) {
|
||||
DEBUGLOG("hold_lock, lock mode %d already held\n",
|
||||
mode);
|
||||
return 0;
|
||||
}
|
||||
if ((lvi->lock_mode == LCK_EXCL) && (mode == LCK_WRITE)) {
|
||||
DEBUGLOG("hold_lock, lock already held LCK_EXCL, "
|
||||
"ignoring LCK_WRITE request\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only allow explicit conversions */
|
||||
if (lvi && !(flags & LCKF_CONVERT)) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
if (lvi) {
|
||||
/* Already exists - convert it */
|
||||
status = sync_lock(resource, mode, flags, &lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (!status)
|
||||
lvi->lock_mode = mode;
|
||||
else
|
||||
DEBUGLOG("hold_lock. convert to %d failed: %s\n", mode,
|
||||
strerror(errno));
|
||||
errno = saved_errno;
|
||||
} else {
|
||||
if (!(lvi = dm_malloc(sizeof(struct lv_info)))) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
lvi->lock_mode = mode;
|
||||
lvi->lock_id = 0;
|
||||
status = sync_lock(resource, mode, flags & ~LCKF_CONVERT, &lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (status) {
|
||||
dm_free(lvi);
|
||||
DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode,
|
||||
strerror(errno));
|
||||
} else
|
||||
if (!insert_info(resource, lvi)) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Unlock and remove it from the hash table */
|
||||
static int hold_unlock(char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
int status;
|
||||
int saved_errno;
|
||||
|
||||
if (!(lvi = lookup_info(resource))) {
|
||||
DEBUGLOG("hold_unlock, lock not already held\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = sync_unlock(resource, lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (!status) {
|
||||
remove_info(resource);
|
||||
dm_free(lvi);
|
||||
} else {
|
||||
DEBUGLOG("hold_unlock. unlock failed(%d): %s\n", status,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Watch the return codes here.
|
||||
liblvm API functions return 1(true) for success, 0(false) for failure and don't set errno.
|
||||
libdlm API functions return 0 for success, -1 for failure and do set errno.
|
||||
These functions here return 0 for success or >0 for failure (where the retcode is errno)
|
||||
*/
|
||||
|
||||
/* Activate LV exclusive or non-exclusive */
|
||||
static int do_activate_lv(char *resource, unsigned char command, unsigned char lock_flags, int mode)
|
||||
{
|
||||
int oldmode;
|
||||
int status;
|
||||
int activate_lv;
|
||||
int exclusive = 0;
|
||||
struct lvinfo lvi;
|
||||
|
||||
/* Is it already open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == mode && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_activate_lv, lock already held at %d\n", oldmode);
|
||||
return 0; /* Nothing to do */
|
||||
}
|
||||
|
||||
/* Does the config file want us to activate this LV ? */
|
||||
if (!lv_activation_filter(cmd, resource, &activate_lv, NULL))
|
||||
return EIO;
|
||||
|
||||
if (!activate_lv)
|
||||
return 0; /* Success, we did nothing! */
|
||||
|
||||
/* Do we need to activate exclusively? */
|
||||
if ((activate_lv == 2) || (mode == LCK_EXCL)) {
|
||||
exclusive = 1;
|
||||
mode = LCK_EXCL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to get the lock if it's a clustered volume group.
|
||||
* Use lock conversion only if requested, to prevent implicit conversion
|
||||
* of exclusive lock to shared one during activation.
|
||||
*/
|
||||
if (!test_mode() && command & LCK_CLUSTER_VG) {
|
||||
status = hold_lock(resource, mode, LCKF_NOQUEUE | ((lock_flags & LCK_CONVERT_MODE) ? LCKF_CONVERT:0));
|
||||
if (status) {
|
||||
/* Return an LVM-sensible error for this.
|
||||
* Forcing EIO makes the upper level return this text
|
||||
* rather than the strerror text for EAGAIN.
|
||||
*/
|
||||
if (errno == EAGAIN) {
|
||||
sprintf(last_error, "Volume is busy on another node");
|
||||
errno = EIO;
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
/* If it's suspended then resume it */
|
||||
if (!lv_info_by_lvid(cmd, resource, 0, &lvi, 0, 0))
|
||||
goto error;
|
||||
|
||||
if (lvi.suspended) {
|
||||
critical_section_inc(cmd, "resuming");
|
||||
if (!lv_resume(cmd, resource, 0, NULL)) {
|
||||
critical_section_dec(cmd, "resumed");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now activate it */
|
||||
if (!lv_activate(cmd, resource, exclusive, 0, 0, NULL))
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (!test_mode() && (oldmode == -1 || oldmode != mode))
|
||||
(void)hold_unlock(resource);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
/* Resume the LV if it was active */
|
||||
static int do_resume_lv(char *resource, unsigned char command, unsigned char lock_flags)
|
||||
{
|
||||
int oldmode, origin_only, exclusive, revert;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_resume_lv, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
|
||||
exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
|
||||
revert = (lock_flags & LCK_REVERT_MODE) ? 1 : 0;
|
||||
|
||||
if (!lv_resume_if_active(cmd, resource, origin_only, exclusive, revert, NULL))
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Suspend the device if active */
|
||||
static int do_suspend_lv(char *resource, unsigned char command, unsigned char lock_flags)
|
||||
{
|
||||
int oldmode;
|
||||
unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
|
||||
unsigned exclusive;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_suspend_lv, lock not already held\n");
|
||||
return 0; /* Not active, so it's OK */
|
||||
}
|
||||
|
||||
exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
|
||||
|
||||
/* Always call lv_suspend to read commited and precommited data */
|
||||
if (!lv_suspend_if_active(cmd, resource, origin_only, exclusive, NULL, NULL))
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_deactivate_lv(char *resource, unsigned char command, unsigned char lock_flags)
|
||||
{
|
||||
int oldmode;
|
||||
int status;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_deactivate_lock, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
|
||||
if (!lv_deactivate(cmd, resource, NULL))
|
||||
return EIO;
|
||||
|
||||
if (!test_mode() && command & LCK_CLUSTER_VG) {
|
||||
status = hold_unlock(resource);
|
||||
if (status)
|
||||
return errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *do_lock_query(char *resource)
|
||||
{
|
||||
int mode;
|
||||
const char *type;
|
||||
|
||||
mode = get_current_lock(resource);
|
||||
switch (mode) {
|
||||
case LCK_NULL: type = "NL"; break;
|
||||
case LCK_READ: type = "CR"; break;
|
||||
case LCK_PREAD:type = "PR"; break;
|
||||
case LCK_WRITE:type = "PW"; break;
|
||||
case LCK_EXCL: type = "EX"; break;
|
||||
default: type = NULL;
|
||||
}
|
||||
|
||||
DEBUGLOG("do_lock_query: resource '%s', mode %i (%s)\n", resource, mode, type ?: "--");
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* This is the LOCK_LV part that happens on all nodes in the cluster -
|
||||
it is responsible for the interaction with device-mapper and LVM */
|
||||
int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
|
||||
resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section());
|
||||
|
||||
if (!cmd->initialized.config || config_files_changed(cmd)) {
|
||||
/* Reinitialise various settings inc. logging, filters */
|
||||
if (do_refresh_cache()) {
|
||||
log_error("Updated config file invalid. Aborting.");
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0);
|
||||
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(1);
|
||||
|
||||
if (lock_flags & LCK_DMEVENTD_MONITOR_IGNORE)
|
||||
init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
|
||||
else {
|
||||
if (lock_flags & LCK_DMEVENTD_MONITOR_MODE)
|
||||
init_dmeventd_monitor(1);
|
||||
else
|
||||
init_dmeventd_monitor(0);
|
||||
}
|
||||
|
||||
cmd->partial_activation = (lock_flags & LCK_PARTIAL_MODE) ? 1 : 0;
|
||||
|
||||
/* clvmd should never try to read suspended device */
|
||||
init_ignore_suspended_devices(1);
|
||||
|
||||
switch (command & LCK_MASK) {
|
||||
case LCK_LV_EXCLUSIVE:
|
||||
status = do_activate_lv(resource, command, lock_flags, LCK_EXCL);
|
||||
break;
|
||||
|
||||
case LCK_LV_SUSPEND:
|
||||
status = do_suspend_lv(resource, command, lock_flags);
|
||||
break;
|
||||
|
||||
case LCK_UNLOCK:
|
||||
case LCK_LV_RESUME: /* if active */
|
||||
status = do_resume_lv(resource, command, lock_flags);
|
||||
break;
|
||||
|
||||
case LCK_LV_ACTIVATE:
|
||||
status = do_activate_lv(resource, command, lock_flags, LCK_READ);
|
||||
break;
|
||||
|
||||
case LCK_LV_DEACTIVATE:
|
||||
status = do_deactivate_lv(resource, command, lock_flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUGLOG("Invalid LV command 0x%x\n", command);
|
||||
status = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(0);
|
||||
|
||||
cmd->partial_activation = 0;
|
||||
|
||||
/* clean the pool for another command */
|
||||
dm_pool_empty(cmd->mem);
|
||||
init_test(0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
|
||||
DEBUGLOG("Command return is %d, critical_section is %d\n", status, critical_section());
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Functions to do on the local node only BEFORE the cluster-wide stuff above happens */
|
||||
int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
{
|
||||
/* Nearly all the stuff happens cluster-wide. Apart from SUSPEND. Here we get the
|
||||
lock out on this node (because we are the node modifying the metadata)
|
||||
before suspending cluster-wide.
|
||||
LCKF_CONVERT is used always, local node is going to modify metadata
|
||||
*/
|
||||
if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_SUSPEND &&
|
||||
(command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("pre_lock_lv: resource '%s', cmd = %s, flags = %s\n",
|
||||
resource, decode_locking_cmd(command), decode_flags(lock_flags));
|
||||
|
||||
if (!(lock_flags & LCK_TEST_MODE) &&
|
||||
hold_lock(resource, LCK_WRITE, LCKF_NOQUEUE | LCKF_CONVERT))
|
||||
return errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Functions to do on the local node only AFTER the cluster-wide stuff above happens */
|
||||
int post_lock_lv(unsigned char command, unsigned char lock_flags,
|
||||
char *resource)
|
||||
{
|
||||
int status;
|
||||
unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
|
||||
|
||||
/* Opposite of above, done on resume after a metadata update */
|
||||
if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_RESUME &&
|
||||
(command & LCK_CLUSTER_VG)) {
|
||||
int oldmode;
|
||||
|
||||
DEBUGLOG("post_lock_lv: resource '%s', cmd = %s, flags = %s\n",
|
||||
resource, decode_locking_cmd(command), decode_flags(lock_flags));
|
||||
|
||||
/* If the lock state is PW then restore it to what it was */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == LCK_WRITE) {
|
||||
struct lvinfo lvi;
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
status = lv_info_by_lvid(cmd, resource, origin_only, &lvi, 0, 0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
if (!status)
|
||||
return EIO;
|
||||
|
||||
if (!(lock_flags & LCK_TEST_MODE)) {
|
||||
if (lvi.exists) {
|
||||
if (hold_lock(resource, LCK_READ, LCKF_CONVERT))
|
||||
return errno;
|
||||
} else if (hold_unlock(resource))
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_refresh_cache(void)
|
||||
{
|
||||
DEBUGLOG("Refreshing context\n");
|
||||
log_notice("Refreshing context");
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
|
||||
if (!refresh_toolcontext(cmd)) {
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
init_ignore_suspended_devices(1);
|
||||
lvmcache_label_scan(cmd);
|
||||
label_scan_destroy(cmd); /* destroys bcache (to close devs), keeps lvmcache */
|
||||
dm_pool_empty(cmd->mem);
|
||||
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle VG lock - drop metadata or update lvmcache state
|
||||
*/
|
||||
void do_lock_vg(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
{
|
||||
uint32_t lock_cmd = command;
|
||||
char *vgname = resource + 2;
|
||||
|
||||
lock_cmd &= (LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_HOLD);
|
||||
|
||||
/*
|
||||
* Check if LCK_CACHE should be set. All P_ locks except # are cache related.
|
||||
*/
|
||||
if (strncmp(resource, "P_#", 3) && !strncmp(resource, "P_", 2))
|
||||
lock_cmd |= LCK_CACHE;
|
||||
|
||||
DEBUGLOG("do_lock_vg: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
|
||||
resource, decode_full_locking_cmd(lock_cmd), decode_flags(lock_flags), critical_section());
|
||||
|
||||
/* P_#global causes a full cache refresh */
|
||||
if (!strcmp(resource, "P_" VG_GLOBAL)) {
|
||||
do_refresh_cache();
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0);
|
||||
|
||||
switch (lock_cmd) {
|
||||
case LCK_VG_COMMIT:
|
||||
DEBUGLOG("vg_commit notification for VG %s\n", vgname);
|
||||
lvmcache_commit_metadata(vgname);
|
||||
break;
|
||||
case LCK_VG_REVERT:
|
||||
DEBUGLOG("vg_revert notification for VG %s\n", vgname);
|
||||
lvmcache_drop_metadata(vgname, 1);
|
||||
break;
|
||||
case LCK_VG_DROP_CACHE:
|
||||
default:
|
||||
DEBUGLOG("Invalidating cached metadata for VG %s\n", vgname);
|
||||
lvmcache_drop_metadata(vgname, 0);
|
||||
}
|
||||
|
||||
init_test(0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally, clvmd should be started before any LVs are active
|
||||
* but this may not be the case...
|
||||
* I suppose this also comes in handy if clvmd crashes, not that it would!
|
||||
*/
|
||||
static int get_initial_state(struct dm_hash_table *excl_uuid)
|
||||
{
|
||||
int lock_mode;
|
||||
char lv[65], vg[65], flags[26], vg_flags[26]; /* with space for '\0' */
|
||||
char uuid[65];
|
||||
char line[255];
|
||||
char *lvs_cmd;
|
||||
const char *lvm_binary = getenv("LVM_BINARY") ? : LVM_PATH;
|
||||
FILE *lvs;
|
||||
|
||||
if (dm_asprintf(&lvs_cmd, "%s lvs --config 'log{command_names=0 prefix=\"\"}' "
|
||||
"--nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr",
|
||||
lvm_binary) < 0)
|
||||
return_0;
|
||||
|
||||
/* FIXME: Maybe link and use liblvm2cmd directly instead of fork */
|
||||
if (!(lvs = popen(lvs_cmd, "r"))) {
|
||||
dm_free(lvs_cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), lvs)) {
|
||||
if (sscanf(line, "%64s %64s %25s %25s\n", vg, lv, flags, vg_flags) == 4) {
|
||||
|
||||
/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
|
||||
if (strlen(vg) == 38 && /* is is a valid UUID ? */
|
||||
(flags[4] == 'a' || flags[4] == 's') && /* is it active or suspended? */
|
||||
vg_flags[5] == 'c') { /* is it clustered ? */
|
||||
/* Convert hyphen-separated UUIDs into one */
|
||||
memcpy(&uuid[0], &vg[0], 6);
|
||||
memcpy(&uuid[6], &vg[7], 4);
|
||||
memcpy(&uuid[10], &vg[12], 4);
|
||||
memcpy(&uuid[14], &vg[17], 4);
|
||||
memcpy(&uuid[18], &vg[22], 4);
|
||||
memcpy(&uuid[22], &vg[27], 4);
|
||||
memcpy(&uuid[26], &vg[32], 6);
|
||||
memcpy(&uuid[32], &lv[0], 6);
|
||||
memcpy(&uuid[38], &lv[7], 4);
|
||||
memcpy(&uuid[42], &lv[12], 4);
|
||||
memcpy(&uuid[46], &lv[17], 4);
|
||||
memcpy(&uuid[50], &lv[22], 4);
|
||||
memcpy(&uuid[54], &lv[27], 4);
|
||||
memcpy(&uuid[58], &lv[32], 6);
|
||||
uuid[64] = '\0';
|
||||
|
||||
/* Look for this lock in the list of EX locks
|
||||
we were passed on the command-line */
|
||||
lock_mode = (dm_hash_lookup(excl_uuid, uuid)) ?
|
||||
LCK_EXCL : LCK_READ;
|
||||
|
||||
DEBUGLOG("getting initial lock for %s\n", uuid);
|
||||
if (hold_lock(uuid, lock_mode, LCKF_NOQUEUE))
|
||||
DEBUGLOG("Failed to hold lock %s\n", uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pclose(lvs))
|
||||
DEBUGLOG("lvs pclose failed: %s\n", strerror(errno));
|
||||
|
||||
dm_free(lvs_cmd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void lvm2_log_fn(int level, const char *file, int line, int dm_errno,
|
||||
const char *message)
|
||||
{
|
||||
|
||||
/* Send messages to the normal LVM2 logging system too,
|
||||
so we get debug output when it's asked for.
|
||||
We need to NULL the function ptr otherwise it will just call
|
||||
back into here! */
|
||||
init_log_fn(NULL);
|
||||
print_log(level, file, line, dm_errno, "%s", message);
|
||||
init_log_fn(lvm2_log_fn);
|
||||
|
||||
/*
|
||||
* Ignore non-error messages, but store the latest one for returning
|
||||
* to the user.
|
||||
*/
|
||||
if (level != _LOG_ERR && level != _LOG_FATAL)
|
||||
return;
|
||||
|
||||
(void) dm_strncpy(last_error, message, sizeof(last_error));
|
||||
}
|
||||
|
||||
/* This checks some basic cluster-LVM configuration stuff */
|
||||
static void check_config(void)
|
||||
{
|
||||
int locking_type;
|
||||
|
||||
locking_type = find_config_tree_int(cmd, global_locking_type_CFG, NULL);
|
||||
|
||||
if (locking_type == 3) /* compiled-in cluster support */
|
||||
return;
|
||||
|
||||
if (locking_type == 2) { /* External library, check name */
|
||||
const char *libname;
|
||||
|
||||
libname = find_config_tree_str(cmd, global_locking_library_CFG, NULL);
|
||||
if (libname && strstr(libname, "liblvm2clusterlock.so"))
|
||||
return;
|
||||
|
||||
log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work.");
|
||||
return;
|
||||
}
|
||||
log_error("locking_type not set correctly in lvm.conf, cluster operations will not work.");
|
||||
}
|
||||
|
||||
/* Backups up the LVM metadata if it's changed */
|
||||
void lvm_do_backup(const char *vgname)
|
||||
{
|
||||
struct volume_group * vg;
|
||||
int consistent = 0;
|
||||
|
||||
DEBUGLOG("Triggering backup of VG metadata for %s.\n", vgname);
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
|
||||
vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, 0, 0, WARN_PV_READ, &consistent);
|
||||
|
||||
if (vg && consistent)
|
||||
check_current_backup(vg);
|
||||
else
|
||||
log_error("Error backing up metadata, can't find VG for group %s", vgname);
|
||||
|
||||
release_vg(vg);
|
||||
dm_pool_empty(cmd->mem);
|
||||
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
}
|
||||
|
||||
struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
|
||||
*name = NULL;
|
||||
if (!v)
|
||||
v = dm_hash_get_first(lv_hash);
|
||||
|
||||
do {
|
||||
if (v) {
|
||||
lvi = dm_hash_get_data(lv_hash, v);
|
||||
DEBUGLOG("Looking for EX locks. found %x mode %d\n", lvi->lock_id, lvi->lock_mode);
|
||||
|
||||
if (lvi->lock_mode == LCK_EXCL) {
|
||||
*name = dm_hash_get_key(lv_hash, v);
|
||||
}
|
||||
v = dm_hash_get_next(lv_hash, v);
|
||||
}
|
||||
} while (v && !*name);
|
||||
|
||||
if (*name)
|
||||
DEBUGLOG("returning EXclusive UUID %s\n", *name);
|
||||
return v;
|
||||
}
|
||||
|
||||
void lvm_do_fs_unlock(void)
|
||||
{
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
DEBUGLOG("Syncing device names\n");
|
||||
fs_unlock();
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
}
|
||||
|
||||
/* Called to initialise the LVM context of the daemon */
|
||||
int init_clvm(struct dm_hash_table *excl_uuid)
|
||||
{
|
||||
/* Use LOG_DAEMON for syslog messages instead of LOG_USER */
|
||||
init_syslog(LOG_DAEMON);
|
||||
openlog("clvmd", LOG_PID, LOG_DAEMON);
|
||||
|
||||
/* Initialise already held locks */
|
||||
if (!get_initial_state(excl_uuid))
|
||||
log_error("Cannot load initial lock states.");
|
||||
|
||||
if (!udev_init_library_context())
|
||||
stack;
|
||||
|
||||
if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
|
||||
log_error("Failed to allocate command context");
|
||||
udev_fin_library_context();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stored_errno()) {
|
||||
destroy_toolcontext(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd->cmd_line = "clvmd";
|
||||
|
||||
/* Check lvm.conf is setup for cluster-LVM */
|
||||
check_config();
|
||||
init_ignore_suspended_devices(1);
|
||||
|
||||
/* Trap log messages so we can pass them back to the user */
|
||||
init_log_fn(lvm2_log_fn);
|
||||
memlock_inc_daemon(cmd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void destroy_lvm(void)
|
||||
{
|
||||
if (cmd) {
|
||||
memlock_dec_daemon(cmd);
|
||||
destroy_toolcontext(cmd);
|
||||
udev_fin_library_context();
|
||||
cmd = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Functions in lvm-functions.c */
|
||||
|
||||
#ifndef _LVM_FUNCTIONS_H
|
||||
#define _LVM_FUNCTIONS_H
|
||||
|
||||
extern int pre_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern const char *do_lock_query(char *resource);
|
||||
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_refresh_cache(void);
|
||||
extern int init_clvm(struct dm_hash_table *excl_uuid);
|
||||
extern void destroy_lvm(void);
|
||||
extern void init_lvhash(void);
|
||||
extern void destroy_lvhash(void);
|
||||
extern void lvm_do_backup(const char *vgname);
|
||||
extern char *get_last_lvm_error(void);
|
||||
extern void do_lock_vg(unsigned char command, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name);
|
||||
void lvm_do_fs_unlock(void);
|
||||
|
||||
#endif
|
||||
@@ -1,382 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* FIXME Remove duplicated functions from this file. */
|
||||
|
||||
/*
|
||||
* Send a command to a running clvmd from the command-line
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include "clvm.h"
|
||||
#include "refresh_clvmd.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
typedef struct lvm_response {
|
||||
char node[255];
|
||||
char *response;
|
||||
int status;
|
||||
int len;
|
||||
} lvm_response_t;
|
||||
|
||||
/*
|
||||
* This gets stuck at the start of memory we allocate so we
|
||||
* can sanity-check it at deallocation time
|
||||
*/
|
||||
#define LVM_SIGNATURE 0x434C564D
|
||||
|
||||
static int _clvmd_sock = -1;
|
||||
|
||||
/* Open connection to the clvm daemon */
|
||||
static int _open_local_sock(void)
|
||||
{
|
||||
int local_socket;
|
||||
struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
|
||||
|
||||
if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
|
||||
fprintf(stderr, "%s: clvmd socket name too long.", CLVMD_SOCKNAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open local socket */
|
||||
if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
fprintf(stderr, "Local socket creation failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(local_socket,(struct sockaddr *) &sockaddr,
|
||||
sizeof(sockaddr))) {
|
||||
int saved_errno = errno;
|
||||
|
||||
fprintf(stderr, "connect() failed on local socket: %s\n",
|
||||
strerror(errno));
|
||||
if (close(local_socket))
|
||||
return -1;
|
||||
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
/* Send a request and return the status */
|
||||
static int _send_request(const char *inbuf, int inlen, char **retbuf, int no_response)
|
||||
{
|
||||
char outbuf[PIPE_BUF];
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
unsigned off;
|
||||
int buflen;
|
||||
int err;
|
||||
|
||||
/* Send it to CLVMD */
|
||||
rewrite:
|
||||
if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
|
||||
if (err == -1 && errno == EINTR)
|
||||
goto rewrite;
|
||||
fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (no_response)
|
||||
return 1;
|
||||
|
||||
/* Get the response */
|
||||
reread:
|
||||
if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
|
||||
if (errno == EINTR)
|
||||
goto reread;
|
||||
fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "EOF reading CLVMD");
|
||||
errno = ENOTCONN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
buflen = len + outheader->arglen;
|
||||
*retbuf = dm_malloc(buflen);
|
||||
if (!*retbuf) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the header */
|
||||
memcpy(*retbuf, outbuf, len);
|
||||
outheader = (struct clvm_header *) *retbuf;
|
||||
|
||||
/* Read the returned values */
|
||||
off = 1; /* we've already read the first byte */
|
||||
while (off <= outheader->arglen && len > 0) {
|
||||
len = read(_clvmd_sock, outheader->args + off,
|
||||
buflen - off - offsetof(struct clvm_header, args));
|
||||
if (len > 0)
|
||||
off += len;
|
||||
}
|
||||
|
||||
/* Was it an error ? */
|
||||
if (outheader->status != 0) {
|
||||
errno = outheader->status;
|
||||
|
||||
/* Only return an error here if there are no node-specific
|
||||
errors present in the message that might have more detail */
|
||||
if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
|
||||
fprintf(stderr, "cluster request failed: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Build the structure header and parse-out wildcard node names */
|
||||
static void _build_header(struct clvm_header *head, int cmd, const char *node,
|
||||
unsigned int len)
|
||||
{
|
||||
head->cmd = cmd;
|
||||
head->status = 0;
|
||||
head->flags = 0;
|
||||
head->xid = 0;
|
||||
head->clientid = 0;
|
||||
if (len)
|
||||
/* 1 byte is used from struct clvm_header.args[1], so -> len - 1 */
|
||||
head->arglen = len - 1;
|
||||
else {
|
||||
head->arglen = 0;
|
||||
*head->args = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate special node names.
|
||||
*/
|
||||
if (!node || !strcmp(node, NODE_ALL))
|
||||
head->node[0] = '\0';
|
||||
else if (!strcmp(node, NODE_LOCAL)) {
|
||||
head->node[0] = '\0';
|
||||
head->flags = CLVMD_FLAG_LOCAL;
|
||||
} else
|
||||
strcpy(head->node, node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a message to a(or all) node(s) in the cluster and wait for replies
|
||||
*/
|
||||
static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num, int no_response)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
char *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
int i;
|
||||
int num_responses = 0;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
lvm_response_t *rarray;
|
||||
|
||||
*num = 0;
|
||||
|
||||
if (_clvmd_sock == -1)
|
||||
_clvmd_sock = _open_local_sock();
|
||||
|
||||
if (_clvmd_sock == -1)
|
||||
return 0;
|
||||
|
||||
_build_header(head, cmd, node, len);
|
||||
if (len)
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status = _send_request(outbuf, sizeof(struct clvm_header) +
|
||||
strlen(head->node) + len, &retbuf, no_response);
|
||||
if (!status || no_response)
|
||||
goto out;
|
||||
|
||||
/* Count the number of responses we got */
|
||||
head = (struct clvm_header *) retbuf;
|
||||
inptr = head->args;
|
||||
while (inptr[0]) {
|
||||
num_responses++;
|
||||
inptr += strlen(inptr) + 1;
|
||||
inptr += sizeof(int);
|
||||
inptr += strlen(inptr) + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate response array.
|
||||
* With an extra pair of INTs on the front to sanity
|
||||
* check the pointer when we are given it back to free
|
||||
*/
|
||||
*response = NULL;
|
||||
if (!(rarray = dm_malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2))) {
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Unpack the response into an lvm_response_t array */
|
||||
inptr = head->args;
|
||||
i = 0;
|
||||
while (inptr[0]) {
|
||||
strcpy(rarray[i].node, inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
|
||||
memcpy(&rarray[i].status, inptr, sizeof(int));
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = dm_malloc(strlen(inptr) + 1);
|
||||
if (rarray[i].response == NULL) {
|
||||
/* Free up everything else and return error */
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
dm_free(rarray[i].response);
|
||||
dm_free(rarray);
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
strcpy(rarray[i].response, inptr);
|
||||
rarray[i].len = strlen(inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
i++;
|
||||
}
|
||||
*num = num_responses;
|
||||
*response = rarray;
|
||||
|
||||
out:
|
||||
dm_free(retbuf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Free reply array */
|
||||
static int _cluster_free_request(lvm_response_t * response, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
dm_free(response[i].response);
|
||||
}
|
||||
|
||||
dm_free(response);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int refresh_clvmd(int all_nodes)
|
||||
{
|
||||
int num_responses;
|
||||
char args[1]; // No args really.
|
||||
lvm_response_t *response = NULL;
|
||||
int saved_errno;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_REFRESH, all_nodes ? NODE_ALL : NODE_LOCAL, args, 0, &response, &num_responses, 0);
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == EHOSTDOWN) {
|
||||
fprintf(stderr, "clvmd not running on node %s",
|
||||
response[i].node);
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
} else if (response[i].status) {
|
||||
fprintf(stderr, "Error resetting node %s: %s",
|
||||
response[i].node,
|
||||
response[i].response[0] ?
|
||||
response[i].response :
|
||||
strerror(response[i].status));
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int restart_clvmd(int all_nodes)
|
||||
{
|
||||
int dummy, status;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_RESTART, all_nodes ? NODE_ALL : NODE_LOCAL, NULL, 0, NULL, &dummy, 1);
|
||||
|
||||
/*
|
||||
* FIXME: we cannot receive response, clvmd re-exec before it.
|
||||
* but also should not close socket too early (the whole rq is dropped then).
|
||||
* FIXME: This should be handled this way:
|
||||
* - client waits for RESTART ack (and socket close)
|
||||
* - server restarts
|
||||
* - client checks that server is ready again (VERSION command?)
|
||||
*/
|
||||
usleep(500000);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int debug_clvmd(int level, int clusterwide)
|
||||
{
|
||||
int num_responses;
|
||||
char args[1];
|
||||
const char *nodes;
|
||||
lvm_response_t *response = NULL;
|
||||
int saved_errno;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
args[0] = level;
|
||||
if (clusterwide)
|
||||
nodes = NODE_ALL;
|
||||
else
|
||||
nodes = NODE_LOCAL;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_SET_DEBUG, nodes, args, 1, &response, &num_responses, 0);
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == EHOSTDOWN) {
|
||||
fprintf(stderr, "clvmd not running on node %s",
|
||||
response[i].node);
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
} else if (response[i].status) {
|
||||
fprintf(stderr, "Error setting debug on node %s: %s",
|
||||
response[i].node,
|
||||
response[i].response[0] ?
|
||||
response[i].response :
|
||||
strerror(response[i].status));
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
int refresh_clvmd(int all_nodes);
|
||||
int restart_clvmd(int all_nodes);
|
||||
int debug_clvmd(int level, int clusterwide);
|
||||
|
||||
@@ -17,8 +17,6 @@ top_builddir = @top_builddir@
|
||||
|
||||
CPG_LIBS = @CPG_LIBS@
|
||||
CPG_CFLAGS = @CPG_CFLAGS@
|
||||
SACKPT_LIBS = @SACKPT_LIBS@
|
||||
SACKPT_CFLAGS = @SACKPT_CFLAGS@
|
||||
|
||||
SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c
|
||||
|
||||
@@ -26,14 +24,13 @@ TARGETS = cmirrord
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper
|
||||
LMLIBS += $(CPG_LIBS) $(SACKPT_LIBS)
|
||||
CFLAGS += $(CPG_CFLAGS) $(SACKPT_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
||||
LMLIBS += $(CPG_LIBS)
|
||||
CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
|
||||
cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
||||
$(LVMLIBS) $(LMLIBS) $(LIBS)
|
||||
$(LVMLIBS) $(LMLIBS) $(INTERNAL_LIBS) $(LIBS)
|
||||
|
||||
install: $(TARGETS)
|
||||
$(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
#include "functions.h"
|
||||
#include "link_mon.h"
|
||||
#include "local.h"
|
||||
#include "xlate.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
|
||||
/* FIXME: remove this and the code */
|
||||
#define CMIRROR_HAS_CHECKPOINT 0
|
||||
|
||||
#include <corosync/cpg.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
#ifndef _LVM_CLOG_CLUSTER_H
|
||||
#define _LVM_CLOG_CLUSTER_H
|
||||
|
||||
#include "dm-log-userspace.h"
|
||||
#include "libdevmapper.h"
|
||||
#include "device_mapper/misc/dm-log-userspace.h"
|
||||
#include "device_mapper/all.h"
|
||||
|
||||
#define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */
|
||||
#define DM_ULOG_CHECKPOINT_READY 21
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "logging.h"
|
||||
#include "cluster.h"
|
||||
#include "compat.h"
|
||||
#include "xlate.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
#include "logging.h"
|
||||
#include "functions.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
#include <dirent.h>
|
||||
@@ -435,7 +436,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
||||
block_on_error = 1;
|
||||
}
|
||||
|
||||
lc = dm_zalloc(sizeof(*lc));
|
||||
lc = zalloc(sizeof(*lc));
|
||||
if (!lc) {
|
||||
LOG_ERROR("Unable to allocate cluster log context");
|
||||
r = -ENOMEM;
|
||||
@@ -532,9 +533,9 @@ fail:
|
||||
LOG_ERROR("Close device error, %s: %s",
|
||||
disk_path, strerror(errno));
|
||||
free(lc->disk_buffer);
|
||||
dm_free(lc->sync_bits);
|
||||
dm_free(lc->clean_bits);
|
||||
dm_free(lc);
|
||||
free(lc->sync_bits);
|
||||
free(lc->clean_bits);
|
||||
free(lc);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -659,9 +660,9 @@ static int clog_dtr(struct dm_ulog_request *rq)
|
||||
strerror(errno));
|
||||
if (lc->disk_buffer)
|
||||
free(lc->disk_buffer);
|
||||
dm_free(lc->clean_bits);
|
||||
dm_free(lc->sync_bits);
|
||||
dm_free(lc);
|
||||
free(lc->clean_bits);
|
||||
free(lc->sync_bits);
|
||||
free(lc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#ifndef _LVM_CLOG_FUNCTIONS_H
|
||||
#define _LVM_CLOG_FUNCTIONS_H
|
||||
|
||||
#include "dm-log-userspace.h"
|
||||
#include "device_mapper/misc/dm-log-userspace.h"
|
||||
#include "cluster.h"
|
||||
|
||||
#define LOG_RESUMED 1
|
||||
|
||||
@@ -57,13 +57,13 @@ all: device-mapper
|
||||
device-mapper: $(TARGETS)
|
||||
|
||||
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
|
||||
LIBS += -ldevmapper $(PTHREAD_LIBS)
|
||||
LIBS += $(PTHREAD_LIBS)
|
||||
|
||||
dmeventd: $(LIB_SHARED) dmeventd.o
|
||||
$(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(INTERNAL_LIBS) $(LIBS) -lm
|
||||
|
||||
dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a
|
||||
dmeventd.static: $(LIB_STATIC) dmeventd.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
|
||||
|
||||
@@ -73,7 +73,6 @@ endif
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
-include $(top_builddir)/libdm/libdevmapper.cflow
|
||||
-include $(top_builddir)/lib/liblvm-internal.cflow
|
||||
-include $(top_builddir)/lib/liblvm2cmd.cflow
|
||||
-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
* dmeventd - dm event daemon to monitor active mapped devices
|
||||
*/
|
||||
|
||||
#include "dm-logging.h"
|
||||
#include "device_mapper/misc/dmlib.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "device_mapper/misc/dm-logging.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
#include "dmeventd.h"
|
||||
|
||||
#include "tool.h"
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
@@ -264,19 +266,19 @@ static pthread_cond_t _timeout_cond = PTHREAD_COND_INITIALIZER;
|
||||
/* DSO data allocate/free. */
|
||||
static void _free_dso_data(struct dso_data *data)
|
||||
{
|
||||
dm_free(data->dso_name);
|
||||
dm_free(data);
|
||||
free(data->dso_name);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static struct dso_data *_alloc_dso_data(struct message_data *data)
|
||||
{
|
||||
struct dso_data *ret = (typeof(ret)) dm_zalloc(sizeof(*ret));
|
||||
struct dso_data *ret = (typeof(ret)) zalloc(sizeof(*ret));
|
||||
|
||||
if (!ret)
|
||||
return_NULL;
|
||||
|
||||
if (!(ret->dso_name = dm_strdup(data->dso_name))) {
|
||||
dm_free(ret);
|
||||
if (!(ret->dso_name = strdup(data->dso_name))) {
|
||||
free(ret);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
@@ -397,9 +399,9 @@ static void _free_thread_status(struct thread_status *thread)
|
||||
_lib_put(thread->dso_data);
|
||||
if (thread->wait_task)
|
||||
dm_task_destroy(thread->wait_task);
|
||||
dm_free(thread->device.uuid);
|
||||
dm_free(thread->device.name);
|
||||
dm_free(thread);
|
||||
free(thread->device.uuid);
|
||||
free(thread->device.name);
|
||||
free(thread);
|
||||
}
|
||||
|
||||
/* Note: events_field must not be 0, ensured by caller */
|
||||
@@ -408,7 +410,7 @@ static struct thread_status *_alloc_thread_status(const struct message_data *dat
|
||||
{
|
||||
struct thread_status *thread;
|
||||
|
||||
if (!(thread = dm_zalloc(sizeof(*thread)))) {
|
||||
if (!(thread = zalloc(sizeof(*thread)))) {
|
||||
log_error("Cannot create new thread, out of memory.");
|
||||
return NULL;
|
||||
}
|
||||
@@ -422,11 +424,11 @@ static struct thread_status *_alloc_thread_status(const struct message_data *dat
|
||||
if (!dm_task_set_uuid(thread->wait_task, data->device_uuid))
|
||||
goto_out;
|
||||
|
||||
if (!(thread->device.uuid = dm_strdup(data->device_uuid)))
|
||||
if (!(thread->device.uuid = strdup(data->device_uuid)))
|
||||
goto_out;
|
||||
|
||||
/* Until real name resolved, use UUID */
|
||||
if (!(thread->device.name = dm_strdup(data->device_uuid)))
|
||||
if (!(thread->device.name = strdup(data->device_uuid)))
|
||||
goto_out;
|
||||
|
||||
/* runs ioctl and may register lvm2 pluging */
|
||||
@@ -515,7 +517,7 @@ static int _fetch_string(char **ptr, char **src, const int delimiter)
|
||||
if ((p = strchr(*src, delimiter))) {
|
||||
if (*src < p) {
|
||||
*p = 0; /* Temporary exit with \0 */
|
||||
if (!(*ptr = dm_strdup(*src))) {
|
||||
if (!(*ptr = strdup(*src))) {
|
||||
log_error("Failed to fetch item %s.", *src);
|
||||
ret = 0; /* Allocation fail */
|
||||
}
|
||||
@@ -525,7 +527,7 @@ static int _fetch_string(char **ptr, char **src, const int delimiter)
|
||||
(*src)++; /* Skip delmiter, next field */
|
||||
} else if ((len = strlen(*src))) {
|
||||
/* No delimiter, item ends with '\0' */
|
||||
if (!(*ptr = dm_strdup(*src))) {
|
||||
if (!(*ptr = strdup(*src))) {
|
||||
log_error("Failed to fetch last item %s.", *src);
|
||||
ret = 0; /* Fail */
|
||||
}
|
||||
@@ -538,11 +540,11 @@ out:
|
||||
/* Free message memory. */
|
||||
static void _free_message(struct message_data *message_data)
|
||||
{
|
||||
dm_free(message_data->id);
|
||||
dm_free(message_data->dso_name);
|
||||
dm_free(message_data->device_uuid);
|
||||
dm_free(message_data->events_str);
|
||||
dm_free(message_data->timeout_str);
|
||||
free(message_data->id);
|
||||
free(message_data->dso_name);
|
||||
free(message_data->device_uuid);
|
||||
free(message_data->events_str);
|
||||
free(message_data->timeout_str);
|
||||
}
|
||||
|
||||
/* Parse a register message from the client. */
|
||||
@@ -574,7 +576,7 @@ static int _parse_message(struct message_data *message_data)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
|
||||
return ret;
|
||||
@@ -608,8 +610,8 @@ static int _fill_device_data(struct thread_status *ts)
|
||||
if (!dm_task_run(dmt))
|
||||
goto fail;
|
||||
|
||||
dm_free(ts->device.name);
|
||||
if (!(ts->device.name = dm_strdup(dm_task_get_name(dmt))))
|
||||
free(ts->device.name);
|
||||
if (!(ts->device.name = strdup(dm_task_get_name(dmt))))
|
||||
goto fail;
|
||||
|
||||
if (!dm_task_get_info(dmt, &dmi))
|
||||
@@ -696,8 +698,8 @@ static int _get_status(struct message_data *message_data)
|
||||
|
||||
len = strlen(message_data->id);
|
||||
msg->size = size + len + 1;
|
||||
dm_free(msg->data);
|
||||
if (!(msg->data = dm_malloc(msg->size)))
|
||||
free(msg->data);
|
||||
if (!(msg->data = malloc(msg->size)))
|
||||
goto out;
|
||||
|
||||
memcpy(msg->data, message_data->id, len);
|
||||
@@ -712,7 +714,7 @@ static int _get_status(struct message_data *message_data)
|
||||
ret = 0;
|
||||
out:
|
||||
for (j = 0; j < i; ++j)
|
||||
dm_free(buffers[j]);
|
||||
free(buffers[j]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -721,7 +723,7 @@ static int _get_parameters(struct message_data *message_data) {
|
||||
struct dm_event_daemon_message *msg = message_data->msg;
|
||||
int size;
|
||||
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
if ((size = dm_asprintf(&msg->data, "%s pid=%d daemon=%s exec_method=%s",
|
||||
message_data->id, getpid(),
|
||||
_foreground ? "no" : "yes",
|
||||
@@ -752,7 +754,7 @@ static void _exit_timeout(void *unused __attribute__((unused)))
|
||||
static void *_timeout_thread(void *unused __attribute__((unused)))
|
||||
{
|
||||
struct thread_status *thread;
|
||||
struct timespec timeout, real_time;
|
||||
struct timespec timeout;
|
||||
time_t curr_time;
|
||||
int ret;
|
||||
|
||||
@@ -763,16 +765,7 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
|
||||
while (!dm_list_empty(&_timeout_registry)) {
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_nsec = 0;
|
||||
#ifndef HAVE_REALTIME
|
||||
curr_time = time(NULL);
|
||||
#else
|
||||
if (clock_gettime(CLOCK_REALTIME, &real_time)) {
|
||||
log_error("Failed to read clock_gettime().");
|
||||
break;
|
||||
}
|
||||
/* 10ms back to the future */
|
||||
curr_time = real_time.tv_sec + ((real_time.tv_nsec > (1000000000 - 10000000)) ? 1 : 0);
|
||||
#endif
|
||||
|
||||
dm_list_iterate_items_gen(thread, &_timeout_registry, timeout_list) {
|
||||
if (thread->next_time <= curr_time) {
|
||||
@@ -1234,7 +1227,7 @@ static int _registered_device(struct message_data *message_data,
|
||||
int r;
|
||||
struct dm_event_daemon_message *msg = message_data->msg;
|
||||
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
|
||||
if ((r = dm_asprintf(&(msg->data), "%s %s %s %u",
|
||||
message_data->id,
|
||||
@@ -1374,7 +1367,7 @@ static int _get_timeout(struct message_data *message_data)
|
||||
if (!thread)
|
||||
return -ENODEV;
|
||||
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->size = dm_asprintf(&(msg->data), "%s %" PRIu32,
|
||||
message_data->id, thread->timeout);
|
||||
|
||||
@@ -1511,7 +1504,7 @@ static int _client_read(struct dm_event_fifos *fifos,
|
||||
bytes = 0;
|
||||
if (!size)
|
||||
break; /* No data -> error */
|
||||
buf = msg->data = dm_malloc(msg->size);
|
||||
buf = msg->data = malloc(msg->size);
|
||||
if (!buf)
|
||||
break; /* No mem -> error */
|
||||
header = 0;
|
||||
@@ -1519,7 +1512,7 @@ static int _client_read(struct dm_event_fifos *fifos,
|
||||
}
|
||||
|
||||
if (bytes != size) {
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
return 0;
|
||||
}
|
||||
@@ -1539,7 +1532,7 @@ static int _client_write(struct dm_event_fifos *fifos,
|
||||
fd_set fds;
|
||||
|
||||
size_t size = 2 * sizeof(uint32_t) + ((msg->data) ? msg->size : 0);
|
||||
uint32_t *header = dm_malloc(size);
|
||||
uint32_t *header = malloc(size);
|
||||
char *buf = (char *)header;
|
||||
|
||||
if (!header) {
|
||||
@@ -1569,7 +1562,7 @@ static int _client_write(struct dm_event_fifos *fifos,
|
||||
}
|
||||
|
||||
if (header != temp)
|
||||
dm_free(header);
|
||||
free(header);
|
||||
|
||||
return (bytes == size);
|
||||
}
|
||||
@@ -1631,7 +1624,7 @@ static int _do_process_request(struct dm_event_daemon_message *msg)
|
||||
msg->size = dm_asprintf(&(msg->data), "%s %s %d", answer,
|
||||
(msg->cmd == DM_EVENT_CMD_DIE) ? "DYING" : "HELLO",
|
||||
DM_EVENT_PROTOCOL_VERSION);
|
||||
dm_free(answer);
|
||||
free(answer);
|
||||
}
|
||||
} else if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
|
||||
stack;
|
||||
@@ -1673,7 +1666,7 @@ static void _process_request(struct dm_event_fifos *fifos)
|
||||
|
||||
DEBUGLOG("<<< CMD:%s (0x%x) completed (result %d).", decode_cmd(cmd), cmd, msg.cmd);
|
||||
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
|
||||
if (cmd == DM_EVENT_CMD_DIE) {
|
||||
if (unlink(DMEVENTD_PIDFILE))
|
||||
@@ -1984,7 +1977,7 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
|
||||
int i, ret;
|
||||
|
||||
ret = daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
msg.data = NULL;
|
||||
|
||||
if (ret) {
|
||||
@@ -2030,8 +2023,8 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
|
||||
static void _restart_dmeventd(void)
|
||||
{
|
||||
struct dm_event_fifos fifos = {
|
||||
.client = -1,
|
||||
.server = -1,
|
||||
.client = -1,
|
||||
/* FIXME Make these either configurable or depend directly on dmeventd_path */
|
||||
.client_path = DM_EVENT_FIFO_CLIENT,
|
||||
.server_path = DM_EVENT_FIFO_SERVER
|
||||
@@ -2070,13 +2063,13 @@ static void _restart_dmeventd(void)
|
||||
++count;
|
||||
}
|
||||
|
||||
if (!(_initial_registrations = dm_malloc(sizeof(char*) * (count + 1)))) {
|
||||
if (!(_initial_registrations = malloc(sizeof(char*) * (count + 1)))) {
|
||||
fprintf(stderr, "Memory allocation registration failed.\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (!(_initial_registrations[i] = dm_strdup(message))) {
|
||||
if (!(_initial_registrations[i] = strdup(message))) {
|
||||
fprintf(stderr, "Memory allocation for message failed.\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
@@ -12,10 +12,12 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "dm-logging.h"
|
||||
#include "dmlib.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "device_mapper/misc/dmlib.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "device_mapper/misc/dm-logging.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
#include "dmeventd.h"
|
||||
#include "lib/misc/intl.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
@@ -25,6 +27,7 @@
|
||||
#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;
|
||||
@@ -47,8 +50,8 @@ struct dm_event_handler {
|
||||
|
||||
static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
|
||||
{
|
||||
dm_free(dmevh->dev_name);
|
||||
dm_free(dmevh->uuid);
|
||||
free(dmevh->dev_name);
|
||||
free(dmevh->uuid);
|
||||
dmevh->dev_name = dmevh->uuid = NULL;
|
||||
dmevh->major = dmevh->minor = 0;
|
||||
}
|
||||
@@ -57,7 +60,7 @@ struct dm_event_handler *dm_event_handler_create(void)
|
||||
{
|
||||
struct dm_event_handler *dmevh;
|
||||
|
||||
if (!(dmevh = dm_zalloc(sizeof(*dmevh)))) {
|
||||
if (!(dmevh = zalloc(sizeof(*dmevh)))) {
|
||||
log_error("Failed to allocate event handler.");
|
||||
return NULL;
|
||||
}
|
||||
@@ -68,9 +71,9 @@ struct dm_event_handler *dm_event_handler_create(void)
|
||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh)
|
||||
{
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
dm_free(dmevh->dso);
|
||||
dm_free(dmevh->dmeventd_path);
|
||||
dm_free(dmevh);
|
||||
free(dmevh->dso);
|
||||
free(dmevh->dmeventd_path);
|
||||
free(dmevh);
|
||||
}
|
||||
|
||||
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path)
|
||||
@@ -78,9 +81,9 @@ int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const cha
|
||||
if (!dmeventd_path) /* noop */
|
||||
return 0;
|
||||
|
||||
dm_free(dmevh->dmeventd_path);
|
||||
free(dmevh->dmeventd_path);
|
||||
|
||||
if (!(dmevh->dmeventd_path = dm_strdup(dmeventd_path)))
|
||||
if (!(dmevh->dmeventd_path = strdup(dmeventd_path)))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
@@ -91,9 +94,9 @@ int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path)
|
||||
if (!path) /* noop */
|
||||
return 0;
|
||||
|
||||
dm_free(dmevh->dso);
|
||||
free(dmevh->dso);
|
||||
|
||||
if (!(dmevh->dso = dm_strdup(path)))
|
||||
if (!(dmevh->dso = strdup(path)))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
@@ -106,7 +109,7 @@ int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *de
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
if (!(dmevh->dev_name = dm_strdup(dev_name)))
|
||||
if (!(dmevh->dev_name = strdup(dev_name)))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
@@ -119,7 +122,7 @@ int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid)
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
if (!(dmevh->uuid = dm_strdup(uuid)))
|
||||
if (!(dmevh->uuid = strdup(uuid)))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
@@ -259,7 +262,7 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
if (header && (bytes == 2 * sizeof(uint32_t))) {
|
||||
msg->cmd = ntohl(header[0]);
|
||||
msg->size = ntohl(header[1]);
|
||||
buf = msg->data = dm_malloc(msg->size);
|
||||
buf = msg->data = malloc(msg->size);
|
||||
size = msg->size;
|
||||
bytes = 0;
|
||||
header = 0;
|
||||
@@ -267,7 +270,7 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
}
|
||||
|
||||
if (bytes != size) {
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
}
|
||||
return bytes == size;
|
||||
@@ -370,13 +373,13 @@ int daemon_talk(struct dm_event_fifos *fifos,
|
||||
*/
|
||||
if (!_daemon_write(fifos, msg)) {
|
||||
stack;
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
do {
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
|
||||
if (!_daemon_read(fifos, msg)) {
|
||||
@@ -605,8 +608,8 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_fifos fifos = {
|
||||
.client = -1,
|
||||
.server = -1,
|
||||
.client = -1,
|
||||
/* FIXME Make these either configurable or depend directly on dmeventd_path */
|
||||
.client_path = DM_EVENT_FIFO_CLIENT,
|
||||
.server_path = DM_EVENT_FIFO_SERVER
|
||||
@@ -619,7 +622,7 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
|
||||
|
||||
ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
|
||||
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = 0;
|
||||
|
||||
if (!ret)
|
||||
@@ -660,7 +663,7 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
@@ -687,7 +690,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
@@ -703,7 +706,7 @@ static char *_fetch_string(char **src, const int delimiter)
|
||||
if ((p = strchr(*src, delimiter)))
|
||||
*p = 0;
|
||||
|
||||
if ((ret = dm_strdup(*src)))
|
||||
if ((ret = strdup(*src)))
|
||||
*src += strlen(ret) + 1;
|
||||
|
||||
if (p)
|
||||
@@ -723,11 +726,11 @@ static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
(*dso_name = _fetch_string(&p, ' ')) &&
|
||||
(*uuid = _fetch_string(&p, ' '))) {
|
||||
*evmask = atoi(p);
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -769,7 +772,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
dm_task_destroy(dmt);
|
||||
dmt = NULL;
|
||||
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
msg.data = NULL;
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
@@ -778,7 +781,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(dmevh->uuid = dm_strdup(reply_uuid))) {
|
||||
if (!(dmevh->uuid = strdup(reply_uuid))) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
@@ -791,13 +794,13 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
dm_event_handler_set_dso(dmevh, reply_dso);
|
||||
dm_event_handler_set_event_mask(dmevh, reply_mask);
|
||||
|
||||
dm_free(reply_dso);
|
||||
free(reply_dso);
|
||||
reply_dso = NULL;
|
||||
|
||||
dm_free(reply_uuid);
|
||||
free(reply_uuid);
|
||||
reply_uuid = NULL;
|
||||
|
||||
if (!(dmevh->dev_name = dm_strdup(dm_task_get_name(dmt)))) {
|
||||
if (!(dmevh->dev_name = strdup(dm_task_get_name(dmt)))) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
@@ -815,9 +818,9 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
dm_free(msg.data);
|
||||
dm_free(reply_dso);
|
||||
dm_free(reply_uuid);
|
||||
free(msg.data);
|
||||
free(reply_dso);
|
||||
free(reply_uuid);
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
if (dmt)
|
||||
dm_task_destroy(dmt);
|
||||
@@ -982,12 +985,12 @@ int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
|
||||
if (!p) {
|
||||
log_error("Malformed reply from dmeventd '%s'.",
|
||||
msg.data);
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
return -EIO;
|
||||
}
|
||||
*timeout = atoi(p);
|
||||
}
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -8,4 +8,3 @@ Description: device-mapper event library
|
||||
Version: @DM_LIB_PATCHLEVEL@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -ldevmapper-event
|
||||
Requires.private: devmapper
|
||||
|
||||
@@ -24,7 +24,7 @@ LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS)
|
||||
LIBS += @LVM2CMD_LIB@ $(INTERNAL_LIBS) $(PTHREAD_LIBS)
|
||||
|
||||
install_lvm2: install_lib_shared
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
#include "tools/lvm2cmd.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
@@ -31,13 +31,6 @@ static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int _register_count = 0;
|
||||
static struct dm_pool *_mem_pool = 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")
|
||||
|
||||
@@ -71,7 +64,7 @@ int dmeventd_lvm2_init(void)
|
||||
if (!_lvm_handle) {
|
||||
lvm2_log_fn(_lvm2_print_log);
|
||||
|
||||
if (!(_lvm_handle = lvm2_init_threaded()))
|
||||
if (!(_lvm_handle = lvm2_init()))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
@@ -107,7 +100,6 @@ void dmeventd_lvm2_exit(void)
|
||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
dm_list_init(&_env_registry);
|
||||
lvm2_exit(_lvm_handle);
|
||||
_lvm_handle = NULL;
|
||||
log_debug("lvm plugin exited.");
|
||||
@@ -132,8 +124,6 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
static char _internal_prefix[] = "_dmeventd_";
|
||||
char *vg = NULL, *lv = NULL, *layer;
|
||||
int r;
|
||||
struct env_data *env_data;
|
||||
const char *env = NULL;
|
||||
|
||||
if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
|
||||
log_error("Unable to determine VG name from %s.",
|
||||
@@ -147,36 +137,18 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
*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;
|
||||
}
|
||||
dmeventd_lvm2_lock();
|
||||
/* output of internal command passed via env var */
|
||||
if (!dmeventd_lvm2_run(cmd))
|
||||
cmd = NULL;
|
||||
else if ((cmd = getenv(cmd)))
|
||||
cmd = dm_pool_strdup(mem, cmd); /* copy with lock */
|
||||
dmeventd_lvm2_unlock();
|
||||
|
||||
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);
|
||||
if (!cmd) {
|
||||
log_error("Unable to find configured command.");
|
||||
return 0;
|
||||
}
|
||||
cmd = env;
|
||||
}
|
||||
|
||||
r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv);
|
||||
|
||||
@@ -30,7 +30,7 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "activate.h" /* For TARGET_NAME* */
|
||||
#include "lib/activate/activate.h"
|
||||
|
||||
/* FIXME Reformat to 80 char lines. */
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "defaults.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/config/defaults.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
|
||||
/* Hold enough elements for the mximum number of RAID images */
|
||||
#define RAID_DEVS_ELEMS ((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
|
||||
@@ -76,17 +76,14 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
|
||||
}
|
||||
|
||||
if (dead) {
|
||||
/*
|
||||
* Use the first event to run a repair ignoring any additonal ones.
|
||||
*
|
||||
* We presume lvconvert to do pre-repair
|
||||
* checks to avoid bloat in this plugin.
|
||||
*/
|
||||
if (!state->warned && status->insync_regions < status->total_regions) {
|
||||
state->warned = 1;
|
||||
log_warn("WARNING: waiting for resynchronization to finish "
|
||||
"before initiating repair on RAID device %s.", device);
|
||||
/* Fall through to allow lvconvert to run. */
|
||||
if (status->insync_regions < status->total_regions) {
|
||||
if (!state->warned) {
|
||||
state->warned = 1;
|
||||
log_warn("WARNING: waiting for resynchronization to finish "
|
||||
"before initiating repair on RAID device %s.", device);
|
||||
}
|
||||
|
||||
goto out; /* Not yet done syncing with accessible devices */
|
||||
}
|
||||
|
||||
if (state->failed)
|
||||
|
||||
@@ -26,7 +26,7 @@ LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
@@ -29,7 +29,7 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib.h" /* using here lvm log */
|
||||
#include "lib/misc/lib.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* TODO - move this mountinfo code into library to be reusable */
|
||||
#ifdef __linux__
|
||||
# include "kdev_t.h"
|
||||
# include "libdm/misc/kdev_t.h"
|
||||
#else
|
||||
# define MAJOR(x) major((x))
|
||||
# define MINOR(x) minor((x))
|
||||
@@ -286,7 +286,7 @@ void process_event(struct dm_task *dmt,
|
||||
if (state->fails++ <= state->max_fails) {
|
||||
log_debug("Postponing frequently failing policy (%u <= %u).",
|
||||
state->fails - 1, state->max_fails);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
if (state->max_fails < MAX_FAILS)
|
||||
state->max_fails <<= 1;
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
#include "device_mapper/vdo/target.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <stdarg.h>
|
||||
@@ -45,23 +46,6 @@ struct dso_state {
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct vdo_status {
|
||||
uint64_t used_blocks;
|
||||
uint64_t total_blocks;
|
||||
};
|
||||
|
||||
static int _vdo_status_parse(const char *params, struct vdo_status *status)
|
||||
{
|
||||
if (sscanf(params, "%*s %*s %*s %*s %*s %" PRIu64 " %" PRIu64,
|
||||
&status->used_blocks,
|
||||
&status->total_blocks) < 2) {
|
||||
log_error("Failed to parse vdo params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
DM_EVENT_LOG_FN("vdo")
|
||||
|
||||
static int _run_command(struct dso_state *state)
|
||||
@@ -165,7 +149,7 @@ void process_event(struct dm_task *dmt,
|
||||
char *params;
|
||||
int needs_policy = 0;
|
||||
struct dm_task *new_dmt = NULL;
|
||||
struct vdo_status status;
|
||||
struct dm_vdo_status_parse_result vdop = { .status = NULL };
|
||||
|
||||
#if VDO_DEBUG
|
||||
log_debug("Watch for VDO %s:%.2f%%.", state->name,
|
||||
@@ -211,24 +195,24 @@ void process_event(struct dm_task *dmt,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!_vdo_status_parse(params, &status)) {
|
||||
if (!dm_vdo_status_parse(state->mem, params, &vdop)) {
|
||||
log_error("Failed to parse status.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
state->percent = dm_make_percent(status.used_blocks,
|
||||
status.total_blocks);
|
||||
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),
|
||||
status.used_blocks, status.total_blocks);
|
||||
vdop.status->used_blocks, vdop.status->total_blocks);
|
||||
#endif
|
||||
|
||||
/* VDO pool size had changed. Clear the threshold. */
|
||||
if (state->known_data_size != status.total_blocks) {
|
||||
if (state->known_data_size != vdop.status->total_blocks) {
|
||||
state->percent_check = CHECK_MINIMUM;
|
||||
state->known_data_size = status.total_blocks;
|
||||
state->known_data_size = vdop.status->total_blocks;
|
||||
state->fails = 0;
|
||||
}
|
||||
|
||||
@@ -261,7 +245,7 @@ void process_event(struct dm_task *dmt,
|
||||
if (state->fails++ <= state->max_fails) {
|
||||
log_debug("Postponing frequently failing policy (%u <= %u).",
|
||||
state->fails - 1, state->max_fails);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
if (state->max_fails < MAX_FAILS)
|
||||
state->max_fails <<= 1;
|
||||
@@ -273,6 +257,9 @@ void process_event(struct dm_task *dmt,
|
||||
if (0 && needs_policy)
|
||||
_use_policy(dmt, state);
|
||||
out:
|
||||
if (vdop.status)
|
||||
dm_pool_free(state->mem, vdop.status);
|
||||
|
||||
if (new_dmt)
|
||||
dm_task_destroy(new_dmt);
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the device-mapper userspace tools.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU Lesser General Public License v.2.1.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SOURCES = dmfilemapd.c
|
||||
|
||||
TARGETS = dmfilemapd
|
||||
|
||||
.PHONY: install_dmfilemapd install_dmfilemapd_static
|
||||
|
||||
INSTALL_DMFILEMAPD_TARGETS = install_dmfilemapd_dynamic
|
||||
|
||||
CLEAN_TARGETS = dmfilemapd.static
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
CFLOW_TARGET = dmfilemapd
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
all: device-mapper
|
||||
device-mapper: $(TARGETS)
|
||||
|
||||
CFLAGS_dmfilemapd.o += $(EXTRA_EXEC_CFLAGS)
|
||||
LIBS += -ldevmapper
|
||||
|
||||
dmfilemapd: $(LIB_SHARED) dmfilemapd.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
|
||||
-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS)
|
||||
|
||||
dmfilemapd.static: $(LIB_STATIC) dmfilemapd.o $(interfacebuilddir)/libdevmapper.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L$(interfacebuilddir) \
|
||||
-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS) $(STATIC_LIBS)
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
-include $(top_builddir)/libdm/libdevmapper.cflow
|
||||
-include $(top_builddir)/lib/liblvm-internal.cflow
|
||||
-include $(top_builddir)/lib/liblvm2cmd.cflow
|
||||
-include $(top_builddir)/daemons/dmfilemapd/$(LIB_NAME).cflow
|
||||
endif
|
||||
|
||||
install_dmfilemapd_dynamic: dmfilemapd
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
|
||||
install_dmfilemapd_static: dmfilemapd.static
|
||||
$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
|
||||
|
||||
install_dmfilemapd: $(INSTALL_DMFILEMAPD_TARGETS)
|
||||
|
||||
install: install_dmfilemapd
|
||||
|
||||
install_device-mapper: install_dmfilemapd
|
||||
2
daemons/lvmetad/.gitignore
vendored
2
daemons/lvmetad/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
lvmetad
|
||||
lvmetactl
|
||||
@@ -1,62 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2011-2012 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU Lesser General Public License v.2.1.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SOURCES = lvmetad-core.c
|
||||
SOURCES2 = lvmetactl.c
|
||||
|
||||
TARGETS = lvmetad lvmetactl
|
||||
|
||||
.PHONY: install_lvmetad
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
CFLOW_TARGET = lvmetad
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
CFLAGS_lvmetactl.o += $(EXTRA_EXEC_CFLAGS)
|
||||
CFLAGS_lvmetad-core.o += $(EXTRA_EXEC_CFLAGS)
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
|
||||
|
||||
lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) -ldaemonserver $(LIBS)
|
||||
|
||||
lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LIBS)
|
||||
|
||||
CLEAN_TARGETS += lvmetactl.o
|
||||
|
||||
# TODO: No idea. No idea how to test either.
|
||||
#ifneq ("$(CFLOW_CMD)", "")
|
||||
#CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
#-include $(top_builddir)/libdm/libdevmapper.cflow
|
||||
#-include $(top_builddir)/lib/liblvm-internal.cflow
|
||||
#-include $(top_builddir)/lib/liblvm2cmd.cflow
|
||||
#-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
|
||||
#-include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow
|
||||
#endif
|
||||
|
||||
install_lvmetad: lvmetad
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
|
||||
install_lvm2: install_lvmetad
|
||||
|
||||
install: install_lvm2
|
||||
@@ -1,249 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*/
|
||||
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvmetad-client.h"
|
||||
|
||||
daemon_handle h;
|
||||
|
||||
static void print_reply(daemon_reply reply)
|
||||
{
|
||||
const char *a = daemon_reply_str(reply, "response", NULL);
|
||||
const char *b = daemon_reply_str(reply, "status", NULL);
|
||||
const char *c = daemon_reply_str(reply, "reason", NULL);
|
||||
|
||||
printf("response \"%s\" status \"%s\" reason \"%s\"\n",
|
||||
a ? a : "", b ? b : "", c ? c : "");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
daemon_reply reply;
|
||||
char *cmd;
|
||||
char *uuid;
|
||||
char *name;
|
||||
int val;
|
||||
int ver;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("lvmetactl dump\n");
|
||||
printf("lvmetactl pv_list\n");
|
||||
printf("lvmetactl vg_list\n");
|
||||
printf("lvmetactl get_global_info\n");
|
||||
printf("lvmetactl vg_lookup_name <name>\n");
|
||||
printf("lvmetactl vg_lookup_uuid <uuid>\n");
|
||||
printf("lvmetactl pv_lookup_uuid <uuid>\n");
|
||||
printf("lvmetactl set_global_invalid 0|1\n");
|
||||
printf("lvmetactl set_global_disable 0|1\n");
|
||||
printf("lvmetactl set_vg_version <uuid> <name> <version>\n");
|
||||
printf("lvmetactl vg_lock_type <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd = argv[1];
|
||||
|
||||
h = lvmetad_open(NULL);
|
||||
|
||||
if (!strcmp(cmd, "dump")) {
|
||||
reply = daemon_send_simple(h, "dump",
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "pv_list")) {
|
||||
reply = daemon_send_simple(h, "pv_list",
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_list")) {
|
||||
reply = daemon_send_simple(h, "vg_list",
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "get_global_info")) {
|
||||
reply = daemon_send_simple(h, "get_global_info",
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "set_global_invalid")) {
|
||||
if (argc < 3) {
|
||||
printf("set_global_invalid 0|1\n");
|
||||
return -1;
|
||||
}
|
||||
val = atoi(argv[2]);
|
||||
|
||||
reply = daemon_send_simple(h, "set_global_info",
|
||||
"global_invalid = " FMTd64, (int64_t) val,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
print_reply(reply);
|
||||
|
||||
} else if (!strcmp(cmd, "set_global_disable")) {
|
||||
if (argc < 3) {
|
||||
printf("set_global_disable 0|1\n");
|
||||
return -1;
|
||||
}
|
||||
val = atoi(argv[2]);
|
||||
|
||||
reply = daemon_send_simple(h, "set_global_info",
|
||||
"global_disable = " FMTd64, (int64_t) val,
|
||||
"disable_reason = %s", LVMETAD_DISABLE_REASON_DIRECT,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
print_reply(reply);
|
||||
|
||||
} else if (!strcmp(cmd, "set_vg_version")) {
|
||||
if (argc < 5) {
|
||||
printf("set_vg_version <uuid> <name> <ver>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
name = argv[3];
|
||||
ver = atoi(argv[4]);
|
||||
|
||||
if ((strlen(uuid) == 1) && (uuid[0] == '-'))
|
||||
uuid = NULL;
|
||||
if ((strlen(name) == 1) && (name[0] == '-'))
|
||||
name = NULL;
|
||||
|
||||
if (uuid && name) {
|
||||
reply = daemon_send_simple(h, "set_vg_info",
|
||||
"uuid = %s", uuid,
|
||||
"name = %s", name,
|
||||
"version = " FMTd64, (int64_t) ver,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
} else if (uuid) {
|
||||
reply = daemon_send_simple(h, "set_vg_info",
|
||||
"uuid = %s", uuid,
|
||||
"version = " FMTd64, (int64_t) ver,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
} else if (name) {
|
||||
reply = daemon_send_simple(h, "set_vg_info",
|
||||
"name = %s", name,
|
||||
"version = " FMTd64, (int64_t) ver,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
} else {
|
||||
printf("name or uuid required\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
print_reply(reply);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_lookup_name")) {
|
||||
if (argc < 3) {
|
||||
printf("vg_lookup_name <name>\n");
|
||||
return -1;
|
||||
}
|
||||
name = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "vg_lookup",
|
||||
"name = %s", name,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_lookup_uuid")) {
|
||||
if (argc < 3) {
|
||||
printf("vg_lookup_uuid <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "vg_lookup",
|
||||
"uuid = %s", uuid,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_lock_type")) {
|
||||
struct dm_config_node *metadata;
|
||||
const char *lock_type;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("vg_lock_type <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "vg_lookup",
|
||||
"uuid = %s", uuid,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
/* printf("%s\n", reply.buffer.mem); */
|
||||
|
||||
metadata = dm_config_find_node(reply.cft->root, "metadata");
|
||||
if (!metadata) {
|
||||
printf("no metadata\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL);
|
||||
if (!lock_type) {
|
||||
printf("no lock_type\n");
|
||||
goto out;
|
||||
}
|
||||
printf("lock_type %s\n", lock_type);
|
||||
|
||||
} else if (!strcmp(cmd, "pv_lookup_uuid")) {
|
||||
if (argc < 3) {
|
||||
printf("pv_lookup_uuid <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "pv_lookup",
|
||||
"uuid = %s", uuid,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else {
|
||||
printf("unknown command\n");
|
||||
goto out_close;
|
||||
}
|
||||
out:
|
||||
daemon_reply_destroy(reply);
|
||||
out_close:
|
||||
daemon_close(h);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_LVMETAD_CLIENT_H
|
||||
#define _LVM_LVMETAD_CLIENT_H
|
||||
|
||||
#include "daemon-client.h"
|
||||
|
||||
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
|
||||
|
||||
#define LVMETAD_TOKEN_UPDATE_IN_PROGRESS "update in progress"
|
||||
|
||||
#define LVMETAD_DISABLE_REASON_DIRECT "DIRECT"
|
||||
#define LVMETAD_DISABLE_REASON_DUPLICATES "DUPLICATES"
|
||||
#define LVMETAD_DISABLE_REASON_VGRESTORE "VGRESTORE"
|
||||
#define LVMETAD_DISABLE_REASON_REPAIR "REPAIR"
|
||||
|
||||
struct volume_group;
|
||||
|
||||
/* Different types of replies we may get from lvmetad. */
|
||||
|
||||
typedef struct {
|
||||
daemon_reply r;
|
||||
const char **uuids; /* NULL terminated array */
|
||||
} lvmetad_uuidlist;
|
||||
|
||||
typedef struct {
|
||||
daemon_reply r;
|
||||
struct dm_config_tree *cft;
|
||||
} lvmetad_vg;
|
||||
|
||||
/* Get a list of VG UUIDs that match a given VG name. */
|
||||
lvmetad_uuidlist lvmetad_lookup_vgname(daemon_handle h, const char *name);
|
||||
|
||||
/* Get the metadata of a single VG, identified by UUID. */
|
||||
lvmetad_vg lvmetad_get_vg(daemon_handle h, const char *uuid);
|
||||
|
||||
/*
|
||||
* Add and remove PVs on demand. Udev-driven systems will use this interface
|
||||
* instead of scanning.
|
||||
*/
|
||||
daemon_reply lvmetad_add_pv(daemon_handle h, const char *pv_uuid, const char *mda_content);
|
||||
daemon_reply lvmetad_remove_pv(daemon_handle h, const char *pv_uuid);
|
||||
|
||||
/* Trigger a full disk scan, throwing away all caches. XXX do we eventually want
|
||||
* this? Probably not yet, anyway.
|
||||
* daemon_reply lvmetad_rescan(daemon_handle h);
|
||||
*/
|
||||
|
||||
/*
|
||||
* Update the version of metadata of a volume group. The VG has to be locked for
|
||||
* writing for this, and the VG metadata here has to match whatever has been
|
||||
* written to the disk (under this lock). This initially avoids the requirement
|
||||
* for lvmetad to write to disk (in later revisions, lvmetad_supersede_vg may
|
||||
* also do the writing, or we probably add another function to do that).
|
||||
*/
|
||||
daemon_reply lvmetad_supersede_vg(daemon_handle h, struct volume_group *vg);
|
||||
|
||||
/* Wrappers to open/close connection */
|
||||
|
||||
static inline daemon_handle lvmetad_open(const char *socket)
|
||||
{
|
||||
daemon_info lvmetad_info = {
|
||||
.path = "lvmetad",
|
||||
.socket = socket ?: LVMETAD_SOCKET,
|
||||
.protocol = "lvmetad",
|
||||
.protocol_version = 1,
|
||||
.autostart = 0
|
||||
};
|
||||
|
||||
return daemon_open(lvmetad_info);
|
||||
}
|
||||
|
||||
static inline void lvmetad_close(daemon_handle h)
|
||||
{
|
||||
return daemon_close(h);
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LD_LIBRARY_PATH="$1"
|
||||
|
||||
test -n "$2" && {
|
||||
rm -f /var/run/lvmetad.{socket,pid}
|
||||
chmod +rx lvmetad
|
||||
valgrind ./lvmetad -f &
|
||||
PID=$!
|
||||
sleep 1
|
||||
./testclient
|
||||
kill $PID
|
||||
exit 0
|
||||
}
|
||||
|
||||
sudo ./test.sh "$1" .
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2014 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvmetad-client.h"
|
||||
#include "label.h"
|
||||
#include "lvmcache.h"
|
||||
#include "metadata.h"
|
||||
|
||||
const char *uuid1 = "abcd-efgh";
|
||||
const char *uuid2 = "bbcd-efgh";
|
||||
const char *vgid = "yada-yada";
|
||||
const char *uuid3 = "cbcd-efgh";
|
||||
|
||||
const char *metadata2 = "{\n"
|
||||
"id = \"yada-yada\"\n"
|
||||
"seqno = 15\n"
|
||||
"status = [\"READ\", \"WRITE\"]\n"
|
||||
"flags = []\n"
|
||||
"extent_size = 8192\n"
|
||||
"physical_volumes {\n"
|
||||
" pv0 {\n"
|
||||
" id = \"abcd-efgh\"\n"
|
||||
" }\n"
|
||||
" pv1 {\n"
|
||||
" id = \"bbcd-efgh\"\n"
|
||||
" }\n"
|
||||
" pv2 {\n"
|
||||
" id = \"cbcd-efgh\"\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"}\n";
|
||||
|
||||
void _handle_reply(daemon_reply reply) {
|
||||
const char *repl = daemon_reply_str(reply, "response", NULL);
|
||||
const char *status = daemon_reply_str(reply, "status", NULL);
|
||||
const char *vgid = daemon_reply_str(reply, "vgid", NULL);
|
||||
|
||||
fprintf(stderr, "[C] REPLY: %s\n", repl);
|
||||
if (!strcmp(repl, "failed"))
|
||||
fprintf(stderr, "[C] REASON: %s\n", daemon_reply_str(reply, "reason", "unknown"));
|
||||
if (vgid)
|
||||
fprintf(stderr, "[C] VGID: %s\n", vgid);
|
||||
if (status)
|
||||
fprintf(stderr, "[C] STATUS: %s\n", status);
|
||||
daemon_reply_destroy(reply);
|
||||
}
|
||||
|
||||
void _pv_add(daemon_handle h, const char *uuid, const char *metadata)
|
||||
{
|
||||
daemon_reply reply = daemon_send_simple(h, "pv_add", "uuid = %s", uuid,
|
||||
"metadata = %b", metadata,
|
||||
NULL);
|
||||
_handle_reply(reply);
|
||||
}
|
||||
|
||||
int scan(daemon_handle h, char *fn) {
|
||||
struct device *dev = dev_cache_get(fn, NULL);
|
||||
|
||||
struct label *label;
|
||||
if (!label_read(dev, &label, 0)) {
|
||||
fprintf(stderr, "[C] no label found on %s\n", fn);
|
||||
return;
|
||||
}
|
||||
|
||||
char uuid[64];
|
||||
if (!id_write_format(dev->pvid, uuid, 64)) {
|
||||
fprintf(stderr, "[C] Failed to format PV UUID for %s", dev_name(dev));
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "[C] found PV: %s\n", uuid);
|
||||
struct lvmcache_info *info = (struct lvmcache_info *) label->info;
|
||||
struct physical_volume pv = { 0, };
|
||||
|
||||
if (!(info->fmt->ops->pv_read(info->fmt, dev_name(dev), &pv, 0))) {
|
||||
fprintf(stderr, "[C] Failed to read PV %s", dev_name(dev));
|
||||
return;
|
||||
}
|
||||
|
||||
struct format_instance_ctx fic;
|
||||
struct format_instance *fid = info->fmt->ops->create_instance(info->fmt, &fic);
|
||||
struct metadata_area *mda;
|
||||
struct volume_group *vg = NULL;
|
||||
dm_list_iterate_items(mda, &info->mdas) {
|
||||
struct volume_group *this = mda->ops->vg_read(fid, "", mda);
|
||||
if (this && !vg || this->seqno > vg->seqno)
|
||||
vg = this;
|
||||
}
|
||||
if (vg) {
|
||||
char *buf = NULL;
|
||||
/* TODO. This is not entirely correct, since export_vg_to_buffer
|
||||
* adds trailing garbage to the buffer. We may need to use
|
||||
* export_vg_to_config_tree and format the buffer ourselves. It
|
||||
* does, however, work for now, since the garbage is well
|
||||
* formatted and has no conflicting keys with the rest of the
|
||||
* request. */
|
||||
export_vg_to_buffer(vg, &buf);
|
||||
daemon_reply reply =
|
||||
daemon_send_simple(h, "pv_add", "uuid = %s", uuid,
|
||||
"metadata = %b", strchr(buf, '{'),
|
||||
NULL);
|
||||
_handle_reply(reply);
|
||||
}
|
||||
}
|
||||
|
||||
void _dump_vg(daemon_handle h, const char *uuid)
|
||||
{
|
||||
daemon_reply reply = daemon_send_simple(h, "vg_by_uuid", "uuid = %s", uuid, NULL);
|
||||
fprintf(stderr, "[C] reply buffer: %s\n", reply.buffer);
|
||||
daemon_reply_destroy(reply);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
daemon_handle h = lvmetad_open();
|
||||
/* FIXME Missing error path */
|
||||
|
||||
if (argc > 1) {
|
||||
int i;
|
||||
struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0, 1, 1);
|
||||
for (i = 1; i < argc; ++i) {
|
||||
const char *uuid = NULL;
|
||||
scan(h, argv[i]);
|
||||
}
|
||||
destroy_toolcontext(cmd);
|
||||
/* FIXME Missing lvmetad_close() */
|
||||
return 0;
|
||||
}
|
||||
|
||||
_pv_add(h, uuid1, NULL);
|
||||
_pv_add(h, uuid2, metadata2);
|
||||
_dump_vg(h, vgid);
|
||||
_pv_add(h, uuid3, NULL);
|
||||
|
||||
daemon_close(h); /* FIXME lvmetad_close? */
|
||||
return 0;
|
||||
}
|
||||
@@ -38,14 +38,14 @@ include $(top_builddir)/make.tmpl
|
||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
|
||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
||||
|
||||
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LOCK_LIBS) -ldaemonserver $(LIBS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LOCK_LIBS) -ldaemonserver $(INTERNAL_LIBS) $(LIBS)
|
||||
|
||||
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(LIBS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(INTERNAL_LIBS) $(LIBS)
|
||||
|
||||
install_lvmlockd: lvmlockd
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*/
|
||||
|
||||
#include "tool.h"
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "lvmlockd-client.h"
|
||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <getopt.h>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#ifndef _LVM_LVMLOCKD_CLIENT_H
|
||||
#define _LVM_LVMLOCKD_CLIENT_H
|
||||
|
||||
#include "daemon-client.h"
|
||||
#include "libdaemon/client/daemon-client.h"
|
||||
|
||||
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
|
||||
|
||||
@@ -22,9 +22,9 @@ static inline daemon_handle lvmlockd_open(const char *sock)
|
||||
daemon_info lvmlockd_info = {
|
||||
.path = "lvmlockd",
|
||||
.socket = sock ?: LVMLOCKD_SOCKET,
|
||||
.autostart = 0,
|
||||
.protocol = "lvmlockd",
|
||||
.protocol_version = 1,
|
||||
.autostart = 0
|
||||
};
|
||||
|
||||
return daemon_open(lvmlockd_info);
|
||||
@@ -32,7 +32,7 @@ static inline daemon_handle lvmlockd_open(const char *sock)
|
||||
|
||||
static inline void lvmlockd_close(daemon_handle h)
|
||||
{
|
||||
daemon_close(h);
|
||||
return daemon_close(h);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -12,14 +12,13 @@
|
||||
#define _ISOC99_SOURCE
|
||||
#define _REENTRANT
|
||||
|
||||
#include "tool.h"
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "daemon-io.h"
|
||||
#include "libdaemon/client/daemon-io.h"
|
||||
#include "daemon-server.h"
|
||||
#include "lvm-version.h"
|
||||
#include "lvmetad-client.h"
|
||||
#include "lvmlockd-client.h"
|
||||
#include "dm-ioctl.h" /* for DM_UUID_LEN */
|
||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
||||
#include "device_mapper/misc/dm-ioctl.h"
|
||||
|
||||
/* #include <assert.h> */
|
||||
#include <errno.h>
|
||||
@@ -144,10 +143,6 @@ static const int lvmlockd_protocol_version = 1;
|
||||
static int daemon_quit;
|
||||
static int adopt_opt;
|
||||
|
||||
static daemon_handle lvmetad_handle;
|
||||
static pthread_mutex_t lvmetad_mutex;
|
||||
static int lvmetad_connected;
|
||||
|
||||
/*
|
||||
* We use a separate socket for dumping daemon info.
|
||||
* This will not interfere with normal operations, and allows
|
||||
@@ -1009,54 +1004,6 @@ static void add_work_action(struct action *act)
|
||||
pthread_mutex_unlock(&worker_mutex);
|
||||
}
|
||||
|
||||
#define ERR_LVMETAD_NOT_RUNNING -200
|
||||
|
||||
static daemon_reply send_lvmetad(const char *id, ...)
|
||||
{
|
||||
daemon_reply reply;
|
||||
va_list ap;
|
||||
int retries = 0;
|
||||
int err;
|
||||
|
||||
va_start(ap, id);
|
||||
|
||||
/*
|
||||
* mutex is used because all threads share a single
|
||||
* lvmetad connection/handle.
|
||||
*/
|
||||
pthread_mutex_lock(&lvmetad_mutex);
|
||||
retry:
|
||||
if (!lvmetad_connected) {
|
||||
lvmetad_handle = lvmetad_open(NULL);
|
||||
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0) {
|
||||
err = lvmetad_handle.error ?: lvmetad_handle.socket_fd;
|
||||
pthread_mutex_unlock(&lvmetad_mutex);
|
||||
log_debug("lvmetad_open reconnect error %d", err);
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
reply.error = ERR_LVMETAD_NOT_RUNNING;
|
||||
va_end(ap);
|
||||
return reply;
|
||||
} else {
|
||||
log_debug("lvmetad reconnected");
|
||||
lvmetad_connected = 1;
|
||||
}
|
||||
}
|
||||
|
||||
reply = daemon_send_simple_v(lvmetad_handle, id, ap);
|
||||
|
||||
/* lvmetad may have been restarted */
|
||||
if ((reply.error == ECONNRESET) && (retries < 2)) {
|
||||
daemon_close(lvmetad_handle);
|
||||
lvmetad_connected = 0;
|
||||
retries++;
|
||||
goto retry;
|
||||
}
|
||||
pthread_mutex_unlock(&lvmetad_mutex);
|
||||
|
||||
va_end(ap);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static int res_lock(struct lockspace *ls, struct resource *r, struct action *act, int *retry)
|
||||
{
|
||||
struct lock *lk;
|
||||
@@ -1252,6 +1199,18 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
|
||||
rv = -EREMOVED;
|
||||
}
|
||||
|
||||
/*
|
||||
* lvmetad is no longer used, but the infrastructure for
|
||||
* distributed cache validation remains. The points
|
||||
* where vg or global cache state would be invalidated
|
||||
* remain below and log_debug messages point out where
|
||||
* they would occur.
|
||||
*
|
||||
* The comments related to "lvmetad" remain because they
|
||||
* describe how some other local cache like lvmetad would
|
||||
* be invalidated here.
|
||||
*/
|
||||
|
||||
/*
|
||||
* r is vglk: tell lvmetad to set the vg invalid
|
||||
* flag, and provide the new r_version. If lvmetad finds
|
||||
@@ -1277,47 +1236,12 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
|
||||
*/
|
||||
|
||||
if (inval_meta && (r->type == LD_RT_VG)) {
|
||||
daemon_reply reply;
|
||||
char *uuid;
|
||||
|
||||
log_debug("S %s R %s res_lock set lvmetad vg version %u",
|
||||
log_debug("S %s R %s res_lock invalidate vg state version %u",
|
||||
ls->name, r->name, new_version);
|
||||
|
||||
if (!ls->vg_uuid[0] || !strcmp(ls->vg_uuid, "none"))
|
||||
uuid = (char *)"none";
|
||||
else
|
||||
uuid = ls->vg_uuid;
|
||||
|
||||
reply = send_lvmetad("set_vg_info",
|
||||
"token = %s", "skip",
|
||||
"uuid = %s", uuid,
|
||||
"name = %s", ls->vg_name,
|
||||
"version = " FMTd64, (int64_t)new_version,
|
||||
NULL);
|
||||
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
|
||||
if (reply.error != ERR_LVMETAD_NOT_RUNNING)
|
||||
log_error("set_vg_info in lvmetad failed %d", reply.error);
|
||||
}
|
||||
daemon_reply_destroy(reply);
|
||||
}
|
||||
|
||||
if (inval_meta && (r->type == LD_RT_GL)) {
|
||||
daemon_reply reply;
|
||||
|
||||
log_debug("S %s R %s res_lock set lvmetad global invalid",
|
||||
ls->name, r->name);
|
||||
|
||||
reply = send_lvmetad("set_global_info",
|
||||
"token = %s", "skip",
|
||||
"global_invalid = " FMTd64, INT64_C(1),
|
||||
NULL);
|
||||
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
|
||||
if (reply.error != ERR_LVMETAD_NOT_RUNNING)
|
||||
log_error("set_global_info in lvmetad failed %d", reply.error);
|
||||
}
|
||||
daemon_reply_destroy(reply);
|
||||
log_debug("S %s R %s res_lock invalidate global state", ls->name, r->name);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2815,9 +2739,6 @@ static int add_lockspace_thread(const char *ls_name,
|
||||
if (ls2->thread_stop) {
|
||||
log_debug("add_lockspace_thread %s exists and stopping", ls->name);
|
||||
rv = -EAGAIN;
|
||||
} else if (!ls2->create_fail && !ls2->create_done) {
|
||||
log_debug("add_lockspace_thread %s exists and starting", ls->name);
|
||||
rv = -ESTARTING;
|
||||
} else {
|
||||
log_debug("add_lockspace_thread %s exists", ls->name);
|
||||
rv = -EEXIST;
|
||||
@@ -3059,7 +2980,7 @@ static int count_lockspace_starting(uint32_t client_id)
|
||||
|
||||
pthread_mutex_lock(&lockspaces_mutex);
|
||||
list_for_each_entry(ls, &lockspaces, list) {
|
||||
if (client_id && (ls->start_client_id != client_id))
|
||||
if (ls->start_client_id != client_id)
|
||||
continue;
|
||||
|
||||
if (!ls->create_done && !ls->create_fail) {
|
||||
@@ -3460,7 +3381,7 @@ static void *worker_thread_main(void *arg_in)
|
||||
add_client_result(act);
|
||||
|
||||
} else if (act->op == LD_OP_START_WAIT) {
|
||||
act->result = count_lockspace_starting(0);
|
||||
act->result = count_lockspace_starting(act->client_id);
|
||||
if (!act->result)
|
||||
add_client_result(act);
|
||||
else
|
||||
@@ -3494,7 +3415,7 @@ static void *worker_thread_main(void *arg_in)
|
||||
list_for_each_entry_safe(act, safe, &delayed_list, list) {
|
||||
if (act->op == LD_OP_START_WAIT) {
|
||||
log_debug("work delayed start_wait for client %u", act->client_id);
|
||||
act->result = count_lockspace_starting(0);
|
||||
act->result = count_lockspace_starting(act->client_id);
|
||||
if (!act->result) {
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
@@ -4830,7 +4751,7 @@ static void close_client_thread(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a list of all VGs with a lockd type (sanlock|dlm) from lvmetad.
|
||||
* Get a list of all VGs with a lockd type (sanlock|dlm).
|
||||
* We'll match this list against a list of existing lockspaces that are
|
||||
* found in the lock manager.
|
||||
*
|
||||
@@ -4841,6 +4762,9 @@ static void close_client_thread(void)
|
||||
|
||||
static int get_lockd_vgs(struct list_head *vg_lockd)
|
||||
{
|
||||
/* FIXME: get VGs some other way */
|
||||
return -1;
|
||||
#if 0
|
||||
struct list_head update_vgs;
|
||||
daemon_reply reply;
|
||||
struct dm_config_node *cn;
|
||||
@@ -4997,6 +4921,7 @@ out:
|
||||
}
|
||||
|
||||
return rv;
|
||||
#endif
|
||||
}
|
||||
|
||||
static char _dm_uuid[DM_UUID_LEN];
|
||||
@@ -5271,7 +5196,7 @@ static void adopt_locks(void)
|
||||
gl_use_sanlock = 1;
|
||||
|
||||
list_for_each_entry(ls, &vg_lockd, list) {
|
||||
log_debug("adopt lvmetad vg %s lock_type %s lock_args %s",
|
||||
log_debug("adopt vg %s lock_type %s lock_args %s",
|
||||
ls->vg_name, lm_str(ls->lm_type), ls->vg_args);
|
||||
|
||||
list_for_each_entry(r, &ls->resources, list)
|
||||
@@ -5336,7 +5261,7 @@ static void adopt_locks(void)
|
||||
/*
|
||||
* LS in ls_found, not in vg_lockd.
|
||||
* An lvm lockspace found in the lock manager has no
|
||||
* corresponding VG in lvmetad. This shouldn't usually
|
||||
* corresponding VG. This shouldn't usually
|
||||
* happen, but it's possible the VG could have been removed
|
||||
* while the orphaned lockspace from it was still around.
|
||||
* Report an error and leave the ls in the lm alone.
|
||||
@@ -5351,7 +5276,7 @@ static void adopt_locks(void)
|
||||
|
||||
/*
|
||||
* LS in vg_lockd, not in ls_found.
|
||||
* lockd vgs from lvmetad that do not have an existing lockspace.
|
||||
* lockd vgs that do not have an existing lockspace.
|
||||
* This wouldn't be unusual; we just skip the vg.
|
||||
* But, if the vg has active lvs, then it should have had locks
|
||||
* and a lockspace. Should we attempt to join the lockspace and
|
||||
@@ -5403,8 +5328,6 @@ static void adopt_locks(void)
|
||||
memcpy(act->vg_args, ls->vg_args, MAX_ARGS);
|
||||
act->host_id = ls->host_id;
|
||||
|
||||
/* set act->version from lvmetad data? */
|
||||
|
||||
log_debug("adopt add %s vg lockspace %s", lm_str(act->lm_type), act->vg_name);
|
||||
|
||||
rv = add_lockspace_thread(ls->name, act->vg_name, act->vg_uuid,
|
||||
@@ -5863,24 +5786,12 @@ static int main_loop(daemon_state *ds_arg)
|
||||
setup_worker_thread();
|
||||
setup_restart();
|
||||
|
||||
pthread_mutex_init(&lvmetad_mutex, NULL);
|
||||
lvmetad_handle = lvmetad_open(NULL);
|
||||
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0)
|
||||
log_debug("lvmetad_open error %d", lvmetad_handle.error);
|
||||
else
|
||||
lvmetad_connected = 1;
|
||||
|
||||
/*
|
||||
* Attempt to rejoin lockspaces and adopt locks from a previous
|
||||
* instance of lvmlockd that left behind lockspaces/locks.
|
||||
*/
|
||||
if (adopt_opt) {
|
||||
/* FIXME: implement this without lvmetad */
|
||||
if (!lvmetad_connected)
|
||||
log_error("Cannot adopt locks without lvmetad running.");
|
||||
else
|
||||
adopt_locks();
|
||||
}
|
||||
if (adopt_opt)
|
||||
adopt_locks();
|
||||
|
||||
while (1) {
|
||||
rv = poll(pollfd, pollfd_maxi + 1, -1);
|
||||
@@ -5996,7 +5907,6 @@ static int main_loop(daemon_state *ds_arg)
|
||||
close_worker_thread();
|
||||
close_client_thread();
|
||||
closelog();
|
||||
daemon_close(lvmetad_handle);
|
||||
return 1; /* libdaemon uses 1 for success */
|
||||
}
|
||||
|
||||
@@ -6035,14 +5945,14 @@ static void usage(char *prog, FILE *file)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
daemon_state ds = {
|
||||
.name = "lvmlockd",
|
||||
.daemon_main = main_loop,
|
||||
.daemon_init = NULL,
|
||||
.daemon_fini = NULL,
|
||||
.pidfile = getenv("LVM_LVMLOCKD_PIDFILE"),
|
||||
.socket_path = getenv("LVM_LVMLOCKD_SOCKET"),
|
||||
.protocol = lvmlockd_protocol,
|
||||
.protocol_version = lvmlockd_protocol_version,
|
||||
.daemon_init = NULL,
|
||||
.daemon_fini = NULL,
|
||||
.daemon_main = main_loop,
|
||||
.name = "lvmlockd",
|
||||
};
|
||||
|
||||
static struct option long_options[] = {
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
#define _XOPEN_SOURCE 500 /* pthread */
|
||||
#define _ISOC99_SOURCE
|
||||
|
||||
#include "tool.h"
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "daemon-server.h"
|
||||
#include "xlate.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
|
||||
#include "lvmlockd-internal.h"
|
||||
#include "lvmlockd-client.h"
|
||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
||||
|
||||
/*
|
||||
* Using synchronous _wait dlm apis so do not define _REENTRANT and
|
||||
|
||||
@@ -151,7 +151,7 @@ struct resource {
|
||||
struct list_head locks;
|
||||
struct list_head actions;
|
||||
char lv_args[MAX_ARGS+1];
|
||||
char lm_data[]; /* lock manager specific data */
|
||||
char lm_data[0]; /* lock manager specific data */
|
||||
};
|
||||
|
||||
#define LD_LF_PERSISTENT 0x00000001
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
#define _XOPEN_SOURCE 500 /* pthread */
|
||||
#define _ISOC99_SOURCE
|
||||
|
||||
#include "tool.h"
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "daemon-server.h"
|
||||
#include "xlate.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
|
||||
#include "lvmlockd-internal.h"
|
||||
#include "lvmlockd-client.h"
|
||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
||||
|
||||
#include "sanlock.h"
|
||||
#include "sanlock_rv.h"
|
||||
|
||||
@@ -30,11 +30,11 @@ include $(top_builddir)/make.tmpl
|
||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(DAEMON_LIBS) -ldaemonserver -ldevmapper $(PTHREAD_LIBS)
|
||||
LIBS += $(DAEMON_LIBS) -ldaemonserver $(PTHREAD_LIBS)
|
||||
|
||||
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(INTERNAL_LIBS) $(LIBS)
|
||||
|
||||
install_lvmpolld: lvmpolld
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
|
||||
@@ -36,7 +36,7 @@ static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
|
||||
const char **newargv;
|
||||
|
||||
if (*ind && !(*ind % MIN_ARGV_SIZE)) {
|
||||
newargv = dm_realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
|
||||
newargv = realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
|
||||
if (!newargv)
|
||||
return 0;
|
||||
*cmdargv = newargv;
|
||||
@@ -50,7 +50,7 @@ static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
|
||||
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort_polling, unsigned handle_missing_pvs)
|
||||
{
|
||||
unsigned i = 0;
|
||||
const char **cmd_argv = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||
const char **cmd_argv = malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||
|
||||
if (!cmd_argv)
|
||||
return NULL;
|
||||
@@ -98,7 +98,7 @@ const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary,
|
||||
|
||||
return cmd_argv;
|
||||
err:
|
||||
dm_free(cmd_argv);
|
||||
free(cmd_argv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ static int copy_env(const char ***cmd_envp, unsigned *i, const char *exclude)
|
||||
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
unsigned i = 0;
|
||||
const char **cmd_envp = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||
const char **cmd_envp = malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||
|
||||
if (!cmd_envp)
|
||||
return NULL;
|
||||
@@ -141,6 +141,6 @@ const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
|
||||
|
||||
return cmd_envp;
|
||||
err:
|
||||
dm_free(cmd_envp);
|
||||
free(cmd_envp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
|
||||
#define _REENTRANT
|
||||
|
||||
#include "tool.h"
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "lvmpolld-cmd-utils.h"
|
||||
#include "lvmpolld-protocol.h"
|
||||
#include "daemons/lvmpolld/lvmpolld-protocol.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -530,7 +530,7 @@ static response progress_info(client_handle h, struct lvmpolld_state *ls, reques
|
||||
|
||||
pdst_unlock(pdst);
|
||||
|
||||
dm_free(id);
|
||||
free(id);
|
||||
|
||||
if (pdlv) {
|
||||
if (st.error)
|
||||
@@ -673,7 +673,7 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
||||
PD_LOG_PREFIX, "poll operation type mismatch on LV identified by",
|
||||
id,
|
||||
polling_op(pdlv_get_type(pdlv)), polling_op(type));
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return reply(LVMPD_RESP_EINVAL,
|
||||
REASON_DIFFERENT_OPERATION_IN_PROGRESS);
|
||||
}
|
||||
@@ -683,14 +683,14 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
||||
lvname, sysdir, type, abort_polling, 2 * uinterval);
|
||||
if (!pdlv) {
|
||||
pdst_unlock(pdst);
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||
}
|
||||
if (!pdst_locked_insert(pdst, id, pdlv)) {
|
||||
pdlv_destroy(pdlv);
|
||||
pdst_unlock(pdst);
|
||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "couldn't store internal LV data structure");
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||
}
|
||||
if (!spawn_detached_thread(pdlv)) {
|
||||
@@ -698,7 +698,7 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
||||
pdst_locked_remove(pdst, id);
|
||||
pdlv_destroy(pdlv);
|
||||
pdst_unlock(pdst);
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||
}
|
||||
|
||||
@@ -709,7 +709,7 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
||||
|
||||
pdst_unlock(pdst);
|
||||
|
||||
dm_free(id);
|
||||
free(id);
|
||||
|
||||
return daemon_reply_simple(LVMPD_RESP_OK, NULL);
|
||||
}
|
||||
@@ -806,7 +806,7 @@ static int printout_raw_response(const char *prefix, const char *msg)
|
||||
char *buf;
|
||||
char *pos;
|
||||
|
||||
buf = dm_strdup(msg);
|
||||
buf = strdup(msg);
|
||||
pos = buf;
|
||||
|
||||
if (!buf)
|
||||
@@ -819,7 +819,7 @@ static int printout_raw_response(const char *prefix, const char *msg)
|
||||
_log_line(pos, &b);
|
||||
pos = next ? next + 1 : 0;
|
||||
}
|
||||
dm_free(buf);
|
||||
free(buf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -915,7 +915,7 @@ int main(int argc, char *argv[])
|
||||
int option_index = 0;
|
||||
int client = 0, server = 0;
|
||||
unsigned action = ACTION_MAX;
|
||||
struct timespec timeout;
|
||||
struct timeval timeout;
|
||||
daemon_idle di = { .ptimeout = &timeout };
|
||||
struct lvmpolld_state ls = { .log_config = "" };
|
||||
daemon_state s = {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include "lvmpolld-common.h"
|
||||
|
||||
#include "config-util.h"
|
||||
#include "libdaemon/client/config-util.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
@@ -27,12 +27,12 @@ static char *_construct_full_lvname(const char *vgname, const char *lvname)
|
||||
size_t l;
|
||||
|
||||
l = strlen(vgname) + strlen(lvname) + 2; /* vg/lv and \0 */
|
||||
name = (char *) dm_malloc(l * sizeof(char));
|
||||
name = (char *) malloc(l * sizeof(char));
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
if (dm_snprintf(name, l, "%s/%s", vgname, lvname) < 0) {
|
||||
dm_free(name);
|
||||
free(name);
|
||||
name = NULL;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ static char *_construct_lvm_system_dir_env(const char *sysdir)
|
||||
* just single char to store NULL byte
|
||||
*/
|
||||
size_t l = sysdir ? strlen(sysdir) + 16 : 1;
|
||||
char *env = (char *) dm_malloc(l * sizeof(char));
|
||||
char *env = (char *) malloc(l * sizeof(char));
|
||||
|
||||
if (!env)
|
||||
return NULL;
|
||||
@@ -55,7 +55,7 @@ static char *_construct_lvm_system_dir_env(const char *sysdir)
|
||||
*env = '\0';
|
||||
|
||||
if (sysdir && dm_snprintf(env, l, "%s%s", LVM_SYSTEM_DIR, sysdir) < 0) {
|
||||
dm_free(env);
|
||||
free(env);
|
||||
env = NULL;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ char *construct_id(const char *sysdir, const char *uuid)
|
||||
size_t l;
|
||||
|
||||
l = strlen(uuid) + (sysdir ? strlen(sysdir) : 0) + 1;
|
||||
id = (char *) dm_malloc(l * sizeof(char));
|
||||
id = (char *) malloc(l * sizeof(char));
|
||||
if (!id)
|
||||
return NULL;
|
||||
|
||||
@@ -82,7 +82,7 @@ char *construct_id(const char *sysdir, const char *uuid)
|
||||
dm_snprintf(id, l, "%s", uuid);
|
||||
|
||||
if (r < 0) {
|
||||
dm_free(id);
|
||||
free(id);
|
||||
id = NULL;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
const char *sinterval, unsigned pdtimeout,
|
||||
struct lvmpolld_store *pdst)
|
||||
{
|
||||
char *lvmpolld_id = dm_strdup(id), /* copy */
|
||||
char *lvmpolld_id = strdup(id), /* copy */
|
||||
*full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
|
||||
*lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
|
||||
|
||||
@@ -106,12 +106,12 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
.lvid = _get_lvid(lvmpolld_id, sysdir),
|
||||
.lvname = full_lvname,
|
||||
.lvm_system_dir_env = lvm_system_dir_env,
|
||||
.sinterval = dm_strdup(sinterval), /* copy */
|
||||
.sinterval = strdup(sinterval), /* copy */
|
||||
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
|
||||
.cmd_state = { .retcode = -1, .signal = 0 },
|
||||
.pdst = pdst,
|
||||
.init_rq_count = 1
|
||||
}, *pdlv = (struct lvmpolld_lv *) dm_malloc(sizeof(struct lvmpolld_lv));
|
||||
}, *pdlv = (struct lvmpolld_lv *) malloc(sizeof(struct lvmpolld_lv));
|
||||
|
||||
if (!pdlv || !tmp.lvid || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
|
||||
goto err;
|
||||
@@ -124,27 +124,27 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
return pdlv;
|
||||
|
||||
err:
|
||||
dm_free((void *)full_lvname);
|
||||
dm_free((void *)lvmpolld_id);
|
||||
dm_free((void *)lvm_system_dir_env);
|
||||
dm_free((void *)tmp.sinterval);
|
||||
dm_free((void *)pdlv);
|
||||
free((void *)full_lvname);
|
||||
free((void *)lvmpolld_id);
|
||||
free((void *)lvm_system_dir_env);
|
||||
free((void *)tmp.sinterval);
|
||||
free((void *)pdlv);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pdlv_destroy(struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
dm_free((void *)pdlv->lvmpolld_id);
|
||||
dm_free((void *)pdlv->lvname);
|
||||
dm_free((void *)pdlv->sinterval);
|
||||
dm_free((void *)pdlv->lvm_system_dir_env);
|
||||
dm_free((void *)pdlv->cmdargv);
|
||||
dm_free((void *)pdlv->cmdenvp);
|
||||
free((void *)pdlv->lvmpolld_id);
|
||||
free((void *)pdlv->lvname);
|
||||
free((void *)pdlv->sinterval);
|
||||
free((void *)pdlv->lvm_system_dir_env);
|
||||
free((void *)pdlv->cmdargv);
|
||||
free((void *)pdlv->cmdenvp);
|
||||
|
||||
pthread_mutex_destroy(&pdlv->lock);
|
||||
|
||||
dm_free((void *)pdlv);
|
||||
free((void *)pdlv);
|
||||
}
|
||||
|
||||
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)
|
||||
@@ -194,7 +194,7 @@ void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished)
|
||||
|
||||
struct lvmpolld_store *pdst_init(const char *name)
|
||||
{
|
||||
struct lvmpolld_store *pdst = (struct lvmpolld_store *) dm_malloc(sizeof(struct lvmpolld_store));
|
||||
struct lvmpolld_store *pdst = (struct lvmpolld_store *) malloc(sizeof(struct lvmpolld_store));
|
||||
if (!pdst)
|
||||
return NULL;
|
||||
|
||||
@@ -212,7 +212,7 @@ struct lvmpolld_store *pdst_init(const char *name)
|
||||
err_mutex:
|
||||
dm_hash_destroy(pdst->store);
|
||||
err_hash:
|
||||
dm_free(pdst);
|
||||
free(pdst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ void pdst_destroy(struct lvmpolld_store *pdst)
|
||||
|
||||
dm_hash_destroy(pdst->store);
|
||||
pthread_mutex_destroy(&pdst->lock);
|
||||
dm_free(pdst);
|
||||
free(pdst);
|
||||
}
|
||||
|
||||
void pdst_locked_lock_all_pdlvs(const struct lvmpolld_store *pdst)
|
||||
@@ -321,7 +321,7 @@ void pdst_locked_destroy_all_pdlvs(const struct lvmpolld_store *pdst)
|
||||
|
||||
struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) dm_malloc(sizeof(struct lvmpolld_thread_data));
|
||||
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) malloc(sizeof(struct lvmpolld_thread_data));
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
@@ -368,7 +368,7 @@ void lvmpolld_thread_data_destroy(void *thread_private)
|
||||
pdst_unlock(data->pdlv->pdst);
|
||||
}
|
||||
|
||||
/* may get reallocated in getline(). dm_free must not be used */
|
||||
/* may get reallocated in getline(). free must not be used */
|
||||
free(data->line);
|
||||
|
||||
if (data->fout && !fclose(data->fout))
|
||||
@@ -389,5 +389,5 @@ void lvmpolld_thread_data_destroy(void *thread_private)
|
||||
if (data->errpipe[1] >= 0)
|
||||
(void) close(data->errpipe[1]);
|
||||
|
||||
dm_free(data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#ifndef _LVM_LVMPOLLD_PROTOCOL_H
|
||||
#define _LVM_LVMPOLLD_PROTOCOL_H
|
||||
|
||||
#include "polling_ops.h"
|
||||
#include "daemons/lvmpolld/polling_ops.h"
|
||||
|
||||
#define LVMPOLLD_PROTOCOL "lvmpolld"
|
||||
#define LVMPOLLD_PROTOCOL_VERSION 1
|
||||
|
||||
52
device_mapper/Makefile
Normal file
52
device_mapper/Makefile
Normal file
@@ -0,0 +1,52 @@
|
||||
# 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
|
||||
|
||||
DEVICE_MAPPER_SOURCE=\
|
||||
device_mapper/datastruct/bitset.c \
|
||||
device_mapper/libdm-common.c \
|
||||
device_mapper/libdm-config.c \
|
||||
device_mapper/libdm-deptree.c \
|
||||
device_mapper/libdm-file.c \
|
||||
device_mapper/libdm-report.c \
|
||||
device_mapper/libdm-string.c \
|
||||
device_mapper/libdm-targets.c \
|
||||
device_mapper/libdm-timestamp.c \
|
||||
device_mapper/mm/pool.c \
|
||||
device_mapper/regex/matcher.c \
|
||||
device_mapper/regex/parse_rx.c \
|
||||
device_mapper/regex/ttree.c \
|
||||
device_mapper/ioctl/libdm-iface.c \
|
||||
device_mapper/vdo/vdo_target.c \
|
||||
device_mapper/vdo/status.c
|
||||
|
||||
DEVICE_MAPPER_DEPENDS=$(addprefix $(top_builddir)/,$(subst .c,.d,$(DEVICE_MAPPER_SOURCE)))
|
||||
DEVICE_MAPPER_OBJECTS=$(addprefix $(top_builddir)/,$(subst .c,.o,$(DEVICE_MAPPER_SOURCE)))
|
||||
CLEAN_TARGETS+=$(DEVICE_MAPPER_DEPENDS) $(DEVICE_MAPPER_OBJECTS)
|
||||
|
||||
#$(DEVICE_MAPPER_DEPENDS): INCLUDES+=$(VDO_INCLUDES)
|
||||
#$(DEVICE_MAPPER_OBJECTS): INCLUDES+=$(VDO_INCLUDES)
|
||||
|
||||
ifeq ("$(USE_TRACKING)","yes")
|
||||
ifeq (,$(findstring $(MAKECMDGOALS),cscope.out cflow clean distclean lcov \
|
||||
help check check_local check_cluster check_lvmetad check_lvmpolld))
|
||||
-include $(DEVICE_MAPPER_DEPENDS)
|
||||
endif
|
||||
endif
|
||||
|
||||
$(DEVICE_MAPPER_OBJECTS): INCLUDES+=-I$(top_srcdir)/device_mapper/
|
||||
|
||||
$(top_builddir)/device_mapper/libdevice-mapper.a: $(DEVICE_MAPPER_OBJECTS)
|
||||
@echo " [AR] $@"
|
||||
$(Q) $(RM) $@
|
||||
$(Q) $(AR) rsv $@ $(DEVICE_MAPPER_OBJECTS) > /dev/null
|
||||
|
||||
CLEAN_TARGETS+=$(top_builddir)/device_mapper/libdevice-mapper.a
|
||||
@@ -1,23 +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 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@
|
||||
|
||||
SOURCES=\
|
||||
vdo/status.c
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIB_NAME = libdevicemapper
|
||||
LIB_STATIC = $(LIB_NAME).a
|
||||
2142
device_mapper/all.h
Normal file
2142
device_mapper/all.h
Normal file
File diff suppressed because it is too large
Load Diff
259
device_mapper/datastruct/bitset.c
Normal file
259
device_mapper/datastruct/bitset.c
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 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 <ctype.h>
|
||||
|
||||
/* FIXME: calculate this. */
|
||||
#define INT_SHIFT 5
|
||||
|
||||
dm_bitset_t dm_bitset_create(struct dm_pool *mem, unsigned num_bits)
|
||||
{
|
||||
unsigned n = (num_bits / DM_BITS_PER_INT) + 2;
|
||||
size_t size = sizeof(int) * n;
|
||||
dm_bitset_t bs;
|
||||
|
||||
if (mem)
|
||||
bs = dm_pool_zalloc(mem, size);
|
||||
else
|
||||
bs = zalloc(size);
|
||||
|
||||
if (!bs)
|
||||
return NULL;
|
||||
|
||||
*bs = num_bits;
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
void dm_bitset_destroy(dm_bitset_t bs)
|
||||
{
|
||||
free(bs);
|
||||
}
|
||||
|
||||
int dm_bitset_equal(dm_bitset_t in1, dm_bitset_t in2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = (in1[0] / DM_BITS_PER_INT) + 1; i; i--)
|
||||
if (in1[i] != in2[i])
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_bit_and(dm_bitset_t out, dm_bitset_t in1, dm_bitset_t in2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = (in1[0] / DM_BITS_PER_INT) + 1; i; i--)
|
||||
out[i] = in1[i] & in2[i];
|
||||
}
|
||||
void dm_bit_union(dm_bitset_t out, dm_bitset_t in1, dm_bitset_t in2)
|
||||
{
|
||||
int i;
|
||||
for (i = (in1[0] / DM_BITS_PER_INT) + 1; i; i--)
|
||||
out[i] = in1[i] | in2[i];
|
||||
}
|
||||
|
||||
static int _test_word(uint32_t test, int bit)
|
||||
{
|
||||
uint32_t tb = test >> bit;
|
||||
|
||||
return (tb ? ffs(tb) + bit - 1 : -1);
|
||||
}
|
||||
|
||||
static int _test_word_rev(uint32_t test, int bit)
|
||||
{
|
||||
uint32_t tb = test << (DM_BITS_PER_INT - 1 - bit);
|
||||
|
||||
return (tb ? bit - clz(tb) : -1);
|
||||
}
|
||||
|
||||
int dm_bit_get_next(dm_bitset_t bs, int last_bit)
|
||||
{
|
||||
int bit, word;
|
||||
uint32_t test;
|
||||
|
||||
last_bit++; /* otherwise we'll return the same bit again */
|
||||
|
||||
/*
|
||||
* bs[0] holds number of bits
|
||||
*/
|
||||
while (last_bit < (int) bs[0]) {
|
||||
word = last_bit >> INT_SHIFT;
|
||||
test = bs[word + 1];
|
||||
bit = last_bit & (DM_BITS_PER_INT - 1);
|
||||
|
||||
if ((bit = _test_word(test, bit)) >= 0)
|
||||
return (word * DM_BITS_PER_INT) + bit;
|
||||
|
||||
last_bit = last_bit - (last_bit & (DM_BITS_PER_INT - 1)) +
|
||||
DM_BITS_PER_INT;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dm_bit_get_prev(dm_bitset_t bs, int last_bit)
|
||||
{
|
||||
int bit, word;
|
||||
uint32_t test;
|
||||
|
||||
last_bit--; /* otherwise we'll return the same bit again */
|
||||
|
||||
/*
|
||||
* bs[0] holds number of bits
|
||||
*/
|
||||
while (last_bit >= 0) {
|
||||
word = last_bit >> INT_SHIFT;
|
||||
test = bs[word + 1];
|
||||
bit = last_bit & (DM_BITS_PER_INT - 1);
|
||||
|
||||
if ((bit = _test_word_rev(test, bit)) >= 0)
|
||||
return (word * DM_BITS_PER_INT) + bit;
|
||||
|
||||
last_bit = (last_bit & ~(DM_BITS_PER_INT - 1)) - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dm_bit_get_first(dm_bitset_t bs)
|
||||
{
|
||||
return dm_bit_get_next(bs, -1);
|
||||
}
|
||||
|
||||
int dm_bit_get_last(dm_bitset_t bs)
|
||||
{
|
||||
return dm_bit_get_prev(bs, bs[0] + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Based on the Linux kernel __bitmap_parselist from lib/bitmap.c
|
||||
*/
|
||||
dm_bitset_t dm_bitset_parse_list(const char *str, struct dm_pool *mem,
|
||||
size_t min_num_bits)
|
||||
{
|
||||
unsigned a, b;
|
||||
int c, old_c, totaldigits, ndigits, nmaskbits;
|
||||
int at_start, in_range;
|
||||
dm_bitset_t mask = NULL;
|
||||
const char *start = str;
|
||||
size_t len;
|
||||
|
||||
scan:
|
||||
len = strlen(str);
|
||||
totaldigits = c = 0;
|
||||
nmaskbits = 0;
|
||||
do {
|
||||
at_start = 1;
|
||||
in_range = 0;
|
||||
a = b = 0;
|
||||
ndigits = totaldigits;
|
||||
|
||||
/* Get the next value or range of values */
|
||||
while (len) {
|
||||
old_c = c;
|
||||
c = *str++;
|
||||
len--;
|
||||
if (isspace(c))
|
||||
continue;
|
||||
|
||||
/* A '\0' or a ',' signal the end of a value or range */
|
||||
if (c == '\0' || c == ',')
|
||||
break;
|
||||
/*
|
||||
* whitespaces between digits are not allowed,
|
||||
* but it's ok if whitespaces are on head or tail.
|
||||
* when old_c is whilespace,
|
||||
* if totaldigits == ndigits, whitespace is on head.
|
||||
* if whitespace is on tail, it should not run here.
|
||||
* as c was ',' or '\0',
|
||||
* the last code line has broken the current loop.
|
||||
*/
|
||||
if ((totaldigits != ndigits) && isspace(old_c))
|
||||
goto_bad;
|
||||
|
||||
if (c == '-') {
|
||||
if (at_start || in_range)
|
||||
goto_bad;
|
||||
b = 0;
|
||||
in_range = 1;
|
||||
at_start = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isdigit(c))
|
||||
goto_bad;
|
||||
|
||||
b = b * 10 + (c - '0');
|
||||
if (!in_range)
|
||||
a = b;
|
||||
at_start = 0;
|
||||
totaldigits++;
|
||||
}
|
||||
if (ndigits == totaldigits)
|
||||
continue;
|
||||
/* if no digit is after '-', it's wrong */
|
||||
if (at_start && in_range)
|
||||
goto_bad;
|
||||
if (!(a <= b))
|
||||
goto_bad;
|
||||
if (b >= nmaskbits)
|
||||
nmaskbits = b + 1;
|
||||
while ((a <= b) && mask) {
|
||||
dm_bit_set(mask, a);
|
||||
a++;
|
||||
}
|
||||
} while (len && c == ',');
|
||||
|
||||
if (!mask) {
|
||||
if (min_num_bits && (nmaskbits < min_num_bits))
|
||||
nmaskbits = min_num_bits;
|
||||
|
||||
if (!(mask = dm_bitset_create(mem, nmaskbits)))
|
||||
goto_bad;
|
||||
str = start;
|
||||
goto scan;
|
||||
}
|
||||
|
||||
return mask;
|
||||
bad:
|
||||
if (mask) {
|
||||
if (mem)
|
||||
dm_pool_free(mem, mask);
|
||||
else
|
||||
dm_bitset_destroy(mask);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
/*
|
||||
* Maintain backward compatibility with older versions that did not
|
||||
* accept a 'min_num_bits' argument to dm_bitset_parse_list().
|
||||
*/
|
||||
dm_bitset_t dm_bitset_parse_list_v1_02_129(const char *str, struct dm_pool *mem);
|
||||
dm_bitset_t dm_bitset_parse_list_v1_02_129(const char *str, struct dm_pool *mem)
|
||||
{
|
||||
return dm_bitset_parse_list(str, mem, 0);
|
||||
}
|
||||
|
||||
#else /* if defined(__GNUC__) */
|
||||
|
||||
#endif
|
||||
2182
device_mapper/ioctl/libdm-iface.c
Normal file
2182
device_mapper/ioctl/libdm-iface.c
Normal file
File diff suppressed because it is too large
Load Diff
88
device_mapper/ioctl/libdm-targets.h
Normal file
88
device_mapper/ioctl/libdm-targets.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 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
|
||||
*/
|
||||
|
||||
#ifndef LIB_DMTARGETS_H
|
||||
#define LIB_DMTARGETS_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
struct dm_ioctl;
|
||||
|
||||
struct target {
|
||||
uint64_t start;
|
||||
uint64_t length;
|
||||
char *type;
|
||||
char *params;
|
||||
|
||||
struct target *next;
|
||||
};
|
||||
|
||||
struct dm_task {
|
||||
int type;
|
||||
char *dev_name;
|
||||
char *mangled_dev_name;
|
||||
|
||||
struct target *head, *tail;
|
||||
|
||||
int read_only;
|
||||
uint32_t event_nr;
|
||||
int major;
|
||||
int minor;
|
||||
int allow_default_major_fallback;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
mode_t mode;
|
||||
uint32_t read_ahead;
|
||||
uint32_t read_ahead_flags;
|
||||
union {
|
||||
struct dm_ioctl *v4;
|
||||
} dmi;
|
||||
char *newname;
|
||||
char *message;
|
||||
char *geometry;
|
||||
uint64_t sector;
|
||||
int no_flush;
|
||||
int no_open_count;
|
||||
int skip_lockfs;
|
||||
int query_inactive_table;
|
||||
int suppress_identical_reload;
|
||||
dm_add_node_t add_node;
|
||||
uint64_t existing_table_size;
|
||||
int cookie_set;
|
||||
int new_uuid;
|
||||
int secure_data;
|
||||
int retry_remove;
|
||||
int deferred_remove;
|
||||
int enable_checks;
|
||||
int expected_errno;
|
||||
int ioctl_errno;
|
||||
|
||||
int record_timestamp;
|
||||
|
||||
char *uuid;
|
||||
char *mangled_uuid;
|
||||
};
|
||||
|
||||
struct cmd_data {
|
||||
const char *name;
|
||||
const unsigned cmd;
|
||||
const int version[3];
|
||||
};
|
||||
|
||||
int dm_check_version(void);
|
||||
uint64_t dm_task_get_existing_table_size(struct dm_task *dmt);
|
||||
|
||||
#endif
|
||||
2692
device_mapper/libdm-common.c
Normal file
2692
device_mapper/libdm-common.c
Normal file
File diff suppressed because it is too large
Load Diff
58
device_mapper/libdm-common.h
Normal file
58
device_mapper/libdm-common.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2012 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
|
||||
*/
|
||||
|
||||
#ifndef LIB_DMCOMMON_H
|
||||
#define LIB_DMCOMMON_H
|
||||
|
||||
#include "device_mapper/all.h"
|
||||
|
||||
#define DM_DEFAULT_NAME_MANGLING_MODE_ENV_VAR_NAME "DM_DEFAULT_NAME_MANGLING_MODE"
|
||||
|
||||
#define DEV_NAME(dmt) (dmt->mangled_dev_name ? : dmt->dev_name)
|
||||
#define DEV_UUID(DMT) (dmt->mangled_uuid ? : dmt->uuid)
|
||||
|
||||
int mangle_string(const char *str, const char *str_name, size_t len,
|
||||
char *buf, size_t buf_len, dm_string_mangling_t mode);
|
||||
|
||||
int unmangle_string(const char *str, const char *str_name, size_t len,
|
||||
char *buf, size_t buf_len, dm_string_mangling_t mode);
|
||||
|
||||
int check_multiple_mangled_string_allowed(const char *str, const char *str_name,
|
||||
dm_string_mangling_t mode);
|
||||
|
||||
struct target *create_target(uint64_t start,
|
||||
uint64_t len,
|
||||
const char *type, const char *params);
|
||||
|
||||
int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major,
|
||||
uid_t uid, gid_t gid, mode_t mode, int check_udev, unsigned rely_on_udev);
|
||||
int rm_dev_node(const char *dev_name, int check_udev, unsigned rely_on_udev);
|
||||
int rename_dev_node(const char *old_name, const char *new_name,
|
||||
int check_udev, unsigned rely_on_udev);
|
||||
int get_dev_node_read_ahead(const char *dev_name, uint32_t major, uint32_t minor,
|
||||
uint32_t *read_ahead);
|
||||
int set_dev_node_read_ahead(const char *dev_name, uint32_t major, uint32_t minor,
|
||||
uint32_t read_ahead, uint32_t read_ahead_flags);
|
||||
void update_devs(void);
|
||||
void selinux_release(void);
|
||||
|
||||
void inc_suspended(void);
|
||||
void dec_suspended(void);
|
||||
|
||||
int parse_thin_pool_status(const char *params, struct dm_status_thin_pool *s);
|
||||
|
||||
int get_uname_version(unsigned *major, unsigned *minor, unsigned *release);
|
||||
|
||||
#endif
|
||||
1486
device_mapper/libdm-config.c
Normal file
1486
device_mapper/libdm-config.c
Normal file
File diff suppressed because it is too large
Load Diff
4120
device_mapper/libdm-deptree.c
Normal file
4120
device_mapper/libdm-deptree.c
Normal file
File diff suppressed because it is too large
Load Diff
261
device_mapper/libdm-file.c
Normal file
261
device_mapper/libdm-file.c
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 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 "misc/dmlib.h"
|
||||
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int _is_dir(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st) < 0) {
|
||||
log_sys_error("stat", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
log_error("Existing path %s is not "
|
||||
"a directory.", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _create_dir_recursive(const char *dir)
|
||||
{
|
||||
char *orig, *s;
|
||||
int rc, r = 0;
|
||||
|
||||
log_verbose("Creating directory \"%s\"", dir);
|
||||
/* Create parent directories */
|
||||
orig = s = strdup(dir);
|
||||
if (!s) {
|
||||
log_error("Failed to duplicate directory name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((s = strchr(s, '/')) != NULL) {
|
||||
*s = '\0';
|
||||
if (*orig) {
|
||||
rc = mkdir(orig, 0777);
|
||||
if (rc < 0) {
|
||||
if (errno == EEXIST) {
|
||||
if (!_is_dir(orig))
|
||||
goto_out;
|
||||
} else {
|
||||
if (errno != EROFS)
|
||||
log_sys_error("mkdir", orig);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
*s++ = '/';
|
||||
}
|
||||
|
||||
/* Create final directory */
|
||||
rc = mkdir(dir, 0777);
|
||||
if (rc < 0) {
|
||||
if (errno == EEXIST) {
|
||||
if (!_is_dir(dir))
|
||||
goto_out;
|
||||
} else {
|
||||
if (errno != EROFS)
|
||||
log_sys_error("mkdir", orig);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
free(orig);
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_create_dir(const char *dir)
|
||||
{
|
||||
struct stat info;
|
||||
|
||||
if (!*dir)
|
||||
return 1;
|
||||
|
||||
if (stat(dir, &info) == 0 && S_ISDIR(info.st_mode))
|
||||
return 1;
|
||||
|
||||
if (!_create_dir_recursive(dir))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_is_empty_dir(const char *dir)
|
||||
{
|
||||
struct dirent *dirent;
|
||||
DIR *d;
|
||||
|
||||
if (!(d = opendir(dir))) {
|
||||
log_sys_error("opendir", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((dirent = readdir(d)))
|
||||
if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, ".."))
|
||||
break;
|
||||
|
||||
if (closedir(d))
|
||||
log_sys_error("closedir", dir);
|
||||
|
||||
return dirent ? 0 : 1;
|
||||
}
|
||||
|
||||
int dm_fclose(FILE *stream)
|
||||
{
|
||||
int prev_fail = ferror(stream);
|
||||
int fclose_fail = fclose(stream);
|
||||
|
||||
/* If there was a previous failure, but fclose succeeded,
|
||||
clear errno, since ferror does not set it, and its value
|
||||
may be unrelated to the ferror-reported failure. */
|
||||
if (prev_fail && !fclose_fail)
|
||||
errno = 0;
|
||||
|
||||
return prev_fail || fclose_fail ? EOF : 0;
|
||||
}
|
||||
|
||||
int dm_create_lockfile(const char *lockfile)
|
||||
{
|
||||
int fd, value;
|
||||
size_t bufferlen;
|
||||
ssize_t write_out;
|
||||
struct flock lock;
|
||||
char buffer[50];
|
||||
int retries = 0;
|
||||
|
||||
if ((fd = open(lockfile, O_CREAT | O_WRONLY,
|
||||
(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) {
|
||||
log_error("Cannot open lockfile [%s], error was [%s]",
|
||||
lockfile, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_start = 0;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_len = 0;
|
||||
retry_fcntl:
|
||||
if (fcntl(fd, F_SETLK, &lock) < 0) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
goto retry_fcntl;
|
||||
case EACCES:
|
||||
case EAGAIN:
|
||||
if (retries == 20) {
|
||||
log_error("Cannot lock lockfile [%s], error was [%s]",
|
||||
lockfile, strerror(errno));
|
||||
break;
|
||||
} else {
|
||||
++ retries;
|
||||
usleep(1000);
|
||||
goto retry_fcntl;
|
||||
}
|
||||
default:
|
||||
log_error("process is already running");
|
||||
}
|
||||
|
||||
goto fail_close;
|
||||
}
|
||||
|
||||
if (ftruncate(fd, 0) < 0) {
|
||||
log_error("Cannot truncate pidfile [%s], error was [%s]",
|
||||
lockfile, strerror(errno));
|
||||
|
||||
goto fail_close_unlink;
|
||||
}
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%u\n", getpid());
|
||||
|
||||
bufferlen = strlen(buffer);
|
||||
write_out = write(fd, buffer, bufferlen);
|
||||
|
||||
if ((write_out < 0) || (write_out == 0 && errno)) {
|
||||
log_error("Cannot write pid to pidfile [%s], error was [%s]",
|
||||
lockfile, strerror(errno));
|
||||
|
||||
goto fail_close_unlink;
|
||||
}
|
||||
|
||||
if ((write_out == 0) || ((size_t)write_out < bufferlen)) {
|
||||
log_error("Cannot write pid to pidfile [%s], shortwrite of"
|
||||
"[%" PRIsize_t "] bytes, expected [%" PRIsize_t "]\n",
|
||||
lockfile, write_out, bufferlen);
|
||||
|
||||
goto fail_close_unlink;
|
||||
}
|
||||
|
||||
if ((value = fcntl(fd, F_GETFD, 0)) < 0) {
|
||||
log_error("Cannot get close-on-exec flag from pidfile [%s], "
|
||||
"error was [%s]", lockfile, strerror(errno));
|
||||
|
||||
goto fail_close_unlink;
|
||||
}
|
||||
value |= FD_CLOEXEC;
|
||||
if (fcntl(fd, F_SETFD, value) < 0) {
|
||||
log_error("Cannot set close-on-exec flag from pidfile [%s], "
|
||||
"error was [%s]", lockfile, strerror(errno));
|
||||
|
||||
goto fail_close_unlink;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
fail_close_unlink:
|
||||
if (unlink(lockfile))
|
||||
log_sys_debug("unlink", lockfile);
|
||||
fail_close:
|
||||
if (close(fd))
|
||||
log_sys_debug("close", lockfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_daemon_is_running(const char* lockfile)
|
||||
{
|
||||
int fd;
|
||||
struct flock lock;
|
||||
|
||||
if((fd = open(lockfile, O_RDONLY)) < 0)
|
||||
return 0;
|
||||
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_start = 0;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_len = 0;
|
||||
if (fcntl(fd, F_GETLK, &lock) < 0) {
|
||||
log_error("Cannot check lock status of lockfile [%s], error was [%s]",
|
||||
lockfile, strerror(errno));
|
||||
if (close(fd))
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (close(fd))
|
||||
stack;
|
||||
|
||||
return (lock.l_type == F_UNLCK) ? 0 : 1;
|
||||
}
|
||||
5105
device_mapper/libdm-report.c
Normal file
5105
device_mapper/libdm-report.c
Normal file
File diff suppressed because it is too large
Load Diff
718
device_mapper/libdm-string.c
Normal file
718
device_mapper/libdm-string.c
Normal file
@@ -0,0 +1,718 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2015 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 "misc/dmlib.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <math.h> /* fabs() */
|
||||
#include <float.h> /* DBL_EPSILON */
|
||||
|
||||
/*
|
||||
* consume characters while they match the predicate function.
|
||||
*/
|
||||
static char *_consume(char *buffer, int (*fn) (int))
|
||||
{
|
||||
while (*buffer && fn(*buffer))
|
||||
buffer++;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int _isword(int c)
|
||||
{
|
||||
return !isspace(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Split buffer into NULL-separated words in argv.
|
||||
* Returns number of words.
|
||||
*/
|
||||
int dm_split_words(char *buffer, unsigned max,
|
||||
unsigned ignore_comments __attribute__((unused)),
|
||||
char **argv)
|
||||
{
|
||||
unsigned arg;
|
||||
|
||||
for (arg = 0; arg < max; arg++) {
|
||||
buffer = _consume(buffer, isspace);
|
||||
if (!*buffer)
|
||||
break;
|
||||
|
||||
argv[arg] = buffer;
|
||||
buffer = _consume(buffer, _isword);
|
||||
|
||||
if (*buffer) {
|
||||
*buffer = '\0';
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove hyphen quoting from a component of a name.
|
||||
* NULL-terminates the component and returns start of next component.
|
||||
*/
|
||||
static char *_unquote(char *component)
|
||||
{
|
||||
char *c = component;
|
||||
char *o = c;
|
||||
char *r;
|
||||
|
||||
while (*c) {
|
||||
if (*(c + 1)) {
|
||||
if (*c == '-') {
|
||||
if (*(c + 1) == '-')
|
||||
c++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
*o = *c;
|
||||
o++;
|
||||
c++;
|
||||
}
|
||||
|
||||
r = (*c) ? c + 1 : c;
|
||||
*o = '\0';
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_split_lvm_name(struct dm_pool *mem, const char *dmname,
|
||||
char **vgname, char **lvname, char **layer)
|
||||
{
|
||||
if (!vgname || !lvname || !layer) {
|
||||
log_error(INTERNAL_ERROR "dm_split_lvm_name: Forbidden NULL parameter detected.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mem && (!dmname || !(*vgname = dm_pool_strdup(mem, dmname)))) {
|
||||
log_error("Failed to duplicate lvm name.");
|
||||
return 0;
|
||||
} else if (!*vgname) {
|
||||
log_error("Missing lvm name for split.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_unquote(*layer = _unquote(*lvname = _unquote(*vgname)));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* On error, up to glibc 2.0.6, snprintf returned -1 if buffer was too small;
|
||||
* From glibc 2.1 it returns number of chars (excl. trailing null) that would
|
||||
* have been written had there been room.
|
||||
*
|
||||
* dm_snprintf reverts to the old behaviour.
|
||||
*/
|
||||
int dm_snprintf(char *buf, size_t bufsize, const char *format, ...)
|
||||
{
|
||||
int n;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
n = vsnprintf(buf, bufsize, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (n < 0 || ((unsigned) n >= bufsize))
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
const char *dm_basename(const char *path)
|
||||
{
|
||||
const char *p = strrchr(path, '/');
|
||||
|
||||
return p ? p + 1 : path;
|
||||
}
|
||||
|
||||
int dm_vasprintf(char **result, const char *format, va_list aq)
|
||||
{
|
||||
int i, n, size = 16;
|
||||
va_list ap;
|
||||
char *buf = malloc(size);
|
||||
|
||||
*result = 0;
|
||||
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
for (i = 0;; i++) {
|
||||
va_copy(ap, aq);
|
||||
n = vsnprintf(buf, size, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (0 <= n && n < size)
|
||||
break;
|
||||
|
||||
free(buf);
|
||||
/* Up to glibc 2.0.6 returns -1 */
|
||||
size = (n < 0) ? size * 2 : n + 1;
|
||||
if (!(buf = malloc(size)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i > 1) {
|
||||
/* Reallocating more then once? */
|
||||
if (!(*result = strdup(buf))) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
free(buf);
|
||||
} else
|
||||
*result = buf;
|
||||
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
int dm_asprintf(char **result, const char *format, ...)
|
||||
{
|
||||
int r;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
r = dm_vasprintf(result, format, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count occurences of 'c' in 'str' until we reach a null char.
|
||||
*
|
||||
* Returns:
|
||||
* len - incremented for each char we encounter.
|
||||
* count - number of occurrences of 'c' and 'c2'.
|
||||
*/
|
||||
static void _count_chars(const char *str, size_t *len, int *count,
|
||||
const int c1, const int c2)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
for (ptr = str; *ptr; ptr++, (*len)++)
|
||||
if (*ptr == c1 || *ptr == c2)
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count occurrences of 'c' in 'str' of length 'size'.
|
||||
*
|
||||
* Returns:
|
||||
* Number of occurrences of 'c'
|
||||
*/
|
||||
unsigned dm_count_chars(const char *str, size_t len, const int c)
|
||||
{
|
||||
size_t i;
|
||||
unsigned count = 0;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (str[i] == c)
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Length of string after escaping double quotes and backslashes.
|
||||
*/
|
||||
size_t dm_escaped_len(const char *str)
|
||||
{
|
||||
size_t len = 1;
|
||||
int count = 0;
|
||||
|
||||
_count_chars(str, &len, &count, '\"', '\\');
|
||||
|
||||
return count + len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a string, quoting orig_char with quote_char.
|
||||
* Optionally also quote quote_char.
|
||||
*/
|
||||
static void _quote_characters(char **out, const char *src,
|
||||
const int orig_char, const int quote_char,
|
||||
int quote_quote_char)
|
||||
{
|
||||
while (*src) {
|
||||
if (*src == orig_char ||
|
||||
(*src == quote_char && quote_quote_char))
|
||||
*(*out)++ = quote_char;
|
||||
|
||||
*(*out)++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
static void _unquote_one_character(char *src, const char orig_char,
|
||||
const char quote_char)
|
||||
{
|
||||
char *out;
|
||||
char s, n;
|
||||
|
||||
/* Optimise for the common case where no changes are needed. */
|
||||
while ((s = *src++)) {
|
||||
if (s == quote_char &&
|
||||
((n = *src) == orig_char || n == quote_char)) {
|
||||
out = src++;
|
||||
*(out - 1) = n;
|
||||
|
||||
while ((s = *src++)) {
|
||||
if (s == quote_char &&
|
||||
((n = *src) == orig_char || n == quote_char)) {
|
||||
s = n;
|
||||
src++;
|
||||
}
|
||||
*out = s;
|
||||
out++;
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unquote each character given in orig_char array and unquote quote_char
|
||||
* as well. Also save the first occurrence of each character from orig_char
|
||||
* that was found unquoted in arr_substr_first_unquoted array. This way we can
|
||||
* process several characters in one go.
|
||||
*/
|
||||
static void _unquote_characters(char *src, const char *orig_chars,
|
||||
size_t num_orig_chars,
|
||||
const char quote_char,
|
||||
char *arr_substr_first_unquoted[])
|
||||
{
|
||||
char *out = src;
|
||||
char c, s, n;
|
||||
unsigned i;
|
||||
|
||||
while ((s = *src++)) {
|
||||
for (i = 0; i < num_orig_chars; i++) {
|
||||
c = orig_chars[i];
|
||||
if (s == quote_char &&
|
||||
((n = *src) == c || n == quote_char)) {
|
||||
s = n;
|
||||
src++;
|
||||
break;
|
||||
}
|
||||
if (arr_substr_first_unquoted && (s == c) &&
|
||||
!arr_substr_first_unquoted[i])
|
||||
arr_substr_first_unquoted[i] = out;
|
||||
};
|
||||
*out++ = s;
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a string, quoting hyphens with hyphens.
|
||||
*/
|
||||
static void _quote_hyphens(char **out, const char *src)
|
||||
{
|
||||
_quote_characters(out, src, '-', '-', 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
|
||||
*/
|
||||
char *dm_build_dm_name(struct dm_pool *mem, const char *vgname,
|
||||
const char *lvname, const char *layer)
|
||||
{
|
||||
size_t len = 1;
|
||||
int hyphens = 1;
|
||||
char *r, *out;
|
||||
|
||||
_count_chars(vgname, &len, &hyphens, '-', 0);
|
||||
_count_chars(lvname, &len, &hyphens, '-', 0);
|
||||
|
||||
if (layer && *layer) {
|
||||
_count_chars(layer, &len, &hyphens, '-', 0);
|
||||
hyphens++;
|
||||
}
|
||||
|
||||
len += hyphens;
|
||||
|
||||
if (!(r = dm_pool_alloc(mem, len))) {
|
||||
log_error("build_dm_name: Allocation failed for %" PRIsize_t
|
||||
" for %s %s %s.", len, vgname, lvname, layer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out = r;
|
||||
_quote_hyphens(&out, vgname);
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, lvname);
|
||||
|
||||
if (layer && *layer) {
|
||||
/* No hyphen if the layer begins with _ e.g. _mlog */
|
||||
if (*layer != '_')
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, layer);
|
||||
}
|
||||
*out = '\0';
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *dm_build_dm_uuid(struct dm_pool *mem, const char *uuid_prefix, const char *lvid, const char *layer)
|
||||
{
|
||||
char *dmuuid;
|
||||
size_t len;
|
||||
|
||||
if (!layer)
|
||||
layer = "";
|
||||
|
||||
len = strlen(uuid_prefix) + strlen(lvid) + strlen(layer) + 2;
|
||||
|
||||
if (!(dmuuid = dm_pool_alloc(mem, len))) {
|
||||
log_error("build_dm_name: Allocation failed for %" PRIsize_t
|
||||
" %s %s.", len, lvid, layer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sprintf(dmuuid, "%s%s%s%s", uuid_prefix, lvid, (*layer) ? "-" : "", layer);
|
||||
|
||||
return dmuuid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a string, quoting double quotes with backslashes.
|
||||
*/
|
||||
char *dm_escape_double_quotes(char *out, const char *src)
|
||||
{
|
||||
char *buf = out;
|
||||
|
||||
_quote_characters(&buf, src, '\"', '\\', 1);
|
||||
*buf = '\0';
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Undo quoting in situ.
|
||||
*/
|
||||
void dm_unescape_double_quotes(char *src)
|
||||
{
|
||||
_unquote_one_character(src, '\"', '\\');
|
||||
}
|
||||
|
||||
/*
|
||||
* Unescape colons and "at" signs in situ and save the substrings
|
||||
* starting at the position of the first unescaped colon and the
|
||||
* first unescaped "at" sign. This is normally used to unescape
|
||||
* device names used as PVs.
|
||||
*/
|
||||
void dm_unescape_colons_and_at_signs(char *src,
|
||||
char **substr_first_unquoted_colon,
|
||||
char **substr_first_unquoted_at_sign)
|
||||
{
|
||||
const char *orig_chars = ":@";
|
||||
char *arr_substr_first_unquoted[] = {NULL, NULL, NULL};
|
||||
|
||||
_unquote_characters(src, orig_chars, 2, '\\', arr_substr_first_unquoted);
|
||||
|
||||
if (substr_first_unquoted_colon)
|
||||
*substr_first_unquoted_colon = arr_substr_first_unquoted[0];
|
||||
|
||||
if (substr_first_unquoted_at_sign)
|
||||
*substr_first_unquoted_at_sign = arr_substr_first_unquoted[1];
|
||||
}
|
||||
|
||||
int dm_strncpy(char *dest, const char *src, size_t n)
|
||||
{
|
||||
if (memccpy(dest, src, 0, n))
|
||||
return 1;
|
||||
|
||||
if (n > 0)
|
||||
dest[n - 1] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test if the doubles are close enough to be considered equal */
|
||||
static int _close_enough(double d1, double d2)
|
||||
{
|
||||
return fabs(d1 - d2) < DBL_EPSILON;
|
||||
}
|
||||
|
||||
#define BASE_UNKNOWN 0
|
||||
#define BASE_SHARED 1
|
||||
#define BASE_1024 8
|
||||
#define BASE_1000 15
|
||||
#define BASE_SPECIAL 21
|
||||
#define NUM_UNIT_PREFIXES 6
|
||||
#define NUM_SPECIAL 3
|
||||
|
||||
#define SIZE_BUF 128
|
||||
|
||||
const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
|
||||
char unit_type, int use_si_units,
|
||||
uint64_t unit_factor, int include_suffix,
|
||||
dm_size_suffix_t suffix_type)
|
||||
{
|
||||
unsigned base = BASE_UNKNOWN;
|
||||
unsigned s;
|
||||
int precision;
|
||||
double d;
|
||||
uint64_t byte = UINT64_C(0);
|
||||
uint64_t units = UINT64_C(1024);
|
||||
char *size_buf = NULL;
|
||||
char new_unit_type = '\0', unit_type_buf[2];
|
||||
const char *prefix = "";
|
||||
const char * const size_str[][3] = {
|
||||
/* BASE_UNKNOWN */
|
||||
{" ", " ", " "}, /* [0] */
|
||||
|
||||
/* BASE_SHARED - Used if use_si_units = 0 */
|
||||
{" Exabyte", " EB", "E"}, /* [1] */
|
||||
{" Petabyte", " PB", "P"}, /* [2] */
|
||||
{" Terabyte", " TB", "T"}, /* [3] */
|
||||
{" Gigabyte", " GB", "G"}, /* [4] */
|
||||
{" Megabyte", " MB", "M"}, /* [5] */
|
||||
{" Kilobyte", " KB", "K"}, /* [6] */
|
||||
{" Byte ", " B", "B"}, /* [7] */
|
||||
|
||||
/* BASE_1024 - Used if use_si_units = 1 */
|
||||
{" Exbibyte", " EiB", "e"}, /* [8] */
|
||||
{" Pebibyte", " PiB", "p"}, /* [9] */
|
||||
{" Tebibyte", " TiB", "t"}, /* [10] */
|
||||
{" Gibibyte", " GiB", "g"}, /* [11] */
|
||||
{" Mebibyte", " MiB", "m"}, /* [12] */
|
||||
{" Kibibyte", " KiB", "k"}, /* [13] */
|
||||
{" Byte ", " B", "b"}, /* [14] */
|
||||
|
||||
/* BASE_1000 - Used if use_si_units = 1 */
|
||||
{" Exabyte", " EB", "E"}, /* [15] */
|
||||
{" Petabyte", " PB", "P"}, /* [16] */
|
||||
{" Terabyte", " TB", "T"}, /* [17] */
|
||||
{" Gigabyte", " GB", "G"}, /* [18] */
|
||||
{" Megabyte", " MB", "M"}, /* [19] */
|
||||
{" Kilobyte", " kB", "K"}, /* [20] */
|
||||
|
||||
/* BASE_SPECIAL */
|
||||
{" Byte ", " B ", "B"}, /* [21] (shared with BASE_1000) */
|
||||
{" Units ", " Un", "U"}, /* [22] */
|
||||
{" Sectors ", " Se", "S"}, /* [23] */
|
||||
};
|
||||
|
||||
if (!(size_buf = dm_pool_alloc(mem, SIZE_BUF))) {
|
||||
log_error("no memory for size display buffer");
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!use_si_units) {
|
||||
/* Case-independent match */
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (toupper((int) unit_type) ==
|
||||
*size_str[BASE_SHARED + s][2]) {
|
||||
base = BASE_SHARED;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Case-dependent match for powers of 1000 */
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (unit_type == *size_str[BASE_1000 + s][2]) {
|
||||
base = BASE_1000;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Case-dependent match for powers of 1024 */
|
||||
if (base == BASE_UNKNOWN)
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (unit_type == *size_str[BASE_1024 + s][2]) {
|
||||
base = BASE_1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (base == BASE_UNKNOWN)
|
||||
/* Check for special units - s, b or u */
|
||||
for (s = 0; s < NUM_SPECIAL; s++)
|
||||
if (toupper((int) unit_type) ==
|
||||
*size_str[BASE_SPECIAL + s][2]) {
|
||||
base = BASE_SPECIAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (size == UINT64_C(0)) {
|
||||
if (base == BASE_UNKNOWN)
|
||||
s = 0;
|
||||
sprintf(size_buf, "0%s", include_suffix ? size_str[base + s][suffix_type] : "");
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
size *= UINT64_C(512);
|
||||
|
||||
if (base != BASE_UNKNOWN) {
|
||||
if (!unit_factor) {
|
||||
unit_type_buf[0] = unit_type;
|
||||
unit_type_buf[1] = '\0';
|
||||
if (!(unit_factor = dm_units_to_factor(&unit_type_buf[0], &new_unit_type, 1, NULL)) ||
|
||||
unit_type != new_unit_type) {
|
||||
/* The two functions should match (and unrecognised units get treated like 'h'). */
|
||||
log_error(INTERNAL_ERROR "Inconsistent units: %c and %c.", unit_type, new_unit_type);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
byte = unit_factor;
|
||||
} else {
|
||||
/* Human-readable style */
|
||||
if (unit_type == 'H' || unit_type == 'R') {
|
||||
units = UINT64_C(1000);
|
||||
base = BASE_1000;
|
||||
} else {
|
||||
units = UINT64_C(1024);
|
||||
base = BASE_1024;
|
||||
}
|
||||
|
||||
if (!use_si_units)
|
||||
base = BASE_SHARED;
|
||||
|
||||
byte = units * units * units * units * units * units;
|
||||
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES && size < byte; s++)
|
||||
byte /= units;
|
||||
|
||||
if ((s < NUM_UNIT_PREFIXES) &&
|
||||
((unit_type == 'R') || (unit_type == 'r'))) {
|
||||
/* When the rounding would cause difference, add '<' prefix
|
||||
* i.e. 2043M is more then 1.9949G prints <2.00G
|
||||
* This version is for 2 digits fixed precision */
|
||||
d = 100. * (double) size / byte;
|
||||
if (!_close_enough(floorl(d), nearbyintl(d)))
|
||||
prefix = "<";
|
||||
}
|
||||
|
||||
include_suffix = 1;
|
||||
}
|
||||
|
||||
/* FIXME Make precision configurable */
|
||||
switch (toupper(*size_str[base + s][DM_SIZE_UNIT])) {
|
||||
case 'B':
|
||||
case 'S':
|
||||
precision = 0;
|
||||
break;
|
||||
default:
|
||||
precision = 2;
|
||||
}
|
||||
|
||||
snprintf(size_buf, SIZE_BUF, "%s%.*f%s", prefix, precision,
|
||||
(double) size / byte, include_suffix ? size_str[base + s][suffix_type] : "");
|
||||
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
uint64_t dm_units_to_factor(const char *units, char *unit_type,
|
||||
int strict, const char **endptr)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
uint64_t v;
|
||||
double custom_value = 0;
|
||||
uint64_t multiplier;
|
||||
|
||||
if (endptr)
|
||||
*endptr = units;
|
||||
|
||||
if (isdigit(*units)) {
|
||||
custom_value = strtod(units, &ptr);
|
||||
if (ptr == units)
|
||||
return 0;
|
||||
v = (uint64_t) strtoull(units, NULL, 10);
|
||||
if (_close_enough((double) v, custom_value))
|
||||
custom_value = 0; /* Use integer arithmetic */
|
||||
units = ptr;
|
||||
} else
|
||||
v = 1;
|
||||
|
||||
/* Only one units char permitted in strict mode. */
|
||||
if (strict && units[0] && units[1])
|
||||
return 0;
|
||||
|
||||
if (v == 1)
|
||||
*unit_type = *units;
|
||||
else
|
||||
*unit_type = 'U';
|
||||
|
||||
switch (*units) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
case 'r':
|
||||
case 'R':
|
||||
multiplier = v = UINT64_C(1);
|
||||
*unit_type = *units;
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
multiplier = UINT64_C(1);
|
||||
break;
|
||||
#define KILO UINT64_C(1024)
|
||||
case 's':
|
||||
case 'S':
|
||||
multiplier = (KILO/2);
|
||||
break;
|
||||
case 'k':
|
||||
multiplier = KILO;
|
||||
break;
|
||||
case 'm':
|
||||
multiplier = KILO * KILO;
|
||||
break;
|
||||
case 'g':
|
||||
multiplier = KILO * KILO * KILO;
|
||||
break;
|
||||
case 't':
|
||||
multiplier = KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'p':
|
||||
multiplier = KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'e':
|
||||
multiplier = KILO * KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
#undef KILO
|
||||
#define KILO UINT64_C(1000)
|
||||
case 'K':
|
||||
multiplier = KILO;
|
||||
break;
|
||||
case 'M':
|
||||
multiplier = KILO * KILO;
|
||||
break;
|
||||
case 'G':
|
||||
multiplier = KILO * KILO * KILO;
|
||||
break;
|
||||
case 'T':
|
||||
multiplier = KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'P':
|
||||
multiplier = KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'E':
|
||||
multiplier = KILO * KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
#undef KILO
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (endptr)
|
||||
*endptr = units + 1;
|
||||
|
||||
if (_close_enough(custom_value, 0.))
|
||||
return v * multiplier; /* Use integer arithmetic */
|
||||
else
|
||||
return (uint64_t) (custom_value * multiplier);
|
||||
}
|
||||
597
device_mapper/libdm-targets.c
Normal file
597
device_mapper/libdm-targets.c
Normal file
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 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 "misc/dmlib.h"
|
||||
#include "libdm-common.h"
|
||||
|
||||
int dm_get_status_snapshot(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_snapshot **status)
|
||||
{
|
||||
struct dm_status_snapshot *s;
|
||||
int r;
|
||||
|
||||
if (!params) {
|
||||
log_error("Failed to parse invalid snapshot params.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(*s)))) {
|
||||
log_error("Failed to allocate snapshot status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sscanf(params, FMTu64 "/" FMTu64 " " FMTu64,
|
||||
&s->used_sectors, &s->total_sectors,
|
||||
&s->metadata_sectors);
|
||||
|
||||
if (r == 3 || r == 2)
|
||||
s->has_metadata_sectors = (r == 3);
|
||||
else if (!strcmp(params, "Invalid"))
|
||||
s->invalid = 1;
|
||||
else if (!strcmp(params, "Merge failed"))
|
||||
s->merge_failed = 1;
|
||||
else if (!strcmp(params, "Overflow"))
|
||||
s->overflow = 1;
|
||||
else {
|
||||
dm_pool_free(mem, s);
|
||||
log_error("Failed to parse snapshot params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip nr fields each delimited by a single space.
|
||||
* FIXME Don't assume single space.
|
||||
*/
|
||||
static const char *_skip_fields(const char *p, unsigned nr)
|
||||
{
|
||||
while (p && nr-- && (p = strchr(p, ' ')))
|
||||
p++;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count number of single-space delimited fields.
|
||||
* Number of fields is number of spaces plus one.
|
||||
*/
|
||||
static unsigned _count_fields(const char *p)
|
||||
{
|
||||
unsigned nr = 1;
|
||||
|
||||
if (!p || !*p)
|
||||
return 0;
|
||||
|
||||
while ((p = _skip_fields(p, 1)))
|
||||
nr++;
|
||||
|
||||
return nr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Various RAID status versions include:
|
||||
* Versions < 1.5.0 (4 fields):
|
||||
* <raid_type> <#devs> <health_str> <sync_ratio>
|
||||
* Versions 1.5.0+ (6 fields):
|
||||
* <raid_type> <#devs> <health_str> <sync_ratio> <sync_action> <mismatch_cnt>
|
||||
* Versions 1.9.0+ (7 fields):
|
||||
* <raid_type> <#devs> <health_str> <sync_ratio> <sync_action> <mismatch_cnt> <data_offset>
|
||||
*/
|
||||
int dm_get_status_raid(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_raid **status)
|
||||
{
|
||||
int i;
|
||||
unsigned num_fields;
|
||||
const char *p, *pp, *msg_fields = "";
|
||||
struct dm_status_raid *s = NULL;
|
||||
unsigned a = 0;
|
||||
|
||||
if ((num_fields = _count_fields(params)) < 4)
|
||||
goto_bad;
|
||||
|
||||
/* Second field holds the device count */
|
||||
msg_fields = "<#devs> ";
|
||||
if (!(p = _skip_fields(params, 1)) || (sscanf(p, "%d", &i) != 1))
|
||||
goto_bad;
|
||||
|
||||
msg_fields = "";
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid))))
|
||||
goto_bad;
|
||||
|
||||
if (!(s->raid_type = dm_pool_zalloc(mem, p - params)))
|
||||
goto_bad; /* memory is freed when pool is destroyed */
|
||||
|
||||
if (!(s->dev_health = dm_pool_zalloc(mem, i + 1))) /* Space for health chars */
|
||||
goto_bad;
|
||||
|
||||
msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> ";
|
||||
if (sscanf(params, "%s %u %s " FMTu64 "/" FMTu64,
|
||||
s->raid_type,
|
||||
&s->dev_count,
|
||||
s->dev_health,
|
||||
&s->insync_regions,
|
||||
&s->total_regions) != 5)
|
||||
goto_bad;
|
||||
|
||||
/*
|
||||
* All pre-1.5.0 version parameters are read. Now we check
|
||||
* for additional 1.5.0+ parameters (i.e. num_fields at least 6).
|
||||
*
|
||||
* Note that 'sync_action' will be NULL (and mismatch_count
|
||||
* will be 0) if the kernel returns a pre-1.5.0 status.
|
||||
*/
|
||||
if (num_fields < 6)
|
||||
goto out;
|
||||
|
||||
msg_fields = "<sync_action> and <mismatch_cnt> ";
|
||||
|
||||
/* Skip pre-1.5.0 params */
|
||||
if (!(p = _skip_fields(params, 4)) || !(pp = _skip_fields(p, 1)))
|
||||
goto_bad;
|
||||
|
||||
if (!(s->sync_action = dm_pool_zalloc(mem, pp - p)))
|
||||
goto_bad;
|
||||
|
||||
if (sscanf(p, "%s " FMTu64, s->sync_action, &s->mismatch_count) != 2)
|
||||
goto_bad;
|
||||
|
||||
if (num_fields < 7)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* All pre-1.9.0 version parameters are read. Now we check
|
||||
* for additional 1.9.0+ parameters (i.e. nr_fields at least 7).
|
||||
*
|
||||
* Note that data_offset will be 0 if the
|
||||
* kernel returns a pre-1.9.0 status.
|
||||
*/
|
||||
msg_fields = "<data_offset>";
|
||||
if (!(p = _skip_fields(params, 6))) /* skip pre-1.9.0 params */
|
||||
goto bad;
|
||||
if (sscanf(p, FMTu64, &s->data_offset) != 1)
|
||||
goto bad;
|
||||
|
||||
out:
|
||||
*status = s;
|
||||
|
||||
if (s->insync_regions == s->total_regions) {
|
||||
/* FIXME: kernel gives misleading info here
|
||||
* Trying to recognize a true state */
|
||||
while (i-- > 0)
|
||||
if (s->dev_health[i] == 'a')
|
||||
a++; /* Count number of 'a' */
|
||||
|
||||
if (a && a < s->dev_count) {
|
||||
/* SOME legs are in 'a' */
|
||||
if (!strcasecmp(s->sync_action, "recover")
|
||||
|| !strcasecmp(s->sync_action, "idle"))
|
||||
/* Kernel may possibly start some action
|
||||
* in near-by future, do not report 100% */
|
||||
s->insync_regions--;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
log_error("Failed to parse %sraid params: %s", msg_fields, params);
|
||||
|
||||
if (s)
|
||||
dm_pool_free(mem, s);
|
||||
|
||||
*status = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* <metadata block size> <#used metadata blocks>/<#total metadata blocks>
|
||||
* <cache block size> <#used cache blocks>/<#total cache blocks>
|
||||
* <#read hits> <#read misses> <#write hits> <#write misses>
|
||||
* <#demotions> <#promotions> <#dirty> <#features> <features>*
|
||||
* <#core args> <core args>* <policy name> <#policy args> <policy args>*
|
||||
*
|
||||
* metadata block size : Fixed block size for each metadata block in
|
||||
* sectors
|
||||
* #used metadata blocks : Number of metadata blocks used
|
||||
* #total metadata blocks : Total number of metadata blocks
|
||||
* cache block size : Configurable block size for the cache device
|
||||
* in sectors
|
||||
* #used cache blocks : Number of blocks resident in the cache
|
||||
* #total cache blocks : Total number of cache blocks
|
||||
* #read hits : Number of times a READ bio has been mapped
|
||||
* to the cache
|
||||
* #read misses : Number of times a READ bio has been mapped
|
||||
* to the origin
|
||||
* #write hits : Number of times a WRITE bio has been mapped
|
||||
* to the cache
|
||||
* #write misses : Number of times a WRITE bio has been
|
||||
* mapped to the origin
|
||||
* #demotions : Number of times a block has been removed
|
||||
* from the cache
|
||||
* #promotions : Number of times a block has been moved to
|
||||
* the cache
|
||||
* #dirty : Number of blocks in the cache that differ
|
||||
* from the origin
|
||||
* #feature args : Number of feature args to follow
|
||||
* feature args : 'writethrough' (optional)
|
||||
* #core args : Number of core arguments (must be even)
|
||||
* core args : Key/value pairs for tuning the core
|
||||
* e.g. migration_threshold
|
||||
* *policy name : Name of the policy
|
||||
* #policy args : Number of policy arguments to follow (must be even)
|
||||
* policy args : Key/value pairs
|
||||
* e.g. sequential_threshold
|
||||
*/
|
||||
int dm_get_status_cache(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_cache **status)
|
||||
{
|
||||
int i, feature_argc;
|
||||
char *str;
|
||||
const char *p, *pp;
|
||||
struct dm_status_cache *s;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_cache))))
|
||||
return_0;
|
||||
|
||||
if (strstr(params, "Error")) {
|
||||
s->error = 1;
|
||||
s->fail = 1; /* This is also I/O fail state */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strstr(params, "Fail")) {
|
||||
s->fail = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Read in args that have definitive placement */
|
||||
if (sscanf(params,
|
||||
" " FMTu32
|
||||
" " FMTu64 "/" FMTu64
|
||||
" " FMTu32
|
||||
" " FMTu64 "/" FMTu64
|
||||
" " FMTu64 " " FMTu64
|
||||
" " FMTu64 " " FMTu64
|
||||
" " FMTu64 " " FMTu64
|
||||
" " FMTu64
|
||||
" %d",
|
||||
&s->metadata_block_size,
|
||||
&s->metadata_used_blocks, &s->metadata_total_blocks,
|
||||
&s->block_size, /* AKA, chunk_size */
|
||||
&s->used_blocks, &s->total_blocks,
|
||||
&s->read_hits, &s->read_misses,
|
||||
&s->write_hits, &s->write_misses,
|
||||
&s->demotions, &s->promotions,
|
||||
&s->dirty_blocks,
|
||||
&feature_argc) != 14)
|
||||
goto bad;
|
||||
|
||||
/* Now jump to "features" section */
|
||||
if (!(p = _skip_fields(params, 12)))
|
||||
goto bad;
|
||||
|
||||
/* Read in features */
|
||||
for (i = 0; i < feature_argc; i++) {
|
||||
if (!strncmp(p, "writethrough ", 13))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strncmp(p, "writeback ", 10))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_WRITEBACK;
|
||||
else if (!strncmp(p, "passthrough ", 12))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_PASSTHROUGH;
|
||||
else if (!strncmp(p, "metadata2 ", 10))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_METADATA2;
|
||||
else
|
||||
log_error("Unknown feature in status: %s", params);
|
||||
|
||||
if (!(p = _skip_fields(p, 1)))
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Read in core_args. */
|
||||
if (sscanf(p, "%d ", &s->core_argc) != 1)
|
||||
goto bad;
|
||||
if ((s->core_argc > 0) &&
|
||||
(!(s->core_argv = dm_pool_zalloc(mem, sizeof(char *) * s->core_argc)) ||
|
||||
!(p = _skip_fields(p, 1)) ||
|
||||
!(str = dm_pool_strdup(mem, p)) ||
|
||||
!(p = _skip_fields(p, (unsigned) s->core_argc)) ||
|
||||
(dm_split_words(str, s->core_argc, 0, s->core_argv) != s->core_argc)))
|
||||
goto bad;
|
||||
|
||||
/* Read in policy args */
|
||||
pp = p;
|
||||
if (!(p = _skip_fields(p, 1)) ||
|
||||
!(s->policy_name = dm_pool_zalloc(mem, (p - pp))))
|
||||
goto bad;
|
||||
if (sscanf(pp, "%s %d", s->policy_name, &s->policy_argc) != 2)
|
||||
goto bad;
|
||||
if (s->policy_argc &&
|
||||
(!(s->policy_argv = dm_pool_zalloc(mem, sizeof(char *) * s->policy_argc)) ||
|
||||
!(p = _skip_fields(p, 1)) ||
|
||||
!(str = dm_pool_strdup(mem, p)) ||
|
||||
(dm_split_words(str, s->policy_argc, 0, s->policy_argv) != s->policy_argc)))
|
||||
goto bad;
|
||||
|
||||
/* TODO: improve this parser */
|
||||
if (strstr(p, " ro"))
|
||||
s->read_only = 1;
|
||||
|
||||
if (strstr(p, " needs_check"))
|
||||
s->needs_check = 1;
|
||||
out:
|
||||
*status = s;
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
log_error("Failed to parse cache params: %s", params);
|
||||
dm_pool_free(mem, s);
|
||||
*status = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* From linux/Documentation/device-mapper/writecache.txt
|
||||
*
|
||||
* Status:
|
||||
* 1. error indicator - 0 if there was no error, otherwise error number
|
||||
* 2. the number of blocks
|
||||
* 3. the number of free blocks
|
||||
* 4. the number of blocks under writeback
|
||||
*/
|
||||
|
||||
int dm_get_status_writecache(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_writecache **status)
|
||||
{
|
||||
struct dm_status_writecache *s;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_writecache))))
|
||||
return_0;
|
||||
|
||||
if (sscanf(params, "%u %llu %llu %llu",
|
||||
&s->error,
|
||||
(unsigned long long *)&s->total_blocks,
|
||||
(unsigned long long *)&s->free_blocks,
|
||||
(unsigned long long *)&s->writeback_blocks) != 4) {
|
||||
log_error("Failed to parse writecache params: %s.", params);
|
||||
dm_pool_free(mem, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_thin_pool_status(const char *params, struct dm_status_thin_pool *s)
|
||||
{
|
||||
int pos;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
if (!params) {
|
||||
log_error("Failed to parse invalid thin params.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strstr(params, "Error")) {
|
||||
s->error = 1;
|
||||
s->fail = 1; /* This is also I/O fail state */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strstr(params, "Fail")) {
|
||||
s->fail = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME: add support for held metadata root */
|
||||
if (sscanf(params, FMTu64 " " FMTu64 "/" FMTu64 " " FMTu64 "/" FMTu64 "%n",
|
||||
&s->transaction_id,
|
||||
&s->used_metadata_blocks,
|
||||
&s->total_metadata_blocks,
|
||||
&s->used_data_blocks,
|
||||
&s->total_data_blocks, &pos) < 5) {
|
||||
log_error("Failed to parse thin pool params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* New status flags */
|
||||
if (strstr(params + pos, "no_discard_passdown"))
|
||||
s->discards = DM_THIN_DISCARDS_NO_PASSDOWN;
|
||||
else if (strstr(params + pos, "ignore_discard"))
|
||||
s->discards = DM_THIN_DISCARDS_IGNORE;
|
||||
else /* default discard_passdown */
|
||||
s->discards = DM_THIN_DISCARDS_PASSDOWN;
|
||||
|
||||
/* Default is 'writable' (rw) data */
|
||||
if (strstr(params + pos, "out_of_data_space"))
|
||||
s->out_of_data_space = 1;
|
||||
else if (strstr(params + pos, "ro "))
|
||||
s->read_only = 1;
|
||||
|
||||
/* Default is 'queue_if_no_space' */
|
||||
if (strstr(params + pos, "error_if_no_space"))
|
||||
s->error_if_no_space = 1;
|
||||
|
||||
if (strstr(params + pos, "needs_check"))
|
||||
s->needs_check = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_get_status_thin_pool(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_thin_pool **status)
|
||||
{
|
||||
struct dm_status_thin_pool *s;
|
||||
|
||||
if (!(s = dm_pool_alloc(mem, sizeof(struct dm_status_thin_pool)))) {
|
||||
log_error("Failed to allocate thin_pool status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!parse_thin_pool_status(params, s)) {
|
||||
dm_pool_free(mem, s);
|
||||
return_0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_get_status_thin(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_thin **status)
|
||||
{
|
||||
struct dm_status_thin *s;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_thin)))) {
|
||||
log_error("Failed to allocate thin status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strchr(params, '-')) {
|
||||
/* nothing to parse */
|
||||
} else if (strstr(params, "Fail")) {
|
||||
s->fail = 1;
|
||||
} else if (sscanf(params, FMTu64 " " FMTu64,
|
||||
&s->mapped_sectors,
|
||||
&s->highest_mapped_sector) != 2) {
|
||||
dm_pool_free(mem, s);
|
||||
log_error("Failed to parse thin params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
#define DM_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
|
||||
|
||||
int dm_get_status_mirror(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_mirror **status)
|
||||
{
|
||||
struct dm_status_mirror *s;
|
||||
const char *p, *pos = params;
|
||||
unsigned num_devs, argc, i;
|
||||
int used;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(*s)))) {
|
||||
log_error("Failed to alloc mem pool to parse mirror status.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sscanf(pos, "%u %n", &num_devs, &used) != 1)
|
||||
goto_out;
|
||||
pos += used;
|
||||
|
||||
if (num_devs > DM_MIRROR_MAX_IMAGES) {
|
||||
log_error(INTERNAL_ERROR "More then " DM_TO_STRING(DM_MIRROR_MAX_IMAGES)
|
||||
" reported in mirror status.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(s->devs = dm_pool_alloc(mem, num_devs * sizeof(*(s->devs))))) {
|
||||
log_error("Allocation of devs failed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_devs; ++i, pos += used)
|
||||
if (sscanf(pos, "%u:%u %n",
|
||||
&(s->devs[i].major), &(s->devs[i].minor), &used) != 2)
|
||||
goto_out;
|
||||
|
||||
if (sscanf(pos, FMTu64 "/" FMTu64 "%n",
|
||||
&s->insync_regions, &s->total_regions, &used) != 2)
|
||||
goto_out;
|
||||
pos += used;
|
||||
|
||||
if (sscanf(pos, "%u %n", &argc, &used) != 1)
|
||||
goto_out;
|
||||
pos += used;
|
||||
|
||||
for (i = 0; i < num_devs ; ++i)
|
||||
s->devs[i].health = pos[i];
|
||||
|
||||
if (!(pos = _skip_fields(pos, argc)))
|
||||
goto_out;
|
||||
|
||||
if (strncmp(pos, "userspace", 9) == 0) {
|
||||
pos += 9;
|
||||
/* FIXME: support status of userspace mirror implementation */
|
||||
}
|
||||
|
||||
if (sscanf(pos, "%u %n", &argc, &used) != 1)
|
||||
goto_out;
|
||||
pos += used;
|
||||
|
||||
if (argc == 1) {
|
||||
/* core, cluster-core */
|
||||
if (!(s->log_type = dm_pool_strdup(mem, pos))) {
|
||||
log_error("Allocation of log type string failed.");
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (!(p = _skip_fields(pos, 1)))
|
||||
goto_out;
|
||||
|
||||
/* disk, cluster-disk */
|
||||
if (!(s->log_type = dm_pool_strndup(mem, pos, p - pos - 1))) {
|
||||
log_error("Allocation of log type string failed.");
|
||||
goto out;
|
||||
}
|
||||
pos = p;
|
||||
|
||||
if ((argc > 2) && !strcmp(s->log_type, "disk")) {
|
||||
s->log_count = argc - 2;
|
||||
|
||||
if (!(s->logs = dm_pool_alloc(mem, s->log_count * sizeof(*(s->logs))))) {
|
||||
log_error("Allocation of logs failed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < s->log_count; ++i, pos += used)
|
||||
if (sscanf(pos, "%u:%u %n",
|
||||
&s->logs[i].major, &s->logs[i].minor, &used) != 2)
|
||||
goto_out;
|
||||
|
||||
for (i = 0; i < s->log_count; ++i)
|
||||
s->logs[i].health = pos[i];
|
||||
}
|
||||
}
|
||||
|
||||
s->dev_count = num_devs;
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
out:
|
||||
log_error("Failed to parse mirror status %s.", params);
|
||||
dm_pool_free(mem, s);
|
||||
*status = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
179
device_mapper/libdm-timestamp.c
Normal file
179
device_mapper/libdm-timestamp.c
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Rackable Systems All rights reserved.
|
||||
* Copyright (C) 2015 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstract out the time methods used so they can be adjusted later -
|
||||
* the results of these routines should stay in-core.
|
||||
*/
|
||||
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "misc/dmlib.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define NSEC_PER_USEC UINT64_C(1000)
|
||||
#define NSEC_PER_MSEC UINT64_C(1000000)
|
||||
#define NSEC_PER_SEC UINT64_C(1000000000)
|
||||
|
||||
/*
|
||||
* The realtime section uses clock_gettime with the CLOCK_MONOTONIC
|
||||
* parameter to prevent issues with time warps
|
||||
* This implementation requires librt.
|
||||
*/
|
||||
#ifdef HAVE_REALTIME
|
||||
|
||||
#include <time.h>
|
||||
|
||||
struct dm_timestamp {
|
||||
struct timespec t;
|
||||
};
|
||||
|
||||
static uint64_t _timestamp_to_uint64(struct dm_timestamp *ts)
|
||||
{
|
||||
uint64_t stamp = 0;
|
||||
|
||||
stamp += (uint64_t) ts->t.tv_sec * NSEC_PER_SEC;
|
||||
stamp += (uint64_t) ts->t.tv_nsec;
|
||||
|
||||
return stamp;
|
||||
}
|
||||
|
||||
struct dm_timestamp *dm_timestamp_alloc(void)
|
||||
{
|
||||
struct dm_timestamp *ts = NULL;
|
||||
|
||||
if (!(ts = zalloc(sizeof(*ts))))
|
||||
stack;
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
int dm_timestamp_get(struct dm_timestamp *ts)
|
||||
{
|
||||
if (!ts)
|
||||
return 0;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts->t)) {
|
||||
log_sys_error("clock_gettime", "get_timestamp");
|
||||
ts->t.tv_sec = 0;
|
||||
ts->t.tv_nsec = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else /* ! HAVE_REALTIME */
|
||||
|
||||
/*
|
||||
* The !realtime section just uses gettimeofday and is therefore subject
|
||||
* to ntp-type time warps - not sure if should allow that.
|
||||
*/
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
struct dm_timestamp {
|
||||
struct timeval t;
|
||||
};
|
||||
|
||||
static uint64_t _timestamp_to_uint64(struct dm_timestamp *ts)
|
||||
{
|
||||
uint64_t stamp = 0;
|
||||
|
||||
stamp += ts->t.tv_sec * NSEC_PER_SEC;
|
||||
stamp += ts->t.tv_usec * NSEC_PER_USEC;
|
||||
|
||||
return stamp;
|
||||
}
|
||||
|
||||
struct dm_timestamp *dm_timestamp_alloc(void)
|
||||
{
|
||||
struct dm_timestamp *ts;
|
||||
|
||||
if (!(ts = malloc(sizeof(*ts))))
|
||||
stack;
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
int dm_timestamp_get(struct dm_timestamp *ts)
|
||||
{
|
||||
if (!ts)
|
||||
return 0;
|
||||
|
||||
if (gettimeofday(&ts->t, NULL)) {
|
||||
log_sys_error("gettimeofday", "get_timestamp");
|
||||
ts->t.tv_sec = 0;
|
||||
ts->t.tv_usec = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* HAVE_REALTIME */
|
||||
|
||||
/*
|
||||
* Compare two timestamps.
|
||||
*
|
||||
* Return: -1 if ts1 is less than ts2
|
||||
* 0 if ts1 is equal to ts2
|
||||
* 1 if ts1 is greater than ts2
|
||||
*/
|
||||
int dm_timestamp_compare(struct dm_timestamp *ts1, struct dm_timestamp *ts2)
|
||||
{
|
||||
uint64_t t1, t2;
|
||||
|
||||
t1 = _timestamp_to_uint64(ts1);
|
||||
t2 = _timestamp_to_uint64(ts2);
|
||||
|
||||
if (t2 < t1)
|
||||
return 1;
|
||||
|
||||
if (t1 < t2)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the absolute difference in nanoseconds between
|
||||
* the dm_timestamp objects ts1 and ts2.
|
||||
*
|
||||
* Callers that need to know whether ts1 is before, equal to, or after ts2
|
||||
* in addition to the magnitude should use dm_timestamp_compare.
|
||||
*/
|
||||
uint64_t dm_timestamp_delta(struct dm_timestamp *ts1, struct dm_timestamp *ts2)
|
||||
{
|
||||
uint64_t t1, t2;
|
||||
|
||||
t1 = _timestamp_to_uint64(ts1);
|
||||
t2 = _timestamp_to_uint64(ts2);
|
||||
|
||||
if (t1 > t2)
|
||||
return t1 - t2;
|
||||
|
||||
return t2 - t1;
|
||||
}
|
||||
|
||||
void dm_timestamp_copy(struct dm_timestamp *ts_new, struct dm_timestamp *ts_old)
|
||||
{
|
||||
*ts_new = *ts_old;
|
||||
}
|
||||
|
||||
void dm_timestamp_destroy(struct dm_timestamp *ts)
|
||||
{
|
||||
free(ts);
|
||||
}
|
||||
364
device_mapper/misc/dm-ioctl.h
Normal file
364
device_mapper/misc/dm-ioctl.h
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
|
||||
* Copyright (C) 2004 - 2017 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_DM_IOCTL_V4_H
|
||||
#define _LINUX_DM_IOCTL_V4_H
|
||||
|
||||
#ifdef __linux__
|
||||
# include <linux/types.h>
|
||||
#endif
|
||||
|
||||
#define DM_DIR "mapper" /* Slashes not supported */
|
||||
#define DM_CONTROL_NODE "control"
|
||||
#define DM_MAX_TYPE_NAME 16
|
||||
#define DM_NAME_LEN 128
|
||||
#define DM_UUID_LEN 129
|
||||
|
||||
/*
|
||||
* A traditional ioctl interface for the device mapper.
|
||||
*
|
||||
* Each device can have two tables associated with it, an
|
||||
* 'active' table which is the one currently used by io passing
|
||||
* through the device, and an 'inactive' one which is a table
|
||||
* that is being prepared as a replacement for the 'active' one.
|
||||
*
|
||||
* DM_VERSION:
|
||||
* Just get the version information for the ioctl interface.
|
||||
*
|
||||
* DM_REMOVE_ALL:
|
||||
* Remove all dm devices, destroy all tables. Only really used
|
||||
* for debug.
|
||||
*
|
||||
* DM_LIST_DEVICES:
|
||||
* Get a list of all the dm device names.
|
||||
*
|
||||
* DM_DEV_CREATE:
|
||||
* Create a new device, neither the 'active' or 'inactive' table
|
||||
* slots will be filled. The device will be in suspended state
|
||||
* after creation, however any io to the device will get errored
|
||||
* since it will be out-of-bounds.
|
||||
*
|
||||
* DM_DEV_REMOVE:
|
||||
* Remove a device, destroy any tables.
|
||||
*
|
||||
* DM_DEV_RENAME:
|
||||
* Rename a device or set its uuid if none was previously supplied.
|
||||
*
|
||||
* DM_SUSPEND:
|
||||
* This performs both suspend and resume, depending which flag is
|
||||
* passed in.
|
||||
* Suspend: This command will not return until all pending io to
|
||||
* the device has completed. Further io will be deferred until
|
||||
* the device is resumed.
|
||||
* Resume: It is no longer an error to issue this command on an
|
||||
* unsuspended device. If a table is present in the 'inactive'
|
||||
* slot, it will be moved to the active slot, then the old table
|
||||
* from the active slot will be _destroyed_. Finally the device
|
||||
* is resumed.
|
||||
*
|
||||
* DM_DEV_STATUS:
|
||||
* Retrieves the status for the table in the 'active' slot.
|
||||
*
|
||||
* DM_DEV_WAIT:
|
||||
* Wait for a significant event to occur to the device. This
|
||||
* could either be caused by an event triggered by one of the
|
||||
* targets of the table in the 'active' slot, or a table change.
|
||||
*
|
||||
* DM_TABLE_LOAD:
|
||||
* Load a table into the 'inactive' slot for the device. The
|
||||
* device does _not_ need to be suspended prior to this command.
|
||||
*
|
||||
* DM_TABLE_CLEAR:
|
||||
* Destroy any table in the 'inactive' slot (ie. abort).
|
||||
*
|
||||
* DM_TABLE_DEPS:
|
||||
* Return a set of device dependencies for the 'active' table.
|
||||
*
|
||||
* DM_TABLE_STATUS:
|
||||
* Return the targets status for the 'active' table.
|
||||
*
|
||||
* DM_TARGET_MSG:
|
||||
* Pass a message string to the target at a specific offset of a device.
|
||||
*
|
||||
* DM_DEV_SET_GEOMETRY:
|
||||
* Set the geometry of a device by passing in a string in this format:
|
||||
*
|
||||
* "cylinders heads sectors_per_track start_sector"
|
||||
*
|
||||
* Beware that CHS geometry is nearly obsolete and only provided
|
||||
* for compatibility with dm devices that can be booted by a PC
|
||||
* BIOS. See struct hd_geometry for range limits. Also note that
|
||||
* the geometry is erased if the device size changes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* All ioctl arguments consist of a single chunk of memory, with
|
||||
* this structure at the start. If a uuid is specified any
|
||||
* lookup (eg. for a DM_INFO) will be done on that, *not* the
|
||||
* name.
|
||||
*/
|
||||
struct dm_ioctl {
|
||||
/*
|
||||
* The version number is made up of three parts:
|
||||
* major - no backward or forward compatibility,
|
||||
* minor - only backwards compatible,
|
||||
* patch - both backwards and forwards compatible.
|
||||
*
|
||||
* All clients of the ioctl interface should fill in the
|
||||
* version number of the interface that they were
|
||||
* compiled with.
|
||||
*
|
||||
* All recognised ioctl commands (ie. those that don't
|
||||
* return -ENOTTY) fill out this field, even if the
|
||||
* command failed.
|
||||
*/
|
||||
uint32_t version[3]; /* in/out */
|
||||
uint32_t data_size; /* total size of data passed in
|
||||
* including this struct */
|
||||
|
||||
uint32_t data_start; /* offset to start of data
|
||||
* relative to start of this struct */
|
||||
|
||||
uint32_t target_count; /* in/out */
|
||||
int32_t open_count; /* out */
|
||||
uint32_t flags; /* in/out */
|
||||
|
||||
/*
|
||||
* event_nr holds either the event number (input and output) or the
|
||||
* udev cookie value (input only).
|
||||
* The DM_DEV_WAIT ioctl takes an event number as input.
|
||||
* The DM_SUSPEND, DM_DEV_REMOVE and DM_DEV_RENAME ioctls
|
||||
* use the field as a cookie to return in the DM_COOKIE
|
||||
* variable with the uevents they issue.
|
||||
* For output, the ioctls return the event number, not the cookie.
|
||||
*/
|
||||
uint32_t event_nr; /* in/out */
|
||||
uint32_t padding;
|
||||
|
||||
uint64_t dev; /* in/out */
|
||||
|
||||
char name[DM_NAME_LEN]; /* device name */
|
||||
char uuid[DM_UUID_LEN]; /* unique identifier for
|
||||
* the block device */
|
||||
char data[7]; /* padding or data */
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to specify tables. These structures appear after the
|
||||
* dm_ioctl.
|
||||
*/
|
||||
struct dm_target_spec {
|
||||
uint64_t sector_start;
|
||||
uint64_t length;
|
||||
int32_t status; /* used when reading from kernel only */
|
||||
|
||||
/*
|
||||
* Location of the next dm_target_spec.
|
||||
* - When specifying targets on a DM_TABLE_LOAD command, this value is
|
||||
* the number of bytes from the start of the "current" dm_target_spec
|
||||
* to the start of the "next" dm_target_spec.
|
||||
* - When retrieving targets on a DM_TABLE_STATUS command, this value
|
||||
* is the number of bytes from the start of the first dm_target_spec
|
||||
* (that follows the dm_ioctl struct) to the start of the "next"
|
||||
* dm_target_spec.
|
||||
*/
|
||||
uint32_t next;
|
||||
|
||||
char target_type[DM_MAX_TYPE_NAME];
|
||||
|
||||
/*
|
||||
* Parameter string starts immediately after this object.
|
||||
* Be careful to add padding after string to ensure correct
|
||||
* alignment of subsequent dm_target_spec.
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to retrieve the target dependencies.
|
||||
*/
|
||||
struct dm_target_deps {
|
||||
uint32_t count; /* Array size */
|
||||
uint32_t padding; /* unused */
|
||||
uint64_t dev[0]; /* out */
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to get a list of all dm devices.
|
||||
*/
|
||||
struct dm_name_list {
|
||||
uint64_t dev;
|
||||
uint32_t next; /* offset to the next record from
|
||||
the _start_ of this */
|
||||
char name[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to retrieve the target versions
|
||||
*/
|
||||
struct dm_target_versions {
|
||||
uint32_t next;
|
||||
uint32_t version[3];
|
||||
|
||||
char name[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* Used to pass message to a target
|
||||
*/
|
||||
struct dm_target_msg {
|
||||
uint64_t sector; /* Device sector */
|
||||
|
||||
char message[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* If you change this make sure you make the corresponding change
|
||||
* to dm-ioctl.c:lookup_ioctl()
|
||||
*/
|
||||
enum {
|
||||
/* Top level cmds */
|
||||
DM_VERSION_CMD = 0,
|
||||
DM_REMOVE_ALL_CMD,
|
||||
DM_LIST_DEVICES_CMD,
|
||||
|
||||
/* device level cmds */
|
||||
DM_DEV_CREATE_CMD,
|
||||
DM_DEV_REMOVE_CMD,
|
||||
DM_DEV_RENAME_CMD,
|
||||
DM_DEV_SUSPEND_CMD,
|
||||
DM_DEV_STATUS_CMD,
|
||||
DM_DEV_WAIT_CMD,
|
||||
|
||||
/* Table level cmds */
|
||||
DM_TABLE_LOAD_CMD,
|
||||
DM_TABLE_CLEAR_CMD,
|
||||
DM_TABLE_DEPS_CMD,
|
||||
DM_TABLE_STATUS_CMD,
|
||||
|
||||
/* Added later */
|
||||
DM_LIST_VERSIONS_CMD,
|
||||
DM_TARGET_MSG_CMD,
|
||||
DM_DEV_SET_GEOMETRY_CMD,
|
||||
DM_DEV_ARM_POLL_CMD,
|
||||
};
|
||||
|
||||
#define DM_IOCTL 0xfd
|
||||
|
||||
#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
|
||||
#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
|
||||
#define DM_LIST_DEVICES _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_WAIT _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_ARM_POLL _IOWR(DM_IOCTL, DM_DEV_ARM_POLL_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_TABLE_LOAD _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl)
|
||||
#define DM_TABLE_CLEAR _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl)
|
||||
#define DM_TABLE_DEPS _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl)
|
||||
#define DM_TABLE_STATUS _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_TARGET_MSG _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl)
|
||||
#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_VERSION_MAJOR 4
|
||||
#define DM_VERSION_MINOR 36
|
||||
#define DM_VERSION_PATCHLEVEL 0
|
||||
#define DM_VERSION_EXTRA "-ioctl (2017-06-09)"
|
||||
|
||||
/* Status bits */
|
||||
#define DM_READONLY_FLAG (1 << 0) /* In/Out */
|
||||
#define DM_SUSPEND_FLAG (1 << 1) /* In/Out */
|
||||
#define DM_PERSISTENT_DEV_FLAG (1 << 3) /* In */
|
||||
|
||||
/*
|
||||
* Flag passed into ioctl STATUS command to get table information
|
||||
* rather than current status.
|
||||
*/
|
||||
#define DM_STATUS_TABLE_FLAG (1 << 4) /* In */
|
||||
|
||||
/*
|
||||
* Flags that indicate whether a table is present in either of
|
||||
* the two table slots that a device has.
|
||||
*/
|
||||
#define DM_ACTIVE_PRESENT_FLAG (1 << 5) /* Out */
|
||||
#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */
|
||||
|
||||
/*
|
||||
* Indicates that the buffer passed in wasn't big enough for the
|
||||
* results.
|
||||
*/
|
||||
#define DM_BUFFER_FULL_FLAG (1 << 8) /* Out */
|
||||
|
||||
/*
|
||||
* This flag is now ignored.
|
||||
*/
|
||||
#define DM_SKIP_BDGET_FLAG (1 << 9) /* In */
|
||||
|
||||
/*
|
||||
* Set this to avoid attempting to freeze any filesystem when suspending.
|
||||
*/
|
||||
#define DM_SKIP_LOCKFS_FLAG (1 << 10) /* In */
|
||||
|
||||
/*
|
||||
* Set this to suspend without flushing queued ios.
|
||||
* Also disables flushing uncommitted changes in the thin target before
|
||||
* generating statistics for DM_TABLE_STATUS and DM_DEV_WAIT.
|
||||
*/
|
||||
#define DM_NOFLUSH_FLAG (1 << 11) /* In */
|
||||
|
||||
/*
|
||||
* If set, any table information returned will relate to the inactive
|
||||
* table instead of the live one. Always check DM_INACTIVE_PRESENT_FLAG
|
||||
* is set before using the data returned.
|
||||
*/
|
||||
#define DM_QUERY_INACTIVE_TABLE_FLAG (1 << 12) /* In */
|
||||
|
||||
/*
|
||||
* If set, a uevent was generated for which the caller may need to wait.
|
||||
*/
|
||||
#define DM_UEVENT_GENERATED_FLAG (1 << 13) /* Out */
|
||||
|
||||
/*
|
||||
* If set, rename changes the uuid not the name. Only permitted
|
||||
* if no uuid was previously supplied: an existing uuid cannot be changed.
|
||||
*/
|
||||
#define DM_UUID_FLAG (1 << 14) /* In */
|
||||
|
||||
/*
|
||||
* If set, all buffers are wiped after use. Use when sending
|
||||
* or requesting sensitive data such as an encryption key.
|
||||
*/
|
||||
#define DM_SECURE_DATA_FLAG (1 << 15) /* In */
|
||||
|
||||
/*
|
||||
* If set, a message generated output data.
|
||||
*/
|
||||
#define DM_DATA_OUT_FLAG (1 << 16) /* Out */
|
||||
|
||||
/*
|
||||
* If set with DM_DEV_REMOVE or DM_REMOVE_ALL this indicates that if
|
||||
* the device cannot be removed immediately because it is still in use
|
||||
* it should instead be scheduled for removal when it gets closed.
|
||||
*
|
||||
* On return from DM_DEV_REMOVE, DM_DEV_STATUS or other ioctls, this
|
||||
* flag indicates that the device is scheduled to be removed when it
|
||||
* gets closed.
|
||||
*/
|
||||
#define DM_DEFERRED_REMOVE (1 << 17) /* In/Out */
|
||||
|
||||
/*
|
||||
* If set, the device is suspended internally.
|
||||
*/
|
||||
#define DM_INTERNAL_SUSPEND_FLAG (1 << 18) /* Out */
|
||||
|
||||
#endif /* _LINUX_DM_IOCTL_H */
|
||||
418
device_mapper/misc/dm-log-userspace.h
Normal file
418
device_mapper/misc/dm-log-userspace.h
Normal file
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2009 Red Hat, Inc.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef __DM_LOG_USERSPACE_H__
|
||||
#define __DM_LOG_USERSPACE_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "dm-ioctl.h" /* For DM_UUID_LEN */
|
||||
|
||||
/*
|
||||
* The device-mapper userspace log module consists of a kernel component and
|
||||
* a user-space component. The kernel component implements the API defined
|
||||
* in dm-dirty-log.h. Its purpose is simply to pass the parameters and
|
||||
* return values of those API functions between kernel and user-space.
|
||||
*
|
||||
* Below are defined the 'request_types' - DM_ULOG_CTR, DM_ULOG_DTR, etc.
|
||||
* These request types represent the different functions in the device-mapper
|
||||
* dirty log API. Each of these is described in more detail below.
|
||||
*
|
||||
* The user-space program must listen for requests from the kernel (representing
|
||||
* the various API functions) and process them.
|
||||
*
|
||||
* User-space begins by setting up the communication link (error checking
|
||||
* removed for clarity):
|
||||
* fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
|
||||
* addr.nl_family = AF_NETLINK;
|
||||
* addr.nl_groups = CN_IDX_DM;
|
||||
* addr.nl_pid = 0;
|
||||
* r = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
|
||||
* opt = addr.nl_groups;
|
||||
* setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &opt, sizeof(opt));
|
||||
*
|
||||
* User-space will then wait to receive requests from the kernel, which it
|
||||
* will process as described below. The requests are received in the form,
|
||||
* ((struct dm_ulog_request) + (additional data)). Depending on the request
|
||||
* type, there may or may not be 'additional data'. In the descriptions below,
|
||||
* you will see 'Payload-to-userspace' and 'Payload-to-kernel'. The
|
||||
* 'Payload-to-userspace' is what the kernel sends in 'additional data' as
|
||||
* necessary parameters to complete the request. The 'Payload-to-kernel' is
|
||||
* the 'additional data' returned to the kernel that contains the necessary
|
||||
* results of the request. The 'data_size' field in the dm_ulog_request
|
||||
* structure denotes the availability and amount of payload data.
|
||||
*/
|
||||
|
||||
/*
|
||||
* DM_ULOG_CTR corresponds to (found in dm-dirty-log.h):
|
||||
* int (*ctr)(struct dm_dirty_log *log, struct dm_target *ti,
|
||||
* unsigned argc, char **argv);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* A single string containing all the argv arguments separated by ' 's
|
||||
* Payload-to-kernel:
|
||||
* The name of the device that is used as the backing store for the log
|
||||
* data. 'dm_get_device' will be called on this device. ('dm_put_device'
|
||||
* will be called on this device automatically after calling DM_ULOG_DTR.)
|
||||
* If there is no device needed for log data, 'data_size' in the
|
||||
* dm_ulog_request struct should be 0.
|
||||
*
|
||||
* The UUID contained in the dm_ulog_request structure is the reference that
|
||||
* will be used by all request types to a specific log. The constructor must
|
||||
* record this assotiation with the instance created.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field, filling the
|
||||
* data field with the log device if necessary, and setting 'data_size'
|
||||
* appropriately.
|
||||
*/
|
||||
#define DM_ULOG_CTR 1
|
||||
|
||||
/*
|
||||
* DM_ULOG_DTR corresponds to (found in dm-dirty-log.h):
|
||||
* void (*dtr)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* A single string containing all the argv arguments separated by ' 's
|
||||
* Payload-to-kernel:
|
||||
* None. ('data_size' in the dm_ulog_request struct should be 0.)
|
||||
*
|
||||
* The UUID contained in the dm_ulog_request structure is all that is
|
||||
* necessary to identify the log instance being destroyed. There is no
|
||||
* payload data.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and clearing
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_DTR 2
|
||||
|
||||
/*
|
||||
* DM_ULOG_PRESUSPEND corresponds to (found in dm-dirty-log.h):
|
||||
* int (*presuspend)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* The UUID contained in the dm_ulog_request structure is all that is
|
||||
* necessary to identify the log instance being presuspended. There is no
|
||||
* payload data.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_PRESUSPEND 3
|
||||
|
||||
/*
|
||||
* DM_ULOG_POSTSUSPEND corresponds to (found in dm-dirty-log.h):
|
||||
* int (*postsuspend)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* The UUID contained in the dm_ulog_request structure is all that is
|
||||
* necessary to identify the log instance being postsuspended. There is no
|
||||
* payload data.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_POSTSUSPEND 4
|
||||
|
||||
/*
|
||||
* DM_ULOG_RESUME corresponds to (found in dm-dirty-log.h):
|
||||
* int (*resume)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* The UUID contained in the dm_ulog_request structure is all that is
|
||||
* necessary to identify the log instance being resumed. There is no
|
||||
* payload data.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_RESUME 5
|
||||
|
||||
/*
|
||||
* DM_ULOG_GET_REGION_SIZE corresponds to (found in dm-dirty-log.h):
|
||||
* uint32_t (*get_region_size)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* uint64_t - contains the region size
|
||||
*
|
||||
* The region size is something that was determined at constructor time.
|
||||
* It is returned in the payload area and 'data_size' is set to
|
||||
* reflect this.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field appropriately.
|
||||
*/
|
||||
#define DM_ULOG_GET_REGION_SIZE 6
|
||||
|
||||
/*
|
||||
* DM_ULOG_IS_CLEAN corresponds to (found in dm-dirty-log.h):
|
||||
* int (*is_clean)(struct dm_dirty_log *log, region_t region);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* uint64_t - the region to get clean status on
|
||||
* Payload-to-kernel:
|
||||
* int64_t - 1 if clean, 0 otherwise
|
||||
*
|
||||
* Payload is sizeof(uint64_t) and contains the region for which the clean
|
||||
* status is being made.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - filling the payload with 0 (not clean) or
|
||||
* 1 (clean), setting 'data_size' and 'error' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_IS_CLEAN 7
|
||||
|
||||
/*
|
||||
* DM_ULOG_IN_SYNC corresponds to (found in dm-dirty-log.h):
|
||||
* int (*in_sync)(struct dm_dirty_log *log, region_t region,
|
||||
* int can_block);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* uint64_t - the region to get sync status on
|
||||
* Payload-to-kernel:
|
||||
* int64_t - 1 if in-sync, 0 otherwise
|
||||
*
|
||||
* Exactly the same as 'is_clean' above, except this time asking "has the
|
||||
* region been recovered?" vs. "is the region not being modified?"
|
||||
*/
|
||||
#define DM_ULOG_IN_SYNC 8
|
||||
|
||||
/*
|
||||
* DM_ULOG_FLUSH corresponds to (found in dm-dirty-log.h):
|
||||
* int (*flush)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* No incoming or outgoing payload. Simply flush log state to disk.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and clearing
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_FLUSH 9
|
||||
|
||||
/*
|
||||
* DM_ULOG_MARK_REGION corresponds to (found in dm-dirty-log.h):
|
||||
* void (*mark_region)(struct dm_dirty_log *log, region_t region);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* uint64_t [] - region(s) to mark
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* Incoming payload contains the one or more regions to mark dirty.
|
||||
* The number of regions contained in the payload can be determined from
|
||||
* 'data_size/sizeof(uint64_t)'.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and clearing
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_MARK_REGION 10
|
||||
|
||||
/*
|
||||
* DM_ULOG_CLEAR_REGION corresponds to (found in dm-dirty-log.h):
|
||||
* void (*clear_region)(struct dm_dirty_log *log, region_t region);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* uint64_t [] - region(s) to clear
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* Incoming payload contains the one or more regions to mark clean.
|
||||
* The number of regions contained in the payload can be determined from
|
||||
* 'data_size/sizeof(uint64_t)'.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and clearing
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_CLEAR_REGION 11
|
||||
|
||||
/*
|
||||
* DM_ULOG_GET_RESYNC_WORK corresponds to (found in dm-dirty-log.h):
|
||||
* int (*get_resync_work)(struct dm_dirty_log *log, region_t *region);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* {
|
||||
* int64_t i; -- 1 if recovery necessary, 0 otherwise
|
||||
* uint64_t r; -- The region to recover if i=1
|
||||
* }
|
||||
* 'data_size' should be set appropriately.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field appropriately.
|
||||
*/
|
||||
#define DM_ULOG_GET_RESYNC_WORK 12
|
||||
|
||||
/*
|
||||
* DM_ULOG_SET_REGION_SYNC corresponds to (found in dm-dirty-log.h):
|
||||
* void (*set_region_sync)(struct dm_dirty_log *log,
|
||||
* region_t region, int in_sync);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* {
|
||||
* uint64_t - region to set sync state on
|
||||
* int64_t - 0 if not-in-sync, 1 if in-sync
|
||||
* }
|
||||
* Payload-to-kernel:
|
||||
* None.
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and clearing
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_SET_REGION_SYNC 13
|
||||
|
||||
/*
|
||||
* DM_ULOG_GET_SYNC_COUNT corresponds to (found in dm-dirty-log.h):
|
||||
* region_t (*get_sync_count)(struct dm_dirty_log *log);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* uint64_t - the number of in-sync regions
|
||||
*
|
||||
* No incoming payload. Kernel-bound payload contains the number of
|
||||
* regions that are in-sync (in a size_t).
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_GET_SYNC_COUNT 14
|
||||
|
||||
/*
|
||||
* DM_ULOG_STATUS_INFO corresponds to (found in dm-dirty-log.h):
|
||||
* int (*status)(struct dm_dirty_log *log, STATUSTYPE_INFO,
|
||||
* char *result, unsigned maxlen);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* Character string containing STATUSTYPE_INFO
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_STATUS_INFO 15
|
||||
|
||||
/*
|
||||
* DM_ULOG_STATUS_TABLE corresponds to (found in dm-dirty-log.h):
|
||||
* int (*status)(struct dm_dirty_log *log, STATUSTYPE_TABLE,
|
||||
* char *result, unsigned maxlen);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* None.
|
||||
* Payload-to-kernel:
|
||||
* Character string containing STATUSTYPE_TABLE
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_STATUS_TABLE 16
|
||||
|
||||
/*
|
||||
* DM_ULOG_IS_REMOTE_RECOVERING corresponds to (found in dm-dirty-log.h):
|
||||
* int (*is_remote_recovering)(struct dm_dirty_log *log, region_t region);
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* uint64_t - region to determine recovery status on
|
||||
* Payload-to-kernel:
|
||||
* {
|
||||
* int64_t is_recovering; -- 0 if no, 1 if yes
|
||||
* uint64_t in_sync_hint; -- lowest region still needing resync
|
||||
* }
|
||||
*
|
||||
* When the request has been processed, user-space must return the
|
||||
* dm_ulog_request to the kernel - setting the 'error' field and
|
||||
* 'data_size' appropriately.
|
||||
*/
|
||||
#define DM_ULOG_IS_REMOTE_RECOVERING 17
|
||||
|
||||
/*
|
||||
* (DM_ULOG_REQUEST_MASK & request_type) to get the request type
|
||||
*
|
||||
* Payload-to-userspace:
|
||||
* A single string containing all the argv arguments separated by ' 's
|
||||
* Payload-to-kernel:
|
||||
* None. ('data_size' in the dm_ulog_request struct should be 0.)
|
||||
*
|
||||
* We are reserving 8 bits of the 32-bit 'request_type' field for the
|
||||
* various request types above. The remaining 24-bits are currently
|
||||
* set to zero and are reserved for future use and compatibility concerns.
|
||||
*
|
||||
* User-space should always use DM_ULOG_REQUEST_TYPE to acquire the
|
||||
* request type from the 'request_type' field to maintain forward compatibility.
|
||||
*/
|
||||
#define DM_ULOG_REQUEST_MASK 0xFF
|
||||
#define DM_ULOG_REQUEST_TYPE(request_type) \
|
||||
(DM_ULOG_REQUEST_MASK & (request_type))
|
||||
|
||||
/*
|
||||
* DM_ULOG_REQUEST_VERSION is incremented when there is a
|
||||
* change to the way information is passed between kernel
|
||||
* and userspace. This could be a structure change of
|
||||
* dm_ulog_request or a change in the way requests are
|
||||
* issued/handled. Changes are outlined here:
|
||||
* version 1: Initial implementation
|
||||
* version 2: DM_ULOG_CTR allowed to return a string containing a
|
||||
* device name that is to be registered with DM via
|
||||
* 'dm_get_device'.
|
||||
*/
|
||||
#define DM_ULOG_REQUEST_VERSION 2
|
||||
|
||||
struct dm_ulog_request {
|
||||
/*
|
||||
* The local unique identifier (luid) and the universally unique
|
||||
* identifier (uuid) are used to tie a request to a specific
|
||||
* mirror log. A single machine log could probably make due with
|
||||
* just the 'luid', but a cluster-aware log must use the 'uuid' and
|
||||
* the 'luid'. The uuid is what is required for node to node
|
||||
* communication concerning a particular log, but the 'luid' helps
|
||||
* differentiate between logs that are being swapped and have the
|
||||
* same 'uuid'. (Think "live" and "inactive" device-mapper tables.)
|
||||
*/
|
||||
uint64_t luid;
|
||||
char uuid[DM_UUID_LEN];
|
||||
char padding[3]; /* Padding because DM_UUID_LEN = 129 */
|
||||
|
||||
uint32_t version; /* See DM_ULOG_REQUEST_VERSION */
|
||||
int32_t error; /* Used to report back processing errors */
|
||||
|
||||
uint32_t seq; /* Sequence number for request */
|
||||
uint32_t request_type; /* DM_ULOG_* defined above */
|
||||
uint32_t data_size; /* How much data (not including this struct) */
|
||||
|
||||
char data[];
|
||||
};
|
||||
|
||||
#endif /* __DM_LOG_USERSPACE_H__ */
|
||||
34
device_mapper/misc/dm-logging.h
Normal file
34
device_mapper/misc/dm-logging.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-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 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 _DM_LOGGING_H
|
||||
#define _DM_LOGGING_H
|
||||
|
||||
#include "device_mapper/all.h"
|
||||
|
||||
extern dm_log_with_errno_fn dm_log_with_errno;
|
||||
|
||||
#define LOG_MESG(l, f, ln, e, x...) \
|
||||
dm_log_with_errno(l, f, ln, e, ## x)
|
||||
|
||||
#define LOG_LINE(l, x...) LOG_MESG(l, __FILE__, __LINE__, 0, ## x)
|
||||
#define LOG_LINE_WITH_ERRNO(l, e, x...) LOG_MESG(l, __FILE__, __LINE__, e, ## x)
|
||||
|
||||
/* Debug messages may have a type instead of an errno */
|
||||
#define LOG_LINE_WITH_CLASS(l, c, x...) LOG_MESG(l, __FILE__, __LINE__, c, ## x)
|
||||
|
||||
#include "lib/log/log.h"
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user