mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-27 00:23:49 +03:00
Compare commits
1 Commits
dev-dct-pv
...
dev-dct-wr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6e67d688e |
22
.gitignore
vendored
22
.gitignore
vendored
@@ -16,10 +16,6 @@
|
||||
*.sw*
|
||||
*~
|
||||
|
||||
# gcov files:
|
||||
*.gcda
|
||||
*.gcno
|
||||
|
||||
.export.sym
|
||||
.exported_symbols_generated
|
||||
.gdb_history
|
||||
@@ -36,18 +32,15 @@ make.tmpl
|
||||
/configure.scan
|
||||
/cscope.*
|
||||
/html/
|
||||
/python/
|
||||
/reports/
|
||||
/tags
|
||||
/tmp/
|
||||
|
||||
coverity/coverity_model.xml
|
||||
|
||||
/libdm/.symver_check
|
||||
|
||||
daemons/clvmd
|
||||
daemons/dmfilemapd
|
||||
daemons/lvmetad/
|
||||
# gcov files:
|
||||
*.gcda
|
||||
*.gcno
|
||||
|
||||
tools/man-generator
|
||||
tools/man-generator.c
|
||||
@@ -108,8 +101,6 @@ test/api/thin_percent.t
|
||||
test/api/vglist.t
|
||||
test/api/vgtest.t
|
||||
test/lib/aux
|
||||
test/lib/cache-mq.profile
|
||||
test/lib/cache-smq.profile
|
||||
test/lib/check
|
||||
test/lib/clvmd
|
||||
test/lib/dm-version-expected
|
||||
@@ -119,7 +110,6 @@ test/lib/dmstats
|
||||
test/lib/fail
|
||||
test/lib/flavour-ndev-cluster
|
||||
test/lib/flavour-ndev-cluster-lvmpolld
|
||||
test/lib/flavour-ndev-devicesfile
|
||||
test/lib/flavour-ndev-lvmetad
|
||||
test/lib/flavour-ndev-lvmetad-lvmpolld
|
||||
test/lib/flavour-ndev-lvmpolld
|
||||
@@ -129,7 +119,6 @@ test/lib/flavour-udev-cluster-lvmpolld
|
||||
test/lib/flavour-udev-lvmetad
|
||||
test/lib/flavour-udev-lvmetad-lvmpolld
|
||||
test/lib/flavour-udev-lvmlockd-dlm
|
||||
test/lib/flavour-udev-lvmlockd-idm
|
||||
test/lib/flavour-udev-lvmlockd-sanlock
|
||||
test/lib/flavour-udev-lvmlockd-test
|
||||
test/lib/flavour-udev-lvmpolld
|
||||
@@ -142,11 +131,8 @@ test/lib/lvm
|
||||
test/lib/lvm-wrapper
|
||||
test/lib/lvmchange
|
||||
test/lib/lvmdbusd.profile
|
||||
test/lib/lvmdevices
|
||||
test/lib/lvmetad
|
||||
test/lib/lvmpolld
|
||||
test/lib/lvm_import_vdo
|
||||
test/lib/lvm_vdo_wrapper
|
||||
test/lib/not
|
||||
test/lib/paths
|
||||
test/lib/paths-common
|
||||
@@ -156,7 +142,5 @@ test/lib/test
|
||||
test/lib/thin-performance.profile
|
||||
test/lib/utils
|
||||
test/lib/version-expected
|
||||
test/lib/vgimportdevices
|
||||
|
||||
test/unit/dmraid_t.c
|
||||
test/unit/unit-test
|
||||
|
||||
47
Makefile.in
47
Makefile.in
@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
|
||||
SUBDIRS = libdm conf daemons include lib libdaemon man scripts tools
|
||||
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
|
||||
|
||||
ifeq ("@UDEV_RULES@", "yes")
|
||||
SUBDIRS += udev
|
||||
@@ -47,20 +47,25 @@ include $(top_srcdir)/base/Makefile
|
||||
include $(top_srcdir)/device_mapper/Makefile
|
||||
include $(top_srcdir)/test/unit/Makefile
|
||||
|
||||
lib: include libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
|
||||
libdm: include
|
||||
libdaemon: include
|
||||
lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
|
||||
daemons: lib libdaemon tools
|
||||
scripts: lib
|
||||
tools: lib libdaemon
|
||||
po: tools daemons
|
||||
man: tools
|
||||
all_man: tools
|
||||
scripts: libdm
|
||||
test: tools daemons
|
||||
unit-test run-unit-test: test
|
||||
|
||||
lib.device-mapper: include.device-mapper
|
||||
libdm.device-mapper: include.device-mapper
|
||||
daemons.device-mapper: libdm.device-mapper
|
||||
tools.device-mapper: libdm.device-mapper
|
||||
scripts.device-mapper: include.device-mapper
|
||||
device-mapper: tools.device-mapper daemons.device-mapper man.device-mapper
|
||||
device_mapper: device-mapper
|
||||
|
||||
ifeq ("@INTL@", "yes")
|
||||
lib.pofile: include.pofile
|
||||
@@ -76,10 +81,9 @@ daemons.cflow: tools.cflow
|
||||
cflow: include.cflow
|
||||
endif
|
||||
|
||||
CSCOPE_DIRS = base daemons device_mapper include lib libdaemon scripts tools libdm test
|
||||
ifneq ("@CSCOPE_CMD@", "")
|
||||
cscope.out:
|
||||
@CSCOPE_CMD@ -b -R $(patsubst %,-s%,$(addprefix $(srcdir)/,$(CSCOPE_DIRS)))
|
||||
@CSCOPE_CMD@ -b -R -s$(top_srcdir)
|
||||
all: cscope.out
|
||||
endif
|
||||
DISTCLEAN_TARGETS += cscope.out
|
||||
@@ -112,11 +116,11 @@ rpm: dist
|
||||
$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES
|
||||
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," \
|
||||
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," \
|
||||
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
|
||||
V=$(V) rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
|
||||
rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
|
||||
|
||||
generate: conf.generate man.generate
|
||||
$(MAKE) -C conf generate
|
||||
@@ -150,31 +154,6 @@ install_all_man:
|
||||
install_tmpfiles_configuration:
|
||||
$(MAKE) -C scripts install_tmpfiles_configuration
|
||||
|
||||
help:
|
||||
@echo -e "\nAvailable targets:"
|
||||
@echo " all Default target."
|
||||
@echo " all_man Build all man pages with generators."
|
||||
@echo " clean Remove all compile files."
|
||||
@echo " device-mapper Device mapper part of lvm2."
|
||||
@echo " dist Generate distributable file."
|
||||
@echo " distclean Remove all build files."
|
||||
@echo " generate Generate man pages for sources."
|
||||
@echo " help Display callable targets."
|
||||
@echo " install Install all files."
|
||||
@echo " install_all_man Install all man pages."
|
||||
@echo " install_cluster Install cmirrord."
|
||||
@echo " install_device-mapper Install device mapper files."
|
||||
@echo " install_initscripts Install initialization scripts."
|
||||
@echo " install_lvm2 Install lvm2 files."
|
||||
@echo " install_systemd_units Install systemd units."
|
||||
@echo " lcov Generate lcov output."
|
||||
@echo " lcov-dated Generate lcov with timedate suffix."
|
||||
@echo " lcov-reset Reset lcov counters"
|
||||
@echo " man Build man pages."
|
||||
@echo " rpm Build rpm."
|
||||
@echo " run-unit-test Run unit tests."
|
||||
@echo " tags Generate c/etags."
|
||||
|
||||
ifneq ("$(LCOV)", "")
|
||||
.PHONY: lcov-reset lcov lcov-dated
|
||||
|
||||
@@ -204,8 +183,8 @@ endif
|
||||
ifneq ($(shell which ctags 2>/dev/null),)
|
||||
.PHONY: tags
|
||||
tags:
|
||||
test -z "$(shell find $(addprefix $(top_srcdir)/,$(CSCOPE_DIRS)) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
||||
test -f tags || find $(addprefix $(top_srcdir)/,$(CSCOPE_DIRS)) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
||||
test -f tags || find $(top_srcdir) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||
|
||||
CLEAN_TARGETS += tags
|
||||
endif
|
||||
|
||||
2
TESTING
2
TESTING
@@ -24,7 +24,7 @@ You MUST disable (or mask) any LVM daemons:
|
||||
For running cluster tests, we are using singlenode locking. Pass
|
||||
`--with-clvmd=singlenode` to configure.
|
||||
|
||||
NOTE: This is useful only for testing, and should not be used in production
|
||||
NOTE: This is useful only for testing, and should not be used in produciton
|
||||
code.
|
||||
|
||||
To run D-Bus daemon tests, existing D-Bus session is required.
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.02.191-git (2022-12-22)
|
||||
1.02.175-git (2020-08-09)
|
||||
|
||||
163
WHATS_NEW
163
WHATS_NEW
@@ -1,157 +1,6 @@
|
||||
version 2.03.19 -
|
||||
====================================
|
||||
Fix and improve runtime memory size detection for VDO volumes.
|
||||
|
||||
version 2.03.18 - 22nd december 2022
|
||||
====================================
|
||||
Fix issues reported by coverity scan.
|
||||
Fix warning for thin pool overprovisioning on lvextend (2.03.17).
|
||||
Add support for writecache metadata_only and pause_writeback settings.
|
||||
Fix missing error messages in lvmdbusd.
|
||||
|
||||
Version 2.03.17 - 10th November 2022
|
||||
====================================
|
||||
Add new options (--fs, --fsmode) for FS handling when resizing LVs.
|
||||
Fix 'lvremove -S|--select LV' to not also remove its historical LV right away.
|
||||
Fix lv_active field type to binary so --select and --binary applies properly.
|
||||
Switch to use mallinfo2 and use it only with glibc.
|
||||
Error out in lvm shell if using a cmd argument not supported in the shell.
|
||||
Fix lvm shell's lastlog command to report previous pre-command failures.
|
||||
Extend VDO and VDOPOOL without flushing and locking fs.
|
||||
Add --valuesonly option to lvmconfig to print only values without keys.
|
||||
Updates configure with recent autoconf tooling.
|
||||
Fix lvconvert --test --type vdo-pool execution.
|
||||
Add json_std output format for more JSON standard compliant version of output.
|
||||
Fix vdo_slab_size_mb value for converted VDO volume.
|
||||
Fix many corner cases in device_id, including handling of S/N duplicates.
|
||||
Fix various issues in lvmdbusd.
|
||||
|
||||
Version 2.03.16 - 18th May 2022
|
||||
===============================
|
||||
Fix segfault when handling selection with historical LVs.
|
||||
Add support --vdosettings with lvcreate, lvconvert, lvchange.
|
||||
Filtering multipath devices respects blacklist setting from multipath
|
||||
configuration.
|
||||
lvmdevices support for removing by device id using --deviceidtype and
|
||||
--deldev.
|
||||
Display writecache block size with lvs -o writecache_block_size.
|
||||
Improve cachesettings description in man lvmcache.
|
||||
Fix lossing of delete message on thin-pool extension.
|
||||
|
||||
Version 2.03.15 - 07th February 2022
|
||||
====================================
|
||||
Remove service based autoactivation. global/event_activation = 0 is NOOP.
|
||||
Improve support for metadata profiles for --type writecache.
|
||||
Use cache or active DM device when available with new kernels.
|
||||
Introduce function to utilize UUIDs from DM_DEVICE_LIST.
|
||||
Increase some hash table size to better support large device sets.
|
||||
|
||||
Version 2.03.14 - 20th October 2021
|
||||
===================================
|
||||
Device scanning is skipping directories on different filesystems.
|
||||
Print info message with too many or too large archived files.
|
||||
Reduce metadata readings during scanning phase.
|
||||
Optimize computation of crc32 check sum with multiple PVs.
|
||||
Enhance recover path on cache creation failure.
|
||||
Filter out unsupported MQ/SMQ cache policy setting.
|
||||
Fix memleak in mpath filter.
|
||||
Support newer location for VDO statistics.
|
||||
Add support for VDO async-unsafe write policy.
|
||||
Improve lvm_import_vdo script.
|
||||
Support VDO LV with lvcreate -ky.
|
||||
Fix lvconvert for VDO LV bigger then 2T.
|
||||
Create VDO LVs automatically without zeroing.
|
||||
Rename vdoimport to lvm_import_vdo.
|
||||
|
||||
Version 2.03.13 - 11th August 2021
|
||||
Version 2.03.11 -
|
||||
==================================
|
||||
Changes in udev support:
|
||||
- obtain_device_list_from_udev defaults to 0.
|
||||
- see devices/external_device_info_source,
|
||||
devices/obtain_device_list_from_udev, and devices/multipath_wwids_file help
|
||||
in lvm.conf
|
||||
Fix devices file handling of loop with deleted backing file.
|
||||
Fix devices file handling of scsi_debug WWIDs.
|
||||
Fix many static analysis issues.
|
||||
Support --poolmetadataspare with vgsplit and vgmerge.
|
||||
Fix detection of active components of external origin volume.
|
||||
Add vdoimport tool to support conversion of VDO volumes.
|
||||
Support configurable allocation/vdo_pool_header_size.
|
||||
Fix handling of lvconvert --type vdo-pool --virtualsize.
|
||||
Simplified handling of archive() and backup() internal calls.
|
||||
Add 'idm' locking type for IDM lock manager.
|
||||
Fix load of kvdo target when it is not present in memory (2.03.12).
|
||||
|
||||
Version 2.03.12 - 07th May 2021
|
||||
===============================
|
||||
Allow attaching cache to thin data volume.
|
||||
Fix memleak when generating list of outdated pvs.
|
||||
Better hyphenation usage in man pages.
|
||||
Replace use of deprecated security_context_t with char*.
|
||||
Configure supports AIO_LIBS and AIO_CFLAGS.
|
||||
Improve build process for static builds.
|
||||
New --setautoactivation option to modify LV or VG auto activation.
|
||||
New metadata based autoactivation property for LVs and VGs.
|
||||
Improve signal handling with lvmpolld.
|
||||
Signal handler can interrupt command also for SIGTERM.
|
||||
Lvreduce --yes support.
|
||||
Add configure option --with/out-symvers for non-glibc builds.
|
||||
Report error when the filesystem is missing on fsadm resized volume.
|
||||
Handle better blockdev with --getsize64 support for fsadm.
|
||||
Do not include editline/history.h when using editline library.
|
||||
Support error and zero segtype for thin-pool data for testing.
|
||||
Support mixed extension for striped, error and zero segtypes.
|
||||
Support resize also for stacked virtual volumes.
|
||||
Skip dm-zero devices just like with dm-error target.
|
||||
Reduce ioctl() calls when checking target status.
|
||||
Merge polling does not fail, when LV is found to be already merged.
|
||||
Poll volumes with at least 100ms delays.
|
||||
Do not flush dm cache when cached LV is going to be removed.
|
||||
New lvmlockctl_kill_command configuration option.
|
||||
Support interruption while waiting on device close before deactivation.
|
||||
Flush thin-pool messages before removing more thin volumes.
|
||||
Improve hash function with less collisions and make it faster.
|
||||
Reduce ioctl count when deactivating volumes.
|
||||
Reduce number of metadata parsing.
|
||||
Enhance performance of lvremove and vgremove commands.
|
||||
Support interruption when taking archive and backup.
|
||||
Accelerate large lvremoves.
|
||||
Speedup search for cached device nodes.
|
||||
Speedup command initialization.
|
||||
Add devices file feature, off by default for now.
|
||||
Support extension of writecached volumes.
|
||||
Fix problem with unbound variable usage within fsadm.
|
||||
Fix IMSM MD RAID detection on 4k devices.
|
||||
Check for presence of VDO target before starting any conversion.
|
||||
Support metatadata profiles with volume VDO pool conversions.
|
||||
Support -Zn for conversion of already formated VDO pools.
|
||||
Avoid removing LVs on error path of lvconvert during creation volumes.
|
||||
Fix crashing lvdisplay when thin volume was waiting for merge.
|
||||
Support option --errorwhenfull when converting volume to thin-pool.
|
||||
Improve thin-performance profile support conversion to thin-pool.
|
||||
Add workaround to avoid read of internal 'converted' devices.
|
||||
Prohibit merging snapshot into the read-only thick snapshot origin.
|
||||
Restore support for flipping rw/r permissions for thin snapshot origin.
|
||||
Support resize of cached volumes.
|
||||
Disable autoactivation with global/event_activation=0.
|
||||
Check if lvcreate passes read_only_volume_list with tags and skips zeroing.
|
||||
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 conversion and allocation of pool metadata.
|
||||
Support thin pool metadata 15.88GiB, adds 64MiB, thin_pool_crop_metadata=0.
|
||||
Enhance lvdisplay to report raid available/partial.
|
||||
Support online rename of VDO pools.
|
||||
Improve removal of pmspare when last pool is removed.
|
||||
Fix problem with wiping of converted LVs.
|
||||
Fix memleak in scanning (2.03.11).
|
||||
Fix corner case allocation for thin-pools.
|
||||
|
||||
Version 2.03.11 - 08th January 2021
|
||||
===================================
|
||||
Fix pvck handling MDA at offset different from 4096.
|
||||
Partial or degraded activation of writecache is not allowed.
|
||||
Enhance error handling for fsadm and handle correct fsck result.
|
||||
Enhance error handling for fsadm and hanled correct fsck result.
|
||||
Dmeventd lvm plugin ignores higher reserved_stack lvm.conf values.
|
||||
Support using BLKZEROOUT for clearing devices.
|
||||
Support interruption when wipping LVs.
|
||||
@@ -171,9 +20,6 @@ Version 2.03.11 - 08th January 2021
|
||||
Enhance --use-policy percentage rounding.
|
||||
Configure --with-vdo and --with-writecache as internal segments.
|
||||
Improving VDO man page examples.
|
||||
Allow pvmove of writecache origin.
|
||||
Report integrity fields.
|
||||
Integrity volumes defaults to journal mode.
|
||||
Switch code base to use flexible array syntax.
|
||||
Fix 64bit math when calculation cachevol size.
|
||||
Preserve uint32_t for seqno handling.
|
||||
@@ -197,7 +43,7 @@ Version 2.03.10 - 09th August 2020
|
||||
|
||||
Version 2.03.09 - 26th March 2020
|
||||
=================================
|
||||
Fix formatting of vdopool (vdo_slab_size_mb was smaller by 2 bits).
|
||||
Fix formating of vdopool (vdo_slab_size_mb was smaller by 2 bits).
|
||||
Fix showing of a dm kernel error when uncaching a volume with cachevol.
|
||||
|
||||
Version 2.03.08 - 11th February 2020
|
||||
@@ -345,6 +191,7 @@ Version 2.03.00 - 10th October 2018
|
||||
Remove clvmd
|
||||
Remove lvmlib (api)
|
||||
Remove lvmetad
|
||||
lvconvert: provide possible layouts between linear and striped/raid
|
||||
Use versionsort to fix archive file expiry beyond 100000 files.
|
||||
|
||||
Version 2.02.178-rc1 - 24th May 2018
|
||||
@@ -1864,7 +1711,7 @@ Version 2.02.105 - 20th January 2014
|
||||
Allow lvmetad to reuse stale socket.
|
||||
Only unlink lvmetad socket on error if created by the same process.
|
||||
Append missing newline to lvmetad missing socket path error message.
|
||||
Check for non-zero alignment in _text_pv_add_metadata_area() to not div by 0.
|
||||
Check for non-zero aligment in _text_pv_add_metadata_area() to not div by 0.
|
||||
Add allocation/use_blkid_wiping to lvm.conf to enable blkid wiping.
|
||||
Enable blkid_wiping by default if the blkid library is present.
|
||||
Add configure --disable-blkid_wiping to disable libblkid signature detection.
|
||||
|
||||
38
WHATS_NEW_DM
38
WHATS_NEW_DM
@@ -1,40 +1,6 @@
|
||||
Version 1.02.191 -
|
||||
=====================================
|
||||
|
||||
Version 1.02.189 - 22nd December 2022
|
||||
=====================================
|
||||
Improve 'dmsetup create' without given table line with new kernels.
|
||||
|
||||
Version 1.02.187 - 10th November 2022
|
||||
=====================================
|
||||
Add DM_REPORT_GROUP_JSON_STD for more JSON standard compliant output format.
|
||||
|
||||
Version 1.02.185 - 18th May 2022
|
||||
================================
|
||||
|
||||
Version 1.02.183 - 07th February 2022
|
||||
=====================================
|
||||
Unmangle UUIDs for DM_DEVICE_LIST ioctl.
|
||||
|
||||
Version 1.02.181 - 20th October 2021
|
||||
====================================
|
||||
Add IMA support with 'dmsetup measure' command.
|
||||
Add defines DM_NAME_LIST_FLAG_HAS_UUID, DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID.
|
||||
Enhance tracking of activated devices when preloading dm tree.
|
||||
Fix bug in construction of cache table line (regression from 1.02.159).
|
||||
|
||||
Version 1.02.179 - 11th August 2021
|
||||
Version 1.02.175 -
|
||||
===================================
|
||||
|
||||
Version 1.02.177 - 07th May 2021
|
||||
================================
|
||||
Configure proceeds without libaio to allow build of device-mapper only.
|
||||
Fix symbol versioning build with -O2 -flto.
|
||||
Add dm_tree_node_add_thin_pool_target_v1 with crop_metadata support.
|
||||
|
||||
Version 1.02.175 - 08th January 2021
|
||||
====================================
|
||||
|
||||
Version 1.02.173 - 09th August 2020
|
||||
===================================
|
||||
Add support for VDO in blkdeactivate script.
|
||||
@@ -585,7 +551,7 @@ Version 1.02.86 - 23rd June 2014
|
||||
Add DM_REPORT_FIELD_TYPE_STRING_LIST: separate string and string list fields.
|
||||
Add dm_str_list to libdevmapper for string list type definition and its reuse.
|
||||
Add dmsetup -S/--select to define selection criteria for dmsetup reports.
|
||||
Add dm_report_init_with_selection to initialize report with selection criteria.
|
||||
Add dm_report_init_with_selection to intialize report with selection criteria.
|
||||
Add DM_REPORT_FIELD_TYPE_SIZE: separate number and size reporting fields.
|
||||
Use RemoveOnStop for dm-event.socket systemd unit.
|
||||
Document env var 'DM_DEFAULT_NAME_MANGLING_MODE' in dmsetup man page.
|
||||
|
||||
280
aclocal.m4
vendored
280
aclocal.m4
vendored
@@ -1,6 +1,6 @@
|
||||
# generated automatically by aclocal 1.16.5 -*- Autoconf -*-
|
||||
# generated automatically by aclocal 1.16.2 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2020 Free Software Foundation, Inc.
|
||||
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
@@ -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-2021 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1999-2020 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
@@ -492,141 +492,34 @@ AC_DEFUN([AM_PATH_PYTHON],
|
||||
])
|
||||
|
||||
if test "$PYTHON" = :; then
|
||||
dnl Run any user-specified action, or abort.
|
||||
dnl Run any user-specified action, or abort.
|
||||
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
|
||||
else
|
||||
|
||||
dnl Query Python for its version number. Although site.py simply uses
|
||||
dnl sys.version[:3], printing that failed with Python 3.10, since the
|
||||
dnl trailing zero was eliminated. So now we output just the major
|
||||
dnl and minor version numbers, as numbers. Apparently the tertiary
|
||||
dnl version is not of interest.
|
||||
dnl
|
||||
dnl Query Python for its version number. Getting [:3] seems to be
|
||||
dnl the best way to do this; it's what "site.py" does in the standard
|
||||
dnl library.
|
||||
|
||||
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
|
||||
[am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[[:2]])"`])
|
||||
[am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`])
|
||||
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
|
||||
|
||||
dnl At times, e.g., when building shared libraries, you may want
|
||||
dnl Use the values of $prefix and $exec_prefix for the corresponding
|
||||
dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
|
||||
dnl distinct variables so they can be overridden if need be. However,
|
||||
dnl general consensus is that you shouldn't need this ability.
|
||||
|
||||
AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
|
||||
AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
|
||||
|
||||
dnl At times (like when building shared libraries) you may want
|
||||
dnl to know which OS platform Python thinks this is.
|
||||
dnl
|
||||
|
||||
AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
|
||||
[am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
|
||||
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
|
||||
|
||||
dnl emacs-page
|
||||
dnl If --with-python-sys-prefix is given, use the values of sys.prefix
|
||||
dnl and sys.exec_prefix for the corresponding values of PYTHON_PREFIX
|
||||
dnl and PYTHON_EXEC_PREFIX. Otherwise, use the GNU ${prefix} and
|
||||
dnl ${exec_prefix} variables.
|
||||
dnl
|
||||
dnl The two are made distinct variables so they can be overridden if
|
||||
dnl need be, although general consensus is that you shouldn't need
|
||||
dnl this separation.
|
||||
dnl
|
||||
dnl Also allow directly setting the prefixes via configure options,
|
||||
dnl overriding any default.
|
||||
dnl
|
||||
if test "x$prefix" = xNONE; then
|
||||
am__usable_prefix=$ac_default_prefix
|
||||
else
|
||||
am__usable_prefix=$prefix
|
||||
fi
|
||||
|
||||
# Allow user to request using sys.* values from Python,
|
||||
# instead of the GNU $prefix values.
|
||||
AC_ARG_WITH([python-sys-prefix],
|
||||
[AS_HELP_STRING([--with-python-sys-prefix],
|
||||
[use Python's sys.prefix and sys.exec_prefix values])],
|
||||
[am_use_python_sys=:],
|
||||
[am_use_python_sys=false])
|
||||
|
||||
# Allow user to override whatever the default Python prefix is.
|
||||
AC_ARG_WITH([python_prefix],
|
||||
[AS_HELP_STRING([--with-python_prefix],
|
||||
[override the default PYTHON_PREFIX])],
|
||||
[am_python_prefix_subst=$withval
|
||||
am_cv_python_prefix=$withval
|
||||
AC_MSG_CHECKING([for explicit $am_display_PYTHON prefix])
|
||||
AC_MSG_RESULT([$am_cv_python_prefix])],
|
||||
[
|
||||
if $am_use_python_sys; then
|
||||
# using python sys.prefix value, not GNU
|
||||
AC_CACHE_CHECK([for python default $am_display_PYTHON prefix],
|
||||
[am_cv_python_prefix],
|
||||
[am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"`])
|
||||
|
||||
dnl If sys.prefix is a subdir of $prefix, replace the literal value of
|
||||
dnl $prefix with a variable reference so it can be overridden.
|
||||
case $am_cv_python_prefix in
|
||||
$am__usable_prefix*)
|
||||
am__strip_prefix=`echo "$am__usable_prefix" | sed 's|.|.|g'`
|
||||
am_python_prefix_subst=`echo "$am_cv_python_prefix" | sed "s,^$am__strip_prefix,\\${prefix},"`
|
||||
;;
|
||||
*)
|
||||
am_python_prefix_subst=$am_cv_python_prefix
|
||||
;;
|
||||
esac
|
||||
else # using GNU prefix value, not python sys.prefix
|
||||
am_python_prefix_subst='${prefix}'
|
||||
am_python_prefix=$am_python_prefix_subst
|
||||
AC_MSG_CHECKING([for GNU default $am_display_PYTHON prefix])
|
||||
AC_MSG_RESULT([$am_python_prefix])
|
||||
fi])
|
||||
# Substituting python_prefix_subst value.
|
||||
AC_SUBST([PYTHON_PREFIX], [$am_python_prefix_subst])
|
||||
|
||||
# emacs-page Now do it all over again for Python exec_prefix, but with yet
|
||||
# another conditional: fall back to regular prefix if that was specified.
|
||||
AC_ARG_WITH([python_exec_prefix],
|
||||
[AS_HELP_STRING([--with-python_exec_prefix],
|
||||
[override the default PYTHON_EXEC_PREFIX])],
|
||||
[am_python_exec_prefix_subst=$withval
|
||||
am_cv_python_exec_prefix=$withval
|
||||
AC_MSG_CHECKING([for explicit $am_display_PYTHON exec_prefix])
|
||||
AC_MSG_RESULT([$am_cv_python_exec_prefix])],
|
||||
[
|
||||
# no explicit --with-python_exec_prefix, but if
|
||||
# --with-python_prefix was given, use its value for python_exec_prefix too.
|
||||
AS_IF([test -n "$with_python_prefix"],
|
||||
[am_python_exec_prefix_subst=$with_python_prefix
|
||||
am_cv_python_exec_prefix=$with_python_prefix
|
||||
AC_MSG_CHECKING([for python_prefix-given $am_display_PYTHON exec_prefix])
|
||||
AC_MSG_RESULT([$am_cv_python_exec_prefix])],
|
||||
[
|
||||
# Set am__usable_exec_prefix whether using GNU or Python values,
|
||||
# since we use that variable for pyexecdir.
|
||||
if test "x$exec_prefix" = xNONE; then
|
||||
am__usable_exec_prefix=$am__usable_prefix
|
||||
else
|
||||
am__usable_exec_prefix=$exec_prefix
|
||||
fi
|
||||
#
|
||||
if $am_use_python_sys; then # using python sys.exec_prefix, not GNU
|
||||
AC_CACHE_CHECK([for python default $am_display_PYTHON exec_prefix],
|
||||
[am_cv_python_exec_prefix],
|
||||
[am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"`])
|
||||
dnl If sys.exec_prefix is a subdir of $exec_prefix, replace the
|
||||
dnl literal value of $exec_prefix with a variable reference so it can
|
||||
dnl be overridden.
|
||||
case $am_cv_python_exec_prefix in
|
||||
$am__usable_exec_prefix*)
|
||||
am__strip_prefix=`echo "$am__usable_exec_prefix" | sed 's|.|.|g'`
|
||||
am_python_exec_prefix_subst=`echo "$am_cv_python_exec_prefix" | sed "s,^$am__strip_prefix,\\${exec_prefix},"`
|
||||
;;
|
||||
*)
|
||||
am_python_exec_prefix_subst=$am_cv_python_exec_prefix
|
||||
;;
|
||||
esac
|
||||
else # using GNU $exec_prefix, not python sys.exec_prefix
|
||||
am_python_exec_prefix_subst='${exec_prefix}'
|
||||
am_python_exec_prefix=$am_python_exec_prefix_subst
|
||||
AC_MSG_CHECKING([for GNU default $am_display_PYTHON exec_prefix])
|
||||
AC_MSG_RESULT([$am_python_exec_prefix])
|
||||
fi])])
|
||||
# Substituting python_exec_prefix_subst.
|
||||
AC_SUBST([PYTHON_EXEC_PREFIX], [$am_python_exec_prefix_subst])
|
||||
|
||||
# Factor out some code duplication into this shell variable.
|
||||
# Just factor out some code duplication.
|
||||
am_python_setup_sysconfig="\
|
||||
import sys
|
||||
# Prefer sysconfig over distutils.sysconfig, for better compatibility
|
||||
@@ -646,95 +539,96 @@ try:
|
||||
except ImportError:
|
||||
pass"
|
||||
|
||||
dnl emacs-page Set up 4 directories:
|
||||
dnl Set up 4 directories:
|
||||
|
||||
dnl 1. pythondir: where to install python scripts. This is the
|
||||
dnl site-packages directory, not the python standard library
|
||||
dnl directory like in previous automake betas. This behavior
|
||||
dnl is more consistent with lispdir.m4 for example.
|
||||
dnl pythondir -- where to install python scripts. This is the
|
||||
dnl site-packages directory, not the python standard library
|
||||
dnl directory like in previous automake betas. This behavior
|
||||
dnl is more consistent with lispdir.m4 for example.
|
||||
dnl Query distutils for this directory.
|
||||
dnl
|
||||
AC_CACHE_CHECK([for $am_display_PYTHON script directory (pythondir)],
|
||||
[am_cv_python_pythondir],
|
||||
[if test "x$am_cv_python_prefix" = x; then
|
||||
am_py_prefix=$am__usable_prefix
|
||||
else
|
||||
am_py_prefix=$am_cv_python_prefix
|
||||
fi
|
||||
am_cv_python_pythondir=`$PYTHON -c "
|
||||
AC_CACHE_CHECK([for $am_display_PYTHON script directory],
|
||||
[am_cv_python_pythondir],
|
||||
[if test "x$prefix" = xNONE
|
||||
then
|
||||
am_py_prefix=$ac_default_prefix
|
||||
else
|
||||
am_py_prefix=$prefix
|
||||
fi
|
||||
am_cv_python_pythondir=`$PYTHON -c "
|
||||
$am_python_setup_sysconfig
|
||||
if can_use_sysconfig:
|
||||
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
|
||||
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
|
||||
else:
|
||||
from distutils import sysconfig
|
||||
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
|
||||
from distutils import sysconfig
|
||||
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
|
||||
sys.stdout.write(sitedir)"`
|
||||
#
|
||||
case $am_cv_python_pythondir in
|
||||
$am_py_prefix*)
|
||||
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
|
||||
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,\\${PYTHON_PREFIX},"`
|
||||
;;
|
||||
*)
|
||||
case $am_py_prefix in
|
||||
/usr|/System*) ;;
|
||||
*) am_cv_python_pythondir="\${PYTHON_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
|
||||
;;
|
||||
case $am_cv_python_pythondir in
|
||||
$am_py_prefix*)
|
||||
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
|
||||
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
|
||||
;;
|
||||
*)
|
||||
case $am_py_prefix in
|
||||
/usr|/System*) ;;
|
||||
*)
|
||||
am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
])
|
||||
])
|
||||
AC_SUBST([pythondir], [$am_cv_python_pythondir])
|
||||
|
||||
dnl 2. pkgpythondir: $PACKAGE directory under pythondir. Was
|
||||
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
|
||||
dnl more consistent with the rest of automake.
|
||||
dnl
|
||||
dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
|
||||
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
|
||||
dnl more consistent with the rest of automake.
|
||||
|
||||
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
|
||||
|
||||
dnl 3. pyexecdir: directory for installing python extension modules
|
||||
dnl (shared libraries).
|
||||
dnl pyexecdir -- directory for installing python extension modules
|
||||
dnl (shared libraries)
|
||||
dnl Query distutils for this directory.
|
||||
dnl
|
||||
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory (pyexecdir)],
|
||||
[am_cv_python_pyexecdir],
|
||||
[if test "x$am_cv_python_exec_prefix" = x; then
|
||||
am_py_exec_prefix=$am__usable_exec_prefix
|
||||
else
|
||||
am_py_exec_prefix=$am_cv_python_exec_prefix
|
||||
fi
|
||||
am_cv_python_pyexecdir=`$PYTHON -c "
|
||||
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
|
||||
[am_cv_python_pyexecdir],
|
||||
[if test "x$exec_prefix" = xNONE
|
||||
then
|
||||
am_py_exec_prefix=$am_py_prefix
|
||||
else
|
||||
am_py_exec_prefix=$exec_prefix
|
||||
fi
|
||||
am_cv_python_pyexecdir=`$PYTHON -c "
|
||||
$am_python_setup_sysconfig
|
||||
if can_use_sysconfig:
|
||||
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_exec_prefix'})
|
||||
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
|
||||
else:
|
||||
from distutils import sysconfig
|
||||
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix')
|
||||
from distutils import sysconfig
|
||||
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
|
||||
sys.stdout.write(sitedir)"`
|
||||
#
|
||||
case $am_cv_python_pyexecdir in
|
||||
$am_py_exec_prefix*)
|
||||
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
|
||||
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,\\${PYTHON_EXEC_PREFIX},"`
|
||||
;;
|
||||
*)
|
||||
case $am_py_exec_prefix in
|
||||
/usr|/System*) ;;
|
||||
*) am_cv_python_pyexecdir="\${PYTHON_EXEC_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
|
||||
;;
|
||||
case $am_cv_python_pyexecdir in
|
||||
$am_py_exec_prefix*)
|
||||
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
|
||||
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
|
||||
;;
|
||||
*)
|
||||
case $am_py_exec_prefix in
|
||||
/usr|/System*) ;;
|
||||
*)
|
||||
am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
])
|
||||
])
|
||||
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
|
||||
|
||||
dnl 4. pkgpyexecdir: $(pyexecdir)/$(PACKAGE)
|
||||
dnl
|
||||
dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
|
||||
|
||||
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
|
||||
|
||||
dnl Run any user-specified action.
|
||||
$2
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
|
||||
@@ -757,7 +651,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-2021 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2020 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
||||
1712
autoconf/config.guess
vendored
1712
autoconf/config.guess
vendored
File diff suppressed because it is too large
Load Diff
2881
autoconf/config.sub
vendored
2881
autoconf/config.sub
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/sh
|
||||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2020-11-14.01; # UTC
|
||||
scriptversion=2006-10-14.15
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
@@ -35,62 +35,57 @@ scriptversion=2020-11-14.01; # UTC
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
IFS=" "" $nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
if test -z "$doit"; then
|
||||
doit_exec=exec
|
||||
else
|
||||
doit_exec=$doit
|
||||
fi
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
posix_glob=
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
# Create dirs (including intermediate dirs) using mode 755.
|
||||
# This is like GNU 'install' as of coreutils 8.32 (2020).
|
||||
mkdir_umask=22
|
||||
|
||||
backupsuffix=
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
chgrpcmd=
|
||||
stripcmd=
|
||||
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
dstarg=
|
||||
no_target_directory=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
@@ -100,116 +95,91 @@ In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-p pass -p to $cpprog.
|
||||
-s $stripprog installed files.
|
||||
-S SUFFIX attempt to back up existing files, with suffix SUFFIX.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
-c (ignored)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
|
||||
By default, rm is invoked with -f; when overridden with RMPROG,
|
||||
it's up to you to specify -f if you want it.
|
||||
|
||||
If -S is not specified, no backups are attempted.
|
||||
|
||||
Email bug reports to bug-automake@gnu.org.
|
||||
Automake home page: https://www.gnu.org/software/automake/
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
-c) shift
|
||||
continue;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
shift
|
||||
shift
|
||||
case $mode in
|
||||
*' '* | *' '* | *'
|
||||
'* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-p) cpprog="$cpprog -p";;
|
||||
-s) stripcmd=$stripprog
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
-t) dstarg=$2
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-S) backupsuffix="$2"
|
||||
shift;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
-T) no_target_directory=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
if test $# -ne 0 && test -z "$dir_arg$dstarg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
if test -n "$dstarg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
set fnord "$@" "$dstarg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
dstarg=$arg
|
||||
done
|
||||
fi
|
||||
|
||||
@@ -218,26 +188,13 @@ if test $# -eq 0; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# It's OK to call `install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
trap '(exit $?); exit' 1 2 13 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
@@ -248,16 +205,16 @@ if test -z "$dir_arg"; then
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
@@ -265,9 +222,9 @@ fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
# Protect names starting with `-'.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
-*) src=./$src ;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
@@ -275,10 +232,6 @@ do
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
# Don't chown directories that already exist.
|
||||
if test $dstdir_status = 0; then
|
||||
chowncmd=""
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
@@ -289,154 +242,196 @@ do
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
if test -z "$dstarg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename.
|
||||
dst=$dstarg
|
||||
# Protect names starting with `-'.
|
||||
case $dst in
|
||||
-*) dst=./$dst ;;
|
||||
esac
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
if test -n "$no_target_directory"; then
|
||||
echo "$0: $dstarg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dstbase=`basename "$src"`
|
||||
case $dst in
|
||||
*/) dst=$dst$dstbase;;
|
||||
*) dst=$dst/$dstbase;;
|
||||
esac
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
# Prefer dirname, but fall back on a substitute if dirname fails.
|
||||
dstdir=`
|
||||
(dirname "$dst") 2>/dev/null ||
|
||||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$dst" : 'X\(//\)[^/]' \| \
|
||||
X"$dst" : 'X\(//\)$' \| \
|
||||
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
||||
echo X"$dst" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)[^/].*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\).*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
s/.*/./; q'
|
||||
`
|
||||
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
case $dstdir in
|
||||
*/) dstdirslash=$dstdir;;
|
||||
*) dstdirslash=$dstdir/;;
|
||||
esac
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
posix_mkdir=false
|
||||
# The $RANDOM variable is not portable (e.g., dash). Use it
|
||||
# here however when possible just to lower collision chance.
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
trap '
|
||||
ret=$?
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
|
||||
exit $ret
|
||||
' 0
|
||||
|
||||
# Because "mkdir -p" follows existing symlinks and we likely work
|
||||
# directly in world-writeable /tmp, make sure that the '$tmpdir'
|
||||
# directory is successfully created first before we actually test
|
||||
# 'mkdir -p'.
|
||||
if (umask $mkdir_umask &&
|
||||
$mkdirprog $mkdir_mode "$tmpdir" &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
test_tmpdir="$tmpdir/a"
|
||||
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
|
||||
mkdir_mode=
|
||||
fi
|
||||
trap '' 0;;
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writeable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# mkdir does not conform to POSIX,
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
/*) prefix=/ ;;
|
||||
-*) prefix=./ ;;
|
||||
*) prefix= ;;
|
||||
esac
|
||||
|
||||
case $posix_glob in
|
||||
'')
|
||||
if (set -f) 2>/dev/null; then
|
||||
posix_glob=true
|
||||
else
|
||||
posix_glob=false
|
||||
fi ;;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
$posix_glob && set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
$posix_glob && set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
test -z "$d" && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -449,25 +444,14 @@ do
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=${dstdirslash}_inst.$$_
|
||||
rmtmp=${dstdirslash}_rm.$$_
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask &&
|
||||
{ test -z "$stripcmd" || {
|
||||
# Create $dsttmp read-write so that cp doesn't create it read-only,
|
||||
# which would cause strip to fail.
|
||||
if test -z "$doit"; then
|
||||
: >"$dsttmp" # No need to fork-exec 'touch'.
|
||||
else
|
||||
$doit touch "$dsttmp"
|
||||
fi
|
||||
}
|
||||
} &&
|
||||
$doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
@@ -475,67 +459,49 @@ do
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
|
||||
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
|
||||
&& { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
|
||||
&& { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# If $backupsuffix is set, and the file being installed
|
||||
# already exists, attempt a backup. Don't worry if it fails,
|
||||
# e.g., if mv doesn't support -f.
|
||||
if test -n "$backupsuffix" && test -f "$dst"; then
|
||||
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
|
||||
fi
|
||||
# Now rename the file to the real destination.
|
||||
{ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
|
||||
|| {
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
if test -f "$dst"; then
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null \
|
||||
|| { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \
|
||||
&& { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\
|
||||
|| {
|
||||
echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
else
|
||||
:
|
||||
fi
|
||||
} &&
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
} || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# time-stamp-end: "$"
|
||||
# End:
|
||||
|
||||
@@ -22,26 +22,17 @@ struct dm_hash_node {
|
||||
void *data;
|
||||
unsigned data_len;
|
||||
unsigned keylen;
|
||||
unsigned hash;
|
||||
char key[0];
|
||||
char key[];
|
||||
};
|
||||
|
||||
struct dm_hash_table {
|
||||
unsigned num_nodes;
|
||||
unsigned num_hint;
|
||||
unsigned mask_slots; /* (slots - 1) -> used as hash mask */
|
||||
unsigned collisions; /* Collissions of hash keys */
|
||||
unsigned search; /* How many keys were searched */
|
||||
unsigned found; /* How many nodes were found */
|
||||
unsigned same_hash; /* Was there a colision with same masked hash and len ? */
|
||||
unsigned num_slots;
|
||||
struct dm_hash_node **slots;
|
||||
};
|
||||
|
||||
#if 0 /* TO BE REMOVED */
|
||||
static unsigned _hash(const void *key, unsigned len)
|
||||
{
|
||||
/* Permutation of the Integers 0 through 255 */
|
||||
static unsigned char _nums[] = {
|
||||
/* 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,
|
||||
@@ -66,79 +57,7 @@ static unsigned _hash(const void *key, unsigned len)
|
||||
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
|
||||
};
|
||||
|
||||
const uint8_t *str = key;
|
||||
unsigned h = 0, g;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
h <<= 4;
|
||||
h += _nums[*str++];
|
||||
g = h & ((unsigned) 0xf << 16u);
|
||||
if (g) {
|
||||
h ^= g >> 16u;
|
||||
h ^= g >> 5u;
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/* In-kernel DM hashing, still lots of collisions */
|
||||
static unsigned _hash_in_kernel(const char *key, unsigned len)
|
||||
{
|
||||
const unsigned char *str = (unsigned char *)key;
|
||||
const unsigned hash_mult = 2654435387U;
|
||||
unsigned hash = 0, i;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
hash = (hash + str[i]) * hash_mult;
|
||||
|
||||
return hash;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef get16bits
|
||||
#if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
#endif
|
||||
|
||||
#if !defined (get16bits)
|
||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Adapted Bob Jenkins hash to read by 2 bytes if possible.
|
||||
* https://secure.wikimedia.org/wikipedia/en/wiki/Jenkins_hash_function
|
||||
*
|
||||
* Reduces amount of hash collisions
|
||||
*/
|
||||
static unsigned _hash(const void *key, unsigned len)
|
||||
{
|
||||
const uint8_t *str = (uint8_t*) key;
|
||||
unsigned hash = 0, i;
|
||||
unsigned sz = len / 2;
|
||||
|
||||
for(i = 0; i < sz; ++i) {
|
||||
hash += get16bits(str + 2 * i);
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
|
||||
if (len & 1) {
|
||||
hash += str[len - 1];
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
static struct dm_hash_node *_create_node(const void *key, unsigned len)
|
||||
{
|
||||
@@ -152,32 +71,49 @@ static struct dm_hash_node *_create_node(const void *key, unsigned len)
|
||||
return n;
|
||||
}
|
||||
|
||||
static unsigned long _hash(const void *key, unsigned len)
|
||||
{
|
||||
const unsigned char *str = key;
|
||||
unsigned long h = 0, g;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
h <<= 4;
|
||||
h += _nums[*str++];
|
||||
g = h & ((unsigned long) 0xf << 16u);
|
||||
if (g) {
|
||||
h ^= g >> 16u;
|
||||
h ^= g >> 5u;
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
struct dm_hash_table *dm_hash_create(unsigned size_hint)
|
||||
{
|
||||
size_t len;
|
||||
unsigned new_size = 16u;
|
||||
struct dm_hash_table *hc = zalloc(sizeof(*hc));
|
||||
|
||||
if (!hc) {
|
||||
log_error("Failed to allocate memory for hash.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
hc->num_hint = size_hint;
|
||||
if (!hc)
|
||||
return_0;
|
||||
|
||||
/* round size hint up to a power of two */
|
||||
while (new_size < size_hint)
|
||||
new_size = new_size << 1;
|
||||
|
||||
hc->mask_slots = new_size - 1;
|
||||
hc->num_slots = new_size;
|
||||
len = sizeof(*(hc->slots)) * new_size;
|
||||
if (!(hc->slots = zalloc(len))) {
|
||||
free(hc);
|
||||
log_error("Failed to allocate slots for hash.");
|
||||
return 0;
|
||||
}
|
||||
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)
|
||||
@@ -185,16 +121,7 @@ static void _free_nodes(struct dm_hash_table *t)
|
||||
struct dm_hash_node *c, *n;
|
||||
unsigned i;
|
||||
|
||||
#ifdef DEBUG
|
||||
log_debug("Free hash hint:%d slots:%d nodes:%d (s:%d f:%d c:%d h:%d)",
|
||||
t->num_hint, t->mask_slots + 1, t->num_nodes,
|
||||
t->search, t->found, t->collisions, t->same_hash);
|
||||
#endif
|
||||
|
||||
if (!t->num_nodes)
|
||||
return;
|
||||
|
||||
for (i = 0; i <= t->mask_slots; i++)
|
||||
for (i = 0; i < t->num_slots; i++)
|
||||
for (c = t->slots[i]; c; c = n) {
|
||||
n = c->next;
|
||||
free(c);
|
||||
@@ -208,30 +135,21 @@ void dm_hash_destroy(struct dm_hash_table *t)
|
||||
free(t);
|
||||
}
|
||||
|
||||
static struct dm_hash_node **_findh(struct dm_hash_table *t, const void *key,
|
||||
uint32_t len, unsigned hash)
|
||||
{
|
||||
struct dm_hash_node **c;
|
||||
|
||||
++t->search;
|
||||
for (c = &t->slots[hash & t->mask_slots]; *c; c = &((*c)->next)) {
|
||||
if ((*c)->keylen == len && (*c)->hash == hash) {
|
||||
if (!memcmp(key, (*c)->key, len)) {
|
||||
++t->found;
|
||||
break;
|
||||
}
|
||||
++t->same_hash;
|
||||
}
|
||||
++t->collisions;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static struct dm_hash_node **_find(struct dm_hash_table *t, const void *key,
|
||||
uint32_t len)
|
||||
{
|
||||
return _findh(t, key, len, _hash(key, 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,
|
||||
@@ -245,8 +163,7 @@ void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key,
|
||||
int dm_hash_insert_binary(struct dm_hash_table *t, const void *key,
|
||||
uint32_t len, void *data)
|
||||
{
|
||||
unsigned hash = _hash(key, len);
|
||||
struct dm_hash_node **c = _findh(t, key, len, hash);
|
||||
struct dm_hash_node **c = _find(t, key, len);
|
||||
|
||||
if (*c)
|
||||
(*c)->data = data;
|
||||
@@ -257,7 +174,6 @@ int dm_hash_insert_binary(struct dm_hash_table *t, const void *key,
|
||||
return 0;
|
||||
|
||||
n->data = data;
|
||||
n->hash = hash;
|
||||
n->next = 0;
|
||||
*c = n;
|
||||
t->num_nodes++;
|
||||
@@ -301,7 +217,7 @@ static struct dm_hash_node **_find_str_with_val(struct dm_hash_table *t,
|
||||
struct dm_hash_node **c;
|
||||
unsigned h;
|
||||
|
||||
h = _hash(key, len) & t->mask_slots;
|
||||
h = _hash(key, len) & (t->num_slots - 1);
|
||||
|
||||
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
||||
if ((*c)->keylen != len)
|
||||
@@ -332,7 +248,7 @@ int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key,
|
||||
n->data = (void *)val;
|
||||
n->data_len = val_len;
|
||||
|
||||
h = _hash(key, len) & t->mask_slots;
|
||||
h = _hash(key, len) & (t->num_slots - 1);
|
||||
|
||||
first = t->slots[h];
|
||||
|
||||
@@ -400,7 +316,7 @@ void *dm_hash_lookup_with_count(struct dm_hash_table *t, const char *key, int *c
|
||||
|
||||
*count = 0;
|
||||
|
||||
h = _hash(key, len) & t->mask_slots;
|
||||
h = _hash(key, len) & (t->num_slots - 1);
|
||||
|
||||
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
||||
if ((*c)->keylen != len)
|
||||
@@ -429,7 +345,7 @@ 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->mask_slots; i++)
|
||||
for (i = 0; i < t->num_slots; i++)
|
||||
for (c = t->slots[i]; c; c = n) {
|
||||
n = c->next;
|
||||
f(c->data);
|
||||
@@ -439,8 +355,8 @@ void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f)
|
||||
void dm_hash_wipe(struct dm_hash_table *t)
|
||||
{
|
||||
_free_nodes(t);
|
||||
memset(t->slots, 0, sizeof(struct dm_hash_node *) * (t->mask_slots + 1));
|
||||
t->num_nodes = t->collisions = t->search = t->same_hash = 0u;
|
||||
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)),
|
||||
@@ -460,7 +376,7 @@ 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->mask_slots && !c; i++)
|
||||
for (i = s; i < t->num_slots && !c; i++)
|
||||
c = t->slots[i];
|
||||
|
||||
return c;
|
||||
@@ -473,5 +389,7 @@ 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)
|
||||
{
|
||||
return n->next ? n->next : _next_slot(t, (n->hash & t->mask_slots) + 1);
|
||||
unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1);
|
||||
|
||||
return n->next ? n->next : _next_slot(t, h + 1);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,13 +28,13 @@ local {
|
||||
# main configuration file, e.g. lvm.conf. When used, it must be set to
|
||||
# a unique value among all hosts sharing access to the storage,
|
||||
# e.g. a host name.
|
||||
#
|
||||
#
|
||||
# Example
|
||||
# Set no system ID:
|
||||
# system_id = ""
|
||||
# Set the system_id to a specific name:
|
||||
# system_id = "host1"
|
||||
#
|
||||
#
|
||||
# This configuration option has an automatic default value.
|
||||
# system_id = ""
|
||||
|
||||
|
||||
460
configure.ac
460
configure.ac
File diff suppressed because it is too large
Load Diff
@@ -22,9 +22,6 @@ SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c
|
||||
|
||||
TARGETS = cmirrord
|
||||
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
CFLOW_TARGET := $(TARGETS)
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LMLIBS += $(CPG_LIBS)
|
||||
@@ -36,8 +33,6 @@ cmirrord: $(OBJECTS)
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
||||
$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS)
|
||||
|
||||
install_cluster: $(TARGETS)
|
||||
install: $(TARGETS)
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_PROGRAM) -D $< $(usrsbindir)/$(<F)
|
||||
|
||||
install: install_cluster
|
||||
$(Q) $(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord
|
||||
|
||||
@@ -245,7 +245,6 @@ static void daemonize(void)
|
||||
}
|
||||
|
||||
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
|
||||
/* coverity[leaked_handle] devnull cannot leak here */
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -108,7 +108,7 @@ static SaVersionT version = { 'B', 1, 1 };
|
||||
#endif
|
||||
|
||||
#define DEBUGGING_HISTORY 100
|
||||
#define DEBUGGING_BUFLEN 270
|
||||
#define DEBUGGING_BUFLEN 128
|
||||
#define LOG_SPRINT(cc, f, arg...) do { \
|
||||
cc->idx++; \
|
||||
cc->idx = cc->idx % DEBUGGING_HISTORY; \
|
||||
@@ -1383,7 +1383,7 @@ static void cpg_leave_callback(struct clog_cpg *match,
|
||||
size_t member_list_entries)
|
||||
{
|
||||
unsigned i;
|
||||
int j, fd = -1;
|
||||
int j, fd;
|
||||
uint32_t lowest = match->lowest_id;
|
||||
struct clog_request *rq, *n;
|
||||
struct checkpoint_data *p_cp, *c_cp;
|
||||
@@ -1548,7 +1548,7 @@ static void cpg_config_callback(cpg_handle_t handle, const struct cpg_name *gnam
|
||||
member_list, member_list_entries);
|
||||
}
|
||||
|
||||
static cpg_callbacks_t cpg_callbacks = {
|
||||
cpg_callbacks_t cpg_callbacks = {
|
||||
.cpg_deliver_fn = cpg_message_callback,
|
||||
.cpg_confchg_fn = cpg_config_callback,
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ struct clog_request {
|
||||
* machine. If the two are equal, there is no need
|
||||
* to do endian conversions.
|
||||
*/
|
||||
union version_u {
|
||||
union {
|
||||
uint64_t version[2]; /* LE version and native version */
|
||||
struct dm_list list;
|
||||
} u;
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#define LOG_OFFSET 2
|
||||
|
||||
#define RESYNC_HISTORY 50
|
||||
#define RESYNC_BUFLEN 270
|
||||
#define RESYNC_BUFLEN 128
|
||||
//static char resync_history[RESYNC_HISTORY][128];
|
||||
//static int idx = 0;
|
||||
#define LOG_SPRINT(_lc, f, arg...) do { \
|
||||
@@ -378,7 +378,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
||||
uint32_t block_on_error = 0;
|
||||
|
||||
int disk_log;
|
||||
char disk_path[PATH_MAX] = { 0 };
|
||||
char disk_path[PATH_MAX];
|
||||
int unlink_path = 0;
|
||||
long page_size;
|
||||
int pages;
|
||||
@@ -658,7 +658,8 @@ static int clog_dtr(struct dm_ulog_request *rq)
|
||||
if (lc->disk_fd != -1 && close(lc->disk_fd))
|
||||
LOG_ERROR("Failed to close disk log: %s",
|
||||
strerror(errno));
|
||||
free(lc->disk_buffer);
|
||||
if (lc->disk_buffer)
|
||||
free(lc->disk_buffer);
|
||||
free(lc->clean_bits);
|
||||
free(lc->sync_bits);
|
||||
free(lc);
|
||||
|
||||
@@ -14,21 +14,11 @@
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
|
||||
SOURCES = libdevmapper-event.c
|
||||
SOURCES2 = dmeventd.c
|
||||
|
||||
TARGETS = dmeventd
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES) $(SOURCES2) \
|
||||
plugins/lvm2/dmeventd_lvm.c \
|
||||
plugins/mirror/dmeventd_mirror.c \
|
||||
plugins/raid/dmeventd_raid.c \
|
||||
plugins/snapshot/dmeventd_snapshot.c \
|
||||
plugins/thin/dmeventd_thin.c \
|
||||
plugins/vdo/dmeventd_vdo.c \
|
||||
)
|
||||
CFLOW_TARGET := $(TARGETS)
|
||||
|
||||
.PHONY: install_lib_dynamic install_lib_static install_include \
|
||||
install_pkgconfig install_dmeventd_dynamic install_dmeventd_static \
|
||||
@@ -47,7 +37,6 @@ endif
|
||||
|
||||
LIB_VERSION = $(LIB_VERSION_DM)
|
||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||
LIBS = $(PTHREAD_LIBS) -L$(interfacebuilddir) -ldevmapper
|
||||
|
||||
CLEAN_TARGETS = dmeventd.static $(LIB_NAME).a
|
||||
|
||||
@@ -57,6 +46,7 @@ endif
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
CFLOW_TARGET = dmeventd
|
||||
|
||||
EXPORTED_HEADER = $(srcdir)/libdevmapper-event.h
|
||||
EXPORTED_FN_PREFIX = dm_event
|
||||
@@ -65,26 +55,34 @@ include $(top_builddir)/make.tmpl
|
||||
|
||||
all: device-mapper
|
||||
device-mapper: $(TARGETS)
|
||||
plugins.device-mapper: $(LIB_SHARED)
|
||||
|
||||
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
|
||||
LIBS += $(PTHREAD_LIBS) -L$(top_builddir)/libdm -ldevmapper
|
||||
|
||||
dmeventd: $(LIB_SHARED) dmeventd.o
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
|
||||
$(Q) $(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) -lm
|
||||
|
||||
dmeventd.static: $(LIB_STATIC) dmeventd.o
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static dmeventd.o \
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
|
||||
|
||||
ifeq ("@PKGCONFIG@", "yes")
|
||||
INSTALL_LIB_TARGETS += install_pkgconfig
|
||||
endif
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
-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_include: $(srcdir)/libdevmapper-event.h
|
||||
@echo " [INSTALL] $(<F)"
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F)
|
||||
|
||||
install_pkgconfig: libdevmapper-event.pc
|
||||
|
||||
@@ -678,9 +678,6 @@ static int _get_status(struct message_data *message_data)
|
||||
char **buffers;
|
||||
char *message;
|
||||
|
||||
if (!message_data->id)
|
||||
return -EINVAL;
|
||||
|
||||
_lock_mutex();
|
||||
count = dm_list_size(&_thread_registry);
|
||||
buffers = alloca(sizeof(char*) * count);
|
||||
@@ -1075,7 +1072,6 @@ out:
|
||||
* "label at end of compound statement" */
|
||||
;
|
||||
|
||||
/* coverity[lock_order] _global_mutex is kept locked */
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return NULL;
|
||||
@@ -1746,8 +1742,7 @@ static void _init_thread_signals(void)
|
||||
sigset_t my_sigset;
|
||||
struct sigaction act = { .sa_handler = _sig_alarm };
|
||||
|
||||
if (sigaction(SIGALRM, &act, NULL))
|
||||
log_sys_debug("sigaction", "SIGLARM");
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
sigfillset(&my_sigset);
|
||||
|
||||
/* These are used for exiting */
|
||||
@@ -2073,7 +2068,7 @@ static void _restart_dmeventd(void)
|
||||
++count;
|
||||
}
|
||||
|
||||
if (!(_initial_registrations = zalloc(sizeof(char*) * (count + 1)))) {
|
||||
if (!(_initial_registrations = malloc(sizeof(char*) * (count + 1)))) {
|
||||
fprintf(stderr, "Memory allocation registration failed.\n");
|
||||
goto bad;
|
||||
}
|
||||
@@ -2085,6 +2080,7 @@ static void _restart_dmeventd(void)
|
||||
}
|
||||
message += strlen(message) + 1;
|
||||
}
|
||||
_initial_registrations[count] = NULL;
|
||||
|
||||
if (version >= 2) {
|
||||
if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
|
||||
|
||||
@@ -709,11 +709,15 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
||||
static char *_fetch_string(char **src, const int delimiter)
|
||||
{
|
||||
char *p, *ret;
|
||||
size_t len = (p = strchr(*src, delimiter)) ?
|
||||
(size_t)(p - *src) : strlen(*src);
|
||||
|
||||
if ((ret = strndup(*src, len)))
|
||||
*src += len + 1;
|
||||
if ((p = strchr(*src, delimiter)))
|
||||
*p = 0;
|
||||
|
||||
if ((ret = strdup(*src)))
|
||||
*src += strlen(ret) + 1;
|
||||
|
||||
if (p)
|
||||
*p = delimiter;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -928,8 +932,8 @@ void dm_event_log(const char *subsys, int level, const char *file,
|
||||
start = now;
|
||||
now -= start;
|
||||
if (_debug_level)
|
||||
fprintf(stream, "[%2ld:%02ld] %8x:%-6s%s",
|
||||
(long)now / 60, (long)now % 60,
|
||||
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
|
||||
(int)now / 60, (int)now % 60,
|
||||
// TODO: Maybe use shorter ID
|
||||
// ((int)(pthread_self()) >> 6) & 0xffff,
|
||||
(int)pthread_self(), subsys,
|
||||
|
||||
@@ -25,6 +25,9 @@ LIB_NAME = libdevmapper-event-lvm2mirror
|
||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
@@ -24,6 +24,9 @@ LIB_NAME = libdevmapper-event-lvm2raid
|
||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
@@ -77,7 +77,7 @@ 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 additional ones.
|
||||
* 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.
|
||||
|
||||
@@ -24,6 +24,9 @@ LIB_NAME = libdevmapper-event-lvm2thin
|
||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
@@ -24,6 +24,9 @@ LIB_NAME = libdevmapper-event-lvm2vdo
|
||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
* in runtime we are linked agains systems libdm 'older' library
|
||||
* which does not provide this symbol and plugin fails to load
|
||||
*/
|
||||
/* coverity[unnecessary_header] used for parsing */
|
||||
#include "device_mapper/vdo/status.c"
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
@@ -15,8 +15,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
lvmdbuspydir = $(python3dir)/lvmdbusd
|
||||
lvmdbusdir = $(DESTDIR)$(lvmdbuspydir)
|
||||
lvmdbusdir = $(python3dir)/lvmdbusd
|
||||
|
||||
LVMDBUS_SRCDIR_FILES = \
|
||||
automatedproperties.py \
|
||||
@@ -54,16 +53,16 @@ include $(top_builddir)/make.tmpl
|
||||
all:
|
||||
$(Q) test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
|
||||
|
||||
install_lvmdbusd: $(LVMDBUSD)
|
||||
install_lvmdbusd:
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_DIR) $(sbindir)
|
||||
$(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
||||
$(Q) $(INSTALL_DIR) $(lvmdbusdir)
|
||||
$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(lvmdbusdir))
|
||||
$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir)
|
||||
$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbuspydir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
|
||||
$(Q) $(CHMOD) 755 $(lvmdbusdir)/__pycache__
|
||||
$(Q) $(CHMOD) 444 $(lvmdbusdir)/__pycache__/*.py[co]
|
||||
$(Q) $(INSTALL_DIR) $(DESTDIR)$(lvmdbusdir)
|
||||
$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(DESTDIR)$(lvmdbusdir))
|
||||
$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(DESTDIR)$(lvmdbusdir)
|
||||
$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbusdir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
|
||||
$(Q) $(CHMOD) 755 $(DESTDIR)$(lvmdbusdir)/__pycache__
|
||||
$(Q) $(CHMOD) 444 $(DESTDIR)$(lvmdbusdir)/__pycache__/*.py[co]
|
||||
|
||||
install_lvm2: install_lvmdbusd
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ class AutomatedProperties(dbus.service.Object):
|
||||
cb, cbe, False)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _get_all_prop(obj, interface_name):
|
||||
if interface_name in obj.interface(True):
|
||||
@@ -156,15 +157,14 @@ class AutomatedProperties(dbus.service.Object):
|
||||
if not self._ap_search_method:
|
||||
return 0
|
||||
|
||||
search = self.lvm_id
|
||||
if search_key:
|
||||
search = search_key
|
||||
|
||||
# Either we have the new object state or we need to go fetch it
|
||||
if object_state:
|
||||
new_state = object_state
|
||||
else:
|
||||
if search_key:
|
||||
search = search_key
|
||||
else:
|
||||
search = self.lvm_id
|
||||
|
||||
new_state = self._ap_search_method([search])[0]
|
||||
assert isinstance(new_state, State)
|
||||
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import subprocess
|
||||
from . import cfg
|
||||
from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm
|
||||
from .cmdhandler import options_to_cli_args, LvmExecutionMeta
|
||||
import dbus
|
||||
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
|
||||
from .request import RequestEntry
|
||||
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
|
||||
add_no_notify
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
|
||||
@@ -37,47 +39,58 @@ def lv_merge_cmd(merge_options, lv_full_name):
|
||||
return cmd
|
||||
|
||||
|
||||
def _load_wrapper(ignored):
|
||||
cfg.load()
|
||||
|
||||
|
||||
def _move_callback(job_state, line_str):
|
||||
try:
|
||||
if line_str.count(':') == 2:
|
||||
(device, ignore, percentage) = line_str.split(':')
|
||||
|
||||
job_state.Percent = int(round(
|
||||
float(percentage.strip()[:-1]), 1))
|
||||
|
||||
# While the move is in progress we need to periodically update
|
||||
# the state to reflect where everything is at. we will do this
|
||||
# by scheduling the load to occur in the main work queue.
|
||||
r = RequestEntry(
|
||||
-1, _load_wrapper, ("_move_callback: load",), None, None, False)
|
||||
cfg.worker_q.put(r)
|
||||
except ValueError:
|
||||
log_error("Trying to parse percentage which failed for %s" % line_str)
|
||||
|
||||
|
||||
def _move_merge(interface_name, command, job_state):
|
||||
# We need to execute these command stand alone by forking & exec'ing
|
||||
# the command always as we will be getting periodic output from them on
|
||||
# the status of the long running operation.
|
||||
command.insert(0, cfg.LVM_CMD)
|
||||
|
||||
meta = LvmExecutionMeta(time.time(), 0, command)
|
||||
cfg.flightrecorder.add(meta)
|
||||
# Instruct lvm to not register an event with us
|
||||
command = add_no_notify(command)
|
||||
|
||||
ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
|
||||
cb_data=job_state)
|
||||
ended = time.time()
|
||||
meta.completed(ended, ec, stdout, stderr)
|
||||
#(self, start, ended, cmd, ec, stdout_txt, stderr_txt)
|
||||
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
|
||||
|
||||
if ec == 0:
|
||||
cfg.blackbox.add(meta)
|
||||
|
||||
process = subprocess.Popen(command, stdout=subprocess.PIPE,
|
||||
env=os.environ,
|
||||
stderr=subprocess.PIPE, close_fds=True)
|
||||
|
||||
log_debug("Background process for %s is %d" %
|
||||
(str(command), process.pid))
|
||||
|
||||
lines_iterator = iter(process.stdout.readline, b"")
|
||||
for line in lines_iterator:
|
||||
line_str = line.decode("utf-8")
|
||||
|
||||
# Check to see if the line has the correct number of separators
|
||||
try:
|
||||
if line_str.count(':') == 2:
|
||||
(device, ignore, percentage) = line_str.split(':')
|
||||
job_state.Percent = round(
|
||||
float(percentage.strip()[:-1]), 1)
|
||||
|
||||
# While the move is in progress we need to periodically update
|
||||
# the state to reflect where everything is at.
|
||||
cfg.load()
|
||||
except ValueError:
|
||||
log_error("Trying to parse percentage which failed for %s" %
|
||||
line_str)
|
||||
|
||||
out = process.communicate()
|
||||
|
||||
with meta.lock:
|
||||
meta.ended = time.time()
|
||||
meta.ec = process.returncode
|
||||
meta.stderr_txt = out[1]
|
||||
|
||||
if process.returncode == 0:
|
||||
job_state.Percent = 100
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
interface_name,
|
||||
'Exit code %s, stderr = %s' % (str(ec), stderr))
|
||||
'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
|
||||
|
||||
cfg.load()
|
||||
return '/'
|
||||
|
||||
@@ -16,8 +16,6 @@ from lvmdbusd import path
|
||||
|
||||
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
|
||||
|
||||
LOCK_FILE = os.getenv("LVM_DBUSD_LOCKFILE", "/var/lock/lvm/lvmdbusd")
|
||||
|
||||
# This is the global object manager
|
||||
om = None
|
||||
|
||||
@@ -45,9 +43,6 @@ worker_q = queue.Queue()
|
||||
# Main event loop
|
||||
loop = None
|
||||
|
||||
# Used to instruct the daemon if we should ignore SIGTERM
|
||||
ignore_sigterm = False
|
||||
|
||||
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
|
||||
BASE_INTERFACE = 'com.redhat.lvmdbus1'
|
||||
PV_INTERFACE = BASE_INTERFACE + '.Pv'
|
||||
@@ -95,14 +90,11 @@ vdo_support = False
|
||||
db = None
|
||||
|
||||
# lvm flight recorder
|
||||
flightrecorder = None
|
||||
blackbox = None
|
||||
|
||||
# RequestEntry ctor
|
||||
create_request_entry = None
|
||||
|
||||
# Circular debug log
|
||||
debug = None
|
||||
|
||||
|
||||
def exit_daemon():
|
||||
"""
|
||||
@@ -112,9 +104,3 @@ def exit_daemon():
|
||||
if run and loop:
|
||||
run.value = 0
|
||||
loop.quit()
|
||||
|
||||
|
||||
# Debug data for lvm
|
||||
lvmdebug = None
|
||||
|
||||
systemd = False
|
||||
|
||||
@@ -6,18 +6,17 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import errno
|
||||
|
||||
from subprocess import Popen, PIPE
|
||||
import select
|
||||
import time
|
||||
import threading
|
||||
from itertools import chain
|
||||
import collections
|
||||
import traceback
|
||||
import os
|
||||
|
||||
from lvmdbusd import cfg
|
||||
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
|
||||
make_non_block, read_decoded, extract_stack_trace, LvmBug, add_config_option, get_error_msg
|
||||
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify
|
||||
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
|
||||
|
||||
try:
|
||||
@@ -25,6 +24,7 @@ try:
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
SEP = '{|}'
|
||||
|
||||
total_time = 0.0
|
||||
total_count = 0
|
||||
@@ -36,7 +36,7 @@ cmd_lock = threading.RLock()
|
||||
|
||||
class LvmExecutionMeta(object):
|
||||
|
||||
def __init__(self, start, ended, cmd, ec=-1000, stdout_txt=None, stderr_txt=None):
|
||||
def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
|
||||
self.lock = threading.RLock()
|
||||
self.start = start
|
||||
self.ended = ended
|
||||
@@ -47,49 +47,32 @@ class LvmExecutionMeta(object):
|
||||
|
||||
def __str__(self):
|
||||
with self.lock:
|
||||
if self.ended == 0:
|
||||
ended_txt = "still running"
|
||||
self.ended = time.time()
|
||||
else:
|
||||
ended_txt = str(time.ctime(self.ended))
|
||||
|
||||
return 'EC= %d for "%s"\n' \
|
||||
"STARTED: %s, ENDED: %s, DURATION: %f\n" \
|
||||
return "EC= %d for %s\n" \
|
||||
"STARTED: %f, ENDED: %f\n" \
|
||||
"STDOUT=%s\n" \
|
||||
"STDERR=%s\n" % \
|
||||
(self.ec, " ".join(self.cmd), time.ctime(self.start), ended_txt, float(self.ended) - self.start,
|
||||
self.stdout_txt,
|
||||
self.stderr_txt)
|
||||
|
||||
def completed(self, end_time, ec, stdout_txt, stderr_txt):
|
||||
with self.lock:
|
||||
self.ended = end_time
|
||||
self.ec = ec
|
||||
self.stdout_txt = stdout_txt
|
||||
self.stderr_txt = stderr_txt
|
||||
(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
|
||||
self.stderr_txt)
|
||||
|
||||
|
||||
class LvmFlightRecorder(object):
|
||||
|
||||
def __init__(self, size=16):
|
||||
self.queue = collections.deque(maxlen=size)
|
||||
self.lock = threading.RLock()
|
||||
|
||||
def add(self, lvm_exec_meta):
|
||||
with self.lock:
|
||||
self.queue.append(lvm_exec_meta)
|
||||
self.queue.append(lvm_exec_meta)
|
||||
|
||||
def dump(self):
|
||||
with self.lock:
|
||||
with cmd_lock:
|
||||
if len(self.queue):
|
||||
log_error("LVM dbus flight recorder START (in order of newest to oldest)")
|
||||
log_error("LVM dbus flight recorder START")
|
||||
for c in reversed(self.queue):
|
||||
log_error(str(c))
|
||||
log_error("LVM dbus flight recorder END")
|
||||
self.queue.clear()
|
||||
|
||||
|
||||
cfg.flightrecorder = LvmFlightRecorder()
|
||||
cfg.blackbox = LvmFlightRecorder()
|
||||
|
||||
|
||||
def _debug_c(cmd, exit_code, out):
|
||||
@@ -99,95 +82,32 @@ def _debug_c(cmd, exit_code, out):
|
||||
log_error(("STDERR=\n %s\n" % out[1]))
|
||||
|
||||
|
||||
def call_lvm(command, debug=False, line_cb=None,
|
||||
cb_data=None):
|
||||
def call_lvm(command, debug=False):
|
||||
"""
|
||||
Call an executable and return a tuple of exitcode, stdout, stderr
|
||||
:param command: Command to execute
|
||||
:param debug: Dump debug to stdout
|
||||
:param line_cb: Call the supplied function for each line read from
|
||||
stdin, CALL MUST EXECUTE QUICKLY and not *block*
|
||||
otherwise call_lvm function will fail to read
|
||||
stdin/stdout. Return value of call back is ignored
|
||||
:param cb_data: Supplied to callback to allow caller access to
|
||||
its own data
|
||||
|
||||
# Callback signature
|
||||
def my_callback(my_context, line_read_stdin)
|
||||
pass
|
||||
:param command: Command to execute
|
||||
:param debug: Dump debug to stdout
|
||||
"""
|
||||
# print 'STACK:'
|
||||
# for line in traceback.format_stack():
|
||||
# print line.strip()
|
||||
|
||||
# Prepend the full lvm executable so that we can run different versions
|
||||
# in different locations on the same box
|
||||
command.insert(0, cfg.LVM_CMD)
|
||||
command = add_no_notify(command)
|
||||
|
||||
# Ensure we get an error message when we fork & exec the lvm command line
|
||||
command = add_config_option(command, "--config", 'log/command_log_selection="log_context!=''"')
|
||||
|
||||
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
|
||||
env=os.environ)
|
||||
out = process.communicate()
|
||||
|
||||
stdout_text = ""
|
||||
stderr_text = ""
|
||||
stdout_index = 0
|
||||
make_non_block(process.stdout)
|
||||
make_non_block(process.stderr)
|
||||
stdout_text = bytes(out[0]).decode("utf-8")
|
||||
stderr_text = bytes(out[1]).decode("utf-8")
|
||||
|
||||
while True and cfg.run.value != 0:
|
||||
try:
|
||||
rd_fd = [process.stdout.fileno(), process.stderr.fileno()]
|
||||
ready = select.select(rd_fd, [], [], 2)
|
||||
|
||||
for r in ready[0]:
|
||||
if r == process.stdout.fileno():
|
||||
stdout_text += read_decoded(process.stdout)
|
||||
elif r == process.stderr.fileno():
|
||||
stderr_text += read_decoded(process.stderr)
|
||||
|
||||
if line_cb is not None:
|
||||
# Process the callback for each line read!
|
||||
while True:
|
||||
i = stdout_text.find("\n", stdout_index)
|
||||
if i != -1:
|
||||
try:
|
||||
line_cb(cb_data, stdout_text[stdout_index:i])
|
||||
except BaseException as be:
|
||||
st = extract_stack_trace(be)
|
||||
log_error("call_lvm: line_cb exception: \n %s" % st)
|
||||
stdout_index = i + 1
|
||||
else:
|
||||
break
|
||||
|
||||
# Check to see if process has terminated, None when running
|
||||
if process.poll() is not None:
|
||||
break
|
||||
except IOError as ioe:
|
||||
log_debug("call_lvm:" + str(ioe))
|
||||
break
|
||||
|
||||
if process.returncode is not None:
|
||||
cfg.lvmdebug.lvm_complete()
|
||||
if debug or (process.returncode != 0 and (process.returncode != 5 and "fullreport" in command)):
|
||||
_debug_c(command, process.returncode, (stdout_text, stderr_text))
|
||||
|
||||
try:
|
||||
report_json = json.loads(stdout_text)
|
||||
except json.decoder.JSONDecodeError:
|
||||
# Some lvm commands don't return json even though we are asking for it to do so.
|
||||
return process.returncode, stdout_text, stderr_text
|
||||
|
||||
error_msg = get_error_msg(report_json)
|
||||
if error_msg:
|
||||
stderr_text += error_msg
|
||||
|
||||
return process.returncode, report_json, stderr_text
|
||||
else:
|
||||
if cfg.run.value == 0:
|
||||
raise SystemExit
|
||||
# We can bail out before the lvm command finished when we get a signal
|
||||
# which is requesting we exit
|
||||
return -errno.EINTR, "", "operation interrupted"
|
||||
if debug or process.returncode != 0:
|
||||
_debug_c(command, process.returncode, (stdout_text, stderr_text))
|
||||
|
||||
return process.returncode, stdout_text, stderr_text
|
||||
|
||||
# The actual method which gets called to invoke the lvm command, can vary
|
||||
# from forking a new process to using lvm shell
|
||||
@@ -202,11 +122,11 @@ def _shell_cfg():
|
||||
_t_call = lvm_shell.call_lvm
|
||||
cfg.SHELL_IN_USE = lvm_shell
|
||||
return True
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
_t_call = call_lvm
|
||||
cfg.SHELL_IN_USE = None
|
||||
log_error("Unable to utilize lvm shell, dropping "
|
||||
"back to fork & exec\n%s" % extract_stack_trace(e))
|
||||
log_error(traceback.format_exc())
|
||||
log_error("Unable to utilize lvm shell, dropping back to fork & exec")
|
||||
return False
|
||||
|
||||
|
||||
@@ -237,15 +157,11 @@ def time_wrapper(command, debug=False):
|
||||
|
||||
with cmd_lock:
|
||||
start = time.time()
|
||||
meta = LvmExecutionMeta(start, 0, command)
|
||||
# Add the partial metadata to flight recorder, so if the command hangs
|
||||
# we will see what it was.
|
||||
cfg.flightrecorder.add(meta)
|
||||
results = _t_call(command, debug)
|
||||
ended = time.time()
|
||||
total_time += (ended - start)
|
||||
total_count += 1
|
||||
meta.completed(ended, *results)
|
||||
cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
|
||||
return results
|
||||
|
||||
|
||||
@@ -255,11 +171,44 @@ call = time_wrapper
|
||||
# Default cmd
|
||||
# Place default arguments for every command here.
|
||||
def _dc(cmd, args):
|
||||
c = [cmd, '--nosuffix', '--unbuffered', '--units', 'b']
|
||||
c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
|
||||
'--unbuffered', '--units', 'b']
|
||||
c.extend(args)
|
||||
return c
|
||||
|
||||
|
||||
def parse(out):
|
||||
rc = []
|
||||
|
||||
for line in out.split('\n'):
|
||||
# This line includes separators, so process them
|
||||
if SEP in line:
|
||||
elem = line.split(SEP)
|
||||
cleaned_elem = []
|
||||
for e in elem:
|
||||
e = e.strip()
|
||||
cleaned_elem.append(e)
|
||||
|
||||
if len(cleaned_elem) > 1:
|
||||
rc.append(cleaned_elem)
|
||||
else:
|
||||
t = line.strip()
|
||||
if len(t) > 0:
|
||||
rc.append(t)
|
||||
return rc
|
||||
|
||||
|
||||
def parse_column_names(out, column_names):
|
||||
lines = parse(out)
|
||||
rc = []
|
||||
|
||||
for i in range(0, len(lines)):
|
||||
d = dict(list(zip(column_names, lines[i])))
|
||||
rc.append(d)
|
||||
|
||||
return rc
|
||||
|
||||
|
||||
def options_to_cli_args(options):
|
||||
rc = []
|
||||
for k, v in list(dict(options).items()):
|
||||
@@ -621,20 +570,62 @@ def lvm_full_report_json():
|
||||
'--configreport', 'vg', '-o', ','.join(vg_columns),
|
||||
'--configreport', 'lv', '-o', ','.join(lv_columns),
|
||||
'--configreport', 'seg', '-o', ','.join(lv_seg_columns),
|
||||
'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns)
|
||||
'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns),
|
||||
'--reportformat', 'json'
|
||||
])
|
||||
|
||||
# We are running the fullreport command, we will ask lvm to output the debug
|
||||
# data, so we can have the required information for lvm to debug the fullreport failures.
|
||||
fn = cfg.lvmdebug.setup()
|
||||
add_config_option(cmd, "--config", "log {level=7 file=%s syslog=0}" % fn)
|
||||
|
||||
rc, out, err = call(cmd)
|
||||
# When we have an exported vg the exit code of lvs or fullreport will be 5
|
||||
if rc == 0 or rc == 5:
|
||||
assert(type(out) == dict)
|
||||
return out
|
||||
raise LvmBug("'fullreport' exited with code '%d'" % rc)
|
||||
# With the current implementation, if we are using the shell then we
|
||||
# are using JSON and JSON is returned back to us as it was parsed to
|
||||
# figure out if we completed OK or not
|
||||
if cfg.SHELL_IN_USE:
|
||||
assert(type(out) == dict)
|
||||
return out
|
||||
else:
|
||||
return json.loads(out)
|
||||
return None
|
||||
|
||||
|
||||
def pv_retrieve_with_segs(device=None):
|
||||
d = []
|
||||
err = ""
|
||||
out = ""
|
||||
rc = 0
|
||||
|
||||
columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
|
||||
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
|
||||
'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
|
||||
'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
|
||||
'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing']
|
||||
|
||||
# Lvm has some issues where it returns failure when querying pvs when other
|
||||
# operations are in process, see:
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1274085
|
||||
for i in range(0, 10):
|
||||
cmd = _dc('pvs', ['-o', ','.join(columns)])
|
||||
|
||||
if device:
|
||||
cmd.extend(device)
|
||||
|
||||
rc, out, err = call(cmd)
|
||||
|
||||
if rc == 0:
|
||||
d = parse_column_names(out, columns)
|
||||
break
|
||||
else:
|
||||
time.sleep(0.2)
|
||||
log_debug("LVM Bug workaround, retrying pvs command...")
|
||||
|
||||
if rc != 0:
|
||||
msg = "We were unable to get pvs to return without error after " \
|
||||
"trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \
|
||||
(rc, err, out)
|
||||
log_error(msg)
|
||||
raise RuntimeError(msg)
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def pv_resize(device, size_bytes, create_options):
|
||||
@@ -791,6 +782,53 @@ def activate_deactivate(op, name, activate, control_flags, options):
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def vg_retrieve(vg_specific):
|
||||
if vg_specific:
|
||||
assert isinstance(vg_specific, list)
|
||||
|
||||
columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free',
|
||||
'vg_sysid', 'vg_extent_size', 'vg_extent_count',
|
||||
'vg_free_count', 'vg_profile', 'max_lv', 'max_pv',
|
||||
'pv_count', 'lv_count', 'snap_count', 'vg_seqno',
|
||||
'vg_mda_count', 'vg_mda_free', 'vg_mda_size',
|
||||
'vg_mda_used_count', 'vg_attr', 'vg_tags']
|
||||
|
||||
cmd = _dc('vgs', ['-o', ','.join(columns)])
|
||||
|
||||
if vg_specific:
|
||||
cmd.extend(vg_specific)
|
||||
|
||||
d = []
|
||||
rc, out, err = call(cmd)
|
||||
if rc == 0:
|
||||
d = parse_column_names(out, columns)
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def lv_retrieve_with_segments():
|
||||
columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size',
|
||||
'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid',
|
||||
'origin', 'data_percent',
|
||||
'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
|
||||
'metadata_lv', 'seg_pe_ranges', 'segtype', 'lv_parent',
|
||||
'lv_role', 'lv_layout',
|
||||
'snap_percent', 'metadata_percent', 'copy_percent',
|
||||
'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
|
||||
|
||||
cmd = _dc('lvs', ['-a', '-o', ','.join(columns)])
|
||||
rc, out, err = call(cmd)
|
||||
|
||||
d = []
|
||||
|
||||
if rc == 0:
|
||||
d = parse_column_names(out, columns)
|
||||
|
||||
return d
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Leave this for future debug as needed
|
||||
pass
|
||||
pv_data = pv_retrieve_with_segs()
|
||||
|
||||
for p in pv_data:
|
||||
print(str(p))
|
||||
|
||||
@@ -6,44 +6,36 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import errno
|
||||
|
||||
from .pv import load_pvs
|
||||
from .vg import load_vgs
|
||||
from .lv import load_lvs
|
||||
from . import cfg
|
||||
from .utils import MThreadRunner, log_debug, log_error, LvmBug, extract_stack_trace
|
||||
from .utils import MThreadRunner, log_debug, log_error
|
||||
import threading
|
||||
import queue
|
||||
import time
|
||||
import traceback
|
||||
|
||||
|
||||
def _main_thread_load(refresh=True, emit_signal=True):
|
||||
num_total_changes = 0
|
||||
to_remove = []
|
||||
|
||||
(changes, remove) = load_pvs(
|
||||
num_total_changes += load_pvs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1:]
|
||||
num_total_changes += changes
|
||||
to_remove.extend(remove)
|
||||
|
||||
(changes, remove) = load_vgs(
|
||||
cache_refresh=False)[1]
|
||||
num_total_changes += load_vgs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1:]
|
||||
cache_refresh=False)[1]
|
||||
|
||||
num_total_changes += changes
|
||||
to_remove.extend(remove)
|
||||
|
||||
(lv_changes, remove) = load_lvs(
|
||||
lv_changes = load_lvs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1:]
|
||||
cache_refresh=False)[1]
|
||||
|
||||
num_total_changes += lv_changes
|
||||
to_remove.extend(remove)
|
||||
|
||||
# When the LVs change it can cause another change in the VGs which is
|
||||
# missed if we don't scan through the VGs again. We could achieve this
|
||||
@@ -52,23 +44,10 @@ def _main_thread_load(refresh=True, emit_signal=True):
|
||||
# changes causing the dbus object representing it to be removed and
|
||||
# recreated.
|
||||
if refresh and lv_changes > 0:
|
||||
(changes, remove) = load_vgs(
|
||||
num_total_changes += load_vgs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1:]
|
||||
|
||||
num_total_changes += changes
|
||||
to_remove.extend(remove)
|
||||
|
||||
# Remove any objects that are no longer needed. We do this after we process
|
||||
# all the objects to ensure that references still exist for objects that
|
||||
# are processed after them.
|
||||
to_remove.reverse()
|
||||
for i in to_remove:
|
||||
dbus_obj = cfg.om.get_object_by_path(i)
|
||||
if dbus_obj:
|
||||
cfg.om.remove_object(dbus_obj, True)
|
||||
num_total_changes += 1
|
||||
cache_refresh=False)[1]
|
||||
|
||||
return num_total_changes
|
||||
|
||||
@@ -120,108 +99,81 @@ class StateUpdate(object):
|
||||
@staticmethod
|
||||
def update_thread(obj):
|
||||
exception_count = 0
|
||||
|
||||
queued_requests = []
|
||||
|
||||
def set_results(val):
|
||||
nonlocal queued_requests
|
||||
for idx in queued_requests:
|
||||
idx.set_result(val)
|
||||
# Only clear out the requests after we have given them a result
|
||||
# otherwise we can orphan the waiting threads, and they never
|
||||
# wake up if we get an exception
|
||||
queued_requests = []
|
||||
|
||||
def bailing(rv):
|
||||
set_results(rv)
|
||||
try:
|
||||
while True:
|
||||
item = obj.queue.get(False)
|
||||
item.set_result(rv)
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
def _load_args(requests):
|
||||
"""
|
||||
If we have multiple requests in the queue, they might not all have the same options. If any of the requests
|
||||
have an option set we need to honor it.
|
||||
"""
|
||||
refresh = any([r.refresh for r in requests])
|
||||
emit_signal = any([r.emit_signal for r in requests])
|
||||
cache_refresh = any([r.cache_refresh for r in requests])
|
||||
log = any([r.log for r in requests])
|
||||
need_main_thread = any([r.need_main_thread for r in requests])
|
||||
|
||||
return refresh, emit_signal, cache_refresh, log, need_main_thread
|
||||
|
||||
def _drain_queue(queued, incoming):
|
||||
try:
|
||||
while True:
|
||||
queued.append(incoming.get(block=False))
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
def _handle_error():
|
||||
nonlocal exception_count
|
||||
exception_count += 1
|
||||
|
||||
if exception_count >= 5:
|
||||
log_error("Too many errors in update_thread, exiting daemon")
|
||||
cfg.debug.dump()
|
||||
cfg.flightrecorder.dump()
|
||||
bailing(errno.EFAULT)
|
||||
cfg.exit_daemon()
|
||||
else:
|
||||
# Slow things down when encountering errors
|
||||
cfg.lvmdebug.complete()
|
||||
time.sleep(1)
|
||||
|
||||
while cfg.run.value != 0:
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
refresh = True
|
||||
emit_signal = True
|
||||
cache_refresh = True
|
||||
log = True
|
||||
need_main_thread = True
|
||||
|
||||
with obj.lock:
|
||||
wait = not obj.deferred
|
||||
obj.deferred = False
|
||||
|
||||
if len(queued_requests) == 0 and wait:
|
||||
# Note: If we don't have anything for 2 seconds we will
|
||||
# get a queue.Empty exception raised here
|
||||
queued_requests.append(obj.queue.get(block=True, timeout=2))
|
||||
queued_requests.append(obj.queue.get(True, 2))
|
||||
|
||||
# Ok we have one or the deferred queue has some,
|
||||
# check if any others and grab them too
|
||||
_drain_queue(queued_requests, obj.queue)
|
||||
# check if any others
|
||||
try:
|
||||
while True:
|
||||
queued_requests.append(obj.queue.get(False))
|
||||
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
if len(queued_requests) > 1:
|
||||
log_debug("Processing %d updates!" % len(queued_requests),
|
||||
'bg_black', 'fg_light_green')
|
||||
|
||||
num_changes = load(*_load_args(queued_requests))
|
||||
# We have what we can, run the update with the needed options
|
||||
for i in queued_requests:
|
||||
if not i.refresh:
|
||||
refresh = False
|
||||
if not i.emit_signal:
|
||||
emit_signal = False
|
||||
if not i.cache_refresh:
|
||||
cache_refresh = False
|
||||
if not i.log:
|
||||
log = False
|
||||
if not i.need_main_thread:
|
||||
need_main_thread = False
|
||||
|
||||
num_changes = load(refresh, emit_signal, cache_refresh, log,
|
||||
need_main_thread)
|
||||
# Update is done, let everyone know!
|
||||
set_results(num_changes)
|
||||
for i in queued_requests:
|
||||
i.set_result(num_changes)
|
||||
|
||||
# Only clear out the requests after we have given them a result
|
||||
# otherwise we can orphan the waiting threads and they never
|
||||
# wake up if we get an exception
|
||||
queued_requests = []
|
||||
|
||||
# We retrieved OK, clear exception count
|
||||
exception_count = 0
|
||||
|
||||
except queue.Empty:
|
||||
pass
|
||||
except SystemExit:
|
||||
break
|
||||
except LvmBug as bug:
|
||||
# If a lvm bug occurred, we will dump the lvm debug data if
|
||||
# we have it.
|
||||
cfg.lvmdebug.dump()
|
||||
log_error(str(bug))
|
||||
_handle_error()
|
||||
except Exception as e:
|
||||
log_error("update_thread: \n%s" % extract_stack_trace(e))
|
||||
_handle_error()
|
||||
finally:
|
||||
cfg.lvmdebug.complete()
|
||||
st = traceback.format_exc()
|
||||
log_error("update_thread exception: \n%s" % st)
|
||||
cfg.blackbox.dump()
|
||||
exception_count += 1
|
||||
if exception_count >= 5:
|
||||
for i in queued_requests:
|
||||
i.set_result(e)
|
||||
|
||||
# Make sure to unblock any that may be waiting before we exit this thread
|
||||
# otherwise they hang forever ...
|
||||
bailing(Exception("update thread exiting"))
|
||||
log_debug("update thread exiting!")
|
||||
log_error("Too many errors in update_thread, exiting daemon")
|
||||
cfg.exit_daemon()
|
||||
|
||||
else:
|
||||
# Slow things down when encountering errors
|
||||
time.sleep(1)
|
||||
|
||||
def __init__(self):
|
||||
self.lock = threading.RLock()
|
||||
|
||||
@@ -226,21 +226,3 @@ class Job(AutomatedProperties):
|
||||
def Uuid(self):
|
||||
import uuid
|
||||
return uuid.uuid1()
|
||||
|
||||
# Override the property "getters" implementation for the job interface, so a user can query a job while the queue
|
||||
# is processing items. Originally all the property get methods were this way, but we changed this in
|
||||
# e53454d6de07de56736303dd2157c3859f6fa848
|
||||
|
||||
# Properties
|
||||
# noinspection PyUnusedLocal
|
||||
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
|
||||
in_signature='ss', out_signature='v')
|
||||
def Get(self, interface_name, property_name):
|
||||
# Note: If we get an exception in this handler we won't know about it,
|
||||
# only the side effect of no returned value!
|
||||
return AutomatedProperties._get_prop(self, interface_name, property_name)
|
||||
|
||||
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
|
||||
in_signature='s', out_signature='a{sv}')
|
||||
def GetAll(self, interface_name):
|
||||
return AutomatedProperties._get_all_prop(self, interface_name)
|
||||
|
||||
@@ -75,10 +75,11 @@ def common(retrieve, o_type, search_keys,
|
||||
|
||||
object_path = None
|
||||
|
||||
to_remove = []
|
||||
if refresh:
|
||||
to_remove = list(existing_paths.keys())
|
||||
for k in list(existing_paths.keys()):
|
||||
cfg.om.remove_object(cfg.om.get_object_by_path(k), True)
|
||||
num_changes += 1
|
||||
|
||||
num_changes += len(rc)
|
||||
|
||||
return rc, num_changes, to_remove
|
||||
return rc, num_changes
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
from .automatedproperties import AutomatedProperties
|
||||
|
||||
from . import utils
|
||||
from .utils import vg_obj_path_generate, log_error, _handle_execute, LvmBug
|
||||
from .utils import vg_obj_path_generate, log_error, _handle_execute
|
||||
import dbus
|
||||
from . import cmdhandler
|
||||
from . import cfg
|
||||
@@ -21,9 +21,11 @@ from .utils import n, n32, d
|
||||
from .loader import common
|
||||
from .state import State
|
||||
from . import background
|
||||
from .utils import round_size, mt_remove_dbus_objects, lvm_column_key
|
||||
from .utils import round_size, mt_remove_dbus_objects
|
||||
from .job import JobState
|
||||
|
||||
import traceback
|
||||
|
||||
|
||||
# Try and build a key for a LV, so that we sort the LVs with least dependencies
|
||||
# first. This may be error prone because of the flexibility LVM
|
||||
@@ -71,74 +73,67 @@ def lvs_state_retrieve(selection, cache_refresh=True):
|
||||
# don't have information available yet.
|
||||
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
|
||||
|
||||
try:
|
||||
for l in lvs:
|
||||
if cfg.vdo_support:
|
||||
rc.append(LvStateVdo(
|
||||
l['lv_uuid'], l['lv_name'],
|
||||
l['lv_path'], n(l['lv_size']),
|
||||
l['vg_name'],
|
||||
l['vg_uuid'], l['pool_lv_uuid'],
|
||||
l['pool_lv'], l['origin_uuid'], l['origin'],
|
||||
n32(l['data_percent']), l['lv_attr'],
|
||||
l['lv_tags'], l['lv_active'], l['data_lv'],
|
||||
l['metadata_lv'], l['segtype'], l['lv_role'],
|
||||
l['lv_layout'],
|
||||
n32(l['snap_percent']),
|
||||
n32(l['metadata_percent']),
|
||||
n32(l['copy_percent']),
|
||||
n32(l['sync_percent']),
|
||||
n(l['lv_metadata_size']),
|
||||
l['move_pv'],
|
||||
l['move_pv_uuid'],
|
||||
l['vdo_operating_mode'],
|
||||
l['vdo_compression_state'],
|
||||
l['vdo_index_state'],
|
||||
n(l['vdo_used_size']),
|
||||
d(l['vdo_saving_percent']),
|
||||
l['vdo_compression'],
|
||||
l['vdo_deduplication'],
|
||||
l['vdo_use_metadata_hints'],
|
||||
n32(l['vdo_minimum_io_size']),
|
||||
n(l['vdo_block_map_cache_size']),
|
||||
n32(l['vdo_block_map_era_length']),
|
||||
l['vdo_use_sparse_index'],
|
||||
n(l['vdo_index_memory_size']),
|
||||
n(l['vdo_slab_size']),
|
||||
n32(l['vdo_ack_threads']),
|
||||
n32(l['vdo_bio_threads']),
|
||||
n32(l['vdo_bio_rotation']),
|
||||
n32(l['vdo_cpu_threads']),
|
||||
n32(l['vdo_hash_zone_threads']),
|
||||
n32(l['vdo_logical_threads']),
|
||||
n32(l['vdo_physical_threads']),
|
||||
n32(l['vdo_max_discard']),
|
||||
l['vdo_write_policy'],
|
||||
n32(l['vdo_header_size'])))
|
||||
else:
|
||||
rc.append(LvState(
|
||||
l['lv_uuid'], l['lv_name'],
|
||||
l['lv_path'], n(l['lv_size']),
|
||||
l['vg_name'],
|
||||
l['vg_uuid'], l['pool_lv_uuid'],
|
||||
l['pool_lv'], l['origin_uuid'], l['origin'],
|
||||
n32(l['data_percent']), l['lv_attr'],
|
||||
l['lv_tags'], l['lv_active'], l['data_lv'],
|
||||
l['metadata_lv'], l['segtype'], l['lv_role'],
|
||||
l['lv_layout'],
|
||||
n32(l['snap_percent']),
|
||||
n32(l['metadata_percent']),
|
||||
n32(l['copy_percent']),
|
||||
n32(l['sync_percent']),
|
||||
n(l['lv_metadata_size']),
|
||||
l['move_pv'],
|
||||
l['move_pv_uuid']))
|
||||
except KeyError as ke:
|
||||
# Sometimes lvm omits returning one of the keys we requested.
|
||||
key = ke.args[0]
|
||||
if lvm_column_key(key):
|
||||
raise LvmBug("missing JSON key: '%s'" % key)
|
||||
raise ke
|
||||
for l in lvs:
|
||||
if cfg.vdo_support:
|
||||
rc.append(LvStateVdo(
|
||||
l['lv_uuid'], l['lv_name'],
|
||||
l['lv_path'], n(l['lv_size']),
|
||||
l['vg_name'],
|
||||
l['vg_uuid'], l['pool_lv_uuid'],
|
||||
l['pool_lv'], l['origin_uuid'], l['origin'],
|
||||
n32(l['data_percent']), l['lv_attr'],
|
||||
l['lv_tags'], l['lv_active'], l['data_lv'],
|
||||
l['metadata_lv'], l['segtype'], l['lv_role'],
|
||||
l['lv_layout'],
|
||||
n32(l['snap_percent']),
|
||||
n32(l['metadata_percent']),
|
||||
n32(l['copy_percent']),
|
||||
n32(l['sync_percent']),
|
||||
n(l['lv_metadata_size']),
|
||||
l['move_pv'],
|
||||
l['move_pv_uuid'],
|
||||
l['vdo_operating_mode'],
|
||||
l['vdo_compression_state'],
|
||||
l['vdo_index_state'],
|
||||
n(l['vdo_used_size']),
|
||||
d(l['vdo_saving_percent']),
|
||||
l['vdo_compression'],
|
||||
l['vdo_deduplication'],
|
||||
l['vdo_use_metadata_hints'],
|
||||
n32(l['vdo_minimum_io_size']),
|
||||
n(l['vdo_block_map_cache_size']),
|
||||
n32(l['vdo_block_map_era_length']),
|
||||
l['vdo_use_sparse_index'],
|
||||
n(l['vdo_index_memory_size']),
|
||||
n(l['vdo_slab_size']),
|
||||
n32(l['vdo_ack_threads']),
|
||||
n32(l['vdo_bio_threads']),
|
||||
n32(l['vdo_bio_rotation']),
|
||||
n32(l['vdo_cpu_threads']),
|
||||
n32(l['vdo_hash_zone_threads']),
|
||||
n32(l['vdo_logical_threads']),
|
||||
n32(l['vdo_physical_threads']),
|
||||
n32(l['vdo_max_discard']),
|
||||
l['vdo_write_policy'],
|
||||
n32(l['vdo_header_size'])))
|
||||
else:
|
||||
rc.append(LvState(
|
||||
l['lv_uuid'], l['lv_name'],
|
||||
l['lv_path'], n(l['lv_size']),
|
||||
l['vg_name'],
|
||||
l['vg_uuid'], l['pool_lv_uuid'],
|
||||
l['pool_lv'], l['origin_uuid'], l['origin'],
|
||||
n32(l['data_percent']), l['lv_attr'],
|
||||
l['lv_tags'], l['lv_active'], l['data_lv'],
|
||||
l['metadata_lv'], l['segtype'], l['lv_role'],
|
||||
l['lv_layout'],
|
||||
n32(l['snap_percent']),
|
||||
n32(l['metadata_percent']),
|
||||
n32(l['copy_percent']),
|
||||
n32(l['sync_percent']),
|
||||
n(l['lv_metadata_size']),
|
||||
l['move_pv'],
|
||||
l['move_pv_uuid']))
|
||||
return rc
|
||||
|
||||
|
||||
@@ -279,15 +274,15 @@ class LvStateVdo(LvState):
|
||||
MetaDataPercent, CopyPercent, SyncPercent,
|
||||
MetaDataSizeBytes, move_pv, move_pv_uuid,
|
||||
vdo_operating_mode, vdo_compression_state, vdo_index_state,
|
||||
vdo_used_size, vdo_saving_percent, vdo_compression,
|
||||
vdo_deduplication, vdo_use_metadata_hints,
|
||||
vdo_minimum_io_size, vdo_block_map_cache_size,
|
||||
vdo_block_map_era_length, vdo_use_sparse_index,
|
||||
vdo_index_memory_size, vdo_slab_size, vdo_ack_threads,
|
||||
vdo_bio_threads, vdo_bio_rotation, vdo_cpu_threads,
|
||||
vdo_hash_zone_threads, vdo_logical_threads,
|
||||
vdo_physical_threads, vdo_max_discard,
|
||||
vdo_write_policy, vdo_header_size):
|
||||
vdo_used_size,vdo_saving_percent,vdo_compression,
|
||||
vdo_deduplication,vdo_use_metadata_hints,
|
||||
vdo_minimum_io_size,vdo_block_map_cache_size,
|
||||
vdo_block_map_era_length,vdo_use_sparse_index,
|
||||
vdo_index_memory_size,vdo_slab_size,vdo_ack_threads,
|
||||
vdo_bio_threads,vdo_bio_rotation,vdo_cpu_threads,
|
||||
vdo_hash_zone_threads,vdo_logical_threads,
|
||||
vdo_physical_threads,vdo_max_discard,
|
||||
vdo_write_policy,vdo_header_size):
|
||||
super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
|
||||
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
|
||||
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
|
||||
@@ -376,8 +371,8 @@ class LvCommon(AutomatedProperties):
|
||||
return dbus.Struct((self.state.Attr[index],
|
||||
type_map.get(self.state.Attr[index], default)),
|
||||
signature="(ss)")
|
||||
except BaseException as b:
|
||||
st = utils.extract_stack_trace(b)
|
||||
except BaseException:
|
||||
st = traceback.format_exc()
|
||||
log_error("attr_struct: \n%s" % st)
|
||||
return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
|
||||
|
||||
@@ -600,7 +595,7 @@ class Lv(LvCommon):
|
||||
optional_size = space + 512 - remainder
|
||||
|
||||
LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
|
||||
lv_name, snapshot_options, name, optional_size))
|
||||
lv_name, snapshot_options,name, optional_size))
|
||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||
return cfg.om.get_object_path_by_lvm_id(full_name)
|
||||
|
||||
@@ -640,7 +635,7 @@ class Lv(LvCommon):
|
||||
|
||||
size_change = new_size_bytes - dbo.SizeBytes
|
||||
LvCommon.handle_execute(*cmdhandler.lv_resize(
|
||||
dbo.lvm_id, size_change, pv_dests, resize_options))
|
||||
dbo.lvm_id, size_change,pv_dests, resize_options))
|
||||
return "/"
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -749,7 +744,7 @@ class Lv(LvCommon):
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
@staticmethod
|
||||
def _caching_common(method, lv_uuid, lv_name, lv_object_path, cache_options):
|
||||
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||
|
||||
@@ -758,7 +753,7 @@ class Lv(LvCommon):
|
||||
|
||||
if lv_to_cache:
|
||||
fcn = lv_to_cache.lv_full_name()
|
||||
rc, out, err = method(
|
||||
rc, out, err = cmdhandler.lv_writecache_lv(
|
||||
dbo.lv_full_name(), fcn, cache_options)
|
||||
if rc == 0:
|
||||
# When we cache an LV, the cache pool and the lv that is getting
|
||||
@@ -775,14 +770,9 @@ class Lv(LvCommon):
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
LV_INTERFACE, 'LV to cache with object path %s not present!' %
|
||||
lv_object_path)
|
||||
lv_object_path)
|
||||
return lv_converted
|
||||
|
||||
@staticmethod
|
||||
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
|
||||
return Lv._caching_common(cmdhandler.lv_writecache_lv, lv_uuid,
|
||||
lv_name, lv_object_path, cache_options)
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=LV_INTERFACE,
|
||||
in_signature='oia{sv}',
|
||||
@@ -855,10 +845,10 @@ class LvVdoPool(Lv):
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=VDO_POOL_INTERFACE,
|
||||
in_signature='ia{sv}',
|
||||
out_signature='o',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
dbus_interface=VDO_POOL_INTERFACE,
|
||||
in_signature='ia{sv}',
|
||||
out_signature='o',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
def DisableCompression(self, tmo, comp_options, cb, cbe):
|
||||
r = RequestEntry(
|
||||
tmo, LvVdoPool._enable_disable_compression,
|
||||
@@ -888,10 +878,10 @@ class LvVdoPool(Lv):
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=VDO_POOL_INTERFACE,
|
||||
in_signature='ia{sv}',
|
||||
out_signature='o',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
dbus_interface=VDO_POOL_INTERFACE,
|
||||
in_signature='ia{sv}',
|
||||
out_signature='o',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
|
||||
r = RequestEntry(
|
||||
tmo, LvVdoPool._enable_disable_deduplication,
|
||||
@@ -962,8 +952,33 @@ class LvCachePool(Lv):
|
||||
|
||||
@staticmethod
|
||||
def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
|
||||
return Lv._caching_common(cmdhandler.lv_cache_lv, lv_uuid, lv_name,
|
||||
lv_object_path, cache_options)
|
||||
# Make sure we have a dbus object representing cache pool
|
||||
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||
|
||||
# Make sure we have dbus object representing lv to cache
|
||||
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
|
||||
|
||||
if lv_to_cache:
|
||||
fcn = lv_to_cache.lv_full_name()
|
||||
rc, out, err = cmdhandler.lv_cache_lv(
|
||||
dbo.lv_full_name(), fcn, cache_options)
|
||||
if rc == 0:
|
||||
# When we cache an LV, the cache pool and the lv that is getting
|
||||
# cached need to be removed from the object manager and
|
||||
# re-created as their interfaces have changed!
|
||||
mt_remove_dbus_objects((dbo, lv_to_cache))
|
||||
cfg.load()
|
||||
|
||||
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
LV_INTERFACE,
|
||||
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
LV_INTERFACE, 'LV to cache with object path %s not present!' %
|
||||
lv_object_path)
|
||||
return lv_converted
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=CACHE_POOL_INTERFACE,
|
||||
|
||||
239
daemons/lvmdbusd/lvm_shell_proxy.py.in
Executable file → Normal file
239
daemons/lvmdbusd/lvm_shell_proxy.py.in
Executable file → Normal file
@@ -13,12 +13,14 @@
|
||||
|
||||
import subprocess
|
||||
import shlex
|
||||
from fcntl import fcntl, F_GETFL, F_SETFL
|
||||
import os
|
||||
import pty
|
||||
import traceback
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import select
|
||||
import copy
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
@@ -26,9 +28,8 @@ except ImportError:
|
||||
import json
|
||||
|
||||
|
||||
import lvmdbusd.cfg as cfg
|
||||
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
|
||||
read_decoded, extract_stack_trace, LvmBug, get_error_msg
|
||||
from lvmdbusd.cfg import LVM_CMD
|
||||
from lvmdbusd.utils import log_debug, log_error, add_no_notify
|
||||
|
||||
SHELL_PROMPT = "lvm> "
|
||||
|
||||
@@ -42,11 +43,17 @@ def _quote_arg(arg):
|
||||
|
||||
class LVMShellProxy(object):
|
||||
|
||||
# Read REPORT FD until we have a complete and valid JSON record or give
|
||||
# up trying to get one.
|
||||
#
|
||||
# Returns stdout, report (JSON), stderr
|
||||
def _read_response(self, no_output=False):
|
||||
@staticmethod
|
||||
def _read(stream):
|
||||
tmp = stream.read()
|
||||
if tmp:
|
||||
return tmp.decode("utf-8")
|
||||
return ''
|
||||
|
||||
# Read until we get prompt back and a result
|
||||
# @param: no_output Caller expects no output to report FD
|
||||
# Returns stdout, report, stderr (report is JSON!)
|
||||
def _read_until_prompt(self, no_output=False):
|
||||
stdout = ""
|
||||
report = ""
|
||||
stderr = ""
|
||||
@@ -58,27 +65,24 @@ class LVMShellProxy(object):
|
||||
# Try reading from all FDs to prevent one from filling up and causing
|
||||
# a hang. Keep reading until we get the prompt back and the report
|
||||
# FD does not contain valid JSON
|
||||
|
||||
while keep_reading and cfg.run.value != 0:
|
||||
while keep_reading:
|
||||
try:
|
||||
rd_fd = [
|
||||
self.parent_stdout_fd,
|
||||
self.lvm_shell.stdout.fileno(),
|
||||
self.report_stream.fileno(),
|
||||
self.parent_stderr_fd]
|
||||
self.lvm_shell.stderr.fileno()]
|
||||
ready = select.select(rd_fd, [], [], 2)
|
||||
|
||||
for r in ready[0]:
|
||||
if r == self.parent_stdout_fd:
|
||||
for line in self.parent_stdout.readlines():
|
||||
stdout += line
|
||||
if r == self.lvm_shell.stdout.fileno():
|
||||
stdout += LVMShellProxy._read(self.lvm_shell.stdout)
|
||||
elif r == self.report_stream.fileno():
|
||||
report += read_decoded(self.report_stream)
|
||||
elif r == self.parent_stderr_fd:
|
||||
for line in self.parent_stderr.readlines():
|
||||
stderr += line
|
||||
report += LVMShellProxy._read(self.report_stream)
|
||||
elif r == self.lvm_shell.stderr.fileno():
|
||||
stderr += LVMShellProxy._read(self.lvm_shell.stderr)
|
||||
|
||||
# Check to see if the lvm process died on us
|
||||
if self.lvm_shell.poll() is not None:
|
||||
if self.lvm_shell.poll():
|
||||
raise Exception(self.lvm_shell.returncode, "%s" % stderr)
|
||||
|
||||
if stdout.endswith(SHELL_PROMPT):
|
||||
@@ -102,96 +106,96 @@ class LVMShellProxy(object):
|
||||
extra_passes -= 1
|
||||
if extra_passes <= 0:
|
||||
if len(report):
|
||||
raise LvmBug("Invalid json: %s" %
|
||||
raise ValueError("Invalid json: %s" %
|
||||
report)
|
||||
else:
|
||||
raise LvmBug(
|
||||
raise ValueError(
|
||||
"lvm returned no JSON output!")
|
||||
|
||||
except IOError as ioe:
|
||||
log_debug(str(ioe))
|
||||
self.exit_shell()
|
||||
raise ioe
|
||||
|
||||
if keep_reading and cfg.run.value == 0:
|
||||
# We didn't complete as we are shutting down
|
||||
# Try to clean up lvm shell process
|
||||
log_debug("exiting lvm shell as we are shutting down")
|
||||
self.exit_shell()
|
||||
raise SystemExit
|
||||
pass
|
||||
|
||||
return stdout, report_json, stderr
|
||||
|
||||
def _write_cmd(self, cmd):
|
||||
self.parent_stdin.write(cmd)
|
||||
self.parent_stdin.flush()
|
||||
cmd_bytes = bytes(cmd, "utf-8")
|
||||
num_written = self.lvm_shell.stdin.write(cmd_bytes)
|
||||
assert (num_written == len(cmd_bytes))
|
||||
self.lvm_shell.stdin.flush()
|
||||
|
||||
@staticmethod
|
||||
def _make_non_block(stream):
|
||||
flags = fcntl(stream, F_GETFL)
|
||||
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# Create a temp directory
|
||||
tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
|
||||
tmp_file = "%s/lvmdbus_report" % (tmp_dir)
|
||||
|
||||
# Create a fifo for the report output
|
||||
os.mkfifo(tmp_file, 0o600)
|
||||
try:
|
||||
# Lets create fifo for the report output
|
||||
os.mkfifo(tmp_file, 0o600)
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
# Open the fifo for use to read and for lvm child process to write to.
|
||||
# We have to open non-blocking as the other side isn't open until
|
||||
# we actually fork the process.
|
||||
self.report_fd = os.open(tmp_file, os.O_NONBLOCK)
|
||||
self.report_stream = os.fdopen(self.report_fd, 'rb', 0)
|
||||
lvm_fd = os.open(tmp_file, os.O_WRONLY)
|
||||
|
||||
# Set up the environment for using our own socket for reporting and disable the abort
|
||||
# logic if lvm logs too much, which easily happens when utilizing the lvm shell.
|
||||
local_env = {"LC_ALL": "C", "LVM_REPORT_FD": "%s" % lvm_fd, "LVM_COMMAND_PROFILE": "lvmdbusd",
|
||||
"LVM_LOG_FILE_MAX_LINES": "0"}
|
||||
# Setup the environment for using our own socket for reporting
|
||||
local_env = copy.deepcopy(os.environ)
|
||||
local_env["LVM_REPORT_FD"] = "32"
|
||||
local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd"
|
||||
|
||||
# If any env variables contain LVM we will propagate them too
|
||||
for k, v in os.environ.items():
|
||||
if "LVM" in k:
|
||||
local_env[k] = v
|
||||
|
||||
self.parent_stdin_fd, child_stdin_fd = pty.openpty()
|
||||
self.parent_stdout_fd, child_stdout_fd = pty.openpty()
|
||||
self.parent_stderr_fd, child_stderr_fd = pty.openpty()
|
||||
self.parent_stdin = os.fdopen(self.parent_stdin_fd, "w")
|
||||
self.parent_stdout = os.fdopen(self.parent_stdout_fd, "r")
|
||||
self.parent_stderr = os.fdopen(self.parent_stderr_fd, "r")
|
||||
# Disable the abort logic if lvm logs too much, which easily happens
|
||||
# when utilizing the lvm shell.
|
||||
local_env["LVM_LOG_FILE_MAX_LINES"] = "0"
|
||||
|
||||
# run the lvm shell
|
||||
self.lvm_shell = subprocess.Popen(
|
||||
[cfg.LVM_CMD],
|
||||
stdin=child_stdin_fd,
|
||||
stdout=child_stdout_fd, env=local_env,
|
||||
stderr=child_stderr_fd, close_fds=True,
|
||||
pass_fds=(lvm_fd,), shell=False)
|
||||
[LVM_CMD + " 32>%s" % tmp_file],
|
||||
stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env,
|
||||
stderr=subprocess.PIPE, close_fds=True, shell=True)
|
||||
|
||||
try:
|
||||
make_non_block(self.parent_stdout_fd)
|
||||
make_non_block(self.parent_stderr_fd)
|
||||
|
||||
# Close our copies of the child FDs there were created with the fork, we don't need them open.
|
||||
os.close(lvm_fd)
|
||||
os.close(child_stdin_fd)
|
||||
os.close(child_stdout_fd)
|
||||
os.close(child_stderr_fd)
|
||||
LVMShellProxy._make_non_block(self.lvm_shell.stdout)
|
||||
LVMShellProxy._make_non_block(self.lvm_shell.stderr)
|
||||
|
||||
# wait for the first prompt
|
||||
log_debug("waiting for first prompt...")
|
||||
errors = self._read_response(no_output=True)[2]
|
||||
errors = self._read_until_prompt(no_output=True)[2]
|
||||
if errors and len(errors):
|
||||
raise LvmBug(errors)
|
||||
log_debug("lvm prompt read!!!")
|
||||
raise RuntimeError(errors)
|
||||
except:
|
||||
raise
|
||||
finally:
|
||||
# These will get deleted when the FD count goes to zero, so we
|
||||
# These will get deleted when the FD count goes to zero so we
|
||||
# can be sure to clean up correctly no matter how we finish
|
||||
os.unlink(tmp_file)
|
||||
os.rmdir(tmp_dir)
|
||||
|
||||
def get_last_log(self):
|
||||
def get_error_msg(self):
|
||||
# We got an error, lets go fetch the error message
|
||||
self._write_cmd('lastlog\n')
|
||||
report_json = self._read_response()[1]
|
||||
return get_error_msg(report_json)
|
||||
|
||||
# read everything from the STDOUT to the next prompt
|
||||
stdout, report_json, stderr = self._read_until_prompt()
|
||||
if 'log' in report_json:
|
||||
error_msg = ""
|
||||
# Walk the entire log array and build an error string
|
||||
for log_entry in report_json['log']:
|
||||
if log_entry['log_type'] == "error":
|
||||
if error_msg:
|
||||
error_msg += ', ' + log_entry['log_message']
|
||||
else:
|
||||
error_msg = log_entry['log_message']
|
||||
|
||||
return error_msg
|
||||
|
||||
return 'No error reason provided! (missing "log" section)'
|
||||
|
||||
def call_lvm(self, argv, debug=False):
|
||||
rc = 1
|
||||
@@ -212,29 +216,21 @@ class LVMShellProxy(object):
|
||||
self._write_cmd(cmd)
|
||||
|
||||
# read everything from the STDOUT to the next prompt
|
||||
stdout, report_json, stderr = self._read_response()
|
||||
stdout, report_json, stderr = self._read_until_prompt()
|
||||
|
||||
# Parse the report to see what happened
|
||||
if 'log' in report_json:
|
||||
ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
|
||||
# If we have an exported vg we get a log_ret_code == 5 when
|
||||
# we do a 'fullreport'
|
||||
# Note: 0 == error
|
||||
if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
|
||||
rc = 0
|
||||
else:
|
||||
# Depending on where lvm fails the command, it may not have anything
|
||||
# to report for "lastlog", so we need to check for a message in the
|
||||
# report json too.
|
||||
error_msg = self.get_last_log()
|
||||
if error_msg is None:
|
||||
error_msg = get_error_msg(report_json)
|
||||
if error_msg is None:
|
||||
error_msg = 'No error reason provided! (missing "log" section)'
|
||||
error_msg = self.get_error_msg()
|
||||
|
||||
if debug or rc != 0:
|
||||
log_error(("CMD= %s" % cmd))
|
||||
log_error(("EC= %d" % rc))
|
||||
log_error(('CMD: %s' % cmd))
|
||||
log_error(("EC = %d" % rc))
|
||||
log_error(("ERROR_MSG=\n %s\n" % error_msg))
|
||||
|
||||
return rc, report_json, error_msg
|
||||
@@ -242,58 +238,35 @@ class LVMShellProxy(object):
|
||||
def exit_shell(self):
|
||||
try:
|
||||
self._write_cmd('exit\n')
|
||||
self.lvm_shell.wait(1)
|
||||
self.lvm_shell = None
|
||||
except Exception as _e:
|
||||
log_error(str(_e))
|
||||
except Exception as e:
|
||||
log_error(str(e))
|
||||
|
||||
def __del__(self):
|
||||
# Note: When we are shutting down the daemon and the main process has already exited
|
||||
# and this gets called we have a limited set of things we can do, like we cannot call
|
||||
# log_error as _common_log is None!!!
|
||||
if self.lvm_shell is not None:
|
||||
try:
|
||||
self.lvm_shell.wait(1)
|
||||
except subprocess.TimeoutExpired:
|
||||
print("lvm shell child process did not exit as instructed, sending SIGTERM")
|
||||
cfg.ignore_sigterm = True
|
||||
self.lvm_shell.terminate()
|
||||
child_exit_code = self.lvm_shell.wait(1)
|
||||
print("lvm shell process exited with %d" % child_exit_code)
|
||||
try:
|
||||
self.lvm_shell.terminate()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("USING LVM BINARY: %s " % cfg.LVM_CMD)
|
||||
|
||||
shell = LVMShellProxy()
|
||||
in_line = "start"
|
||||
try:
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "bisect":
|
||||
shell = LVMShellProxy()
|
||||
shell.exit_shell()
|
||||
else:
|
||||
shell = LVMShellProxy()
|
||||
in_line = "start"
|
||||
try:
|
||||
while in_line:
|
||||
in_line = input("lvm> ")
|
||||
if in_line:
|
||||
if in_line == "exit":
|
||||
shell.exit_shell()
|
||||
sys.exit(0)
|
||||
start = time.time()
|
||||
ret, out, err = shell.call_lvm(in_line.split())
|
||||
end = time.time()
|
||||
while in_line:
|
||||
in_line = input("lvm> ")
|
||||
if in_line:
|
||||
start = time.time()
|
||||
ret, out, err = shell.call_lvm(in_line.split())
|
||||
end = time.time()
|
||||
|
||||
print(("RC: %d" % ret))
|
||||
print(("OUT:\n%s" % out))
|
||||
print(("ERR:\n%s" % err))
|
||||
print(("RC: %d" % ret))
|
||||
print(("OUT:\n%s" % out))
|
||||
print(("ERR:\n%s" % err))
|
||||
|
||||
print("Command = %f seconds" % (end - start))
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except EOFError:
|
||||
pass
|
||||
except Exception as e:
|
||||
log_error("main process exiting on exception!\n%s" % extract_stack_trace(e))
|
||||
sys.exit(1)
|
||||
|
||||
sys.exit(0)
|
||||
print("Command = %f seconds" % (end - start))
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except EOFError:
|
||||
pass
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
|
||||
@@ -13,13 +13,14 @@ from collections import OrderedDict
|
||||
|
||||
import pprint as prettyprint
|
||||
import os
|
||||
import sys
|
||||
|
||||
from lvmdbusd import cmdhandler
|
||||
from lvmdbusd.utils import log_debug, log_error, lvm_column_key, LvmBug
|
||||
from lvmdbusd.utils import log_debug, log_error
|
||||
|
||||
|
||||
class DataStore(object):
|
||||
def __init__(self, vdo_support=False):
|
||||
def __init__(self, usejson=True, vdo_support=False):
|
||||
self.pvs = {}
|
||||
self.vgs = {}
|
||||
self.lvs = {}
|
||||
@@ -34,9 +35,41 @@ class DataStore(object):
|
||||
self.lvs_in_vgs = {}
|
||||
self.pvs_in_vgs = {}
|
||||
|
||||
# self.refresh()
|
||||
self.num_refreshes = 0
|
||||
|
||||
if usejson:
|
||||
self.json = cmdhandler.supports_json()
|
||||
else:
|
||||
self.json = usejson
|
||||
|
||||
self.vdo_support = vdo_support
|
||||
|
||||
@staticmethod
|
||||
def _insert_record(table, key, record, allowed_multiple):
|
||||
if key in table:
|
||||
existing = table[key]
|
||||
|
||||
for rec_k, rec_v in record.items():
|
||||
if rec_k in allowed_multiple:
|
||||
# This column name allows us to store multiple value for
|
||||
# each type
|
||||
if not isinstance(existing[rec_k], list):
|
||||
existing_value = existing[rec_k]
|
||||
existing[rec_k] = [existing_value, rec_v]
|
||||
else:
|
||||
existing[rec_k].append(rec_v)
|
||||
else:
|
||||
# If something is not expected to have changing values
|
||||
# lets ensure that
|
||||
if existing[rec_k] != rec_v:
|
||||
raise RuntimeError(
|
||||
"existing[%s]=%s != %s" %
|
||||
(rec_k, str(existing[rec_k]),
|
||||
str(rec_v)))
|
||||
else:
|
||||
table[key] = record
|
||||
|
||||
@staticmethod
|
||||
def _pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup):
|
||||
for p in c_pvs.values():
|
||||
@@ -51,6 +84,22 @@ class DataStore(object):
|
||||
# Lookup for translating between /dev/<name> and pv uuid
|
||||
c_lookup[p['pv_name']] = p['pv_uuid']
|
||||
|
||||
@staticmethod
|
||||
def _parse_pvs(_pvs):
|
||||
pvs = sorted(_pvs, key=lambda pk: pk['pv_name'])
|
||||
|
||||
c_pvs = OrderedDict()
|
||||
c_lookup = {}
|
||||
c_pvs_in_vgs = {}
|
||||
|
||||
for p in pvs:
|
||||
DataStore._insert_record(
|
||||
c_pvs, p['pv_uuid'], p,
|
||||
['pvseg_start', 'pvseg_size', 'segtype'])
|
||||
|
||||
DataStore._pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup)
|
||||
return c_pvs, c_lookup, c_pvs_in_vgs
|
||||
|
||||
@staticmethod
|
||||
def _parse_pvs_json(_all):
|
||||
|
||||
@@ -58,7 +107,7 @@ class DataStore(object):
|
||||
c_lookup = {}
|
||||
c_pvs_in_vgs = {}
|
||||
|
||||
# Each item in the report is a collection of information pertaining
|
||||
# Each item item in the report is a collection of information pertaining
|
||||
# to the vg
|
||||
for r in _all['report']:
|
||||
tmp_pv = []
|
||||
@@ -92,6 +141,28 @@ class DataStore(object):
|
||||
|
||||
return c_pvs, c_lookup, c_pvs_in_vgs
|
||||
|
||||
@staticmethod
|
||||
def _parse_vgs(_vgs):
|
||||
vgs = sorted(_vgs, key=lambda vk: vk['vg_uuid'])
|
||||
|
||||
c_vgs = OrderedDict()
|
||||
c_lookup = {}
|
||||
|
||||
for i in vgs:
|
||||
vg_name = i['vg_name']
|
||||
|
||||
# Lvm allows duplicate vg names. When this occurs, each subsequent
|
||||
# matching VG name will be called vg_name:vg_uuid. Note: ':' is an
|
||||
# invalid character for lvm VG names
|
||||
if vg_name in c_lookup:
|
||||
vg_name = "%s:%s" % (vg_name, i['vg_uuid'])
|
||||
i['vg_name'] = vg_name
|
||||
|
||||
c_lookup[vg_name] = i['vg_uuid']
|
||||
DataStore._insert_record(c_vgs, i['vg_uuid'], i, [])
|
||||
|
||||
return c_vgs, c_lookup
|
||||
|
||||
@staticmethod
|
||||
def _parse_vgs_json(_all):
|
||||
|
||||
@@ -156,12 +227,28 @@ class DataStore(object):
|
||||
|
||||
return c_lvs, c_lvs_in_vgs, c_lvs_hidden, c_lv_full_lookup
|
||||
|
||||
@staticmethod
|
||||
def _parse_lvs(_lvs):
|
||||
lvs = sorted(_lvs, key=lambda vk: vk['lv_name'])
|
||||
|
||||
c_lvs = OrderedDict()
|
||||
c_lv_full_lookup = OrderedDict()
|
||||
|
||||
for i in lvs:
|
||||
full_name = "%s/%s" % (i['vg_name'], i['lv_name'])
|
||||
c_lv_full_lookup[full_name] = i['lv_uuid']
|
||||
DataStore._insert_record(
|
||||
c_lvs, i['lv_uuid'], i,
|
||||
['seg_pe_ranges', 'segtype'])
|
||||
|
||||
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
|
||||
|
||||
def _parse_lvs_json(self, _all):
|
||||
|
||||
c_lvs = OrderedDict()
|
||||
c_lv_full_lookup = {}
|
||||
|
||||
# Each item in the report is a collection of information pertaining
|
||||
# Each item item in the report is a collection of information pertaining
|
||||
# to the vg
|
||||
for r in _all['report']:
|
||||
# Get the lv data for this VG.
|
||||
@@ -309,12 +396,12 @@ class DataStore(object):
|
||||
:param log Add debug log entry/exit messages
|
||||
:return: None
|
||||
"""
|
||||
try:
|
||||
self.num_refreshes += 1
|
||||
if log:
|
||||
log_debug("lvmdb - refresh entry")
|
||||
self.num_refreshes += 1
|
||||
if log:
|
||||
log_debug("lvmdb - refresh entry")
|
||||
|
||||
# Grab everything first then parse it
|
||||
# Grab everything first then parse it
|
||||
if self.json:
|
||||
# Do a single lvm retrieve for everything in json
|
||||
a = cmdhandler.lvm_full_report_json()
|
||||
|
||||
@@ -322,25 +409,29 @@ class DataStore(object):
|
||||
_vgs, _vgs_lookup = self._parse_vgs_json(a)
|
||||
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs_json(a)
|
||||
|
||||
# Set all
|
||||
self.pvs = _pvs
|
||||
self.pv_path_to_uuid = _pvs_lookup
|
||||
self.vg_name_to_uuid = _vgs_lookup
|
||||
self.lv_full_name_to_uuid = _lvs_lookup
|
||||
else:
|
||||
_raw_pvs = cmdhandler.pv_retrieve_with_segs()
|
||||
_raw_vgs = cmdhandler.vg_retrieve(None)
|
||||
_raw_lvs = cmdhandler.lv_retrieve_with_segments()
|
||||
|
||||
self.vgs = _vgs
|
||||
self.lvs = _lvs
|
||||
self.lvs_in_vgs = _lvs_in_vgs
|
||||
self.pvs_in_vgs = _pvs_in_vgs
|
||||
self.lvs_hidden = _lvs_hidden
|
||||
_pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs(_raw_pvs)
|
||||
_vgs, _vgs_lookup = self._parse_vgs(_raw_vgs)
|
||||
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs(_raw_lvs)
|
||||
|
||||
# Create lookup table for which LV and segments are on each PV
|
||||
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
|
||||
except KeyError as ke:
|
||||
key = ke.args[0]
|
||||
if lvm_column_key(key):
|
||||
raise LvmBug("missing JSON key: '%s'" % key)
|
||||
raise ke
|
||||
# Set all
|
||||
self.pvs = _pvs
|
||||
self.pv_path_to_uuid = _pvs_lookup
|
||||
self.vg_name_to_uuid = _vgs_lookup
|
||||
self.lv_full_name_to_uuid = _lvs_lookup
|
||||
|
||||
self.vgs = _vgs
|
||||
self.lvs = _lvs
|
||||
self.lvs_in_vgs = _lvs_in_vgs
|
||||
self.pvs_in_vgs = _pvs_in_vgs
|
||||
self.lvs_hidden = _lvs_hidden
|
||||
|
||||
# Create lookup table for which LV and segments are on each PV
|
||||
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
|
||||
|
||||
if log:
|
||||
log_debug("lvmdb - refresh exit")
|
||||
@@ -360,13 +451,10 @@ class DataStore(object):
|
||||
return rc
|
||||
|
||||
def pv_missing(self, pv_uuid):
|
||||
# The uuid might not be a PV, default to false
|
||||
if pv_uuid in self.pvs:
|
||||
if self.pvs[pv_uuid]['pv_missing'] == '':
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
return True
|
||||
|
||||
def fetch_vgs(self, vg_name):
|
||||
if not vg_name:
|
||||
@@ -439,7 +527,13 @@ class DataStore(object):
|
||||
if __name__ == "__main__":
|
||||
pp = prettyprint.PrettyPrinter(indent=4)
|
||||
|
||||
ds = DataStore()
|
||||
use_json = False
|
||||
|
||||
if len(sys.argv) != 1:
|
||||
print(len(sys.argv))
|
||||
use_json = True
|
||||
|
||||
ds = DataStore(use_json)
|
||||
ds.refresh()
|
||||
|
||||
print("PVS")
|
||||
|
||||
@@ -22,13 +22,14 @@ from . import lvmdb
|
||||
from gi.repository import GLib
|
||||
from .fetch import StateUpdate
|
||||
from .manager import Manager
|
||||
import traceback
|
||||
import queue
|
||||
from . import udevwatch
|
||||
from .utils import log_debug, log_error, log_msg, DebugMessages
|
||||
from .utils import log_debug, log_error
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from .cmdhandler import LvmFlightRecorder, supports_vdo, supports_json
|
||||
from .cmdhandler import LvmFlightRecorder, supports_vdo
|
||||
from .request import RequestEntry
|
||||
|
||||
|
||||
@@ -49,15 +50,12 @@ def process_request():
|
||||
log_debug("Method complete: %s" % str(req.method))
|
||||
except queue.Empty:
|
||||
pass
|
||||
except SystemExit:
|
||||
break
|
||||
except Exception as e:
|
||||
st = utils.extract_stack_trace(e)
|
||||
except Exception:
|
||||
st = traceback.format_exc()
|
||||
utils.log_error("process_request exception: \n%s" % st)
|
||||
log_debug("process_request thread exiting!")
|
||||
|
||||
|
||||
def check_fr_size(value):
|
||||
def check_bb_size(value):
|
||||
v = int(value)
|
||||
if v < 0:
|
||||
raise argparse.ArgumentTypeError(
|
||||
@@ -79,13 +77,13 @@ def install_signal_handlers():
|
||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP, utils.handler, signal.SIGHUP)
|
||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, utils.handler, signal.SIGINT)
|
||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR1, utils.handler, signal.SIGUSR1)
|
||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR2, utils.handler, signal.SIGUSR2)
|
||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, utils.handler, signal.SIGTERM)
|
||||
else:
|
||||
log_error("GLib.unix_signal_[add|add_full] are NOT available!")
|
||||
|
||||
|
||||
def process_args():
|
||||
def main():
|
||||
start = time.time()
|
||||
# Add simple command line handling
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--udev", action='store_true',
|
||||
@@ -106,141 +104,101 @@ def process_args():
|
||||
default=False,
|
||||
dest='use_lvm_shell')
|
||||
parser.add_argument(
|
||||
"--frsize",
|
||||
help="Size of the flight recorder (num. entries), 0 to disable (signal 12 to dump)",
|
||||
"--blackboxsize",
|
||||
help="Size of the black box flight recorder, 0 to disable",
|
||||
default=10,
|
||||
type=check_fr_size,
|
||||
dest='fr_size')
|
||||
type=check_bb_size,
|
||||
dest='bb_size')
|
||||
|
||||
args = parser.parse_args()
|
||||
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
|
||||
|
||||
if not args.use_json:
|
||||
log_error("Daemon no longer supports lvm without JSON support, exiting!")
|
||||
sys.exit(1)
|
||||
else:
|
||||
if not supports_json():
|
||||
log_error("Un-supported version of LVM, daemon requires JSON output, exiting!")
|
||||
sys.exit(1)
|
||||
|
||||
# Add udev watching
|
||||
if args.use_udev:
|
||||
# Make sure this msg ends up in the journal, so we know
|
||||
log_msg('The --udev option is no longer supported,'
|
||||
'the daemon always uses a combination of dbus notify from lvm tools and udev')
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def running_under_systemd():
|
||||
""""
|
||||
Checks to see if we are running under systemd, by checking damon fd 0, 1
|
||||
systemd sets stdin to /dev/null and 1 & 2 are a socket
|
||||
"""
|
||||
base = "/proc/self/fd"
|
||||
stdout = os.readlink("%s/0" % base)
|
||||
if stdout == "/dev/null":
|
||||
stdout = os.readlink("%s/1" % base)
|
||||
if "socket" in stdout:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
start = time.time()
|
||||
use_session = os.getenv('LVM_DBUSD_USE_SESSION', False)
|
||||
|
||||
# Ensure that we get consistent output for parsing stdout/stderr and that we
|
||||
# are using the lvmdbusd profile.
|
||||
# Ensure that we get consistent output for parsing stdout/stderr
|
||||
os.environ["LC_ALL"] = "C"
|
||||
os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
|
||||
|
||||
# Save off the debug data needed for lvm team to debug issues
|
||||
# only used for 'fullreport' at this time.
|
||||
cfg.lvmdebug = utils.LvmDebugData()
|
||||
|
||||
# Indicator if we are running under systemd
|
||||
cfg.systemd = running_under_systemd()
|
||||
|
||||
# Add simple command line handling
|
||||
cfg.args = process_args()
|
||||
|
||||
cfg.args = parser.parse_args()
|
||||
cfg.create_request_entry = RequestEntry
|
||||
|
||||
# We create a flight recorder in cmdhandler too, but we replace it here
|
||||
# as the user may be specifying a different size. The default one in
|
||||
# cmdhandler is for when we are running other code with a different main.
|
||||
cfg.flightrecorder = LvmFlightRecorder(cfg.args.fr_size)
|
||||
cfg.blackbox = LvmFlightRecorder(cfg.args.bb_size)
|
||||
|
||||
# Create a circular buffer for debug logs
|
||||
cfg.debug = DebugMessages()
|
||||
|
||||
log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
|
||||
if cfg.args.use_lvm_shell and not cfg.args.use_json:
|
||||
log_error("You cannot specify --lvmshell and --nojson")
|
||||
sys.exit(1)
|
||||
|
||||
# We will dynamically add interfaces which support vdo if it
|
||||
# exists.
|
||||
cfg.vdo_support = supports_vdo()
|
||||
|
||||
if cfg.vdo_support and not cfg.args.use_json:
|
||||
log_error("You cannot specify --nojson when lvm has VDO support")
|
||||
sys.exit(1)
|
||||
|
||||
# List of threads that we start up
|
||||
thread_list = []
|
||||
|
||||
install_signal_handlers()
|
||||
|
||||
with utils.LockFile(cfg.LOCK_FILE):
|
||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||
dbus.mainloop.glib.threads_init()
|
||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||
dbus.mainloop.glib.threads_init()
|
||||
|
||||
cmdhandler.set_execution(cfg.args.use_lvm_shell)
|
||||
cmdhandler.set_execution(cfg.args.use_lvm_shell)
|
||||
|
||||
if use_session:
|
||||
cfg.bus = dbus.SessionBus()
|
||||
else:
|
||||
cfg.bus = dbus.SystemBus()
|
||||
# The base name variable needs to exist for things to work.
|
||||
# noinspection PyUnusedLocal
|
||||
base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
|
||||
cfg.om = Lvm(BASE_OBJ_PATH)
|
||||
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
|
||||
if use_session:
|
||||
cfg.bus = dbus.SessionBus()
|
||||
else:
|
||||
cfg.bus = dbus.SystemBus()
|
||||
# The base name variable needs to exist for things to work.
|
||||
# noinspection PyUnusedLocal
|
||||
base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
|
||||
cfg.om = Lvm(BASE_OBJ_PATH)
|
||||
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
|
||||
|
||||
cfg.db = lvmdb.DataStore(vdo_support=cfg.vdo_support)
|
||||
cfg.db = lvmdb.DataStore(cfg.args.use_json, cfg.vdo_support)
|
||||
|
||||
# Using a thread to process requests, we cannot hang the dbus library
|
||||
# thread that is handling the dbus interface
|
||||
thread_list.append(
|
||||
threading.Thread(target=process_request, name='process_request'))
|
||||
# Using a thread to process requests, we cannot hang the dbus library
|
||||
# thread that is handling the dbus interface
|
||||
thread_list.append(
|
||||
threading.Thread(target=process_request, name='process_request'))
|
||||
|
||||
# Have a single thread handling updating lvm and the dbus model so we
|
||||
# don't have multiple threads doing this as the same time
|
||||
updater = StateUpdate()
|
||||
thread_list.append(updater.thread)
|
||||
# Have a single thread handling updating lvm and the dbus model so we
|
||||
# don't have multiple threads doing this as the same time
|
||||
updater = StateUpdate()
|
||||
thread_list.append(updater.thread)
|
||||
|
||||
cfg.load = updater.load
|
||||
cfg.load = updater.load
|
||||
|
||||
cfg.loop = GLib.MainLoop()
|
||||
cfg.loop = GLib.MainLoop()
|
||||
|
||||
for thread in thread_list:
|
||||
thread.damon = True
|
||||
thread.start()
|
||||
for thread in thread_list:
|
||||
thread.damon = True
|
||||
thread.start()
|
||||
|
||||
# In all cases we are going to monitor for udev until we get an
|
||||
# ExternalEvent. In the case where we get an external event and the user
|
||||
# didn't specify --udev we will stop monitoring udev
|
||||
udevwatch.add()
|
||||
# Add udev watching
|
||||
if cfg.args.use_udev:
|
||||
log_debug('Utilizing udev to trigger updates')
|
||||
|
||||
end = time.time()
|
||||
log_debug(
|
||||
'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
|
||||
(end - start, cmdhandler.total_time, cmdhandler.total_count),
|
||||
'bg_black', 'fg_light_green')
|
||||
# In all cases we are going to monitor for udev until we get an
|
||||
# ExternalEvent. In the case where we get an external event and the user
|
||||
# didn't specify --udev we will stop monitoring udev
|
||||
udevwatch.add()
|
||||
|
||||
try:
|
||||
if cfg.run.value != 0:
|
||||
cfg.loop.run()
|
||||
udevwatch.remove()
|
||||
end = time.time()
|
||||
log_debug(
|
||||
'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
|
||||
(end - start, cmdhandler.total_time, cmdhandler.total_count),
|
||||
'bg_black', 'fg_light_green')
|
||||
|
||||
for thread in thread_list:
|
||||
thread.join()
|
||||
except KeyboardInterrupt:
|
||||
# If we are unable to register signal handler, we will end up here when
|
||||
# the service gets a ^C or a kill -2 <parent pid>
|
||||
utils.handler(signal.SIGINT)
|
||||
try:
|
||||
if cfg.run.value != 0:
|
||||
cfg.loop.run()
|
||||
udevwatch.remove()
|
||||
|
||||
for thread in thread_list:
|
||||
thread.join()
|
||||
except KeyboardInterrupt:
|
||||
# If we are unable to register signal handler, we will end up here when
|
||||
# the service gets a ^C or a kill -2 <parent pid>
|
||||
utils.handler(signal.SIGINT)
|
||||
return 0
|
||||
|
||||
@@ -137,8 +137,7 @@ class Manager(AutomatedProperties):
|
||||
"""
|
||||
Dump the flight recorder to syslog
|
||||
"""
|
||||
cfg.debug.dump()
|
||||
cfg.flightrecorder.dump()
|
||||
cfg.blackbox.dump()
|
||||
|
||||
@staticmethod
|
||||
def _lookup_by_lvm_id(key):
|
||||
@@ -195,7 +194,6 @@ class Manager(AutomatedProperties):
|
||||
def _external_event(command):
|
||||
utils.log_debug("Processing _external_event= %s" % command,
|
||||
'bg_black', 'fg_orange')
|
||||
cfg.got_external_event = True
|
||||
cfg.load()
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -203,6 +201,14 @@ class Manager(AutomatedProperties):
|
||||
in_signature='s', out_signature='i')
|
||||
def ExternalEvent(self, command):
|
||||
utils.log_debug("ExternalEvent %s" % command)
|
||||
# If a user didn't explicitly specify udev, we will turn it off now.
|
||||
if not cfg.args.use_udev:
|
||||
if udevwatch.remove():
|
||||
utils.log_debug("ExternalEvent received, disabling "
|
||||
"udev monitoring")
|
||||
# We are dependent on external events now to stay current!
|
||||
cfg.got_external_event = True
|
||||
|
||||
r = RequestEntry(
|
||||
-1, Manager._external_event, (command,), None, None, False)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
@@ -9,11 +9,12 @@
|
||||
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
import dbus
|
||||
import os
|
||||
import copy
|
||||
from . import cfg
|
||||
from .utils import log_debug, pv_obj_path_generate, log_error, extract_stack_trace
|
||||
from .utils import log_debug, pv_obj_path_generate, log_error
|
||||
from .automatedproperties import AutomatedProperties
|
||||
|
||||
|
||||
@@ -39,8 +40,8 @@ class ObjectManager(AutomatedProperties):
|
||||
for k, v in list(obj._objects.items()):
|
||||
path, props = v[0].emit_data()
|
||||
rc[path] = props
|
||||
except Exception as e:
|
||||
log_error("_get_managed_objects exception, bailing: \n%s" % extract_stack_trace(e))
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
sys.exit(1)
|
||||
return rc
|
||||
|
||||
@@ -52,6 +53,15 @@ class ObjectManager(AutomatedProperties):
|
||||
(self, ), cb, cbe, False)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
def locked(self):
|
||||
"""
|
||||
If some external code need to run across a number of different
|
||||
calls into ObjectManager while blocking others they can use this method
|
||||
to lock others out.
|
||||
:return:
|
||||
"""
|
||||
return ObjectManagerLock(self.rlock)
|
||||
|
||||
@dbus.service.signal(
|
||||
dbus_interface="org.freedesktop.DBus.ObjectManager",
|
||||
signature='oa{sa{sv}}')
|
||||
@@ -277,7 +287,7 @@ class ObjectManager(AutomatedProperties):
|
||||
register it with the object manager for the specified uuid & lvm_id.
|
||||
Note: If path create is not None, uuid and lvm_id cannot be equal
|
||||
:param uuid: The uuid for the lvm object we are searching for
|
||||
:param lvm_id: The lvm name (e.g. pv device path, vg name, lv full name)
|
||||
:param lvm_id: The lvm name (eg. pv device path, vg name, lv full name)
|
||||
:param path_create: If not None, create the path using this function if
|
||||
we fail to find the object by uuid or lvm_id.
|
||||
:returns None if lvm asset not found and path_create == None otherwise
|
||||
@@ -298,11 +308,12 @@ class ObjectManager(AutomatedProperties):
|
||||
# We have a uuid and a lvm_id we can do sanity checks to ensure
|
||||
# that they are consistent
|
||||
|
||||
# If a PV is missing its device path is '[unknown]' or some
|
||||
# If a PV is missing it's device path is '[unknown]' or some
|
||||
# other text derivation of unknown. When we find that a PV is
|
||||
# missing we will clear out the lvm_id as it's not unique
|
||||
# and thus not useful and harmful for lookups.
|
||||
if cfg.db.pv_missing(uuid):
|
||||
# missing we will clear out the lvm_id as it's likely not unique
|
||||
# and thus not useful and potentially harmful for lookups.
|
||||
if path_create == pv_obj_path_generate and \
|
||||
cfg.db.pv_missing(uuid):
|
||||
lvm_id = None
|
||||
|
||||
# Lets check for the uuid first
|
||||
@@ -326,3 +337,29 @@ class ObjectManager(AutomatedProperties):
|
||||
# (uuid, lvm_id, str(path_create), path))
|
||||
|
||||
return path
|
||||
|
||||
|
||||
class ObjectManagerLock(object):
|
||||
"""
|
||||
The sole purpose of this class is to allow other code the ability to
|
||||
lock the object manager using a `with` statement, eg.
|
||||
|
||||
with cfg.om.locked():
|
||||
# Do stuff with object manager
|
||||
|
||||
This will ensure that the lock is always released (assuming this is done
|
||||
correctly)
|
||||
"""
|
||||
|
||||
def __init__(self, recursive_lock):
|
||||
self._lock = recursive_lock
|
||||
|
||||
def __enter__(self):
|
||||
# Acquire lock
|
||||
self._lock.acquire()
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
def __exit__(self, e_type, e_value, e_traceback):
|
||||
# Release lock
|
||||
self._lock.release()
|
||||
self._lock = None
|
||||
|
||||
@@ -14,11 +14,11 @@ import dbus
|
||||
from .cfg import PV_INTERFACE
|
||||
from . import cmdhandler
|
||||
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
|
||||
lv_object_path_method, _handle_execute, lvm_column_key
|
||||
lv_object_path_method, _handle_execute
|
||||
from .loader import common
|
||||
from .request import RequestEntry
|
||||
from .state import State
|
||||
from .utils import round_size, LvmBug
|
||||
from .utils import round_size
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
@@ -28,23 +28,16 @@ def pvs_state_retrieve(selection, cache_refresh=True):
|
||||
if cache_refresh:
|
||||
cfg.db.refresh()
|
||||
|
||||
try:
|
||||
for p in cfg.db.fetch_pvs(selection):
|
||||
rc.append(
|
||||
PvState(
|
||||
p["pv_name"], p["pv_uuid"], p["pv_name"],
|
||||
p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]),
|
||||
n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]),
|
||||
n(p["pv_mda_free"]), int(p["pv_ba_start"]),
|
||||
n(p["pv_ba_size"]), n(p["pe_start"]),
|
||||
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
|
||||
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
|
||||
except KeyError as ke:
|
||||
# Sometimes lvm omits returning one of the keys we requested.
|
||||
key = ke.args[0]
|
||||
if lvm_column_key(key):
|
||||
raise LvmBug("missing JSON key: '%s'" % key)
|
||||
raise ke
|
||||
for p in cfg.db.fetch_pvs(selection):
|
||||
rc.append(
|
||||
PvState(
|
||||
p["pv_name"], p["pv_uuid"], p["pv_name"],
|
||||
p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]),
|
||||
n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]),
|
||||
n(p["pv_mda_free"]), int(p["pv_ba_start"]),
|
||||
n(p["pv_ba_size"]), n(p["pe_start"]),
|
||||
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
|
||||
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
|
||||
return rc
|
||||
|
||||
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import dbus
|
||||
import threading
|
||||
# noinspection PyUnresolvedReferences
|
||||
from gi.repository import GLib
|
||||
from .job import Job
|
||||
from . import cfg
|
||||
from .utils import log_error, mt_async_call, extract_stack_trace
|
||||
import traceback
|
||||
from .utils import log_error, mt_async_call
|
||||
|
||||
|
||||
class RequestEntry(object):
|
||||
@@ -71,23 +71,13 @@ class RequestEntry(object):
|
||||
try:
|
||||
result = self.method(*self.arguments)
|
||||
self.register_result(result)
|
||||
except SystemExit as se:
|
||||
self.register_error(-1, str(se), se)
|
||||
raise se
|
||||
except dbus.exceptions.DBusException as dbe:
|
||||
# This is an expected error path when something goes awry that
|
||||
# we handled
|
||||
self.register_error(-1, str(dbe), dbe)
|
||||
except Exception as e:
|
||||
# Use the request entry to return the result as the client may
|
||||
# have gotten a job by the time we hit an error
|
||||
# Lets set the exception text as the error message and log the
|
||||
# exception in the journal for figuring out what went wrong.
|
||||
cfg.debug.dump()
|
||||
cfg.flightrecorder.dump()
|
||||
tb = extract_stack_trace(e)
|
||||
log_error("While processing %s: we encountered\n%s" % (str(self.method), tb))
|
||||
log_error("Error returned to client: %s" % str(e))
|
||||
# Lets get the stacktrace and set that to the error message
|
||||
st = traceback.format_exc()
|
||||
cfg.blackbox.dump()
|
||||
log_error("Exception returned to client: \n%s" % st)
|
||||
self.register_error(-1, str(e), e)
|
||||
|
||||
def is_done(self):
|
||||
|
||||
@@ -52,30 +52,20 @@ def filter_event(action, device):
|
||||
# when appropriate.
|
||||
refresh = False
|
||||
|
||||
# Ignore everything but change
|
||||
if action != 'change':
|
||||
return
|
||||
if '.ID_FS_TYPE_NEW' in device:
|
||||
fs_type_new = device['.ID_FS_TYPE_NEW']
|
||||
|
||||
if 'ID_FS_TYPE' in device:
|
||||
fs_type_new = device['ID_FS_TYPE']
|
||||
if 'LVM' in fs_type_new:
|
||||
# If we get a lvm related udev event for a block device
|
||||
# we don't know about, it's either a pvcreate which we
|
||||
# would handle with the dbus notification or something
|
||||
# copied a pv signature onto a block device, this is
|
||||
# required to catch the latter.
|
||||
if not cfg.om.get_object_by_lvm_id(device['DEVNAME']):
|
||||
refresh = True
|
||||
refresh = True
|
||||
elif fs_type_new == '':
|
||||
# Check to see if the device was one we knew about
|
||||
if 'DEVNAME' in device:
|
||||
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
|
||||
found = cfg.om.get_object_by_lvm_id(device['DEVNAME'])
|
||||
if found:
|
||||
refresh = True
|
||||
else:
|
||||
# This handles the wipefs -a path
|
||||
if not refresh and 'DEVNAME' in device:
|
||||
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
|
||||
refresh = True
|
||||
|
||||
if 'DM_LV_NAME' in device:
|
||||
refresh = True
|
||||
|
||||
if refresh:
|
||||
udev_add()
|
||||
|
||||
@@ -10,15 +10,10 @@
|
||||
import xml.etree.ElementTree as Et
|
||||
import sys
|
||||
import inspect
|
||||
import collections
|
||||
import ctypes
|
||||
import errno
|
||||
import fcntl
|
||||
import os
|
||||
import stat
|
||||
import string
|
||||
import datetime
|
||||
import tempfile
|
||||
|
||||
import dbus
|
||||
from lvmdbusd import cfg
|
||||
@@ -284,47 +279,17 @@ def parse_tags(tags):
|
||||
return dbus.Array([], signature='s')
|
||||
|
||||
|
||||
class DebugMessages(object):
|
||||
|
||||
def __init__(self, size=5000):
|
||||
self.queue = collections.deque(maxlen=size)
|
||||
self.lock = threading.RLock()
|
||||
|
||||
def add(self, message):
|
||||
with self.lock:
|
||||
self.queue.append(message)
|
||||
|
||||
def dump(self):
|
||||
if cfg.args and not cfg.args.debug:
|
||||
with self.lock:
|
||||
if len(self.queue):
|
||||
log_error("LVM dbus debug messages START last (%d max) messages" % self.queue.maxlen)
|
||||
for m in self.queue:
|
||||
print(m)
|
||||
log_error("LVM dbus debug messages END")
|
||||
self.queue.clear()
|
||||
|
||||
|
||||
def _format_log_entry(msg):
|
||||
def _common_log(msg, *attributes):
|
||||
cfg.stdout_lock.acquire()
|
||||
tid = ctypes.CDLL('libc.so.6').syscall(186)
|
||||
|
||||
if not cfg.systemd and STDOUT_TTY:
|
||||
if STDOUT_TTY:
|
||||
msg = "%s: %d:%d - %s" % \
|
||||
(datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"),
|
||||
os.getpid(), tid, msg)
|
||||
|
||||
else:
|
||||
if cfg.systemd:
|
||||
# Systemd already puts the daemon pid in the log, we'll just add the tid
|
||||
msg = "[%d]: %s" % (tid, msg)
|
||||
else:
|
||||
msg = "[%d:%d]: %s" % (os.getpid(), tid, msg)
|
||||
return msg
|
||||
|
||||
|
||||
def _common_log(msg, *attributes):
|
||||
cfg.stdout_lock.acquire()
|
||||
msg = _format_log_entry(msg)
|
||||
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
|
||||
|
||||
if STDOUT_TTY and attributes:
|
||||
print(color(msg, *attributes))
|
||||
@@ -341,19 +306,12 @@ def _common_log(msg, *attributes):
|
||||
def log_debug(msg, *attributes):
|
||||
if cfg.args and cfg.args.debug:
|
||||
_common_log(msg, *attributes)
|
||||
else:
|
||||
if cfg.debug:
|
||||
cfg.debug.add(_format_log_entry(msg))
|
||||
|
||||
|
||||
def log_error(msg, *attributes):
|
||||
_common_log(msg, *attributes)
|
||||
|
||||
|
||||
def log_msg(msg, *attributes):
|
||||
_common_log(msg, *attributes)
|
||||
|
||||
|
||||
def dump_threads_stackframe():
|
||||
ident_to_name = {}
|
||||
|
||||
@@ -381,32 +339,15 @@ def dump_threads_stackframe():
|
||||
# noinspection PyUnusedLocal
|
||||
def handler(signum):
|
||||
try:
|
||||
# signal 10
|
||||
if signum == signal.SIGUSR1:
|
||||
cfg.debug.dump()
|
||||
dump_threads_stackframe()
|
||||
# signal 12
|
||||
elif signum == signal.SIGUSR2:
|
||||
cfg.debug.dump()
|
||||
cfg.flightrecorder.dump()
|
||||
else:
|
||||
# If we are getting a SIGTERM, and we sent one to the lvm shell we
|
||||
# will ignore this and keep running.
|
||||
if signum == signal.SIGTERM and cfg.ignore_sigterm:
|
||||
# Clear the flag, so we will exit on SIGTERM if we didn't
|
||||
# send it.
|
||||
cfg.ignore_sigterm = False
|
||||
return True
|
||||
|
||||
# If lvm shell is in use, tell it to exit
|
||||
if cfg.SHELL_IN_USE is not None:
|
||||
cfg.SHELL_IN_USE.exit_shell()
|
||||
cfg.run.value = 0
|
||||
log_error('Exiting daemon with signal %d' % signum)
|
||||
log_debug('Exiting daemon with signal %d' % signum)
|
||||
if cfg.loop is not None:
|
||||
cfg.loop.quit()
|
||||
except BaseException as be:
|
||||
st = extract_stack_trace(be)
|
||||
except:
|
||||
st = traceback.format_exc()
|
||||
log_error("signal handler: exception (logged, not reported!) \n %s" % st)
|
||||
|
||||
# It's important we report that we handled the exception for the exception
|
||||
@@ -630,23 +571,6 @@ def validate_tag(interface, tag):
|
||||
% (tag, _ALLOWABLE_TAG_CH))
|
||||
|
||||
|
||||
def add_config_option(cmdline, key, value):
|
||||
if 'help' in cmdline:
|
||||
return cmdline
|
||||
|
||||
if key in cmdline:
|
||||
for i, arg in enumerate(cmdline):
|
||||
if arg == key:
|
||||
if len(cmdline) <= i + 1:
|
||||
raise dbus.exceptions.DBusException("Missing value for --config option.")
|
||||
cmdline[i + 1] += " %s" % value
|
||||
break
|
||||
else:
|
||||
cmdline.extend([key, value])
|
||||
|
||||
return cmdline
|
||||
|
||||
|
||||
def add_no_notify(cmdline):
|
||||
"""
|
||||
Given a command line to execute we will see if `--config` is present, if it
|
||||
@@ -658,18 +582,27 @@ def add_no_notify(cmdline):
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
# Only after we have seen an external event will we disable lvm from sending
|
||||
# Only after we have seen an external event will be disable lvm from sending
|
||||
# us one when we call lvm
|
||||
rv = cmdline
|
||||
if cfg.got_external_event:
|
||||
rv = add_config_option(rv, "--config", "global/notify_dbus=0")
|
||||
if 'help' in cmdline:
|
||||
return cmdline
|
||||
|
||||
return rv
|
||||
if '--config' in cmdline:
|
||||
for i, arg in enumerate(cmdline):
|
||||
if arg == '--config':
|
||||
if len(cmdline) <= i+1:
|
||||
raise dbus.exceptions.DBusException("Missing value for --config option.")
|
||||
cmdline[i+1] += " global/notify_dbus=0"
|
||||
break
|
||||
else:
|
||||
cmdline.extend(['--config', 'global/notify_dbus=0'])
|
||||
return cmdline
|
||||
|
||||
|
||||
# The methods below which start with mt_* are used to execute the desired code
|
||||
# on the main thread of execution to alleviate any issues the dbus-python
|
||||
# library with regard to multithreaded access. Essentially, we are trying to
|
||||
# on the the main thread of execution to alleviate any issues the dbus-python
|
||||
# library with regards to multi-threaded access. Essentially, we are trying to
|
||||
# ensure all dbus library interaction is done from the same thread!
|
||||
|
||||
|
||||
@@ -683,8 +616,9 @@ def _async_handler(call_back, parameters):
|
||||
call_back(*parameters)
|
||||
else:
|
||||
call_back()
|
||||
except BaseException as be:
|
||||
log_error("mt_async_call: exception (logged, not reported!) \n %s" % extract_stack_trace(be))
|
||||
except:
|
||||
st = traceback.format_exc()
|
||||
log_error("mt_async_call: exception (logged, not reported!) \n %s" % st)
|
||||
|
||||
|
||||
# Execute the function on the main thread with the provided parameters, do
|
||||
@@ -734,6 +668,9 @@ class MThreadRunner(object):
|
||||
self.rc = self.f()
|
||||
except BaseException as be:
|
||||
self.exception = be
|
||||
st = traceback.format_exc()
|
||||
log_error("MThreadRunner: exception \n %s" % st)
|
||||
log_error("Exception will be raised in calling thread!")
|
||||
|
||||
|
||||
def _remove_objects(dbus_objects_rm):
|
||||
@@ -744,135 +681,3 @@ def _remove_objects(dbus_objects_rm):
|
||||
# Remove dbus objects from main thread
|
||||
def mt_remove_dbus_objects(objs):
|
||||
MThreadRunner(_remove_objects, objs).done()
|
||||
|
||||
|
||||
# Make stream non-blocking
|
||||
def make_non_block(stream):
|
||||
flags = fcntl.fcntl(stream, fcntl.F_GETFL)
|
||||
fcntl.fcntl(stream, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
||||
|
||||
|
||||
def read_decoded(stream):
|
||||
tmp = stream.read()
|
||||
if tmp:
|
||||
return tmp.decode("utf-8")
|
||||
return ''
|
||||
|
||||
|
||||
class LockFile(object):
|
||||
"""
|
||||
Simple lock file class
|
||||
Based on Pg.1144 "The Linux Programming Interface" by Michael Kerrisk
|
||||
"""
|
||||
def __init__(self, lock_file):
|
||||
self.fd = 0
|
||||
self.lock_file = lock_file
|
||||
|
||||
def __enter__(self):
|
||||
try:
|
||||
self.fd = os.open(self.lock_file, os.O_CREAT | os.O_RDWR, stat.S_IRUSR | stat.S_IWUSR)
|
||||
|
||||
# Get and set the close on exec and lock the file
|
||||
flags = fcntl.fcntl(self.fd, fcntl.F_GETFD)
|
||||
flags |= fcntl.FD_CLOEXEC
|
||||
fcntl.fcntl(self.fd, fcntl.F_SETFL, flags)
|
||||
fcntl.lockf(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EAGAIN:
|
||||
log_error("Daemon already running, exiting!")
|
||||
else:
|
||||
log_error("Error during creation of lock file(%s): errno(%d), exiting!" % (self.lock_file, e.errno))
|
||||
sys.exit(114)
|
||||
|
||||
def __exit__(self, _type, _value, _traceback):
|
||||
os.close(self.fd)
|
||||
|
||||
|
||||
def extract_stack_trace(exception):
|
||||
return ''.join(traceback.format_exception(None, exception, exception.__traceback__))
|
||||
|
||||
|
||||
def lvm_column_key(key):
|
||||
# Check LV
|
||||
if key.startswith("lv_") or key.startswith("vg_") or key.startswith("pool_") or \
|
||||
key.endswith("_percent") or key.startswith("move_") or key.startswith("vdo_") or \
|
||||
key in ["origin_uuid", "segtype", "origin", "data_lv", "metadata_lv"]:
|
||||
return True
|
||||
# Check VG
|
||||
if key.startswith("vg_") or key.startswith("lv_") or key.startswith("pv_") or \
|
||||
key in ["max_lv", "max_pv", "snap_count"]:
|
||||
return True
|
||||
# Check PV
|
||||
if key.startswith("pv") or key.startswith("vg") or (key in ['dev_size', 'pe_start']):
|
||||
return True
|
||||
return False
|
||||
|
||||
class LvmBug(RuntimeError):
|
||||
"""
|
||||
Things that are clearly a bug with lvm itself.
|
||||
"""
|
||||
def __init__(self, msg):
|
||||
super().__init__(msg)
|
||||
|
||||
def __str__(self):
|
||||
return "lvm bug encountered: %s" % ' '.join(self.args)
|
||||
|
||||
|
||||
class LvmDebugData:
|
||||
def __init__(self):
|
||||
self.fd = -1
|
||||
self.fn = None
|
||||
|
||||
def _remove_file(self):
|
||||
if self.fn is not None:
|
||||
os.unlink(self.fn)
|
||||
self.fn = None
|
||||
|
||||
def _close_fd(self):
|
||||
if self.fd != -1:
|
||||
os.close(self.fd)
|
||||
self.fd = -1
|
||||
|
||||
def setup(self):
|
||||
# Create a secure filename
|
||||
self.fd, self.fn = tempfile.mkstemp(suffix=".log", prefix="lvmdbusd.lvm.debug.")
|
||||
return self.fn
|
||||
|
||||
def lvm_complete(self):
|
||||
# Remove the file ASAP, so we decrease our odds of leaving it
|
||||
# around if the daemon gets killed by a signal -9
|
||||
self._remove_file()
|
||||
|
||||
def dump(self):
|
||||
# Read the file and log it to log_err
|
||||
if self.fd != -1:
|
||||
# How big could the verbose debug get?
|
||||
debug = os.read(self.fd, 1024*1024*5)
|
||||
debug_txt = debug.decode("utf-8")
|
||||
for line in debug_txt.split("\n"):
|
||||
log_error("lvm debug >>> %s" % line)
|
||||
self._close_fd()
|
||||
# In case lvm_complete doesn't get called.
|
||||
self._remove_file()
|
||||
|
||||
def complete(self):
|
||||
self._close_fd()
|
||||
# In case lvm_complete doesn't get called.
|
||||
self._remove_file()
|
||||
|
||||
|
||||
def get_error_msg(report_json):
|
||||
# Get the error message from the returned JSON
|
||||
if 'log' in report_json:
|
||||
error_msg = ""
|
||||
# Walk the entire log array and build an error string
|
||||
for log_entry in report_json['log']:
|
||||
if log_entry['log_type'] == "error":
|
||||
if error_msg:
|
||||
error_msg += ', ' + log_entry['log_message']
|
||||
else:
|
||||
error_msg = log_entry['log_message']
|
||||
|
||||
return error_msg
|
||||
|
||||
return None
|
||||
|
||||
@@ -20,7 +20,7 @@ from .request import RequestEntry
|
||||
from .loader import common
|
||||
from .state import State
|
||||
from . import background
|
||||
from .utils import round_size, mt_remove_dbus_objects, LvmBug, lvm_column_key
|
||||
from .utils import round_size, mt_remove_dbus_objects
|
||||
from .job import JobState
|
||||
|
||||
|
||||
@@ -31,24 +31,17 @@ def vgs_state_retrieve(selection, cache_refresh=True):
|
||||
if cache_refresh:
|
||||
cfg.db.refresh()
|
||||
|
||||
try:
|
||||
for v in cfg.db.fetch_vgs(selection):
|
||||
rc.append(
|
||||
VgState(
|
||||
v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
|
||||
n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
|
||||
n(v['vg_extent_count']), n(v['vg_free_count']),
|
||||
v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
|
||||
n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
|
||||
n(v['vg_seqno']), n(v['vg_mda_count']),
|
||||
n(v['vg_mda_free']), n(v['vg_mda_size']),
|
||||
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
|
||||
except KeyError as ke:
|
||||
# Sometimes lvm omits returning one of the keys we requested.
|
||||
key = ke.args[0]
|
||||
if lvm_column_key(key):
|
||||
raise LvmBug("missing JSON key: '%s'" % key)
|
||||
raise ke
|
||||
for v in cfg.db.fetch_vgs(selection):
|
||||
rc.append(
|
||||
VgState(
|
||||
v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
|
||||
n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
|
||||
n(v['vg_extent_count']), n(v['vg_free_count']),
|
||||
v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
|
||||
n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
|
||||
n(v['vg_seqno']), n(v['vg_mda_count']),
|
||||
n(v['vg_mda_free']), n(v['vg_mda_size']),
|
||||
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
|
||||
return rc
|
||||
|
||||
|
||||
|
||||
@@ -30,39 +30,33 @@ ifeq ("@BUILD_LOCKDDLM@", "yes")
|
||||
LOCK_LIBS += -ldlmcontrol
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LOCKDIDM@", "yes")
|
||||
SOURCES += lvmlockd-idm.c
|
||||
LOCK_LIBS += -lseagate_ilm -lblkid
|
||||
endif
|
||||
|
||||
SOURCES2 = lvmlockctl.c
|
||||
|
||||
TARGETS = lvmlockd lvmlockctl
|
||||
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
CFLOW_TARGET = lvmlockd
|
||||
|
||||
.PHONY: install_lvmlockd install_lvmlockctl
|
||||
.PHONY: install_lvmlockd
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
||||
|
||||
|
||||
ifeq ($(USE_SD_NOTIFY),yes)
|
||||
CFLAGS += $(shell pkg-config --cflags libsystemd) -DUSE_SD_NOTIFY
|
||||
LIBS += $(shell pkg-config --libs libsystemd)
|
||||
endif
|
||||
|
||||
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
|
||||
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LOCK_LIBS) $(LIBS)
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LOCK_LIBS) -ldaemonserver $(INTERNAL_LIBS) $(LIBS)
|
||||
|
||||
lvmlockctl: lvmlockctl.o $(INTERNAL_LIBS)
|
||||
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(INTERNAL_LIBS) $(LIBS)
|
||||
|
||||
install_lvmlockd: lvmlockd
|
||||
@echo " [INSTALL] $<"
|
||||
|
||||
@@ -18,11 +18,8 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
static int quit = 0;
|
||||
static int info = 0;
|
||||
@@ -33,7 +30,6 @@ static int kill_vg = 0;
|
||||
static int drop_vg = 0;
|
||||
static int gl_enable = 0;
|
||||
static int gl_disable = 0;
|
||||
static int use_stderr = 0;
|
||||
static int stop_lockspaces = 0;
|
||||
static char *arg_vg_name = NULL;
|
||||
|
||||
@@ -51,22 +47,6 @@ do { \
|
||||
printf(fmt "\n", ##args); \
|
||||
} while (0)
|
||||
|
||||
#define log_sys_emerg(fmt, args...) \
|
||||
do { \
|
||||
if (use_stderr) \
|
||||
fprintf(stderr, fmt "\n", ##args); \
|
||||
else \
|
||||
syslog(LOG_EMERG, fmt, ##args); \
|
||||
} while (0)
|
||||
|
||||
#define log_sys_warn(fmt, args...) \
|
||||
do { \
|
||||
if (use_stderr) \
|
||||
fprintf(stderr, fmt "\n", ##args); \
|
||||
else \
|
||||
syslog(LOG_WARNING, fmt, ##args); \
|
||||
} while (0)
|
||||
|
||||
#define MAX_LINE 512
|
||||
|
||||
/* copied from lvmlockd-internal.h */
|
||||
@@ -457,7 +437,6 @@ retry:
|
||||
if (count < dump_len)
|
||||
goto retry;
|
||||
|
||||
dump_buf[count] = 0;
|
||||
rv = 0;
|
||||
if ((info && dump) || !strcmp(req_name, "dump"))
|
||||
printf("%s\n", dump_buf);
|
||||
@@ -523,274 +502,51 @@ static int do_stop_lockspaces(void)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int _reopen_fd_to_null(int fd)
|
||||
static int do_kill(void)
|
||||
{
|
||||
int null_fd;
|
||||
int r = 0;
|
||||
|
||||
if ((null_fd = open("/dev/null", O_RDWR)) == -1) {
|
||||
log_error("open error /dev/null %d", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (close(fd)) {
|
||||
log_error("close error fd %d %d", fd, errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dup2(null_fd, fd) == -1) {
|
||||
log_error("dup2 error %d", errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
if (close(null_fd)) {
|
||||
log_error("close error fd %d %d", null_fd, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#define MAX_AV_COUNT 32
|
||||
#define ONE_ARG_LEN 1024
|
||||
|
||||
static void _run_command_pipe(const char *cmd_str, pid_t *pid_out, FILE **fp_out)
|
||||
{
|
||||
char arg[ONE_ARG_LEN];
|
||||
char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */
|
||||
char *arg_dup;
|
||||
int av_count = 0;
|
||||
int cmd_len;
|
||||
int arg_len;
|
||||
pid_t pid = 0;
|
||||
FILE *fp = NULL;
|
||||
int pipefd[2];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_AV_COUNT + 1; i++)
|
||||
av[i] = NULL;
|
||||
|
||||
cmd_len = strlen(cmd_str);
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg_len = 0;
|
||||
|
||||
for (i = 0; i < cmd_len; i++) {
|
||||
if (!cmd_str[i])
|
||||
break;
|
||||
|
||||
if (av_count == MAX_AV_COUNT)
|
||||
goto out;
|
||||
|
||||
if (cmd_str[i] == '\\') {
|
||||
if (i == (cmd_len - 1))
|
||||
break;
|
||||
i++;
|
||||
|
||||
if (cmd_str[i] == '\\') {
|
||||
arg[arg_len++] = cmd_str[i];
|
||||
continue;
|
||||
}
|
||||
if (isspace(cmd_str[i])) {
|
||||
arg[arg_len++] = cmd_str[i];
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isalnum(cmd_str[i]) || ispunct(cmd_str[i])) {
|
||||
arg[arg_len++] = cmd_str[i];
|
||||
} else if (isspace(cmd_str[i])) {
|
||||
if (arg_len) {
|
||||
if (!(arg_dup = strdup(arg)))
|
||||
goto out;
|
||||
av[av_count++] = arg_dup;
|
||||
}
|
||||
|
||||
memset(arg, 0, sizeof(arg));
|
||||
arg_len = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_len) {
|
||||
if (av_count >= MAX_AV_COUNT)
|
||||
goto out;
|
||||
if (!(arg_dup = strdup(arg)))
|
||||
goto out;
|
||||
av[av_count++] = arg_dup;
|
||||
}
|
||||
|
||||
if (pipe(pipefd)) {
|
||||
log_error("pipe error %d", errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
log_error("fork error %d", errno);
|
||||
pid = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
/* Child -> writer, convert pipe[0] to STDOUT */
|
||||
if (!_reopen_fd_to_null(STDIN_FILENO))
|
||||
log_error("reopen STDIN error");
|
||||
else if (close(pipefd[0 /*read*/]))
|
||||
log_error("close error pipe[0] %d", errno);
|
||||
else if (close(STDOUT_FILENO))
|
||||
log_error("close error STDOUT %d", errno);
|
||||
else if (dup2(pipefd[1 /*write*/], STDOUT_FILENO) == -1)
|
||||
log_error("dup2 error STDOUT %d", errno);
|
||||
else if (close(pipefd[1]))
|
||||
log_error("close error pipe[1] %d", errno);
|
||||
else {
|
||||
execvp(av[0], av);
|
||||
log_error("execvp error %d", errno);
|
||||
}
|
||||
_exit(errno);
|
||||
}
|
||||
|
||||
/* Parent -> reader */
|
||||
if (close(pipefd[1 /*write*/]))
|
||||
log_error("close error STDOUT %d", errno);
|
||||
|
||||
if (!(fp = fdopen(pipefd[0 /*read*/], "r"))) {
|
||||
log_error("fdopen STDIN error %d", errno);
|
||||
if (close(pipefd[0]))
|
||||
log_error("close error STDIN %d", errno);
|
||||
}
|
||||
|
||||
out:
|
||||
for (i = 0; i < MAX_AV_COUNT + 1; i++)
|
||||
free(av[i]);
|
||||
|
||||
*pid_out = pid;
|
||||
*fp_out = fp;
|
||||
}
|
||||
|
||||
/* Returns -1 on error, 0 on success. */
|
||||
|
||||
static int _close_command_pipe(pid_t pid, FILE *fp)
|
||||
{
|
||||
int status, estatus;
|
||||
int ret = -1;
|
||||
|
||||
if (waitpid(pid, &status, 0) != pid) {
|
||||
log_error("waitpid error pid %d %d", pid, errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
/* pid exited with an exit code */
|
||||
estatus = WEXITSTATUS(status);
|
||||
|
||||
/* exit status 0: child success */
|
||||
if (!estatus) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* exit status not zero: child error */
|
||||
log_error("child exit error %d", estatus);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (WIFSIGNALED(status)) {
|
||||
/* pid terminated due to a signal */
|
||||
log_error("child exit from signal");
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_error("child exit problem");
|
||||
|
||||
out:
|
||||
if (fp && fclose(fp))
|
||||
log_error("fclose error STDIN %d", errno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns -1 on error, 0 on success. */
|
||||
|
||||
static int _get_kill_command(char *kill_cmd)
|
||||
{
|
||||
char config_cmd[PATH_MAX + 128] = { 0 };
|
||||
char config_val[1024] = { 0 };
|
||||
char line[PATH_MAX] = { 0 };
|
||||
pid_t pid = 0;
|
||||
FILE *fp = NULL;
|
||||
|
||||
snprintf(config_cmd, PATH_MAX, "%s config --typeconfig full global/lvmlockctl_kill_command", LVM_PATH);
|
||||
|
||||
_run_command_pipe(config_cmd, &pid, &fp);
|
||||
|
||||
if (!pid) {
|
||||
log_error("failed to run %s", config_cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fp) {
|
||||
log_error("failed to get output %s", config_cmd);
|
||||
_close_command_pipe(pid, fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fgets(line, sizeof(line), fp)) {
|
||||
log_error("no output from %s", config_cmd);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (sscanf(line, "lvmlockctl_kill_command=\"%256[^\n\"]\"", config_val) != 1) {
|
||||
log_error("unrecognized config value from %s", config_cmd);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!config_val[0] || (config_val[0] == ' ')) {
|
||||
log_error("invalid config value from %s", config_cmd);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (config_val[0] != '/') {
|
||||
log_error("lvmlockctl_kill_command must be full path");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
printf("Found lvmlockctl_kill_command: %s\n", config_val);
|
||||
|
||||
snprintf(kill_cmd, PATH_MAX, "%s %s", config_val, arg_vg_name);
|
||||
kill_cmd[PATH_MAX-1] = '\0';
|
||||
|
||||
_close_command_pipe(pid, fp);
|
||||
return 0;
|
||||
bad:
|
||||
_close_command_pipe(pid, fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Returns -1 on error, 0 on success. */
|
||||
|
||||
static int _run_kill_command(char *kill_cmd)
|
||||
{
|
||||
pid_t pid = 0;
|
||||
FILE *fp = NULL;
|
||||
daemon_reply reply;
|
||||
int result;
|
||||
int rv;
|
||||
|
||||
_run_command_pipe(kill_cmd, &pid, &fp);
|
||||
rv = _close_command_pipe(pid, fp);
|
||||
syslog(LOG_EMERG, "Lost access to sanlock lease storage in VG %s.", arg_vg_name);
|
||||
/* These two lines explain the manual alternative to the FIXME below. */
|
||||
syslog(LOG_EMERG, "Immediately deactivate LVs in VG %s.", arg_vg_name);
|
||||
syslog(LOG_EMERG, "Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
|
||||
|
||||
if (!pid)
|
||||
return -1;
|
||||
/*
|
||||
* It may not be strictly necessary to notify lvmlockd of the kill, but
|
||||
* lvmlockd can use this information to avoid attempting any new lock
|
||||
* requests in the VG (which would fail anyway), and can return an
|
||||
* error indicating that the VG has been killed.
|
||||
*/
|
||||
|
||||
if (rv < 0)
|
||||
return -1;
|
||||
reply = _lvmlockd_send("kill_vg",
|
||||
"cmd = %s", "lvmlockctl",
|
||||
"pid = " FMTd64, (int64_t) getpid(),
|
||||
"vg_name = %s", arg_vg_name,
|
||||
NULL);
|
||||
|
||||
return 0;
|
||||
if (!_lvmlockd_result(reply, &result)) {
|
||||
log_error("lvmlockd result %d", result);
|
||||
rv = result;
|
||||
} else {
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
daemon_reply_destroy(reply);
|
||||
|
||||
/*
|
||||
* FIXME: here is where we should implement a strong form of
|
||||
* blkdeactivate, and if it completes successfully, automatically call
|
||||
* do_drop() afterward. (The drop step may not always be necessary
|
||||
* if the lvm commands run while shutting things down release all the
|
||||
* leases.)
|
||||
*
|
||||
* run_strong_blkdeactivate();
|
||||
* do_drop();
|
||||
*/
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int do_drop(void)
|
||||
@@ -799,7 +555,7 @@ static int do_drop(void)
|
||||
int result;
|
||||
int rv;
|
||||
|
||||
log_sys_warn("Dropping locks for VG %s.", arg_vg_name);
|
||||
syslog(LOG_WARNING, "Dropping locks for VG %s.", arg_vg_name);
|
||||
|
||||
/*
|
||||
* Check for misuse by looking for any active LVs in the VG
|
||||
@@ -827,84 +583,6 @@ static int do_drop(void)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int do_kill(void)
|
||||
{
|
||||
char kill_cmd[PATH_MAX] = { 0 };
|
||||
daemon_reply reply;
|
||||
int no_kill_command = 0;
|
||||
int result;
|
||||
int rv;
|
||||
|
||||
log_sys_emerg("lvmlockd lost access to locks in VG %s.", arg_vg_name);
|
||||
|
||||
rv = _get_kill_command(kill_cmd);
|
||||
if (rv < 0) {
|
||||
log_sys_emerg("Immediately deactivate LVs in VG %s.", arg_vg_name);
|
||||
log_sys_emerg("Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
|
||||
no_kill_command = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* It may not be strictly necessary to notify lvmlockd of the kill, but
|
||||
* lvmlockd can use this information to avoid attempting any new lock
|
||||
* requests in the VG (which would fail anyway), and can return an
|
||||
* error indicating that the VG has been killed.
|
||||
*/
|
||||
_lvmlockd = lvmlockd_open(NULL);
|
||||
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
|
||||
log_error("Cannot connect to lvmlockd for kill_vg.");
|
||||
goto run;
|
||||
}
|
||||
reply = _lvmlockd_send("kill_vg",
|
||||
"cmd = %s", "lvmlockctl",
|
||||
"pid = " FMTd64, (int64_t) getpid(),
|
||||
"vg_name = %s", arg_vg_name,
|
||||
NULL);
|
||||
if (!_lvmlockd_result(reply, &result))
|
||||
log_error("lvmlockd result %d kill_vg", result);
|
||||
daemon_reply_destroy(reply);
|
||||
lvmlockd_close(_lvmlockd);
|
||||
|
||||
run:
|
||||
if (no_kill_command)
|
||||
return 0;
|
||||
|
||||
rv = _run_kill_command(kill_cmd);
|
||||
if (rv < 0) {
|
||||
log_sys_emerg("Failed to run VG %s kill command %s", arg_vg_name, kill_cmd);
|
||||
log_sys_emerg("Immediately deactivate LVs in VG %s.", arg_vg_name);
|
||||
log_sys_emerg("Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_sys_warn("Successful VG %s kill command %s", arg_vg_name, kill_cmd);
|
||||
|
||||
/*
|
||||
* If kill command was successfully, call do_drop(). (The drop step
|
||||
* may not always be necessary if the lvm commands run while shutting
|
||||
* things down release all the leases.)
|
||||
*/
|
||||
rv = 0;
|
||||
_lvmlockd = lvmlockd_open(NULL);
|
||||
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
|
||||
log_sys_emerg("Failed to connect to lvmlockd to drop locks in VG %s.", arg_vg_name);
|
||||
return -1;
|
||||
}
|
||||
reply = _lvmlockd_send("drop_vg",
|
||||
"cmd = %s", "lvmlockctl",
|
||||
"pid = " FMTd64, (int64_t) getpid(),
|
||||
"vg_name = %s", arg_vg_name,
|
||||
NULL);
|
||||
if (!_lvmlockd_result(reply, &result)) {
|
||||
log_sys_emerg("Failed to drop locks in VG %s", arg_vg_name);
|
||||
rv = result;
|
||||
}
|
||||
daemon_reply_destroy(reply);
|
||||
lvmlockd_close(_lvmlockd);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
printf("lvmlockctl options\n");
|
||||
@@ -922,7 +600,7 @@ static void print_usage(void)
|
||||
printf("--force | -f 0|1>\n");
|
||||
printf(" Force option for other commands.\n");
|
||||
printf("--kill | -k <vgname>\n");
|
||||
printf(" Kill access to the VG locks are lost (see lvmlockctl_kill_command).\n");
|
||||
printf(" Kill access to the VG when sanlock cannot renew lease.\n");
|
||||
printf("--drop | -r <vgname>\n");
|
||||
printf(" Clear locks for the VG when it is unused after kill (-k).\n");
|
||||
printf("--gl-enable | -E <vgname>\n");
|
||||
@@ -931,8 +609,6 @@ static void print_usage(void)
|
||||
printf(" Tell lvmlockd to disable the global lock in a sanlock VG.\n");
|
||||
printf("--stop-lockspaces | -S\n");
|
||||
printf(" Stop all lockspaces.\n");
|
||||
printf("--stderr | -e\n");
|
||||
printf(" Send kill and drop messages to stderr instead of syslog\n");
|
||||
}
|
||||
|
||||
static int read_options(int argc, char *argv[])
|
||||
@@ -952,7 +628,6 @@ static int read_options(int argc, char *argv[])
|
||||
{"gl-enable", required_argument, 0, 'E' },
|
||||
{"gl-disable", required_argument, 0, 'D' },
|
||||
{"stop-lockspaces", no_argument, 0, 'S' },
|
||||
{"stderr", no_argument, 0, 'e' },
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -962,7 +637,7 @@ static int read_options(int argc, char *argv[])
|
||||
}
|
||||
|
||||
while (1) {
|
||||
c = getopt_long(argc, argv, "hqidE:D:w:k:r:Se", long_options, &option_index);
|
||||
c = getopt_long(argc, argv, "hqidE:D:w:k:r:S", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
@@ -988,30 +663,23 @@ static int read_options(int argc, char *argv[])
|
||||
break;
|
||||
case 'k':
|
||||
kill_vg = 1;
|
||||
free(arg_vg_name);
|
||||
arg_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
drop_vg = 1;
|
||||
free(arg_vg_name);
|
||||
arg_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'E':
|
||||
gl_enable = 1;
|
||||
free(arg_vg_name);
|
||||
arg_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'D':
|
||||
gl_disable = 1;
|
||||
free(arg_vg_name);
|
||||
arg_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'S':
|
||||
stop_lockspaces = 1;
|
||||
break;
|
||||
case 'e':
|
||||
use_stderr = 1;
|
||||
break;
|
||||
default:
|
||||
print_usage();
|
||||
exit(1);
|
||||
@@ -1030,12 +698,8 @@ int main(int argc, char **argv)
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
/* do_kill handles lvmlockd connections itself */
|
||||
if (kill_vg)
|
||||
return do_kill();
|
||||
|
||||
|
||||
_lvmlockd = lvmlockd_open(NULL);
|
||||
|
||||
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
|
||||
log_error("Cannot connect to lvmlockd.");
|
||||
return -1;
|
||||
@@ -1056,6 +720,11 @@ int main(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (kill_vg) {
|
||||
rv = do_kill();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (drop_vg) {
|
||||
rv = do_drop();
|
||||
goto out;
|
||||
|
||||
@@ -421,56 +421,6 @@ struct lockspace *alloc_lockspace(void)
|
||||
return ls;
|
||||
}
|
||||
|
||||
static char **alloc_pvs_path(struct pvs *pvs, int num)
|
||||
{
|
||||
if (!num)
|
||||
return NULL;
|
||||
|
||||
pvs->path = malloc(sizeof(char *) * num);
|
||||
if (!pvs->path)
|
||||
return NULL;
|
||||
|
||||
memset(pvs->path, 0x0, sizeof(char *) * num);
|
||||
return pvs->path;
|
||||
}
|
||||
|
||||
static void free_pvs_path(struct pvs *pvs)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pvs->num; i++)
|
||||
free((char *)pvs->path[i]);
|
||||
|
||||
free(pvs->path);
|
||||
pvs->path = NULL;
|
||||
}
|
||||
|
||||
static char **alloc_and_copy_pvs_path(struct pvs *dst, struct pvs *src)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!alloc_pvs_path(dst, src->num))
|
||||
return NULL;
|
||||
|
||||
dst->num = 0;
|
||||
for (i = 0; i < src->num; i++) {
|
||||
if (!src->path[i] || !strcmp(src->path[i], "none"))
|
||||
continue;
|
||||
|
||||
dst->path[dst->num] = strdup(src->path[i]);
|
||||
if (!dst->path[dst->num]) {
|
||||
log_error("out of memory for copying pvs path");
|
||||
goto failed;
|
||||
}
|
||||
dst->num++;
|
||||
}
|
||||
return dst->path;
|
||||
|
||||
failed:
|
||||
free_pvs_path(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct action *alloc_action(void)
|
||||
{
|
||||
struct action *act;
|
||||
@@ -556,11 +506,10 @@ static struct lock *alloc_lock(void)
|
||||
|
||||
static void free_action(struct action *act)
|
||||
{
|
||||
free(act->path);
|
||||
act->path = NULL;
|
||||
|
||||
free_pvs_path(&act->pvs);
|
||||
|
||||
if (act->path) {
|
||||
free(act->path);
|
||||
act->path = NULL;
|
||||
}
|
||||
pthread_mutex_lock(&unused_struct_mutex);
|
||||
if (unused_action_count >= MAX_UNUSED_ACTION) {
|
||||
free(act);
|
||||
@@ -615,12 +564,9 @@ static int setup_structs(void)
|
||||
struct lock *lk;
|
||||
int data_san = lm_data_size_sanlock();
|
||||
int data_dlm = lm_data_size_dlm();
|
||||
int data_idm = lm_data_size_idm();
|
||||
int i;
|
||||
|
||||
resource_lm_data_size = data_san > data_dlm ? data_san : data_dlm;
|
||||
resource_lm_data_size = resource_lm_data_size > data_idm ?
|
||||
resource_lm_data_size : data_idm;
|
||||
|
||||
pthread_mutex_init(&unused_struct_mutex, NULL);
|
||||
INIT_LIST_HEAD(&unused_action);
|
||||
@@ -737,8 +683,6 @@ static const char *lm_str(int x)
|
||||
return "dlm";
|
||||
case LD_LM_SANLOCK:
|
||||
return "sanlock";
|
||||
case LD_LM_IDM:
|
||||
return "idm";
|
||||
default:
|
||||
return "lm_unknown";
|
||||
}
|
||||
@@ -919,7 +863,7 @@ static void write_adopt_file(void)
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
fflush(fp);
|
||||
(void) fclose(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static int read_adopt_file(struct list_head *vg_lockd)
|
||||
@@ -928,7 +872,7 @@ static int read_adopt_file(struct list_head *vg_lockd)
|
||||
char vg_uuid[72];
|
||||
char lm_type_str[16];
|
||||
char mode[8];
|
||||
struct lockspace *ls = NULL, *ls2;
|
||||
struct lockspace *ls, *ls2;
|
||||
struct resource *r;
|
||||
FILE *fp;
|
||||
|
||||
@@ -952,20 +896,16 @@ static int read_adopt_file(struct list_head *vg_lockd)
|
||||
goto fail;
|
||||
|
||||
memset(vg_uuid, 0, sizeof(vg_uuid));
|
||||
memset(lm_type_str, 0, sizeof(lm_type_str));
|
||||
|
||||
if (sscanf(adopt_line, "VG: %63s %64s %15s %64s",
|
||||
if (sscanf(adopt_line, "VG: %63s %64s %16s %64s",
|
||||
vg_uuid, ls->vg_name, lm_type_str, ls->vg_args) != 4) {
|
||||
free(ls);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(ls->vg_uuid, vg_uuid, 64);
|
||||
|
||||
if ((ls->lm_type = str_to_lm(lm_type_str)) < 0) {
|
||||
free(ls);
|
||||
if ((ls->lm_type = str_to_lm(lm_type_str)) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
list_add(&ls->list, vg_lockd);
|
||||
|
||||
@@ -976,18 +916,14 @@ static int read_adopt_file(struct list_head *vg_lockd)
|
||||
r->type = LD_RT_LV;
|
||||
|
||||
memset(vg_uuid, 0, sizeof(vg_uuid));
|
||||
memset(mode, 0, sizeof(mode));
|
||||
|
||||
if (sscanf(adopt_line, "LV: %64s %64s %s %7s %u",
|
||||
if (sscanf(adopt_line, "LV: %64s %64s %s %8s %u",
|
||||
vg_uuid, r->name, r->lv_args, mode, &r->version) != 5) {
|
||||
free_resource(r);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((r->adopt_mode = str_to_mode(mode)) == LD_LK_IV) {
|
||||
free_resource(r);
|
||||
if ((r->adopt_mode = str_to_mode(mode)) == LD_LK_IV)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ls && !memcmp(ls->vg_uuid, vg_uuid, 64)) {
|
||||
list_add(&r->list, &ls->resources);
|
||||
@@ -1004,17 +940,16 @@ static int read_adopt_file(struct list_head *vg_lockd)
|
||||
|
||||
if (r) {
|
||||
log_error("No lockspace found for resource %s vg_uuid %s", r->name, vg_uuid);
|
||||
free_resource(r);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(void) fclose(fp);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
(void) fclose(fp);
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1031,8 +966,6 @@ static int lm_prepare_lockspace(struct lockspace *ls, struct action *act)
|
||||
rv = lm_prepare_lockspace_dlm(ls);
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
rv = lm_prepare_lockspace_sanlock(ls);
|
||||
else if (ls->lm_type == LD_LM_IDM)
|
||||
rv = lm_prepare_lockspace_idm(ls);
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -1049,8 +982,6 @@ static int lm_add_lockspace(struct lockspace *ls, struct action *act, int adopt)
|
||||
rv = lm_add_lockspace_dlm(ls, adopt);
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
rv = lm_add_lockspace_sanlock(ls, adopt);
|
||||
else if (ls->lm_type == LD_LM_IDM)
|
||||
rv = lm_add_lockspace_idm(ls, adopt);
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -1067,8 +998,6 @@ static int lm_rem_lockspace(struct lockspace *ls, struct action *act, int free_v
|
||||
rv = lm_rem_lockspace_dlm(ls, free_vg);
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
rv = lm_rem_lockspace_sanlock(ls, free_vg);
|
||||
else if (ls->lm_type == LD_LM_IDM)
|
||||
rv = lm_rem_lockspace_idm(ls, free_vg);
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -1086,9 +1015,6 @@ static int lm_lock(struct lockspace *ls, struct resource *r, int mode, struct ac
|
||||
rv = lm_lock_dlm(ls, r, mode, vb_out, adopt);
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
rv = lm_lock_sanlock(ls, r, mode, vb_out, retry, adopt);
|
||||
else if (ls->lm_type == LD_LM_IDM)
|
||||
rv = lm_lock_idm(ls, r, mode, vb_out, act->lv_uuid,
|
||||
&act->pvs, adopt);
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -1106,8 +1032,6 @@ static int lm_convert(struct lockspace *ls, struct resource *r,
|
||||
rv = lm_convert_dlm(ls, r, mode, r_version);
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
rv = lm_convert_sanlock(ls, r, mode, r_version);
|
||||
else if (ls->lm_type == LD_LM_IDM)
|
||||
rv = lm_convert_idm(ls, r, mode, r_version);
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -1125,8 +1049,6 @@ static int lm_unlock(struct lockspace *ls, struct resource *r, struct action *ac
|
||||
rv = lm_unlock_dlm(ls, r, r_version, lmu_flags);
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
rv = lm_unlock_sanlock(ls, r, r_version, lmu_flags);
|
||||
else if (ls->lm_type == LD_LM_IDM)
|
||||
rv = lm_unlock_idm(ls, r, r_version, lmu_flags);
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -1141,8 +1063,6 @@ static int lm_hosts(struct lockspace *ls, int notify)
|
||||
return lm_hosts_dlm(ls, notify);
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
return lm_hosts_sanlock(ls, notify);
|
||||
else if (ls->lm_type == LD_LM_IDM)
|
||||
return lm_hosts_idm(ls, notify);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1152,8 +1072,6 @@ static void lm_rem_resource(struct lockspace *ls, struct resource *r)
|
||||
lm_rem_resource_dlm(ls, r);
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
lm_rem_resource_sanlock(ls, r);
|
||||
else if (ls->lm_type == LD_LM_IDM)
|
||||
lm_rem_resource_idm(ls, r);
|
||||
}
|
||||
|
||||
static int lm_find_free_lock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size)
|
||||
@@ -1162,8 +1080,6 @@ static int lm_find_free_lock(struct lockspace *ls, uint64_t *free_offset, int *s
|
||||
return 0;
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
return lm_find_free_lock_sanlock(ls, free_offset, sector_size, align_size);
|
||||
else if (ls->lm_type == LD_LM_IDM)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1772,8 +1688,8 @@ static int res_update(struct lockspace *ls, struct resource *r,
|
||||
}
|
||||
|
||||
/*
|
||||
* For DLM and IDM locking scheme, there is nothing to deallocate when freeing a
|
||||
* LV, the LV will simply be unlocked by rem_resource.
|
||||
* There is nothing to deallocate when freeing a dlm LV, the LV
|
||||
* will simply be unlocked by rem_resource.
|
||||
*/
|
||||
|
||||
static int free_lv(struct lockspace *ls, struct resource *r)
|
||||
@@ -1782,8 +1698,6 @@ static int free_lv(struct lockspace *ls, struct resource *r)
|
||||
return lm_free_lv_sanlock(ls, r);
|
||||
else if (ls->lm_type == LD_LM_DLM)
|
||||
return 0;
|
||||
else if (ls->lm_type == LD_LM_IDM)
|
||||
return 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1884,7 +1798,9 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
act->result = -EINVAL;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
} else if (act->op == LD_OP_LOCK && act->mode == LD_LK_UN) {
|
||||
}
|
||||
|
||||
if (act->op == LD_OP_LOCK && act->mode == LD_LK_UN) {
|
||||
rv = res_unlock(ls, r, act);
|
||||
|
||||
if (rv == -ENOENT && (act->flags & LD_AF_UNLOCK_CANCEL))
|
||||
@@ -2764,7 +2680,7 @@ out_rem:
|
||||
|
||||
log_debug("S %s clearing locks", ls->name);
|
||||
|
||||
(void) clear_locks(ls, free_vg, drop_vg);
|
||||
rv = clear_locks(ls, free_vg, drop_vg);
|
||||
|
||||
/*
|
||||
* Tell any other hosts in the lockspace to leave it
|
||||
@@ -2842,8 +2758,6 @@ out_act:
|
||||
ls->drop_vg = drop_vg;
|
||||
if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm))
|
||||
global_dlm_lockspace_exists = 0;
|
||||
if (ls->lm_type == LD_LM_IDM && !strcmp(ls->name, gl_lsname_idm))
|
||||
global_idm_lockspace_exists = 0;
|
||||
|
||||
/*
|
||||
* Avoid a name collision of the same lockspace is added again before
|
||||
@@ -2935,8 +2849,6 @@ static void gl_ls_name(char *ls_name)
|
||||
memcpy(ls_name, gl_lsname_dlm, MAX_NAME);
|
||||
else if (gl_use_sanlock)
|
||||
memcpy(ls_name, gl_lsname_sanlock, MAX_NAME);
|
||||
else if (gl_use_idm)
|
||||
memcpy(ls_name, gl_lsname_idm, MAX_NAME);
|
||||
else
|
||||
memset(ls_name, 0, MAX_NAME);
|
||||
}
|
||||
@@ -2965,22 +2877,10 @@ static int add_lockspace_thread(const char *ls_name,
|
||||
strncpy(ls->name, ls_name, MAX_NAME);
|
||||
ls->lm_type = lm_type;
|
||||
|
||||
if (act) {
|
||||
if (act)
|
||||
ls->start_client_id = act->client_id;
|
||||
|
||||
/*
|
||||
* Copy PV list to lockspact structure, so this is
|
||||
* used for VG locking for idm scheme.
|
||||
*/
|
||||
if (lm_type == LD_LM_IDM &&
|
||||
!alloc_and_copy_pvs_path(&ls->pvs, &act->pvs)) {
|
||||
free(ls);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (vg_uuid)
|
||||
/* coverity[buffer_size_warning] */
|
||||
strncpy(ls->vg_uuid, vg_uuid, 64);
|
||||
|
||||
if (vg_name)
|
||||
@@ -3006,17 +2906,7 @@ static int add_lockspace_thread(const char *ls_name,
|
||||
pthread_mutex_lock(&lockspaces_mutex);
|
||||
ls2 = find_lockspace_name(ls->name);
|
||||
if (ls2) {
|
||||
/*
|
||||
* If find an existed lockspace, we need to update the PV list
|
||||
* based on the latest information, and release for the old
|
||||
* PV list in case it keeps stale information.
|
||||
*/
|
||||
free_pvs_path(&ls2->pvs);
|
||||
if (lm_type == LD_LM_IDM &&
|
||||
!alloc_and_copy_pvs_path(&ls2->pvs, &ls->pvs)) {
|
||||
log_debug("add_lockspace_thread %s fails to allocate pvs", ls->name);
|
||||
rv = -ENOMEM;
|
||||
} else if (ls2->thread_stop) {
|
||||
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) {
|
||||
@@ -3028,7 +2918,6 @@ static int add_lockspace_thread(const char *ls_name,
|
||||
}
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
free_resource(r);
|
||||
free_pvs_path(&ls->pvs);
|
||||
free(ls);
|
||||
return rv;
|
||||
}
|
||||
@@ -3042,8 +2931,6 @@ static int add_lockspace_thread(const char *ls_name,
|
||||
|
||||
if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm))
|
||||
global_dlm_lockspace_exists = 1;
|
||||
if (ls->lm_type == LD_LM_IDM && !strcmp(ls->name, gl_lsname_idm))
|
||||
global_idm_lockspace_exists = 1;
|
||||
list_add_tail(&ls->list, &lockspaces);
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
@@ -3054,7 +2941,6 @@ static int add_lockspace_thread(const char *ls_name,
|
||||
list_del(&ls->list);
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
free_resource(r);
|
||||
free_pvs_path(&ls->pvs);
|
||||
free(ls);
|
||||
return rv;
|
||||
}
|
||||
@@ -3063,15 +2949,16 @@ static int add_lockspace_thread(const char *ls_name,
|
||||
}
|
||||
|
||||
/*
|
||||
* There is no variant for sanlock because, with sanlock, the global
|
||||
* lockspace is one of the vg lockspaces.
|
||||
* There is no add_sanlock_global_lockspace or
|
||||
* rem_sanlock_global_lockspace because with sanlock,
|
||||
* the global lockspace is one of the vg lockspaces.
|
||||
*/
|
||||
static int add_global_lockspace(char *ls_name, int lm_type,
|
||||
struct action *act)
|
||||
|
||||
static int add_dlm_global_lockspace(struct action *act)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (global_dlm_lockspace_exists || global_idm_lockspace_exists)
|
||||
if (global_dlm_lockspace_exists)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@@ -3079,9 +2966,9 @@ static int add_global_lockspace(char *ls_name, int lm_type,
|
||||
* lock request, insert an internal gl sh lock request?
|
||||
*/
|
||||
|
||||
rv = add_lockspace_thread(ls_name, NULL, NULL, lm_type, NULL, act);
|
||||
rv = add_lockspace_thread(gl_lsname_dlm, NULL, NULL, LD_LM_DLM, NULL, act);
|
||||
if (rv < 0)
|
||||
log_debug("add_global_lockspace add_lockspace_thread %d", rv);
|
||||
log_debug("add_dlm_global_lockspace add_lockspace_thread %d", rv);
|
||||
|
||||
/*
|
||||
* EAGAIN may be returned for a short period because
|
||||
@@ -3094,12 +2981,12 @@ static int add_global_lockspace(char *ls_name, int lm_type,
|
||||
}
|
||||
|
||||
/*
|
||||
* When DLM or IDM locking scheme is used for global lock, if the global
|
||||
* lockspace is the only one left, then stop it. This is not used for
|
||||
* an explicit rem_lockspace action from the client, only for auto
|
||||
* remove.
|
||||
* If dlm gl lockspace is the only one left, then stop it.
|
||||
* This is not used for an explicit rem_lockspace action from
|
||||
* the client, only for auto remove.
|
||||
*/
|
||||
static int rem_global_lockspace(char *ls_name)
|
||||
|
||||
static int rem_dlm_global_lockspace(void)
|
||||
{
|
||||
struct lockspace *ls, *ls_gl = NULL;
|
||||
int others = 0;
|
||||
@@ -3107,7 +2994,7 @@ static int rem_global_lockspace(char *ls_name)
|
||||
|
||||
pthread_mutex_lock(&lockspaces_mutex);
|
||||
list_for_each_entry(ls, &lockspaces, list) {
|
||||
if (!strcmp(ls->name, ls_name)) {
|
||||
if (!strcmp(ls->name, gl_lsname_dlm)) {
|
||||
ls_gl = ls;
|
||||
continue;
|
||||
}
|
||||
@@ -3139,26 +3026,6 @@ out:
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int add_dlm_global_lockspace(struct action *act)
|
||||
{
|
||||
return add_global_lockspace(gl_lsname_dlm, LD_LM_DLM, act);
|
||||
}
|
||||
|
||||
static int rem_dlm_global_lockspace(void)
|
||||
{
|
||||
return rem_global_lockspace(gl_lsname_dlm);
|
||||
}
|
||||
|
||||
static int add_idm_global_lockspace(struct action *act)
|
||||
{
|
||||
return add_global_lockspace(gl_lsname_idm, LD_LM_IDM, act);
|
||||
}
|
||||
|
||||
static int rem_idm_global_lockspace(void)
|
||||
{
|
||||
return rem_global_lockspace(gl_lsname_idm);
|
||||
}
|
||||
|
||||
/*
|
||||
* When the first dlm lockspace is added for a vg, automatically add a separate
|
||||
* dlm lockspace for the global lock.
|
||||
@@ -3184,9 +3051,6 @@ static int add_lockspace(struct action *act)
|
||||
if (gl_use_dlm) {
|
||||
rv = add_dlm_global_lockspace(act);
|
||||
return rv;
|
||||
} else if (gl_use_idm) {
|
||||
rv = add_idm_global_lockspace(act);
|
||||
return rv;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -3195,8 +3059,6 @@ static int add_lockspace(struct action *act)
|
||||
if (act->rt == LD_RT_VG) {
|
||||
if (gl_use_dlm)
|
||||
add_dlm_global_lockspace(NULL);
|
||||
else if (gl_use_idm)
|
||||
add_idm_global_lockspace(NULL);
|
||||
|
||||
vg_ls_name(act->vg_name, ls_name);
|
||||
|
||||
@@ -3264,15 +3126,14 @@ static int rem_lockspace(struct action *act)
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
/*
|
||||
* For DLM and IDM locking scheme, the global lockspace was
|
||||
* automatically added when the first vg lockspace was added,
|
||||
* now reverse that by automatically removing the dlm global
|
||||
* lockspace when the last vg lockspace is removed.
|
||||
* The dlm global lockspace was automatically added when
|
||||
* the first dlm vg lockspace was added, now reverse that
|
||||
* by automatically removing the dlm global lockspace when
|
||||
* the last dlm vg lockspace is removed.
|
||||
*/
|
||||
|
||||
if (rt == LD_RT_VG && gl_use_dlm)
|
||||
rem_dlm_global_lockspace();
|
||||
else if (rt == LD_RT_VG && gl_use_idm)
|
||||
rem_idm_global_lockspace();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3396,7 +3257,6 @@ static int for_each_lockspace(int do_stop, int do_free, int do_force)
|
||||
if (ls->free_vg) {
|
||||
/* In future we may need to free ls->actions here */
|
||||
free_ls_resources(ls);
|
||||
free_pvs_path(&ls->pvs);
|
||||
free(ls);
|
||||
free_count++;
|
||||
}
|
||||
@@ -3410,7 +3270,6 @@ static int for_each_lockspace(int do_stop, int do_free, int do_force)
|
||||
if (!gl_type_static) {
|
||||
gl_use_dlm = 0;
|
||||
gl_use_sanlock = 0;
|
||||
gl_use_idm = 0;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
@@ -3486,9 +3345,6 @@ static int work_init_vg(struct action *act)
|
||||
rv = lm_init_vg_sanlock(ls_name, act->vg_name, act->flags, act->vg_args);
|
||||
else if (act->lm_type == LD_LM_DLM)
|
||||
rv = lm_init_vg_dlm(ls_name, act->vg_name, act->flags, act->vg_args);
|
||||
else if (act->lm_type == LD_LM_IDM)
|
||||
/* Non't do anything for IDM when initialize VG */
|
||||
rv = 0;
|
||||
else
|
||||
rv = -EINVAL;
|
||||
|
||||
@@ -3592,8 +3448,6 @@ static int work_init_lv(struct action *act)
|
||||
|
||||
} else if (act->lm_type == LD_LM_DLM) {
|
||||
return 0;
|
||||
} else if (act->lm_type == LD_LM_IDM) {
|
||||
return 0;
|
||||
} else {
|
||||
log_error("init_lv ls_name %s bad lm_type %d", ls_name, act->lm_type);
|
||||
return -EINVAL;
|
||||
@@ -3657,29 +3511,20 @@ static void *worker_thread_main(void *arg_in)
|
||||
if (act->op == LD_OP_RUNNING_LM) {
|
||||
int run_sanlock = lm_is_running_sanlock();
|
||||
int run_dlm = lm_is_running_dlm();
|
||||
int run_idm = lm_is_running_idm();
|
||||
|
||||
if (daemon_test) {
|
||||
run_sanlock = gl_use_sanlock;
|
||||
run_dlm = gl_use_dlm;
|
||||
run_idm = gl_use_idm;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's not possible to enable multiple locking schemes
|
||||
* for global lock, otherwise, it must be conflict and
|
||||
* reports it!
|
||||
*/
|
||||
if ((run_sanlock + run_dlm + run_idm) >= 2)
|
||||
if (run_sanlock && run_dlm)
|
||||
act->result = -EXFULL;
|
||||
else if (!run_sanlock && !run_dlm && !run_idm)
|
||||
else if (!run_sanlock && !run_dlm)
|
||||
act->result = -ENOLCK;
|
||||
else if (run_sanlock)
|
||||
act->result = LD_LM_SANLOCK;
|
||||
else if (run_dlm)
|
||||
act->result = LD_LM_DLM;
|
||||
else if (run_idm)
|
||||
act->result = LD_LM_IDM;
|
||||
add_client_result(act);
|
||||
|
||||
} else if ((act->op == LD_OP_LOCK) && (act->flags & LD_AF_SEARCH_LS)) {
|
||||
@@ -3967,9 +3812,6 @@ static int client_send_result(struct client *cl, struct action *act)
|
||||
} else if (gl_use_dlm) {
|
||||
if (!gl_lsname_dlm[0])
|
||||
strcat(result_flags, "NO_GL_LS,");
|
||||
} else if (gl_use_idm) {
|
||||
if (!gl_lsname_idm[0])
|
||||
strcat(result_flags, "NO_GL_LS,");
|
||||
} else {
|
||||
int found_lm = 0;
|
||||
|
||||
@@ -3977,8 +3819,6 @@ static int client_send_result(struct client *cl, struct action *act)
|
||||
found_lm++;
|
||||
if (lm_support_sanlock() && lm_is_running_sanlock())
|
||||
found_lm++;
|
||||
if (lm_support_idm() && lm_is_running_idm())
|
||||
found_lm++;
|
||||
|
||||
if (!found_lm)
|
||||
strcat(result_flags, "NO_GL_LS,NO_LM");
|
||||
@@ -4154,13 +3994,11 @@ static int add_lock_action(struct action *act)
|
||||
if (gl_use_sanlock && (act->op == LD_OP_ENABLE || act->op == LD_OP_DISABLE)) {
|
||||
vg_ls_name(act->vg_name, ls_name);
|
||||
} else {
|
||||
if (!gl_use_dlm && !gl_use_sanlock && !gl_use_idm) {
|
||||
if (!gl_use_dlm && !gl_use_sanlock) {
|
||||
if (lm_is_running_dlm())
|
||||
gl_use_dlm = 1;
|
||||
else if (lm_is_running_sanlock())
|
||||
gl_use_sanlock = 1;
|
||||
else if (lm_is_running_idm())
|
||||
gl_use_idm = 1;
|
||||
}
|
||||
gl_ls_name(ls_name);
|
||||
}
|
||||
@@ -4208,17 +4046,6 @@ static int add_lock_action(struct action *act)
|
||||
add_dlm_global_lockspace(NULL);
|
||||
goto retry;
|
||||
|
||||
} else if (act->op == LD_OP_LOCK && act->rt == LD_RT_GL && act->mode != LD_LK_UN && gl_use_idm) {
|
||||
/*
|
||||
* Automatically start the idm global lockspace when
|
||||
* a command tries to acquire the global lock.
|
||||
*/
|
||||
log_debug("lockspace \"%s\" not found for idm gl, adding...", ls_name);
|
||||
act->flags |= LD_AF_SEARCH_LS;
|
||||
act->flags |= LD_AF_WAIT_STARTING;
|
||||
add_idm_global_lockspace(NULL);
|
||||
goto retry;
|
||||
|
||||
} else if (act->op == LD_OP_LOCK && act->mode == LD_LK_UN) {
|
||||
log_debug("lockspace \"%s\" not found for unlock ignored", ls_name);
|
||||
return -ENOLS;
|
||||
@@ -4439,8 +4266,6 @@ static int str_to_lm(const char *str)
|
||||
return LD_LM_SANLOCK;
|
||||
if (!strcmp(str, "dlm"))
|
||||
return LD_LM_DLM;
|
||||
if (!strcmp(str, "idm"))
|
||||
return LD_LM_IDM;
|
||||
return -2;
|
||||
}
|
||||
|
||||
@@ -4776,14 +4601,12 @@ static void client_recv_action(struct client *cl)
|
||||
const char *vg_sysid;
|
||||
const char *path;
|
||||
const char *str;
|
||||
struct pvs pvs;
|
||||
char buf[18]; /* "path[%d]\0", %d outputs signed integer so max to 10 bytes */
|
||||
int64_t val;
|
||||
uint32_t opts = 0;
|
||||
int result = 0;
|
||||
int cl_pid;
|
||||
int op, rt, lm, mode;
|
||||
int rv, i;
|
||||
int rv;
|
||||
|
||||
buffer_init(&req.buffer);
|
||||
|
||||
@@ -4872,13 +4695,11 @@ static void client_recv_action(struct client *cl)
|
||||
if (!cl->name[0] && cl_name)
|
||||
strncpy(cl->name, cl_name, MAX_NAME);
|
||||
|
||||
if (!gl_use_dlm && !gl_use_sanlock && !gl_use_idm && (lm > 0)) {
|
||||
if (!gl_use_dlm && !gl_use_sanlock && (lm > 0)) {
|
||||
if (lm == LD_LM_DLM && lm_support_dlm())
|
||||
gl_use_dlm = 1;
|
||||
else if (lm == LD_LM_SANLOCK && lm_support_sanlock())
|
||||
gl_use_sanlock = 1;
|
||||
else if (lm == LD_LM_IDM && lm_support_idm())
|
||||
gl_use_idm = 1;
|
||||
|
||||
log_debug("set gl_use_%s", lm_str(lm));
|
||||
}
|
||||
@@ -4935,40 +4756,6 @@ static void client_recv_action(struct client *cl)
|
||||
if (val)
|
||||
act->host_id = val;
|
||||
|
||||
/* Create PV list for idm */
|
||||
if (lm == LD_LM_IDM) {
|
||||
memset(&pvs, 0x0, sizeof(pvs));
|
||||
|
||||
pvs.num = daemon_request_int(req, "path_num", 0);
|
||||
log_error("pvs_num = %d", pvs.num);
|
||||
|
||||
if (!pvs.num)
|
||||
goto skip_pvs_path;
|
||||
|
||||
/* Receive the pv list which is transferred from LVM command */
|
||||
if (!alloc_pvs_path(&pvs, pvs.num)) {
|
||||
log_error("fail to allocate pvs path");
|
||||
rv = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < pvs.num; i++) {
|
||||
snprintf(buf, sizeof(buf), "path[%d]", i);
|
||||
pvs.path[i] = (char *)daemon_request_str(req, buf, NULL);
|
||||
}
|
||||
|
||||
if (!alloc_and_copy_pvs_path(&act->pvs, &pvs)) {
|
||||
log_error("fail to allocate pvs path");
|
||||
rv = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pvs.path)
|
||||
free(pvs.path);
|
||||
pvs.path = NULL;
|
||||
}
|
||||
|
||||
skip_pvs_path:
|
||||
act->max_retries = daemon_request_int(req, "max_retries", DEFAULT_MAX_RETRIES);
|
||||
|
||||
dm_config_destroy(req.cft);
|
||||
@@ -4990,12 +4777,6 @@ skip_pvs_path:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lm == LD_LM_IDM && !lm_support_idm()) {
|
||||
log_debug("idm not supported");
|
||||
rv = -EPROTONOSUPPORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (act->op == LD_OP_LOCK && act->mode != LD_LK_UN)
|
||||
cl->lock_ops = 1;
|
||||
|
||||
@@ -5185,7 +4966,7 @@ static void *client_thread_main(void *arg_in)
|
||||
}
|
||||
out:
|
||||
if (adopt_opt && lock_acquire_written)
|
||||
(void) unlink(adopt_file);
|
||||
unlink(adopt_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5594,7 +5375,6 @@ static void adopt_locks(void)
|
||||
}
|
||||
|
||||
list_del(&ls->list);
|
||||
free_pvs_path(&ls->pvs);
|
||||
free(ls);
|
||||
}
|
||||
|
||||
@@ -5635,7 +5415,6 @@ static void adopt_locks(void)
|
||||
if (rv < 0) {
|
||||
log_error("Failed to create lockspace thread for VG %s", ls->vg_name);
|
||||
list_del(&ls->list);
|
||||
free_pvs_path(&ls->pvs);
|
||||
free(ls);
|
||||
free_action(act);
|
||||
count_start_fail++;
|
||||
@@ -5954,29 +5733,18 @@ static void adopt_locks(void)
|
||||
}
|
||||
|
||||
|
||||
/* Try to purge the orphan locks when lock manager is dlm */
|
||||
if (lm_support_dlm() && lm_is_running_dlm()) {
|
||||
list_for_each_entry(ls, &ls_found, list) {
|
||||
pthread_mutex_lock(&lockspaces_mutex);
|
||||
ls1 = find_lockspace_name(ls->name);
|
||||
if (ls1) {
|
||||
log_debug("ls: %s purge locks", ls->name);
|
||||
lm_purge_locks_dlm(ls1);
|
||||
}
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
}
|
||||
}
|
||||
/* FIXME: purge any remaining orphan locks in each rejoined ls? */
|
||||
|
||||
if (count_start_fail || count_adopt_fail)
|
||||
goto fail;
|
||||
|
||||
(void) unlink(adopt_file);
|
||||
unlink(adopt_file);
|
||||
write_adopt_file();
|
||||
log_debug("adopt_locks done");
|
||||
return;
|
||||
|
||||
fail:
|
||||
(void) unlink(adopt_file);
|
||||
unlink(adopt_file);
|
||||
log_error("adopt_locks failed, reset host");
|
||||
}
|
||||
|
||||
@@ -6089,7 +5857,6 @@ static int main_loop(daemon_state *ds_arg)
|
||||
}
|
||||
|
||||
strcpy(gl_lsname_dlm, S_NAME_GL_DLM);
|
||||
strcpy(gl_lsname_idm, S_NAME_GL_IDM);
|
||||
|
||||
INIT_LIST_HEAD(&lockspaces);
|
||||
pthread_mutex_init(&lockspaces_mutex, NULL);
|
||||
@@ -6280,7 +6047,6 @@ int main(int argc, char *argv[])
|
||||
.daemon_fini = NULL,
|
||||
.daemon_main = main_loop,
|
||||
};
|
||||
daemon_host_id_file = NULL;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"help", no_argument, 0, 'h' },
|
||||
@@ -6314,7 +6080,6 @@ int main(int argc, char *argv[])
|
||||
case '0':
|
||||
break;
|
||||
case 128:
|
||||
free((void *) adopt_file);
|
||||
adopt_file = strdup(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
@@ -6334,11 +6099,9 @@ int main(int argc, char *argv[])
|
||||
daemon_debug = 1;
|
||||
break;
|
||||
case 'p':
|
||||
free((void*)ds.pidfile);
|
||||
ds.pidfile = strdup(optarg);
|
||||
break;
|
||||
case 's':
|
||||
free((void*)ds.socket_path);
|
||||
ds.socket_path = strdup(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
@@ -6347,8 +6110,6 @@ int main(int argc, char *argv[])
|
||||
gl_use_dlm = 1;
|
||||
else if (lm == LD_LM_SANLOCK && lm_support_sanlock())
|
||||
gl_use_sanlock = 1;
|
||||
else if (lm == LD_LM_IDM && lm_support_idm())
|
||||
gl_use_idm = 1;
|
||||
else {
|
||||
fprintf(stderr, "invalid gl-type option\n");
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -6358,7 +6119,6 @@ int main(int argc, char *argv[])
|
||||
daemon_host_id = atoi(optarg);
|
||||
break;
|
||||
case 'F':
|
||||
free((void*)daemon_host_id_file);
|
||||
daemon_host_id_file = strdup(optarg);
|
||||
break;
|
||||
case 'o':
|
||||
|
||||
@@ -119,7 +119,6 @@ static int read_cluster_name(char *clustername)
|
||||
log_error(close_error_msg, fd);
|
||||
return rv;
|
||||
}
|
||||
clustername[rv] = 0;
|
||||
|
||||
n = strstr(clustername, "\n");
|
||||
if (n)
|
||||
@@ -220,86 +219,6 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DLM_COMMS_PATH "/sys/kernel/config/dlm/cluster/comms"
|
||||
#define LOCK_LINE_MAX 1024
|
||||
static int get_local_nodeid(void)
|
||||
{
|
||||
struct dirent *de;
|
||||
DIR *ls_dir;
|
||||
char ls_comms_path[PATH_MAX];
|
||||
FILE *file = NULL;
|
||||
char line[LOCK_LINE_MAX];
|
||||
int rv = -1, val;
|
||||
|
||||
memset(ls_comms_path, 0, sizeof(ls_comms_path));
|
||||
snprintf(ls_comms_path, PATH_MAX, "%s",DLM_COMMS_PATH);
|
||||
|
||||
if (!(ls_dir = opendir(ls_comms_path)))
|
||||
return -ECONNREFUSED;
|
||||
|
||||
while ((de = readdir(ls_dir))) {
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
memset(ls_comms_path, 0, sizeof(ls_comms_path));
|
||||
snprintf(ls_comms_path, PATH_MAX, "%s/%s/local",
|
||||
DLM_COMMS_PATH, de->d_name);
|
||||
file = fopen(ls_comms_path, "r");
|
||||
if (!file)
|
||||
continue;
|
||||
if (fgets(line, LOCK_LINE_MAX, file)) {
|
||||
fclose(file);
|
||||
rv = sscanf(line, "%d", &val);
|
||||
if ((rv == 1) && (val == 1 )) {
|
||||
memset(ls_comms_path, 0, sizeof(ls_comms_path));
|
||||
snprintf(ls_comms_path, PATH_MAX, "%s/%s/nodeid",
|
||||
DLM_COMMS_PATH, de->d_name);
|
||||
file = fopen(ls_comms_path, "r");
|
||||
if (!file)
|
||||
continue;
|
||||
if (fgets(line, LOCK_LINE_MAX, file)) {
|
||||
rv = sscanf(line, "%d", &val);
|
||||
if (rv == 1) {
|
||||
fclose(file);
|
||||
closedir(ls_dir);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
if (closedir(ls_dir))
|
||||
log_error("get_local_nodeid closedir error");
|
||||
return rv;
|
||||
}
|
||||
|
||||
int lm_purge_locks_dlm(struct lockspace *ls)
|
||||
{
|
||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||
int nodeid;
|
||||
int rv = -1;
|
||||
|
||||
if (!lmd || !lmd->dh) {
|
||||
log_error("purge_locks_dlm %s no dlm_handle_t error", ls->name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nodeid = get_local_nodeid();
|
||||
if (nodeid < 0) {
|
||||
log_error("failed to get local nodeid");
|
||||
goto fail;
|
||||
}
|
||||
if (dlm_ls_purge(lmd->dh, nodeid, 0)) {
|
||||
log_error("purge_locks_dlm %s error", ls->name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rv = 0;
|
||||
fail:
|
||||
return rv;
|
||||
}
|
||||
|
||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
|
||||
{
|
||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||
@@ -408,7 +327,8 @@ int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
|
||||
log_error("S %s R %s rem_resource_dlm unlock error %d", ls->name, r->name, rv);
|
||||
}
|
||||
out:
|
||||
free(rdd->vb);
|
||||
if (rdd->vb)
|
||||
free(rdd->vb);
|
||||
|
||||
memset(rdd, 0, sizeof(struct rd_dlm));
|
||||
r->lm_init = 0;
|
||||
@@ -871,18 +791,17 @@ int lm_is_running_dlm(void)
|
||||
|
||||
int lm_refresh_lv_start_dlm(struct action *act)
|
||||
{
|
||||
char path[PATH_MAX] = { 0 };
|
||||
char path[PATH_MAX];
|
||||
char command[DLMC_RUN_COMMAND_LEN];
|
||||
char run_uuid[DLMC_RUN_UUID_LEN];
|
||||
char *p, *vgname, *lvname;
|
||||
int rv;
|
||||
|
||||
/* split /dev/vgname/lvname into vgname and lvname strings */
|
||||
strncpy(path, act->path, PATH_MAX-1);
|
||||
strncpy(path, act->path, strlen(act->path));
|
||||
|
||||
/* skip past dev */
|
||||
if (!(p = strchr(path + 1, '/')))
|
||||
return -EINVAL;
|
||||
p = strchr(path + 1, '/');
|
||||
|
||||
/* skip past slashes */
|
||||
while (*p == '/')
|
||||
|
||||
@@ -1,837 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Seagate Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 500 /* pthread */
|
||||
#define _ISOC99_SOURCE
|
||||
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "daemon-server.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
|
||||
#include "lvmlockd-internal.h"
|
||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
||||
|
||||
#include "ilm.h"
|
||||
|
||||
#include <blkid/blkid.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <regex.h>
|
||||
#include <stddef.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <time.h>
|
||||
|
||||
#define IDM_TIMEOUT 60000 /* unit: millisecond, 60 seconds */
|
||||
|
||||
/*
|
||||
* Each lockspace thread has its own In-Drive Mutex (IDM) lock manager's
|
||||
* connection. After established socket connection, the lockspace has
|
||||
* been created in IDM lock manager and afterwards use the socket file
|
||||
* descriptor to send any requests for lock related operations.
|
||||
*/
|
||||
|
||||
struct lm_idm {
|
||||
int sock; /* IDM lock manager connection */
|
||||
};
|
||||
|
||||
struct rd_idm {
|
||||
struct idm_lock_id id;
|
||||
struct idm_lock_op op;
|
||||
uint64_t vb_timestamp;
|
||||
struct val_blk *vb;
|
||||
};
|
||||
|
||||
int lm_data_size_idm(void)
|
||||
{
|
||||
return sizeof(struct rd_idm);
|
||||
}
|
||||
|
||||
static uint64_t read_utc_us(void)
|
||||
{
|
||||
struct timespec cur_time;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &cur_time);
|
||||
|
||||
/*
|
||||
* Convert to microseconds unit. IDM reserves the MSB in 8 bytes
|
||||
* and the low 56 bits are used for timestamp; 56 bits can support
|
||||
* calendar year to 2284, so it has 260 years for overflow. Thus it
|
||||
* is quite safe for overflow issue when wrote this code.
|
||||
*/
|
||||
return cur_time.tv_sec * 1000000 + cur_time.tv_nsec / 1000;
|
||||
}
|
||||
|
||||
static int uuid_read_format(char *uuid_str, const char *buffer)
|
||||
{
|
||||
int out = 0;
|
||||
|
||||
/* just strip out any dashes */
|
||||
while (*buffer) {
|
||||
|
||||
if (*buffer == '-') {
|
||||
buffer++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (out >= 32) {
|
||||
log_error("Too many characters to be uuid.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uuid_str[out++] = *buffer;
|
||||
buffer++;
|
||||
}
|
||||
|
||||
if (out != 32) {
|
||||
log_error("Couldn't read uuid: incorrect number of "
|
||||
"characters.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SYSFS_ROOT "/sys"
|
||||
#define BUS_SCSI_DEVS "/bus/scsi/devices"
|
||||
|
||||
static struct idm_lock_op glb_lock_op;
|
||||
|
||||
static void lm_idm_free_dir_list(struct dirent **dir_list, int dir_num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dir_num; ++i)
|
||||
free(dir_list[i]);
|
||||
free(dir_list);
|
||||
}
|
||||
|
||||
static int lm_idm_scsi_directory_select(const struct dirent *s)
|
||||
{
|
||||
regex_t regex;
|
||||
int ret;
|
||||
|
||||
/* Only select directory with the format x:x:x:x */
|
||||
ret = regcomp(®ex, "^[0-9]+:[0-9]+:[0-9]+:[0-9]+$", REG_EXTENDED);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
ret = regexec(®ex, s->d_name, 0, NULL, 0);
|
||||
if (!ret) {
|
||||
regfree(®ex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
regfree(®ex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm_idm_scsi_find_block_dirctory(const char *block_path)
|
||||
{
|
||||
struct stat stats;
|
||||
|
||||
if ((stat(block_path, &stats) >= 0) && S_ISDIR(stats.st_mode))
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int lm_idm_scsi_block_node_select(const struct dirent *s)
|
||||
{
|
||||
if (DT_LNK != s->d_type && DT_DIR != s->d_type)
|
||||
return 0;
|
||||
|
||||
if (DT_DIR == s->d_type) {
|
||||
/* Skip this directory: '.' and parent: '..' */
|
||||
if (!strcmp(s->d_name, ".") || !strcmp(s->d_name, ".."))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lm_idm_scsi_find_block_node(const char *blk_path, char **blk_dev)
|
||||
{
|
||||
struct dirent **dir_list;
|
||||
int dir_num;
|
||||
|
||||
dir_num = scandir(blk_path, &dir_list, lm_idm_scsi_block_node_select, NULL);
|
||||
if (dir_num < 0) {
|
||||
log_error("Cannot find valid directory entry in %s", blk_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should have only one block name under the path, if the dir_num is
|
||||
* not 1 (e.g. 0 or any number bigger than 1), it must be wrong and
|
||||
* should never happen.
|
||||
*/
|
||||
if (dir_num == 1)
|
||||
*blk_dev = strdup(dir_list[0]->d_name);
|
||||
else
|
||||
*blk_dev = NULL;
|
||||
|
||||
lm_idm_free_dir_list(dir_list, dir_num);
|
||||
|
||||
if (!*blk_dev)
|
||||
return -1;
|
||||
|
||||
return dir_num;
|
||||
}
|
||||
|
||||
static int lm_idm_scsi_search_propeller_partition(char *dev)
|
||||
{
|
||||
int i, nparts;
|
||||
blkid_probe pr;
|
||||
blkid_partlist ls;
|
||||
int found = -1;
|
||||
|
||||
pr = blkid_new_probe_from_filename(dev);
|
||||
if (!pr) {
|
||||
log_error("%s: failed to create a new libblkid probe", dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Binary interface */
|
||||
ls = blkid_probe_get_partitions(pr);
|
||||
if (!ls) {
|
||||
log_error("%s: failed to read partitions", dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* List partitions */
|
||||
nparts = blkid_partlist_numof_partitions(ls);
|
||||
if (!nparts)
|
||||
goto done;
|
||||
|
||||
for (i = 0; i < nparts; i++) {
|
||||
const char *p;
|
||||
blkid_partition par = blkid_partlist_get_partition(ls, i);
|
||||
|
||||
p = blkid_partition_get_name(par);
|
||||
if (p) {
|
||||
log_debug("partition name='%s'", p);
|
||||
|
||||
if (!strcmp(p, "propeller"))
|
||||
found = blkid_partition_get_partno(par);
|
||||
}
|
||||
|
||||
if (found >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
blkid_free_probe(pr);
|
||||
return found;
|
||||
}
|
||||
|
||||
static char *lm_idm_scsi_get_block_device_node(const char *scsi_path)
|
||||
{
|
||||
char *blk_path = NULL;
|
||||
char *blk_dev = NULL;
|
||||
char *dev_node = NULL;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Locate the "block" directory, such like:
|
||||
* /sys/bus/scsi/devices/1:0:0:0/block
|
||||
*/
|
||||
ret = asprintf(&blk_path, "%s/%s", scsi_path, "block");
|
||||
if (ret < 0) {
|
||||
log_error("Fail to allocate block path for %s", scsi_path);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = lm_idm_scsi_find_block_dirctory(blk_path);
|
||||
if (ret < 0) {
|
||||
log_error("Fail to find block path %s", blk_path);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate the block device name, such like:
|
||||
* /sys/bus/scsi/devices/1:0:0:0/block/sdb
|
||||
*
|
||||
* After return from this function and if it makes success,
|
||||
* the global variable "blk_dev" points to the block device
|
||||
* name, in this example it points to string "sdb".
|
||||
*/
|
||||
ret = lm_idm_scsi_find_block_node(blk_path, &blk_dev);
|
||||
if (ret < 0) {
|
||||
log_error("Fail to find block node");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = asprintf(&dev_node, "/dev/%s", blk_dev);
|
||||
if (ret < 0) {
|
||||
log_error("Fail to allocate memory for blk node path");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = lm_idm_scsi_search_propeller_partition(dev_node);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
free(blk_path);
|
||||
free(blk_dev);
|
||||
return dev_node;
|
||||
|
||||
fail:
|
||||
free(blk_path);
|
||||
free(blk_dev);
|
||||
free(dev_node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int lm_idm_get_gl_lock_pv_list(void)
|
||||
{
|
||||
struct dirent **dir_list;
|
||||
char scsi_bus_path[PATH_MAX];
|
||||
char *drive_path;
|
||||
int i, dir_num, ret;
|
||||
|
||||
if (glb_lock_op.drive_num)
|
||||
return 0;
|
||||
|
||||
snprintf(scsi_bus_path, sizeof(scsi_bus_path), "%s%s",
|
||||
SYSFS_ROOT, BUS_SCSI_DEVS);
|
||||
|
||||
dir_num = scandir(scsi_bus_path, &dir_list,
|
||||
lm_idm_scsi_directory_select, NULL);
|
||||
if (dir_num < 0) { /* scsi mid level may not be loaded */
|
||||
log_error("Attached devices: none");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < dir_num; i++) {
|
||||
char *scsi_path;
|
||||
|
||||
ret = asprintf(&scsi_path, "%s/%s", scsi_bus_path,
|
||||
dir_list[i]->d_name);
|
||||
if (ret < 0) {
|
||||
log_error("Fail to allocate memory for scsi directory");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (glb_lock_op.drive_num >= ILM_DRIVE_MAX_NUM) {
|
||||
log_error("Global lock: drive number %d exceeds limitation (%d) ?!",
|
||||
glb_lock_op.drive_num, ILM_DRIVE_MAX_NUM);
|
||||
free(scsi_path);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
drive_path = lm_idm_scsi_get_block_device_node(scsi_path);
|
||||
if (!drive_path) {
|
||||
free(scsi_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
glb_lock_op.drives[glb_lock_op.drive_num] = drive_path;
|
||||
glb_lock_op.drive_num++;
|
||||
|
||||
free(scsi_path);
|
||||
}
|
||||
|
||||
lm_idm_free_dir_list(dir_list, dir_num);
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
lm_idm_free_dir_list(dir_list, dir_num);
|
||||
|
||||
for (i = 0; i < glb_lock_op.drive_num; i++) {
|
||||
if (glb_lock_op.drives[i]) {
|
||||
free(glb_lock_op.drives[i]);
|
||||
glb_lock_op.drives[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void lm_idm_update_vb_timestamp(uint64_t *vb_timestamp)
|
||||
{
|
||||
uint64_t utc_us = read_utc_us();
|
||||
|
||||
/*
|
||||
* It's possible that the multiple nodes have no clock
|
||||
* synchronization with microsecond prcision and the time
|
||||
* is going backward. For this case, simply increment the
|
||||
* existing timestamp and write out to drive.
|
||||
*/
|
||||
if (*vb_timestamp >= utc_us)
|
||||
(*vb_timestamp)++;
|
||||
else
|
||||
*vb_timestamp = utc_us;
|
||||
}
|
||||
|
||||
int lm_prepare_lockspace_idm(struct lockspace *ls)
|
||||
{
|
||||
struct lm_idm *lm = NULL;
|
||||
|
||||
lm = malloc(sizeof(struct lm_idm));
|
||||
if (!lm) {
|
||||
log_error("S %s prepare_lockspace_idm fail to allocate lm_idm for %s",
|
||||
ls->name, ls->vg_name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(lm, 0x0, sizeof(struct lm_idm));
|
||||
|
||||
ls->lm_data = lm;
|
||||
log_debug("S %s prepare_lockspace_idm done", ls->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt)
|
||||
{
|
||||
char killpath[IDM_FAILURE_PATH_LEN];
|
||||
char killargs[IDM_FAILURE_ARGS_LEN];
|
||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
||||
int rv;
|
||||
|
||||
if (daemon_test)
|
||||
return 0;
|
||||
|
||||
if (!strcmp(ls->name, S_NAME_GL_IDM)) {
|
||||
/*
|
||||
* Prepare the pv list for global lock, if the drive contains
|
||||
* "propeller" partition, then this drive will be considered
|
||||
* as a member of pv list.
|
||||
*/
|
||||
rv = lm_idm_get_gl_lock_pv_list();
|
||||
if (rv < 0) {
|
||||
log_error("S %s add_lockspace_idm fail to get pv list for glb lock",
|
||||
ls->name);
|
||||
return -EIO;
|
||||
} else {
|
||||
log_error("S %s add_lockspace_idm get pv list for glb lock",
|
||||
ls->name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct the execution path for command "lvmlockctl" by using the
|
||||
* path to the lvm binary and appending "lockctl".
|
||||
*/
|
||||
memset(killpath, 0, sizeof(killpath));
|
||||
snprintf(killpath, IDM_FAILURE_PATH_LEN, "%slockctl", LVM_PATH);
|
||||
|
||||
/* Pass the argument "--kill vg_name" for killpath */
|
||||
memset(killargs, 0, sizeof(killargs));
|
||||
snprintf(killargs, IDM_FAILURE_ARGS_LEN, "--kill %s", ls->vg_name);
|
||||
|
||||
/* Connect with IDM lock manager per every lockspace. */
|
||||
rv = ilm_connect(&lmi->sock);
|
||||
if (rv < 0) {
|
||||
log_error("S %s add_lockspace_idm fail to connect the lock manager %d",
|
||||
ls->name, lmi->sock);
|
||||
lmi->sock = 0;
|
||||
rv = -EMANAGER;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rv = ilm_set_killpath(lmi->sock, killpath, killargs);
|
||||
if (rv < 0) {
|
||||
log_error("S %s add_lockspace_idm fail to set kill path %d",
|
||||
ls->name, rv);
|
||||
rv = -EMANAGER;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
log_debug("S %s add_lockspace_idm kill path is: \"%s %s\"",
|
||||
ls->name, killpath, killargs);
|
||||
|
||||
log_debug("S %s add_lockspace_idm done", ls->name);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (lmi && lmi->sock)
|
||||
close(lmi->sock);
|
||||
|
||||
free(lmi);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg)
|
||||
{
|
||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
||||
int i, rv = 0;
|
||||
|
||||
if (daemon_test)
|
||||
goto out;
|
||||
|
||||
rv = ilm_disconnect(lmi->sock);
|
||||
if (rv < 0)
|
||||
log_error("S %s rem_lockspace_idm error %d", ls->name, rv);
|
||||
|
||||
/* Release pv list for global lock */
|
||||
if (!strcmp(ls->name, "lvm_global")) {
|
||||
for (i = 0; i < glb_lock_op.drive_num; i++) {
|
||||
if (glb_lock_op.drives[i]) {
|
||||
free(glb_lock_op.drives[i]);
|
||||
glb_lock_op.drives[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
free(lmi);
|
||||
ls->lm_data = NULL;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int lm_add_resource_idm(struct lockspace *ls, struct resource *r)
|
||||
{
|
||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
||||
|
||||
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
||||
rdi->vb = zalloc(sizeof(struct val_blk));
|
||||
if (!rdi->vb)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lm_rem_resource_idm(struct lockspace *ls, struct resource *r)
|
||||
{
|
||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
||||
|
||||
free(rdi->vb);
|
||||
|
||||
memset(rdi, 0, sizeof(struct rd_idm));
|
||||
r->lm_init = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int to_idm_mode(int ld_mode)
|
||||
{
|
||||
switch (ld_mode) {
|
||||
case LD_LK_EX:
|
||||
return IDM_MODE_EXCLUSIVE;
|
||||
case LD_LK_SH:
|
||||
return IDM_MODE_SHAREABLE;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
||||
int adopt)
|
||||
{
|
||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
||||
char **drive_path = NULL;
|
||||
uint64_t timestamp;
|
||||
int reset_vb = 0;
|
||||
int rv, i;
|
||||
|
||||
if (!r->lm_init) {
|
||||
rv = lm_add_resource_idm(ls, r);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
r->lm_init = 1;
|
||||
}
|
||||
|
||||
rdi->op.mode = to_idm_mode(ld_mode);
|
||||
if (rv < 0) {
|
||||
log_error("lock_idm invalid mode %d", ld_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_debug("S %s R %s lock_idm", ls->name, r->name);
|
||||
|
||||
if (daemon_test) {
|
||||
if (rdi->vb) {
|
||||
vb_out->version = le16_to_cpu(rdi->vb->version);
|
||||
vb_out->flags = le16_to_cpu(rdi->vb->flags);
|
||||
vb_out->r_version = le32_to_cpu(rdi->vb->r_version);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
rdi->op.timeout = IDM_TIMEOUT;
|
||||
|
||||
/*
|
||||
* Generate the UUID string, for RT_VG, it only needs to generate
|
||||
* UUID string for VG level, for RT_LV, it needs to generate
|
||||
* UUID strings for both VG and LV levels. At the end, these IDs
|
||||
* are used as identifier for IDM in drive firmware.
|
||||
*/
|
||||
if (r->type == LD_RT_VG || r->type == LD_RT_LV)
|
||||
log_debug("S %s R %s VG uuid %s", ls->name, r->name, ls->vg_uuid);
|
||||
if (r->type == LD_RT_LV)
|
||||
log_debug("S %s R %s LV uuid %s", ls->name, r->name, lv_uuid);
|
||||
|
||||
memset(&rdi->id, 0x0, sizeof(struct idm_lock_id));
|
||||
if (r->type == LD_RT_VG) {
|
||||
uuid_read_format(rdi->id.vg_uuid, ls->vg_uuid);
|
||||
} else if (r->type == LD_RT_LV) {
|
||||
uuid_read_format(rdi->id.vg_uuid, ls->vg_uuid);
|
||||
uuid_read_format(rdi->id.lv_uuid, lv_uuid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Establish the drive path list for lock, since different lock type
|
||||
* has different drive list; the GL lock uses the global pv list,
|
||||
* the VG lock uses the pv list spanned for the whole volume group,
|
||||
* the LV lock uses the pv list for the logical volume.
|
||||
*/
|
||||
switch (r->type) {
|
||||
case LD_RT_GL:
|
||||
drive_path = glb_lock_op.drives;
|
||||
rdi->op.drive_num = glb_lock_op.drive_num;
|
||||
break;
|
||||
case LD_RT_VG:
|
||||
drive_path = (char **)ls->pvs.path;
|
||||
rdi->op.drive_num = ls->pvs.num;
|
||||
break;
|
||||
case LD_RT_LV:
|
||||
drive_path = (char **)pvs->path;
|
||||
rdi->op.drive_num = pvs->num;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!drive_path) {
|
||||
log_error("S %s R %s cannot find the valid drive path array",
|
||||
ls->name, r->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rdi->op.drive_num >= ILM_DRIVE_MAX_NUM) {
|
||||
log_error("S %s R %s exceeds limitation for drive path array",
|
||||
ls->name, r->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < rdi->op.drive_num; i++)
|
||||
rdi->op.drives[i] = drive_path[i];
|
||||
|
||||
log_debug("S %s R %s mode %d drive_num %d timeout %d",
|
||||
ls->name, r->name, rdi->op.mode,
|
||||
rdi->op.drive_num, rdi->op.timeout);
|
||||
|
||||
for (i = 0; i < rdi->op.drive_num; i++)
|
||||
log_debug("S %s R %s drive path[%d] %s",
|
||||
ls->name, r->name, i, rdi->op.drives[i]);
|
||||
|
||||
rv = ilm_lock(lmi->sock, &rdi->id, &rdi->op);
|
||||
if (rv < 0) {
|
||||
log_debug("S %s R %s lock_idm acquire mode %d rv %d",
|
||||
ls->name, r->name, ld_mode, rv);
|
||||
return -ELOCKIO;
|
||||
}
|
||||
|
||||
if (rdi->vb) {
|
||||
rv = ilm_read_lvb(lmi->sock, &rdi->id, (char *)×tamp,
|
||||
sizeof(uint64_t));
|
||||
|
||||
/*
|
||||
* If fail to read value block, which might be caused by drive
|
||||
* failure, notify up layer to invalidate metadata.
|
||||
*/
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s lock_idm get_lvb error %d",
|
||||
ls->name, r->name, rv);
|
||||
reset_vb = 1;
|
||||
|
||||
/* Reset timestamp */
|
||||
rdi->vb_timestamp = 0;
|
||||
|
||||
/*
|
||||
* If the cached timestamp mismatches with the stored value
|
||||
* in the IDM, this means another host has updated timestamp
|
||||
* for the new VB. Let's reset VB and notify up layer to
|
||||
* invalidate metadata.
|
||||
*/
|
||||
} else if (rdi->vb_timestamp != timestamp) {
|
||||
log_debug("S %s R %s lock_idm get lvb timestamp %lu:%lu",
|
||||
ls->name, r->name, rdi->vb_timestamp,
|
||||
timestamp);
|
||||
|
||||
rdi->vb_timestamp = timestamp;
|
||||
reset_vb = 1;
|
||||
}
|
||||
|
||||
if (reset_vb == 1) {
|
||||
memset(rdi->vb, 0, sizeof(struct val_blk));
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
|
||||
/*
|
||||
* The lock is still acquired, but the vb values has
|
||||
* been invalidated.
|
||||
*/
|
||||
rv = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Otherwise, copy the cached VB to up layer */
|
||||
memcpy(vb_out, rdi->vb, sizeof(struct val_blk));
|
||||
}
|
||||
|
||||
out:
|
||||
return rv;
|
||||
}
|
||||
|
||||
int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
||||
int ld_mode, uint32_t r_version)
|
||||
{
|
||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
||||
int mode, rv;
|
||||
|
||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
||||
if (!rdi->vb->version) {
|
||||
/* first time vb has been written */
|
||||
rdi->vb->version = VAL_BLK_VERSION;
|
||||
}
|
||||
rdi->vb->r_version = r_version;
|
||||
|
||||
log_debug("S %s R %s convert_idm set r_version %u",
|
||||
ls->name, r->name, r_version);
|
||||
|
||||
lm_idm_update_vb_timestamp(&rdi->vb_timestamp);
|
||||
log_debug("S %s R %s convert_idm vb %x %x %u timestamp %lu",
|
||||
ls->name, r->name, rdi->vb->version, rdi->vb->flags,
|
||||
rdi->vb->r_version, rdi->vb_timestamp);
|
||||
}
|
||||
|
||||
mode = to_idm_mode(ld_mode);
|
||||
if (mode < 0) {
|
||||
log_error("S %s R %s convert_idm invalid mode %d",
|
||||
ls->name, r->name, ld_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_debug("S %s R %s convert_idm", ls->name, r->name);
|
||||
|
||||
if (daemon_test)
|
||||
return 0;
|
||||
|
||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
||||
rv = ilm_write_lvb(lmi->sock, &rdi->id,
|
||||
(char *)rdi->vb_timestamp, sizeof(uint64_t));
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s convert_idm write lvb error %d",
|
||||
ls->name, r->name, rv);
|
||||
return -ELMERR;
|
||||
}
|
||||
}
|
||||
|
||||
rv = ilm_convert(lmi->sock, &rdi->id, mode);
|
||||
if (rv < 0)
|
||||
log_error("S %s R %s convert_idm convert error %d",
|
||||
ls->name, r->name, rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int lm_unlock_idm(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version, uint32_t lmu_flags)
|
||||
{
|
||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
||||
int rv;
|
||||
|
||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
||||
if (!rdi->vb->version) {
|
||||
/* first time vb has been written */
|
||||
rdi->vb->version = VAL_BLK_VERSION;
|
||||
}
|
||||
if (r_version)
|
||||
rdi->vb->r_version = r_version;
|
||||
|
||||
lm_idm_update_vb_timestamp(&rdi->vb_timestamp);
|
||||
log_debug("S %s R %s unlock_idm vb %x %x %u timestamp %lu",
|
||||
ls->name, r->name, rdi->vb->version, rdi->vb->flags,
|
||||
rdi->vb->r_version, rdi->vb_timestamp);
|
||||
}
|
||||
|
||||
log_debug("S %s R %s unlock_idm", ls->name, r->name);
|
||||
|
||||
if (daemon_test)
|
||||
return 0;
|
||||
|
||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
||||
rv = ilm_write_lvb(lmi->sock, &rdi->id,
|
||||
(char *)&rdi->vb_timestamp, sizeof(uint64_t));
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s unlock_idm set_lvb error %d",
|
||||
ls->name, r->name, rv);
|
||||
return -ELMERR;
|
||||
}
|
||||
}
|
||||
|
||||
rv = ilm_unlock(lmi->sock, &rdi->id);
|
||||
if (rv < 0)
|
||||
log_error("S %s R %s unlock_idm error %d", ls->name, r->name, rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int lm_hosts_idm(struct lockspace *ls, int notify)
|
||||
{
|
||||
struct resource *r;
|
||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
||||
struct rd_idm *rdi;
|
||||
int count, self, found_others = 0;
|
||||
int rv;
|
||||
|
||||
list_for_each_entry(r, &ls->resources, list) {
|
||||
if (!r->lm_init)
|
||||
continue;
|
||||
|
||||
rdi = (struct rd_idm *)r->lm_data;
|
||||
|
||||
rv = ilm_get_host_count(lmi->sock, &rdi->id, &rdi->op,
|
||||
&count, &self);
|
||||
if (rv < 0) {
|
||||
log_error("S %s lm_hosts_idm error %d", ls->name, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Fixup: need to reduce self count */
|
||||
if (count > found_others)
|
||||
found_others = count;
|
||||
}
|
||||
|
||||
return found_others;
|
||||
}
|
||||
|
||||
int lm_get_lockspaces_idm(struct list_head *ls_rejoin)
|
||||
{
|
||||
/* TODO: Need to add support for adoption. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lm_is_running_idm(void)
|
||||
{
|
||||
int sock, rv;
|
||||
|
||||
if (daemon_test)
|
||||
return gl_use_idm;
|
||||
|
||||
rv = ilm_connect(&sock);
|
||||
if (rv < 0) {
|
||||
log_error("Fail to connect seagate IDM lock manager %d", rv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ilm_disconnect(sock);
|
||||
return 1;
|
||||
}
|
||||
@@ -20,7 +20,6 @@
|
||||
#define R_NAME_GL "GLLK"
|
||||
#define R_NAME_VG "VGLK"
|
||||
#define S_NAME_GL_DLM "lvm_global"
|
||||
#define S_NAME_GL_IDM "lvm_global"
|
||||
#define LVM_LS_PREFIX "lvm_" /* ls name is prefix + vg_name */
|
||||
/* global lockspace name for sanlock is a vg name */
|
||||
|
||||
@@ -30,7 +29,6 @@ enum {
|
||||
LD_LM_UNUSED = 1, /* place holder so values match lib/locking/lvmlockd.h */
|
||||
LD_LM_DLM = 2,
|
||||
LD_LM_SANLOCK = 3,
|
||||
LD_LM_IDM = 4,
|
||||
};
|
||||
|
||||
/* operation types */
|
||||
@@ -120,11 +118,6 @@ struct client {
|
||||
*/
|
||||
#define DEFAULT_MAX_RETRIES 4
|
||||
|
||||
struct pvs {
|
||||
char **path;
|
||||
int num;
|
||||
};
|
||||
|
||||
struct action {
|
||||
struct list_head list;
|
||||
uint32_t client_id;
|
||||
@@ -147,7 +140,6 @@ struct action {
|
||||
char vg_args[MAX_ARGS+1];
|
||||
char lv_args[MAX_ARGS+1];
|
||||
char vg_sysid[MAX_NAME+1];
|
||||
struct pvs pvs; /* PV list for idm */
|
||||
};
|
||||
|
||||
struct resource {
|
||||
@@ -192,7 +184,6 @@ struct lockspace {
|
||||
uint64_t free_lock_offset; /* for sanlock, start search for free lock here */
|
||||
int free_lock_sector_size; /* for sanlock */
|
||||
int free_lock_align_size; /* for sanlock */
|
||||
struct pvs pvs; /* for idm: PV list */
|
||||
|
||||
uint32_t start_client_id; /* client_id that started the lockspace */
|
||||
pthread_t thread; /* makes synchronous lock requests */
|
||||
@@ -334,13 +325,10 @@ static inline int list_empty(const struct list_head *head)
|
||||
EXTERN int gl_type_static;
|
||||
EXTERN int gl_use_dlm;
|
||||
EXTERN int gl_use_sanlock;
|
||||
EXTERN int gl_use_idm;
|
||||
EXTERN int gl_vg_removed;
|
||||
EXTERN char gl_lsname_dlm[MAX_NAME+1];
|
||||
EXTERN char gl_lsname_sanlock[MAX_NAME+1];
|
||||
EXTERN char gl_lsname_idm[MAX_NAME+1];
|
||||
EXTERN int global_dlm_lockspace_exists;
|
||||
EXTERN int global_idm_lockspace_exists;
|
||||
|
||||
EXTERN int daemon_test; /* run as much as possible without a live lock manager */
|
||||
EXTERN int daemon_debug;
|
||||
@@ -392,7 +380,6 @@ static inline const char *mode_str(int x)
|
||||
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||
int lm_prepare_lockspace_dlm(struct lockspace *ls);
|
||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
|
||||
int lm_purge_locks_dlm(struct lockspace *ls);
|
||||
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
|
||||
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
struct val_blk *vb_out, int adopt);
|
||||
@@ -430,11 +417,6 @@ static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_purge_locks_dlm(struct lockspace *ls)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
|
||||
{
|
||||
return -1;
|
||||
@@ -637,102 +619,4 @@ static inline int lm_support_sanlock(void)
|
||||
|
||||
#endif /* sanlock support */
|
||||
|
||||
#ifdef LOCKDIDM_SUPPORT
|
||||
|
||||
int lm_data_size_idm(void);
|
||||
int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||
int lm_prepare_lockspace_idm(struct lockspace *ls);
|
||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt);
|
||||
int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg);
|
||||
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
||||
int adopt);
|
||||
int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
||||
int ld_mode, uint32_t r_version);
|
||||
int lm_unlock_idm(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version, uint32_t lmu_flags);
|
||||
int lm_hosts_idm(struct lockspace *ls, int notify);
|
||||
int lm_get_lockspaces_idm(struct list_head *ls_rejoin);
|
||||
int lm_is_running_idm(void);
|
||||
int lm_rem_resource_idm(struct lockspace *ls, struct resource *r);
|
||||
|
||||
static inline int lm_support_idm(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int lm_data_size_idm(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags,
|
||||
char *vg_args)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_prepare_lockspace_idm(struct lockspace *ls)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_add_lockspace_idm(struct lockspace *ls, int adopt)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
||||
int adopt)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
||||
int ld_mode, uint32_t r_version)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_unlock_idm(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version, uint32_t lmu_flags)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_hosts_idm(struct lockspace *ls, int notify)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_get_lockspaces_idm(struct list_head *ls_rejoin)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_is_running_idm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lm_rem_resource_idm(struct lockspace *ls, struct resource *r)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_support_idm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* Seagate IDM support */
|
||||
|
||||
#endif /* _LVM_LVMLOCKD_INTERNAL_H */
|
||||
|
||||
@@ -227,17 +227,6 @@ int lm_data_size_sanlock(void)
|
||||
|
||||
static uint64_t daemon_test_lv_count;
|
||||
|
||||
/*
|
||||
* Copy a null-terminated string "str" into a fixed
|
||||
* size (SANLK_NAME_LEN) struct field "buf" which is
|
||||
* not null terminated.
|
||||
*/
|
||||
static void strcpy_name_len(char *buf, char *str, int len)
|
||||
{
|
||||
/* coverity[buffer_size_warning] */
|
||||
strncpy(buf, str, SANLK_NAME_LEN);
|
||||
}
|
||||
|
||||
static int lock_lv_name_from_args(char *vg_args, char *lock_lv_name)
|
||||
{
|
||||
return last_string_from_args(vg_args, lock_lv_name);
|
||||
@@ -585,7 +574,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
}
|
||||
}
|
||||
|
||||
strcpy_name_len(ss.name, ls_name, SANLK_NAME_LEN);
|
||||
strncpy(ss.name, ls_name, SANLK_NAME_LEN);
|
||||
memcpy(ss.host_id_disk.path, disk.path, SANLK_PATH_LEN);
|
||||
ss.host_id_disk.offset = 0;
|
||||
ss.flags = (sector_size == 4096) ? (SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN8M) :
|
||||
@@ -618,7 +607,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
gl_name = R_NAME_GL;
|
||||
|
||||
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||
strcpy_name_len(rd.rs.name, (char *)gl_name, SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.name, gl_name, SANLK_NAME_LEN);
|
||||
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
||||
rd.rs.disks[0].offset = align_size * GL_LOCK_BEGIN;
|
||||
rd.rs.num_disks = 1;
|
||||
@@ -633,7 +622,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
}
|
||||
|
||||
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||
strcpy_name_len(rd.rs.name, (char *)R_NAME_VG, SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.name, R_NAME_VG, SANLK_NAME_LEN);
|
||||
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
||||
rd.rs.disks[0].offset = align_size * VG_LOCK_BEGIN;
|
||||
rd.rs.num_disks = 1;
|
||||
@@ -667,8 +656,8 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
||||
strcpy_name_len(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
|
||||
strcpy_name_len(rd.rs.name, (char *)"#unused", SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
|
||||
strcpy(rd.rs.name, "#unused");
|
||||
|
||||
offset = align_size * LV_LOCK_BEGIN;
|
||||
|
||||
@@ -684,10 +673,10 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
break;
|
||||
}
|
||||
|
||||
if (rv < 0) {
|
||||
if (rv) {
|
||||
log_error("clear lv resource area %llu error %d",
|
||||
(unsigned long long)offset, rv);
|
||||
return rv;
|
||||
break;
|
||||
}
|
||||
offset += align_size;
|
||||
}
|
||||
@@ -736,7 +725,7 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
strcpy_name_len(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
|
||||
rd.rs.num_disks = 1;
|
||||
if ((rv = build_dm_path(rd.rs.disks[0].path, SANLK_PATH_LEN, vg_name, lock_lv_name)))
|
||||
return rv;
|
||||
@@ -811,7 +800,7 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
||||
log_debug("S %s init_lv_san %s found unused area at %llu",
|
||||
ls_name, lv_name, (unsigned long long)offset);
|
||||
|
||||
strcpy_name_len(rd.rs.name, lv_name, SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.name, lv_name, SANLK_NAME_LEN);
|
||||
rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
|
||||
@@ -910,7 +899,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
||||
if (!sector_size || !align_size)
|
||||
return -1;
|
||||
|
||||
strcpy_name_len(ss.name, ls_name, SANLK_NAME_LEN);
|
||||
strncpy(ss.name, ls_name, SANLK_NAME_LEN);
|
||||
|
||||
rv = sanlock_write_lockspace(&ss, 0, 0, sanlock_io_timeout);
|
||||
if (rv < 0) {
|
||||
@@ -935,7 +924,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
||||
return rv;
|
||||
}
|
||||
|
||||
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||
|
||||
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||
if (rv < 0) {
|
||||
@@ -960,7 +949,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
||||
return rv;
|
||||
}
|
||||
|
||||
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||
|
||||
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||
if (rv < 0) {
|
||||
@@ -994,7 +983,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||
|
||||
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||
if (rv) {
|
||||
@@ -1020,7 +1009,7 @@ int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r)
|
||||
if (daemon_test)
|
||||
return 0;
|
||||
|
||||
strcpy_name_len(rs->name, (char *)"#unused", SANLK_NAME_LEN);
|
||||
strcpy(rs->name, "#unused");
|
||||
|
||||
rv = sanlock_write_resource(rs, 0, 0, 0);
|
||||
if (rv < 0) {
|
||||
@@ -1054,14 +1043,14 @@ int lm_ex_disable_gl_sanlock(struct lockspace *ls)
|
||||
memset(&rd1, 0, sizeof(rd1));
|
||||
memset(&rd2, 0, sizeof(rd2));
|
||||
|
||||
strcpy_name_len(rd1.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
strcpy_name_len(rd1.rs.name, (char *)R_NAME_GL, SANLK_NAME_LEN);
|
||||
strncpy(rd1.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
strncpy(rd1.rs.name, R_NAME_GL, SANLK_NAME_LEN);
|
||||
|
||||
strcpy_name_len(rd2.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
strcpy_name_len(rd2.rs.name, (char *)R_NAME_GL_DISABLED, SANLK_NAME_LEN);
|
||||
strncpy(rd2.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
strncpy(rd2.rs.name, R_NAME_GL_DISABLED, SANLK_NAME_LEN);
|
||||
|
||||
rd1.rs.num_disks = 1;
|
||||
memcpy(rd1.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
strncpy(rd1.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
rd1.rs.disks[0].offset = lms->align_size * GL_LOCK_BEGIN;
|
||||
|
||||
rd1.rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
@@ -1123,11 +1112,11 @@ int lm_able_gl_sanlock(struct lockspace *ls, int enable)
|
||||
|
||||
memset(&rd, 0, sizeof(rd));
|
||||
|
||||
strcpy_name_len(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
strcpy_name_len(rd.rs.name, (char *)gl_name, SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.name, gl_name, SANLK_NAME_LEN);
|
||||
|
||||
rd.rs.num_disks = 1;
|
||||
memcpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
rd.rs.disks[0].offset = lms->align_size * GL_LOCK_BEGIN;
|
||||
rd.rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
@@ -1164,12 +1153,12 @@ static int gl_is_enabled(struct lockspace *ls, struct lm_sanlock *lms)
|
||||
|
||||
memset(&rd, 0, sizeof(rd));
|
||||
|
||||
strcpy_name_len(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
|
||||
/* leave rs.name empty, it is what we're checking */
|
||||
|
||||
rd.rs.num_disks = 1;
|
||||
memcpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
|
||||
offset = lms->align_size * GL_LOCK_BEGIN;
|
||||
rd.rs.disks[0].offset = offset;
|
||||
@@ -1235,9 +1224,9 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *
|
||||
|
||||
memset(&rd, 0, sizeof(rd));
|
||||
|
||||
strcpy_name_len(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
strncpy(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
rd.rs.num_disks = 1;
|
||||
memcpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
rd.rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
|
||||
@@ -1422,7 +1411,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
memcpy(lms->ss.name, lsname, SANLK_NAME_LEN);
|
||||
lms->ss.host_id_disk.offset = 0;
|
||||
lms->ss.host_id = ls->host_id;
|
||||
memcpy(lms->ss.host_id_disk.path, disk_path, SANLK_PATH_LEN-1);
|
||||
strncpy(lms->ss.host_id_disk.path, disk_path, SANLK_PATH_LEN-1);
|
||||
|
||||
if (daemon_test) {
|
||||
if (!gl_lsname_sanlock[0]) {
|
||||
@@ -1514,7 +1503,8 @@ out:
|
||||
fail:
|
||||
if (lms && lms->sock)
|
||||
close(lms->sock);
|
||||
free(lms);
|
||||
if (lms)
|
||||
free(lms);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1576,8 +1566,10 @@ int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
|
||||
goto out;
|
||||
|
||||
rv = sanlock_rem_lockspace(&lms->ss, 0);
|
||||
if (rv < 0)
|
||||
if (rv < 0) {
|
||||
log_error("S %s rem_lockspace_san error %d", ls->name, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (free_vg) {
|
||||
/*
|
||||
@@ -1586,7 +1578,7 @@ int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
|
||||
* This shouldn't be generally necessary, but there may some races
|
||||
* between nodes starting and removing a vg which this could help.
|
||||
*/
|
||||
strcpy_name_len(lms->ss.name, (char *)"#unused", SANLK_NAME_LEN);
|
||||
strncpy(lms->ss.name, "#unused", SANLK_NAME_LEN);
|
||||
|
||||
rv = sanlock_write_lockspace(&lms->ss, 0, 0, sanlock_io_timeout);
|
||||
if (rv < 0) {
|
||||
@@ -1614,8 +1606,8 @@ static int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
|
||||
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
|
||||
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
|
||||
|
||||
strcpy_name_len(rds->rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
strcpy_name_len(rds->rs.name, r->name, SANLK_NAME_LEN);
|
||||
strncpy(rds->rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
strncpy(rds->rs.name, r->name, SANLK_NAME_LEN);
|
||||
rds->rs.num_disks = 1;
|
||||
memcpy(rds->rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN);
|
||||
rds->rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) : (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
@@ -1642,7 +1634,8 @@ int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r)
|
||||
|
||||
/* FIXME: assert r->mode == UN or unlock if it's not? */
|
||||
|
||||
free(rds->vb);
|
||||
if (rds->vb)
|
||||
free(rds->vb);
|
||||
|
||||
memset(rds, 0, sizeof(struct rd_sanlock));
|
||||
r->lm_init = 0;
|
||||
@@ -1658,7 +1651,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
struct sanlk_options opt;
|
||||
uint64_t lock_lv_offset;
|
||||
uint32_t flags = 0;
|
||||
struct val_blk vb = { 0 };
|
||||
struct val_blk vb;
|
||||
int added = 0;
|
||||
int rv;
|
||||
|
||||
@@ -2044,7 +2037,7 @@ static int release_rename(struct lockspace *ls, struct resource *r)
|
||||
res1 = (struct sanlk_resource *)&rd1;
|
||||
res2 = (struct sanlk_resource *)&rd2;
|
||||
|
||||
strcpy_name_len(res2->name, (char *)"invalid_removed", SANLK_NAME_LEN);
|
||||
strcpy(res2->name, "invalid_removed");
|
||||
|
||||
res_args[0] = res1;
|
||||
res_args[1] = res2;
|
||||
@@ -2237,8 +2230,8 @@ int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin)
|
||||
|
||||
ls->lm_type = LD_LM_SANLOCK;
|
||||
ls->host_id = ss->host_id;
|
||||
memcpy(ls->name, ss->name, SANLK_NAME_LEN);
|
||||
memcpy(ls->vg_name, ss->name + strlen(LVM_LS_PREFIX), SANLK_NAME_LEN - strlen(LVM_LS_PREFIX));
|
||||
strncpy(ls->name, ss->name, MAX_NAME);
|
||||
strncpy(ls->vg_name, ss->name + strlen(LVM_LS_PREFIX), MAX_NAME);
|
||||
list_add_tail(&ls->list, ls_rejoin);
|
||||
|
||||
ss++;
|
||||
|
||||
@@ -19,11 +19,12 @@ SOURCES = lvmpolld-core.c lvmpolld-data-utils.c lvmpolld-cmd-utils.c
|
||||
|
||||
TARGETS = lvmpolld
|
||||
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
CFLOW_TARGET := $(TARGETS)
|
||||
|
||||
.PHONY: install_lvmpolld
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
CFLOW_TARGET = lvmpolld
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||
|
||||
@@ -92,12 +92,6 @@ const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary,
|
||||
if (!add_to_cmd_arr(&cmd_argv, "-An", &i))
|
||||
goto err;
|
||||
|
||||
if (pdlv->devicesfile) {
|
||||
if (!add_to_cmd_arr(&cmd_argv, "--devicesfile", &i) ||
|
||||
!add_to_cmd_arr(&cmd_argv, pdlv->devicesfile, &i))
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* terminating NULL */
|
||||
if (!add_to_cmd_arr(&cmd_argv, NULL, &i))
|
||||
goto err;
|
||||
|
||||
@@ -52,7 +52,7 @@ static pthread_key_t key;
|
||||
|
||||
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
|
||||
{
|
||||
#if defined(_GNU_SOURCE) && defined(STRERROR_R_CHAR_P)
|
||||
#ifdef _GNU_SOURCE
|
||||
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
|
||||
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
|
||||
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
|
||||
@@ -149,7 +149,7 @@ static void _lvmpolld_global_unlock(struct lvmpolld_state *ls)
|
||||
static int _fini(struct daemon_state *s)
|
||||
{
|
||||
int done;
|
||||
const struct timespec t = { .tv_nsec = 10000000 }; /* .01 sec */
|
||||
const struct timespec t = { .tv_nsec = 250000000 }; /* .25 sec */
|
||||
struct lvmpolld_state *ls = s->private;
|
||||
|
||||
DEBUGLOG(s, "fini");
|
||||
@@ -236,7 +236,9 @@ static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data
|
||||
}
|
||||
|
||||
while (1) {
|
||||
r = poll(fds, 2, pdlv_get_timeout(pdlv) * 1000);
|
||||
do {
|
||||
r = poll(fds, 2, pdlv_get_timeout(pdlv) * 1000);
|
||||
} while (r < 0 && errno == EINTR);
|
||||
|
||||
DEBUGLOG(pdlv->ls, "%s: %s %d", PD_LOG_PREFIX, "poll() returned", r);
|
||||
if (r < 0) {
|
||||
@@ -372,7 +374,7 @@ static void debug_print(struct lvmpolld_state *ls, const char * const* ptr)
|
||||
|
||||
static void *fork_and_poll(void *args)
|
||||
{
|
||||
int outfd, errfd, state = 0;
|
||||
int outfd, errfd, state;
|
||||
struct lvmpolld_thread_data *data;
|
||||
pid_t r;
|
||||
|
||||
@@ -553,15 +555,14 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
|
||||
const char *interval, const char *id,
|
||||
const char *vgname, const char *lvname,
|
||||
const char *sysdir, enum poll_type type,
|
||||
unsigned abort_polling, unsigned uinterval,
|
||||
const char *devicesfile)
|
||||
unsigned abort_polling, unsigned uinterval)
|
||||
{
|
||||
const char **cmdargv, **cmdenvp;
|
||||
struct lvmpolld_lv *pdlv;
|
||||
unsigned handle_missing_pvs = daemon_request_int(req, LVMPD_PARM_HANDLE_MISSING_PVS, 0);
|
||||
|
||||
pdlv = pdlv_create(ls, id, vgname, lvname, sysdir, type,
|
||||
interval, uinterval, pdst, devicesfile);
|
||||
interval, uinterval, pdst);
|
||||
|
||||
if (!pdlv) {
|
||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to create internal LV data structure.");
|
||||
@@ -620,7 +621,6 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
||||
const char *lvname = daemon_request_str(req, LVMPD_PARM_LVNAME, NULL);
|
||||
const char *vgname = daemon_request_str(req, LVMPD_PARM_VGNAME, NULL);
|
||||
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
|
||||
const char *devicesfile = daemon_request_str(req, LVMPD_PARM_DEVICESFILE, NULL);
|
||||
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
|
||||
|
||||
assert(type < POLL_TYPE_MAX);
|
||||
@@ -680,7 +680,7 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
||||
pdlv->init_rq_count++; /* safe. protected by store lock */
|
||||
} else {
|
||||
pdlv = construct_pdlv(req, ls, pdst, interval, id, vgname,
|
||||
lvname, sysdir, type, abort_polling, 2 * uinterval, devicesfile);
|
||||
lvname, sysdir, type, abort_polling, 2 * uinterval);
|
||||
if (!pdlv) {
|
||||
pdst_unlock(pdst);
|
||||
free(id);
|
||||
|
||||
@@ -93,13 +93,11 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
const char *vgname, const char *lvname,
|
||||
const char *sysdir, enum poll_type type,
|
||||
const char *sinterval, unsigned pdtimeout,
|
||||
struct lvmpolld_store *pdst,
|
||||
const char *devicesfile)
|
||||
struct lvmpolld_store *pdst)
|
||||
{
|
||||
char *lvmpolld_id = strdup(id), /* copy */
|
||||
*full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
|
||||
*lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
|
||||
char *devicesfile_dup = devicesfile ? strdup(devicesfile) : NULL;
|
||||
|
||||
struct lvmpolld_lv tmp = {
|
||||
.ls = ls,
|
||||
@@ -107,7 +105,6 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
.lvmpolld_id = lvmpolld_id,
|
||||
.lvid = _get_lvid(lvmpolld_id, sysdir),
|
||||
.lvname = full_lvname,
|
||||
.devicesfile = devicesfile_dup,
|
||||
.lvm_system_dir_env = lvm_system_dir_env,
|
||||
.sinterval = strdup(sinterval), /* copy */
|
||||
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
|
||||
@@ -127,7 +124,6 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
return pdlv;
|
||||
|
||||
err:
|
||||
free((void *)devicesfile_dup);
|
||||
free((void *)full_lvname);
|
||||
free((void *)lvmpolld_id);
|
||||
free((void *)lvm_system_dir_env);
|
||||
@@ -140,7 +136,6 @@ err:
|
||||
void pdlv_destroy(struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
free((void *)pdlv->lvmpolld_id);
|
||||
free((void *)pdlv->devicesfile);
|
||||
free((void *)pdlv->lvname);
|
||||
free((void *)pdlv->sinterval);
|
||||
free((void *)pdlv->lvm_system_dir_env);
|
||||
|
||||
@@ -49,7 +49,6 @@ struct lvmpolld_lv {
|
||||
const enum poll_type type;
|
||||
const char *const lvid;
|
||||
const char *const lvmpolld_id;
|
||||
const char *const devicesfile;
|
||||
const char *const lvname; /* full vg/lv name */
|
||||
const unsigned pdtimeout; /* in seconds */
|
||||
const char *const sinterval;
|
||||
@@ -102,8 +101,7 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
const char *vgname, const char *lvname,
|
||||
const char *sysdir, enum poll_type type,
|
||||
const char *sinterval, unsigned pdtimeout,
|
||||
struct lvmpolld_store *pdst,
|
||||
const char *devicesfile);
|
||||
struct lvmpolld_store *pdst);
|
||||
|
||||
/* only call with appropriate struct lvmpolld_store lock held */
|
||||
void pdlv_destroy(struct lvmpolld_lv *pdlv);
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#define LVMPD_PARM_SYSDIR "sysdir"
|
||||
#define LVMPD_PARM_VALUE "value" /* either retcode or signal value */
|
||||
#define LVMPD_PARM_VGNAME "vgname"
|
||||
#define LVMPD_PARM_DEVICESFILE "devicesfile"
|
||||
|
||||
#define LVMPD_RESP_FAILED "failed"
|
||||
#define LVMPD_RESP_FINISHED "finished"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2018 - 2022 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the device-mapper userspace tools.
|
||||
#
|
||||
@@ -29,7 +29,6 @@ DEVICE_MAPPER_SOURCE=\
|
||||
device_mapper/regex/parse_rx.c \
|
||||
device_mapper/regex/ttree.c \
|
||||
device_mapper/vdo/status.c \
|
||||
device_mapper/vdo/vdo_reader.c \
|
||||
device_mapper/vdo/vdo_target.c
|
||||
|
||||
DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a
|
||||
|
||||
@@ -173,16 +173,6 @@ struct dm_names {
|
||||
char name[];
|
||||
};
|
||||
|
||||
struct dm_active_device {
|
||||
struct dm_list list;
|
||||
int major;
|
||||
int minor;
|
||||
char *name; /* device name */
|
||||
|
||||
uint32_t event_nr; /* valid when DM_DEVICE_LIST_HAS_EVENT_NR is set */
|
||||
char *uuid; /* valid uuid when DM_DEVICE_LIST_HAS_UUID is set */
|
||||
};
|
||||
|
||||
struct dm_versions {
|
||||
uint32_t next; /* Offset to next struct from start of this struct */
|
||||
uint32_t version[3];
|
||||
@@ -220,25 +210,6 @@ const char *dm_task_get_message_response(struct dm_task *dmt);
|
||||
*/
|
||||
const char *dm_task_get_name(const struct dm_task *dmt);
|
||||
struct dm_names *dm_task_get_names(struct dm_task *dmt);
|
||||
/*
|
||||
* Retrieve the list of devices and put them into easily accessible
|
||||
* struct dm_active_device list elements.
|
||||
* devs_features provides flag-set with used features so it's easy to check
|
||||
* whether the kernel provides i.e. UUID info together with DM names
|
||||
*/
|
||||
#define DM_DEVICE_LIST_HAS_EVENT_NR 1
|
||||
#define DM_DEVICE_LIST_HAS_UUID 2
|
||||
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
|
||||
unsigned *devs_features);
|
||||
/*
|
||||
* -1: no idea about uuid (not provided by DM_DEVICE_LIST ioctl)
|
||||
* 0: uuid not present
|
||||
* 1: listed and dm_active_device will be set for not NULL pointer
|
||||
*/
|
||||
int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
|
||||
const struct dm_active_device **dev);
|
||||
/* Release all associated memory with list of active DM devices */
|
||||
void dm_device_list_destroy(struct dm_list **devs_list);
|
||||
|
||||
int dm_task_set_ro(struct dm_task *dmt);
|
||||
int dm_task_set_newname(struct dm_task *dmt, const char *newname);
|
||||
@@ -263,7 +234,6 @@ int dm_task_suppress_identical_reload(struct dm_task *dmt);
|
||||
int dm_task_secure_data(struct dm_task *dmt);
|
||||
int dm_task_retry_remove(struct dm_task *dmt);
|
||||
int dm_task_deferred_remove(struct dm_task *dmt);
|
||||
int dm_task_ima_measurement(struct dm_task *dmt);
|
||||
void dm_task_skip_reload_params_compare(struct dm_task *dmt);
|
||||
|
||||
/*
|
||||
@@ -982,9 +952,7 @@ struct writecache_settings {
|
||||
uint32_t fua;
|
||||
uint32_t nofua;
|
||||
uint32_t cleaner;
|
||||
uint32_t max_age; /* in milliseconds */
|
||||
uint32_t metadata_only;
|
||||
uint32_t pause_writeback; /* in milliseconds */
|
||||
uint32_t max_age;
|
||||
|
||||
/*
|
||||
* Allow an unrecognized key and its val to be passed to the kernel for
|
||||
@@ -1006,8 +974,6 @@ struct writecache_settings {
|
||||
unsigned nofua_set:1;
|
||||
unsigned cleaner_set:1;
|
||||
unsigned max_age_set:1;
|
||||
unsigned metadata_only_set:1;
|
||||
unsigned pause_writeback_set:1;
|
||||
};
|
||||
|
||||
int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
|
||||
@@ -1053,7 +1019,6 @@ int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
|
||||
*/
|
||||
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
uint32_t vdo_version,
|
||||
const char *vdo_pool_name,
|
||||
const char *data_uuid,
|
||||
uint64_t data_size,
|
||||
@@ -1107,10 +1072,10 @@ int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
|
||||
#define DM_THIN_MIN_DATA_BLOCK_SIZE (UINT32_C(128))
|
||||
#define DM_THIN_MAX_DATA_BLOCK_SIZE (UINT32_C(2097152))
|
||||
/*
|
||||
* Max supported size for thin pool metadata device (17045913600 bytes)
|
||||
* Max supported size for thin pool metadata device (17112760320 bytes)
|
||||
* Limitation is hardcoded into the kernel and bigger device size
|
||||
* is not accepted.
|
||||
* drivers/md/dm-thin-metadata.h THIN_METADATA_MAX_SECTORS
|
||||
* But here DM_THIN_MAX_METADATA_SIZE got defined incorrectly
|
||||
* Correct size is (UINT64_C(255) * ((1 << 14) - 64) * (4096 / (1 << 9)))
|
||||
*/
|
||||
#define DM_THIN_MAX_METADATA_SIZE (UINT64_C(255) * (1 << 14) * (4096 / (1 << 9)) - 256 * 1024)
|
||||
|
||||
@@ -1123,16 +1088,6 @@ int dm_tree_node_add_thin_pool_target(struct dm_tree_node *node,
|
||||
uint64_t low_water_mark,
|
||||
unsigned skip_block_zeroing);
|
||||
|
||||
int dm_tree_node_add_thin_pool_target_v1(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
uint64_t transaction_id,
|
||||
const char *metadata_uuid,
|
||||
const char *pool_uuid,
|
||||
uint32_t data_block_size,
|
||||
uint64_t low_water_mark,
|
||||
unsigned skip_block_zeroing,
|
||||
unsigned crop_metadata);
|
||||
|
||||
/* Supported messages for thin provision target */
|
||||
typedef enum {
|
||||
DM_THIN_MESSAGE_CREATE_SNAP, /* device_id, origin_id */
|
||||
@@ -1987,8 +1942,7 @@ struct dm_report_group;
|
||||
typedef enum {
|
||||
DM_REPORT_GROUP_SINGLE,
|
||||
DM_REPORT_GROUP_BASIC,
|
||||
DM_REPORT_GROUP_JSON,
|
||||
DM_REPORT_GROUP_JSON_STD
|
||||
DM_REPORT_GROUP_JSON
|
||||
} dm_report_group_type_t;
|
||||
|
||||
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data);
|
||||
|
||||
@@ -150,8 +150,7 @@ 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;
|
||||
size_t nmaskbits;
|
||||
int c, old_c, totaldigits, ndigits, nmaskbits;
|
||||
int at_start, in_range;
|
||||
dm_bitset_t mask = NULL;
|
||||
const char *start = str;
|
||||
@@ -243,3 +242,18 @@ bad:
|
||||
}
|
||||
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
|
||||
|
||||
@@ -139,6 +139,7 @@ static char *_align(char *ptr, unsigned int a)
|
||||
return (char *) (((unsigned long) ptr + agn) & ~agn);
|
||||
}
|
||||
|
||||
#ifdef DM_IOCTLS
|
||||
static unsigned _kernel_major = 0;
|
||||
static unsigned _kernel_minor = 0;
|
||||
static unsigned _kernel_release = 0;
|
||||
@@ -181,9 +182,6 @@ int get_uname_version(unsigned *major, unsigned *minor, unsigned *release)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef DM_IOCTLS
|
||||
|
||||
/*
|
||||
* Set number to NULL to populate _dm_bitset - otherwise first
|
||||
* match is returned.
|
||||
@@ -495,10 +493,7 @@ static void _dm_task_free_targets(struct dm_task *dmt)
|
||||
|
||||
for (t = dmt->head; t; t = n) {
|
||||
n = t->next;
|
||||
if (dmt->secure_data)
|
||||
_dm_zfree_string(t->params);
|
||||
else
|
||||
free(t->params);
|
||||
_dm_zfree_string(t->params);
|
||||
free(t->type);
|
||||
free(t);
|
||||
}
|
||||
@@ -509,10 +504,7 @@ static void _dm_task_free_targets(struct dm_task *dmt)
|
||||
void dm_task_destroy(struct dm_task *dmt)
|
||||
{
|
||||
_dm_task_free_targets(dmt);
|
||||
if (dmt->secure_data)
|
||||
_dm_zfree_dmi(dmt->dmi.v4);
|
||||
else
|
||||
free(dmt->dmi.v4);
|
||||
_dm_zfree_dmi(dmt->dmi.v4);
|
||||
free(dmt->dev_name);
|
||||
free(dmt->mangled_dev_name);
|
||||
free(dmt->newname);
|
||||
@@ -618,7 +610,8 @@ int dm_check_version(void)
|
||||
int dm_cookie_supported(void)
|
||||
{
|
||||
return (dm_check_version() &&
|
||||
((_dm_version == 4) ? _dm_version_minor >= 15 : _dm_version > 4));
|
||||
_dm_version >= 4 &&
|
||||
_dm_version_minor >= 15);
|
||||
}
|
||||
|
||||
static int _dm_inactive_supported(void)
|
||||
@@ -756,159 +749,6 @@ struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
|
||||
dmt->dmi.v4->data_start);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Round up the ptr to an 8-byte boundary.
|
||||
* Follow kernel pattern.
|
||||
*/
|
||||
#define ALIGN_MASK 7
|
||||
static size_t _align_val(size_t val)
|
||||
{
|
||||
return (val + ALIGN_MASK) & ~ALIGN_MASK;
|
||||
}
|
||||
static void *_align_ptr(void *ptr)
|
||||
{
|
||||
return (void *)_align_val((size_t)ptr);
|
||||
}
|
||||
|
||||
static int _check_has_event_nr(void) {
|
||||
static int _has_event_nr = -1;
|
||||
|
||||
if (_has_event_nr < 0)
|
||||
_has_event_nr = dm_check_version() &&
|
||||
((_dm_version == 4) ? _dm_version_minor >= 38 : _dm_version > 4);
|
||||
|
||||
return _has_event_nr;
|
||||
}
|
||||
|
||||
struct dm_device_list {
|
||||
struct dm_list list;
|
||||
unsigned count;
|
||||
unsigned features;
|
||||
struct dm_hash_table *uuids;
|
||||
};
|
||||
|
||||
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
|
||||
unsigned *devs_features)
|
||||
{
|
||||
struct dm_names *names, *names1;
|
||||
struct dm_active_device *dm_dev, *dm_new_dev;
|
||||
struct dm_device_list *devs;
|
||||
unsigned next = 0;
|
||||
uint32_t *event_nr;
|
||||
char *uuid_ptr;
|
||||
size_t len;
|
||||
int cnt = 0;
|
||||
|
||||
*devs_list = 0;
|
||||
*devs_features = 0;
|
||||
|
||||
if ((names = dm_task_get_names(dmt)) && names->dev) {
|
||||
names1 = names;
|
||||
if (!names->name[0])
|
||||
cnt = -1; /* -> cnt == 0 when no device is really present */
|
||||
do {
|
||||
names1 = (struct dm_names *)((char *) names1 + next);
|
||||
next = names1->next;
|
||||
++cnt;
|
||||
} while (next);
|
||||
}
|
||||
|
||||
if (!(devs = malloc(sizeof(*devs) + (cnt ? cnt * sizeof(*dm_dev) + (char*)names1 - (char*)names + 256 : 0))))
|
||||
return_0;
|
||||
|
||||
dm_list_init(&devs->list);
|
||||
devs->count = cnt;
|
||||
devs->uuids = NULL;
|
||||
|
||||
if (!cnt) {
|
||||
/* nothing in the list -> mark all features present */
|
||||
*devs_features |= (DM_DEVICE_LIST_HAS_EVENT_NR | DM_DEVICE_LIST_HAS_UUID);
|
||||
goto out; /* nothing else to do */
|
||||
}
|
||||
|
||||
dm_dev = (struct dm_active_device *) (devs + 1);
|
||||
|
||||
do {
|
||||
names = (struct dm_names *)((char *) names + next);
|
||||
|
||||
dm_dev->major = MAJOR(names->dev);
|
||||
dm_dev->minor = MINOR(names->dev);
|
||||
dm_dev->name = (char*)(dm_dev + 1);
|
||||
dm_dev->event_nr = 0;
|
||||
dm_dev->uuid = NULL;
|
||||
|
||||
strcpy(dm_dev->name, names->name);
|
||||
len = strlen(names->name) + 1;
|
||||
|
||||
dm_new_dev = _align_ptr((char*)(dm_dev + 1) + len);
|
||||
if (_check_has_event_nr()) {
|
||||
/* Hash for UUIDs with some more bits to reduce colision count */
|
||||
if (!devs->uuids && !(devs->uuids = dm_hash_create(cnt * 8))) {
|
||||
free(devs);
|
||||
return_0;
|
||||
}
|
||||
|
||||
*devs_features |= DM_DEVICE_LIST_HAS_EVENT_NR;
|
||||
event_nr = _align_ptr(names->name + len);
|
||||
dm_dev->event_nr = event_nr[0];
|
||||
|
||||
if ((event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
|
||||
*devs_features |= DM_DEVICE_LIST_HAS_UUID;
|
||||
uuid_ptr = _align_ptr(event_nr + 2);
|
||||
dm_dev->uuid = (char*) dm_new_dev;
|
||||
dm_new_dev = _align_ptr((char*)dm_new_dev + strlen(uuid_ptr) + 1);
|
||||
strcpy(dm_dev->uuid, uuid_ptr);
|
||||
if (!dm_hash_insert(devs->uuids, dm_dev->uuid, dm_dev))
|
||||
return_0; // FIXME
|
||||
#if 0
|
||||
log_debug("Active %s (%s) %d:%d event:%u",
|
||||
dm_dev->name, dm_dev->uuid,
|
||||
dm_dev->major, dm_dev->minor, dm_dev->event_nr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
dm_list_add(&devs->list, &dm_dev->list);
|
||||
dm_dev = dm_new_dev;
|
||||
next = names->next;
|
||||
} while (next);
|
||||
|
||||
out:
|
||||
*devs_list = (struct dm_list *)devs;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
|
||||
const struct dm_active_device **dev)
|
||||
{
|
||||
struct dm_device_list *devs = (struct dm_device_list *) devs_list;
|
||||
struct dm_active_device *dm_dev;
|
||||
|
||||
if (devs->uuids &&
|
||||
(dm_dev = dm_hash_lookup(devs->uuids, uuid))) {
|
||||
if (dev)
|
||||
*dev = dm_dev;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dm_device_list_destroy(struct dm_list **devs_list)
|
||||
{
|
||||
struct dm_device_list *devs = (struct dm_device_list *) *devs_list;
|
||||
|
||||
if (devs) {
|
||||
if (devs->uuids)
|
||||
dm_hash_destroy(devs->uuids);
|
||||
|
||||
free(devs);
|
||||
*devs_list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct dm_names *dm_task_get_names(struct dm_task *dmt)
|
||||
{
|
||||
return (struct dm_names *) (((char *) dmt->dmi.v4) +
|
||||
@@ -1080,13 +920,6 @@ int dm_task_secure_data(struct dm_task *dmt)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_ima_measurement(struct dm_task *dmt)
|
||||
{
|
||||
dmt->ima_measurement = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_retry_remove(struct dm_task *dmt)
|
||||
{
|
||||
dmt->retry_remove = 1;
|
||||
@@ -1279,7 +1112,7 @@ static int _add_params(int type)
|
||||
|
||||
static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
{
|
||||
size_t min_size;
|
||||
const size_t min_size = 16 * 1024;
|
||||
const int (*version)[3];
|
||||
|
||||
struct dm_ioctl *dmi;
|
||||
@@ -1298,18 +1131,6 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
else if (dmt->head)
|
||||
log_debug_activation(INTERNAL_ERROR "dm '%s' ioctl should not define parameters.",
|
||||
_cmd_data_v4[dmt->type].name);
|
||||
switch (dmt->type) {
|
||||
case DM_DEVICE_CREATE:
|
||||
case DM_DEVICE_DEPS:
|
||||
case DM_DEVICE_LIST:
|
||||
case DM_DEVICE_STATUS:
|
||||
case DM_DEVICE_TABLE:
|
||||
case DM_DEVICE_TARGET_MSG:
|
||||
min_size = 16 * 1024;
|
||||
break;
|
||||
default:
|
||||
min_size = 2 * 1024;
|
||||
}
|
||||
|
||||
if (count && (dmt->sector || dmt->message)) {
|
||||
log_error("targets and message are incompatible");
|
||||
@@ -1411,11 +1232,9 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
/* FIXME Until resume ioctl supplies name, use dev_name for readahead */
|
||||
if (DEV_NAME(dmt) && (dmt->type != DM_DEVICE_RESUME || dmt->minor < 0 ||
|
||||
dmt->major < 0))
|
||||
/* coverity[buffer_size_warning] */
|
||||
strncpy(dmi->name, DEV_NAME(dmt), sizeof(dmi->name));
|
||||
|
||||
if (DEV_UUID(dmt))
|
||||
/* coverity[buffer_size_warning] */
|
||||
strncpy(dmi->uuid, DEV_UUID(dmt), sizeof(dmi->uuid));
|
||||
|
||||
if (dmt->type == DM_DEVICE_SUSPEND)
|
||||
@@ -1454,14 +1273,6 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
}
|
||||
dmi->flags |= DM_UUID_FLAG;
|
||||
}
|
||||
if (dmt->ima_measurement) {
|
||||
if (_dm_version_minor < 45) {
|
||||
log_error("WARNING: IMA measurement unsupported by "
|
||||
"kernel. Aborting operation.");
|
||||
goto bad;
|
||||
}
|
||||
dmi->flags |= DM_IMA_MEASUREMENT_FLAG;
|
||||
}
|
||||
|
||||
dmi->target_count = count;
|
||||
dmi->event_nr = dmt->event_nr;
|
||||
@@ -1523,7 +1334,7 @@ static int _process_mapper_dir(struct dm_task *dmt)
|
||||
}
|
||||
|
||||
if (closedir(d))
|
||||
log_sys_debug("closedir", dir);
|
||||
log_sys_error("closedir", dir);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1595,7 +1406,8 @@ static int _udev_complete(struct dm_task *dmt)
|
||||
static int _check_uevent_generated(struct dm_ioctl *dmi)
|
||||
{
|
||||
if (!dm_check_version() ||
|
||||
((_dm_version == 4) ? _dm_version_minor < 17 : _dm_version < 4))
|
||||
_dm_version < 4 ||
|
||||
_dm_version_minor < 17)
|
||||
/* can't check, assume uevent is generated */
|
||||
return 1;
|
||||
|
||||
@@ -1656,7 +1468,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
||||
task->head = dmt->head;
|
||||
task->tail = dmt->tail;
|
||||
task->secure_data = dmt->secure_data;
|
||||
task->ima_measurement = dmt->ima_measurement;
|
||||
|
||||
r = dm_task_run(task);
|
||||
|
||||
@@ -1771,30 +1582,23 @@ static int _reload_with_suppression_v4(struct dm_task *dmt)
|
||||
t2->params[len] = '\0';
|
||||
|
||||
if (t1->start != t2->start) {
|
||||
log_debug("reload %u:%u diff start %llu %llu type %s %s", task->major, task->minor,
|
||||
(unsigned long long)t1->start, (unsigned long long)t2->start, t1->type, t2->type);
|
||||
log_debug("reload %u:%u start diff", task->major, task->minor);
|
||||
goto no_match;
|
||||
}
|
||||
if (t1->length != t2->length) {
|
||||
log_debug("reload %u:%u diff length %llu %llu type %s %s", task->major, task->minor,
|
||||
(unsigned long long)t1->length, (unsigned long long)t2->length, t1->type, t2->type);
|
||||
log_debug("reload %u:%u length diff", task->major, task->minor);
|
||||
goto no_match;
|
||||
}
|
||||
if (strcmp(t1->type, t2->type)) {
|
||||
log_debug("reload %u:%u diff type %s %s", task->major, task->minor, t1->type, t2->type);
|
||||
log_debug("reload %u:%u type diff %s %s", task->major, task->minor, t1->type, t2->type);
|
||||
goto no_match;
|
||||
}
|
||||
if (strcmp(t1->params, t2->params)) {
|
||||
if (dmt->skip_reload_params_compare) {
|
||||
log_debug("reload %u:%u diff params ignore for type %s",
|
||||
task->major, task->minor, t1->type);
|
||||
log_debug("reload params1 %s", t1->params);
|
||||
log_debug("reload params2 %s", t2->params);
|
||||
} else {
|
||||
log_debug("reload %u:%u diff params for type %s",
|
||||
task->major, task->minor, t1->type);
|
||||
log_debug("reload params1 %s", t1->params);
|
||||
log_debug("reload params2 %s", t2->params);
|
||||
if (dmt->skip_reload_params_compare)
|
||||
log_debug("reload %u:%u skip params ignore %s %s",
|
||||
task->major, task->minor, t1->params, t2->params);
|
||||
else {
|
||||
log_debug("reload %u:%u params diff", task->major, task->minor);
|
||||
goto no_match;
|
||||
}
|
||||
}
|
||||
@@ -1961,34 +1765,23 @@ static int _do_dm_ioctl_unmangle_string(char *str, const char *str_name,
|
||||
static int _dm_ioctl_unmangle_names(int type, struct dm_ioctl *dmi)
|
||||
{
|
||||
char buf[DM_NAME_LEN];
|
||||
char buf_uuid[DM_UUID_LEN];
|
||||
struct dm_name_list *names;
|
||||
struct dm_names *names;
|
||||
unsigned next = 0;
|
||||
char *name;
|
||||
int r = 1;
|
||||
uint32_t *event_nr;
|
||||
char *uuid_ptr;
|
||||
dm_string_mangling_t mangling_mode = dm_get_name_mangling_mode();
|
||||
|
||||
if ((name = dmi->name))
|
||||
r &= _do_dm_ioctl_unmangle_string(name, "name", buf, sizeof(buf),
|
||||
mangling_mode);
|
||||
r = _do_dm_ioctl_unmangle_string(name, "name", buf, sizeof(buf),
|
||||
dm_get_name_mangling_mode());
|
||||
|
||||
if (type == DM_DEVICE_LIST &&
|
||||
((names = ((struct dm_name_list *) ((char *)dmi + dmi->data_start)))) &&
|
||||
((names = ((struct dm_names *) ((char *)dmi + dmi->data_start)))) &&
|
||||
names->dev) {
|
||||
do {
|
||||
names = (struct dm_name_list *)((char *) names + next);
|
||||
event_nr = _align_ptr(names->name + strlen(names->name) + 1);
|
||||
r &= _do_dm_ioctl_unmangle_string(names->name, "name",
|
||||
buf, sizeof(buf), mangling_mode);
|
||||
/* Unmangle also UUID within same loop */
|
||||
if (_check_has_event_nr() &&
|
||||
(event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
|
||||
uuid_ptr = _align_ptr(event_nr + 2);
|
||||
r &= _do_dm_ioctl_unmangle_string(uuid_ptr, "UUID", buf_uuid,
|
||||
sizeof(buf_uuid), mangling_mode);
|
||||
}
|
||||
names = (struct dm_names *)((char *) names + next);
|
||||
r = _do_dm_ioctl_unmangle_string(names->name, "name",
|
||||
buf, sizeof(buf),
|
||||
dm_get_name_mangling_mode());
|
||||
next = names->next;
|
||||
} while (next);
|
||||
}
|
||||
@@ -2081,7 +1874,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
}
|
||||
|
||||
log_debug_activation("dm %s %s%s %s%s%s %s%.0d%s%.0d%s"
|
||||
"%s[ %s%s%s%s%s%s%s%s%s%s] %.0" PRIu64 " %s [%u] (*%u)",
|
||||
"%s[ %s%s%s%s%s%s%s%s%s] %.0" PRIu64 " %s [%u] (*%u)",
|
||||
_cmd_data_v4[dmt->type].name,
|
||||
dmt->new_uuid ? "UUID " : "",
|
||||
dmi->name, dmi->uuid, dmt->newname ? " " : "",
|
||||
@@ -2099,7 +1892,6 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
dmt->retry_remove ? "retryremove " : "",
|
||||
dmt->deferred_remove ? "deferredremove " : "",
|
||||
dmt->secure_data ? "securedata " : "",
|
||||
dmt->ima_measurement ? "ima_measurement " : "",
|
||||
dmt->query_inactive_table ? "inactive " : "",
|
||||
dmt->enable_checks ? "enablechecks " : "",
|
||||
dmt->sector, _sanitise_message(dmt->message),
|
||||
@@ -2392,3 +2184,52 @@ void dm_lib_exit(void)
|
||||
_version_ok = 1;
|
||||
_version_checked = 0;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
/*
|
||||
* Maintain binary backward compatibility.
|
||||
* Version script mechanism works with 'gcc' compatible compilers only.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This following code is here to retain ABI compatibility after adding
|
||||
* the field deferred_remove to struct dm_info in version 1.02.89.
|
||||
*
|
||||
* Binaries linked against version 1.02.88 of libdevmapper or earlier
|
||||
* will use this function that returns dm_info without the
|
||||
* deferred_remove field.
|
||||
*
|
||||
* Binaries compiled against version 1.02.89 onwards will use
|
||||
* the new function dm_task_get_info_with_deferred_remove due to the
|
||||
* #define.
|
||||
*
|
||||
* N.B. Keep this function at the end of the file to make sure that
|
||||
* no code in this file accidentally calls it.
|
||||
*/
|
||||
|
||||
int dm_task_get_info_base(struct dm_task *dmt, struct dm_info *info);
|
||||
int dm_task_get_info_base(struct dm_task *dmt, struct dm_info *info)
|
||||
{
|
||||
struct dm_info new_info;
|
||||
|
||||
if (!dm_task_get_info(dmt, &new_info))
|
||||
return 0;
|
||||
|
||||
memcpy(info, &new_info, offsetof(struct dm_info, deferred_remove));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_get_info_with_deferred_remove(struct dm_task *dmt, struct dm_info *info);
|
||||
int dm_task_get_info_with_deferred_remove(struct dm_task *dmt, struct dm_info *info)
|
||||
{
|
||||
struct dm_info new_info;
|
||||
|
||||
if (!dm_task_get_info(dmt, &new_info))
|
||||
return 0;
|
||||
|
||||
memcpy(info, &new_info, offsetof(struct dm_info, internal_suspend));
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -70,7 +70,6 @@ struct dm_task {
|
||||
int enable_checks;
|
||||
int expected_errno;
|
||||
int ioctl_errno;
|
||||
int ima_measurement;
|
||||
|
||||
int record_timestamp;
|
||||
|
||||
|
||||
@@ -338,7 +338,6 @@ struct dm_task *dm_task_create(int type)
|
||||
dmt->new_uuid = 0;
|
||||
dmt->secure_data = 0;
|
||||
dmt->record_timestamp = 0;
|
||||
dmt->ima_measurement = 0;
|
||||
|
||||
return dmt;
|
||||
}
|
||||
@@ -383,7 +382,7 @@ static int _find_dm_name_of_device(dev_t st_rdev, char *buf, size_t buf_len)
|
||||
}
|
||||
|
||||
if (closedir(d))
|
||||
log_sys_debug("closedir", _dm_dir);
|
||||
log_sys_error("closedir", _dm_dir);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -932,7 +931,7 @@ int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
static int _selabel_lookup(const char *path, mode_t mode,
|
||||
char **scontext)
|
||||
security_context_t *scontext)
|
||||
{
|
||||
#ifdef HAVE_SELINUX_LABEL_H
|
||||
if (!_selabel_handle &&
|
||||
@@ -975,7 +974,7 @@ static int _is_selinux_enabled(void)
|
||||
int dm_prepare_selinux_context(const char *path, mode_t mode)
|
||||
{
|
||||
#ifdef HAVE_SELINUX
|
||||
char *scontext = NULL;
|
||||
security_context_t scontext = NULL;
|
||||
|
||||
if (_is_selinux_enabled() <= 0)
|
||||
return 1;
|
||||
@@ -1003,7 +1002,7 @@ int dm_prepare_selinux_context(const char *path, mode_t mode)
|
||||
int dm_set_selinux_context(const char *path, mode_t mode)
|
||||
{
|
||||
#ifdef HAVE_SELINUX
|
||||
char *scontext = NULL;
|
||||
security_context_t scontext = NULL;
|
||||
|
||||
if (_is_selinux_enabled() <= 0)
|
||||
return 1;
|
||||
@@ -1225,7 +1224,7 @@ int get_dev_node_read_ahead(const char *dev_name, uint32_t major, uint32_t minor
|
||||
int len;
|
||||
int r = 1;
|
||||
int fd;
|
||||
long read_ahead_long = 0;
|
||||
long read_ahead_long;
|
||||
|
||||
/*
|
||||
* If we know the device number, use sysfs if we can.
|
||||
@@ -1446,7 +1445,7 @@ struct node_op_parms {
|
||||
char *old_name;
|
||||
int warn_if_udev_failed;
|
||||
unsigned rely_on_udev;
|
||||
char names[0];
|
||||
char names[];
|
||||
};
|
||||
|
||||
static void _store_str(char **pos, char **ptr, const char *str)
|
||||
@@ -1921,7 +1920,7 @@ static int _sysfs_find_kernel_name(uint32_t major, uint32_t minor, char *buf, si
|
||||
continue;
|
||||
|
||||
if ((sz = dm_snprintf(path, sizeof(path), "%sblock/%s/dev",
|
||||
_sysfs_dir, name)) < 5) {
|
||||
_sysfs_dir, name)) == -1) {
|
||||
log_warn("Couldn't create path for %s.", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -599,7 +599,7 @@ static struct dm_config_node *_section(struct parser *p, struct dm_config_node *
|
||||
match(TOK_IDENTIFIER);
|
||||
}
|
||||
|
||||
if (!*str) {
|
||||
if (!strlen(str)) {
|
||||
log_error("Parse error at byte %" PRIptrdiff_t " (line %d): empty section identifier",
|
||||
p->tb - p->fb + 1, p->line);
|
||||
return NULL;
|
||||
@@ -983,7 +983,7 @@ static const char *_find_config_str(const void *start, node_lookup_fn find_fn,
|
||||
}
|
||||
|
||||
if (fail)
|
||||
log_very_verbose("%s not found in config: defaulting to \"%s\"",
|
||||
log_very_verbose("%s not found in config: defaulting to %s",
|
||||
path, fail);
|
||||
return fail;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,6 @@ struct load_segment {
|
||||
uint32_t device_id; /* Thin */
|
||||
|
||||
// VDO params
|
||||
uint32_t vdo_version; /* VDO - version of target table line */
|
||||
struct dm_tree_node *vdo_data; /* VDO */
|
||||
struct dm_vdo_target_params vdo_params; /* VDO */
|
||||
const char *vdo_name; /* VDO - device name is ALSO passed as table arg */
|
||||
@@ -331,7 +330,16 @@ struct dm_tree_node {
|
||||
dm_node_callback_fn callback;
|
||||
void *callback_data;
|
||||
|
||||
int activated; /* tracks activation during preload */
|
||||
/*
|
||||
* TODO:
|
||||
* Add advanced code which tracks of send ioctls and their
|
||||
* proper revert operation for more advanced recovery
|
||||
* Current code serves mostly only to recovery when
|
||||
* thin pool metadata check fails and command would
|
||||
* have left active thin data and metadata subvolumes.
|
||||
*/
|
||||
struct dm_list activated; /* Head of activated nodes for preload revert */
|
||||
struct dm_list activated_list; /* List of activated nodes for preload revert */
|
||||
};
|
||||
|
||||
struct dm_tree {
|
||||
@@ -366,18 +374,19 @@ struct dm_tree *dm_tree_create(void)
|
||||
dtree->root.dtree = dtree;
|
||||
dm_list_init(&dtree->root.uses);
|
||||
dm_list_init(&dtree->root.used_by);
|
||||
dm_list_init(&dtree->root.activated);
|
||||
dtree->skip_lockfs = 0;
|
||||
dtree->no_flush = 0;
|
||||
dtree->mem = dmem;
|
||||
dtree->optional_uuid_suffixes = NULL;
|
||||
|
||||
if (!(dtree->devs = dm_hash_create(61))) {
|
||||
if (!(dtree->devs = dm_hash_create(8))) {
|
||||
log_error("dtree hash creation failed");
|
||||
dm_pool_destroy(dtree->mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(dtree->uuids = dm_hash_create(31))) {
|
||||
if (!(dtree->uuids = dm_hash_create(32))) {
|
||||
log_error("dtree uuid hash creation failed");
|
||||
dm_hash_destroy(dtree->devs);
|
||||
dm_pool_destroy(dtree->mem);
|
||||
@@ -550,6 +559,7 @@ static struct dm_tree_node *_create_dm_tree_node(struct dm_tree *dtree,
|
||||
|
||||
dm_list_init(&node->uses);
|
||||
dm_list_init(&node->used_by);
|
||||
dm_list_init(&node->activated);
|
||||
dm_list_init(&node->props.segs);
|
||||
|
||||
dev = MKDEV(info->major, info->minor);
|
||||
@@ -605,7 +615,7 @@ static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
|
||||
default_uuid_prefix = dm_uuid_prefix();
|
||||
default_uuid_prefix_len = strlen(default_uuid_prefix);
|
||||
|
||||
if (suffix_list && (suffix_position = strrchr(uuid, '-'))) {
|
||||
if (suffix_list && (suffix_position = rindex(uuid, '-'))) {
|
||||
while ((suffix = suffix_list[i++])) {
|
||||
if (strcmp(suffix_position + 1, suffix))
|
||||
continue;
|
||||
@@ -2177,7 +2187,7 @@ static int _create_node(struct dm_tree_node *dnode, struct dm_tree_node *parent)
|
||||
}
|
||||
|
||||
if (r)
|
||||
dnode->activated = 1;
|
||||
dm_list_add_h(&parent->activated, &dnode->activated_list);
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
@@ -2372,7 +2382,7 @@ static int _mirror_emit_segment_line(struct dm_task *dmt, struct load_segment *s
|
||||
|
||||
EMIT_PARAMS(pos, " %u ", seg->mirror_area_count);
|
||||
|
||||
if (!_emit_areas_line(dmt, seg, params, paramsize, &pos))
|
||||
if (_emit_areas_line(dmt, seg, params, paramsize, &pos) <= 0)
|
||||
return_0;
|
||||
|
||||
if (handle_errors)
|
||||
@@ -2574,7 +2584,7 @@ static int _raid_emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
/* Print number of metadata/data device pairs */
|
||||
EMIT_PARAMS(pos, " %u", area_count);
|
||||
|
||||
if (!_emit_areas_line(dmt, seg, params, paramsize, &pos))
|
||||
if (_emit_areas_line(dmt, seg, params, paramsize, &pos) <= 0)
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
@@ -2634,7 +2644,7 @@ static int _cache_emit_segment_line(struct dm_task *dmt,
|
||||
EMIT_PARAMS(pos, " %s", name);
|
||||
|
||||
/* Do not pass migration_threshold 2048 which is default */
|
||||
EMIT_PARAMS(pos, " %u", (seg->policy_argc + ((seg->migration_threshold != 2048) ? 1 : 0)) * 2);
|
||||
EMIT_PARAMS(pos, " %u", (seg->policy_argc + (seg->migration_threshold != 2048) ? 1 : 0) * 2);
|
||||
if (seg->migration_threshold != 2048)
|
||||
EMIT_PARAMS(pos, " migration_threshold %u", seg->migration_threshold);
|
||||
if (seg->policy_settings)
|
||||
@@ -2679,10 +2689,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
|
||||
count += 1;
|
||||
if (seg->writecache_settings.max_age_set)
|
||||
count += 2;
|
||||
if (seg->writecache_settings.metadata_only_set)
|
||||
count += 1;
|
||||
if (seg->writecache_settings.pause_writeback_set)
|
||||
count += 2;
|
||||
if (seg->writecache_settings.new_key)
|
||||
count += 2;
|
||||
|
||||
@@ -2734,14 +2740,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
|
||||
EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age);
|
||||
}
|
||||
|
||||
if (seg->writecache_settings.metadata_only_set) {
|
||||
EMIT_PARAMS(pos, " metadata_only");
|
||||
}
|
||||
|
||||
if (seg->writecache_settings.pause_writeback_set) {
|
||||
EMIT_PARAMS(pos, " pause_writeback %u", seg->writecache_settings.pause_writeback);
|
||||
}
|
||||
|
||||
if (seg->writecache_settings.new_key) {
|
||||
EMIT_PARAMS(pos, " %s %s",
|
||||
seg->writecache_settings.new_key,
|
||||
@@ -2826,9 +2824,6 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
|
||||
if (set->sectors_per_bit_set)
|
||||
EMIT_PARAMS(pos, " sectors_per_bit:%llu", (unsigned long long)set->sectors_per_bit);
|
||||
|
||||
if (!dm_task_secure_data(dmt))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2862,18 +2857,13 @@ static int _thin_pool_emit_segment_line(struct dm_task *dmt,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t minor,
|
||||
static int _vdo_emit_segment_line(struct dm_task *dmt,
|
||||
struct load_segment *seg,
|
||||
char *params, size_t paramsize)
|
||||
{
|
||||
int pos = 0;
|
||||
char data[DM_FORMAT_DEV_BUFSIZE];
|
||||
char data_dev[128]; // for /dev/dm-XXXX
|
||||
uint64_t logical_blocks;
|
||||
struct dm_task *vdo_dmt;
|
||||
uint64_t start, length = 0;
|
||||
char *type = NULL;
|
||||
char *vdo_params = NULL;
|
||||
|
||||
if (!_build_dev_string(data, sizeof(data), seg->vdo_data))
|
||||
return_0;
|
||||
@@ -2883,59 +2873,17 @@ static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is already running VDO target, read 'existing' virtual size out of table line
|
||||
* and avoid reading it them from VDO metadata device
|
||||
*
|
||||
* NOTE: ATM VDO virtual size can be ONLY extended thus it's simple to recongnize 'right' size.
|
||||
* However if there would be supported also reduction, this check would need to check range.
|
||||
*/
|
||||
if ((vdo_dmt = dm_task_create(DM_DEVICE_TABLE))) {
|
||||
if (dm_task_set_major(vdo_dmt, major) &&
|
||||
dm_task_set_minor(vdo_dmt, minor) &&
|
||||
dm_task_run(vdo_dmt)) {
|
||||
(void) dm_get_next_target(vdo_dmt, NULL, &start, &length, &type, &vdo_params);
|
||||
if (!type || strcmp(type, "vdo"))
|
||||
length = 0;
|
||||
}
|
||||
|
||||
dm_task_destroy(vdo_dmt);
|
||||
}
|
||||
|
||||
if (!length && dm_vdo_parse_logical_size(data_dev, &logical_blocks))
|
||||
length = logical_blocks * 8;
|
||||
|
||||
if (seg->size < length) {
|
||||
log_debug_activation("Correcting VDO virtual volume size from " FMTu64 " to " FMTu64 ".",
|
||||
seg->size, length);
|
||||
seg->size = length;
|
||||
}
|
||||
|
||||
if (seg->vdo_version < 4) {
|
||||
EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s ",
|
||||
data_dev,
|
||||
seg->vdo_data_size / 8, // this parameter is in 4K units
|
||||
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
|
||||
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
|
||||
seg->vdo_params.block_map_era_length,
|
||||
seg->vdo_params.use_metadata_hints ? "on" : "off" ,
|
||||
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_SYNC) ? "sync" :
|
||||
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC) ? "async" :
|
||||
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
|
||||
seg->vdo_name);
|
||||
} else {
|
||||
EMIT_PARAMS(pos, "V4 %s " FMTu64 " %u " FMTu64 " %u "
|
||||
"deduplication %s compression %s ",
|
||||
data_dev,
|
||||
seg->vdo_data_size / 8, // this parameter is in 4K units
|
||||
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
|
||||
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
|
||||
seg->vdo_params.block_map_era_length,
|
||||
seg->vdo_params.use_deduplication ? "on" : "off",
|
||||
seg->vdo_params.use_compression ? "on" : "off");
|
||||
}
|
||||
|
||||
EMIT_PARAMS(pos, "maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
|
||||
EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s "
|
||||
"maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
|
||||
data_dev,
|
||||
seg->vdo_data_size / 8, // this parameter is in 4K units
|
||||
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
|
||||
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
|
||||
seg->vdo_params.block_map_era_length,
|
||||
seg->vdo_params.use_metadata_hints ? "on" : "off" ,
|
||||
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_SYNC) ? "sync" :
|
||||
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC) ? "async" : "auto", // policy
|
||||
seg->vdo_name,
|
||||
seg->vdo_params.max_discard,
|
||||
seg->vdo_params.ack_threads,
|
||||
seg->vdo_params.bio_threads,
|
||||
@@ -2979,6 +2927,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
size_t paramsize)
|
||||
{
|
||||
int pos = 0;
|
||||
int r;
|
||||
int target_type_is_raid = 0;
|
||||
char originbuf[DM_FORMAT_DEV_BUFSIZE], cowbuf[DM_FORMAT_DEV_BUFSIZE];
|
||||
|
||||
@@ -2989,7 +2938,8 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
break;
|
||||
case SEG_MIRRORED:
|
||||
/* Mirrors are pretty complicated - now in separate function */
|
||||
if (!_mirror_emit_segment_line(dmt, seg, params, paramsize))
|
||||
r = _mirror_emit_segment_line(dmt, seg, params, paramsize);
|
||||
if (!r)
|
||||
return_0;
|
||||
break;
|
||||
case SEG_SNAPSHOT:
|
||||
@@ -3010,7 +2960,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size);
|
||||
break;
|
||||
case SEG_VDO:
|
||||
if (!_vdo_emit_segment_line(dmt, major, minor, seg, params, paramsize))
|
||||
if (!(r = _vdo_emit_segment_line(dmt, seg, params, paramsize)))
|
||||
return_0;
|
||||
break;
|
||||
case SEG_CRYPT:
|
||||
@@ -3039,8 +2989,9 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
case SEG_RAID6_LA_6:
|
||||
case SEG_RAID6_RA_6:
|
||||
target_type_is_raid = 1;
|
||||
if (!_raid_emit_segment_line(dmt, major, minor, seg, seg_start,
|
||||
params, paramsize))
|
||||
r = _raid_emit_segment_line(dmt, major, minor, seg, seg_start,
|
||||
params, paramsize);
|
||||
if (!r)
|
||||
return_0;
|
||||
|
||||
break;
|
||||
@@ -3081,9 +3032,10 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
case SEG_CRYPT:
|
||||
case SEG_LINEAR:
|
||||
case SEG_STRIPED:
|
||||
if (!_emit_areas_line(dmt, seg, params, paramsize, &pos))
|
||||
return_0;
|
||||
|
||||
if ((r = _emit_areas_line(dmt, seg, params, paramsize, &pos)) <= 0) {
|
||||
stack;
|
||||
return r;
|
||||
}
|
||||
if (!params[0]) {
|
||||
log_error("No parameters supplied for %s target "
|
||||
"%u:%u.", _dm_segtypes[seg->type].target,
|
||||
@@ -3228,29 +3180,26 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Try to deactivate only nodes created during preload. */
|
||||
static int _dm_tree_revert_activated(struct dm_tree_node *dnode)
|
||||
/*
|
||||
* Currently try to deactivate only nodes created during preload.
|
||||
* New node is always attached to the front of activated_list
|
||||
*/
|
||||
static int _dm_tree_revert_activated(struct dm_tree_node *parent)
|
||||
{
|
||||
void *handle = NULL;
|
||||
struct dm_tree_node *child;
|
||||
|
||||
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
|
||||
if (child->activated) {
|
||||
if (child->callback) {
|
||||
log_debug_activation("Dropping callback for %s.", _node_name(child));
|
||||
child->callback = NULL;
|
||||
}
|
||||
|
||||
log_debug_activation("Reverting %s.", _node_name(child));
|
||||
if (!_deactivate_node(child->name, child->info.major, child->info.minor,
|
||||
&child->dtree->cookie, child->udev_flags, 0)) {
|
||||
log_debug_activation("Unable to deactivate %s.", _node_name(child));
|
||||
return 0;
|
||||
}
|
||||
dm_list_iterate_items_gen(child, &parent->activated, activated_list) {
|
||||
log_debug_activation("Reverting %s.", _node_name(child));
|
||||
if (child->callback) {
|
||||
log_debug_activation("Dropping callback for %s.", _node_name(child));
|
||||
child->callback = NULL;
|
||||
}
|
||||
|
||||
if (dm_tree_node_num_children(child, 0) &&
|
||||
!_dm_tree_revert_activated(child))
|
||||
if (!_deactivate_node(child->name, child->info.major, child->info.minor,
|
||||
&child->dtree->cookie, child->udev_flags, 0)) {
|
||||
log_error("Unable to deactivate %s.", _node_name(child));
|
||||
return 0;
|
||||
}
|
||||
if (!_dm_tree_revert_activated(child))
|
||||
return_0;
|
||||
}
|
||||
|
||||
@@ -4029,24 +3978,6 @@ int dm_tree_node_add_thin_pool_target(struct dm_tree_node *node,
|
||||
uint32_t data_block_size,
|
||||
uint64_t low_water_mark,
|
||||
unsigned skip_block_zeroing)
|
||||
{
|
||||
return dm_tree_node_add_thin_pool_target_v1(node, size, transaction_id,
|
||||
metadata_uuid, pool_uuid,
|
||||
data_block_size,
|
||||
low_water_mark,
|
||||
skip_block_zeroing,
|
||||
1);
|
||||
}
|
||||
|
||||
int dm_tree_node_add_thin_pool_target_v1(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
uint64_t transaction_id,
|
||||
const char *metadata_uuid,
|
||||
const char *pool_uuid,
|
||||
uint32_t data_block_size,
|
||||
uint64_t low_water_mark,
|
||||
unsigned skip_block_zeroing,
|
||||
unsigned crop_metadata)
|
||||
{
|
||||
struct load_segment *seg, *mseg;
|
||||
uint64_t devsize = 0;
|
||||
@@ -4074,18 +4005,17 @@ int dm_tree_node_add_thin_pool_target_v1(struct dm_tree_node *node,
|
||||
if (!_link_tree_nodes(node, seg->metadata))
|
||||
return_0;
|
||||
|
||||
if (crop_metadata)
|
||||
/* FIXME: more complex target may need more tweaks */
|
||||
dm_list_iterate_items(mseg, &seg->metadata->props.segs) {
|
||||
devsize += mseg->size;
|
||||
if (devsize > DM_THIN_MAX_METADATA_SIZE) {
|
||||
log_debug_activation("Ignoring %" PRIu64 " of device.",
|
||||
devsize - DM_THIN_MAX_METADATA_SIZE);
|
||||
mseg->size -= (devsize - DM_THIN_MAX_METADATA_SIZE);
|
||||
devsize = DM_THIN_MAX_METADATA_SIZE;
|
||||
/* FIXME: drop remaining segs */
|
||||
}
|
||||
/* FIXME: more complex target may need more tweaks */
|
||||
dm_list_iterate_items(mseg, &seg->metadata->props.segs) {
|
||||
devsize += mseg->size;
|
||||
if (devsize > DM_THIN_MAX_METADATA_SIZE) {
|
||||
log_debug_activation("Ignoring %" PRIu64 " of device.",
|
||||
devsize - DM_THIN_MAX_METADATA_SIZE);
|
||||
mseg->size -= (devsize - DM_THIN_MAX_METADATA_SIZE);
|
||||
devsize = DM_THIN_MAX_METADATA_SIZE;
|
||||
/* FIXME: drop remaining segs */
|
||||
}
|
||||
}
|
||||
|
||||
if (!(seg->pool = dm_tree_find_node_by_uuid(node->dtree, pool_uuid))) {
|
||||
log_error("Missing pool uuid %s.", pool_uuid);
|
||||
@@ -4380,9 +4310,63 @@ void dm_tree_node_set_callback(struct dm_tree_node *dnode,
|
||||
dnode->callback_data = data;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
/*
|
||||
* Backward compatible implementations.
|
||||
*
|
||||
* Keep these at the end of the file to make sure that
|
||||
* no code in this file accidentally calls it.
|
||||
*/
|
||||
|
||||
/* Backward compatible dm_tree_node_size_changed() implementations. */
|
||||
int dm_tree_node_size_changed_base(const struct dm_tree_node *dnode);
|
||||
int dm_tree_node_size_changed_base(const struct dm_tree_node *dnode)
|
||||
{
|
||||
/* Base does not make difference between smaller and bigger */
|
||||
return dm_tree_node_size_changed(dnode) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retain ABI compatibility after adding the DM_CACHE_FEATURE_METADATA2
|
||||
* in version 1.02.138.
|
||||
*
|
||||
* Binaries compiled against version 1.02.138 onwards will use
|
||||
* the new function dm_tree_node_add_cache_target which detects unknown
|
||||
* feature flags and returns error for them.
|
||||
*/
|
||||
int dm_tree_node_add_cache_target_base(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
uint64_t feature_flags, /* DM_CACHE_FEATURE_* */
|
||||
const char *metadata_uuid,
|
||||
const char *data_uuid,
|
||||
const char *origin_uuid,
|
||||
const char *policy_name,
|
||||
const struct dm_config_node *policy_settings,
|
||||
uint32_t data_block_size);
|
||||
int dm_tree_node_add_cache_target_base(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
uint64_t feature_flags,
|
||||
const char *metadata_uuid,
|
||||
const char *data_uuid,
|
||||
const char *origin_uuid,
|
||||
const char *policy_name,
|
||||
const struct dm_config_node *policy_settings,
|
||||
uint32_t data_block_size)
|
||||
{
|
||||
/* Old version supported only these FEATURE bits, others were ignored so masked them */
|
||||
static const uint64_t _mask =
|
||||
DM_CACHE_FEATURE_WRITEBACK |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_PASSTHROUGH;
|
||||
|
||||
return dm_tree_node_add_cache_target(node, size, feature_flags & _mask,
|
||||
metadata_uuid, data_uuid, origin_uuid,
|
||||
policy_name, policy_settings, 0, 0, 0, 0, data_block_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
uint32_t vdo_version,
|
||||
const char *vdo_pool_name,
|
||||
const char *data_uuid,
|
||||
uint64_t data_size,
|
||||
@@ -4404,13 +4388,11 @@ int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
|
||||
if (!_link_tree_nodes(node, seg->vdo_data))
|
||||
return_0;
|
||||
|
||||
seg->vdo_version = vdo_version;
|
||||
seg->vdo_params = *vtp;
|
||||
seg->vdo_name = vdo_pool_name;
|
||||
seg->vdo_data_size = data_size;
|
||||
|
||||
if (seg->vdo_version < 4)
|
||||
node->props.send_messages = 2;
|
||||
node->props.send_messages = 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ int dm_is_empty_dir(const char *dir)
|
||||
DIR *d;
|
||||
|
||||
if (!(d = opendir(dir))) {
|
||||
log_sys_debug("opendir", dir);
|
||||
log_sys_error("opendir", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ int dm_is_empty_dir(const char *dir)
|
||||
break;
|
||||
|
||||
if (closedir(d))
|
||||
log_sys_debug("closedir", dir);
|
||||
log_sys_error("closedir", dir);
|
||||
|
||||
return dirent ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -384,246 +384,172 @@ int dm_report_field_percent(struct dm_report *rh,
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct pos_len {
|
||||
struct str_list_sort_value_item {
|
||||
unsigned pos;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct str_pos_len {
|
||||
const char *str;
|
||||
struct pos_len item;
|
||||
};
|
||||
|
||||
struct str_list_sort_value {
|
||||
const char *value;
|
||||
struct pos_len *items;
|
||||
struct str_list_sort_value_item *items;
|
||||
};
|
||||
|
||||
static int _str_sort_cmp(const void *a, const void *b)
|
||||
{
|
||||
return strcmp(((const struct str_pos_len *) a)->str, ((const struct str_pos_len *) b)->str);
|
||||
}
|
||||
struct str_list_sort_item {
|
||||
const char *str;
|
||||
struct str_list_sort_value_item item;
|
||||
};
|
||||
|
||||
#define FIELD_STRING_LIST_DEFAULT_DELIMITER ","
|
||||
static int _str_list_sort_item_cmp(const void *a, const void *b)
|
||||
{
|
||||
const struct str_list_sort_item *slsi_a = (const struct str_list_sort_item *) a;
|
||||
const struct str_list_sort_item *slsi_b = (const struct str_list_sort_item *) b;
|
||||
|
||||
return strcmp(slsi_a->str, slsi_b->str);
|
||||
}
|
||||
|
||||
static int _report_field_string_list(struct dm_report *rh,
|
||||
struct dm_report_field *field,
|
||||
const struct dm_list *data,
|
||||
const char *delimiter,
|
||||
int sort_repstr)
|
||||
int sort)
|
||||
{
|
||||
static const char _error_msg_prefix[] = "_report_field_string_list: ";
|
||||
unsigned int list_size, i, pos;
|
||||
struct str_pos_len *arr = NULL;
|
||||
static const char _string_list_grow_object_failed_msg[] = "dm_report_field_string_list: dm_pool_grow_object_failed";
|
||||
struct str_list_sort_value *sort_value = NULL;
|
||||
unsigned int list_size, pos, i;
|
||||
struct str_list_sort_item *arr = NULL;
|
||||
struct dm_str_list *sl;
|
||||
size_t delimiter_len, repstr_str_len, repstr_size;
|
||||
char *repstr = NULL;
|
||||
struct pos_len *repstr_extra;
|
||||
struct str_list_sort_value *sortval = NULL;
|
||||
size_t delimiter_len, len;
|
||||
void *object;
|
||||
int r = 0;
|
||||
|
||||
/*
|
||||
* The 'field->report_string' has 2 parts:
|
||||
*
|
||||
* - string representing the whole string list
|
||||
* (terminated by '\0' at its end as usual)
|
||||
*
|
||||
* - extra info beyond the end of the string representing
|
||||
* position and length of each list item within the
|
||||
* field->report_string (array of 'struct pos_len')
|
||||
*
|
||||
* We can use the extra info to unambiguously identify list items,
|
||||
* the delimiter is not enough here as it's not assured it won't appear
|
||||
* in list item itself. We will make use of this extra info in case
|
||||
* we need to apply further formatting to the list in dm_report_output
|
||||
* where the pure field->report_string is not enough for printout.
|
||||
*
|
||||
*
|
||||
* The 'field->sort_value' contains a value of type 'struct
|
||||
* str_list_sort_value' ('sortval'). This one has a pointer to the
|
||||
* 'field->report_string' string ('sortval->value') and info
|
||||
* about position and length of each list item within the string
|
||||
* (array of 'struct pos_len').
|
||||
*
|
||||
*
|
||||
* The 'field->report_string' is either in sorted or unsorted form,
|
||||
* depending on 'sort_repstr' arg.
|
||||
*
|
||||
* The 'field->sort_value.items' is always in sorted form because
|
||||
* we need that for effective sorting and selection.
|
||||
*
|
||||
* If 'field->report_string' is sorted, then field->report_string
|
||||
* and field->sort_value.items share the same array of
|
||||
* 'struct pos_len' (because they're both sorted the same way),
|
||||
* otherwise, each one has its own array.
|
||||
*
|
||||
* The very first item in the array of 'struct pos_len' is always
|
||||
* a pair denoting '[list_size,strlen(field->report_string)]'. The
|
||||
* rest of items denote start and lenght of each item in the list.
|
||||
*
|
||||
*
|
||||
* For example, if we have a list with "abc", "xy", "defgh"
|
||||
* as input and delimiter is ",", we end up with either:
|
||||
*
|
||||
* A) if we don't want the report string sorted ('sort_repstr == 0'):
|
||||
*
|
||||
* - field->report_string = repstr
|
||||
*
|
||||
* repstr repstr_extra
|
||||
* | |
|
||||
* V V
|
||||
* abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|
||||
* |____________||________________________|
|
||||
* string array of struct pos_len
|
||||
* |____||________________|
|
||||
* #items items
|
||||
*
|
||||
* - field->sort_value = sortval
|
||||
*
|
||||
* sortval->value = repstr
|
||||
* sortval->items = {[3,12],[0,3],[7,5],[4,2]}
|
||||
* (that is 'abc,defgh,xy')
|
||||
*
|
||||
*
|
||||
* B) if we want the report string sorted ('sort_repstr == 1'):
|
||||
*
|
||||
* - field->report_string = repstr
|
||||
*
|
||||
* repstr repstr_extra
|
||||
* | |
|
||||
* V V
|
||||
* abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|
||||
* |____________||________________________|
|
||||
* string array of struct pos_len
|
||||
* |____||________________|
|
||||
* #items items
|
||||
*
|
||||
* - field->sort_value = sortval
|
||||
*
|
||||
* sortval->value = repstr
|
||||
* sortval->items = repstr_extra
|
||||
* (that is 'abc,defgh,xy')
|
||||
*/
|
||||
|
||||
if (!delimiter)
|
||||
delimiter = FIELD_STRING_LIST_DEFAULT_DELIMITER;
|
||||
delimiter_len = strlen(delimiter);
|
||||
list_size = dm_list_size(data);
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(struct str_list_sort_value)))) {
|
||||
log_error("%s failed to allocate sort value structure", _error_msg_prefix);
|
||||
goto out;
|
||||
if (!(sort_value = dm_pool_zalloc(rh->mem, sizeof(struct str_list_sort_value)))) {
|
||||
log_error("dm_report_field_string_list: dm_pool_zalloc failed for sort_value");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_size = dm_list_size(data);
|
||||
|
||||
/*
|
||||
* Sort value stores the pointer to the report_string and then
|
||||
* position and length for each list element withing the report_string.
|
||||
* The first element stores number of elements in 'len' (therefore
|
||||
* list_size + 1 is used below for the extra element).
|
||||
* For example, with this input:
|
||||
* sort = 0; (we don't want to report sorted)
|
||||
* report_string = "abc,xy,defgh"; (this is reported)
|
||||
*
|
||||
* ...we end up with:
|
||||
* sort_value->value = report_string; (we'll use the original report_string for indices)
|
||||
* sort_value->items[0] = {0,3}; (we have 3 items)
|
||||
* sort_value->items[1] = {0,3}; ("abc")
|
||||
* sort_value->items[2] = {7,5}; ("defgh")
|
||||
* sort_value->items[3] = {4,2}; ("xy")
|
||||
*
|
||||
* The items alone are always sorted while in report_string they can be
|
||||
* sorted or not (based on "sort" arg) - it depends on how we prefer to
|
||||
* display the list. Having items sorted internally helps with searching
|
||||
* through them.
|
||||
*/
|
||||
if (!(sort_value->items = dm_pool_zalloc(rh->mem, (list_size + 1) * sizeof(struct str_list_sort_value_item)))) {
|
||||
log_error("dm_report_fiel_string_list: dm_pool_zalloc failed for sort value items");
|
||||
goto out;
|
||||
}
|
||||
sort_value->items[0].len = list_size;
|
||||
|
||||
/* zero items */
|
||||
if (list_size == 0) {
|
||||
field->report_string = sortval->value = "";
|
||||
sortval->items = NULL;
|
||||
field->sort_value = sortval;
|
||||
if (!list_size) {
|
||||
sort_value->value = field->report_string = "";
|
||||
field->sort_value = sort_value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* one item */
|
||||
if (list_size == 1) {
|
||||
sl = (struct dm_str_list *) dm_list_first(data);
|
||||
|
||||
repstr_str_len = strlen(sl->str);
|
||||
repstr_size = repstr_str_len + 1 + (2 * sizeof(struct pos_len));
|
||||
|
||||
if (!(repstr = dm_pool_alloc(rh->mem, repstr_size))) {
|
||||
log_error("%s failed to allocate report string structure", _error_msg_prefix);
|
||||
if (!sl ||
|
||||
!(sort_value->value = field->report_string = dm_pool_strdup(rh->mem, sl->str))) {
|
||||
log_error("dm_report_field_string_list: dm_pool_strdup failed");
|
||||
goto out;
|
||||
}
|
||||
repstr_extra = (struct pos_len *) (repstr + repstr_str_len + 1);
|
||||
|
||||
memcpy(repstr, sl->str, repstr_str_len + 1);
|
||||
memcpy(repstr_extra, &((struct pos_len) {.pos = 1, .len = repstr_str_len}), sizeof(struct pos_len));
|
||||
memcpy(repstr_extra + 1, &((struct pos_len) {.pos = 0, .len = repstr_str_len}), sizeof(struct pos_len));
|
||||
|
||||
sortval->value = field->report_string = repstr;
|
||||
sortval->items = repstr_extra;
|
||||
field->sort_value = sortval;
|
||||
sort_value->items[1].pos = 0;
|
||||
sort_value->items[1].len = strlen(sl->str);
|
||||
field->sort_value = sort_value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* more than one item - allocate temporary array for string list items for further processing */
|
||||
if (!(arr = malloc(list_size * sizeof(struct str_pos_len)))) {
|
||||
log_error("%s failed to allocate temporary array for processing", _error_msg_prefix);
|
||||
/* more than one item - sort the list */
|
||||
if (!(arr = malloc(sizeof(struct str_list_sort_item) * list_size))) {
|
||||
log_error("dm_report_field_string_list: malloc failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
repstr_size = 0;
|
||||
if (!(dm_pool_begin_object(rh->mem, 256))) {
|
||||
log_error(_string_list_grow_object_failed_msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!delimiter)
|
||||
delimiter = ",";
|
||||
delimiter_len = strlen(delimiter);
|
||||
|
||||
i = pos = len = 0;
|
||||
dm_list_iterate_items(sl, data) {
|
||||
arr[i].str = sl->str;
|
||||
repstr_size += (arr[i].item.len = strlen(sl->str));
|
||||
if (!sort) {
|
||||
/* sorted outpud not required - report the list as it is */
|
||||
len = strlen(sl->str);
|
||||
if (!dm_pool_grow_object(rh->mem, arr[i].str, len) ||
|
||||
(i+1 != list_size && !dm_pool_grow_object(rh->mem, delimiter, delimiter_len))) {
|
||||
log_error(_string_list_grow_object_failed_msg);
|
||||
goto out;
|
||||
}
|
||||
arr[i].item.pos = pos;
|
||||
arr[i].item.len = len;
|
||||
pos = i+1 == list_size ? pos+len : pos+len+delimiter_len;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, repstr_size contains sum of lengths of all string list items.
|
||||
* Now, add these to the repstr_size:
|
||||
*
|
||||
* --> sum of character count used by all delimiters: + ((list_size - 1) * delimiter_len)
|
||||
*
|
||||
* --> '\0' used at the end of the string list: + 1
|
||||
*
|
||||
* --> sum of structures used to keep info about pos and length of each string list item:
|
||||
* [0, <list_size>] [<pos1>,<size1>] [<pos2>,<size2>] ...
|
||||
* That is: + ((list_size + 1) * sizeof(struct pos_len))
|
||||
*/
|
||||
repstr_size += ((list_size - 1) * delimiter_len);
|
||||
repstr_str_len = repstr_size;
|
||||
repstr_size += 1 + ((list_size + 1) * sizeof(struct pos_len));
|
||||
qsort(arr, i, sizeof(struct str_list_sort_item), _str_list_sort_item_cmp);
|
||||
|
||||
if (sort_repstr)
|
||||
qsort(arr, list_size, sizeof(struct str_pos_len), _str_sort_cmp);
|
||||
for (i = 0, pos = 0; i < list_size; i++) {
|
||||
if (sort) {
|
||||
/* sorted output required - report the list as sorted */
|
||||
len = strlen(arr[i].str);
|
||||
if (!dm_pool_grow_object(rh->mem, arr[i].str, len) ||
|
||||
(i+1 != list_size && !dm_pool_grow_object(rh->mem, delimiter, delimiter_len))) {
|
||||
log_error(_string_list_grow_object_failed_msg);
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* Save position and length of the string
|
||||
* element in report_string for sort_value.
|
||||
* Use i+1 here since items[0] stores list size!!!
|
||||
*/
|
||||
sort_value->items[i+1].pos = pos;
|
||||
sort_value->items[i+1].len = len;
|
||||
pos = i+1 == list_size ? pos+len : pos+len+delimiter_len;
|
||||
} else {
|
||||
sort_value->items[i+1].pos = arr[i].item.pos;
|
||||
sort_value->items[i+1].len = arr[i].item.len;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(repstr = dm_pool_alloc(rh->mem, repstr_size))) {
|
||||
log_error("%s failed to allocate report string structure", _error_msg_prefix);
|
||||
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
|
||||
log_error(_string_list_grow_object_failed_msg);
|
||||
goto out;
|
||||
}
|
||||
repstr_extra = (struct pos_len *) (repstr + repstr_str_len + 1);
|
||||
|
||||
memcpy(repstr_extra, &(struct pos_len) {.pos = list_size, .len = repstr_str_len}, sizeof(struct pos_len));
|
||||
for (i = 0, pos = 0; i < list_size; i++) {
|
||||
arr[i].item.pos = pos;
|
||||
|
||||
memcpy(repstr + pos, arr[i].str, arr[i].item.len);
|
||||
memcpy(repstr_extra + i + 1, &arr[i].item, sizeof(struct pos_len));
|
||||
|
||||
pos += arr[i].item.len;
|
||||
if (i + 1 < list_size) {
|
||||
memcpy(repstr + pos, delimiter, delimiter_len);
|
||||
pos += delimiter_len;
|
||||
}
|
||||
}
|
||||
*(repstr + pos) = '\0';
|
||||
|
||||
sortval->value = repstr;
|
||||
if (sort_repstr)
|
||||
sortval->items = repstr_extra;
|
||||
else {
|
||||
if (!(sortval->items = dm_pool_alloc(rh->mem, (list_size + 1) * sizeof(struct pos_len)))) {
|
||||
log_error("%s failed to allocate array of items inside sort value structure",
|
||||
_error_msg_prefix);
|
||||
goto out;
|
||||
}
|
||||
|
||||
qsort(arr, list_size, sizeof(struct str_pos_len), _str_sort_cmp);
|
||||
|
||||
sortval->items[0] = (struct pos_len) {.pos = list_size, .len = repstr_str_len};
|
||||
for (i = 0; i < list_size; i++)
|
||||
sortval->items[i+1] = arr[i].item;
|
||||
}
|
||||
|
||||
field->report_string = repstr;
|
||||
field->sort_value = sortval;
|
||||
object = dm_pool_end_object(rh->mem);
|
||||
sort_value->value = object;
|
||||
field->sort_value = sort_value;
|
||||
field->report_string = object;
|
||||
r = 1;
|
||||
out:
|
||||
if (!r && sortval)
|
||||
dm_pool_free(rh->mem, sortval);
|
||||
if (!r && sort_value)
|
||||
dm_pool_free(rh->mem, sort_value);
|
||||
free(arr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1762,7 +1688,7 @@ static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *v
|
||||
struct dm_str_list *sel_item;
|
||||
unsigned int i = 1;
|
||||
|
||||
if (!val->items) {
|
||||
if (!val->items[0].len) {
|
||||
if (sel_list_size == 1) {
|
||||
/* match blank string list with selection defined as blank string only */
|
||||
sel_item = dm_list_item(dm_list_first(&sel->str_list.list), struct dm_str_list);
|
||||
@@ -1772,7 +1698,7 @@ static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *v
|
||||
}
|
||||
|
||||
/* if item count differs, it's clear the lists do not match */
|
||||
if (val->items[0].pos != sel_list_size)
|
||||
if (val->items[0].len != sel_list_size)
|
||||
return 0;
|
||||
|
||||
/* both lists are sorted so they either match 1:1 or not */
|
||||
@@ -1795,7 +1721,7 @@ static int _cmp_field_string_list_subset_all(const struct str_list_sort_value *v
|
||||
unsigned int i, last_found = 1;
|
||||
int r = 0;
|
||||
|
||||
if (!val->items) {
|
||||
if (!val->items[0].len) {
|
||||
if (sel_list_size == 1) {
|
||||
/* match blank string list with selection defined as blank string only */
|
||||
sel_item = dm_list_item(dm_list_first(&sel->str_list.list), struct dm_str_list);
|
||||
@@ -1807,7 +1733,7 @@ static int _cmp_field_string_list_subset_all(const struct str_list_sort_value *v
|
||||
/* check selection is a subset of the value */
|
||||
dm_list_iterate_items(sel_item, &sel->str_list.list) {
|
||||
r = 0;
|
||||
for (i = last_found; i <= val->items[0].pos; i++) {
|
||||
for (i = last_found; i <= val->items[0].len; i++) {
|
||||
if ((strlen(sel_item->str) == val->items[i].len) &&
|
||||
!strncmp(sel_item->str, val->value + val->items[i].pos, val->items[i].len)) {
|
||||
last_found = i;
|
||||
@@ -1829,7 +1755,7 @@ static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
|
||||
unsigned int i;
|
||||
|
||||
/* match blank string list with selection that contains blank string */
|
||||
if (!val->items) {
|
||||
if (!val->items[0].len) {
|
||||
dm_list_iterate_items(sel_item, &sel->str_list.list) {
|
||||
if (!strcmp(sel_item->str, ""))
|
||||
return 1;
|
||||
@@ -1842,7 +1768,7 @@ static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
|
||||
* TODO: Optimize this so we don't need to compare the whole lists' content.
|
||||
* Make use of the fact that the lists are sorted!
|
||||
*/
|
||||
for (i = 1; i <= val->items[0].pos; i++) {
|
||||
for (i = 1; i <= val->items[0].len; i++) {
|
||||
if ((strlen(sel_item->str) == val->items[i].len) &&
|
||||
!strncmp(sel_item->str, val->value + val->items[i].pos, val->items[i].len))
|
||||
return 1;
|
||||
@@ -2406,7 +2332,7 @@ static const char *_reserved_name(struct dm_report *rh,
|
||||
uint32_t field_num, const char *s, size_t len)
|
||||
{
|
||||
dm_report_reserved_handler handler;
|
||||
const char *canonical_name = NULL;
|
||||
const char *canonical_name;
|
||||
const char **name;
|
||||
char *tmp_s;
|
||||
char c;
|
||||
@@ -2548,7 +2474,7 @@ dm_percent_t dm_make_percent(uint64_t numerator, uint64_t denominator)
|
||||
|
||||
int dm_report_value_cache_set(struct dm_report *rh, const char *name, const void *data)
|
||||
{
|
||||
if (!rh->value_cache && (!(rh->value_cache = dm_hash_create(63)))) {
|
||||
if (!rh->value_cache && (!(rh->value_cache = dm_hash_create(64)))) {
|
||||
log_error("Failed to create cache for values used during reporting.");
|
||||
return 0;
|
||||
}
|
||||
@@ -3848,7 +3774,7 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
|
||||
struct field_selection *fs;
|
||||
struct selection_node *sn;
|
||||
const char *ws, *we; /* field name */
|
||||
const char *vs = NULL, *ve = NULL; /* value */
|
||||
const char *vs, *ve; /* value */
|
||||
const char *last;
|
||||
uint32_t flags, field_num;
|
||||
int implicit;
|
||||
@@ -3984,7 +3910,7 @@ static struct selection_node *_parse_ex(struct dm_report *rh,
|
||||
static const char _pe_expected_msg[] = "Syntax error: right parenthesis expected at \'%s\'";
|
||||
struct selection_node *sn = NULL;
|
||||
uint32_t t;
|
||||
const char *tmp = NULL;
|
||||
const char *tmp;
|
||||
|
||||
t = _tok_op_log(s, next, SEL_MODIFIER_NOT | SEL_PRECEDENCE_PS);
|
||||
if (t == SEL_MODIFIER_NOT) {
|
||||
@@ -4030,7 +3956,7 @@ static struct selection_node *_parse_and_ex(struct dm_report *rh,
|
||||
struct selection_node *and_sn)
|
||||
{
|
||||
struct selection_node *n;
|
||||
const char *tmp = NULL;
|
||||
const char *tmp;
|
||||
|
||||
n = _parse_ex(rh, s, next);
|
||||
if (!n)
|
||||
@@ -4062,7 +3988,7 @@ static struct selection_node *_parse_or_ex(struct dm_report *rh,
|
||||
struct selection_node *or_sn)
|
||||
{
|
||||
struct selection_node *n;
|
||||
const char *tmp = NULL;
|
||||
const char *tmp;
|
||||
|
||||
n = _parse_and_ex(rh, s, next, NULL);
|
||||
if (!n)
|
||||
@@ -4434,7 +4360,6 @@ static int _sort_rows(struct dm_report *rh)
|
||||
#define JSON_ARRAY_START "["
|
||||
#define JSON_ARRAY_END "]"
|
||||
#define JSON_ESCAPE_CHAR "\\"
|
||||
#define JSON_NULL "null"
|
||||
|
||||
#define UNABLE_TO_EXTEND_OUTPUT_LINE_MSG "dm_report: Unable to extend output line"
|
||||
|
||||
@@ -4444,42 +4369,38 @@ static int _is_basic_report(struct dm_report *rh)
|
||||
(rh->group_item->group->type == DM_REPORT_GROUP_BASIC);
|
||||
}
|
||||
|
||||
static int _is_json_std_report(struct dm_report *rh)
|
||||
{
|
||||
return rh->group_item &&
|
||||
rh->group_item->group->type == DM_REPORT_GROUP_JSON_STD;
|
||||
}
|
||||
|
||||
static int _is_json_report(struct dm_report *rh)
|
||||
{
|
||||
return rh->group_item &&
|
||||
(rh->group_item->group->type == DM_REPORT_GROUP_JSON ||
|
||||
rh->group_item->group->type == DM_REPORT_GROUP_JSON_STD);
|
||||
(rh->group_item->group->type == DM_REPORT_GROUP_JSON);
|
||||
}
|
||||
|
||||
static int _is_pure_numeric_field(struct dm_report_field *field)
|
||||
{
|
||||
return field->props->flags & (DM_REPORT_FIELD_TYPE_NUMBER | DM_REPORT_FIELD_TYPE_PERCENT);
|
||||
}
|
||||
|
||||
static const char *_get_field_id(struct dm_report *rh, struct dm_report_field *field)
|
||||
/*
|
||||
* Produce report output
|
||||
*/
|
||||
static int _output_field(struct dm_report *rh, struct dm_report_field *field)
|
||||
{
|
||||
const struct dm_report_field_type *fields = field->props->implicit ? _implicit_report_fields
|
||||
: rh->fields;
|
||||
|
||||
return fields[field->props->field_num].id;
|
||||
}
|
||||
|
||||
static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field *field)
|
||||
{
|
||||
char *field_id;
|
||||
int32_t width;
|
||||
uint32_t align;
|
||||
const char *repstr;
|
||||
const char *p1_repstr, *p2_repstr;
|
||||
char *buf = NULL;
|
||||
size_t buf_size = 0;
|
||||
|
||||
if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
|
||||
if (!(field_id = strdup(_get_field_id(rh, field)))) {
|
||||
if (_is_json_report(rh)) {
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
|
||||
!dm_pool_grow_object(rh->mem, fields[field->props->field_num].id, 0) ||
|
||||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
|
||||
!dm_pool_grow_object(rh->mem, JSON_PAIR, 1) ||
|
||||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
return 0;
|
||||
}
|
||||
} else if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
|
||||
if (!(field_id = strdup(fields[field->props->field_num].id))) {
|
||||
log_error("dm_report: Failed to copy field name");
|
||||
return 0;
|
||||
}
|
||||
@@ -4510,14 +4431,43 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
|
||||
}
|
||||
}
|
||||
|
||||
if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
|
||||
repstr = field->report_string;
|
||||
width = field->props->width;
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) {
|
||||
if (_is_json_report(rh)) {
|
||||
/* Escape any JSON_QUOTE that may appear in reported string. */
|
||||
p1_repstr = repstr;
|
||||
while ((p2_repstr = strstr(p1_repstr, JSON_QUOTE))) {
|
||||
if (p2_repstr > p1_repstr) {
|
||||
if (!dm_pool_grow_object(rh->mem, p1_repstr, p2_repstr - p1_repstr)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_ESCAPE_CHAR, 1) ||
|
||||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
p1_repstr = p2_repstr + 1;
|
||||
}
|
||||
|
||||
if (!dm_pool_grow_object(rh->mem, p1_repstr, 0)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!dm_pool_grow_object(rh->mem, repstr, 0)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
|
||||
align = ((field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ||
|
||||
(field->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) ?
|
||||
(field->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) ?
|
||||
DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
|
||||
|
||||
width = field->props->width;
|
||||
|
||||
/* Including trailing '\0'! */
|
||||
buf_size = width + 1;
|
||||
if (!(buf = malloc(buf_size))) {
|
||||
@@ -4527,7 +4477,7 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
|
||||
|
||||
if (align & DM_REPORT_FIELD_ALIGN_LEFT) {
|
||||
if (dm_snprintf(buf, buf_size, "%-*.*s",
|
||||
width, width, field->report_string) < 0) {
|
||||
width, width, repstr) < 0) {
|
||||
log_error("dm_report: left-aligned snprintf() failed");
|
||||
goto bad;
|
||||
}
|
||||
@@ -4537,7 +4487,7 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
|
||||
}
|
||||
} else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) {
|
||||
if (dm_snprintf(buf, buf_size, "%*.*s",
|
||||
width, width, field->report_string) < 0) {
|
||||
width, width, repstr) < 0) {
|
||||
log_error("dm_report: right-aligned snprintf() failed");
|
||||
goto bad;
|
||||
}
|
||||
@@ -4546,11 +4496,6 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!dm_pool_grow_object(rh->mem, field->report_string, 0)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
|
||||
@@ -4560,164 +4505,21 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
} else if (_is_json_report(rh)) {
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _safe_repstr_output(struct dm_report *rh, const char *repstr, size_t len)
|
||||
{
|
||||
const char *p_repstr;
|
||||
const char *repstr_end = len ? repstr + len : repstr + strlen(repstr);
|
||||
|
||||
/* Escape any JSON_QUOTE that may appear in reported string. */
|
||||
while (1) {
|
||||
if (!(p_repstr = memchr(repstr, JSON_QUOTE[0], repstr_end - repstr)))
|
||||
break;
|
||||
|
||||
if (p_repstr > repstr) {
|
||||
if (!dm_pool_grow_object(rh->mem, repstr, p_repstr - repstr)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_ESCAPE_CHAR, 1) ||
|
||||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
repstr = p_repstr + 1;
|
||||
}
|
||||
|
||||
if (!dm_pool_grow_object(rh->mem, repstr, repstr_end - repstr)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _output_field_json_fmt(struct dm_report *rh, struct dm_report_field *field)
|
||||
{
|
||||
const char *repstr;
|
||||
size_t list_size, i;
|
||||
struct pos_len *pos_len;
|
||||
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
|
||||
!dm_pool_grow_object(rh->mem, _get_field_id(rh, field), 0) ||
|
||||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
|
||||
!dm_pool_grow_object(rh->mem, JSON_PAIR, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (field->props->flags & DM_REPORT_FIELD_TYPE_STRING_LIST) {
|
||||
if (!_is_json_std_report(rh)) {
|
||||
|
||||
/* string list in JSON - report whole list as simple string in quotes */
|
||||
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_safe_repstr_output(rh, field->report_string, 0))
|
||||
return_0;
|
||||
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* string list in JSON_STD - report list as proper JSON array */
|
||||
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_ARRAY_START, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*field->report_string != 0) {
|
||||
pos_len = (struct pos_len *) (field->report_string +
|
||||
((struct str_list_sort_value *) field->sort_value)->items[0].len + 1);
|
||||
list_size = pos_len->pos;
|
||||
} else
|
||||
list_size = 0;
|
||||
|
||||
for (i = 0; i < list_size; i++) {
|
||||
pos_len++;
|
||||
|
||||
if (i != 0) {
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_SEPARATOR, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_safe_repstr_output(rh, field->report_string + pos_len->pos, pos_len->len))
|
||||
return_0;
|
||||
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_ARRAY_END, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* all other types than string list - handle both JSON and JSON_STD */
|
||||
|
||||
if (!(_is_json_std_report(rh) && _is_pure_numeric_field(field))) {
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (_is_json_std_report(rh) && _is_pure_numeric_field(field) && !*field->report_string)
|
||||
repstr = JSON_NULL;
|
||||
else
|
||||
repstr = field->report_string;
|
||||
|
||||
if (!_safe_repstr_output(rh, repstr, 0))
|
||||
return_0;
|
||||
|
||||
if (!(_is_json_std_report(rh) && _is_pure_numeric_field(field))) {
|
||||
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
|
||||
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Produce report output
|
||||
*/
|
||||
static int _output_field(struct dm_report *rh, struct dm_report_field *field)
|
||||
{
|
||||
return _is_json_report(rh) ? _output_field_json_fmt(rh, field)
|
||||
: _output_field_basic_fmt(rh, field);
|
||||
}
|
||||
|
||||
static void _destroy_rows(struct dm_report *rh)
|
||||
{
|
||||
/*
|
||||
@@ -5181,7 +4983,6 @@ int dm_report_group_push(struct dm_report_group *group, struct dm_report *report
|
||||
goto_bad;
|
||||
break;
|
||||
case DM_REPORT_GROUP_JSON:
|
||||
case DM_REPORT_GROUP_JSON_STD:
|
||||
if (!_report_group_push_json(item, data))
|
||||
goto_bad;
|
||||
break;
|
||||
@@ -5245,7 +5046,6 @@ int dm_report_group_pop(struct dm_report_group *group)
|
||||
return_0;
|
||||
break;
|
||||
case DM_REPORT_GROUP_JSON:
|
||||
case DM_REPORT_GROUP_JSON_STD:
|
||||
if (!_report_group_pop_json(item))
|
||||
return_0;
|
||||
break;
|
||||
@@ -5282,7 +5082,7 @@ int dm_report_group_output_and_pop_all(struct dm_report_group *group)
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (group->type == DM_REPORT_GROUP_JSON || group->type == DM_REPORT_GROUP_JSON_STD) {
|
||||
if (group->type == DM_REPORT_GROUP_JSON) {
|
||||
_json_output_start(group);
|
||||
log_print(JSON_OBJECT_END);
|
||||
group->indent -= JSON_INDENT_UNIT;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
|
||||
* Copyright (C) 2004 - 2021 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 - 2017 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
@@ -184,7 +183,7 @@ struct dm_target_spec {
|
||||
struct dm_target_deps {
|
||||
uint32_t count; /* Array size */
|
||||
uint32_t padding; /* unused */
|
||||
uint64_t dev[0]; /* out */
|
||||
uint64_t dev[]; /* out */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -194,23 +193,9 @@ struct dm_name_list {
|
||||
uint64_t dev;
|
||||
uint32_t next; /* offset to the next record from
|
||||
the _start_ of this */
|
||||
char name[0];
|
||||
|
||||
/*
|
||||
* The following members can be accessed by taking a pointer that
|
||||
* points immediately after the terminating zero character in "name"
|
||||
* and aligning this pointer to next 8-byte boundary.
|
||||
* Uuid is present if the flag DM_NAME_LIST_FLAG_HAS_UUID is set.
|
||||
*
|
||||
* uint32_t event_nr;
|
||||
* uint32_t flags;
|
||||
* char uuid[0];
|
||||
*/
|
||||
char name[];
|
||||
};
|
||||
|
||||
#define DM_NAME_LIST_FLAG_HAS_UUID 1
|
||||
#define DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID 2
|
||||
|
||||
/*
|
||||
* Used to retrieve the target versions
|
||||
*/
|
||||
@@ -218,7 +203,7 @@ struct dm_target_versions {
|
||||
uint32_t next;
|
||||
uint32_t version[3];
|
||||
|
||||
char name[0];
|
||||
char name[];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -227,7 +212,7 @@ struct dm_target_versions {
|
||||
struct dm_target_msg {
|
||||
uint64_t sector; /* Device sector */
|
||||
|
||||
char message[0];
|
||||
char message[];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -289,9 +274,9 @@ enum {
|
||||
#define DM_GET_TARGET_VERSION _IOWR(DM_IOCTL, DM_GET_TARGET_VERSION_CMD, struct dm_ioctl)
|
||||
|
||||
#define DM_VERSION_MAJOR 4
|
||||
#define DM_VERSION_MINOR 45
|
||||
#define DM_VERSION_MINOR 36
|
||||
#define DM_VERSION_PATCHLEVEL 0
|
||||
#define DM_VERSION_EXTRA "-ioctl (2021-03-22)"
|
||||
#define DM_VERSION_EXTRA "-ioctl (2017-06-09)"
|
||||
|
||||
/* Status bits */
|
||||
#define DM_READONLY_FLAG (1 << 0) /* In/Out */
|
||||
@@ -379,10 +364,4 @@ enum {
|
||||
*/
|
||||
#define DM_INTERNAL_SUSPEND_FLAG (1 << 18) /* Out */
|
||||
|
||||
/*
|
||||
* If set, returns in the in buffer passed by UM, the raw table information
|
||||
* that would be measured by IMA subsystem on device state change.
|
||||
*/
|
||||
#define DM_IMA_MEASUREMENT_FLAG (1 << 19) /* In */
|
||||
|
||||
#endif /* _LINUX_DM_IOCTL_H */
|
||||
|
||||
@@ -69,18 +69,15 @@ bool dm_vdo_status_parse(struct dm_pool *mem, const char *input,
|
||||
enum dm_vdo_write_policy {
|
||||
DM_VDO_WRITE_POLICY_AUTO = 0,
|
||||
DM_VDO_WRITE_POLICY_SYNC,
|
||||
DM_VDO_WRITE_POLICY_ASYNC,
|
||||
DM_VDO_WRITE_POLICY_ASYNC_UNSAFE
|
||||
DM_VDO_WRITE_POLICY_ASYNC
|
||||
};
|
||||
|
||||
// FIXME: review whether we should use the createParams from the userlib
|
||||
struct dm_vdo_target_params {
|
||||
uint32_t minimum_io_size; // in sectors
|
||||
uint32_t block_map_cache_size_mb;
|
||||
union {
|
||||
uint32_t block_map_era_length; // format period
|
||||
uint32_t block_map_period; // supported alias
|
||||
};
|
||||
uint32_t block_map_era_length; // format period
|
||||
|
||||
uint32_t check_point_frequency;
|
||||
uint32_t index_memory_size_mb; // format
|
||||
|
||||
@@ -108,8 +105,6 @@ struct dm_vdo_target_params {
|
||||
bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
|
||||
uint64_t vdo_size);
|
||||
|
||||
bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
@@ -15,52 +15,49 @@
|
||||
#ifndef DEVICE_MAPPER_VDO_LIMITS_H
|
||||
#define DEVICE_MAPPER_VDO_LIMITS_H
|
||||
|
||||
#ifndef SECTOR_SHIFT
|
||||
#define SECTOR_SHIFT 9L
|
||||
#endif
|
||||
|
||||
#define DM_VDO_BLOCK_SIZE UINT64_C(8) // 4KiB in sectors
|
||||
#define DM_VDO_BLOCK_SIZE_KB (DM_VDO_BLOCK_SIZE << SECTOR_SHIFT)
|
||||
|
||||
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB (128) // 128MiB
|
||||
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB (16 * 1024 * 1024 - 1) // 16TiB - 1
|
||||
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_PER_LOGICAL_THREAD (4096 * DM_VDO_BLOCK_SIZE_KB)
|
||||
|
||||
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM 1
|
||||
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM 16380
|
||||
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM (1)
|
||||
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM (16380)
|
||||
|
||||
#define DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB 256 // 0.25 GiB
|
||||
#define DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB (256) // 0.25 GiB
|
||||
#define DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB (1024 * 1024 * 1024) // 1TiB
|
||||
|
||||
#define DM_VDO_SLAB_SIZE_MINIMUM_MB 128 // 128MiB
|
||||
//#define DM_VDO_READ_CACHE_SIZE_MINIMUM_MB (0)
|
||||
#define DM_VDO_READ_CACHE_SIZE_MAXIMUM_MB (16 * 1024 * 1024 - 1) // 16TiB - 1
|
||||
|
||||
#define DM_VDO_SLAB_SIZE_MINIMUM_MB (128) // 128MiB
|
||||
#define DM_VDO_SLAB_SIZE_MAXIMUM_MB (32 * 1024) // 32GiB
|
||||
#define DM_VDO_SLABS_MAXIMUM 8192
|
||||
|
||||
#define DM_VDO_LOGICAL_SIZE_MAXIMUM (UINT64_C(4) * 1024 * 1024 * 1024 * 1024 * 1024 >> SECTOR_SHIFT) // 4PiB
|
||||
#define DM_VDO_PHYSICAL_SIZE_MAXIMUM (UINT64_C(64) * DM_VDO_BLOCK_SIZE_KB * 1024 * 1024 * 1024 >> SECTOR_SHIFT) // 256TiB
|
||||
//#define DM_VDO_LOGICAL_SIZE_MINIMUM_MB (0)
|
||||
#define DM_VDO_LOGICAL_SIZE_MAXIMUM_MB (UINT64_C(4) * 1024 * 1024 * 1024) // 4PiB
|
||||
|
||||
#define DM_VDO_ACK_THREADS_MINIMUM 0
|
||||
#define DM_VDO_ACK_THREADS_MAXIMUM 100
|
||||
//#define DM_VDO_ACK_THREADS_MINIMUM (0)
|
||||
#define DM_VDO_ACK_THREADS_MAXIMUM (100)
|
||||
|
||||
#define DM_VDO_BIO_THREADS_MINIMUM 1
|
||||
#define DM_VDO_BIO_THREADS_MAXIMUM 100
|
||||
#define DM_VDO_BIO_THREADS_MINIMUM (1)
|
||||
#define DM_VDO_BIO_THREADS_MAXIMUM (100)
|
||||
|
||||
#define DM_VDO_BIO_ROTATION_MINIMUM 1
|
||||
#define DM_VDO_BIO_ROTATION_MAXIMUM 1024
|
||||
#define DM_VDO_BIO_ROTATION_MINIMUM (1)
|
||||
#define DM_VDO_BIO_ROTATION_MAXIMUM (1024)
|
||||
|
||||
#define DM_VDO_CPU_THREADS_MINIMUM 1
|
||||
#define DM_VDO_CPU_THREADS_MAXIMUM 100
|
||||
#define DM_VDO_CPU_THREADS_MINIMUM (1)
|
||||
#define DM_VDO_CPU_THREADS_MAXIMUM (100)
|
||||
|
||||
#define DM_VDO_HASH_ZONE_THREADS_MINIMUM 0
|
||||
#define DM_VDO_HASH_ZONE_THREADS_MAXIMUM 100
|
||||
//#define DM_VDO_HASH_ZONE_THREADS_MINIMUM (0)
|
||||
#define DM_VDO_HASH_ZONE_THREADS_MAXIMUM (100)
|
||||
|
||||
#define DM_VDO_LOGICAL_THREADS_MINIMUM 0
|
||||
#define DM_VDO_LOGICAL_THREADS_MAXIMUM 60
|
||||
//#define DM_VDO_LOGICAL_THREADS_MINIMUM (0)
|
||||
#define DM_VDO_LOGICAL_THREADS_MAXIMUM (100)
|
||||
|
||||
#define DM_VDO_PHYSICAL_THREADS_MINIMUM 0
|
||||
#define DM_VDO_PHYSICAL_THREADS_MAXIMUM 16
|
||||
//#define DM_VDO_PHYSICAL_THREADS_MINIMUM (0)
|
||||
#define DM_VDO_PHYSICAL_THREADS_MAXIMUM (16)
|
||||
|
||||
#define DM_VDO_MAX_DISCARD_MINIMUM 1
|
||||
#define DM_VDO_MAX_DISCARD_MAXIMUM (UINT32_MAX / (uint32_t)(DM_VDO_BLOCK_SIZE_KB))
|
||||
#define DM_VDO_MAX_DISCARD_MINIMUM (1)
|
||||
#define DM_VDO_MAX_DISCARD_MAXIMUM (UINT32_MAX / 4096)
|
||||
|
||||
#endif // DEVICE_MAPPER_VDO_LIMITS_H
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on VDO sources: https://github.com/dm-vdo/vdo
|
||||
*
|
||||
* Simplified parser of VDO superblock to obtain basic VDO parameteers
|
||||
*
|
||||
* TODO: maybe switch to some library in the future
|
||||
*/
|
||||
|
||||
//#define _GNU_SOURCE 1
|
||||
//#define _LARGEFILE64_SOURCE 1
|
||||
|
||||
#include "device_mapper/misc/dmlib.h"
|
||||
|
||||
#include "target.h"
|
||||
|
||||
#include "lib/mm/xlate.h"
|
||||
//#include "linux/byteorder/big_endian.h"
|
||||
//#include "linux/byteorder/little_endian.h"
|
||||
//#define le32_to_cpu __le32_to_cpu
|
||||
//#define le64_to_cpu __le64_to_cpu
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/fs.h> /* For block ioctl definitions */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef unsigned char uuid_t[16];
|
||||
|
||||
#define __packed __attribute__((packed))
|
||||
|
||||
static const char _MAGIC_NUMBER[] = "dmvdo001";
|
||||
#define MAGIC_NUMBER_SIZE (sizeof(_MAGIC_NUMBER) - 1)
|
||||
|
||||
struct vdo_version_number {
|
||||
uint32_t major_version;
|
||||
uint32_t minor_version;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* The registry of component ids for use in headers
|
||||
*/
|
||||
enum {
|
||||
SUPER_BLOCK = 0,
|
||||
FIXED_LAYOUT = 1,
|
||||
RECOVERY_JOURNAL = 2,
|
||||
SLAB_DEPOT = 3,
|
||||
BLOCK_MAP = 4,
|
||||
GEOMETRY_BLOCK = 5,
|
||||
}; /* ComponentID */
|
||||
|
||||
struct vdo_header {
|
||||
uint32_t id; /* The component this is a header for */
|
||||
struct vdo_version_number version; /* The version of the data format */
|
||||
size_t size; /* The size of the data following this header */
|
||||
} __packed;
|
||||
|
||||
struct vdo_geometry_block {
|
||||
char magic_number[MAGIC_NUMBER_SIZE];
|
||||
struct vdo_header header;
|
||||
uint32_t checksum;
|
||||
} __packed;
|
||||
|
||||
struct vdo_config {
|
||||
uint64_t logical_blocks; /* number of logical blocks */
|
||||
uint64_t physical_blocks; /* number of physical blocks */
|
||||
uint64_t slab_size; /* number of blocks in a slab */
|
||||
uint64_t recovery_journal_size; /* number of recovery journal blocks */
|
||||
uint64_t slab_journal_blocks; /* number of slab journal blocks */
|
||||
} __packed;
|
||||
|
||||
struct vdo_component_41_0 {
|
||||
uint32_t state;
|
||||
uint64_t complete_recoveries;
|
||||
uint64_t read_only_recoveries;
|
||||
struct vdo_config config; /* packed */
|
||||
uint64_t nonce;
|
||||
} __packed;
|
||||
|
||||
enum vdo_volume_region_id {
|
||||
VDO_INDEX_REGION = 0,
|
||||
VDO_DATA_REGION = 1,
|
||||
VDO_VOLUME_REGION_COUNT,
|
||||
};
|
||||
|
||||
struct vdo_volume_region {
|
||||
/* The ID of the region */
|
||||
enum vdo_volume_region_id id;
|
||||
/*
|
||||
* The absolute starting offset on the device. The region continues
|
||||
* until the next region begins.
|
||||
*/
|
||||
uint64_t start_block;
|
||||
} __packed;
|
||||
|
||||
struct vdo_index_config {
|
||||
uint32_t mem;
|
||||
uint32_t unused;
|
||||
uint8_t sparse;
|
||||
} __packed;
|
||||
|
||||
struct vdo_volume_geometry {
|
||||
uint32_t release_version;
|
||||
uint64_t nonce;
|
||||
uuid_t uuid;
|
||||
uint64_t bio_offset;
|
||||
struct vdo_volume_region regions[VDO_VOLUME_REGION_COUNT];
|
||||
struct vdo_index_config index_config;
|
||||
} __packed;
|
||||
|
||||
/* Decoding mostly only some used stucture members */
|
||||
|
||||
static void _vdo_decode_version(struct vdo_version_number *v)
|
||||
{
|
||||
v->major_version = le32_to_cpu(v->major_version);
|
||||
v->minor_version = le32_to_cpu(v->minor_version);
|
||||
}
|
||||
|
||||
static void _vdo_decode_header(struct vdo_header *h)
|
||||
{
|
||||
h->id = le32_to_cpu(h->id);
|
||||
_vdo_decode_version(&h->version);
|
||||
h->size = le64_to_cpu(h->size);
|
||||
}
|
||||
|
||||
static void _vdo_decode_geometry_region(struct vdo_volume_region *vr)
|
||||
{
|
||||
vr->id = le32_to_cpu(vr->id);
|
||||
vr->start_block = le32_to_cpu(vr->start_block);
|
||||
}
|
||||
|
||||
static void _vdo_decode_volume_geometry(struct vdo_volume_geometry *vg)
|
||||
{
|
||||
vg->release_version = le64_to_cpu(vg->release_version);
|
||||
vg->nonce = le64_to_cpu(vg->nonce);
|
||||
_vdo_decode_geometry_region(&vg->regions[VDO_DATA_REGION]);
|
||||
}
|
||||
|
||||
static void _vdo_decode_config(struct vdo_config *vc)
|
||||
{
|
||||
vc->logical_blocks = le64_to_cpu(vc->logical_blocks);
|
||||
vc->physical_blocks = le64_to_cpu(vc->physical_blocks);
|
||||
vc->slab_size = le64_to_cpu(vc->slab_size);
|
||||
vc->recovery_journal_size = le64_to_cpu(vc->recovery_journal_size);
|
||||
vc->slab_journal_blocks = le64_to_cpu(vc->slab_journal_blocks);
|
||||
}
|
||||
|
||||
static void _vdo_decode_pvc(struct vdo_component_41_0 *pvc)
|
||||
{
|
||||
_vdo_decode_config(&pvc->config);
|
||||
pvc->nonce = le64_to_cpu(pvc->nonce);
|
||||
}
|
||||
|
||||
bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)
|
||||
{
|
||||
char buffer[4096];
|
||||
int fh, n;
|
||||
bool r = false;
|
||||
off_t l;
|
||||
struct stat st;
|
||||
uint64_t size;
|
||||
uint64_t regpos;
|
||||
|
||||
struct vdo_header h;
|
||||
struct vdo_version_number vn;
|
||||
struct vdo_volume_geometry vg;
|
||||
struct vdo_component_41_0 pvc;
|
||||
|
||||
*logical_blocks = 0;
|
||||
if ((fh = open(vdo_path, O_RDONLY)) == -1) {
|
||||
log_sys_debug("Failed to open VDO backend %s.", vdo_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioctl(fh, BLKGETSIZE64, &size) == -1) {
|
||||
if (errno != ENOTTY) {
|
||||
log_sys_debug("ioctl", vdo_path);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* lets retry for file sizes */
|
||||
if (fstat(fh, &st) < 0) {
|
||||
log_sys_debug("fstat", vdo_path);
|
||||
goto err;
|
||||
}
|
||||
|
||||
size = st.st_size;
|
||||
}
|
||||
|
||||
if ((n = read(fh, buffer, sizeof(buffer))) < 0) {
|
||||
log_sys_debug("read", vdo_path);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (strncmp(buffer, _MAGIC_NUMBER, MAGIC_NUMBER_SIZE)) {
|
||||
log_debug_activation("Found mismatching VDO magic header in %s.", vdo_path);
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(&h, buffer + MAGIC_NUMBER_SIZE, sizeof(h));
|
||||
_vdo_decode_header(&h);
|
||||
|
||||
if (h.version.major_version != 5) {
|
||||
log_debug_activation("Unsupported VDO version %u.%u.", h.version.major_version, h.version.minor_version);
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(&vg, buffer + MAGIC_NUMBER_SIZE + sizeof(h), sizeof(vg));
|
||||
_vdo_decode_volume_geometry(&vg);
|
||||
|
||||
regpos = vg.regions[VDO_DATA_REGION].start_block * 4096;
|
||||
|
||||
if ((regpos + sizeof(buffer)) > size) {
|
||||
log_debug_activation("File/Device is shorter and can't provide requested VDO volume region at " FMTu64 " > " FMTu64 ".", regpos, size);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((l = lseek(fh, regpos, SEEK_SET)) < 0) {
|
||||
log_sys_debug("lseek", vdo_path);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((n = read(fh, buffer, sizeof(buffer))) < 0) {
|
||||
log_sys_debug("read", vdo_path);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
memcpy(&vn, buffer + sizeof(struct vdo_geometry_block), sizeof(vn));
|
||||
_vdo_decode_version(&vn);
|
||||
|
||||
if (vn.major_version > 41) {
|
||||
log_debug_activation("Unknown VDO component version %u.", vn.major_version); // should be 41!
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(&pvc, buffer + sizeof(struct vdo_geometry_block) + sizeof(vn), sizeof(pvc));
|
||||
_vdo_decode_pvc(&pvc);
|
||||
|
||||
if (pvc.nonce != vg.nonce) {
|
||||
log_debug_activation("VDO metadata has mismatching VDO nonces " FMTu64 " != " FMTu64 ".", pvc.nonce, vg.nonce);
|
||||
goto err;
|
||||
}
|
||||
|
||||
#if 0
|
||||
log_debug_activation("LogBlocks " FMTu64 ".", pvc.config.logical_blocks);
|
||||
log_debug_activation("PhyBlocks " FMTu64 ".", pvc.config.physical_blocks);
|
||||
log_debug_activation("SlabSize " FMTu64 ".", pvc.config.slab_size);
|
||||
log_debug_activation("RecJourSize " FMTu64 ".", pvc.config.recovery_journal_size);
|
||||
log_debug_activation("SlabJouSize " FMTu64 ".", pvc.config.slab_journal_blocks);
|
||||
#endif
|
||||
|
||||
*logical_blocks = pvc.config.logical_blocks;
|
||||
r = true;
|
||||
err:
|
||||
(void) close(fh);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -18,124 +18,88 @@
|
||||
#include "vdo_limits.h"
|
||||
#include "target.h"
|
||||
|
||||
/* validate vdo target parameters and 'vdo_size' in sectors */
|
||||
bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
|
||||
uint64_t vdo_size)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
/* 512 or 4096 bytes only ATM */
|
||||
if ((vtp->minimum_io_size != (512 >> SECTOR_SHIFT)) &&
|
||||
(vtp->minimum_io_size != (4096 >> SECTOR_SHIFT))) {
|
||||
log_error("VDO minimum io size %u is unsupported [512, 4096].",
|
||||
if ((vtp->minimum_io_size != 1) &&
|
||||
(vtp->minimum_io_size != 8)) {
|
||||
log_error("VDO minimum io size %u is unsupported.",
|
||||
vtp->minimum_io_size);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if ((vtp->block_map_cache_size_mb < DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB) ||
|
||||
(vtp->block_map_cache_size_mb > DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB)) {
|
||||
log_error("VDO block map cache size %u MiB is out of range [%u..%u].",
|
||||
vtp->block_map_cache_size_mb,
|
||||
DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB,
|
||||
DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if ((vtp->block_map_era_length < DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM) ||
|
||||
(vtp->block_map_era_length > DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM)) {
|
||||
log_error("VDO block map era length %u is out of range [%u..%u].",
|
||||
vtp->block_map_era_length,
|
||||
DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM,
|
||||
DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM);
|
||||
log_error("VDO block map cache size %u out of range.",
|
||||
vtp->block_map_cache_size_mb);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if ((vtp->index_memory_size_mb < DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB) ||
|
||||
(vtp->index_memory_size_mb > DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB)) {
|
||||
log_error("VDO index memory size %u MiB is out of range [%u..%u].",
|
||||
vtp->index_memory_size_mb,
|
||||
DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB,
|
||||
DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB);
|
||||
log_error("VDO index memory size %u out of range.",
|
||||
vtp->index_memory_size_mb);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if ((vtp->slab_size_mb < DM_VDO_SLAB_SIZE_MINIMUM_MB) ||
|
||||
(vtp->slab_size_mb > DM_VDO_SLAB_SIZE_MAXIMUM_MB)) {
|
||||
log_error("VDO slab size %u MiB is out of range [%u..%u].",
|
||||
vtp->slab_size_mb,
|
||||
DM_VDO_SLAB_SIZE_MINIMUM_MB,
|
||||
DM_VDO_SLAB_SIZE_MAXIMUM_MB);
|
||||
log_error("VDO slab size %u out of range.",
|
||||
vtp->slab_size_mb);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if ((vtp->max_discard < DM_VDO_MAX_DISCARD_MINIMUM) ||
|
||||
(vtp->max_discard > DM_VDO_MAX_DISCARD_MAXIMUM)) {
|
||||
log_error("VDO max discard %u is out of range [%u..%u].",
|
||||
vtp->max_discard,
|
||||
DM_VDO_MAX_DISCARD_MINIMUM,
|
||||
DM_VDO_MAX_DISCARD_MAXIMUM);
|
||||
log_error("VDO max discard %u out of range.",
|
||||
vtp->max_discard);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (vtp->ack_threads > DM_VDO_ACK_THREADS_MAXIMUM) {
|
||||
log_error("VDO ack threads %u is out of range [0..%u].",
|
||||
vtp->ack_threads,
|
||||
DM_VDO_ACK_THREADS_MAXIMUM);
|
||||
log_error("VDO ack threads %u out of range.", vtp->ack_threads);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if ((vtp->bio_threads < DM_VDO_BIO_THREADS_MINIMUM) ||
|
||||
(vtp->bio_threads > DM_VDO_BIO_THREADS_MAXIMUM)) {
|
||||
log_error("VDO bio threads %u is out of range [%u..%u].",
|
||||
vtp->bio_threads,
|
||||
DM_VDO_BIO_THREADS_MINIMUM,
|
||||
DM_VDO_BIO_THREADS_MAXIMUM);
|
||||
log_error("VDO bio threads %u out of range.", vtp->bio_threads);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if ((vtp->bio_rotation < DM_VDO_BIO_ROTATION_MINIMUM) ||
|
||||
(vtp->bio_rotation > DM_VDO_BIO_ROTATION_MAXIMUM)) {
|
||||
log_error("VDO bio rotation %u is out of range [%u..%u].",
|
||||
vtp->bio_rotation,
|
||||
DM_VDO_BIO_ROTATION_MINIMUM,
|
||||
DM_VDO_BIO_ROTATION_MAXIMUM);
|
||||
log_error("VDO bio rotation %u out of range.", vtp->bio_rotation);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if ((vtp->cpu_threads < DM_VDO_CPU_THREADS_MINIMUM) ||
|
||||
(vtp->cpu_threads > DM_VDO_CPU_THREADS_MAXIMUM)) {
|
||||
log_error("VDO cpu threads %u is out of range [%u..%u].",
|
||||
vtp->cpu_threads,
|
||||
DM_VDO_CPU_THREADS_MINIMUM,
|
||||
DM_VDO_CPU_THREADS_MAXIMUM);
|
||||
log_error("VDO cpu threads %u out of range.", vtp->cpu_threads);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (vtp->hash_zone_threads > DM_VDO_HASH_ZONE_THREADS_MAXIMUM) {
|
||||
log_error("VDO hash zone threads %u is out of range [0..%u].",
|
||||
vtp->hash_zone_threads,
|
||||
DM_VDO_HASH_ZONE_THREADS_MAXIMUM);
|
||||
log_error("VDO hash zone threads %u out of range.", vtp->hash_zone_threads);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (vtp->logical_threads > DM_VDO_LOGICAL_THREADS_MAXIMUM) {
|
||||
log_error("VDO logical threads %u is out of range [0..%u].",
|
||||
vtp->logical_threads,
|
||||
DM_VDO_LOGICAL_THREADS_MAXIMUM);
|
||||
log_error("VDO logical threads %u out of range.", vtp->logical_threads);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (vtp->physical_threads > DM_VDO_PHYSICAL_THREADS_MAXIMUM) {
|
||||
log_error("VDO physical threads %u is out of range [0..%u].",
|
||||
vtp->physical_threads,
|
||||
DM_VDO_PHYSICAL_THREADS_MAXIMUM);
|
||||
log_error("VDO physical threads %u out of range.", vtp->physical_threads);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
switch (vtp->write_policy) {
|
||||
case DM_VDO_WRITE_POLICY_SYNC:
|
||||
case DM_VDO_WRITE_POLICY_ASYNC:
|
||||
case DM_VDO_WRITE_POLICY_ASYNC_UNSAFE:
|
||||
case DM_VDO_WRITE_POLICY_AUTO:
|
||||
break;
|
||||
default:
|
||||
@@ -155,10 +119,10 @@ bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (vdo_size > DM_VDO_LOGICAL_SIZE_MAXIMUM) {
|
||||
log_error("VDO logical size is larger than limit " FMTu64 " TiB by " FMTu64 " KiB.",
|
||||
DM_VDO_LOGICAL_SIZE_MAXIMUM / (UINT64_C(1024) * 1024 * 1024 * 1024 >> SECTOR_SHIFT),
|
||||
(vdo_size - DM_VDO_LOGICAL_SIZE_MAXIMUM) / 2);
|
||||
if (vdo_size >= (DM_VDO_LOGICAL_SIZE_MAXIMUM_MB * UINT64_C(1024 * 2))) {
|
||||
log_error("VDO logical size is by " FMTu64 "KiB bigger then limit " FMTu64 "TiB.",
|
||||
(vdo_size - (DM_VDO_LOGICAL_SIZE_MAXIMUM_MB * UINT64_C(1024 * 2))) / 2,
|
||||
DM_VDO_LOGICAL_SIZE_MAXIMUM_MB / UINT64_C(1024) / UINT64_C(1024));
|
||||
valid = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ the entries (each hotspot block covers a larger area than a single
|
||||
cache block).
|
||||
|
||||
All this means smq uses ~25bytes per cache block. Still a lot of
|
||||
memory, but a substantial improvement nonetheless.
|
||||
memory, but a substantial improvement nontheless.
|
||||
|
||||
Level balancing:
|
||||
mq placed entries in different levels of the multiqueue structures
|
||||
|
||||
@@ -35,7 +35,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
|
||||
capi:authenc(hmac(sha256),xts(aes))-random
|
||||
capi:rfc7539(chacha20,poly1305)-random
|
||||
|
||||
The /proc/crypto contains a list of currently loaded crypto modes.
|
||||
The /proc/crypto contains a list of curently loaded crypto modes.
|
||||
|
||||
<key>
|
||||
Key used for encryption. It is encoded either as a hexadecimal number
|
||||
@@ -81,7 +81,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
|
||||
|
||||
<#opt_params>
|
||||
Number of optional parameters. If there are no optional parameters,
|
||||
the optional parameters section can be skipped or #opt_params can be zero.
|
||||
the optional paramaters section can be skipped or #opt_params can be zero.
|
||||
Otherwise #opt_params is the number of following arguments.
|
||||
|
||||
Example of optional parameters section:
|
||||
|
||||
@@ -94,7 +94,7 @@ journal_watermark:number
|
||||
|
||||
commit_time:number
|
||||
Commit time in milliseconds. When this time passes, the journal is
|
||||
written. The journal is also written immediately if the FLUSH
|
||||
written. The journal is also written immediatelly if the FLUSH
|
||||
request is received.
|
||||
|
||||
internal_hash:algorithm(:key) (the key is optional)
|
||||
@@ -120,7 +120,7 @@ journal_crypt:algorithm(:key) (the key is optional)
|
||||
"salsa20", "ctr(aes)" or "ecb(arc4)").
|
||||
|
||||
The journal contains history of last writes to the block device,
|
||||
an attacker reading the journal could see the last sector numbers
|
||||
an attacker reading the journal could see the last sector nubmers
|
||||
that were written. From the sector numbers, the attacker can infer
|
||||
the size of files that were written. To protect against this
|
||||
situation, you can encrypt the journal.
|
||||
|
||||
@@ -65,7 +65,7 @@ Construction Parameters
|
||||
|
||||
<#opt_params>
|
||||
Number of optional parameters. If there are no optional parameters,
|
||||
the optional parameters section can be skipped or #opt_params can be zero.
|
||||
the optional paramaters section can be skipped or #opt_params can be zero.
|
||||
Otherwise #opt_params is the number of following arguments.
|
||||
|
||||
Example of optional parameters section:
|
||||
|
||||
@@ -37,7 +37,7 @@ segment type. The available RAID types are:
|
||||
"raid6_nr" - RAID6 Rotating parity N with data restart
|
||||
"raid6_nc" - RAID6 Rotating parity N with data continuation
|
||||
The exception to 'no shorthand options' will be where the RAID implementations
|
||||
can displace traditional targets. This is the case with 'mirror' and 'raid1'.
|
||||
can displace traditional tagets. This is the case with 'mirror' and 'raid1'.
|
||||
In this case, "mirror_segtype_default" - found under the "global" section in
|
||||
lvm.conf - can be set to "mirror" or "raid1". The segment type inferred when
|
||||
the '-m' option is used will be taken from this setting. The default segment
|
||||
@@ -104,7 +104,7 @@ and 4 devices for RAID 6/10.
|
||||
|
||||
lvconvert should work exactly as it does now when dealing with mirrors -
|
||||
even if(when) we switch to MD RAID1. Of course, there are no plans to
|
||||
allow the presence of the metadata area to be configurable (e.g. --corelog).
|
||||
allow the presense of the metadata area to be configurable (e.g. --corelog).
|
||||
It will be simple enough to detect if the LV being up/down-converted is
|
||||
new or old-style mirroring.
|
||||
|
||||
@@ -120,7 +120,7 @@ RAID4 to RAID5 or RAID5 to RAID6.
|
||||
Line 02/03/04:
|
||||
These are familiar options - all of which would now be available as options
|
||||
for change. (However, it'd be nice if we didn't have regionsize in there.
|
||||
It's simple on the kernel side, but is just an extra - often unnecessary -
|
||||
It's simple on the kernel side, but is just an extra - often unecessary -
|
||||
parameter to many functions in the LVM codebase.)
|
||||
|
||||
Line 05:
|
||||
@@ -375,8 +375,8 @@ the slot. Even the names of the images will be renamed to properly reflect
|
||||
their index in the array. Unlike the "mirror" segment type, you will never have
|
||||
an image named "*_rimage_1" occupying the index position 0.
|
||||
|
||||
As with adding images, removing images holds off on committing LVM metadata
|
||||
until all possible changes have been made. This reduces the likelihood of bad
|
||||
As with adding images, removing images holds off on commiting LVM metadata
|
||||
until all possible changes have been made. This reduces the likelyhood of bad
|
||||
intermediate stages being left due to a failure of operation or machine crash.
|
||||
|
||||
RAID1 '--splitmirrors', '--trackchanges', and '--merge' operations
|
||||
|
||||
@@ -87,7 +87,7 @@ are as follows:
|
||||
/etc/lvm/lvm.conf. Once this operation is complete, the logical volumes
|
||||
will be consistent. However, the volume group will still be inconsistent -
|
||||
due to the refernced-but-missing device/PV - and operations will still be
|
||||
restricted to the aforementioned actions until either the device is
|
||||
restricted to the aformentioned actions until either the device is
|
||||
restored or 'vgreduce --removemissing' is run.
|
||||
|
||||
Device Revival (transient failures):
|
||||
@@ -135,9 +135,9 @@ If a mirror is not 'in-sync', a read failure will produce an I/O error.
|
||||
This error will propagate all the way up to the applications above the
|
||||
logical volume (e.g. the file system). No automatic intervention will
|
||||
take place in this case either. It is up to the user to decide what
|
||||
can be done/salvaged in this scenario. If the user is confident that the
|
||||
can be done/salvaged in this senario. If the user is confident that the
|
||||
images of the mirror are the same (or they are willing to simply attempt
|
||||
to retrieve whatever data they can), 'lvconvert' can be used to eliminate
|
||||
to retreive whatever data they can), 'lvconvert' can be used to eliminate
|
||||
the failed image and proceed.
|
||||
|
||||
Mirror resynchronization errors:
|
||||
@@ -191,11 +191,11 @@ command are set in the LVM configuration file. They are:
|
||||
3-way mirror fails, the mirror will be converted to a 2-way mirror.
|
||||
The "allocate" policy takes the further action of trying to replace
|
||||
the failed image using space that is available in the volume group.
|
||||
Replacing a failed mirror image will incur the cost of
|
||||
Replacing a failed mirror image will incure the cost of
|
||||
resynchronizing - degrading the performance of the mirror. The
|
||||
default policy for handling an image failure is "remove". This
|
||||
allows the mirror to still function, but gives the administrator the
|
||||
choice of when to incur the extra performance costs of replacing
|
||||
choice of when to incure the extra performance costs of replacing
|
||||
the failed image.
|
||||
|
||||
RAID logical volume device failures are handled differently from the "mirror"
|
||||
|
||||
@@ -63,7 +63,7 @@ classical snapshot merge, thin snapshot merge.
|
||||
|
||||
The second store is suited only for pvmove --abort operations in-progress. Both
|
||||
stores are independent and identical LVs (pvmove /dev/sda3 and pvmove --abort /dev/sda3)
|
||||
can be run concurrently from lvmpolld point of view (on lvm2 side the consistency is
|
||||
can be run concurently from lvmpolld point of view (on lvm2 side the consistency is
|
||||
guaranteed by lvm2 locking mechanism).
|
||||
|
||||
Locking order
|
||||
|
||||
@@ -126,7 +126,7 @@ Usage Examples
|
||||
followed by 'vgchange -ay vg2'
|
||||
|
||||
|
||||
Option (ii) - localised admin & configuration
|
||||
Option (ii) - localised admin & configuation
|
||||
(i.e. each host holds *locally* which classes of volumes to activate)
|
||||
# Add @database tag to vg1's metadata
|
||||
vgchange --addtag @database vg1
|
||||
|
||||
@@ -35,7 +35,7 @@ VGs from PVs as they appear, and at the same time collect information on what is
|
||||
already available. A command, pvscan --cache is expected to be used to
|
||||
implement udev rules. It is relatively easy to make this command print out a
|
||||
list of VGs (and possibly LVs) that have been made available by adding any
|
||||
particular device to the set of visible devices. In other words, udev says "hey,
|
||||
particular device to the set of visible devices. In othe words, udev says "hey,
|
||||
/dev/sdb just appeared", calls pvscan --cache, which talks to lvmetad, which
|
||||
says "cool, that makes vg0 complete". Pvscan takes this info and prints it out,
|
||||
and the udev rule can then somehow decide whether anything needs to be done
|
||||
|
||||
2
include/.gitignore
vendored
2
include/.gitignore
vendored
@@ -1,3 +1 @@
|
||||
*.h
|
||||
.symlinks
|
||||
.symlinks_created
|
||||
|
||||
@@ -18,21 +18,6 @@ top_builddir = @top_builddir@
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
cmds.h:
|
||||
@echo " [GEN] $@"
|
||||
$(Q) set -o pipefail && \
|
||||
( cat $(top_srcdir)/tools/license.inc && \
|
||||
echo "/* Do not edit. This file is generated by the Makefile. */" && \
|
||||
echo "cmd(CMD_NONE, none)" && \
|
||||
$(GREP) '^ID:' $(top_srcdir)/tools/command-lines.in | LC_ALL=C $(SORT) -u | $(AWK) '{print "cmd(" $$2 "_CMD, " $$2 ")"}' && \
|
||||
echo "cmd(CMD_COUNT, count)" \
|
||||
) > $@
|
||||
|
||||
all: cmds.h
|
||||
|
||||
clean:
|
||||
rm -f cmds.h
|
||||
|
||||
DISTCLEAN_TARGETS += configure.h lvm-version.h
|
||||
CLEAN_TARGETS += \
|
||||
.symlinks \
|
||||
@@ -114,5 +99,4 @@ CLEAN_TARGETS += \
|
||||
util.h \
|
||||
uuid.h \
|
||||
vg.h \
|
||||
xlate.h \
|
||||
cmds.h
|
||||
xlate.h
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
/* include/configure.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 to include code that uses libsystemd machine-id apis. */
|
||||
#undef APP_MACHINEID_SUPPORT
|
||||
|
||||
/* Define to 1 to use libblkid detection of signatures when wiping. */
|
||||
#undef BLKID_WIPING_SUPPORT
|
||||
|
||||
@@ -25,13 +22,18 @@
|
||||
/* The path to 'cache_restore', if available. */
|
||||
#undef CACHE_RESTORE_CMD
|
||||
|
||||
/* Define to 1 if the `closedir' function returns void instead of int. */
|
||||
/* Define to 1 if the `closedir' function returns void instead of `int'. */
|
||||
#undef CLOSEDIR_VOID
|
||||
|
||||
/* Path to cmirrord pidfile. */
|
||||
#undef CMIRRORD_PIDFILE
|
||||
|
||||
/* Define to 1 if using 'alloca.c'. */
|
||||
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for `alloca.c' support on those systems.
|
||||
*/
|
||||
#undef CRAY_STACKSEG_END
|
||||
|
||||
/* Define to 1 if using `alloca.c'. */
|
||||
#undef C_ALLOCA
|
||||
|
||||
/* Name of default metadata archive subdirectory. */
|
||||
@@ -85,9 +87,6 @@
|
||||
/* Use blkid wiping by default. */
|
||||
#undef DEFAULT_USE_BLKID_WIPING
|
||||
|
||||
/* Default for lvm.conf use_devicesfile. */
|
||||
#undef DEFAULT_USE_DEVICES_FILE
|
||||
|
||||
/* Use lvmlockd by default. */
|
||||
#undef DEFAULT_USE_LVMLOCKD
|
||||
|
||||
@@ -109,6 +108,9 @@
|
||||
/* Define to 1 to enable the device-mapper filemap daemon. */
|
||||
#undef DMFILEMAPD
|
||||
|
||||
/* Define to enable compat protocol */
|
||||
#undef DM_COMPAT
|
||||
|
||||
/* Define default group for device node */
|
||||
#undef DM_DEVICE_GID
|
||||
|
||||
@@ -130,16 +132,14 @@
|
||||
/* Path to fsadm binary. */
|
||||
#undef FSADM_PATH
|
||||
|
||||
/* Define to use GNU versioning in the shared library. */
|
||||
#undef GNU_SYMVER
|
||||
|
||||
/* Define to 1 if you have the `alarm' function. */
|
||||
#undef HAVE_ALARM
|
||||
|
||||
/* Define to 1 if you have 'alloca', as a function or macro. */
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#undef HAVE_ALLOCA
|
||||
|
||||
/* Define to 1 if <alloca.h> works. */
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
|
||||
*/
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
@@ -182,6 +182,9 @@
|
||||
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||
#undef HAVE_DOPRNT
|
||||
|
||||
/* Define to 1 if you have the <editline/history.h> header file. */
|
||||
#undef HAVE_EDITLINE_HISTORY_H
|
||||
|
||||
/* Define to 1 if you have the <editline/readline.h> header file. */
|
||||
#undef HAVE_EDITLINE_READLINE_H
|
||||
|
||||
@@ -191,9 +194,6 @@
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `ffs' function. */
|
||||
#undef HAVE_FFS
|
||||
|
||||
/* Define to 1 if you have the <float.h> header file. */
|
||||
#undef HAVE_FLOAT_H
|
||||
|
||||
@@ -267,9 +267,6 @@
|
||||
/* Define to 1 if you have the <machine/endian.h> header file. */
|
||||
#undef HAVE_MACHINE_ENDIAN_H
|
||||
|
||||
/* Define to 1 if you have the `mallinfo2' function. */
|
||||
#undef HAVE_MALLINFO2
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#undef HAVE_MALLOC
|
||||
@@ -280,6 +277,9 @@
|
||||
/* Define to 1 if you have the `memchr' function. */
|
||||
#undef HAVE_MEMCHR
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#undef HAVE_MEMSET
|
||||
|
||||
@@ -396,7 +396,7 @@
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define if you have `strerror_r'. */
|
||||
/* Define to 1 if you have the `strerror_r' function. */
|
||||
#undef HAVE_STRERROR_R
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
@@ -519,9 +519,6 @@
|
||||
/* valgrind.h found */
|
||||
#undef HAVE_VALGRIND
|
||||
|
||||
/* Define to 1 if you have the `versionsort' function. */
|
||||
#undef HAVE_VERSIONSORT
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#undef HAVE_VFORK
|
||||
|
||||
@@ -546,9 +543,6 @@
|
||||
/* Define to 1 if the system has the `__builtin_clzll' built-in function */
|
||||
#undef HAVE___BUILTIN_CLZLL
|
||||
|
||||
/* Define to 1 if the system has the `__builtin_ffs' built-in function */
|
||||
#undef HAVE___BUILTIN_FFS
|
||||
|
||||
/* Define to 1 to include built-in support for integrity. */
|
||||
#undef INTEGRITY_INTERNAL
|
||||
|
||||
@@ -564,9 +558,6 @@
|
||||
/* Define to 1 to include code that uses lvmlockd dlm option. */
|
||||
#undef LOCKDDLM_SUPPORT
|
||||
|
||||
/* Define to 1 to include code that uses lvmlockd IDM option. */
|
||||
#undef LOCKDIDM_SUPPORT
|
||||
|
||||
/* Define to 1 to include code that uses lvmlockd sanlock option. */
|
||||
#undef LOCKDSANLOCK_SUPPORT
|
||||
|
||||
@@ -577,9 +568,6 @@
|
||||
/* Path to lvmconfig binary. */
|
||||
#undef LVMCONFIG_PATH
|
||||
|
||||
/* Path to lvm_import_vdo script. */
|
||||
#undef LVMIMPORTVDO_PATH
|
||||
|
||||
/* Path to lvmlockd pidfile. */
|
||||
#undef LVMLOCKD_PIDFILE
|
||||
|
||||
@@ -598,9 +586,6 @@
|
||||
/* Path to lvm binary. */
|
||||
#undef LVM_PATH
|
||||
|
||||
/* Path to lvresize_fs_helper script. */
|
||||
#undef LVRESIZE_FS_HELPER_PATH
|
||||
|
||||
/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
|
||||
*/
|
||||
#undef MAJOR_IN_MKDEV
|
||||
@@ -645,6 +630,9 @@
|
||||
/* Define to 1 to include the LVM readline shell. */
|
||||
#undef READLINE_SUPPORT
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* Define to 1 to include built-in support for snapshots. */
|
||||
#undef SNAPSHOT_INTERNAL
|
||||
|
||||
@@ -656,17 +644,12 @@
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
#undef STACK_DIRECTION
|
||||
|
||||
/* Define to 1 if all of the C90 standard headers exist (not just the ones
|
||||
required in a freestanding environment). This macro is provided for
|
||||
backward compatibility; new code need not use it. */
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if strerror_r returns char *. */
|
||||
#undef STRERROR_R_CHAR_P
|
||||
|
||||
/* Define to 1 to include code that uses systemd journal. */
|
||||
#undef SYSTEMD_JOURNAL_SUPPORT
|
||||
|
||||
/* Path to testsuite data */
|
||||
#undef TESTSUITE_DATA
|
||||
|
||||
@@ -689,6 +672,9 @@
|
||||
/* The path to 'thin_restore', if available. */
|
||||
#undef THIN_RESTORE_CMD
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#undef TIME_WITH_SYS_TIME
|
||||
|
||||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||
#undef TM_IN_SYS_TIME
|
||||
|
||||
@@ -765,7 +751,7 @@
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
#undef off_t
|
||||
|
||||
/* Define as a signed integer type capable of holding a process identifier. */
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to rpl_realloc if the replacement function should be used. */
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
|
||||
SOURCES =\
|
||||
activate/activate.c \
|
||||
@@ -30,20 +29,14 @@ SOURCES =\
|
||||
device/bcache.c \
|
||||
device/bcache-utils.c \
|
||||
device/dev-cache.c \
|
||||
device/device_id.c \
|
||||
device/dev-ext.c \
|
||||
device/dev-io.c \
|
||||
device/dev-md.c \
|
||||
device/dev-mpath.c \
|
||||
device/dev-swap.c \
|
||||
device/dev-type.c \
|
||||
device/dev-luks.c \
|
||||
device/dev-dasd.c \
|
||||
device/dev-lvm1-pool.c \
|
||||
device/filesystem.c \
|
||||
device/online.c \
|
||||
device/parse_vpd.c \
|
||||
device/dev_util.c \
|
||||
display/display.c \
|
||||
error/errseg.c \
|
||||
unknown/unknown.c \
|
||||
@@ -57,8 +50,8 @@ SOURCES =\
|
||||
filters/filter-partitioned.c \
|
||||
filters/filter-type.c \
|
||||
filters/filter-usable.c \
|
||||
filters/filter-internal.c \
|
||||
filters/filter-signature.c \
|
||||
filters/filter-deviceid.c \
|
||||
format_text/archive.c \
|
||||
format_text/archiver.c \
|
||||
format_text/export.c \
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "lib/metadata/segtype.h"
|
||||
#include "lib/misc/sharedlib.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/misc/lvm-signal.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
@@ -178,22 +177,6 @@ int lv_passes_auto_activation_filter(struct cmd_context *cmd, struct logical_vol
|
||||
return _lv_passes_volumes_filter(cmd, lv, cn, activation_auto_activation_volume_list_CFG);
|
||||
}
|
||||
|
||||
static int _passes_readonly_filter(struct cmd_context *cmd,
|
||||
const struct logical_volume *lv)
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
|
||||
if (!(cn = find_config_tree_array(cmd, activation_read_only_volume_list_CFG, NULL)))
|
||||
return 0;
|
||||
|
||||
return _lv_passes_volumes_filter(cmd, lv, cn, activation_read_only_volume_list_CFG);
|
||||
}
|
||||
|
||||
int lv_passes_readonly_filter(const struct logical_volume *lv)
|
||||
{
|
||||
return _passes_readonly_filter(lv->vg->cmd, lv);
|
||||
}
|
||||
|
||||
#ifndef DEVMAPPER_SUPPORT
|
||||
void set_activation(int act, int silent)
|
||||
{
|
||||
@@ -291,10 +274,6 @@ int lv_raid_message(const struct logical_volume *lv, const char *msg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_raid_status(const struct logical_volume *lv, struct lv_status_raid **status)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_writecache_message(const struct logical_volume *lv, const char *msg)
|
||||
{
|
||||
return 0;
|
||||
@@ -322,11 +301,6 @@ int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_vdo_pool_size_config(const struct logical_volume *lv,
|
||||
struct vdo_pool_size_config *cfg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lvs_in_vg_activated(const struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
@@ -418,7 +392,7 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usable_check_params check, int *is_lv)
|
||||
int device_is_usable(struct device *dev, struct dev_usable_check_params check)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -481,6 +455,17 @@ static int _passes_activation_filter(struct cmd_context *cmd,
|
||||
return _lv_passes_volumes_filter(cmd, lv, cn, activation_volume_list_CFG);
|
||||
}
|
||||
|
||||
static int _passes_readonly_filter(struct cmd_context *cmd,
|
||||
const struct logical_volume *lv)
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
|
||||
if (!(cn = find_config_tree_array(cmd, activation_read_only_volume_list_CFG, NULL)))
|
||||
return 0;
|
||||
|
||||
return _lv_passes_volumes_filter(cmd, lv, cn, activation_read_only_volume_list_CFG);
|
||||
}
|
||||
|
||||
int library_version(char *version, size_t size)
|
||||
{
|
||||
if (!activation())
|
||||
@@ -491,20 +476,12 @@ int library_version(char *version, size_t size)
|
||||
|
||||
int driver_version(char *version, size_t size)
|
||||
{
|
||||
static char _vsn[80] = { 0 };
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
log_very_verbose("Getting driver version");
|
||||
|
||||
if (!_vsn[0] &&
|
||||
!dm_driver_version(_vsn, sizeof(_vsn)))
|
||||
return_0;
|
||||
|
||||
(void) dm_strncpy(version, _vsn, size);
|
||||
|
||||
return 1;
|
||||
return dm_driver_version(version, size);
|
||||
}
|
||||
|
||||
int target_version(const char *target_name, uint32_t *maj,
|
||||
@@ -576,7 +553,7 @@ int module_present(struct cmd_context *cmd, const char *target_name)
|
||||
dm_sysfs_dir(), target_name);
|
||||
|
||||
if (i > 0) {
|
||||
while ((i > 0) && path[--i] != '/') /* stop on dm_ */
|
||||
while (path[--i] != '/') /* stop on dm_ */
|
||||
if (path[i] == '-')
|
||||
path[i] = '_'; /* replace '-' with '_' */
|
||||
|
||||
@@ -587,9 +564,13 @@ int module_present(struct cmd_context *cmd, const char *target_name)
|
||||
}
|
||||
|
||||
#ifdef MODPROBE_CMD
|
||||
if (strcmp(target_name, TARGET_NAME_VDO) == 0)
|
||||
argv[1] = MODULE_NAME_VDO; /* ATM kvdo is without dm- prefix */
|
||||
else if (dm_snprintf(module, sizeof(module), "dm-%s", target_name) < 0) {
|
||||
if (strcmp(target_name, MODULE_NAME_VDO) == 0) {
|
||||
argv[1] = target_name; /* ATM kvdo is without dm- prefix */
|
||||
if ((ret = exec_cmd(cmd, argv, NULL, 0)))
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dm_snprintf(module, sizeof(module), "dm-%s", target_name) < 0) {
|
||||
log_error("module_present module name too long: %s",
|
||||
target_name);
|
||||
return 0;
|
||||
@@ -629,15 +610,6 @@ int target_present(struct cmd_context *cmd, const char *target_name,
|
||||
&maj, &min, &patchlevel);
|
||||
}
|
||||
|
||||
int get_device_list(const struct volume_group *vg, struct dm_list **devs,
|
||||
unsigned *devs_features)
|
||||
{
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
return dev_manager_get_device_list(NULL, devs, devs_features);
|
||||
}
|
||||
|
||||
/*
|
||||
* When '*info' is NULL, returns 1 only when LV is active.
|
||||
* When '*info' != NULL, returns 1 when info structure is populated.
|
||||
@@ -851,15 +823,12 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
|
||||
#define OPEN_COUNT_CHECK_USLEEP_DELAY 200000
|
||||
|
||||
/* Only report error if error_if_used is set */
|
||||
/* Returns 0 if in use, 1 if it is unused, 2 when it is not present in table */
|
||||
int lv_check_not_in_use(const struct logical_volume *lv, int error_if_used)
|
||||
{
|
||||
struct lvinfo info;
|
||||
unsigned int open_count_check_retries;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) || !info.exists)
|
||||
return 2;
|
||||
else if (!info.open_count)
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) || !info.exists || !info.open_count)
|
||||
return 1;
|
||||
|
||||
/* If sysfs is not used, use open_count information only. */
|
||||
@@ -886,24 +855,25 @@ int lv_check_not_in_use(const struct logical_volume *lv, int error_if_used)
|
||||
}
|
||||
|
||||
open_count_check_retries = retry_deactivation() ? OPEN_COUNT_CHECK_RETRIES : 1;
|
||||
while (open_count_check_retries--) {
|
||||
if (interruptible_usleep(OPEN_COUNT_CHECK_USLEEP_DELAY))
|
||||
break; /* interrupted */
|
||||
while (info.open_count > 0 && open_count_check_retries--) {
|
||||
if (!open_count_check_retries) {
|
||||
if (error_if_used)
|
||||
log_error("Logical volume %s in use.", display_lvname(lv));
|
||||
else
|
||||
log_debug_activation("Logical volume %s in use.", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
usleep(OPEN_COUNT_CHECK_USLEEP_DELAY);
|
||||
log_debug_activation("Retrying open_count check for %s.",
|
||||
display_lvname(lv));
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) || !info.exists) {
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, &info, 1, 0)) {
|
||||
stack; /* device dissappeared? */
|
||||
return 1;
|
||||
} else if (!info.open_count)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (error_if_used)
|
||||
log_error("Logical volume %s in use.", display_lvname(lv));
|
||||
else
|
||||
log_debug_activation("Logical volume %s in use.", display_lvname(lv));
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -994,28 +964,35 @@ int lv_raid_percent(const struct logical_volume *lv, dm_percent_t *percent)
|
||||
|
||||
int lv_raid_data_offset(const struct logical_volume *lv, uint64_t *data_offset)
|
||||
{
|
||||
struct lv_status_raid *raid_status;
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
struct dm_status_raid *status;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, NULL, 0, 0))
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking raid data offset and dev sectors for LV %s/%s",
|
||||
lv->vg->name, lv->name);
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!lv_raid_status(lv, &raid_status))
|
||||
return_0;
|
||||
if (!(r = dev_manager_raid_status(dm, lv, &status))) {
|
||||
dev_manager_destroy(dm);
|
||||
return_0;
|
||||
}
|
||||
|
||||
*data_offset = raid_status->raid->data_offset;
|
||||
*data_offset = status->data_offset;
|
||||
|
||||
dm_pool_destroy(raid_status->mem);
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_raid_dev_health(const struct logical_volume *lv, char **dev_health)
|
||||
{
|
||||
int r = 1;
|
||||
struct lv_status_raid *raid_status;
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
struct dm_status_raid *status;
|
||||
|
||||
*dev_health = NULL;
|
||||
|
||||
@@ -1025,23 +1002,25 @@ int lv_raid_dev_health(const struct logical_volume *lv, char **dev_health)
|
||||
log_debug_activation("Checking raid device health for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (!lv_raid_status(lv, &raid_status))
|
||||
return_0;
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!(*dev_health = dm_pool_strdup(lv->vg->cmd->mem,
|
||||
raid_status->raid->dev_health))) {
|
||||
stack;
|
||||
r = 0;
|
||||
if (!(r = dev_manager_raid_status(dm, lv, &status)) ||
|
||||
!(*dev_health = dm_pool_strdup(lv->vg->cmd->mem,
|
||||
status->dev_health))) {
|
||||
dev_manager_destroy(dm);
|
||||
return_0;
|
||||
}
|
||||
|
||||
dm_pool_destroy(raid_status->mem);
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_raid_dev_count(const struct logical_volume *lv, uint32_t *dev_cnt)
|
||||
{
|
||||
struct lv_status_raid *raid_status;
|
||||
struct dev_manager *dm;
|
||||
struct dm_status_raid *status;
|
||||
|
||||
*dev_cnt = 0;
|
||||
|
||||
@@ -1050,20 +1029,24 @@ int lv_raid_dev_count(const struct logical_volume *lv, uint32_t *dev_cnt)
|
||||
|
||||
log_debug_activation("Checking raid device count for LV %s/%s",
|
||||
lv->vg->name, lv->name);
|
||||
|
||||
if (!lv_raid_status(lv, &raid_status))
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
*dev_cnt = raid_status->raid->dev_count;
|
||||
if (!dev_manager_raid_status(dm, lv, &status)) {
|
||||
dev_manager_destroy(dm);
|
||||
return_0;
|
||||
}
|
||||
*dev_cnt = status->dev_count;
|
||||
|
||||
dm_pool_destroy(raid_status->mem);
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_raid_mismatch_count(const struct logical_volume *lv, uint64_t *cnt)
|
||||
{
|
||||
struct lv_status_raid *raid_status;
|
||||
struct dev_manager *dm;
|
||||
struct dm_status_raid *status;
|
||||
|
||||
*cnt = 0;
|
||||
|
||||
@@ -1073,20 +1056,25 @@ int lv_raid_mismatch_count(const struct logical_volume *lv, uint64_t *cnt)
|
||||
log_debug_activation("Checking raid mismatch count for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (!lv_raid_status(lv, &raid_status))
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
*cnt = raid_status->raid->mismatch_count;
|
||||
if (!dev_manager_raid_status(dm, lv, &status)) {
|
||||
dev_manager_destroy(dm);
|
||||
return_0;
|
||||
}
|
||||
*cnt = status->mismatch_count;
|
||||
|
||||
dm_pool_destroy(raid_status->mem);
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_raid_sync_action(const struct logical_volume *lv, char **sync_action)
|
||||
{
|
||||
struct lv_status_raid *raid_status;
|
||||
int r = 1;
|
||||
struct dev_manager *dm;
|
||||
struct dm_status_raid *status;
|
||||
char *action;
|
||||
|
||||
*sync_action = NULL;
|
||||
|
||||
@@ -1096,27 +1084,30 @@ int lv_raid_sync_action(const struct logical_volume *lv, char **sync_action)
|
||||
log_debug_activation("Checking raid sync_action for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (!lv_raid_status(lv, &raid_status))
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
/* status->sync_action can be NULL if dm-raid version < 1.5.0 */
|
||||
if (!raid_status->raid->sync_action ||
|
||||
!(*sync_action = dm_pool_strdup(lv->vg->cmd->mem,
|
||||
raid_status->raid->sync_action))) {
|
||||
stack;
|
||||
r = 0;
|
||||
if (!dev_manager_raid_status(dm, lv, &status) ||
|
||||
!status->sync_action ||
|
||||
!(action = dm_pool_strdup(lv->vg->cmd->mem,
|
||||
status->sync_action))) {
|
||||
dev_manager_destroy(dm);
|
||||
return_0;
|
||||
}
|
||||
|
||||
dm_pool_destroy(raid_status->mem);
|
||||
*sync_action = action;
|
||||
|
||||
return r;
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_raid_message(const struct logical_volume *lv, const char *msg)
|
||||
{
|
||||
struct lv_status_raid *raid_status;
|
||||
struct dev_manager *dm = NULL;
|
||||
int r = 0;
|
||||
struct dev_manager *dm;
|
||||
struct dm_status_raid *status;
|
||||
|
||||
if (!seg_is_raid(first_seg(lv))) {
|
||||
/*
|
||||
@@ -1141,10 +1132,16 @@ int lv_raid_message(const struct logical_volume *lv, const char *msg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_raid_status(lv, &raid_status))
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!raid_status->raid->sync_action) {
|
||||
if (!(r = dev_manager_raid_status(dm, lv, &status))) {
|
||||
log_error("Failed to retrieve status of %s.",
|
||||
display_lvname(lv));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!status->sync_action) {
|
||||
log_error("Kernel driver does not support this action: %s", msg);
|
||||
goto out;
|
||||
}
|
||||
@@ -1166,43 +1163,19 @@ int lv_raid_message(const struct logical_volume *lv, const char *msg)
|
||||
log_error("\"%s\" is not a supported sync operation.", msg);
|
||||
goto out;
|
||||
}
|
||||
if (strcmp(raid_status->raid->sync_action, "idle")) {
|
||||
if (strcmp(status->sync_action, "idle")) {
|
||||
log_error("%s state is currently \"%s\". Unable to switch to \"%s\".",
|
||||
display_lvname(lv), raid_status->raid->sync_action, msg);
|
||||
display_lvname(lv), status->sync_action, msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
r = dev_manager_raid_message(dm, lv, msg);
|
||||
out:
|
||||
if (dm)
|
||||
dev_manager_destroy(dm);
|
||||
dm_pool_destroy(raid_status->mem);
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_raid_status(const struct logical_volume *lv, struct lv_status_raid **status)
|
||||
{
|
||||
struct dev_manager *dm;
|
||||
int exists;
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!dev_manager_raid_status(dm, lv, status, &exists)) {
|
||||
dev_manager_destroy(dm);
|
||||
if (exists)
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
/* User has to call dm_pool_destroy(status->mem)! */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_writecache_message(const struct logical_volume *lv, const char *msg)
|
||||
{
|
||||
int r = 0;
|
||||
@@ -1235,7 +1208,6 @@ int lv_cache_status(const struct logical_volume *cache_lv,
|
||||
{
|
||||
struct dev_manager *dm;
|
||||
struct lv_segment *cache_seg;
|
||||
int exists;
|
||||
|
||||
if (lv_is_cache_pool(cache_lv)) {
|
||||
if (dm_list_empty(&cache_lv->segs_using_this_lv) ||
|
||||
@@ -1253,14 +1225,21 @@ int lv_cache_status(const struct logical_volume *cache_lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info(cache_lv->vg->cmd, cache_lv, 1, NULL, 0, 0)) {
|
||||
log_error("Cannot check status for locally inactive cache volume %s.",
|
||||
display_lvname(cache_lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug_activation("Checking status for cache volume %s.",
|
||||
display_lvname(cache_lv));
|
||||
|
||||
if (!(dm = dev_manager_create(cache_lv->vg->cmd, cache_lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!dev_manager_cache_status(dm, cache_lv, status, &exists)) {
|
||||
if (!dev_manager_cache_status(dm, cache_lv, status)) {
|
||||
dev_manager_destroy(dm);
|
||||
if (exists)
|
||||
stack;
|
||||
return 0;
|
||||
return_0;
|
||||
}
|
||||
/* User has to call dm_pool_destroy(status->mem)! */
|
||||
|
||||
@@ -1271,16 +1250,19 @@ int lv_thin_pool_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin_pool **thin_pool_status)
|
||||
{
|
||||
struct dev_manager *dm;
|
||||
int exists;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking thin pool status for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!dev_manager_thin_pool_status(dm, lv, flush, thin_pool_status, &exists)) {
|
||||
if (!dev_manager_thin_pool_status(dm, lv, flush, thin_pool_status)) {
|
||||
dev_manager_destroy(dm);
|
||||
if (exists)
|
||||
stack;
|
||||
return 0;
|
||||
return_0;
|
||||
}
|
||||
|
||||
/* User has to call dm_pool_destroy(thin_pool_status->mem)! */
|
||||
@@ -1292,16 +1274,19 @@ int lv_thin_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin **thin_status)
|
||||
{
|
||||
struct dev_manager *dm;
|
||||
int exists;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, NULL, 0, 0))
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking thin status for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!dev_manager_thin_status(dm, lv, flush, thin_status, &exists)) {
|
||||
if (!dev_manager_thin_status(dm, lv, flush, thin_status)) {
|
||||
dev_manager_destroy(dm);
|
||||
if (exists)
|
||||
stack;
|
||||
return 0;
|
||||
return_0;
|
||||
}
|
||||
|
||||
/* User has to call dm_pool_destroy(thin_status->mem)! */
|
||||
@@ -1311,16 +1296,20 @@ int lv_thin_status(const struct logical_volume *lv, int flush,
|
||||
|
||||
int lv_thin_device_id(const struct logical_volume *lv, uint32_t *device_id)
|
||||
{
|
||||
struct dev_manager *dm;
|
||||
int exists;
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, NULL, 0, 0))
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking device id for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!(r = dev_manager_thin_device_id(dm, lv, device_id, &exists)))
|
||||
if (exists)
|
||||
stack;
|
||||
if (!(r = dev_manager_thin_device_id(dm, lv, device_id)))
|
||||
stack;
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
@@ -1337,22 +1326,28 @@ int lv_thin_device_id(const struct logical_volume *lv, uint32_t *device_id)
|
||||
int lv_vdo_pool_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_vdo **vdo_status)
|
||||
{
|
||||
int r = 0;
|
||||
struct dev_manager *dm;
|
||||
int exists;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking VDO pool status for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, !lv_is_pvmove(lv))))
|
||||
return_0;
|
||||
|
||||
if (!dev_manager_vdo_pool_status(dm, lv, flush, vdo_status, &exists)) {
|
||||
dev_manager_destroy(dm);
|
||||
if (exists)
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!dev_manager_vdo_pool_status(dm, lv, vdo_status, flush))
|
||||
goto_out;
|
||||
|
||||
/* User has to call dm_pool_destroy(vdo_status->mem) */
|
||||
r = 1;
|
||||
out:
|
||||
if (!r)
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent)
|
||||
@@ -1368,32 +1363,6 @@ int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* lv_vdo_pool_size_config obtains size configuration from active VDO table line
|
||||
*
|
||||
* If the 'params' string has been already retrieved, use it.
|
||||
* If the mempool already exists, use it.
|
||||
*
|
||||
*/
|
||||
int lv_vdo_pool_size_config(const struct logical_volume *lv,
|
||||
struct vdo_pool_size_config *cfg)
|
||||
{
|
||||
struct dev_manager *dm;
|
||||
int r;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
|
||||
return 1; /* Inactive VDO pool -> no runtime config */
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, !lv_is_pvmove(lv))))
|
||||
return_0;
|
||||
|
||||
r = dev_manager_vdo_pool_size_config(dm, lv, cfg);
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lv_active(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
{
|
||||
struct lvinfo info;
|
||||
@@ -1539,7 +1508,7 @@ int lvs_in_vg_opened(const struct volume_group *vg)
|
||||
*/
|
||||
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype)
|
||||
{
|
||||
unsigned attrs = 0;
|
||||
unsigned attrs;
|
||||
|
||||
if (segtype_is_raid4(segtype) &&
|
||||
(!segtype->ops->target_present ||
|
||||
@@ -2074,6 +2043,12 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
/* Ignore origin_only unless LV is origin in both old and new metadata */
|
||||
/* or LV is thin or thin pool volume */
|
||||
if (!lv_is_thin_volume(lv) && !lv_is_thin_pool(lv) &&
|
||||
!(lv_is_origin(lv) && lv_is_origin(lv_pre)))
|
||||
laopts->origin_only = 0;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Suspending %s%s.", display_lvname(lv),
|
||||
laopts->origin_only ? " origin without snapshots" : "");
|
||||
@@ -2095,12 +2070,6 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
|
||||
lv_calculate_readahead(lv, NULL);
|
||||
|
||||
/* Ignore origin_only unless LV is origin in both old and new metadata */
|
||||
/* or LV is thin or thin pool volume */
|
||||
if (!lv_is_thin_volume(lv) && !lv_is_thin_pool(lv) &&
|
||||
!(lv_is_origin(lv) && lv_is_origin(lv_pre)))
|
||||
laopts->origin_only = 0;
|
||||
|
||||
/*
|
||||
* Preload devices for the LV.
|
||||
* If the PVMOVE LV is being removed, it's only present in the old
|
||||
@@ -2172,11 +2141,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
* TODO: Relax this limiting condition further */
|
||||
if (!flush_required &&
|
||||
(lv_is_pvmove(lv) || pvmove_lv ||
|
||||
(!lv_is_mirror(lv) &&
|
||||
!lv_is_thin_volume(lv) &&
|
||||
!lv_is_thin_pool(lv) &&
|
||||
!lv_is_vdo(lv) &&
|
||||
!lv_is_vdo_pool(lv)))) {
|
||||
(!lv_is_mirror(lv) && !lv_is_thin_pool(lv) && !lv_is_thin_volume(lv)))) {
|
||||
log_debug("Requiring flush for LV %s.", display_lvname(lv));
|
||||
flush_required = 1;
|
||||
}
|
||||
@@ -2426,7 +2391,6 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
|
||||
static const struct lv_activate_opts laopts = { .skip_in_use = 1 };
|
||||
struct dm_list *snh;
|
||||
int r = 0;
|
||||
unsigned tmp_state;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
@@ -2439,47 +2403,44 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
|
||||
|
||||
log_debug_activation("Deactivating %s.", display_lvname(lv));
|
||||
|
||||
if (!lv_info(cmd, lv, 0, &info, 0, 0))
|
||||
goto_out;
|
||||
|
||||
if (!info.exists) {
|
||||
r = 1;
|
||||
/* Check attached snapshot segments are also inactive */
|
||||
dm_list_iterate(snh, &lv->snapshot_segs) {
|
||||
if (!lv_info(cmd, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow,
|
||||
0, &info, 0, 0))
|
||||
goto_out;
|
||||
if (info.exists) {
|
||||
r = 0; /* Snapshot left in table? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lv_is_vdo_pool(lv)) {
|
||||
/* If someone has remove 'linear' mapping over VDO device
|
||||
* we may still be able to deactivate the rest of the tree
|
||||
* i.e. in test-suite we simulate this via 'dmsetup remove' */
|
||||
if (!lv_info(cmd, lv, 1, &info, 1, 0))
|
||||
goto_out;
|
||||
|
||||
if (info.exists && !info.open_count)
|
||||
r = 0; /* Unused VDO device left in table? */
|
||||
}
|
||||
|
||||
if (r)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lv_is_visible(lv) || lv_is_virtual_origin(lv) ||
|
||||
lv_is_merging_thin_snapshot(lv)) {
|
||||
switch (lv_check_not_in_use(lv, 1)) {
|
||||
case 0: goto_out;
|
||||
case 2: goto no_exists;
|
||||
}
|
||||
if (!lv_check_not_in_use(lv, 1))
|
||||
goto_out;
|
||||
|
||||
if (lv_is_origin(lv) && _lv_has_open_snapshots(lv))
|
||||
goto_out;
|
||||
} else {
|
||||
if (!lv_info(cmd, lv, 0, &info, 0, 0))
|
||||
goto_out;
|
||||
|
||||
if (!info.exists) {
|
||||
no_exists:
|
||||
r = 1;
|
||||
/* Check attached snapshot segments are also inactive */
|
||||
dm_list_iterate(snh, &lv->snapshot_segs) {
|
||||
if (!lv_info(cmd, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow,
|
||||
0, &info, 0, 0))
|
||||
goto_out;
|
||||
if (info.exists) {
|
||||
r = 0; /* Snapshot left in table? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lv_is_vdo_pool(lv)) {
|
||||
/* If someone has remove 'linear' mapping over VDO device
|
||||
* we may still be able to deactivate the rest of the tree
|
||||
* i.e. in test-suite we simulate this via 'dmsetup remove' */
|
||||
if (!lv_info(cmd, lv, 1, &info, 1, 0))
|
||||
goto_out;
|
||||
|
||||
if (info.exists && !info.open_count)
|
||||
r = 0; /* Unused VDO device left in table? */
|
||||
}
|
||||
|
||||
if (r)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!monitor_dev_for_events(cmd, lv, &laopts, 0))
|
||||
@@ -2499,17 +2460,12 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
|
||||
}
|
||||
critical_section_dec(cmd, "deactivated");
|
||||
|
||||
tmp_state = cmd->disable_dm_devs;
|
||||
cmd->disable_dm_devs = 1;
|
||||
|
||||
if (!lv_info(cmd, lv, 0, &info, 0, 0) || info.exists) {
|
||||
/* Turn into log_error, but we do not log error */
|
||||
log_debug_activation("Deactivated volume is still %s present.",
|
||||
display_lvname(lv));
|
||||
r = 0;
|
||||
}
|
||||
|
||||
cmd->disable_dm_devs = tmp_state;
|
||||
out:
|
||||
|
||||
return r;
|
||||
@@ -2795,13 +2751,10 @@ static int _component_cb(struct logical_volume *lv, void *data)
|
||||
|
||||
if (lv_is_locked(lv) || lv_is_pvmove(lv) ||/* ignoring */
|
||||
/* thin-pool is special and it's using layered device */
|
||||
(lv_is_thin_pool(lv) && thin_pool_is_active(lv)))
|
||||
(lv_is_thin_pool(lv) && pool_is_active(lv)))
|
||||
return -1;
|
||||
|
||||
/* External origin is activated through thinLV and uses -real suffix.
|
||||
* Note: for old clustered logic we would need to check for all thins */
|
||||
if ((lv_is_external_origin(lv) && lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0)) ||
|
||||
lv_is_active(lv)) {
|
||||
if (lv_is_active(lv)) {
|
||||
if (!lv_is_component(lv) || lv_is_visible(lv))
|
||||
return -1; /* skip whole subtree */
|
||||
|
||||
@@ -2884,7 +2837,7 @@ static int _deactivate_sub_lv_cb(struct logical_volume *lv, void *data)
|
||||
*/
|
||||
int deactivate_lv_with_sub_lv(const struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *flv = NULL;
|
||||
struct logical_volume *flv;
|
||||
|
||||
if (!deactivate_lv(lv->vg->cmd, lv)) {
|
||||
log_error("Cannot deactivate logical volume %s.",
|
||||
@@ -2894,7 +2847,7 @@ int deactivate_lv_with_sub_lv(const struct logical_volume *lv)
|
||||
|
||||
if (!for_each_sub_lv((struct logical_volume *)lv, _deactivate_sub_lv_cb, &flv)) {
|
||||
log_error("Cannot deactivate subvolume %s of logical volume %s.",
|
||||
(flv) ? display_lvname(flv) : "", display_lvname(lv));
|
||||
display_lvname(flv), display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,10 +106,6 @@ int target_present(struct cmd_context *cmd, const char *target_name,
|
||||
int use_modprobe);
|
||||
int target_version(const char *target_name, uint32_t *maj,
|
||||
uint32_t *min, uint32_t *patchlevel);
|
||||
|
||||
int get_device_list(const struct volume_group *vg, struct dm_list **devs,
|
||||
unsigned *devs_features);
|
||||
|
||||
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype);
|
||||
int lvm_dm_prefix_check(int major, int minor, const char *prefix);
|
||||
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
@@ -192,7 +188,6 @@ int lv_raid_dev_health(const struct logical_volume *lv, char **dev_health);
|
||||
int lv_raid_mismatch_count(const struct logical_volume *lv, uint64_t *cnt);
|
||||
int lv_raid_sync_action(const struct logical_volume *lv, char **sync_action);
|
||||
int lv_raid_message(const struct logical_volume *lv, const char *msg);
|
||||
int lv_raid_status(const struct logical_volume *lv, struct lv_status_raid **status);
|
||||
int lv_writecache_message(const struct logical_volume *lv, const char *msg);
|
||||
int lv_cache_status(const struct logical_volume *cache_lv,
|
||||
struct lv_status_cache **status);
|
||||
@@ -204,8 +199,6 @@ int lv_thin_pool_status(const struct logical_volume *lv, int flush,
|
||||
int lv_vdo_pool_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_vdo **status);
|
||||
int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent);
|
||||
int lv_vdo_pool_size_config(const struct logical_volume *lv,
|
||||
struct vdo_pool_size_config *cfg);
|
||||
|
||||
/*
|
||||
* Return number of LVs in the VG that are active.
|
||||
@@ -215,8 +208,6 @@ int lvs_in_vg_opened(const struct volume_group *vg);
|
||||
|
||||
int lv_is_active(const struct logical_volume *lv);
|
||||
|
||||
int lv_passes_readonly_filter(const struct logical_volume *lv);
|
||||
|
||||
/* Check is any component LV is active */
|
||||
const struct logical_volume *lv_component_is_active(const struct logical_volume *lv);
|
||||
const struct logical_volume *lv_holder_is_active(const struct logical_volume *lv);
|
||||
@@ -260,7 +251,7 @@ struct dev_usable_check_params {
|
||||
* Returns 1 if mapped device is not suspended, blocked or
|
||||
* is using a reserved name.
|
||||
*/
|
||||
int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usable_check_params check, int *is_lv);
|
||||
int device_is_usable(struct device *dev, struct dev_usable_check_params check);
|
||||
|
||||
/*
|
||||
* Declaration moved here from fs.h to keep header fs.h hidden
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/misc/lvm-exec.h"
|
||||
#include "lib/datastruct/str_list.h"
|
||||
#include "lib/misc/lvm-signal.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
@@ -107,8 +106,6 @@ static struct dm_task *_setup_task_run(int task, struct dm_info *info,
|
||||
int with_flush,
|
||||
int query_inactive)
|
||||
{
|
||||
char vsn[80];
|
||||
unsigned maj, min;
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!(dmt = dm_task_create(task)))
|
||||
@@ -140,20 +137,8 @@ static struct dm_task *_setup_task_run(int task, struct dm_info *info,
|
||||
if (!with_flush && !dm_task_no_flush(dmt))
|
||||
log_warn("WARNING: Failed to set no_flush.");
|
||||
|
||||
switch (task) {
|
||||
case DM_DEVICE_TARGET_MSG:
|
||||
if (task == DM_DEVICE_TARGET_MSG)
|
||||
return dmt; /* TARGET_MSG needs more local tweaking before task_run() */
|
||||
case DM_DEVICE_LIST:
|
||||
/* Use 'newuuid' only with DM version that supports it */
|
||||
if (driver_version(vsn, sizeof(vsn)) &&
|
||||
(sscanf(vsn, "%u.%u", &maj, &min) == 2) &&
|
||||
(maj == 4 ? min >= 19 : maj > 4) &&
|
||||
!dm_task_set_newuuid(dmt, " ")) // new uuid has no meaning here
|
||||
log_warn("WARNING: Failed to query uuid with LIST.");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt))
|
||||
goto_out;
|
||||
@@ -171,7 +156,6 @@ out:
|
||||
|
||||
static int _get_segment_status_from_target_params(const char *target_name,
|
||||
const char *params,
|
||||
const struct dm_info *dminfo,
|
||||
struct lv_seg_status *seg_status)
|
||||
{
|
||||
const struct lv_segment *seg = seg_status->seg;
|
||||
@@ -204,7 +188,7 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
||||
/* If kernel's type isn't an exact match is it compatible? */
|
||||
(!segtype->ops->target_status_compatible ||
|
||||
!segtype->ops->target_status_compatible(target_name))) {
|
||||
log_warn("WARNING: Detected %s segment type does not match expected type %s for %s.",
|
||||
log_warn(INTERNAL_ERROR "WARNING: Segment type %s found does not match expected type %s for %s.",
|
||||
target_name, segtype->name, display_lvname(seg_status->seg->lv));
|
||||
return 0;
|
||||
}
|
||||
@@ -231,7 +215,7 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_SNAPSHOT;
|
||||
} else if (segtype_is_vdo_pool(segtype)) {
|
||||
if (!parse_vdo_pool_status(seg_status->mem, seg->lv, params, dminfo, &seg_status->vdo_pool))
|
||||
if (!parse_vdo_pool_status(seg_status->mem, seg->lv, params, &seg_status->vdo_pool))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_VDO_POOL;
|
||||
} else if (segtype_is_writecache(segtype)) {
|
||||
@@ -277,7 +261,7 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
|
||||
int dmtask;
|
||||
int with_flush; /* TODO: arg for _info_run */
|
||||
void *target = NULL;
|
||||
uint64_t target_start, target_length, start, extent_size, length, length_crop = 0;
|
||||
uint64_t target_start, target_length, start, length;
|
||||
char *target_name, *target_params;
|
||||
const char *devname;
|
||||
|
||||
@@ -306,14 +290,14 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
|
||||
|
||||
/* Query status only for active device */
|
||||
if (seg_status && dminfo->exists) {
|
||||
extent_size = length = seg_status->seg->lv->vg->extent_size;
|
||||
start = extent_size * seg_status->seg->le;
|
||||
start = length = seg_status->seg->lv->vg->extent_size;
|
||||
start *= seg_status->seg->le;
|
||||
length *= _seg_len(seg_status->seg);
|
||||
|
||||
/* Uses max DM_THIN_MAX_METADATA_SIZE sectors for metadata device */
|
||||
if (lv_is_thin_pool_metadata(seg_status->seg->lv) &&
|
||||
(length > DM_THIN_MAX_METADATA_SIZE))
|
||||
length_crop = DM_THIN_MAX_METADATA_SIZE;
|
||||
length = DM_THIN_MAX_METADATA_SIZE;
|
||||
|
||||
/* Uses virtual size with headers for VDO pool device */
|
||||
if (lv_is_vdo_pool(seg_status->seg->lv))
|
||||
@@ -326,18 +310,14 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
|
||||
target = dm_get_next_target(dmt, target, &target_start,
|
||||
&target_length, &target_name, &target_params);
|
||||
|
||||
if ((start == target_start) &&
|
||||
((length == target_length) ||
|
||||
((lv_is_vdo_pool(seg_status->seg->lv)) && /* should fit within extent size */
|
||||
(length < target_length) && ((length + extent_size) > target_length)) ||
|
||||
(length_crop && (length_crop == target_length))))
|
||||
if ((start == target_start) && (length == target_length))
|
||||
break; /* Keep target_params when matching segment is found */
|
||||
|
||||
target_params = NULL; /* Marking this target_params unusable */
|
||||
} while (target);
|
||||
|
||||
if (!target_name ||
|
||||
!_get_segment_status_from_target_params(target_name, target_params, dminfo, seg_status))
|
||||
!_get_segment_status_from_target_params(target_name, target_params, seg_status))
|
||||
stack;
|
||||
}
|
||||
|
||||
@@ -375,8 +355,7 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
|
||||
*
|
||||
* Returns: 1 if mirror should be ignored, 0 if safe to use
|
||||
*/
|
||||
static int _ignore_blocked_mirror_devices(struct cmd_context *cmd,
|
||||
struct device *dev,
|
||||
static int _ignore_blocked_mirror_devices(struct device *dev,
|
||||
uint64_t start, uint64_t length,
|
||||
char *mirror_status_str)
|
||||
{
|
||||
@@ -419,12 +398,12 @@ static int _ignore_blocked_mirror_devices(struct cmd_context *cmd,
|
||||
goto_out;
|
||||
|
||||
tmp_dev->dev = MKDEV(sm->logs[0].major, sm->logs[0].minor);
|
||||
if (device_is_usable(cmd, tmp_dev, (struct dev_usable_check_params)
|
||||
if (device_is_usable(tmp_dev, (struct dev_usable_check_params)
|
||||
{ .check_empty = 1,
|
||||
.check_blocked = 1,
|
||||
.check_suspended = ignore_suspended_devices(),
|
||||
.check_error_target = 1,
|
||||
.check_reserved = 0 }, NULL))
|
||||
.check_reserved = 0 }))
|
||||
goto out; /* safe to use */
|
||||
stack;
|
||||
}
|
||||
@@ -623,60 +602,6 @@ static int _ignore_frozen_raid(struct device *dev, const char *params)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _is_usable_uuid(const struct device *dev, const char *name, const char *uuid, int check_reserved, int check_lv, int *is_lv)
|
||||
{
|
||||
char *vgname, *lvname, *layer;
|
||||
char vg_name[NAME_LEN];
|
||||
|
||||
if (!check_reserved && !check_lv)
|
||||
return 1;
|
||||
|
||||
if (!strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1)) { /* with LVM- prefix */
|
||||
if (check_reserved) {
|
||||
/* Check internal lvm devices */
|
||||
if (strlen(uuid) > (sizeof(UUID_PREFIX) + 2 * ID_LEN)) { /* 68 with suffix */
|
||||
log_debug_activation("%s: Reserved uuid %s on internal LV device %s not usable.",
|
||||
dev_name(dev), uuid, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Recognize some older reserved LVs just from the LV name (snapshot, pvmove...) */
|
||||
vgname = vg_name;
|
||||
if (!dm_strncpy(vg_name, name, sizeof(vg_name)) ||
|
||||
!dm_split_lvm_name(NULL, NULL, &vgname, &lvname, &layer))
|
||||
return_0;
|
||||
|
||||
/* FIXME: fails to handle dev aliases i.e. /dev/dm-5, replace with UUID suffix */
|
||||
if (lvname && (is_reserved_lvname(lvname) || *layer)) {
|
||||
log_debug_activation("%s: Reserved internal LV device %s/%s%s%s not usable.",
|
||||
dev_name(dev), vgname, lvname, *layer ? "-" : "", layer);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (check_lv) {
|
||||
/* Skip LVs */
|
||||
if (is_lv)
|
||||
*is_lv = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (check_reserved &&
|
||||
(!strncmp(uuid, CRYPT_TEMP, sizeof(CRYPT_TEMP) - 1) ||
|
||||
!strncmp(uuid, CRYPT_SUBDEV, sizeof(CRYPT_SUBDEV) - 1) ||
|
||||
!strncmp(uuid, STRATIS, sizeof(STRATIS) - 1))) {
|
||||
/* Skip private crypto devices */
|
||||
log_debug_activation("%s: Reserved uuid %s on %s device %s not usable.",
|
||||
dev_name(dev), uuid,
|
||||
uuid[0] == 'C' ? "crypto" : "stratis",
|
||||
name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* device_is_usable
|
||||
* @dev
|
||||
@@ -693,16 +618,16 @@ static int _is_usable_uuid(const struct device *dev, const char *name, const cha
|
||||
*
|
||||
* Returns: 1 if usable, 0 otherwise
|
||||
*/
|
||||
int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usable_check_params check, int *is_lv)
|
||||
int device_is_usable(struct device *dev, struct dev_usable_check_params check)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
const char *name, *uuid;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
char *params, *vgname = NULL, *lvname, *layer;
|
||||
void *next = NULL;
|
||||
int only_error_or_zero_target = 1;
|
||||
int only_error_target = 1;
|
||||
int r = 0;
|
||||
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_STATUS, &info, NULL, NULL, NULL,
|
||||
@@ -725,9 +650,43 @@ int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usa
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (uuid &&
|
||||
!_is_usable_uuid(dev, name, uuid, check.check_reserved, check.check_lv, is_lv))
|
||||
/* Check internal lvm devices */
|
||||
if (check.check_reserved &&
|
||||
uuid && !strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1)) {
|
||||
if (strlen(uuid) > (sizeof(UUID_PREFIX) + 2 * ID_LEN)) { /* 68 */
|
||||
log_debug_activation("%s: Reserved uuid %s on internal LV device %s not usable.",
|
||||
dev_name(dev), uuid, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(vgname = strdup(name)) ||
|
||||
!dm_split_lvm_name(NULL, NULL, &vgname, &lvname, &layer))
|
||||
goto_out;
|
||||
|
||||
/* FIXME: fails to handle dev aliases i.e. /dev/dm-5, replace with UUID suffix */
|
||||
if (lvname && (is_reserved_lvname(lvname) || *layer)) {
|
||||
log_debug_activation("%s: Reserved internal LV device %s/%s%s%s not usable.",
|
||||
dev_name(dev), vgname, lvname, *layer ? "-" : "", layer);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (check.check_lv && uuid && !strncmp(uuid, "LVM-", 4)) {
|
||||
/* Skip LVs */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (check.check_reserved && uuid &&
|
||||
(!strncmp(uuid, CRYPT_TEMP, sizeof(CRYPT_TEMP) - 1) ||
|
||||
!strncmp(uuid, CRYPT_SUBDEV, sizeof(CRYPT_SUBDEV) - 1) ||
|
||||
!strncmp(uuid, STRATIS, sizeof(STRATIS) - 1))) {
|
||||
/* Skip private crypto devices */
|
||||
log_debug_activation("%s: Reserved uuid %s on %s device %s not usable.",
|
||||
dev_name(dev), uuid,
|
||||
uuid[0] == 'C' ? "crypto" : "stratis",
|
||||
name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* FIXME Also check for mpath no paths */
|
||||
do {
|
||||
@@ -742,7 +701,7 @@ int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usa
|
||||
log_debug_activation("%s: Scanning mirror devices is disabled.", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
if (!_ignore_blocked_mirror_devices(cmd, dev, start,
|
||||
if (!_ignore_blocked_mirror_devices(dev, start,
|
||||
length, params)) {
|
||||
log_debug_activation("%s: Mirror device %s not usable.",
|
||||
dev_name(dev), name);
|
||||
@@ -797,15 +756,13 @@ int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usa
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (only_error_or_zero_target &&
|
||||
strcmp(target_type, TARGET_NAME_ERROR) &&
|
||||
strcmp(target_type, TARGET_NAME_ZERO))
|
||||
only_error_or_zero_target = 0;
|
||||
if (strcmp(target_type, TARGET_NAME_ERROR))
|
||||
only_error_target = 0;
|
||||
} while (next);
|
||||
|
||||
/* Skip devices consisting entirely of error or zero targets. */
|
||||
/* Skip devices consisting entirely of error targets. */
|
||||
/* FIXME Deal with device stacked above error targets? */
|
||||
if (check.check_error_target && only_error_or_zero_target) {
|
||||
if (check.check_error_target && only_error_target) {
|
||||
log_debug_activation("%s: Error device %s not usable.",
|
||||
dev_name(dev), name);
|
||||
goto out;
|
||||
@@ -816,6 +773,7 @@ int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usa
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
free(vgname);
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
@@ -867,12 +825,13 @@ static int _info(struct cmd_context *cmd,
|
||||
return 1;
|
||||
|
||||
/* Check for original version of dlid before the suffixes got added in 2.02.106 */
|
||||
if ((suffix_position = strrchr(dlid, '-'))) {
|
||||
if ((suffix_position = rindex(dlid, '-'))) {
|
||||
while ((suffix = uuid_suffix_list[i++])) {
|
||||
if (strcmp(suffix_position + 1, suffix))
|
||||
continue;
|
||||
|
||||
(void) dm_strncpy(old_style_dlid, dlid, sizeof(old_style_dlid));
|
||||
(void) strncpy(old_style_dlid, dlid, sizeof(old_style_dlid));
|
||||
old_style_dlid[sizeof(old_style_dlid) - 1] = '\0';
|
||||
if (!_info_run(old_style_dlid, dminfo, read_ahead, seg_status,
|
||||
name_check, with_open_count, with_read_ahead,
|
||||
0, 0))
|
||||
@@ -938,25 +897,6 @@ int dev_manager_check_prefix_dm_major_minor(uint32_t major, uint32_t minor, cons
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_manager_get_device_list(const char *prefix, struct dm_list **devs, unsigned *devs_features)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
int r = 1;
|
||||
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_LIST, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0)))
|
||||
return_0;
|
||||
|
||||
if (!dm_task_get_device_list(dmt, devs, devs_features)) {
|
||||
r = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_manager_info(struct cmd_context *cmd,
|
||||
const struct logical_volume *lv, const char *layer,
|
||||
int with_open_count, int with_read_ahead, int with_name_check,
|
||||
@@ -972,16 +912,6 @@ int dev_manager_info(struct cmd_context *cmd,
|
||||
if (!(dlid = build_dm_uuid(cmd->mem, lv, layer)))
|
||||
goto_out;
|
||||
|
||||
if (!cmd->disable_dm_devs &&
|
||||
cmd->cache_dm_devs &&
|
||||
!dm_device_list_find_by_uuid(cmd->cache_dm_devs, dlid, NULL)) {
|
||||
log_debug("Cached as inactive %s.", name);
|
||||
if (dminfo)
|
||||
memset(dminfo, 0, sizeof(*dminfo));
|
||||
r = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(r = _info(cmd, name, dlid,
|
||||
with_open_count, with_read_ahead, with_name_check,
|
||||
dminfo, read_ahead, seg_status)))
|
||||
@@ -1183,8 +1113,7 @@ static int _percent_run(struct dev_manager *dm, const char *name,
|
||||
const char *dlid,
|
||||
const char *target_type, int wait,
|
||||
const struct logical_volume *lv, dm_percent_t *overall_percent,
|
||||
uint32_t *event_nr, int fail_if_percent_unsupported,
|
||||
int *interrupted)
|
||||
uint32_t *event_nr, int fail_if_percent_unsupported)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
@@ -1205,12 +1134,9 @@ static int _percent_run(struct dev_manager *dm, const char *name,
|
||||
if (!(segtype = get_segtype_from_string(dm->cmd, target_type)))
|
||||
return_0;
|
||||
|
||||
if (wait)
|
||||
sigint_allow();
|
||||
|
||||
if (!(dmt = _setup_task_run(wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS, &info,
|
||||
name, dlid, event_nr, 0, 0, 0, 0, 0)))
|
||||
goto_bad;
|
||||
return_0;
|
||||
|
||||
if (!info.exists)
|
||||
goto_out;
|
||||
@@ -1278,19 +1204,8 @@ static int _percent_run(struct dev_manager *dm, const char *name,
|
||||
display_percent(dm->cmd, *overall_percent));
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
bad:
|
||||
if (wait) {
|
||||
sigint_restore();
|
||||
|
||||
if (sigint_caught()) {
|
||||
*interrupted = 1;
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1299,24 +1214,20 @@ static int _percent(struct dev_manager *dm, const char *name, const char *dlid,
|
||||
const struct logical_volume *lv, dm_percent_t *percent,
|
||||
uint32_t *event_nr, int fail_if_percent_unsupported)
|
||||
{
|
||||
int interrupted = 0;
|
||||
|
||||
if (dlid && *dlid) {
|
||||
if (_percent_run(dm, NULL, dlid, target_type, wait, lv, percent,
|
||||
event_nr, fail_if_percent_unsupported, &interrupted))
|
||||
event_nr, fail_if_percent_unsupported))
|
||||
return 1;
|
||||
|
||||
if (!interrupted &&
|
||||
_original_uuid_format_check_required(dm->cmd) &&
|
||||
if (_original_uuid_format_check_required(dm->cmd) &&
|
||||
_percent_run(dm, NULL, dlid + sizeof(UUID_PREFIX) - 1,
|
||||
target_type, wait, lv, percent,
|
||||
event_nr, fail_if_percent_unsupported, &interrupted))
|
||||
event_nr, fail_if_percent_unsupported))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!interrupted && name &&
|
||||
_percent_run(dm, name, NULL, target_type, wait, lv, percent,
|
||||
event_nr, fail_if_percent_unsupported, &interrupted))
|
||||
if (name && _percent_run(dm, name, NULL, target_type, wait, lv, percent,
|
||||
event_nr, fail_if_percent_unsupported))
|
||||
return 1;
|
||||
|
||||
return_0;
|
||||
@@ -1518,7 +1429,7 @@ int dev_manager_mirror_percent(struct dev_manager *dm,
|
||||
|
||||
int dev_manager_raid_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct lv_status_raid **status, int *exists)
|
||||
struct dm_status_raid **status)
|
||||
{
|
||||
int r = 0;
|
||||
const char *dlid;
|
||||
@@ -1528,11 +1439,6 @@ int dev_manager_raid_status(struct dev_manager *dm,
|
||||
char *type = NULL;
|
||||
char *params = NULL;
|
||||
const char *layer = lv_layer(lv);
|
||||
struct dm_status_raid *sr;
|
||||
|
||||
*exists = -1;
|
||||
if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_cache))))
|
||||
return_0;
|
||||
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, layer)))
|
||||
return_0;
|
||||
@@ -1540,11 +1446,8 @@ int dev_manager_raid_status(struct dev_manager *dm,
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_STATUS, &info, NULL, dlid, 0, 0, 0, 0, 0, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(*exists = info.exists))
|
||||
goto out;
|
||||
|
||||
log_debug_activation("Checking raid status for volume %s.",
|
||||
display_lvname(lv));
|
||||
if (!info.exists)
|
||||
goto_out;
|
||||
|
||||
dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms);
|
||||
|
||||
@@ -1556,13 +1459,9 @@ int dev_manager_raid_status(struct dev_manager *dm,
|
||||
|
||||
/* FIXME Check there's only one target */
|
||||
|
||||
if (!dm_get_status_raid(dm->mem, params, &sr))
|
||||
if (!dm_get_status_raid(dm->mem, params, status))
|
||||
goto_out;
|
||||
|
||||
(*status)->mem = dm->mem; /* User has to destroy this mem pool later */
|
||||
(*status)->raid = sr;
|
||||
(*status)->in_sync = dm_make_percent(sr->insync_regions, sr->total_regions);
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
@@ -1651,7 +1550,7 @@ out:
|
||||
|
||||
int dev_manager_cache_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct lv_status_cache **status, int *exists)
|
||||
struct lv_status_cache **status)
|
||||
{
|
||||
int r = 0;
|
||||
const char *dlid;
|
||||
@@ -1662,18 +1561,14 @@ int dev_manager_cache_status(struct dev_manager *dm,
|
||||
char *params = NULL;
|
||||
struct dm_status_cache *c;
|
||||
|
||||
*exists = -1;
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
|
||||
return_0;
|
||||
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_STATUS, &info, NULL, dlid, 0, 0, 0, 0, 0, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(*exists = info.exists))
|
||||
goto out;
|
||||
|
||||
log_debug_activation("Checking status for cache volume %s.",
|
||||
display_lvname(lv));
|
||||
if (!info.exists)
|
||||
goto_out;
|
||||
|
||||
dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms);
|
||||
|
||||
@@ -1718,7 +1613,7 @@ out:
|
||||
|
||||
int dev_manager_thin_pool_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin_pool **status, int *exists)
|
||||
struct lv_status_thin_pool **status)
|
||||
{
|
||||
struct dm_status_thin_pool *dm_status;
|
||||
const char *dlid;
|
||||
@@ -1729,10 +1624,6 @@ int dev_manager_thin_pool_status(struct dev_manager *dm,
|
||||
char *params = NULL;
|
||||
int r = 0;
|
||||
|
||||
*exists = -1;
|
||||
if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_thin_pool))))
|
||||
return_0;
|
||||
|
||||
/* Build dlid for the thin pool layer */
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
|
||||
return_0;
|
||||
@@ -1740,11 +1631,8 @@ int dev_manager_thin_pool_status(struct dev_manager *dm,
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_STATUS, &info, NULL, dlid, 0, 0, 0, 0, flush, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(*exists = info.exists))
|
||||
goto out;
|
||||
|
||||
log_debug_activation("Checking thin pool status for LV %s.",
|
||||
display_lvname(lv));
|
||||
if (!info.exists)
|
||||
goto_out;
|
||||
|
||||
dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms);
|
||||
|
||||
@@ -1757,6 +1645,9 @@ int dev_manager_thin_pool_status(struct dev_manager *dm,
|
||||
if (!dm_get_status_thin_pool(dm->mem, params, &dm_status))
|
||||
goto_out;
|
||||
|
||||
if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_thin_pool))))
|
||||
goto_out;
|
||||
|
||||
(*status)->mem = dm->mem;
|
||||
(*status)->thin_pool = dm_status;
|
||||
|
||||
@@ -1779,7 +1670,7 @@ out:
|
||||
|
||||
int dev_manager_thin_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin **status, int *exists)
|
||||
struct lv_status_thin **status)
|
||||
{
|
||||
struct dm_status_thin *dm_status;
|
||||
const char *dlid;
|
||||
@@ -1791,21 +1682,14 @@ int dev_manager_thin_status(struct dev_manager *dm,
|
||||
uint64_t csize;
|
||||
int r = 0;
|
||||
|
||||
*exists = -1;
|
||||
if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_thin))))
|
||||
return_0;
|
||||
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
|
||||
return_0;
|
||||
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_STATUS, &info, NULL, dlid, 0, 0, 0, 0, flush, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(*exists = info.exists))
|
||||
goto out;
|
||||
|
||||
log_debug_activation("Checking thin status for LV %s.",
|
||||
display_lvname(lv));
|
||||
if (!info.exists)
|
||||
goto_out;
|
||||
|
||||
dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms);
|
||||
|
||||
@@ -1818,6 +1702,9 @@ int dev_manager_thin_status(struct dev_manager *dm,
|
||||
if (!dm_get_status_thin(dm->mem, params, &dm_status))
|
||||
goto_out;
|
||||
|
||||
if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_thin))))
|
||||
goto_out;
|
||||
|
||||
(*status)->mem = dm->mem;
|
||||
(*status)->thin = dm_status;
|
||||
|
||||
@@ -1850,7 +1737,7 @@ out:
|
||||
*/
|
||||
int dev_manager_thin_device_id(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
uint32_t *device_id, int *exists)
|
||||
uint32_t *device_id)
|
||||
{
|
||||
const char *dlid;
|
||||
struct dm_task *dmt;
|
||||
@@ -1860,7 +1747,6 @@ int dev_manager_thin_device_id(struct dev_manager *dm,
|
||||
const char *layer = lv_layer(lv);
|
||||
int r = 0;
|
||||
|
||||
*exists = -1;
|
||||
if (lv_is_merging_origin(lv) && !lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
|
||||
/* If the merge has already happened, that table
|
||||
* can already be using correct LV without -real layer */
|
||||
@@ -1873,11 +1759,8 @@ int dev_manager_thin_device_id(struct dev_manager *dm,
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_TABLE, &info, NULL, dlid, 0, 0, 0, 0, 1, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(*exists = info.exists))
|
||||
goto out;
|
||||
|
||||
log_debug_activation("Checking device id for LV %s.",
|
||||
display_lvname(lv));
|
||||
if (!info.exists)
|
||||
goto_out;
|
||||
|
||||
if (dm_get_next_target(dmt, NULL, &start, &length,
|
||||
&target_type, ¶ms)) {
|
||||
@@ -1906,9 +1789,11 @@ out:
|
||||
}
|
||||
|
||||
int dev_manager_vdo_pool_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv, int flush,
|
||||
struct lv_status_vdo **status, int *exists)
|
||||
const struct logical_volume *lv,
|
||||
struct lv_status_vdo **vdo_status,
|
||||
int flush)
|
||||
{
|
||||
struct lv_status_vdo *status;
|
||||
const char *dlid;
|
||||
struct dm_info info;
|
||||
uint64_t start, length;
|
||||
@@ -1917,9 +1802,12 @@ int dev_manager_vdo_pool_status(struct dev_manager *dm,
|
||||
char *params = NULL;
|
||||
int r = 0;
|
||||
|
||||
*exists = -1;
|
||||
if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_vdo))))
|
||||
return_0;
|
||||
*vdo_status = NULL;
|
||||
|
||||
if (!(status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_vdo)))) {
|
||||
log_error("Cannot allocate VDO status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
|
||||
return_0;
|
||||
@@ -1927,63 +1815,9 @@ int dev_manager_vdo_pool_status(struct dev_manager *dm,
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_STATUS, &info, NULL, dlid, 0, 0, 0, 0, flush, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(*exists = info.exists))
|
||||
goto out;
|
||||
|
||||
log_debug_activation("Checking VDO pool status for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms)) {
|
||||
log_error("More then one table line found for %s.",
|
||||
display_lvname(lv));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!type || strcmp(type, TARGET_NAME_VDO)) {
|
||||
log_error("Expected %s segment type but got %s instead.",
|
||||
TARGET_NAME_VDO, type ? type : "NULL");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!parse_vdo_pool_status(dm->mem, lv, params, &info, *status))
|
||||
if (!info.exists)
|
||||
goto_out;
|
||||
|
||||
(*status)->mem = dm->mem;
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_manager_vdo_pool_size_config(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct vdo_pool_size_config *cfg)
|
||||
{
|
||||
const char *dlid;
|
||||
struct dm_info info;
|
||||
uint64_t start, length;
|
||||
struct dm_task *dmt = NULL;
|
||||
char *type = NULL;
|
||||
char *params = NULL;
|
||||
int r = 0;
|
||||
unsigned version = 0;
|
||||
|
||||
memset(cfg, 0, sizeof(*cfg));
|
||||
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
|
||||
return_0;
|
||||
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_TABLE, &info, NULL, dlid, 0, 0, 0, 0, 0, 0)))
|
||||
return_0;
|
||||
|
||||
if (!info.exists)
|
||||
goto inactive; /* VDO device is not active, should not happen here... */
|
||||
|
||||
log_debug_activation("Checking VDO pool table line for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms)) {
|
||||
log_error("More then one table line found for %s.",
|
||||
display_lvname(lv));
|
||||
@@ -1996,25 +1830,12 @@ int dev_manager_vdo_pool_size_config(struct dev_manager *dm,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sscanf(params, "V%u %*s " FMTu64 " %*u " FMTu32,
|
||||
&version, &cfg->physical_size, &cfg->block_map_cache_size_mb) != 3) {
|
||||
log_error("Failed to parse VDO parameters %s for LV %s.",
|
||||
params, display_lvname(lv));
|
||||
goto out;
|
||||
}
|
||||
if (!parse_vdo_pool_status(dm->mem, lv, params, status))
|
||||
goto_out;
|
||||
|
||||
switch (version) {
|
||||
case 2: break;
|
||||
case 4: break;
|
||||
default: log_warn("WARNING: Unknown VDO table line version %u.", version);
|
||||
}
|
||||
status->mem = dm->mem;
|
||||
*vdo_status = status;
|
||||
|
||||
cfg->virtual_size = length;
|
||||
cfg->physical_size *= 8; // From 4K unit to 512B
|
||||
cfg->block_map_cache_size_mb /= 256; // From 4K unit to MiB
|
||||
cfg->index_memory_size_mb = first_seg(lv)->vdo_params.index_memory_size_mb; // Preserved
|
||||
|
||||
inactive:
|
||||
r = 1;
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
@@ -2242,7 +2063,7 @@ static int _check_holder(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
if (!strncmp(default_uuid_prefix, uuid, default_uuid_prefix_len))
|
||||
uuid += default_uuid_prefix_len;
|
||||
|
||||
if (!memcmp(uuid, &lv->vg->id, ID_LEN) &&
|
||||
if (!strncmp(uuid, (char*)&lv->vg->id, sizeof(lv->vg->id)) &&
|
||||
!dm_tree_find_node_by_uuid(dtree, uuid)) {
|
||||
/* trims any UUID suffix (i.e. -cow) */
|
||||
(void) dm_strncpy((char*)&id, uuid, 2 * sizeof(struct id) + 1);
|
||||
@@ -2321,7 +2142,6 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
{
|
||||
char *dlid, *name;
|
||||
struct dm_info info, info2;
|
||||
const struct dm_active_device *dev;
|
||||
|
||||
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
|
||||
return_0;
|
||||
@@ -2329,21 +2149,9 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
if (!(dlid = build_dm_uuid(dm->track_pending_delete ? dm->cmd->pending_delete_mem : dm->mem, lv, layer)))
|
||||
return_0;
|
||||
|
||||
if (!dm->cmd->disable_dm_devs &&
|
||||
dm->cmd->cache_dm_devs) {
|
||||
if (!dm_device_list_find_by_uuid(dm->cmd->cache_dm_devs, dlid, &dev)) {
|
||||
log_debug("Cached as not present %s.", name);
|
||||
return 1;
|
||||
}
|
||||
info = (struct dm_info) {
|
||||
.exists = 1,
|
||||
.major = dev->major,
|
||||
.minor = dev->minor,
|
||||
};
|
||||
log_debug("Cached as present %s %s (%d:%d).",
|
||||
name, dlid, info.major, info.minor);
|
||||
} else if (!_info(dm->cmd, name, dlid, 0, 0, 0, &info, NULL, NULL))
|
||||
if (!_info(dm->cmd, name, dlid, 1, 0, 0, &info, NULL, NULL))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* For top level volumes verify that existing device match
|
||||
* requested major/minor and that major/minor pair is available for use
|
||||
@@ -2462,35 +2270,22 @@ static int _pool_callback(struct dm_tree_node *node,
|
||||
const struct pool_cb_data *data = cb_data;
|
||||
const struct logical_volume *pool_lv = data->pool_lv;
|
||||
const struct logical_volume *mlv = first_seg(pool_lv)->metadata_lv;
|
||||
struct cmd_context *cmd = pool_lv->vg->cmd;
|
||||
long buf[64 / sizeof(long)]; /* buffer for short disk header (64B) */
|
||||
int args = 0;
|
||||
char *mpath;
|
||||
const char *argv[19] = { /* Max supported 15 args */
|
||||
find_config_tree_str_allow_empty(cmd, data->exec, NULL)
|
||||
find_config_tree_str_allow_empty(pool_lv->vg->cmd, data->exec, NULL)
|
||||
};
|
||||
|
||||
if (!*argv[0]) /* *_check tool is unconfigured/disabled with "" setting */
|
||||
return 1;
|
||||
|
||||
if (lv_is_cache_vol(pool_lv)) {
|
||||
if (!(mpath = lv_dmpath_suffix_dup(data->dm->mem, pool_lv, "-cmeta"))) {
|
||||
log_error("Failed to build device path for checking cachevol metadata %s.",
|
||||
display_lvname(pool_lv));
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!(mpath = lv_dmpath_dup(data->dm->mem, mlv))) {
|
||||
log_error("Failed to build device path for checking pool metadata %s.",
|
||||
display_lvname(mlv));
|
||||
return 0;
|
||||
}
|
||||
if (!(mpath = lv_dmpath_dup(data->dm->mem, mlv))) {
|
||||
log_error("Failed to build device path for checking pool metadata %s.",
|
||||
display_lvname(mlv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_device_list_destroy(&cmd->cache_dm_devs); /* Cache no longer valid */
|
||||
|
||||
log_debug("Running check command on %s", mpath);
|
||||
|
||||
if (data->skip_zero) {
|
||||
if ((fd = open(mpath, O_RDONLY)) < 0) {
|
||||
log_sys_error("open", mpath);
|
||||
@@ -2517,7 +2312,7 @@ static int _pool_callback(struct dm_tree_node *node,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cn = find_config_tree_array(cmd, data->opts, NULL))) {
|
||||
if (!(cn = find_config_tree_array(mlv->vg->cmd, data->opts, NULL))) {
|
||||
log_error(INTERNAL_ERROR "Unable to find configuration for pool check options.");
|
||||
return 0;
|
||||
}
|
||||
@@ -2539,7 +2334,7 @@ static int _pool_callback(struct dm_tree_node *node,
|
||||
|
||||
argv[++args] = mpath;
|
||||
|
||||
if (!(ret = exec_cmd(cmd, (const char * const *)argv,
|
||||
if (!(ret = exec_cmd(pool_lv->vg->cmd, (const char * const *)argv,
|
||||
&status, 0))) {
|
||||
if (status == ENOENT) {
|
||||
log_warn("WARNING: Check is skipped, please install recommended missing binary %s!",
|
||||
@@ -2548,7 +2343,7 @@ static int _pool_callback(struct dm_tree_node *node,
|
||||
}
|
||||
|
||||
if ((data->version.maj || data->version.min || data->version.patch) &&
|
||||
!_check_tool_version(cmd, argv[0],
|
||||
!_check_tool_version(pool_lv->vg->cmd, argv[0],
|
||||
data->version.maj, data->version.min, data->version.patch)) {
|
||||
log_warn("WARNING: Check is skipped, please upgrade installed version of %s!",
|
||||
argv[0]);
|
||||
@@ -2592,6 +2387,10 @@ static int _pool_register_callback(struct dev_manager *dm,
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
/* Skip for single-device cache pool */
|
||||
if (lv_is_cache(lv) && lv_is_cache_vol(first_seg(lv)->pool_lv))
|
||||
return 1;
|
||||
|
||||
if (!(data = dm_pool_zalloc(dm->mem, sizeof(*data)))) {
|
||||
log_error("Failed to allocated path for callback.");
|
||||
return 0;
|
||||
@@ -3014,10 +2813,6 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
|
||||
/* FIXME Avoid repeating identical stat in dm_tree_node_add_target_area */
|
||||
for (s = start_area; s < areas; s++) {
|
||||
|
||||
/* FIXME: dev_name() does not return NULL! It needs to check if dm_list_empty(&dev->aliases)
|
||||
but this knot of logic is too complex to pull apart without careful deconstruction. */
|
||||
|
||||
if ((seg_type(seg, s) == AREA_PV &&
|
||||
(!seg_pvseg(seg, s) || !seg_pv(seg, s) || !seg_dev(seg, s) ||
|
||||
!(name = dev_name(seg_dev(seg, s))) || !*name ||
|
||||
@@ -3036,10 +2831,7 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
return_0;
|
||||
num_error_areas++;
|
||||
} else if (seg_type(seg, s) == AREA_PV) {
|
||||
struct device *dev = seg_dev(seg, s);
|
||||
name = dm_list_empty(&dev->aliases) ? NULL : dev_name(dev);
|
||||
|
||||
if (!dm_tree_node_add_target_area(node, name, NULL,
|
||||
if (!dm_tree_node_add_target_area(node, dev_name(seg_dev(seg, s)), NULL,
|
||||
(seg_pv(seg, s)->pe_start + (extent_size * seg_pe(seg, s)))))
|
||||
return_0;
|
||||
num_existing_areas++;
|
||||
@@ -3691,12 +3483,6 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
!_pool_register_callback(dm, dnode, lv))
|
||||
return_0;
|
||||
|
||||
if (lv_is_cache(lv) && lv_is_cache_vol(first_seg(lv)->pool_lv) &&
|
||||
/* Register callback only for layer activation or non-layered cache LV */
|
||||
(layer || !lv_layer(lv)) &&
|
||||
!_pool_register_callback(dm, dnode, lv))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* Update tables for ANY PVMOVE holders for active LV where the name starts with 'pvmove',
|
||||
* but it's not anymore PVMOVE LV and also it's not a PVMOVE _mimage LV.
|
||||
@@ -3883,7 +3669,6 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
struct dm_tree_node *root;
|
||||
char *dlid;
|
||||
int r = 0;
|
||||
unsigned tmp_state;
|
||||
|
||||
if (action < DM_ARRAY_SIZE(_action_names))
|
||||
log_debug_activation("Creating %s%s tree for %s.",
|
||||
@@ -3903,16 +3688,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
dm->suspend = (action == SUSPEND_WITH_LOCKFS) || (action == SUSPEND);
|
||||
dm->track_external_lv_deps = 1;
|
||||
|
||||
/* ATM do not use caching for anything else then striped target.
|
||||
* And also skip for CLEAN action */
|
||||
tmp_state = dm->cmd->disable_dm_devs;
|
||||
if (!seg_is_striped_target(first_seg(lv)) || (action == CLEAN))
|
||||
dm->cmd->disable_dm_devs = 1;
|
||||
|
||||
dtree = _create_partial_dtree(dm, lv, laopts->origin_only);
|
||||
dm->cmd->disable_dm_devs = tmp_state;
|
||||
|
||||
if (!dtree)
|
||||
if (!(dtree = _create_partial_dtree(dm, lv, laopts->origin_only)))
|
||||
return_0;
|
||||
|
||||
if (!(root = dm_tree_find_node(dtree, 0, 0))) {
|
||||
@@ -3975,8 +3751,6 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
* non 'thin pool/volume' and size increase */
|
||||
else if (!lv_is_thin_volume(lv) &&
|
||||
!lv_is_thin_pool(lv) &&
|
||||
!lv_is_vdo(lv) &&
|
||||
!lv_is_vdo_pool(lv) &&
|
||||
dm_tree_node_size_changed(root))
|
||||
dm->flush_required = 1;
|
||||
|
||||
@@ -4095,78 +3869,3 @@ out:
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* crypt offset is usually the LUKS header size but can be larger.
|
||||
* The LUKS header is usually 2MB for LUKS1 and 16MB for LUKS2.
|
||||
* The offset needs to be subtracted from the LV size to get the
|
||||
* size used to resize the crypt device.
|
||||
*/
|
||||
int get_crypt_table_offset(dev_t crypt_devt, uint32_t *offset_bytes)
|
||||
{
|
||||
struct dm_task *dmt = dm_task_create(DM_DEVICE_TABLE);
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
void *next = NULL;
|
||||
char *params = NULL;
|
||||
char offset_str[32] = { 0 };
|
||||
int copy_offset = 0;
|
||||
int spaces = 0;
|
||||
int i, i_off = 0;
|
||||
|
||||
if (!dmt)
|
||||
return_0;
|
||||
|
||||
if (!dm_task_set_major_minor(dmt, (int)MAJOR(crypt_devt), (int)MINOR(crypt_devt), 0)) {
|
||||
dm_task_destroy(dmt);
|
||||
return_0;
|
||||
}
|
||||
|
||||
/* Non-blocking status read */
|
||||
if (!dm_task_no_flush(dmt))
|
||||
log_warn("WARNING: Can't set no_flush for dm status.");
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
dm_task_destroy(dmt);
|
||||
return_0;
|
||||
}
|
||||
|
||||
next = dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
|
||||
if (!target_type || !params || strcmp(target_type, "crypt")) {
|
||||
dm_task_destroy(dmt);
|
||||
return_0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get offset from params string:
|
||||
* <cipher> <key> <iv_offset> <device> <offset> [<#opt_params> <opt_params>]
|
||||
* <offset> is reported in 512 byte sectors.
|
||||
*/
|
||||
for (i = 0; i < strlen(params); i++) {
|
||||
if (params[i] == ' ') {
|
||||
spaces++;
|
||||
if (spaces == 4)
|
||||
copy_offset = 1;
|
||||
if (spaces == 5)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (!copy_offset)
|
||||
continue;
|
||||
|
||||
offset_str[i_off++] = params[i];
|
||||
|
||||
if (i_off == sizeof(offset_str)) {
|
||||
offset_str[0] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
if (!offset_str[0])
|
||||
return_0;
|
||||
|
||||
*offset_bytes = ((uint32_t)strtoul(offset_str, NULL, 0) * 512);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -29,8 +29,6 @@ struct lv_seg_status;
|
||||
|
||||
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts, const char *layer);
|
||||
|
||||
int get_crypt_table_offset(dev_t crypt_devt, uint32_t *offset_bytes);
|
||||
|
||||
/*
|
||||
* Constructor and destructor.
|
||||
*/
|
||||
@@ -61,7 +59,7 @@ int dev_manager_mirror_percent(struct dev_manager *dm,
|
||||
dm_percent_t *percent, uint32_t *event_nr);
|
||||
int dev_manager_raid_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct lv_status_raid **status, int *exists);
|
||||
struct dm_status_raid **status);
|
||||
int dev_manager_raid_message(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
const char *msg);
|
||||
@@ -70,22 +68,20 @@ int dev_manager_writecache_message(struct dev_manager *dm,
|
||||
const char *msg);
|
||||
int dev_manager_cache_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct lv_status_cache **status, int *exists);
|
||||
struct lv_status_cache **status);
|
||||
int dev_manager_thin_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin **status, int *exists);
|
||||
struct lv_status_thin **status);
|
||||
int dev_manager_thin_device_id(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
uint32_t *device_id, int *exist);
|
||||
uint32_t *device_id);
|
||||
int dev_manager_thin_pool_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin_pool **status, int *exists);
|
||||
struct lv_status_thin_pool **status);
|
||||
int dev_manager_vdo_pool_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv, int flush,
|
||||
struct lv_status_vdo **status, int *exists);
|
||||
int dev_manager_vdo_pool_size_config(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct vdo_pool_size_config *cfg);
|
||||
const struct logical_volume *lv,
|
||||
struct lv_status_vdo **vdo_status,
|
||||
int flush);
|
||||
int dev_manager_suspend(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
struct lv_activate_opts *laopts, int lockfs, int flush_required);
|
||||
int dev_manager_activate(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
@@ -108,7 +104,5 @@ int dev_manager_device_uses_vg(struct device *dev,
|
||||
int dev_manager_remove_dm_major_minor(uint32_t major, uint32_t minor);
|
||||
|
||||
int dev_manager_check_prefix_dm_major_minor(uint32_t major, uint32_t minor, const char *prefix);
|
||||
int dev_manager_get_device_list(const char *prefix, struct dm_list **devs,
|
||||
unsigned *devs_features);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -76,7 +76,7 @@ static int _rm_dir(const char *dev_dir, const char *vg_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dir_exists(vg_path) && dm_is_empty_dir(vg_path)) {
|
||||
if (dir_exists(vg_path) && is_empty_dir(vg_path)) {
|
||||
log_very_verbose("Removing directory %s", vg_path);
|
||||
rmdir(vg_path);
|
||||
}
|
||||
@@ -93,7 +93,7 @@ static void _rm_blks(const char *dir)
|
||||
DIR *d;
|
||||
|
||||
if (!(d = opendir(dir))) {
|
||||
log_sys_debug("opendir", dir);
|
||||
log_sys_error("opendir", dir);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ static void _rm_blks(const char *dir)
|
||||
continue;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
|
||||
log_debug("Couldn't create path for %s.", name);
|
||||
log_error("Couldn't create path for %s", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -113,12 +113,12 @@ static void _rm_blks(const char *dir)
|
||||
continue;
|
||||
log_very_verbose("Removing %s", path);
|
||||
if (unlink(path) < 0)
|
||||
log_sys_debug("unlink", path);
|
||||
log_sys_error("unlink", path);
|
||||
}
|
||||
}
|
||||
|
||||
if (closedir(d))
|
||||
log_sys_debug("closedir", dir);
|
||||
log_sys_error("closedir", dir);
|
||||
}
|
||||
|
||||
static int _mk_link(const char *dev_dir, const char *vg_name,
|
||||
@@ -169,7 +169,7 @@ static int _mk_link(const char *dev_dir, const char *vg_name,
|
||||
|
||||
log_very_verbose("Removing %s", lvm1_group_path);
|
||||
if (unlink(lvm1_group_path) < 0)
|
||||
log_sys_debug("unlink", lvm1_group_path);
|
||||
log_sys_error("unlink", lvm1_group_path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ struct fs_op_parms {
|
||||
char *lv_name;
|
||||
char *dev;
|
||||
char *old_lv_name;
|
||||
char names[0];
|
||||
char names[];
|
||||
};
|
||||
|
||||
static void _store_str(char **pos, char **ptr, const char *str)
|
||||
|
||||
958
lib/cache/lvmcache.c
vendored
958
lib/cache/lvmcache.c
vendored
File diff suppressed because it is too large
Load Diff
18
lib/cache/lvmcache.h
vendored
18
lib/cache/lvmcache.h
vendored
@@ -47,7 +47,7 @@ struct lvmcache_vginfo;
|
||||
*/
|
||||
struct lvmcache_vgsummary {
|
||||
const char *vgname;
|
||||
char vgid[ID_LEN + 1];
|
||||
struct id vgid;
|
||||
uint64_t vgstatus;
|
||||
char *creation_host;
|
||||
const char *system_id;
|
||||
@@ -84,6 +84,7 @@ void lvmcache_del_dev(struct device *dev);
|
||||
int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info *info,
|
||||
struct lvmcache_vgsummary *vgsummary);
|
||||
int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted);
|
||||
int lvmcache_update_vg_from_write(struct volume_group *vg);
|
||||
|
||||
void lvmcache_lock_vgname(const char *vgname, int read_only);
|
||||
void lvmcache_unlock_vgname(const char *vgname);
|
||||
@@ -95,10 +96,9 @@ struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname,
|
||||
const char *vgid);
|
||||
struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid);
|
||||
struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, struct device *dev, int valid_only);
|
||||
struct lvmcache_info *lvmcache_info_from_pv_id(const struct id *pv_id, struct device *dev, int valid_only);
|
||||
const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid);
|
||||
const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgname);
|
||||
struct device *lvmcache_device_from_pv_id(struct cmd_context *cmd, const struct id *pv_id, uint64_t *label_sector);
|
||||
struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector);
|
||||
const char *lvmcache_vgname_from_info(struct lvmcache_info *info);
|
||||
const struct format_type *lvmcache_fmt_from_info(struct lvmcache_info *info);
|
||||
|
||||
@@ -181,11 +181,13 @@ int lvmcache_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const ch
|
||||
|
||||
bool lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid);
|
||||
|
||||
int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, const char *pvid_arg);
|
||||
int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, char *pvid);
|
||||
|
||||
uint64_t lvmcache_max_metadata_size(void);
|
||||
void lvmcache_save_metadata_size(uint64_t val);
|
||||
|
||||
int dev_in_device_list(struct device *dev, struct dm_list *head);
|
||||
|
||||
bool lvmcache_has_bad_metadata(struct device *dev);
|
||||
|
||||
bool lvmcache_has_old_metadata(struct cmd_context *cmd, const char *vgname, const char *vgid, struct device *dev);
|
||||
@@ -207,8 +209,6 @@ void lvmcache_del_outdated_devs(struct cmd_context *cmd,
|
||||
|
||||
void lvmcache_save_bad_mda(struct lvmcache_info *info, struct metadata_area *mda);
|
||||
|
||||
void lvmcache_del_save_bad_mda(struct lvmcache_info *info, int mda_num, int bad_mda_flag);
|
||||
|
||||
void lvmcache_get_bad_mdas(struct cmd_context *cmd,
|
||||
const char *vgname, const char *vgid,
|
||||
struct dm_list *bad_mda_list);
|
||||
@@ -222,10 +222,4 @@ const char *devname_error_reason(const char *devname);
|
||||
|
||||
struct metadata_area *lvmcache_get_dev_mda(struct device *dev, int mda_num);
|
||||
|
||||
void lvmcache_extra_md_component_checks(struct cmd_context *cmd);
|
||||
|
||||
unsigned int lvmcache_vg_info_count(void);
|
||||
|
||||
int lvmcache_pvsummary_count(const char *vgname);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -335,7 +335,7 @@ static int _lookup_kallsyms(const char *symbol)
|
||||
|
||||
static int _target_present(struct cmd_context *cmd,
|
||||
const struct lv_segment *seg __attribute__((unused)),
|
||||
unsigned *attributes)
|
||||
unsigned *attributes __attribute__((unused)))
|
||||
{
|
||||
/* List of features with their kernel target version */
|
||||
static const struct feature {
|
||||
@@ -618,9 +618,6 @@ static int _cache_add_target_line(struct dev_manager *dm,
|
||||
{
|
||||
struct lv_segment *cache_pool_seg;
|
||||
struct lv_segment *setting_seg;
|
||||
struct dm_config_node *policy_settings;
|
||||
struct dm_config_node *cn;
|
||||
unsigned i, j;
|
||||
union lvid metadata_lvid;
|
||||
union lvid data_lvid;
|
||||
char *metadata_uuid, *data_uuid, *origin_uuid;
|
||||
@@ -721,61 +718,6 @@ static int _cache_add_target_line(struct dev_manager *dm,
|
||||
return_0;
|
||||
}
|
||||
|
||||
policy_settings = seg->cleaner_policy ? NULL : setting_seg->policy_settings;
|
||||
if (policy_settings && cache_pool_seg->policy_name) {
|
||||
static const struct act {
|
||||
const char *name;
|
||||
const char *settings[20];
|
||||
} _accepted[] = {
|
||||
{
|
||||
"MQ", {
|
||||
"migration_threshold", "sequential_threshold", "random_threshold",
|
||||
"read_promote_adjustment", "write_promote_adjustment",
|
||||
"discard_promote_adjustment", NULL
|
||||
},
|
||||
}, {
|
||||
"SMQ", {
|
||||
"migration_threshold", NULL
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Check if cache settings are acceptable to knownm policies */
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_accepted); i++) {
|
||||
if (strcasecmp(cache_pool_seg->policy_name, _accepted[i].name))
|
||||
continue;
|
||||
|
||||
for (cn = policy_settings->child; cn; cn = cn->sib) {
|
||||
for (j = 0; _accepted[i].settings[j]; j++)
|
||||
if (strcmp(cn->key, _accepted[i].settings[j]) == 0)
|
||||
break; /* -> Valid setting */
|
||||
|
||||
/* Have we found 'unsupported' cache setting? */
|
||||
if (!_accepted[i].settings[j]) {
|
||||
/* Make a copy of policy settings a remove unsupported settings and Warn */
|
||||
if (!(policy_settings = dm_config_clone_node_with_mem(mem, policy_settings, 0)))
|
||||
return_0;
|
||||
restart:
|
||||
for (cn = policy_settings->child; cn; cn = cn->sib) {
|
||||
for (j = 0; _accepted[i].settings[j]; j++) {
|
||||
if (strcmp(cn->key, _accepted[i].settings[j]) == 0)
|
||||
break; /* need to be dropped */
|
||||
}
|
||||
if (!_accepted[i].settings[j]) {
|
||||
log_warn("WARNING: %s cache policy does not support \"%s=" FMTu64 "\" setting, "
|
||||
"remove with 'lvchange --cachesettings \"%s=default\" ...'.",
|
||||
_accepted[i].name, cn->key, cn->v->v.i, cn->key);
|
||||
dm_config_remove_node(policy_settings, cn);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dm_tree_node_add_cache_target(node, len,
|
||||
feature_flags,
|
||||
metadata_uuid,
|
||||
@@ -784,7 +726,7 @@ static int _cache_add_target_line(struct dev_manager *dm,
|
||||
seg->cleaner_policy ? "cleaner" :
|
||||
/* undefined policy name -> likely an old "mq" */
|
||||
cache_pool_seg->policy_name ? : "mq",
|
||||
policy_settings,
|
||||
seg->cleaner_policy ? NULL : setting_seg->policy_settings,
|
||||
seg->metadata_start,
|
||||
seg->metadata_len,
|
||||
seg->data_start,
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef _CMD_ENUM_H
|
||||
#define _CMD_ENUM_H
|
||||
|
||||
/*
|
||||
* include/cmds.h is generated by the Makefile. For each command definition
|
||||
* in command-lines.in, cmds.h contains:
|
||||
* cmd(foo_CMD, foo)
|
||||
*
|
||||
* This header adds each of the foo_CMD's into an enum, so there's
|
||||
* a unique integer identifier for each command definition.
|
||||
*/
|
||||
|
||||
enum {
|
||||
#define cmd(a, b) a ,
|
||||
#include "../../include/cmds.h"
|
||||
#undef cmd
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "lib/cache/lvmcache.h"
|
||||
#include "lib/format_text/archiver.h"
|
||||
#include "lib/lvmpolld/lvmpolld-client.h"
|
||||
#include "lib/device/device_id.h"
|
||||
|
||||
#include <locale.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -41,10 +40,6 @@
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef APP_MACHINEID_SUPPORT
|
||||
#include <systemd/sd-id128.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
@@ -133,12 +128,9 @@ static const char *_read_system_id_from_file(struct cmd_context *cmd, const char
|
||||
return system_id;
|
||||
}
|
||||
|
||||
/* systemd-id128 new produced: f64406832c2140e8ac5422d1089aae03 */
|
||||
#define LVM_APPLICATION_ID SD_ID128_MAKE(f6,44,06,83,2c,21,40,e8,ac,54,22,d1,08,9a,ae,03)
|
||||
|
||||
static const char *_system_id_from_source(struct cmd_context *cmd, const char *source)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
char filebuf[PATH_MAX];
|
||||
const char *file;
|
||||
const char *etc_str;
|
||||
const char *str;
|
||||
@@ -157,25 +149,10 @@ static const char *_system_id_from_source(struct cmd_context *cmd, const char *s
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef APP_MACHINEID_SUPPORT
|
||||
if (!strcasecmp(source, "appmachineid")) {
|
||||
sd_id128_t id = { 0 };
|
||||
|
||||
if (sd_id128_get_machine_app_specific(LVM_APPLICATION_ID, &id) != 0)
|
||||
log_warn("WARNING: sd_id128_get_machine_app_specific() failed %s (%d).",
|
||||
strerror(errno), errno);
|
||||
|
||||
if (dm_snprintf(buf, PATH_MAX, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)) < 0)
|
||||
stack;
|
||||
system_id = system_id_from_string(cmd, buf);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!strcasecmp(source, "machineid") || !strcasecmp(source, "machine-id")) {
|
||||
etc_str = find_config_tree_str(cmd, global_etc_CFG, NULL);
|
||||
if (dm_snprintf(buf, sizeof(buf), "%s/machine-id", etc_str) != -1)
|
||||
system_id = _read_system_id_from_file(cmd, buf);
|
||||
if (dm_snprintf(filebuf, sizeof(filebuf), "%s/machine-id", etc_str) != -1)
|
||||
system_id = _read_system_id_from_file(cmd, filebuf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -252,7 +229,7 @@ static void _get_sysfs_dir(struct cmd_context *cmd, char *buf, size_t buf_size)
|
||||
return;
|
||||
}
|
||||
|
||||
(void) dm_strncpy(buf, sys_mnt, buf_size);
|
||||
strncpy(buf, sys_mnt, buf_size);
|
||||
}
|
||||
|
||||
static uint32_t _parse_debug_fields(struct cmd_context *cmd, int cfg, const char *cfgname)
|
||||
@@ -342,33 +319,6 @@ static int _parse_debug_classes(struct cmd_context *cmd)
|
||||
return debug_classes;
|
||||
}
|
||||
|
||||
static uint32_t _parse_log_journal(struct cmd_context *cmd, int cfg, const char *cfgname)
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
uint32_t fields = 0;
|
||||
uint32_t val;
|
||||
|
||||
if (!(cn = find_config_tree_array(cmd, cfg, NULL))) {
|
||||
log_debug("Unable to find configuration for log/%s.", cfgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_verbose("log/%s contains a value which is not a string. Ignoring.", cfgname);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((val = log_journal_str_to_val(cv->v.str)))
|
||||
fields |= val;
|
||||
else
|
||||
log_verbose("Unrecognised value for log/%s: %s", cfgname, cv->v.str);
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
static void _init_logging(struct cmd_context *cmd)
|
||||
{
|
||||
int append = 1;
|
||||
@@ -379,11 +329,12 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
|
||||
/* Syslog */
|
||||
cmd->default_settings.syslog = find_config_tree_bool(cmd, log_syslog_CFG, NULL);
|
||||
if (cmd->default_settings.syslog)
|
||||
init_syslog(1, DEFAULT_LOG_FACILITY);
|
||||
else
|
||||
if (cmd->default_settings.syslog != 1)
|
||||
fin_syslog();
|
||||
|
||||
if (cmd->default_settings.syslog > 1)
|
||||
init_syslog(cmd->default_settings.syslog);
|
||||
|
||||
/* Debug level for log file output */
|
||||
cmd->default_settings.debug = find_config_tree_int(cmd, log_level_CFG, NULL);
|
||||
init_debug(cmd->default_settings.debug);
|
||||
@@ -436,9 +387,6 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
init_debug_file_fields(_parse_debug_fields(cmd, log_debug_file_fields_CFG, "debug_file_fields"));
|
||||
init_debug_output_fields(_parse_debug_fields(cmd, log_debug_output_fields_CFG, "debug_output_fields"));
|
||||
|
||||
cmd->default_settings.journal = _parse_log_journal(cmd, log_journal_CFG, "journal");
|
||||
init_log_journal(cmd->default_settings.journal);
|
||||
|
||||
t = time(NULL);
|
||||
ctime_r(&t, &timebuf[0]);
|
||||
timebuf[24] = '\0';
|
||||
@@ -453,12 +401,15 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
reset_lvm_errno(1);
|
||||
}
|
||||
|
||||
static int _check_disable_udev(const char *msg)
|
||||
{
|
||||
static int _check_disable_udev(const char *msg) {
|
||||
if (getenv("DM_DISABLE_UDEV")) {
|
||||
log_very_verbose("DM_DISABLE_UDEV environment variable set.");
|
||||
log_very_verbose("Overriding configuration to use udev_rules=0, udev_sync=0, verify_udev_operations=1.");
|
||||
log_very_verbose("LVM will %s.", msg);
|
||||
log_very_verbose("DM_DISABLE_UDEV environment variable set. "
|
||||
"Overriding configuration to use "
|
||||
"udev_rules=0, udev_sync=0, verify_udev_operations=1.");
|
||||
if (udev_is_running())
|
||||
log_warn("Udev is running and DM_DISABLE_UDEV environment variable is set. "
|
||||
"Bypassing udev, LVM will %s.", msg);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -611,7 +562,7 @@ static int _init_system_id(struct cmd_context *cmd)
|
||||
static int _process_config(struct cmd_context *cmd)
|
||||
{
|
||||
mode_t old_umask;
|
||||
const char *dev_ext_info_src = NULL;
|
||||
const char *dev_ext_info_src;
|
||||
const char *read_ahead;
|
||||
struct stat st;
|
||||
const struct dm_config_node *cn;
|
||||
@@ -643,28 +594,16 @@ static int _process_config(struct cmd_context *cmd)
|
||||
if (!dm_set_uuid_prefix(UUID_PREFIX))
|
||||
return_0;
|
||||
#endif
|
||||
cmd->device_id_sysfs_dir = find_config_tree_str(cmd, devices_device_id_sysfs_dir_CFG, NULL);
|
||||
|
||||
dev_ext_info_src = find_config_tree_str(cmd, devices_external_device_info_source_CFG, NULL);
|
||||
|
||||
if (dev_ext_info_src &&
|
||||
strcmp(dev_ext_info_src, "none") &&
|
||||
strcmp(dev_ext_info_src, "udev")) {
|
||||
log_warn("WARNING: unknown external device info source, using none.");
|
||||
dev_ext_info_src = NULL;
|
||||
}
|
||||
|
||||
if (dev_ext_info_src && !strcmp(dev_ext_info_src, "udev")) {
|
||||
if (udev_init_library_context()) {
|
||||
init_external_device_info_source(DEV_EXT_UDEV);
|
||||
} else {
|
||||
log_warn("WARNING: failed to init udev for external device info, using none.");
|
||||
dev_ext_info_src = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev_ext_info_src || !strcmp(dev_ext_info_src, "none"))
|
||||
if (dev_ext_info_src && !strcmp(dev_ext_info_src, "none"))
|
||||
init_external_device_info_source(DEV_EXT_NONE);
|
||||
else if (dev_ext_info_src && !strcmp(dev_ext_info_src, "udev"))
|
||||
init_external_device_info_source(DEV_EXT_UDEV);
|
||||
else {
|
||||
log_error("Invalid external device info source specification.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* proc dir */
|
||||
if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
|
||||
@@ -721,8 +660,6 @@ static int _process_config(struct cmd_context *cmd)
|
||||
*/
|
||||
cmd->default_settings.udev_fallback = udev_disabled ? 1 : -1;
|
||||
|
||||
cmd->default_settings.issue_discards = find_config_tree_bool(cmd, devices_issue_discards_CFG, NULL);
|
||||
|
||||
init_retry_deactivation(find_config_tree_bool(cmd, activation_retry_deactivation_CFG, NULL));
|
||||
|
||||
init_activation_checks(find_config_tree_bool(cmd, activation_checks_CFG, NULL));
|
||||
@@ -768,7 +705,6 @@ static int _process_config(struct cmd_context *cmd)
|
||||
init_pv_min_size((uint64_t)pv_min_kb * (1024 >> SECTOR_SHIFT));
|
||||
|
||||
cmd->check_pv_dev_sizes = find_config_tree_bool(cmd, metadata_check_pv_device_sizes_CFG, NULL);
|
||||
cmd->event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL);
|
||||
|
||||
if (!process_profilable_config(cmd))
|
||||
return_0;
|
||||
@@ -1027,13 +963,8 @@ static void _destroy_config(struct cmd_context *cmd)
|
||||
/* CONFIG_FILE/CONFIG_MERGED_FILES */
|
||||
if ((cft = remove_config_tree_by_source(cmd, CONFIG_MERGED_FILES)))
|
||||
config_destroy(cft);
|
||||
else if ((cft = remove_config_tree_by_source(cmd, CONFIG_FILE))) {
|
||||
dm_list_iterate_items(cfl, &cmd->config_files) {
|
||||
if (cfl->cft == cft)
|
||||
dm_list_del(&cfl->list);
|
||||
}
|
||||
config_destroy(cft);
|
||||
}
|
||||
else
|
||||
remove_config_tree_by_source(cmd, CONFIG_FILE);
|
||||
|
||||
dm_list_iterate_items(cfl, &cmd->config_files)
|
||||
config_destroy(cfl->cft);
|
||||
@@ -1079,10 +1010,16 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
if (!dev_cache_init(cmd))
|
||||
return_0;
|
||||
|
||||
if ((device_list_from_udev = find_config_tree_bool(cmd, devices_obtain_device_list_from_udev_CFG, NULL))) {
|
||||
if (!udev_init_library_context())
|
||||
device_list_from_udev = 0;
|
||||
}
|
||||
/*
|
||||
* Override existing config and hardcode device_list_from_udev = 0 if:
|
||||
* - udev is not running
|
||||
* - udev is disabled using DM_DISABLE_UDEV environment variable
|
||||
*/
|
||||
if (_check_disable_udev("obtain device list by scanning device directory"))
|
||||
device_list_from_udev = 0;
|
||||
else
|
||||
device_list_from_udev = udev_is_running() ?
|
||||
find_config_tree_bool(cmd, devices_obtain_device_list_from_udev_CFG, NULL) : 0;
|
||||
|
||||
init_obtain_device_list_from_udev(device_list_from_udev);
|
||||
|
||||
@@ -1144,9 +1081,26 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
|
||||
* Update MAX_FILTERS definition above when adding new filters.
|
||||
*/
|
||||
|
||||
/*
|
||||
* sysfs filter. Only available on 2.6 kernels. Non-critical.
|
||||
* Listed first because it's very efficient at eliminating
|
||||
* unavailable devices.
|
||||
*/
|
||||
if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
|
||||
if ((filters[nr_filt] = sysfs_filter_create()))
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
/* internal filter used by command processing. */
|
||||
if (!(filters[nr_filt] = internal_filter_create())) {
|
||||
log_error("Failed to create internal device filter");
|
||||
goto bad;
|
||||
}
|
||||
nr_filt++;
|
||||
|
||||
/* global regex filter. Optional. */
|
||||
if ((cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL))) {
|
||||
if (!(filters[nr_filt] = regex_filter_create(cn->v, 0, 1))) {
|
||||
if (!(filters[nr_filt] = regex_filter_create(cn->v))) {
|
||||
log_error("Failed to create global regex device filter");
|
||||
goto bad;
|
||||
}
|
||||
@@ -1155,7 +1109,7 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
|
||||
|
||||
/* regex filter. Optional. */
|
||||
if ((cn = find_config_tree_node(cmd, devices_filter_CFG, NULL))) {
|
||||
if (!(filters[nr_filt] = regex_filter_create(cn->v, 1, 0))) {
|
||||
if (!(filters[nr_filt] = regex_filter_create(cn->v))) {
|
||||
log_error("Failed to create regex device filter");
|
||||
goto bad;
|
||||
}
|
||||
@@ -1169,24 +1123,6 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
|
||||
}
|
||||
nr_filt++;
|
||||
|
||||
/* filter based on the device_ids saved in the devices file */
|
||||
if (!(filters[nr_filt] = deviceid_filter_create(cmd))) {
|
||||
log_error("Failed to create deviceid device filter");
|
||||
goto bad;
|
||||
}
|
||||
nr_filt++;
|
||||
|
||||
/*
|
||||
* sysfs filter. Only available on 2.6 kernels. Non-critical.
|
||||
* Eliminates unavailable devices.
|
||||
* TODO: this may be unnecessary now with device ids
|
||||
* (currently not used for devs match to device id using syfs)
|
||||
*/
|
||||
if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
|
||||
if ((filters[nr_filt] = sysfs_filter_create()))
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
/* usable device filter. Required. */
|
||||
if (!(filters[nr_filt] = usable_filter_create(cmd, cmd->dev_types, FILTER_MODE_NO_LVMETAD))) {
|
||||
log_error("Failed to create usabled device filter");
|
||||
@@ -1228,7 +1164,7 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
if (!(composite = composite_filter_create(nr_filt, filters)))
|
||||
if (!(composite = composite_filter_create(nr_filt, 1, filters)))
|
||||
goto_bad;
|
||||
|
||||
return composite;
|
||||
@@ -1549,7 +1485,6 @@ int init_run_by_dmeventd(struct cmd_context *cmd)
|
||||
init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
|
||||
init_ignore_suspended_devices(1);
|
||||
init_disable_dmeventd_monitoring(1); /* Lock settings */
|
||||
cmd->run_by_dmeventd = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1597,6 +1532,7 @@ struct cmd_context *create_config_context(void)
|
||||
|
||||
dm_list_init(&cmd->config_files);
|
||||
dm_list_init(&cmd->tags);
|
||||
dm_list_init(&cmd->hints);
|
||||
|
||||
if (!_init_lvm_conf(cmd))
|
||||
goto_out;
|
||||
@@ -1646,6 +1582,8 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
|
||||
bindtextdomain(INTL_PACKAGE, LOCALEDIR);
|
||||
#endif
|
||||
|
||||
init_syslog(DEFAULT_LOG_FACILITY);
|
||||
|
||||
if (!(cmd = zalloc(sizeof(*cmd)))) {
|
||||
log_error("Failed to allocate command context");
|
||||
return NULL;
|
||||
@@ -1656,11 +1594,11 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
|
||||
cmd->handles_missing_pvs = 0;
|
||||
cmd->handles_unknown_segments = 0;
|
||||
cmd->hosttags = 0;
|
||||
cmd->check_devs_used = 1;
|
||||
dm_list_init(&cmd->arg_value_groups);
|
||||
dm_list_init(&cmd->formats);
|
||||
dm_list_init(&cmd->segtypes);
|
||||
dm_list_init(&cmd->tags);
|
||||
dm_list_init(&cmd->hints);
|
||||
dm_list_init(&cmd->config_files);
|
||||
label_init();
|
||||
|
||||
@@ -1779,8 +1717,6 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
|
||||
if (!_init_dev_cache(cmd))
|
||||
goto_out;
|
||||
|
||||
devices_file_init(cmd);
|
||||
|
||||
memlock_init(cmd);
|
||||
|
||||
if (!_init_formats(cmd))
|
||||
@@ -1985,8 +1921,6 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_dev_cache(cmd))
|
||||
return_0;
|
||||
|
||||
devices_file_init(cmd);
|
||||
|
||||
if (!_init_formats(cmd))
|
||||
return_0;
|
||||
|
||||
@@ -2034,17 +1968,24 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
_destroy_segtypes(&cmd->segtypes);
|
||||
_destroy_formats(cmd, &cmd->formats);
|
||||
_destroy_filters(cmd);
|
||||
if (cmd->mem)
|
||||
dm_pool_destroy(cmd->mem);
|
||||
dev_cache_exit();
|
||||
_destroy_dev_types(cmd);
|
||||
_destroy_tags(cmd);
|
||||
|
||||
if ((cft_cmdline = remove_config_tree_by_source(cmd, CONFIG_STRING)))
|
||||
config_destroy(cft_cmdline);
|
||||
_destroy_config(cmd);
|
||||
|
||||
if (cmd->cft_def_hash)
|
||||
dm_hash_destroy(cmd->cft_def_hash);
|
||||
|
||||
dm_device_list_destroy(&cmd->cache_dm_devs);
|
||||
if (cmd->libmem)
|
||||
dm_pool_destroy(cmd->libmem);
|
||||
|
||||
if (cmd->pending_delete_mem)
|
||||
dm_pool_destroy(cmd->pending_delete_mem);
|
||||
#ifndef VALGRIND_POOL
|
||||
if (cmd->linebuffer) {
|
||||
/* Reset stream buffering to defaults */
|
||||
@@ -2069,7 +2010,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
free(cmd->linebuffer);
|
||||
}
|
||||
#endif
|
||||
destroy_config_context(cmd);
|
||||
free(cmd);
|
||||
|
||||
lvmpolld_disconnect();
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user