1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-20 05:44:20 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
David Teigland
39f781ca21 Add dm-integrity support
Create a linear LV with a dm-integrity layer added
above it.  The dm-integrity layer stores checksums
of the data written to the LV, and returns an error
if data read from the LV does not match the previously
saved checksum.

lvcreate --type integrity --integrity String [options]

The --integrity String specifies if the dm-integrity
metadata (checksums) should be interleaved with data
blocks, or written to a separate external LV:

  --integrity external (default)
  Store integrity metadata on a separate LV.
  Allows removing integrity from the LV later.

  --integrity internal
  Store integrity metadata interleaved with data
  on the same LV.  Around 1% of the LV size will
  be used for integrity metadata.

  --integrity y
  Enable default integrity settings (external).

Command variations:

lvcreate --type integrity -n Name -L Size VG

  [--integrity external is the default]

lvcreate --integrity external -n Name -L Size VG

  [--integrity external implies --type integrity]

lvcreate --integrity y -n Name -L Size VG

  [--integrity y uses default/external, and implies
   --type integrity]

lvcreate --integrity internal -n Name -L Size VG

  [--integrity internal implies --type integrity]

Options:

  --integritymetadata LV
  Use the specified LV for external metadata.
  Allows specific device placement of metadata.
  Without this option, the command creates a
  hidden LV (with an _imeta suffix) to hold the
  metadata.

  --integritysettings String
  set dm-integrity parameters, e.g. to use a journal
  instead of bitmap, --integritysettings "mode=J".

Example:

$ lvcreate --integrity external -n lvex -L1G vg
$ lvs -a vg
  LV           VG Attr       LSize  Origin
  lvex         vg -wi-a-----  1.00g [lvex_iorig]
  [lvex_imeta] vg -wi-ao---- 12.00m
  [lvex_iorig] vg -wi-ao----  1.00g

$ lvcreate --integrity internal -n lvin -L1G vg
$ lvs -a vg
  LV           VG Attr       LSize Origin
  lvin         vg -wi-a----- 1.00g [lvin_iorig]
  [lvin_iorig] vg -wi-ao---- 1.00g

Zeroing:

After a new integrity LV is created, zeroes are written to
the entire LV to initialize integrity metadata (checksums).
Without this initialization, the LV will return read errors
for any unwritten (and uninitialized) data.

A large LV may take a long time to zero.  The -Zn option can
be used to disable the whole-LV zeroing, or the lvcreate
command can be canceled while zeroing the new LV.  In either
case, the user may write to the entire LV to initialize the
integrity metadata themselves.

TODO:

- add command to remove intregrity from an LV (only for external),
  i.e. lvconvert --integrity none LV

- let integrity be used by raid images
2019-12-03 15:44:11 -06:00
667 changed files with 38133 additions and 74707 deletions

22
.gitignore vendored
View File

@@ -16,10 +16,6 @@
*.sw*
*~
# gcov files:
*.gcda
*.gcno
.export.sym
.exported_symbols_generated
.gdb_history
@@ -34,21 +30,14 @@ make.tmpl
/config.log
/config.status
/configure.scan
/cscope.*
/cscope.out
/html/
/python/
/reports/
/tags
/tmp/
coverity/coverity_model.xml
/libdm/.symver_check
daemons/clvmd
daemons/dmfilemapd
daemons/lvmetad/
tools/man-generator
tools/man-generator.c
@@ -108,8 +97,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 +106,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 +115,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 +127,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 +138,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

View File

@@ -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,6 +47,8 @@ include $(top_srcdir)/base/Makefile
include $(top_srcdir)/device_mapper/Makefile
include $(top_srcdir)/test/unit/Makefile
libdm: include
libdaemon: include
lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
daemons: lib libdaemon tools
scripts: lib
@@ -54,13 +56,16 @@ 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

11
README
View File

@@ -1,6 +1,7 @@
This tree contains the LVM2 and device-mapper tools and libraries.
This is development branch, for stable 2.02 release see stable-2.02 branch.
This is development branch, for stable 2.02 release see 2018-06-01-stable
branch.
For more information about LVM2 read the changelog in the WHATS_NEW file.
Installation instructions are in INSTALL.
@@ -9,6 +10,7 @@ There is no warranty - see COPYING and COPYING.LIB.
Tarballs are available from:
ftp://sourceware.org/pub/lvm2/
ftp://sources.redhat.com/pub/lvm2/
https://github.com/lvmteam/lvm2/releases
The source code is stored in git:
@@ -43,9 +45,6 @@ Report upstream bugs at:
or open issues at:
https://github.com/lvmteam/lvm2/issues
The source code repository used until 7th June 2012 is accessible using CVS:
The source code repository used until 7th June 2012 is accessible here:
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2.
cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 login cvs
cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 checkout LVM2
The password is cvs.

View File

@@ -1 +1 @@
2.03.17(2)-git (2022-05-18)
2.03.07(2)-git (2019-10-23)

View File

@@ -1 +1 @@
1.02.187-git (2022-05-18)
1.02.167-git (2019-10-23)

212
WHATS_NEW
View File

@@ -1,214 +1,7 @@
Version 2.03.17 -
===============================
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.
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
Version 2.03.07 -
===================================
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
==================================
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.
Dmeventd lvm plugin ignores higher reserved_stack lvm.conf values.
Support using BLKZEROOUT for clearing devices.
Support interruption when wipping LVs.
Support interruption for bcache waiting.
Fix bcache when device has too many failing writes.
Fix bcache waiting for IO completion with failing disks.
Configure use own python path name order to prefer using python3.
Add configure --enable-editline support as an alternative to readline.
Enhance reporting and error handling when creating thin volumes.
Enable vgsplit for VDO volumes.
Lvextend of vdo pool volumes ensure at least 1 new VDO slab is added.
Use revert_lv() on reload error path after vg_revert().
Configure --with-integrity enabled.
Restore lost signal blocking while VG lock is held.
Improve estimation of needed extents when creating thin-pool.
Use extra 1% when resizing thin-pool metadata LV with --use-policy.
Enhance --use-policy percentage rounding.
Configure --with-vdo and --with-writecache as internal segments.
Improving VDO man page examples.
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.
Switch from mmap to plain read when loading regular files.
Update lvmvdo man page and better explain DISCARD usage.
Version 2.03.10 - 09th August 2020
==================================
Add writecache and integrity support to lvmdbusd.
Generate unique cachevol name when default required from lvcreate.
Converting RAID1 volume to one with same number of legs now succeeds with a
warning.
Fix conversion to raid from striped lagging type.
Fix conversion to 'mirrored' mirror log with larger regionsize.
Zero pool metadata on allocation (disable with allocation/zero_metadata=0).
Failure in zeroing or wiping will fail command (bypass with -Zn, -Wn).
Add lvcreate of new cache or writecache lv with single command.
Fix running out of free buffers for async writing for larger writes.
Add integrity with raid capability.
Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
Version 2.03.09 - 26th March 2020
=================================
Fix formating of vdopool (vdo_slab_size_mb was smaller by 2 bits).
Fix showing of a dm kernel error when uncaching a volume with cachevol.
Version 2.03.08 - 11th February 2020
====================================
Prevent problematic snapshots of writecache volumes.
Add error handling for failing allocation in _reserve_area().
Fix memleak in syncing of internal cache.
Fix pvck dump_current_text memleak.
Fix lvmlockd result code on error path for _query_lock_lv().
Update pvck man page and help output.
Reject invalid writecache high/low_watermark setting.
Report writecache status.
Accept more output lines from vdo_format.
Prohibit reshaping of stacked raid LVs.
Avoid running cache input arg validation when creating vdo pool.
Prevent raid reshaping of stacked volumes.
Added VDO lvmdbusd methods for enable/disable compression & dedupe.
Added VDO lvmdbusd method for converting LV to VDO pool.
Version 2.03.07 - 30th November 2019
====================================
Subcommand in vgck for repairing headers and metadata.
Ensure minimum required region size on striped RaidLV creation.
Fix resize of thin-pool with data and metadata of different segtype.
Improve mirror type leg splitting.
Improve error path handling in daemons on shutdown.
Fix activation order when removing merged snapshot.
Experimental VDO support for lvmdbusd.
@@ -330,6 +123,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
@@ -1849,7 +1643,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.

View File

@@ -1,49 +1,5 @@
Version 1.02.187 -
================================
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
Version 1.02.167 -
====================================
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.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.
Version 1.02.171 - 26th March 2020
==================================
Try to remove all created devices on dm preload tree error path.
Fix dm_list interators with gcc 10 optimization (-ftree-pta).
Dmeventd handles timer without looping on short intervals.
Version 1.02.169 - 11th February 2020
=====================================
Enhance error messages for device creation.
Version 1.02.167 - 30th November 2019
=====================================
Version 1.02.165 - 23rd October 2019
====================================
@@ -578,7 +534,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.

288
aclocal.m4 vendored
View File

@@ -1,6 +1,6 @@
# generated automatically by aclocal 1.16.5 -*- Autoconf -*-
# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -413,7 +413,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
])dnl PKG_HAVE_DEFINE_WITH_MODULES
# Copyright (C) 1999-2021 Free Software Foundation, Inc.
# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -446,12 +446,10 @@ AC_DEFUN([AM_PATH_PYTHON],
[
dnl Find a Python interpreter. Python versions prior to 2.0 are not
dnl supported. (2.0 was released on October 16, 2000).
dnl FIXME: Remove the need to hard-code Python versions here.
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
[python python2 python3 dnl
python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 dnl
python3.2 python3.1 python3.0 dnl
python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl
python2.0])
[python python2 python3 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0])
AC_ARG_VAR([PYTHON], [the Python interpreter])
@@ -492,141 +490,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 +537,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 +649,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
sys.exit(sys.hexversion < minverhex)"
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,

1712
autoconf/config.guess vendored

File diff suppressed because it is too large Load Diff

2881
autoconf/config.sub vendored

File diff suppressed because it is too large Load Diff

View File

@@ -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:

View File

@@ -22,26 +22,17 @@ struct dm_hash_node {
void *data;
unsigned data_len;
unsigned keylen;
unsigned hash;
char key[0];
};
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,16 +57,29 @@ 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;
static struct dm_hash_node *_create_node(const char *str, unsigned len)
{
struct dm_hash_node *n = malloc(sizeof(*n) + len);
if (n) {
memcpy(n->key, str, len);
n->keylen = len;
}
return n;
}
static unsigned long _hash(const char *str, unsigned len)
{
unsigned long h = 0, g;
unsigned i;
for (i = 0; i < len; i++) {
h <<= 4;
h += _nums[*str++];
g = h & ((unsigned) 0xf << 16u);
h += _nums[(unsigned char) *str++];
g = h & ((unsigned long) 0xf << 16u);
if (g) {
h ^= g >> 16u;
h ^= g >> 5u;
@@ -85,99 +89,30 @@ static unsigned _hash(const void *key, unsigned len)
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)
{
struct dm_hash_node *n = malloc(sizeof(*n) + len);
if (n) {
memcpy(n->key, key, len);
n->keylen = len;
}
return n;
}
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 +120,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 +134,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 +162,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 +173,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 +216,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 +247,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 +315,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 +344,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 +354,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 +375,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 +388,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);
}

View File

@@ -1,8 +1,6 @@
#ifndef BASE_DATA_STRUCT_LIST_H
#define BASE_DATA_STRUCT_LIST_H
#include "base/memory/container_of.h"
//----------------------------------------------------------------
/*
@@ -100,7 +98,7 @@ struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *e
* contained in a structure of type t, return the containing structure.
*/
#define dm_list_struct_base(v, t, head) \
container_of(v, t, head)
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
/*
* Given the address v of an instance of 'struct dm_list list' contained in
@@ -113,7 +111,7 @@ struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *e
* return another element f.
*/
#define dm_struct_field(v, t, e, f) \
(((t *)((uintptr_t)(v) - offsetof(t, e)))->f)
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
/*
* Given the address v of a known element e in a known structure of type t,

View File

@@ -47,7 +47,7 @@ struct value_chain {
struct prefix_chain {
struct value child;
unsigned len;
uint8_t prefix[];
uint8_t prefix[0];
};
struct node4 {
@@ -1032,7 +1032,7 @@ void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
{
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
if (lr.kb == ke || _prefix_chain_matches(&lr, ke))
(void) _iterate(lr.v, it);
_iterate(lr.v, it);
}
//----------------------------------------------------------------

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2018 - 2020 Red Hat, Inc. All rights reserved.
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
//
// This file is part of LVM2.
//
@@ -13,12 +13,10 @@
#ifndef BASE_MEMORY_CONTAINER_OF_H
#define BASE_MEMORY_CONTAINER_OF_H
#include <stddef.h> // offsetof
//----------------------------------------------------------------
#define container_of(v, t, head) \
((t *)((char *)(v) - offsetof(t, head)))
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
//----------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@@ -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 = ""

10372
configure vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -46,7 +46,6 @@ const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile
return "STRING";
}
/*
struct logical_volume *origin_from_cow(const struct logical_volume *lv)
{
if (lv)
@@ -54,7 +53,6 @@ struct logical_volume *origin_from_cow(const struct logical_volume *lv)
__coverity_panic__();
}
*/
/* simple_memccpy() from glibc */
void *memccpy(void *dest, const void *src, int c, size_t n)

View File

@@ -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

View File

@@ -245,7 +245,6 @@ static void daemonize(void)
}
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
/* coverity[leaked_handle] devnull cannot leak here */
}
/*

View File

@@ -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,
};

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
@@ -755,7 +752,7 @@ static void _exit_timeout(void *unused __attribute__((unused)))
static void *_timeout_thread(void *unused __attribute__((unused)))
{
struct thread_status *thread;
struct timespec timeout, real_time;
struct timespec timeout;
time_t curr_time;
int ret;
@@ -766,16 +763,7 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
while (!dm_list_empty(&_timeout_registry)) {
timeout.tv_sec = 0;
timeout.tv_nsec = 0;
#ifndef HAVE_REALTIME
curr_time = time(NULL);
#else
if (clock_gettime(CLOCK_REALTIME, &real_time)) {
log_error("Failed to read clock_gettime().");
break;
}
/* 10ms back to the future */
curr_time = real_time.tv_sec + ((real_time.tv_nsec > (1000000000 - 10000000)) ? 1 : 0);
#endif
dm_list_iterate_items_gen(thread, &_timeout_registry, timeout_list) {
if (thread->next_time <= curr_time) {
@@ -1075,7 +1063,6 @@ out:
* "label at end of compound statement" */
;
/* coverity[lock_order] _global_mutex is kept locked */
pthread_cleanup_pop(1);
return NULL;
@@ -1498,34 +1485,37 @@ static int _client_read(struct dm_event_fifos *fifos,
t.tv_usec = 0;
ret = select(fifos->client + 1, &fds, NULL, NULL, &t);
if (!ret && bytes)
continue; /* trying to finish read */
if (!ret && !bytes) /* nothing to read */
return 0;
if (ret <= 0) /* nothing to read */
goto bad;
if (!ret) /* trying to finish read */
continue;
if (ret < 0) /* error */
return 0;
ret = read(fifos->client, buf + bytes, size - bytes);
bytes += ret > 0 ? ret : 0;
if (!msg->data && (bytes == 2 * sizeof(uint32_t))) {
if (header && (bytes == 2 * sizeof(uint32_t))) {
msg->cmd = ntohl(header[0]);
size = msg->size = ntohl(header[1]);
bytes = 0;
if (!(size = msg->size = ntohl(header[1])))
break;
if (!(buf = msg->data = malloc(msg->size)))
goto bad;
if (!size)
break; /* No data -> error */
buf = msg->data = malloc(msg->size);
if (!buf)
break; /* No mem -> error */
header = 0;
}
}
if (bytes == size)
return 1;
if (bytes != size) {
free(msg->data);
msg->data = NULL;
return 0;
}
bad:
free(msg->data);
msg->data = NULL;
return 0;
return 1;
}
/*
@@ -1746,8 +1736,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 */
@@ -2033,8 +2022,8 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
static void _restart_dmeventd(void)
{
struct dm_event_fifos fifos = {
.client = -1,
.server = -1,
.client = -1,
/* FIXME Make these either configurable or depend directly on dmeventd_path */
.client_path = DM_EVENT_FIFO_CLIENT,
.server_path = DM_EVENT_FIFO_SERVER
@@ -2073,7 +2062,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 +2074,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)) {
@@ -2247,8 +2237,7 @@ int main(int argc, char *argv[])
_init_thread_signals();
if (pthread_mutex_init(&_global_mutex, NULL))
exit(EXIT_FAILURE);
pthread_mutex_init(&_global_mutex, NULL);
if (!_systemd_activation && !_open_fifos(&fifos))
exit(EXIT_FIFO_FAILURE);

View File

@@ -237,16 +237,16 @@ static int _daemon_read(struct dm_event_fifos *fifos,
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
if (ret < 0 && errno != EINTR) {
log_error("Unable to read from event server.");
goto bad;
return 0;
}
if ((ret == 0) && (i > 4) && !bytes) {
log_error("No input from event server.");
goto bad;
return 0;
}
}
if (ret < 1) {
log_error("Unable to read from event server.");
goto bad;
return 0;
}
ret = read(fifos->server, buf + bytes, size);
@@ -255,32 +255,25 @@ static int _daemon_read(struct dm_event_fifos *fifos,
continue;
log_error("Unable to read from event server.");
goto bad;
return 0;
}
bytes += ret;
if (!msg->data && (bytes == 2 * sizeof(uint32_t))) {
if (header && (bytes == 2 * sizeof(uint32_t))) {
msg->cmd = ntohl(header[0]);
msg->size = ntohl(header[1]);
buf = msg->data = malloc(msg->size);
size = msg->size;
bytes = 0;
if (!(size = msg->size = ntohl(header[1])))
break;
if (!(buf = msg->data = malloc(msg->size))) {
log_error("Unable to allocate message data.");
return 0;
}
header = 0;
}
}
if (bytes == size)
return 1;
bad:
free(msg->data);
msg->data = NULL;
return 0;
if (bytes != size) {
free(msg->data);
msg->data = NULL;
}
return bytes == size;
}
/* Write message to daemon. */
@@ -615,8 +608,8 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
{
int ret;
struct dm_event_fifos fifos = {
.client = -1,
.server = -1,
.client = -1,
/* FIXME Make these either configurable or depend directly on dmeventd_path */
.client_path = DM_EVENT_FIFO_CLIENT,
.server_path = DM_EVENT_FIFO_SERVER
@@ -709,11 +702,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;
}

View File

@@ -71,7 +71,7 @@ int dmeventd_lvm2_init(void)
if (!_lvm_handle) {
lvm2_log_fn(_lvm2_print_log);
if (!(_lvm_handle = lvm2_init_threaded()))
if (!(_lvm_handle = lvm2_init()))
goto out;
/*

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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)

View File

@@ -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 '/'

View File

@@ -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
@@ -92,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():
"""
@@ -109,9 +104,3 @@ def exit_daemon():
if run and loop:
run.value = 0
loop.quit()
# Debug data for lvm
lvmdebug = None
systemd = False

View File

@@ -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
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,23 +82,16 @@ 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)
@@ -123,58 +99,15 @@ def call_lvm(command, debug=False, line_cb=None,
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))
return process.returncode, stdout_text, 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
@@ -189,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
@@ -224,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
@@ -242,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()):
@@ -436,14 +398,6 @@ def vg_create_vdo_pool_lv_and_lv(vg_name, pool_name, lv_name, data_size,
return call(cmd)
def vg_create_vdo_pool(pool_full_name, lv_name, virtual_size, create_options):
cmd = ['lvconvert']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--type', 'vdo-pool', '-n', lv_name, '--force', '-y',
'-V', '%dB' % virtual_size, pool_full_name])
return call(cmd)
def lv_remove(lv_path, remove_options):
cmd = ['lvremove']
cmd.extend(options_to_cli_args(remove_options))
@@ -491,15 +445,6 @@ def lv_cache_lv(cache_pool_full_name, lv_full_name, cache_options):
return call(cmd)
def lv_writecache_lv(cache_lv_full_name, lv_full_name, cache_options):
# lvconvert --type writecache --cachevol VG/CacheLV VG/OriginLV
cmd = ['lvconvert']
cmd.extend(options_to_cli_args(cache_options))
cmd.extend(['-y', '--type', 'writecache', '--cachevol',
cache_lv_full_name, lv_full_name])
return call(cmd)
def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
cmd = ['lvconvert']
if destroy_cache:
@@ -515,28 +460,6 @@ def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
return call(cmd)
def lv_vdo_compression(lv_path, enable, comp_options):
cmd = ['lvchange', '--compression']
if enable:
cmd.append('y')
else:
cmd.append('n')
cmd.extend(options_to_cli_args(comp_options))
cmd.append(lv_path)
return call(cmd)
def lv_vdo_deduplication(lv_path, enable, dedup_options):
cmd = ['lvchange', '--deduplication']
if enable:
cmd.append('y')
else:
cmd.append('n')
cmd.extend(options_to_cli_args(dedup_options))
cmd.append(lv_path)
return call(cmd)
def supports_json():
cmd = ['help']
rc, out, err = call(cmd)
@@ -608,32 +531,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:
# If the 'call' implementation is lvmshell, the out is a dictionary as lvmshell has to
# parse the output to get the exit value. When doing fork & exec, out is a string
# representing the JSON. TODO: Make this consistent between implementations.
# With the current implementation, if we are using the shell then we
# are using JSON and JSON is returned back to us as it was parsed to
# figure out if we completed OK or not
if cfg.SHELL_IN_USE:
assert(type(out) == dict)
return out
else:
try:
return json.loads(out)
except json.decoder.JSONDecodeError as joe:
log_error("JSONDecodeError %s, \n JSON=\n%s\n" %
(str(joe), out))
raise LvmBug("'fullreport' returned invalid JSON")
return json.loads(out)
return None
raise LvmBug("'fullreport' exited with code '%d'" % rc)
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):
@@ -790,6 +743,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))

View File

@@ -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()

View File

@@ -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)

View File

@@ -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

View File

@@ -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)")
@@ -393,7 +388,7 @@ class LvCommon(AutomatedProperties):
'l': 'mirror log device', 'c': 'under conversion',
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
'e': 'raid or pool metadata or pool metadata spare',
'd': 'vdo pool', 'D': 'vdo pool data', 'g': 'integrity',
'd': 'vdo pool', 'D': 'vdo pool data',
'-': 'Unspecified'}
return self.attr_struct(0, type_map)
@@ -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(
@@ -748,54 +743,6 @@ class Lv(LvCommon):
cb, cbe, return_tuple=False)
cfg.worker_q.put(r)
@staticmethod
def _caching_common(method, lv_uuid, lv_name, lv_object_path, cache_options):
# Make sure we have a dbus object representing it
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
# Make sure we have dbus object representing lv to cache
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
if lv_to_cache:
fcn = lv_to_cache.lv_full_name()
rc, out, err = method(
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
@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}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def WriteCacheLv(self, lv_object, tmo, cache_options, cb, cbe):
r = RequestEntry(
tmo, Lv._writecache_lv,
(self.Uuid, self.lvm_id, lv_object,
cache_options), cb, cbe)
cfg.worker_q.put(r)
# noinspection PyPep8Naming
@utils.dbus_property(VDO_POOL_INTERFACE, 'OperatingMode', 's')
@utils.dbus_property(VDO_POOL_INTERFACE, 'CompressionState', 's')
@@ -833,72 +780,6 @@ class LvVdoPool(Lv):
def DataLv(self):
return dbus.ObjectPath(self._data_lv)
@staticmethod
def _enable_disable_compression(pool_uuid, pool_name, enable, comp_options):
# Make sure we have a dbus object representing it
LvCommon.validate_dbus_object(pool_uuid, pool_name)
# Rename the logical volume
LvCommon.handle_execute(*cmdhandler.lv_vdo_compression(
pool_name, enable, comp_options))
return '/'
@dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def EnableCompression(self, tmo, comp_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_compression,
(self.Uuid, self.lvm_id, True, comp_options),
cb, cbe, False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def DisableCompression(self, tmo, comp_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_compression,
(self.Uuid, self.lvm_id, False, comp_options),
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _enable_disable_deduplication(pool_uuid, pool_name, enable, dedup_options):
# Make sure we have a dbus object representing it
LvCommon.validate_dbus_object(pool_uuid, pool_name)
# Rename the logical volume
LvCommon.handle_execute(*cmdhandler.lv_vdo_deduplication(
pool_name, enable, dedup_options))
return '/'
@dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def EnableDeduplication(self, tmo, dedup_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_deduplication,
(self.Uuid, self.lvm_id, True, dedup_options),
cb, cbe, False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_deduplication,
(self.Uuid, self.lvm_id, False, dedup_options),
cb, cbe, False)
cfg.worker_q.put(r)
# noinspection PyPep8Naming
class LvThinPool(Lv):
@@ -962,8 +843,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,

208
daemons/lvmdbusd/lvm_shell_proxy.py.in Executable file → Normal file
View 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
from lvmdbusd.cfg import LVM_CMD, run
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
read_decoded, extract_stack_trace, LvmBug
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 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,100 +106,83 @@ 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 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(
[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 LVMShellProxy.get_error_msg(report_json)
@staticmethod
def get_error_msg(report_json):
# Get the error message from the returned 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
@@ -208,7 +195,7 @@ class LVMShellProxy(object):
return error_msg
return None
return 'No error reason provided! (missing "log" section)'
def call_lvm(self, argv, debug=False):
rc = 1
@@ -229,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 = LVMShellProxy.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
@@ -270,37 +249,24 @@ class LVMShellProxy(object):
if __name__ == "__main__":
print("USING LVM BINARY: %s " % 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)

View File

@@ -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")
@@ -436,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")

View File

@@ -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,12 +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)
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',
@@ -105,140 +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()
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('Utilizing udev to trigger updates')
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('LVMDBUSD_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

View File

@@ -27,7 +27,7 @@ class Manager(AutomatedProperties):
@property
def Version(self):
return dbus.String('1.1.0')
return dbus.String('1.0.0')
@staticmethod
def handle_execute(rc, out, err):
@@ -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(
@@ -206,9 +204,11 @@ class Manager(AutomatedProperties):
# 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_msg("ExternalEvent received, disabling "
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)

View File

@@ -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,7 +308,7 @@ 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 likely not unique
# and thus not useful and potentially harmful for lookups.
@@ -327,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

View File

@@ -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

View File

@@ -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):

View File

@@ -52,8 +52,8 @@ def filter_event(action, device):
# when appropriate.
refresh = False
if 'ID_FS_TYPE' in device:
fs_type_new = device['ID_FS_TYPE']
if '.ID_FS_TYPE_NEW' in device:
fs_type_new = device['.ID_FS_TYPE_NEW']
if 'LVM' in fs_type_new:
refresh = True

View File

@@ -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,21 +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:
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
@@ -619,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
@@ -647,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!
@@ -672,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
@@ -723,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):
@@ -733,118 +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()

View File

@@ -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
@@ -820,35 +813,3 @@ class VgVdo(Vg):
round_size(virtual_size),
create_options), cb, cbe)
cfg.worker_q.put(r)
@staticmethod
def _vdo_pool_create(uuid, vg_name, pool_lv, name, virtual_size, create_options):
Vg.validate_dbus_object(uuid, vg_name)
# Retrieve the full name of the pool lv
pool = cfg.om.get_object_by_path(pool_lv)
if not pool:
msg = 'LV with object path %s not present!' % \
(pool_lv)
raise dbus.exceptions.DBusException(VG_VDO_INTERFACE, msg)
Vg.handle_execute(*cmdhandler.vg_create_vdo_pool(
pool.lv_full_name(), name, virtual_size,
create_options))
return Vg.fetch_new_lv(vg_name, pool.Name)
@dbus.service.method(
dbus_interface=VG_VDO_INTERFACE,
in_signature='ostia{sv}',
out_signature='(oo)',
async_callbacks=('cb', 'cbe'))
def CreateVdoPool(self, pool_lv, name, virtual_size,
tmo, create_options, cb, cbe):
utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, name)
r = RequestEntry(tmo, VgVdo._vdo_pool_create,
(self.state.Uuid, self.state.lvm_id,
pool_lv, name,
round_size(virtual_size),
create_options), cb, cbe)
cfg.worker_q.put(r)

View File

@@ -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] $<"

View File

@@ -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 */
@@ -300,12 +280,13 @@ static void format_info_line(char *line, char *r_name, char *r_type)
static void format_info(void)
{
char line[MAX_LINE] = { 0 };
char r_name[MAX_NAME+1] = { 0 };
char r_type[MAX_NAME+1] = { 0 };
char line[MAX_LINE];
char r_name[MAX_NAME+1];
char r_type[MAX_NAME+1];
int i, j;
j = 0;
memset(line, 0, sizeof(line));
for (i = 0; i < dump_len; i++) {
line[j++] = dump_buf[i];
@@ -345,8 +326,6 @@ static int _lvmlockd_result(daemon_reply reply, int *result)
{
int reply_result;
*result = NO_LOCKD_RESULT;
if (reply.error) {
log_error("lvmlockd_result reply error %d", reply.error);
return 0;
@@ -358,7 +337,7 @@ static int _lvmlockd_result(daemon_reply reply, int *result)
}
reply_result = daemon_reply_int(reply, "op_result", NO_LOCKD_RESULT);
if (reply_result == NO_LOCKD_RESULT) {
if (reply_result == -1000) {
log_error("lvmlockd_result no op_result");
return 0;
}
@@ -457,7 +436,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 +501,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 +554,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 +582,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 +599,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 +608,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 +627,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 +636,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 +662,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 +697,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 +719,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;

View File

@@ -14,7 +14,6 @@
#include "libdaemon/client/daemon-client.h"
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
#define LVMLOCKD_ADOPT_FILE DEFAULT_RUN_DIR "/lvmlockd.adopt"
/* Wrappers to open/close connection */
@@ -23,9 +22,9 @@ static inline daemon_handle lvmlockd_open(const char *sock)
daemon_info lvmlockd_info = {
.path = "lvmlockd",
.socket = sock ?: LVMLOCKD_SOCKET,
.autostart = 0,
.protocol = "lvmlockd",
.protocol_version = 1,
.autostart = 0
};
return daemon_open(lvmlockd_info);
@@ -33,7 +32,7 @@ static inline daemon_handle lvmlockd_open(const char *sock)
static inline void lvmlockd_close(daemon_handle h)
{
daemon_close(h);
return daemon_close(h);
}
/*

File diff suppressed because it is too large Load Diff

View File

@@ -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)
@@ -328,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;
@@ -398,18 +398,12 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
(void *)1, (void *)1, (void *)1,
NULL, NULL);
if (rv == -1 && (errno == EAGAIN)) {
if (rv == -1 && errno == -EAGAIN) {
log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
ls->name, r->name, ld_mode);
rv = -EUCLEAN;
goto fail;
}
if (rv == -1 && (errno == ENOENT)) {
log_debug("S %s R %s adopt_dlm adopt mode %d no lock",
ls->name, r->name, ld_mode);
rv = -ENOENT;
goto fail;
}
if (rv < 0) {
log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
ls->name, r->name, mode, flags, rv, errno);
@@ -791,18 +785,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 == '/')

View File

@@ -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(&regex, "^[0-9]+:[0-9]+:[0-9]+:[0-9]+$", REG_EXTENDED);
if (ret)
return 0;
ret = regexec(&regex, s->d_name, 0, NULL, 0);
if (!ret) {
regfree(&regex);
return 1;
}
regfree(&regex);
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 *)&timestamp,
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;
}

View File

@@ -11,8 +11,6 @@
#ifndef _LVM_LVMLOCKD_INTERNAL_H
#define _LVM_LVMLOCKD_INTERNAL_H
#include "base/memory/container_of.h"
#define MAX_NAME 64
#define MAX_ARGS 64
@@ -20,7 +18,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 +27,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 +116,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 +138,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 {
@@ -155,7 +145,6 @@ struct resource {
char name[MAX_NAME+1]; /* vg name or lv name */
int8_t type; /* resource type LD_RT_ */
int8_t mode;
int8_t adopt_mode;
unsigned int sh_count; /* number of sh locks on locks list */
uint32_t version;
uint32_t last_client_id; /* last client_id to lock or unlock resource */
@@ -166,7 +155,7 @@ struct resource {
struct list_head locks;
struct list_head actions;
char lv_args[MAX_ARGS+1];
char lm_data[]; /* lock manager specific data */
char lm_data[0]; /* lock manager specific data */
};
#define LD_LF_PERSISTENT 0x00000001
@@ -192,7 +181,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 */
@@ -228,6 +216,10 @@ struct val_blk {
/* lm_unlock flags */
#define LMUF_FREE_VG 0x00000001
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
@@ -334,13 +326,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;
@@ -631,102 +620,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 */

View File

@@ -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++;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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"

View File

@@ -164,30 +164,20 @@ struct dm_info {
struct dm_deps {
uint32_t count;
uint32_t filler;
uint64_t device[];
uint64_t device[0];
};
struct dm_names {
uint64_t dev;
uint32_t next; /* Offset to next struct from start of this struct */
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 */
char name[0];
};
struct dm_versions {
uint32_t next; /* Offset to next struct from start of this struct */
uint32_t version[3];
char name[];
char name[0];
};
int dm_get_library_version(char *version, size_t size);
@@ -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,8 +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);
/*
* Record timestamp immediately after the ioctl returns.
@@ -414,7 +383,7 @@ int dm_get_status_cache(struct dm_pool *mem, const char *params,
struct dm_status_cache **status);
struct dm_status_writecache {
uint64_t error;
uint32_t error;
uint64_t total_blocks;
uint64_t free_blocks;
uint64_t writeback_blocks;
@@ -981,8 +950,6 @@ struct writecache_settings {
uint64_t autocommit_time; /* in milliseconds */
uint32_t fua;
uint32_t nofua;
uint32_t cleaner;
uint32_t max_age;
/*
* Allow an unrecognized key and its val to be passed to the kernel for
@@ -1002,8 +969,6 @@ struct writecache_settings {
unsigned autocommit_time_set:1;
unsigned fua_set:1;
unsigned nofua_set:1;
unsigned cleaner_set:1;
unsigned max_age_set:1;
};
int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
@@ -1017,14 +982,14 @@ int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
struct integrity_settings {
char mode[8];
uint32_t tag_size;
uint32_t block_size; /* optional table param always set by lvm */
const char *internal_hash; /* optional table param always set by lvm */
const char *internal_hash;
uint32_t journal_sectors;
uint32_t interleave_sectors;
uint32_t buffer_sectors;
uint32_t journal_watermark;
uint32_t commit_time;
uint32_t block_size;
uint32_t bitmap_flush_interval;
uint64_t sectors_per_bit;
@@ -1033,6 +998,7 @@ struct integrity_settings {
unsigned buffer_sectors_set:1;
unsigned journal_watermark_set:1;
unsigned commit_time_set:1;
unsigned block_size_set:1;
unsigned bitmap_flush_interval_set:1;
unsigned sectors_per_bit_set:1;
};
@@ -1041,16 +1007,13 @@ int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
uint64_t size,
const char *origin_uuid,
const char *meta_uuid,
struct integrity_settings *settings,
int recalculate);
struct integrity_settings *settings);
/*
* VDO target
*/
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
uint64_t size,
uint32_t vdo_version,
const char *vdo_pool_name,
const char *data_uuid,
uint64_t data_size,
const struct dm_vdo_target_params *param);
@@ -1103,10 +1066,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)
@@ -1119,16 +1082,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 */
@@ -1359,7 +1312,7 @@ int dm_bit_get_next(dm_bitset_t bs, int last_bit);
int dm_bit_get_last(dm_bitset_t bs);
int dm_bit_get_prev(dm_bitset_t bs, int last_bit);
#define DM_BITS_PER_INT ((unsigned)sizeof(int) * CHAR_BIT)
#define DM_BITS_PER_INT (sizeof(int) * CHAR_BIT)
#define dm_bit(bs, i) \
((bs)[((i) / DM_BITS_PER_INT) + 1] & (0x1 << ((i) & (DM_BITS_PER_INT - 1))))
@@ -1983,8 +1936,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);

View File

@@ -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

View File

@@ -205,7 +205,7 @@ static int _get_proc_number(const char *file, const char *name,
}
while (getline(&line, &len, fl) != -1) {
if (sscanf(line, "%u %255s\n", &num, &nm[0]) == 2) {
if (sscanf(line, "%d %255s\n", &num, &nm[0]) == 2) {
if (!strcmp(name, nm)) {
if (number) {
*number = num;
@@ -493,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);
}
@@ -507,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);
@@ -616,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)
@@ -754,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) +
@@ -963,11 +805,6 @@ int dm_task_suppress_identical_reload(struct dm_task *dmt)
return 1;
}
void dm_task_skip_reload_params_compare(struct dm_task *dmt)
{
dmt->skip_reload_params_compare = 1;
}
int dm_task_set_add_node(struct dm_task *dmt, dm_add_node_t add_node)
{
switch (add_node) {
@@ -1078,13 +915,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;
@@ -1277,7 +1107,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;
@@ -1296,18 +1126,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");
@@ -1409,11 +1227,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)
@@ -1452,14 +1268,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;
@@ -1521,7 +1329,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;
}
@@ -1593,7 +1401,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;
@@ -1654,7 +1463,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);
@@ -1767,36 +1575,11 @@ static int _reload_with_suppression_v4(struct dm_task *dmt)
len = strlen(t2->params);
while (len-- > 0 && t2->params[len] == ' ')
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);
if ((t1->start != t2->start) ||
(t1->length != t2->length) ||
(strcmp(t1->type, t2->type)) ||
(strcmp(t1->params, t2->params)))
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);
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);
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);
goto no_match;
}
}
t1 = t1->next;
t2 = t2->next;
}
@@ -1959,34 +1742,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);
}
@@ -2079,7 +1851,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 ? " " : "",
@@ -2097,7 +1869,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),
@@ -2390,3 +2161,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

View File

@@ -59,7 +59,6 @@ struct dm_task {
int skip_lockfs;
int query_inactive_table;
int suppress_identical_reload;
int skip_reload_params_compare;
dm_add_node_t add_node;
uint64_t existing_table_size;
int cookie_set;
@@ -70,7 +69,6 @@ struct dm_task {
int enable_checks;
int expected_errno;
int ioctl_errno;
int ima_measurement;
int record_timestamp;

View File

@@ -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;
}
@@ -513,7 +512,7 @@ int unmangle_string(const char *str, const char *str_name, size_t len,
int strict = mode != DM_STRING_MANGLING_NONE;
char str_rest[DM_NAME_LEN];
size_t i, j;
unsigned int code;
int code;
int r = 0;
if (!str || !buf)
@@ -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.
@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 */
@@ -228,7 +227,6 @@ struct load_segment {
uint64_t integrity_data_sectors; /* integrity (provided_data_sectors) */
struct dm_tree_node *integrity_meta_node; /* integrity */
struct integrity_settings integrity_settings; /* integrity */
int integrity_recalculate; /* integrity */
};
/* Per-device properties */
@@ -275,16 +273,6 @@ struct load_properties {
*/
unsigned delay_resume_if_extended;
/*
* When comparing table lines to decide if a reload is
* needed, ignore any differences betwen the lvm device
* params and the kernel-reported device params.
* dm-integrity reports many internal parameters on the
* table line when lvm does not explicitly set them,
* causing lvm and the kernel to have differing params.
*/
unsigned skip_reload_params_compare;
/*
* Call node_send_messages(), set to 2 if there are messages
* When != 0, it validates matching transaction id, thus thin-pools
@@ -331,7 +319,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 +363,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 +548,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 +604,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;
@@ -1579,37 +1578,8 @@ static int _thin_pool_node_message(struct dm_tree_node *dnode, struct thin_messa
}
if (!_node_message(dnode->info.major, dnode->info.minor,
tm->expected_errno, buf)) {
switch (m->type) {
case DM_THIN_MESSAGE_CREATE_SNAP:
case DM_THIN_MESSAGE_CREATE_THIN:
if (errno == EEXIST) {
/*
* ATM errno from ioctl() is preserved through code error path chain
* If this would ever change, another way need to be used to
* obtain result from failed DM message
*/
log_error("Thin pool %s already contain thin device with device_id %u.",
_node_name(dnode), m->u.m_create_snap.device_id);
/*
* TODO:
*
* Give some useful advice how to solve this problem,
* until lvconvert --repair can handle this automatically
*/
log_error("Manual intervention may be required to remove device dev_id=%u in thin pool metadata.",
m->u.m_create_snap.device_id);
log_error("Optionally new thin volume with device_id=%u can be manually added into a volume group.",
m->u.m_create_snap.device_id);
log_warn("WARNING: When uncertain how to do this, contact support!");
return 0;
}
/* fall through */
default:
return_0;
}
}
tm->expected_errno, buf))
return_0;
return 1;
}
@@ -1656,15 +1626,6 @@ static int _thin_pool_node_send_messages(struct dm_tree_node *dnode,
if (!have_messages || !send)
return 1; /* transaction_id is matching */
if (stp.fail || stp.read_only || stp.needs_check) {
log_error("Cannot send messages to thin pool %s%s%s%s.",
_node_name(dnode),
stp.fail ? " in failed state" : "",
stp.read_only ? " with read only metadata" : "",
stp.needs_check ? " which needs check first" : "");
return 0;
}
dm_list_iterate_items(tmsg, &seg->thin_messages) {
if (!(_thin_pool_node_message(dnode, tmsg)))
return_0;
@@ -2126,7 +2087,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
return r;
}
static int _create_node(struct dm_tree_node *dnode, struct dm_tree_node *parent)
static int _create_node(struct dm_tree_node *dnode)
{
int r = 0;
struct dm_task *dmt;
@@ -2175,15 +2136,38 @@ static int _create_node(struct dm_tree_node *dnode, struct dm_tree_node *parent)
"Unable to get DM task info for %s.",
dnode->name);
}
if (r)
dnode->activated = 1;
out:
dm_task_destroy(dmt);
return r;
}
/*
* _remove_node
*
* This function is only used to remove a DM device that has failed
* to load any table.
*/
static int _remove_node(struct dm_tree_node *dnode)
{
if (!dnode->info.exists)
return 1;
if (dnode->info.live_table || dnode->info.inactive_table) {
log_error(INTERNAL_ERROR
"_remove_node called on device with loaded table(s).");
return 0;
}
if (!_deactivate_node(dnode->name, dnode->info.major, dnode->info.minor,
&dnode->dtree->cookie, dnode->udev_flags, 0)) {
log_error("Failed to clean-up device with no table: %s.",
_node_name(dnode));
return 0;
}
return 1;
}
static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *node)
{
if (!dm_format_dev(devbuf, bufsize, node->info.major, node->info.minor)) {
@@ -2372,7 +2356,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 +2558,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 +2618,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)
@@ -2675,10 +2659,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
count += 1;
if (seg->writecache_settings.nofua_set)
count += 1;
if (seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner)
count += 1;
if (seg->writecache_settings.max_age_set)
count += 2;
if (seg->writecache_settings.new_key)
count += 2;
@@ -2722,14 +2702,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
EMIT_PARAMS(pos, " nofua");
}
if (seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner) {
EMIT_PARAMS(pos, " cleaner");
}
if (seg->writecache_settings.max_age_set) {
EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age);
}
if (seg->writecache_settings.new_key) {
EMIT_PARAMS(pos, " %s %s",
seg->writecache_settings.new_key,
@@ -2756,14 +2728,11 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
!_build_dev_string(meta_dev, sizeof(meta_dev), seg->integrity_meta_node))
return_0;
count = 3; /* block_size, internal_hash, fix_padding options are always passed */
count = 1; /* for internal_hash which we always pass in */
if (seg->integrity_meta_node)
count++;
if (seg->integrity_recalculate)
count++;
if (set->journal_sectors_set)
count++;
if (set->interleave_sectors_set)
@@ -2774,25 +2743,23 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
count++;
if (set->commit_time_set)
count++;
if (set->block_size_set)
count++;
if (set->bitmap_flush_interval_set)
count++;
if (set->sectors_per_bit_set)
count++;
EMIT_PARAMS(pos, "%s 0 %u %s %d fix_padding block_size:%u internal_hash:%s",
EMIT_PARAMS(pos, "%s 0 %u %s %d internal_hash:%s",
origin_dev,
set->tag_size,
set->mode,
count,
set->block_size,
set->internal_hash);
if (seg->integrity_meta_node)
EMIT_PARAMS(pos, " meta_device:%s", meta_dev);
if (seg->integrity_recalculate)
EMIT_PARAMS(pos, " recalculate");
if (set->journal_sectors_set)
EMIT_PARAMS(pos, " journal_sectors:%u", set->journal_sectors);
@@ -2808,15 +2775,15 @@ static int _integrity_emit_segment_line(struct dm_task *dmt,
if (set->commit_time_set)
EMIT_PARAMS(pos, " commit_time:%u", set->commit_time);
if (set->block_size_set)
EMIT_PARAMS(pos, " block_size:%u", set->block_size);
if (set->bitmap_flush_interval_set)
EMIT_PARAMS(pos, " bitmap_flush_interval:%u", set->bitmap_flush_interval);
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;
}
@@ -2866,28 +2833,17 @@ static int _vdo_emit_segment_line(struct dm_task *dmt,
return 0;
}
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 ",
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);
}
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,
@@ -2931,6 +2887,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];
@@ -2941,7 +2898,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:
@@ -2962,7 +2920,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, seg, params, paramsize))
if (!(r = _vdo_emit_segment_line(dmt, seg, params, paramsize)))
return_0;
break;
case SEG_CRYPT:
@@ -2991,8 +2949,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;
@@ -3033,9 +2992,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,
@@ -3132,9 +3092,6 @@ static int _load_node(struct dm_tree_node *dnode)
if (!dm_task_suppress_identical_reload(dmt))
log_warn("WARNING: Failed to suppress reload of identical tables.");
if (dnode->props.skip_reload_params_compare)
dm_task_skip_reload_params_compare(dmt);
if ((r = dm_task_run(dmt))) {
r = dm_task_get_info(dmt, &dnode->info);
if (r && !dnode->info.inactive_table)
@@ -3153,8 +3110,8 @@ static int _load_node(struct dm_tree_node *dnode)
if (!existing_table_size && dnode->props.delay_resume_if_new)
dnode->props.size_changed = 0;
log_debug_activation("Table size changed from %" PRIu64 " to %" PRIu64 " for %s.%s",
existing_table_size,
log_debug_activation("Table size changed from %" PRIu64 " to %"
PRIu64 " for %s.%s", existing_table_size,
seg_start, _node_name(dnode),
dnode->props.size_changed ? "" : " (Ignoring.)");
@@ -3180,45 +3137,32 @@ 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;
}
return 1;
}
static int _dm_tree_wait_and_revert_activated(struct dm_tree_node *dnode)
{
if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
stack;
dm_tree_set_cookie(dnode, 0);
return _dm_tree_revert_activated(dnode);
}
int dm_tree_preload_children(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len)
@@ -3248,7 +3192,7 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
return_0;
/* FIXME Cope if name exists with no uuid? */
if (!child->info.exists && !(node_created = _create_node(child, dnode)))
if (!child->info.exists && !(node_created = _create_node(child)))
return_0;
/* Propagate delayed resume from exteded child node */
@@ -3258,22 +3202,28 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
if (!child->info.inactive_table &&
child->props.segment_count &&
!_load_node(child)) {
stack;
/*
* If the table load fails, try to device in the kernel
* together with other created and preloaded devices.
* If the table load does not succeed, we remove the
* device in the kernel that would otherwise have an
* empty table. This makes the create + load of the
* device atomic. However, if other dependencies have
* already been created and loaded; this code is
* insufficient to remove those - only the node
* encountering the table load failure is removed.
*/
if (!_dm_tree_wait_and_revert_activated(dnode))
stack;
r = 0;
continue;
if (node_created) {
if (!_remove_node(child))
return_0;
if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
stack;
dm_tree_set_cookie(dnode, 0);
(void) _dm_tree_revert_activated(child);
}
return_0;
}
/* No resume for a device without parents or with unchanged or smaller size */
if (!dm_tree_node_num_children(child, 1))
continue;
if (child->props.size_changed <= 0)
if (!dm_tree_node_num_children(child, 1) || (child->props.size_changed <= 0))
continue;
if (!child->info.inactive_table && !child->info.suspended)
@@ -3284,19 +3234,28 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
&child->info, &child->dtree->cookie, child->udev_flags,
child->info.suspended)) {
log_error("Unable to resume %s.", _node_name(child));
if (!_dm_tree_wait_and_revert_activated(dnode))
stack;
/* If the device was not previously active, we might as well remove this node. */
if (!child->info.live_table &&
!_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));
r = 0;
/* Each child is handled independently */
continue;
}
if (node_created) {
/* Collect newly introduced devices for revert */
dm_list_add_h(&dnode->activated, &child->activated_list);
/* When creating new node also check transaction_id. */
if (child->props.send_messages &&
!_node_send_messages(child, uuid_prefix, uuid_prefix_len, 0)) {
stack;
if (!_dm_tree_wait_and_revert_activated(dnode))
if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
stack;
dm_tree_set_cookie(dnode, 0);
(void) _dm_tree_revert_activated(dnode);
r = 0;
continue;
}
@@ -3870,41 +3829,32 @@ int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
uint64_t size,
const char *origin_uuid,
const char *meta_uuid,
struct integrity_settings *settings,
int recalculate)
struct integrity_settings *settings)
{
struct load_segment *seg;
if (!(seg = _add_segment(node, SEG_INTEGRITY, size)))
return_0;
if (!meta_uuid) {
log_error("No integrity meta uuid.");
return 0;
}
if (meta_uuid) {
if (!(seg->integrity_meta_node = dm_tree_find_node_by_uuid(node->dtree, meta_uuid))) {
log_error("Missing integrity's meta uuid %s.", meta_uuid);
return 0;
}
if (!(seg->integrity_meta_node = dm_tree_find_node_by_uuid(node->dtree, meta_uuid))) {
log_error("Missing integrity's meta uuid %s.", meta_uuid);
return 0;
if (!_link_tree_nodes(node, seg->integrity_meta_node))
return_0;
}
if (!_link_tree_nodes(node, seg->integrity_meta_node))
return_0;
if (!(seg->origin = dm_tree_find_node_by_uuid(node->dtree, origin_uuid))) {
log_error("Missing integrity's origin uuid %s.", origin_uuid);
return 0;
}
if (!_link_tree_nodes(node, seg->origin))
return_0;
memcpy(&seg->integrity_settings, settings, sizeof(struct integrity_settings));
seg->integrity_recalculate = recalculate;
node->props.skip_reload_params_compare = 1;
return 1;
}
@@ -3981,24 +3931,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;
@@ -4026,18 +3958,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);
@@ -4332,10 +4263,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,
const struct dm_vdo_target_params *vtp)
@@ -4356,9 +4340,8 @@ 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_name = node->name;
seg->vdo_data_size = data_size;
node->props.send_messages = 2;

View File

@@ -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;
}

View File

@@ -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;
}
@@ -823,11 +749,10 @@ static void _display_fields_more(struct dm_report *rh,
id_len = strlen(type->prefix) + 3;
for (f = 0; fields[f].report_fn; f++) {
if (!(type = _find_type(rh, fields[f].type))) {
log_debug(INTERNAL_ERROR "Field type undefined.");
continue;
}
desc = (type->desc) ? : " ";
if ((type = _find_type(rh, fields[f].type)) && type->desc)
desc = type->desc;
else
desc = " ";
if (desc != last_desc) {
if (*last_desc)
log_warn(" ");
@@ -1762,7 +1687,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 +1697,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 +1720,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 +1732,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 +1754,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 +1767,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 +2331,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 +2473,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 +3773,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 +3909,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 +3955,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 +3987,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 +4359,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 +4368,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 +4430,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 +4476,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 +4486,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 +4495,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 +4504,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 +4982,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 +5045,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 +5081,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;

View File

@@ -366,8 +366,8 @@ int dm_get_status_writecache(struct dm_pool *mem, const char *params,
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_writecache))))
return_0;
if (sscanf(params, "%llu %llu %llu %llu",
(unsigned long long *)&s->error,
if (sscanf(params, "%u %llu %llu %llu",
&s->error,
(unsigned long long *)&s->total_blocks,
(unsigned long long *)&s->free_blocks,
(unsigned long long *)&s->writeback_blocks) != 4) {
@@ -384,11 +384,13 @@ int dm_get_status_integrity(struct dm_pool *mem, const char *params,
struct dm_status_integrity **status)
{
struct dm_status_integrity *s;
char recalc_str[16] = "\0";
char recalc_str[8];
if (!(s = dm_pool_zalloc(mem, sizeof(*s))))
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_integrity))))
return_0;
memset(recalc_str, 0, sizeof(recalc_str));
if (sscanf(params, "%llu %llu %s",
(unsigned long long *)&s->number_of_mismatches,
(unsigned long long *)&s->provided_data_sectors,

View File

@@ -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.
*/
@@ -195,22 +194,8 @@ struct dm_name_list {
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];
*/
};
#define DM_NAME_LIST_FLAG_HAS_UUID 1
#define DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID 2
/*
* Used to retrieve the target versions
*/
@@ -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 */

View File

@@ -98,7 +98,7 @@ void dm_pools_check_leaks(void)
p->orig_pool,
p->name, p->stats.bytes);
#else
log_error(" [%p] %s", (void *)p, p->name);
log_error(" [%p] %s", p, p->name);
#endif
}
pthread_mutex_unlock(&_dm_pools_mutex);

View File

@@ -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

View File

@@ -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

View File

@@ -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) {
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) / 2,
DM_VDO_LOGICAL_SIZE_MAXIMUM / (UINT64_C(1024) * 1024 * 1024 * 1024 >> SECTOR_SHIFT));
(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;
}

View File

@@ -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)

2
include/.gitignore vendored
View File

@@ -1,3 +1 @@
*.h
.symlinks
.symlinks_created

View File

@@ -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
@@ -124,22 +126,17 @@
/* Library version */
#undef DM_LIB_VERSION
/* Define to 1 to include the LVM editline shell. */
#undef EDITLINE_SUPPORT
/* 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. */
@@ -154,9 +151,6 @@
/* Define to 1 if you have the `atexit' function. */
#undef HAVE_ATEXIT
/* Define if ioctl BLKZEROOUT can be used for device zeroing. */
#undef HAVE_BLKZEROOUT
/* Define to 1 if canonicalize_file_name is available. */
#undef HAVE_CANONICALIZE_FILE_NAME
@@ -182,18 +176,12 @@
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
#undef HAVE_DOPRNT
/* Define to 1 if you have the <editline/readline.h> header file. */
#undef HAVE_EDITLINE_READLINE_H
/* Define to 1 if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
/* 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 +255,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 +265,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 +384,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 +507,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,12 +531,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
/* Internalization package */
#undef INTL_PACKAGE
@@ -564,9 +543,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 +553,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 +571,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 +615,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 +629,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 +657,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 +736,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. */

View File

@@ -15,7 +15,6 @@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
abs_srcdir = @abs_srcdir@
SOURCES =\
activate/activate.c \
@@ -30,19 +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 \
display/display.c \
error/errseg.c \
unknown/unknown.c \
@@ -56,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 \
@@ -82,7 +76,6 @@ SOURCES =\
metadata/mirror.c \
metadata/pool_manip.c \
metadata/pv.c \
metadata/pv_list.c \
metadata/pv_manip.c \
metadata/pv_map.c \
metadata/raid_manip.c \

View File

@@ -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)
{
@@ -202,8 +185,8 @@ void set_activation(int act, int silent)
if (warned || !act)
return;
log_warn("WARNING: Compiled without libdevmapper support. "
"Can't enable activation.");
log_error("Compiled without libdevmapper support. "
"Can't enable activation.");
warned = 1;
}
@@ -238,13 +221,23 @@ int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_la
{
return 0;
}
int lv_info_with_seg_status(struct cmd_context *cmd,
const struct lv_segment *lv_seg,
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
struct lvinfo *info, int with_open_count, int with_read_ahead)
{
return 0;
}
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
const struct lv_segment *lv_seg, int use_layer,
struct lv_with_info_and_seg_status *status,
int with_open_count, int with_read_ahead)
{
return 0;
}
int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
int use_layer, struct lv_seg_status *lv_seg_status)
{
return 0;
}
int lv_cache_status(const struct logical_volume *cache_lv,
struct lv_status_cache **status)
{
@@ -291,21 +284,18 @@ 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)
int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
dm_percent_t *percent)
{
return 0;
}
int lv_writecache_message(const struct logical_volume *lv, const char *msg)
int lv_thin_percent(const struct logical_volume *lv, int mapped,
dm_percent_t *percent)
{
return 0;
}
int lv_thin_pool_status(const struct logical_volume *lv, int flush,
struct lv_status_thin_pool **thin_pool_status)
{
return 0;
}
int lv_thin_status(const struct logical_volume *lv, int flush,
struct lv_status_thin **thin_status)
int lv_thin_pool_transaction_id(const struct logical_volume *lv,
uint64_t *transaction_id)
{
return 0;
}
@@ -313,15 +303,6 @@ int lv_thin_device_id(const struct logical_volume *lv, uint32_t *device_id)
{
return 0;
}
int lv_vdo_pool_status(const struct logical_volume *lv, int flush,
struct lv_status_vdo **vdo_status)
{
return 0;
}
int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent)
{
return 0;
}
int lvs_in_vg_activated(const struct volume_group *vg)
{
return 0;
@@ -413,7 +394,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;
}
@@ -476,6 +457,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())
@@ -486,20 +478,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,
@@ -571,7 +555,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 '_' */
@@ -582,9 +566,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;
@@ -624,15 +612,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.
@@ -846,15 +825,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. */
@@ -881,24 +857,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;
}
/*
@@ -989,28 +966,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;
@@ -1020,23 +1004,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;
@@ -1045,20 +1031,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;
@@ -1068,20 +1058,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;
@@ -1091,27 +1086,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))) {
/*
@@ -1136,10 +1134,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;
}
@@ -1161,43 +1165,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;
@@ -1230,7 +1210,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) ||
@@ -1248,74 +1227,125 @@ 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)! */
return 1;
}
int lv_thin_pool_status(const struct logical_volume *lv, int flush,
struct lv_status_thin_pool **thin_pool_status)
/*
* Returns data or metadata percent usage, depends on metadata 0/1.
* Returns 1 if percent set, else 0 on failure.
*/
int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
dm_percent_t *percent)
{
int r;
struct dev_manager *dm;
int exists;
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
return 0;
log_debug_activation("Checking thin %sdata percent for LV %s.",
(metadata) ? "meta" : "", 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)) {
dev_manager_destroy(dm);
if (exists)
stack;
return 0;
}
if (!(r = dev_manager_thin_pool_percent(dm, lv, metadata, percent)))
stack;
/* User has to call dm_pool_destroy(thin_pool_status->mem)! */
dev_manager_destroy(dm);
return 1;
return r;
}
int lv_thin_status(const struct logical_volume *lv, int flush,
struct lv_status_thin **thin_status)
/*
* Returns 1 if percent set, else 0 on failure.
*/
int lv_thin_percent(const struct logical_volume *lv,
int mapped, dm_percent_t *percent)
{
int r;
struct dev_manager *dm;
int exists;
if (!lv_info(lv->vg->cmd, lv, 0, NULL, 0, 0))
return 0;
log_debug_activation("Checking thin percent 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)) {
dev_manager_destroy(dm);
if (exists)
stack;
if (!(r = dev_manager_thin_percent(dm, lv, mapped, percent)))
stack;
dev_manager_destroy(dm);
return r;
}
/*
* Returns 1 if transaction_id set, else 0 on failure.
*/
int lv_thin_pool_transaction_id(const struct logical_volume *lv,
uint64_t *transaction_id)
{
int r;
struct dev_manager *dm;
struct dm_status_thin_pool *status;
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
return 0;
}
/* User has to call dm_pool_destroy(thin_status->mem)! */
log_debug_activation("Checking thin-pool transaction id for LV %s.",
display_lvname(lv));
return 1;
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
return_0;
if (!(r = dev_manager_thin_pool_status(dm, lv, &status, 0)))
stack;
else
*transaction_id = status->transaction_id;
dev_manager_destroy(dm);
return r;
}
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);
@@ -1332,22 +1362,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)
@@ -1508,7 +1544,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 ||
@@ -2043,6 +2079,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" : "");
@@ -2064,12 +2106,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
@@ -2141,11 +2177,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;
}
@@ -2165,6 +2197,8 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
if (laopts->origin_only && lv_is_thin_volume(lv) && lv_is_thin_volume(lv_pre))
lockfs = 1;
critical_section_inc(cmd, "suspending");
if (!lv_is_locked(lv) && lv_is_locked(lv_pre) &&
(pvmove_lv = find_pvmove_lv_in_lv(lv_pre))) {
/*
@@ -2206,23 +2240,16 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
}
dm_list_add(&suspend_lvs, &lvl->list);
}
critical_section_inc(cmd, "suspending");
dm_list_iterate_items(lvl, &suspend_lvs)
if (!_lv_suspend_lv(lvl->lv, laopts, lockfs, 1)) {
critical_section_dec(cmd, "failed suspend");
goto_out; /* FIXME: resume on recovery path? */
}
} else { /* Standard suspend */
critical_section_inc(cmd, "suspending");
} else /* Standard suspend */
if (!_lv_suspend_lv(lv, laopts, lockfs, flush_required)) {
critical_section_dec(cmd, "failed suspend");
goto_out;
}
}
r = 1;
out:
@@ -2242,8 +2269,8 @@ int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned o
const struct logical_volume *lv, const struct logical_volume *lv_pre)
{
struct lv_activate_opts laopts = {
.exclusive = exclusive,
.origin_only = origin_only
.origin_only = origin_only,
.exclusive = exclusive
};
return _lv_suspend(cmd, lvid_s, &laopts, 0, lv, lv_pre);
@@ -2295,9 +2322,6 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
lv_is_thin_volume(lv) ? " thin only" : " without snapshots") : "",
laopts->revert ? " (reverting)" : "");
if (laopts->revert)
goto needs_resume;
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
goto_out;
@@ -2357,8 +2381,8 @@ int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s,
unsigned revert, const struct logical_volume *lv)
{
struct lv_activate_opts laopts = {
.exclusive = exclusive,
.origin_only = origin_only,
.exclusive = exclusive,
.revert = revert
};
@@ -2395,7 +2419,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;
@@ -2408,47 +2431,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))
@@ -2468,17 +2488,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;
@@ -2520,13 +2535,6 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
goto out;
}
if ((cmd->partial_activation || cmd->degraded_activation) &&
lv_is_partial(lv) && lv_is_raid(lv) && lv_raid_has_integrity((struct logical_volume *)lv)) {
cmd->partial_activation = 0;
cmd->degraded_activation = 0;
log_print("No degraded or partial activation for raid with integrity.");
}
if ((!lv->vg->cmd->partial_activation) && lv_is_partial(lv)) {
if (!lv_is_raid_type(lv) || !partial_raid_lv_supports_degraded_activation(lv)) {
log_error("Refusing activation of partial LV %s. "
@@ -2543,14 +2551,6 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
}
}
if ((cmd->partial_activation || cmd->degraded_activation) && lv_is_writecache(lv)) {
struct logical_volume *lv_fast = first_seg(lv)->writecache;
if (lv_is_partial(lv) || (lv_fast && lv_is_partial(lv_fast))) {
log_error("Cannot use partial or degraded activation with writecache.");
goto out;
}
}
if (lv_has_unknown_segments(lv)) {
log_error("Refusing activation of LV %s containing "
"an unrecognised segment.", display_lvname(lv));
@@ -2764,13 +2764,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 */
@@ -2853,7 +2850,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.",
@@ -2863,7 +2860,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;
}
@@ -2873,6 +2870,7 @@ int deactivate_lv_with_sub_lv(const struct logical_volume *lv)
int activate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
{
const struct logical_volume *active_lv;
const struct logical_volume *lv_use;
int ret;
/*
@@ -2891,19 +2889,30 @@ int activate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
goto out;
}
if (lv->status & LV_UNCOMMITTED)
lv_use = lv;
else
lv_use = lv_committed(lv);
ret = lv_activate_with_filter(cmd, NULL, 0,
(lv->status & LV_NOSCAN) ? 1 : 0,
(lv->status & LV_TEMPORARY) ? 1 : 0,
lv_committed(lv));
lv_use);
out:
return ret;
}
int deactivate_lv(struct cmd_context *cmd, const struct logical_volume *lv)
{
const struct logical_volume *lv_use;
int ret;
ret = lv_deactivate(cmd, NULL, lv_committed(lv));
if (lv->status & LV_UNCOMMITTED)
lv_use = lv;
else
lv_use = lv_committed(lv);
ret = lv_deactivate(cmd, NULL, lv_use);
return ret;
}
@@ -2958,7 +2967,8 @@ int revert_lv(struct cmd_context *cmd, const struct logical_volume *lv)
ret = lv_resume_if_active(cmd, NULL, 0, 0, 1, lv_committed(lv));
critical_section_dec(cmd, "unlocking on revert");
critical_section_dec(cmd, "unlocking on resume");
return ret;
}

View File

@@ -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,15 +188,16 @@ 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);
int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
dm_percent_t *percent);
int lv_thin_percent(const struct logical_volume *lv, int mapped,
dm_percent_t *percent);
int lv_thin_pool_transaction_id(const struct logical_volume *lv,
uint64_t *transaction_id);
int lv_thin_device_id(const struct logical_volume *lv, uint32_t *device_id);
int lv_thin_status(const struct logical_volume *lv, int flush,
struct lv_status_thin **status);
int lv_thin_pool_status(const struct logical_volume *lv, int flush,
struct lv_status_thin_pool **status);
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);
@@ -213,8 +210,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);
@@ -258,7 +253,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

File diff suppressed because it is too large Load Diff

View File

@@ -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,19 +68,24 @@ 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);
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_cache **status);
int dev_manager_thin_pool_status(struct dev_manager *dm,
const struct logical_volume *lv,
struct dm_status_thin_pool **status,
int flush);
int dev_manager_thin_pool_percent(struct dev_manager *dm,
const struct logical_volume *lv,
int metadata, dm_percent_t *percent);
int dev_manager_thin_percent(struct dev_manager *dm,
const struct logical_volume *lv,
int mapped, dm_percent_t *percent);
int dev_manager_thin_device_id(struct dev_manager *dm,
const struct logical_volume *lv,
uint32_t *device_id, int *exist);
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);
uint32_t *device_id);
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);
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,
@@ -105,7 +108,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

View File

@@ -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);
}
}

1525
lib/cache/lvmcache.c vendored

File diff suppressed because it is too large Load Diff

38
lib/cache/lvmcache.h vendored
View File

@@ -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;
@@ -69,21 +69,21 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset);
int lvmcache_label_scan(struct cmd_context *cmd);
int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid);
int lvmcache_label_rescan_vg_rw(struct cmd_context *cmd, const char *vgname, const char *vgid);
int lvmcache_label_reopen_vg_rw(struct cmd_context *cmd, const char *vgname, const char *vgid);
/* Add/delete a device */
struct lvmcache_info *lvmcache_add(struct cmd_context *cmd, struct labeller *labeller, const char *pvid,
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
struct device *dev, uint64_t label_sector,
const char *vgname, const char *vgid,
uint32_t vgstatus, int *is_duplicate);
int lvmcache_add_orphan_vginfo(struct cmd_context *cmd, const char *vgname, struct format_type *fmt);
int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt);
void lvmcache_del(struct lvmcache_info *info);
void lvmcache_del_dev(struct device *dev);
/* Update things */
int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info *info,
int lvmcache_update_vgname_and_id(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 +95,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);
@@ -162,6 +161,11 @@ struct device *lvmcache_device(struct lvmcache_info *info);
unsigned lvmcache_mda_count(struct lvmcache_info *info);
uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
struct metadata_area *lvmcache_get_mda(struct cmd_context *cmd,
const char *vgname,
struct device *dev,
int use_mda_num);
bool lvmcache_has_duplicate_devs(void);
void lvmcache_del_dev_from_duplicates(struct device *dev);
bool lvmcache_dev_is_unused_duplicate(struct device *dev);
@@ -170,7 +174,6 @@ int lvmcache_get_unused_duplicates(struct cmd_context *cmd, struct dm_list *head
int vg_has_duplicate_pvs(struct volume_group *vg);
int lvmcache_found_duplicate_vgnames(void);
bool lvmcache_has_duplicate_local_vgname(const char *vgid, const char *vgname);
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd);
@@ -181,7 +184,7 @@ 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);
@@ -209,25 +212,8 @@ 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);
void lvmcache_get_mdas(struct cmd_context *cmd,
const char *vgname, const char *vgid,
struct dm_list *mda_list);
const char *dev_filtered_reason(struct device *dev);
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

View File

@@ -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,

View File

@@ -1,19 +0,0 @@
#ifndef _CMD_ENUM_H
#define _CMD_ENUM_H
/*
* tools/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 "../tools/cmds.h"
#undef cmd
};
#endif

View File

@@ -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;
@@ -645,25 +596,14 @@ static int _process_config(struct cmd_context *cmd)
#endif
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",
@@ -720,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));
@@ -767,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;
@@ -1026,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);
@@ -1078,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);
@@ -1143,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;
}
@@ -1154,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;
}
@@ -1168,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");
@@ -1227,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;
@@ -1339,7 +1276,7 @@ int init_lvmcache_orphans(struct cmd_context *cmd)
struct format_type *fmt;
dm_list_iterate_items(fmt, &cmd->formats)
if (!lvmcache_add_orphan_vginfo(cmd, fmt->orphan_vg_name, fmt))
if (!lvmcache_add_orphan_vginfo(fmt->orphan_vg_name, fmt))
return_0;
return 1;
@@ -1425,10 +1362,8 @@ static int _init_segtypes(struct cmd_context *cmd)
return 0;
#endif
#ifdef INTEGRITY_INTERNAL
if (!init_integrity_segtypes(cmd, &seglib))
return 0;
#endif
return 1;
}
@@ -1548,7 +1483,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;
}
@@ -1596,6 +1530,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;
@@ -1645,6 +1580,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;
@@ -1655,7 +1592,6 @@ 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);
@@ -1778,8 +1714,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))
@@ -1984,8 +1918,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;
@@ -2033,17 +1965,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 */
@@ -2068,7 +2007,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
free(cmd->linebuffer);
}
#endif
destroy_config_context(cmd);
free(cmd);
lvmpolld_disconnect();

View File

@@ -18,7 +18,6 @@
#include "lib/device/dev-cache.h"
#include "lib/device/dev-type.h"
#include "lib/commands/cmd_enum.h"
#include <limits.h>
@@ -30,9 +29,7 @@ struct config_info {
int debug_classes;
int verbose;
int silent;
int suppress;
int test;
int yes;
int syslog;
int activation;
int suffix;
@@ -42,8 +39,7 @@ struct config_info {
int udev_rules;
int udev_sync;
int udev_fallback;
int issue_discards;
uint32_t journal;
int cache_vgmetadata;
const char *msg_prefix;
const char *fmt_name;
const char *dmeventd_executable;
@@ -95,7 +91,6 @@ struct cmd_context {
const char *name; /* needed before cmd->command is set */
struct command_name *cname;
struct command *command;
int command_enum; /* duplicate from command->command_enum for lib code */
char **argv;
struct arg_values *opt_arg_values;
struct dm_list arg_value_groups;
@@ -146,7 +141,6 @@ struct cmd_context {
unsigned degraded_activation:1;
unsigned auto_set_activation_skip:1;
unsigned si_unit_consistency:1;
unsigned report_strict_type_mode:1;
unsigned report_binary_values_as_numeric:1;
unsigned report_mark_hidden_devices:1;
unsigned metadata_read_only:1;
@@ -177,7 +171,7 @@ struct cmd_context {
unsigned activate_component:1; /* command activates component LV */
unsigned process_component_lvs:1; /* command processes also component LVs */
unsigned mirror_warn_printed:1; /* command already printed warning about non-monitored mirrors */
unsigned expect_missing_vg_device:1; /* when reading a vg it's expected that a dev for a pv isn't found */
unsigned pvscan_cache_single:1;
unsigned can_use_one_scan:1;
unsigned is_clvmd:1;
unsigned md_component_detection:1;
@@ -188,37 +182,13 @@ struct cmd_context {
unsigned pvscan_recreate_hints:1; /* enable special case hint handling for pvscan --cache */
unsigned scan_lvs:1;
unsigned wipe_outdated_pvs:1;
unsigned enable_devices_list:1; /* command is using --devices option */
unsigned enable_devices_file:1; /* command is using devices file */
unsigned pending_devices_file:1; /* command may create and enable devices file */
unsigned create_edit_devices_file:1; /* command expects to create and/or edit devices file */
unsigned edit_devices_file:1; /* command expects to edit devices file */
unsigned filter_deviceid_skip:1; /* don't use filter-deviceid */
unsigned filter_regex_with_devices_file:1; /* use filter-regex even when devices file is enabled */
unsigned filter_nodata_only:1; /* only use filters that do not require data from the dev */
unsigned run_by_dmeventd:1; /* command is being run by dmeventd */
unsigned sysinit:1; /* --sysinit is used */
unsigned ignorelockingfailure:1; /* --ignorelockingfailure is used */
unsigned check_devs_used:1; /* check devs used by LVs */
unsigned print_device_id_not_found:1; /* print devices file entries not found */
unsigned ignore_device_name_mismatch:1; /* skip updating devices file names */
unsigned backup_disabled:1; /* skip repeated debug message */
unsigned event_activation:1; /* whether event_activation is set */
unsigned udevoutput:1;
unsigned online_vg_file_removed:1;
unsigned disable_dm_devs:1; /* temporarily disable use of dm devs cache */
/*
* Devices and filtering.
*/
struct dev_filter *filter;
struct dm_list use_devices; /* struct dev_use for each entry in devices file */
struct dm_list hints;
const char *md_component_checks;
const char *search_for_devnames; /* config file setting */
const char *devicesfile; /* from --devicesfile option */
struct dm_list deviceslist; /* from --devices option, struct dm_str_list */
struct dm_list *cache_dm_devs; /* cache with UUIDs from DM_DEVICE_LIST (when available) */
/*
* Configuration.
@@ -250,7 +220,6 @@ struct cmd_context {
char system_dir[PATH_MAX];
char dev_dir[PATH_MAX];
char proc_dir[PATH_MAX];
char devices_file_path[PATH_MAX];
/*
* Reporting.

View File

@@ -501,15 +501,12 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
checksum_fn_t checksum_fn, uint32_t checksum,
int checksum_only, int no_dup_node_check)
{
char namebuf[NAME_LEN + 1] __attribute__((aligned(8)));
int namelen = 0;
int bad_name = 0;
char *fb, *fe;
int r = 0;
int sz, use_plain_read = 1;
int use_mmap = 1;
off_t mmap_offset = 0;
char *buf = NULL;
struct config_source *cs = dm_config_get_custom(cft);
size_t rsize;
if (!_is_file_based_config_source(cs->type)) {
log_error(INTERNAL_ERROR "config_file_read_fd: expected file, special file "
@@ -518,30 +515,26 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
return 0;
}
/* Only use plain read with regular files */
/* Only use mmap with regular files */
if (!(dev->flags & DEV_REGULAR) || size2)
use_plain_read = 0;
use_mmap = 0;
/* Ensure there is extra '\0' after end of buffer since we pass
* buffer to funtions like strtoll() */
if (!(buf = zalloc(size + size2 + 1))) {
log_error("Failed to allocate circular buffer.");
return 0;
}
if (use_plain_read) {
/* Note: also used for lvm.conf to read all settings */
for (rsize = 0; rsize < size; rsize += sz) {
do {
sz = read(dev_fd(dev), buf + rsize, size - rsize);
} while ((sz < 0) && ((errno == EINTR) || (errno == EAGAIN)));
if (sz < 0) {
log_sys_error("read", dev_name(dev));
goto out;
}
if (use_mmap) {
mmap_offset = offset % lvm_getpagesize();
/* memory map the file */
fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
if (fb == (caddr_t) (-1)) {
log_sys_error("mmap", dev_name(dev));
goto out;
}
fb = fb + mmap_offset;
} else {
if (!(buf = malloc(size + size2))) {
log_error("Failed to allocate circular buffer.");
return 0;
}
if (!dev_read_bytes(dev, offset, size, buf))
goto out;
@@ -549,25 +542,8 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
if (!dev_read_bytes(dev, offset2, size2, buf + size))
goto out;
}
}
fb = buf;
if (!(dev->flags & DEV_REGULAR)) {
memcpy(namebuf, buf, NAME_LEN);
while (namebuf[namelen] && !isspace(namebuf[namelen]) && namebuf[namelen] != '{' && namelen < (NAME_LEN - 1))
namelen++;
namebuf[namelen] = '\0';
/*
* Check that the text metadata begins with a valid name.
*/
if (!validate_name(namebuf)) {
log_warn("WARNING: Metadata location on %s at offset %llu begins with invalid name.",
dev_name(dev), (unsigned long long)offset);
bad_name = 1;
}
fb = buf;
}
/*
@@ -579,13 +555,10 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
if (checksum_fn && checksum !=
(checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)fb, size),
(const uint8_t *)(fb + size), size2))) {
log_warn("WARNING: Checksum error on %s at offset %llu.", dev_name(dev), (unsigned long long)offset);
log_error("%s: Checksum error at offset %" PRIu64, dev_name(dev), (uint64_t) offset);
goto out;
}
if (bad_name)
goto out;
if (!checksum_only) {
fe = fb + size + size2;
if (no_dup_node_check) {
@@ -600,7 +573,15 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
r = 1;
out:
free(buf);
if (!use_mmap)
free(buf);
else {
/* unmap the file */
if (munmap(fb - mmap_offset, size + mmap_offset)) {
log_sys_error("munmap", dev_name(dev));
r = 0;
}
}
return r;
}
@@ -735,7 +716,7 @@ static struct dm_config_value *_get_def_array_values(struct cmd_context *cmd,
return array;
}
if (!(token = enc_value = strdup(def_enc_value))) {
if (!(p = token = enc_value = strdup(def_enc_value))) {
log_error("_get_def_array_values: strdup failed");
return NULL;
}
@@ -934,7 +915,7 @@ static int _check_value_differs_from_default(struct cft_check_handle *handle,
} else {
str = v_def ? v_def->v.str
: cfg_def_get_default_value(handle->cmd, def, CFG_TYPE_STRING, NULL);
diff = str ? strcmp(str, v->v.str) : 0;
diff = strcmp(str, v->v.str);
}
break;
case DM_CFG_EMPTY_ARRAY:
@@ -1166,10 +1147,8 @@ int config_def_check(struct cft_check_handle *handle)
* sections and settings with full path as a key.
* If section name is variable, use '#' as a substitute.
*/
*vp = 0;
*rp = 0;
if (!handle->cmd->cft_def_hash) {
if (!(handle->cmd->cft_def_hash = dm_hash_create(500))) {
if (!(handle->cmd->cft_def_hash = dm_hash_create(64))) {
log_error("Failed to create configuration definition hash.");
r = 0; goto out;
}
@@ -1735,7 +1714,6 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
const char *node_type_name = cn->v ? "option" : "section";
char path[CFG_PATH_MAX_LEN];
char commentline[MAX_COMMENT_LINE+1];
int is_deprecated = 0;
if (cn->id <= 0)
return 1;
@@ -1749,14 +1727,13 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
cfg_def = cfg_def_get_item_p(cn->id);
is_deprecated = _def_node_is_deprecated(cfg_def, out->tree_spec);
if (out->tree_spec->withsummary || out->tree_spec->withcomments) {
_cfg_def_make_path(path, sizeof(path), cfg_def->id, cfg_def, 1);
fprintf(out->fp, "\n");
fprintf(out->fp, "%s# Configuration %s %s.\n", line, node_type_name, path);
if (out->tree_spec->withcomments && is_deprecated && cfg_def->deprecation_comment)
if (out->tree_spec->withcomments &&
_def_node_is_deprecated(cfg_def, out->tree_spec))
fprintf(out->fp, "%s# %s", line, cfg_def->deprecation_comment);
if (cfg_def->comment) {
@@ -1767,14 +1744,14 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
continue;
commentline[0] = '\0';
}
fprintf(out->fp, "%s#%s%s\n", line, commentline[0] ? " " : "", commentline);
fprintf(out->fp, "%s# %s\n", line, commentline);
/* withsummary prints only the first comment line. */
if (!out->tree_spec->withcomments)
break;
}
}
if (is_deprecated)
if (_def_node_is_deprecated(cfg_def, out->tree_spec))
fprintf(out->fp, "%s# This configuration %s is deprecated.\n", line, node_type_name);
if (cfg_def->flags & CFG_ADVANCED)
@@ -1802,7 +1779,7 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
return_0;
fprintf(out->fp, "%s# Available since version %s.\n", line, version);
if (is_deprecated) {
if (_def_node_is_deprecated(cfg_def, out->tree_spec)) {
if (!_get_config_node_version(cfg_def->deprecated_since_version, version))
return_0;
fprintf(out->fp, "%s# Deprecated since version %s.\n", line, version);
@@ -1830,9 +1807,8 @@ static int _out_line_fn(const struct dm_config_node *cn, const char *line, void
char summary[MAX_COMMENT_LINE+1];
char version[9];
int pos = 0;
int space_prefix_len = 0;
const char *p;
size_t len;
char *space_prefix;
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
@@ -1866,36 +1842,16 @@ static int _out_line_fn(const struct dm_config_node *cn, const char *line, void
/* Usual tree view with nodes and their values. */
if (out->tree_spec->valuesonly && !(cfg_def->type & CFG_TYPE_SECTION)) {
if ((space_prefix_len = strspn(line, "\t "))) {
len = strlen(line);
p = line + space_prefix_len;
/* copy space_prefix, skip key and '=', copy value */
if (!dm_pool_begin_object(out->mem, len))
return_0;
if (!dm_pool_grow_object(out->mem, line, space_prefix_len) ||
!dm_pool_grow_object(out->mem, p + strcspn(p, "=") + 1, len + 1)) {
dm_pool_abandon_object(out->mem);
return_0;
}
line = dm_pool_end_object(out->mem);
} else
line = strchr(line, '=') + 1;
}
if ((out->tree_spec->type != CFG_DEF_TREE_CURRENT) &&
(out->tree_spec->type != CFG_DEF_TREE_DIFF) &&
(out->tree_spec->type != CFG_DEF_TREE_FULL) &&
!out->tree_spec->valuesonly &&
(cfg_def->flags & (CFG_DEFAULT_UNDEFINED | CFG_DEFAULT_COMMENTED))) {
/* print with # at the front to comment out the line */
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn)) {
space_prefix_len = strspn(line, "\t ");
fprintf(out->fp, "%.*s%s%s\n", space_prefix_len, line, "# ",
line + space_prefix_len);
space_prefix = ((len = strspn(line, "\t "))) ? dm_pool_strndup(out->mem, line, len) : NULL;
fprintf(out->fp, "%s%s%s\n", space_prefix ? : "", "# ", line + len);
if (space_prefix)
dm_pool_free(out->mem, space_prefix);
}
return 1;
}
@@ -1904,9 +1860,6 @@ static int _out_line_fn(const struct dm_config_node *cn, const char *line, void
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn))
fprintf(out->fp, "%s\n", line);
if (out->tree_spec->valuesonly && !(cfg_def->type & CFG_TYPE_SECTION) && space_prefix_len)
dm_pool_free(out->mem, (char *) line);
return 1;
}

View File

@@ -176,7 +176,6 @@ struct config_def_tree_spec {
unsigned unconfigured:1; /* use unconfigured path strings */
unsigned withgeneralpreamble:1; /* include preamble for a general config file */
unsigned withlocalpreamble:1; /* include preamble for a local config file */
unsigned valuesonly:1; /* print only values without keys */
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
};

Some files were not shown because too many files have changed in this diff Show More