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

Compare commits

..

8 Commits

Author SHA1 Message Date
Bryn M. Reeves
0b553fdda7 libdm: allow resize of regions mapping growing extents
Instead of deleting and re-creating an extent that has increased
in length, use dm_stats_resize_region() to enlarge the region
in-place.
2017-02-10 17:09:24 +00:00
Bryn M. Reeves
95cd544477 libdm: add dm_stats_resize_region()
Add support for resizing statistics regions. This depends on the
(not yet upstream) @stats_resize message which allows a region to
be grown in-place without losing counter values.

FIXME: test for driver version once known.
2017-02-10 17:09:24 +00:00
Bryn M. Reeves
f0f2083e67 libdm: add dm_stats_driver_supports_resize() 2017-02-10 17:09:24 +00:00
Bryn M. Reeves
d47b56fa7a man: add FILE MAPPING section to dmstats.8.in
Add a section to explain file mapping, outside of the individual
command descriptions, and to describe the limitations of the
current update strategy.
2017-02-10 17:09:17 +00:00
Bryn M. Reeves
b8241dc6d3 man: add dmfilemapd options to dmstats.8.in
Add descriptions of --follow and --nomonitor, and the behaviour
of create and update_filemap when starting dmfilemapd.
2017-02-10 17:09:17 +00:00
Bryn M. Reeves
05acbfbb15 dmstats: start dmfilemapd when creating or updating file maps
Launch an instance of the filemap monitoring daemon when creating,
or updating, a file mapped group, unless the --nomonitor switch is
given.

Unless --foreground is given the daemon will detach from the
terminal and run in the background until it is signaled or the
daemon termination conditions are met.

The --follow={inode|path} switch is added to control the daemon
behaviour when files are moved, unlinked, or renamed while they
are being monitored.

The daemon runs with the same verbosity as the dmstats command
that starts it.
2017-02-10 17:09:17 +00:00
Bryn M. Reeves
03b4767893 man: add dmfilemapd.8 2017-02-10 17:09:17 +00:00
Bryn M. Reeves
75de6a52a7 daemons: add dmfilemapd
Add a daemon that can be launched to monitor a group of regions
corresponding to the extents of a file, and to update the regions as the
file's allocation changes.

The daemon is intended to be started from a library interface, but can
also be run from the command line:

  dmfilemapd <fd> <group_id> <path> <mode> [<foreground>[<log_level>]]

Where fd is a file descriptor open on the mapped file, group_id is the
group identifier of the mapped group and mode is either "inode" or
"path". E.g.:

  # dmfilemapd 3 0 vm.img inode 1 3 3<vm.img
  ...

If foreground is non-zero, the daemon will not fork to run in the
background. If verbose is non-zero, libdm and daemon log messages will
be printed.

It is possible for the group identifier to change when regions are
re-mapped: this occurs when the group leader is deleted (regroup=1 in
dm_stats_update_regions_from_fd()), and another region is created before
the daemon has a chance to recreate the leader region.

The operation is inherently racey since there is currently no way to
atomically move or resize a dm_stats region while retaining its
region_id.

Detect this condition and update the group_id value stored in the
filemap monitor.

A function is also provided in the the stats API to launch the filemap
monitoring daemon:

  int dm_stats_start_filemapd(int fd, uint64_t group_id, const char *path,
                              dm_filemapd_mode_t mode, unsigned foreground,
                              unsigned verbose);

This carries out the first fork and execs dmfilemapd with the arguments
specified.

A dm_filemapd_mode_t value is specified by the mode argument: either
DM_FILEMAPD_FOLLOW_INODE, or DM_FILEMAPD_FOLLOW_PATH. A helper function,
dm_filemapd_mode_from_string(), is provided to parse a string containing
a valid mode name into the appropriate dm_filemapd_mode_t value.
2017-02-10 17:09:17 +00:00
949 changed files with 33382 additions and 75339 deletions

51
.gitignore vendored
View File

@@ -1,7 +1,6 @@
*.5
*.7
*.8
*.8_gen
*.a
*.d
*.o
@@ -31,53 +30,3 @@ make.tmpl
/cscope.out
/tags
/tmp/
tools/man-generator
tools/man-generator.c
test/lib/lvchange
test/lib/lvconvert
test/lib/lvcreate
test/lib/lvdisplay
test/lib/lvextend
test/lib/lvmconfig
test/lib/lvmdiskscan
test/lib/lvmsadc
test/lib/lvmsar
test/lib/lvreduce
test/lib/lvremove
test/lib/lvrename
test/lib/lvresize
test/lib/lvs
test/lib/lvscan
test/lib/pvchange
test/lib/pvck
test/lib/pvcreate
test/lib/pvdisplay
test/lib/pvmove
test/lib/pvremove
test/lib/pvresize
test/lib/pvs
test/lib/pvscan
test/lib/vgcfgbackup
test/lib/vgcfgrestore
test/lib/vgchange
test/lib/vgck
test/lib/vgconvert
test/lib/vgcreate
test/lib/vgdisplay
test/lib/vgexport
test/lib/vgextend
test/lib/vgimport
test/lib/vgimportclone
test/lib/vgmerge
test/lib/vgmknodes
test/lib/vgreduce
test/lib/vgremove
test/lib/vgrename
test/lib/vgs
test/lib/vgscan
test/lib/vgsplit
test/unit/unit-test

View File

@@ -1,6 +1,6 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
SUBDIRS = conf daemons include lib libdaemon libdm man scripts device_mapper tools
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
ifeq ("@UDEV_RULES@", "yes")
SUBDIRS += udev
@@ -43,7 +43,8 @@ endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS = conf include man test scripts \
libdaemon lib tools daemons libdm \
udev po liblvm python device_mapper
udev po liblvm python \
unit-tests/datastruct unit-tests/mm unit-tests/regex
tools.distclean: test.distclean
endif
DISTCLEAN_DIRS += lcov_reports*
@@ -58,12 +59,7 @@ liblvm: lib
daemons: lib libdaemon tools
tools: lib libdaemon device-mapper
po: tools daemons
man: tools
all_man: tools
scripts: liblvm libdm
test: tools daemons
unit-test: lib
run-unit-test: unit-test
lib.device-mapper: include.device-mapper
libdm.device-mapper: include.device-mapper
@@ -99,10 +95,10 @@ endif
DISTCLEAN_TARGETS += cscope.out
CLEAN_DIRS += autom4te.cache
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit-test run-unit-test: test
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit: all
$(MAKE) -C test $(@)
conf.generate man.generate: tools
conf.generate: tools
# how to use parenthesis in makefiles
leftparen:=(
@@ -132,9 +128,8 @@ rpm: dist
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
generate: conf.generate man.generate
generate: conf.generate
$(MAKE) -C conf generate
$(MAKE) -C man generate
all_man:
$(MAKE) -C man all_man
@@ -148,7 +143,7 @@ install_system_dirs:
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR)
$(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache
install_initscripts:
install_initscripts:
$(MAKE) -C scripts install_initscripts
install_systemd_generators:
@@ -171,7 +166,6 @@ install_tmpfiles_configuration:
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
libdaemon/client.info libdaemon/server.info \
test/unit.info \
daemons/clvmd.info \
daemons/dmeventd.info \
daemons/lvmetad.info \
@@ -214,6 +208,31 @@ endif
endif
ifeq ("$(TESTING)", "yes")
# testing and report generation
RUBY=ruby1.9 -Ireport-generators/lib -Ireport-generators/test
.PHONY: unit-test ruby-test test-programs
# FIXME: put dependencies on libdm and liblvm
# FIXME: Should be handled by Makefiles in subdirs, not here at top level.
test-programs:
cd unit-tests/regex && $(MAKE)
cd unit-tests/datastruct && $(MAKE)
cd unit-tests/mm && $(MAKE)
unit-test: test-programs
$(RUBY) report-generators/unit_test.rb $(shell find . -name TESTS)
$(RUBY) report-generators/title_page.rb
memcheck: test-programs
$(RUBY) report-generators/memcheck.rb $(shell find . -name TESTS)
$(RUBY) report-generators/title_page.rb
ruby-test:
$(RUBY) report-generators/test/ts.rb
endif
ifneq ($(shell which ctags),)
.PHONY: tags
tags:

18
README
View File

@@ -6,17 +6,11 @@ Installation instructions are in INSTALL.
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:
https://sourceware.org/git/?p=lvm2.git
git clone git://sourceware.org/git/lvm2.git
mirrored to:
https://github.com/lvmteam/lvm2
git clone https://github.com/lvmteam/lvm2.git
git clone git@github.com:lvmteam/lvm2.git
http://git.fedorahosted.org/git/lvm2.git
git clone git://git.fedorahosted.org/git/lvm2.git
Mailing list for general discussion related to LVM2:
linux-lvm@redhat.com
@@ -34,14 +28,6 @@ and multipath-tools:
dm-devel@redhat.com
Subscribe from https://www.redhat.com/mailman/listinfo/dm-devel
Website:
https://sourceware.org/lvm2/
Report upstream bugs at:
https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper
or open issues at:
https://github.com/lvmteam/lvm2/issues
The source code repository used until 7th June 2012 is accessible here:
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2.

62
TESTING
View File

@@ -1,62 +0,0 @@
LVM2 Test Suite
===============
The codebase contains many tests in the test subdirectory.
Before running tests
--------------------
Keep in mind the testsuite MUST run under root user.
It is recommended not to use LVM on the test machine, especially when running
tests with udev (`make check_system`.)
You MUST disable (or mask) any LVM daemons:
- lvmetad
- dmeventd
- lvmpolld
- lvmdbusd
- lvmlockd
- clvmd
- cmirrord
For running cluster tests, we are using singlenode locking. Pass
`--with-clvmd=singlenode` to configure.
NOTE: This is useful only for testing, and should not be used in produciton
code.
To run D-Bus daemon tests, existing D-Bus session is required.
Running tests
-------------
As root run:
make check
To run only tests matching a string:
make check T=test
To skip tests matching a string:
make check S=test
There are other targets and many environment variables can be used to tweak the
testsuite - for full list and description run `make -C test help`.
Installing testsuite
--------------------
It is possible to install and run a testsuite against installed LVM. Run the
following:
make -C test install
Then lvm2-testsuite binary can be executed to test installed binaries.
See `lvm2-testsuite --help` for options. The same environment variables can be
used as with `make check`.

View File

@@ -1 +1 @@
2.02.178(2)-git (2017-12-18)
2.02.169(2)-git (2016-11-30)

View File

@@ -1 +1 @@
1.02.147-git (2017-12-18)
1.02.138-git (2016-11-30)

294
WHATS_NEW
View File

@@ -1,295 +1,7 @@
Version 2.02.178 -
Version 2.02.169 -
=====================================
Remove lvm1 and pool format handling and add filter to ignore them.
Move some filter checks to after disks are read.
Rework disk scanning and when it is used.
Add new io layer and shift code to using it.
lvconvert: don't return success on degraded -m raid1 conversion
--enable-testing switch for ./configure has been removed.
--with-snapshots switch for ./configure has been removed.
--with-mirrors switch for ./configure has been removed.
--with-raid switch for ./configure has been removed.
--with-thin switch for ./configure has been removed.
--with-cache switch for ./configure has been removed.
Extend validation of region_size for mirror segment.
Reload whole device stack when reinitilizing mirror log.
Mirrors without monitoring are WARNING and not blocking on error.
Detect too big region_size with clustered mirrors.
Fix evaluation of maximal region size for mirror log.
Enhance mirror log size estimation and use smaller size when possible.
Fix incorrect mirror log size calculation on 32bit arch.
Enhnace preloading tree creating.
Fix regression on acceptance of any LV on lvconvert.
Restore usability of thin LV to be again external origin for another thin.
Keep systemd vars on change event in 69-dm-lvm-metad.rules for systemd reload.
Write systemd and non-systemd rule in 69-dm-lvm-metad.rules, GOTO active one.
Add test for activation/volume_list (Sub)LV remnants.
Disallow usage of cache format 2 with mq cache policy.
Again accept striped LV as COW LV with lvconvert -s (2.02.169).
Fix raid target version testing for supported features.
Allow activation of pools when thin/cache_check tool is missing.
Remove RaidLV on creation failure when rmeta devices can't be activated.
Add prioritized_section() to restore cookie boundaries (2.02.177).
Enhance error messages when read error happens.
Enhance mirror log initialization for old mirror target.
Skip private crypto and stratis devices.
Skip frozen raid devices from scanning.
Activate RAID SubLVs on read_only_volume_list readwrite
Offer convenience type raid5_n converting to raid10
Automatically avoid reading invalid snapshots during device scan.
Ensure COW device is writable even for read-only thick snapshots.
Support activation of component LVs in read-only mode.
Extend internal library to recognize and work with component LV.
Skip duplicate check for active LV when prompting for its removal.
Activate correct lock holding LV when it is cached.
Do not modify archived metadata when removing striped raid.
Fix memleak on error path when obtaining lv_raid_data_offset.
Fix compatibility size test of extended external origin.
Add external_origin visiting in for_each_sub_lv().
Ensure cluster commands drop their device cache before locking VG.
Do not report LV as remotely active when it's locally exclusive in cluster.
Add deprecate messages for usage of mirrors with mirrorlog.
Separate reporting of monitoring status and error status.
Improve validation of created strings in vgimportclone.
Add missing initialisation of mem pool in systemd generator.
Do not reopen output streams for multithreaded users of liblvm.
Use versionsort to fix archive file expiry beyond 100000 files.
Add devices/use_aio, aio_max, aio_memory to configure AIO limits.
Support asynchronous I/O when scanning devices.
Detect asynchronous I/O capability in configure or accept --disable-aio.
Add AIO_SUPPORTED_CODE_PATH to indicate whether AIO may be used.
Configure ensures /usr/bin dir is checked for dmpd tools.
Restore pvmove support for wide-clustered active volumes (2.02.177).
Avoid non-exclusive activation of exclusive segment types.
Fix trimming sibling PVs when doing a pvmove of raid subLVs.
Preserve exclusive activation during thin snaphost merge.
Suppress some repeated reads of the same disk data at the device layer.
Avoid exceeding array bounds in allocation tag processing.
Refactor metadata reading code to use callback functions.
Move memory allocation for the key dev_reads into the device layer.
Version 2.02.177 - 18th December 2017
=====================================
When writing text metadata content, use complete 4096 byte blocks.
Change text format metadata alignment from 512 to 4096 bytes.
When writing metadata, consistently skip mdas marked as failed.
Refactor and adjust text format metadata alignment calculation.
Fix python3 path in lvmdbusd to use value detected by configure.
Reduce checks for active LVs in vgchange before background polling.
Ensure _node_send_message always uses clean status of thin pool.
Fix lvmlockd to use pool lock when accessing _tmeta volume.
Report expected sanlock_convert errors only when retries fail.
Avoid blocking in sanlock_convert on SH to EX lock conversion.
Deactivate missing raid LV legs (_rimage_X-missing_Y_Z) on decativation.
Skip read-modify-write when entire block is replaced.
Categorise I/O with reason annotations in debug messages.
Allow extending of raid LVs created with --nosync after a failed repair.
Command will lock memory only when suspending volumes.
Merge segments when pvmove is finished.
Remove label_verify that has never been used.
Ensure very large numbers used as arguments are not casted to lower values.
Enhance reading and validation of options stripes and stripes_size.
Fix printing of default stripe size when user is not using stripes.
Activation code for pvmove automatically discovers holding LVs for resume.
Make a pvmove LV locking holder.
Do not change critical section counter on resume path without real resume.
Enhance activation code to automatically suspend pvmove participants.
Prevent conversion of thin volumes to snapshot origin when lvmlockd is used.
Correct the steps to change lock type in lvmlockd man page.
Retry lock acquisition on recognized sanlock errors.
Fix lock manager error codes in lvmlockd.
Remove unnecessary single read from lvmdiskscan.
Check raid reshape flags in vg_validate().
Add support for pvmove of cache and snapshot origins.
Avoid using precommitted metadata for suspending pvmove tree.
Ehnance pvmove locking.
Deactivate activated LVs on error path when pvmove activation fails.
Add "io" to log/debug_classes for logging low-level I/O.
Eliminate redundant nested VG metadata in VG struct.
Avoid importing persistent filter in vgscan/pvscan/vgrename.
Fix memleak of string buffer when vgcfgbackup runs in secure mode.
Do not print error when clvmd cannot find running clvmd.
Prevent start of new merge of snapshot if origin is already being merged.
Fix offered type for raid6_n_6 to raid5 conversion (raid5_n).
Deactivate sub LVs when removing unused cache-pool.
Do not take backup with suspended devices.
Avoid RAID4 activation on incompatible kernels under all circumstances.
Reject conversion request to striped/raid0 on 2-legged raid4/5.
Version 2.02.176 - 3rd November 2017
====================================
Keep Install section only in lvm2-{lvmetad,lvmpolld}.socket systemd unit.
Fix segfault in lvm_pv_remove in liblvm. (2.02.173)
Do not allow storing VG metadata with LV without any segment.
Fix printed message when thin snapshot was already merged.
Remove created spare LV when creation of thin-pool failed.
Avoid reading ignored metadata when mda gets used again.
Fix detection of moved PVs in vgsplit. (2.02.175)
Ignore --stripes/--stripesize on RAID takeover
Improve used paths for generated systemd units and init shells.
Disallow creation of snapshot of mirror/raid subLV (was never supported).
Fix regression in more advanced vgname extraction in lvconvert (2.02.169).
Allow lvcreate to be used for caching of _tdata LV.
Avoid internal error when resizing cache type _tdata LV (not yet supported).
Show original converted names when lvconverting LV to pool volume.
Move lib code used only by liblvm into metadata-liblvm.c.
Distinguish between device not found and excluded by filter.
Monitor external origin LVs.
Remove the replicator code, including configure --with-replicators.
Allow lvcreate --type mirror to work with 100%FREE.
Improve selection of resource name for complex volume activation lock.
Avoid cutting first character of resource name for activation lock.
Support for encrypted devices in fsadm.
Improve thin pool overprovisioning and repair warning messages.
Fix incorrect adjustment of region size on striped RaidLVs.
Version 2.02.175 - 6th October 2017
===================================
Use --help with blockdev when checking for --getsize64 support in fsadm.
Dump lvmdbusd debug information with SIGUSR1.
Fix metadata corruption in vgsplit and vgmerge intermediate states.
Add PV_MOVED_VG PV status flag to mark PVs moving between VGs.
Fix lvmdbus hang and recognise unknown VG correctly.
Improve error messages when command rules fail.
Require LV name with pvmove in a shared VG.
Allow shared active mirror LVs with lvmlockd, dlm, and cmirrord.
Support lvconvert --repair with cache and cachepool volumes.
lvconvert --repair respects --poolmetadataspare option.
Mark that we don't plan to develop liblvm2app and python bindings any further.
Fix thin pool creation in shared VG. (2.02.173)
Version 2.02.174 - 13th September 2017
======================================
Prevent raid1 split with trackchanges in a shared VG.
Avoid double unlocking of client & lockspace mutexes in lvmlockd.
Fix leaking of file descriptor for non-blocking filebased locking.
Fix check for 2nd mda at end of disk fits if using pvcreate --restorefile.
Use maximum metadataarea size that fits with pvcreate --restorefile.
Always clear cached bootloaderarea when wiping label e.g. in pvcreate.
Disallow --bootloaderareasize with pvcreate --restorefile.
Fix lvmlockd check for running lock managers during lock adoption.
Add --withgeneralpreamble and --withlocalpreamble to lvmconfig.
Improve makefiles' linking.
Fix some paths in generated makefiles to respected configured settings.
Add warning when creating thin-pool with zeroing and chunk size >= 512KiB.
Introduce exit code 4 EINIT_FAILED to replace -1 when initialisation fails.
Add synchronization points with udev during reshape of raid LVs.
Version 2.02.173 - 20th July 2017
=================================
Add synchronization points with udev during conversion of raid LVs.
Improve --size args validation and report more detailed error message.
Initialize debugging mutex before any debug message in clvmd.
Log error instead of warn when noticing connection problem with lvmetad.
Fix memory leak in lvmetad when working with duplicates.
Remove restrictions on reshaping open and clustered raid devices.
Add incompatible data_offset to raid metadata to fix reshape activation.
Accept 'lvm -h' and 'lvm --help' as well as 'lvm help' for help.
Suppress error message from accept() on clean lvmetad shutdown.
Tidy clvmd client list processing and fix segfaults.
Protect clvmd debug log messages with mutex and add client id.
Fix shellcheck reported issues for script files.
Version 2.02.172 - 28th June 2017
=================================
Add missing NULL to argv array when spliting cmdline arguments.
Add display_percent helper function for printing percent values.
lvconvert --repair handles failing raid legs (present but marked 'D'ead).
Do not lvdisplay --maps unset settings of cache pool.
Fix lvdisplay --maps for cache pool without policy settings.
Support aborting of flushing cache LV.
Reenable conversion of data and metadata thin-pool volumes to raid.
Improve raid status reporting with lvs.
No longer necessary to '--force' a repair for RAID1.
Linear to RAID1 upconverts now use "recover" sync action, not "resync".
Improve lvcreate --cachepool arg validation.
Limit maximum size of thin-pool for specific chunk size.
Print a warning about in-use PVs with no VG using them.
Disable automatic clearing of PVs that look like in-use orphans.
Cache format2 flag is now using segment name type field.
Support storing status flags via segtype name field.
Stop using '--yes' mode when fsadm runs without terminal.
Extend validation of filesystems resized by fsadm.
Enhance lvconvert automatic settings of possible (raid) LV types.
Allow lvchange to change properties on a thin pool data sub LV.
Fix lvcreate extent percentage calculation for mirrors.
Don't reinstate still-missing devices when correcting inconsistent metadata.
Properly handle subshell return codes in fsadm.
Disallow cachepool creation with policy cleaner and mode writeback.
Version 2.02.171 - 3rd May 2017
===============================
Fix memory warnings by using mempools for command definition processing.
Fix running commands from a script file.
Add pvcreate prompt when device size doesn't match setphysicalvolumesize.
lvconvert - preserve region size on raid1 image count changes
Adjust pvresize/pvcreate messages and prompt if underlying dev size differs.
raid - sanely handle insufficient space on takeover.
Fix configure --enable-notify-dbus status message.
Change configure option name prefix from --enable-lockd to --enable-lvmlockd.
lvcreate - raise mirror/raid default regionsize to 2MiB
Add missing configurable prefix to configuration file installation directory.
Version 2.02.170 - 13th April 2017
==================================
Introduce global/fsadm_executable to make fsadm path configurable.
Look for limited thin pool metadata size when using 16G metadata.
Add lvconvert pool creation rule disallowing options with poolmetadata.
Fix lvconvert when the same LV is incorrectly reused in options.
Fix lvconvert VG name validation in option values.
Fix missing lvmlockd LV locks in lvchange and lvconvert.
Fix dmeventd setup for lvchange --poll.
Fix use of --poll and --monitor with lvchange and vgchange.
Disallow lvconvert of hidden LV to a pool.
Ignore --partial option when not used for activation.
Allow --activationmode option with lvchange --refresh.
Better message on lvconvert --regionsize
Allow valid lvconvert --regionsize change
Add raid10 alias raid10_near
Handle insufficient PVs on lvconvert takeover
Fix SIGINT blocking to prevent corrupted metadata
Fix systemd unit existence check for lvmconf --services --startstopservices.
Check and use PATH_MAX buffers when creating vgrename device paths.
Version 2.02.169 - 28th March 2017
==================================
Automatically decide whether '-' in a man page is a hyphen or a minus sign.
Add build-time configuration command line to 'lvm version' output.
Handle known table line parameter order change in specific raid target vsns.
Conditionally reject raid convert to striped/raid0* after reshape.
Ensure raid6 upconversion restrictions.
Adjust mirror & raid dmeventd plugins for new lvconvert --repair behaviour.
Disable lvmetad when lvconvert --repair is run.
Remove obsolete lvmchange binary - convert to built-in command.
Show more information for cached volumes in lvdisplay [-m].
Add option for lvcreate/lvconvert --cachemetadataformat auto|1|2.
Support cache segment with configurable metadata format.
Add allocation/cache_metadata_format profilable settings.
Use function cache_set_params() for both lvcreate and lvconvert.
Skip rounding on cache chunk size boudary when create cache LV.
Improve cache_set_params support for chunk_size selection.
Fix metadata profile allocation/cache_[mode|policy] setting.
Fix missing support for using allocation/cache_pool_chunk_size setting.
Upstream git moved to https://sourceware.org/git/?p=lvm2
Support conversion of raid type, stripesize and number of disks
Reject writemostly/writebehind in lvchange during resynchronization.
Deactivate active origin first before removal for improved workflow.
Fix regression of accepting both --type and -m with lvresize. (2.02.158)
Add lvconvert --swapmetadata, new specific way to swap pool metadata LVs.
Add lvconvert --startpoll, new specific way to start polling conversions.
Add lvconvert --mergethin, new specific way to merge thin snapshots.
Add lvconvert --mergemirrors, new specific way to merge split mirrors.
Add lvconvert --mergesnapshot, new specific way to combine cow LVs.
Split up lvconvert code based on command definitions.
Split up lvchange code based on command definitions.
Generate help output and man pages from command definitions.
Verify all command line items against command definition.
Match every command run to one command definition.
Specify every allowed command definition/syntax in command-lines.in.
Add extra memory page when limiting pthread stack size in clvmd.
Support striped/raid0* <-> raid10_near conversions.
Support shrinking of RaidLVs.
Support region size changes on existing RaidLVs.
Support shrinking of RaidLvs
Support region size changes on existing RaidLVs
Avoid parallel usage of cpg_mcast_joined() in clvmd with corosync.
Support raid6_{ls,rs,la,ra}_6 segment types and conversions from/to it.
Support raid6_n_6 segment type and conversions from/to it.

View File

@@ -1,94 +1,16 @@
Version 1.02.147 -
Version 1.02.138 -
=====================================
Reuse uname() result for mirror target.
Recognize also mounted btrfs through dm_device_has_mounted_fs().
Add missing log_error() into dm_stats_populate() returning 0.
Avoid calling dm_stats_populat() for DM devices without any stats regions.
Support DM_DEBUG_WITH_LINE_NUMBERS envvar for debug msg with source:line.
Configured command for thin pool threshold handling gets whole environment.
Fix tests for failing dm_snprintf() in stats code.
Parsing mirror status accepts 'userspace' keyword in status.
Introduce dm_malloc_aligned for page alignment of buffers.
Version 1.02.146 - 18th December 2017
=====================================
Activation tree of thin pool skips duplicated check of pool status.
Remove code supporting replicator target.
Do not ignore failure of _info_by_dev().
Propagate delayed resume for pvmove subvolumes.
Suppress integrity encryption keys in 'table' output unless --showkeys supplied.
Version 1.02.145 - 3rd November 2017
====================================
Keep Install section only in dm-event.socket systemd unit.
Issue a specific error with dmsetup status if device is unknown.
Fix RT_LIBS reference in generated libdevmapper.pc for pkg-config
Version 1.02.144 - 6th October 2017
===================================
Schedule exit when received SIGTERM in dmeventd.
Also try to unmount /boot on blkdeactivate -u if on top of supported device.
Use blkdeactivate -r wait in blk-availability systemd service/initscript.
Add blkdeactivate -r wait option to wait for MD resync/recovery/reshape.
Fix blkdeactivate regression with failing DM/MD devs deactivation (1.02.142).
Fix typo in blkdeactivate's '--{dm,lvm,mpath}options' option name.
Correct return value testing when get reserved values for reporting.
Take -S with dmsetup suspend/resume/clear/wipe_table/remove/deps/status/table.
Version 1.02.143 - 13th September 2017
======================================
Restore umask when creation of node fails.
Add --concise to dmsetup create for many devices with tables in one command.
Accept minor number without major in library when it knows dm major number.
Introduce single-line concise table output format: dmsetup table --concise
Version 1.02.142 - 20th July 2017
=================================
Create /dev/disk/by-part{uuid,label} and gpt-auto-root symlinks with udev.
Version 1.02.141 - 28th June 2017
=================================
Fix reusing of dm_task structure for status reading (used by dmeventd).
Add dm_percent_to_round_float for adjusted percentage rounding.
Reset array with dead rimage devices once raid gets in sync.
Drop unneeded --config option from raid dmeventd plugin.
dm_get_status_raid() handle better some incosistent md statuses.
Accept truncated files in calls to dm_stats_update_regions_from_fd().
Restore Warning by 5% increment when thin-pool is over 80% (1.02.138).
Version 1.02.140 - 3rd May 2017
===============================
Add missing configure --enable-dmfilemapd status message and fix --disable.
Version 1.02.139 - 13th April 2017
==================================
Fix assignment in _target_version() when dm task can't run.
Flush stdout on each iteration when using --count or --interval.
Show detailed error message when execvp fails while starting dmfilemapd.
Fix segmentation fault when dmfilemapd is run with no arguments.
Numerous minor dmfilemapd fixes from coverity.
Version 1.02.138 - 28th March 2017
==================================
Support additional raid5/6 configurations.
Provide dm_tree_node_add_cache_target@base compatible symbol.
Support DM_CACHE_FEATURE_METADATA2, new cache metadata format 2.
Improve code to handle mode mask for cache nodes.
Cache status check for passthrough also require trailing space.
Add extra memory page when limiting pthread stack size in dmeventd.
Avoids immediate resume when preloaded device is smaller.
Do not suppress kernel key description in dmsetup table output for dm-crypt.
Support configurable command executed from dmeventd thin plugin.
Support new R|r human readable units output format.
Thin dmeventd plugin reacts faster on lvextend failure path with umount.
Add dm_stats_bind_from_fd() to bind a stats handle from a file descriptor.
Do not try call callback when reverting activation on error path.
Fix file mapping for extents with physically adjacent extents in dmstats.
Fix file mapping for extents with physically adjacent extents.
Validation vsnprintf result in runtime translate of dm_log (1.02.136).
Separate filemap extent allocation from region table in dmstats.
Fix segmentation fault when filemap region creation fails in dmstats.
Fix performance of region cleanup for failed filemap creation in dmstats.
Fix very slow region deletion with many regions in dmstats.
Separate filemap extent allocation from region table.
Fix segmentation fault when filemap region creation fails.
Fix performance of region cleanup for failed filemap creation.
Fix very slow region deletion with many regions.
Version 1.02.137 - 30th November 2016
=====================================

View File

@@ -155,7 +155,7 @@ AC_DEFUN([AC_TRY_LDFLAGS],
# and this notice are preserved. This file is offered as-is, without any
# warranty.
serial 3
#serial 3
AC_DEFUN([AX_GCC_BUILTIN], [
AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1])

210
aclocal.m4 vendored
View File

@@ -69,63 +69,32 @@ AC_DEFUN([AX_PYTHON_MODULE],[
fi
])
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
dnl serial 11 (pkg-config-0.29)
dnl
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
dnl
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 2 of the License, or
dnl (at your option) any later version.
dnl
dnl This program is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dnl General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
dnl 02111-1307, USA.
dnl
dnl As a special exception to the GNU General Public License, if you
dnl distribute this file as part of a program that contains a
dnl configuration script generated by Autoconf, you may include it under
dnl the same distribution terms that you use for the rest of that
dnl program.
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 1 (pkg-config-0.24)
#
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
dnl PKG_PREREQ(MIN-VERSION)
dnl -----------------------
dnl Since: 0.29
dnl
dnl Verify that the version of the pkg-config macros are at least
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
dnl installed version of pkg-config, this checks the developer's version
dnl of pkg.m4 when generating configure.
dnl
dnl To ensure that this macro is defined, also add:
dnl m4_ifndef([PKG_PREREQ],
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
dnl
dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require.
m4_defun([PKG_PREREQ],
[m4_define([PKG_MACROS_VERSION], [0.29])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
dnl ----------------------------------
dnl Since: 0.16
dnl
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
dnl first found in the path. Checks that the version of pkg-config found
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
dnl used since that's the first version where most current features of
dnl pkg-config existed.
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
# ----------------------------------
AC_DEFUN([PKG_PROG_PKG_CONFIG],
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
@@ -147,19 +116,18 @@ if test -n "$PKG_CONFIG"; then
PKG_CONFIG=""
fi
fi[]dnl
])dnl PKG_PROG_PKG_CONFIG
])# PKG_PROG_PKG_CONFIG
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl -------------------------------------------------------------------
dnl Since: 0.18
dnl
dnl Check to see whether a particular set of modules exists. Similar to
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
dnl
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
dnl only at the first occurence in configure.ac, so if the first place
dnl it's called might be skipped (such as if it is within an "if", you
dnl have to call PKG_CHECK_EXISTS manually
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# Check to see whether a particular set of modules exists. Similar
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
#
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
# only at the first occurence in configure.ac, so if the first place
# it's called might be skipped (such as if it is within an "if", you
# have to call PKG_CHECK_EXISTS manually
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_EXISTS],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
if test -n "$PKG_CONFIG" && \
@@ -169,10 +137,8 @@ m4_ifvaln([$3], [else
$3])dnl
fi])
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
dnl ---------------------------------------------
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
dnl pkg_failed based on the result.
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
# ---------------------------------------------
m4_define([_PKG_CONFIG],
[if test -n "$$1"; then
pkg_cv_[]$1="$$1"
@@ -184,11 +150,10 @@ m4_define([_PKG_CONFIG],
else
pkg_failed=untried
fi[]dnl
])dnl _PKG_CONFIG
])# _PKG_CONFIG
dnl _PKG_SHORT_ERRORS_SUPPORTED
dnl ---------------------------
dnl Internal check to see if pkg-config supports short errors.
# _PKG_SHORT_ERRORS_SUPPORTED
# -----------------------------
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -196,17 +161,19 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
else
_pkg_short_errors_supported=no
fi[]dnl
])dnl _PKG_SHORT_ERRORS_SUPPORTED
])# _PKG_SHORT_ERRORS_SUPPORTED
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
dnl [ACTION-IF-NOT-FOUND])
dnl --------------------------------------------------------------
dnl Since: 0.4.0
dnl
dnl Note that if there is a possibility the first call to
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
# [ACTION-IF-NOT-FOUND])
#
#
# Note that if there is a possibility the first call to
# PKG_CHECK_MODULES might not happen, you should be sure to include an
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
#
#
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_MODULES],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
@@ -260,40 +227,16 @@ else
AC_MSG_RESULT([yes])
$3
fi[]dnl
])dnl PKG_CHECK_MODULES
])# PKG_CHECK_MODULES
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
dnl [ACTION-IF-NOT-FOUND])
dnl ---------------------------------------------------------------------
dnl Since: 0.29
dnl
dnl Checks for existence of MODULES and gathers its build flags with
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
dnl and VARIABLE-PREFIX_LIBS from --libs.
dnl
dnl Note that if there is a possibility the first call to
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
dnl configure.ac.
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
_save_PKG_CONFIG=$PKG_CONFIG
PKG_CONFIG="$PKG_CONFIG --static"
PKG_CHECK_MODULES($@)
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
])dnl PKG_CHECK_MODULES_STATIC
dnl PKG_INSTALLDIR([DIRECTORY])
dnl -------------------------
dnl Since: 0.27
dnl
dnl Substitutes the variable pkgconfigdir as the location where a module
dnl should install pkg-config .pc files. By default the directory is
dnl $libdir/pkgconfig, but the default can be changed by passing
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
dnl parameter.
# PKG_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable pkgconfigdir as the location where a module
# should install pkg-config .pc files. By default the directory is
# $libdir/pkgconfig, but the default can be changed by passing
# DIRECTORY. The user can override through the --with-pkgconfigdir
# parameter.
AC_DEFUN([PKG_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
m4_pushdef([pkg_description],
@@ -304,18 +247,16 @@ AC_ARG_WITH([pkgconfigdir],
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
])dnl PKG_INSTALLDIR
]) dnl PKG_INSTALLDIR
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
dnl --------------------------------
dnl Since: 0.27
dnl
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
dnl module should install arch-independent pkg-config .pc files. By
dnl default the directory is $datadir/pkgconfig, but the default can be
dnl changed by passing DIRECTORY. The user can override through the
dnl --with-noarch-pkgconfigdir parameter.
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable noarch_pkgconfigdir as the location where a
# module should install arch-independent pkg-config .pc files. By
# default the directory is $datadir/pkgconfig, but the default can be
# changed by passing DIRECTORY. The user can override through the
# --with-noarch-pkgconfigdir parameter.
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
m4_pushdef([pkg_description],
@@ -326,15 +267,13 @@ AC_ARG_WITH([noarch-pkgconfigdir],
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
])dnl PKG_NOARCH_INSTALLDIR
]) dnl PKG_NOARCH_INSTALLDIR
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl -------------------------------------------
dnl Since: 0.28
dnl
dnl Retrieves the value of the pkg-config variable for the given module.
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# -------------------------------------------
# Retrieves the value of the pkg-config variable for the given module.
AC_DEFUN([PKG_CHECK_VAR],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
@@ -343,7 +282,7 @@ _PKG_CONFIG([$1], [variable="][$3]["], [$2])
AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])dnl PKG_CHECK_VAR
])# PKG_CHECK_VAR
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
#
@@ -597,4 +536,5 @@ AC_DEFUN([AM_RUN_LOG],
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
(exit $ac_status); }])
m4_include([acinclude.m4])

View File

@@ -1,570 +0,0 @@
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
//
// This file is part of LVM2.
//
// This copyrighted material is made available to anyone wishing to use,
// modify, copy, or redistribute it subject to the terms and conditions
// of the GNU Lesser General Public License v.2.1.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "radix-tree.h"
#include "base/memory/container_of.h"
#include "base/memory/zalloc.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
//----------------------------------------------------------------
enum node_type {
UNSET = 0,
VALUE,
VALUE_CHAIN,
PREFIX_CHAIN,
NODE4,
NODE16,
NODE48,
NODE256
};
struct value {
enum node_type type;
union radix_value value;
};
// This is used for entries that have a key which is a prefix of another key.
struct value_chain {
union radix_value value;
struct value child;
};
struct prefix_chain {
struct value child;
unsigned len;
uint8_t prefix[0];
};
struct node4 {
uint32_t nr_entries;
uint8_t keys[4];
struct value values[4];
};
struct node16 {
uint32_t nr_entries;
uint8_t keys[16];
struct value values[16];
};
struct node48 {
uint32_t nr_entries;
uint8_t keys[256];
struct value values[48];
};
struct node256 {
struct value values[256];
};
struct radix_tree {
unsigned nr_entries;
struct value root;
};
//----------------------------------------------------------------
struct radix_tree *radix_tree_create(void)
{
struct radix_tree *rt = malloc(sizeof(*rt));
if (rt) {
rt->nr_entries = 0;
rt->root.type = UNSET;
}
return rt;
}
static void _free_node(struct value v, radix_value_dtr dtr, void *context)
{
unsigned i;
struct value_chain *vc;
struct prefix_chain *pc;
struct node4 *n4;
struct node16 *n16;
struct node48 *n48;
struct node256 *n256;
switch (v.type) {
case UNSET:
break;
case VALUE:
if (dtr)
dtr(context, v.value);
break;
case VALUE_CHAIN:
vc = v.value.ptr;
if (dtr)
dtr(context, vc->value);
_free_node(vc->child, dtr, context);
free(vc);
break;
case PREFIX_CHAIN:
pc = v.value.ptr;
_free_node(pc->child, dtr, context);
free(pc);
break;
case NODE4:
n4 = (struct node4 *) v.value.ptr;
for (i = 0; i < n4->nr_entries; i++)
_free_node(n4->values[i], dtr, context);
free(n4);
break;
case NODE16:
n16 = (struct node16 *) v.value.ptr;
for (i = 0; i < n16->nr_entries; i++)
_free_node(n16->values[i], dtr, context);
free(n16);
break;
case NODE48:
n48 = (struct node48 *) v.value.ptr;
for (i = 0; i < n48->nr_entries; i++)
_free_node(n48->values[i], dtr, context);
free(n48);
break;
case NODE256:
n256 = (struct node256 *) v.value.ptr;
for (i = 0; i < 256; i++)
_free_node(n256->values[i], dtr, context);
free(n256);
break;
}
}
void radix_tree_destroy(struct radix_tree *rt, radix_value_dtr dtr, void *context)
{
_free_node(rt->root, dtr, context);
free(rt);
}
static bool _insert(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv);
static bool _insert_unset(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
unsigned len = ke - kb;
if (!len) {
// value
v->type = VALUE;
v->value = rv;
} else {
// prefix -> value
struct prefix_chain *pc = zalloc(sizeof(*pc) + len);
if (!pc)
return false;
pc->child.type = VALUE;
pc->child.value = rv;
pc->len = len;
memcpy(pc->prefix, kb, len);
v->type = PREFIX_CHAIN;
v->value.ptr = pc;
}
return true;
}
static bool _insert_value(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
unsigned len = ke - kb;
if (!len)
// overwrite
v->value = rv;
else {
// value_chain -> value
struct value_chain *vc = zalloc(sizeof(*vc));
if (!vc)
return false;
vc->value = v->value;
if (!_insert(&vc->child, kb, ke, rv)) {
free(vc);
return false;
}
v->type = VALUE_CHAIN;
v->value.ptr = vc;
}
return true;
}
static bool _insert_value_chain(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct value_chain *vc = v->value.ptr;
return _insert(&vc->child, kb, ke, rv);
}
static unsigned min(unsigned lhs, unsigned rhs)
{
if (lhs <= rhs)
return lhs;
else
return rhs;
}
static bool _insert_prefix_chain(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct prefix_chain *pc = v->value.ptr;
if (*kb == pc->prefix[0]) {
// There's a common prefix let's split the chain into two and
// recurse.
struct prefix_chain *pc2;
unsigned i, len = min(pc->len, ke - kb);
for (i = 0; i < len; i++)
if (kb[i] != pc->prefix[i])
break;
pc2 = zalloc(sizeof(*pc2) + pc->len - i);
pc2->len = pc->len - i;
memmove(pc2->prefix, pc->prefix + i, pc2->len);
pc2->child = pc->child;
// FIXME: this trashes pc so we can't back out
pc->child.type = PREFIX_CHAIN;
pc->child.value.ptr = pc2;
pc->len = i;
if (!_insert(&pc->child, kb + i, ke, rv)) {
free(pc2);
return false;
}
} else {
// Stick an n4 in front.
struct node4 *n4 = zalloc(sizeof(*n4));
if (!n4)
return false;
n4->keys[0] = *kb;
if (!_insert(n4->values, kb + 1, ke, rv)) {
free(n4);
return false;
}
if (pc->len) {
n4->keys[1] = pc->prefix[0];
if (pc->len == 1) {
n4->values[1] = pc->child;
free(pc);
} else {
memmove(pc->prefix, pc->prefix + 1, pc->len - 1);
pc->len--;
n4->values[1] = *v;
}
n4->nr_entries = 2;
} else
n4->nr_entries = 1;
v->type = NODE4;
v->value.ptr = n4;
}
return true;
}
static bool _insert_node4(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct node4 *n4 = v->value.ptr;
if (n4->nr_entries == 4) {
struct node16 *n16 = zalloc(sizeof(*n16));
if (!n16)
return false;
n16->nr_entries = 5;
memcpy(n16->keys, n4->keys, sizeof(n4->keys));
memcpy(n16->values, n4->values, sizeof(n4->values));
n16->keys[4] = *kb;
if (!_insert(n16->values + 4, kb + 1, ke, rv)) {
free(n16);
return false;
}
free(n4);
v->type = NODE16;
v->value.ptr = n16;
} else {
n4 = v->value.ptr;
if (!_insert(n4->values + n4->nr_entries, kb + 1, ke, rv))
return false;
n4->keys[n4->nr_entries] = *kb;
n4->nr_entries++;
}
return true;
}
static bool _insert_node16(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct node16 *n16 = v->value.ptr;
if (n16->nr_entries == 16) {
unsigned i;
struct node48 *n48 = zalloc(sizeof(*n48));
if (!n48)
return false;
n48->nr_entries = 17;
memset(n48->keys, 48, sizeof(n48->keys));
for (i = 0; i < 16; i++) {
n48->keys[n16->keys[i]] = i;
n48->values[i] = n16->values[i];
}
n48->keys[*kb] = 16;
if (!_insert(n48->values + 16, kb + 1, ke, rv)) {
free(n48);
return false;
}
free(n16);
v->type = NODE48;
v->value.ptr = n48;
} else {
if (!_insert(n16->values + n16->nr_entries, kb + 1, ke, rv))
return false;
n16->keys[n16->nr_entries] = *kb;
n16->nr_entries++;
}
return true;
}
static bool _insert_node48(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct node48 *n48 = v->value.ptr;
if (n48->nr_entries == 48) {
unsigned i;
struct node256 *n256 = zalloc(sizeof(*n256));
if (!n256)
return false;
for (i = 0; i < 256; i++) {
if (n48->keys[i] >= 48)
continue;
n256->values[i] = n48->values[n48->keys[i]];
}
if (!_insert(n256->values + *kb, kb + 1, ke, rv)) {
free(n256);
return false;
}
free(n48);
v->type = NODE256;
v->value.ptr = n256;
} else {
if (!_insert(n48->values + n48->nr_entries, kb + 1, ke, rv))
return false;
n48->keys[*kb] = n48->nr_entries;
n48->nr_entries++;
}
return true;
}
static bool _insert_node256(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct node256 *n256 = v->value.ptr;
if (!_insert(n256->values + *kb, kb + 1, ke, rv)) {
n256->values[*kb].type = UNSET;
return false;
}
return true;
}
// FIXME: the tree should not be touched if insert fails (eg, OOM)
static bool _insert(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
if (kb == ke) {
if (v->type == UNSET) {
v->type = VALUE;
v->value = rv;
} else if (v->type == VALUE) {
v->value = rv;
} else {
struct value_chain *vc = zalloc(sizeof(*vc));
if (!vc)
return false;
vc->value = rv;
vc->child = *v;
v->type = VALUE_CHAIN;
v->value.ptr = vc;
}
return true;
}
switch (v->type) {
case UNSET:
return _insert_unset(v, kb, ke, rv);
case VALUE:
return _insert_value(v, kb, ke, rv);
case VALUE_CHAIN:
return _insert_value_chain(v, kb, ke, rv);
case PREFIX_CHAIN:
return _insert_prefix_chain(v, kb, ke, rv);
case NODE4:
return _insert_node4(v, kb, ke, rv);
case NODE16:
return _insert_node16(v, kb, ke, rv);
case NODE48:
return _insert_node48(v, kb, ke, rv);
case NODE256:
return _insert_node256(v, kb, ke, rv);
}
// can't get here
return false;
}
struct lookup_result {
struct value *v;
uint8_t *kb;
};
static struct lookup_result _lookup_prefix(struct value *v, uint8_t *kb, uint8_t *ke)
{
unsigned i;
struct value_chain *vc;
struct prefix_chain *pc;
struct node4 *n4;
struct node16 *n16;
struct node48 *n48;
struct node256 *n256;
if (kb == ke)
return (struct lookup_result) {.v = v, .kb = kb};
switch (v->type) {
case UNSET:
case VALUE:
break;
case VALUE_CHAIN:
vc = v->value.ptr;
return _lookup_prefix(&vc->child, kb, ke);
case PREFIX_CHAIN:
pc = v->value.ptr;
if (ke - kb < pc->len)
return (struct lookup_result) {.v = v, .kb = kb};
for (i = 0; i < pc->len; i++)
if (kb[i] != pc->prefix[i])
return (struct lookup_result) {.v = v, .kb = kb};
return _lookup_prefix(&pc->child, kb + pc->len, ke);
case NODE4:
n4 = v->value.ptr;
for (i = 0; i < n4->nr_entries; i++)
if (n4->keys[i] == *kb)
return _lookup_prefix(n4->values + i, kb + 1, ke);
break;
case NODE16:
// FIXME: use binary search or simd?
n16 = v->value.ptr;
for (i = 0; i < n16->nr_entries; i++)
if (n16->keys[i] == *kb)
return _lookup_prefix(n16->values + i, kb + 1, ke);
break;
case NODE48:
n48 = v->value.ptr;
i = n48->keys[*kb];
if (i < 48)
return _lookup_prefix(n48->values + i, kb + 1, ke);
break;
case NODE256:
n256 = v->value.ptr;
return _lookup_prefix(n256->values + *kb, kb + 1, ke);
}
return (struct lookup_result) {.v = v, .kb = kb};
}
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
if (_insert(lr.v, lr.kb, ke, rv)) {
rt->nr_entries++;
return true;
}
return false;
}
void radix_tree_delete(struct radix_tree *rt, uint8_t *key_begin, uint8_t *key_end)
{
assert(0);
}
bool radix_tree_lookup(struct radix_tree *rt,
uint8_t *kb, uint8_t *ke, union radix_value *result)
{
struct value_chain *vc;
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
if (lr.kb == ke) {
switch (lr.v->type) {
case VALUE:
*result = lr.v->value;
return true;
case VALUE_CHAIN:
vc = lr.v->value.ptr;
*result = vc->value;
return true;
default:
return false;
}
}
return false;
}
//----------------------------------------------------------------

View File

@@ -1,43 +0,0 @@
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
//
// This file is part of LVM2.
//
// This copyrighted material is made available to anyone wishing to use,
// modify, copy, or redistribute it subject to the terms and conditions
// of the GNU Lesser General Public License v.2.1.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BASE_DATA_STRUCT_RADIX_TREE_H
#define BASE_DATA_STRUCT_RADIX_TREE_H
#include <stdbool.h>
#include <stdint.h>
//----------------------------------------------------------------
struct radix_tree;
union radix_value {
void *ptr;
uint64_t n;
};
struct radix_tree *radix_tree_create(void);
typedef void (*radix_value_dtr)(void *context, union radix_value v);
// dtr may be NULL
void radix_tree_destroy(struct radix_tree *rt, radix_value_dtr dtr, void *context);
unsigned radix_tree_size(struct radix_tree *rt);
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v);
void radix_tree_delete(struct radix_tree *rt, uint8_t *kb, uint8_t *ke);
bool radix_tree_lookup(struct radix_tree *rt,
uint8_t *kb, uint8_t *ke, union radix_value *result);
//----------------------------------------------------------------
#endif

View File

@@ -1,23 +0,0 @@
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
//
// This file is part of LVM2.
//
// This copyrighted material is made available to anyone wishing to use,
// modify, copy, or redistribute it subject to the terms and conditions
// of the GNU Lesser General Public License v.2.1.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BASE_MEMORY_CONTAINER_OF_H
#define BASE_MEMORY_CONTAINER_OF_H
//----------------------------------------------------------------
#define container_of(v, t, head) \
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
//----------------------------------------------------------------
#endif

View File

@@ -1,31 +0,0 @@
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
//
// This file is part of LVM2.
//
// This copyrighted material is made available to anyone wishing to use,
// modify, copy, or redistribute it subject to the terms and conditions
// of the GNU Lesser General Public License v.2.1.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BASE_MEMORY_ZALLOC_H
#define BASE_MEMORY_ZALLOC_H
#include <stdlib.h>
#include <string.h>
//----------------------------------------------------------------
static inline void *zalloc(size_t len)
{
void *ptr = malloc(len);
if (ptr)
memset(ptr, 0, len);
return ptr;
}
//----------------------------------------------------------------
#endif

View File

@@ -32,8 +32,8 @@ include $(top_builddir)/make.tmpl
.PHONY: install_conf install_localconf install_profiles
generate:
LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in
LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --withcomments --withspaces local > lvmlocal.conf.in
(cat $(top_srcdir)/conf/example.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --ignorelocal --withspaces) > example.conf.in
(cat $(top_srcdir)/conf/lvmlocal.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --withspaces local) > lvmlocal.conf.in
install_conf: $(CONFSRC)
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
@@ -48,8 +48,8 @@ install_localconf: $(CONFLOCAL)
fi
install_profiles: $(PROFILES)
$(INSTALL_DIR) $(profiledir)
$(INSTALL_DATA) $(PROFILES) $(profiledir)/
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_PROFILE_DIR)
$(INSTALL_DATA) $(PROFILES) $(DESTDIR)$(DEFAULT_PROFILE_DIR)/
install_lvm2: install_conf install_localconf install_profiles

View File

@@ -9,6 +9,6 @@ allocation {
cache_mode = "writethrough"
cache_policy = "smq"
cache_settings {
# currently no settings for "smq" policy
# currently no settins for "smq" policy
}
}

23
conf/example.conf.base Normal file
View File

@@ -0,0 +1,23 @@
# This is an example configuration file for the LVM2 system.
# It contains the default settings that would be used if there was no
# @DEFAULT_SYS_DIR@/lvm.conf file.
#
# Refer to 'man lvm.conf' for further information including the file layout.
#
# Refer to 'man lvm.conf' for information about how settings configured in
# this file are combined with built-in values and command line options to
# arrive at the final values used by LVM.
#
# Refer to 'man lvmconfig' for information about displaying the built-in
# and configured values used by LVM.
#
# If a default value is set in this file (not commented out), then a
# new version of LVM using this file will continue using that value,
# even if the new version of LVM changes the built-in default value.
#
# To put this file in a different directory and override @DEFAULT_SYS_DIR@ set
# the environment variable LVM_SYSTEM_DIR before running the tools.
#
# N.B. Take care that each setting only appears once if uncommenting
# example settings in this file.

View File

@@ -379,9 +379,8 @@ allocation {
# Configuration option allocation/raid_stripe_all_devices.
# Stripe across all PVs when RAID stripes are not specified.
# If enabled, all PVs in the VG or on the command line are used for
# raid0/4/5/6/10 when the command does not specify the number of
# stripes to use.
# If enabled, all PVs in the VG or on the command line are used for raid0/4/5/6/10
# when the command does not specify the number of stripes to use.
# This was the default behaviour until release 2.02.162.
# This configuration option has an automatic default value.
# raid_stripe_all_devices = 0
@@ -390,17 +389,6 @@ allocation {
# Cache pool metadata and data will always use different PVs.
cache_pool_metadata_require_separate_pvs = 0
# Configuration option allocation/cache_metadata_format.
# Sets default metadata format for new cache.
#
# Accepted values:
# 0 Automatically detected best available format
# 1 Original format
# 2 Improved 2nd. generation format
#
# This configuration option has an automatic default value.
# cache_metadata_format = 0
# Configuration option allocation/cache_mode.
# The default cache mode used for new cache.
#
@@ -417,7 +405,7 @@ allocation {
# Configuration option allocation/cache_policy.
# The default cache policy used for new cache volume.
# Since kernel 4.2 the default policy is smq (Stochastic multiqueue),
# Since kernel 4.2 the default policy is smq (Stochastic multique),
# otherwise the older mq (Multiqueue) policy is selected.
# This configuration option does not have a default value defined.
@@ -611,9 +599,9 @@ log {
# Select log messages by class.
# Some debugging messages are assigned to a class and only appear in
# debug output if the class is listed here. Classes currently
# available: memory, devices, io, activation, allocation, lvmetad,
# available: memory, devices, activation, allocation, lvmetad,
# metadata, cache, locking, lvmpolld. Use "all" to see everything.
debug_classes = [ "memory", "devices", "io", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld", "dbus" ]
debug_classes = [ "memory", "devices", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld", "dbus" ]
}
# Configuration section backup.
@@ -821,6 +809,13 @@ global {
# encountered the internal error. Please only enable for debugging.
abort_on_internal_errors = 0
# Configuration option global/detect_internal_vg_cache_corruption.
# Internal verification of VG structures.
# Check if CRC matches when a parsed VG is used multiple times. This
# is useful to catch unexpected changes to cached VG structures.
# Please only enable for debugging.
detect_internal_vg_cache_corruption = 0
# Configuration option global/metadata_read_only.
# No operations that change on-disk metadata are permitted.
# Additionally, read-only commands that encounter metadata in need of
@@ -933,7 +928,7 @@ global {
use_lvmetad = @DEFAULT_USE_LVMETAD@
# Configuration option global/lvmetad_update_wait_time.
# Number of seconds a command will wait for lvmetad update to finish.
# The number of seconds a command will wait for lvmetad update to finish.
# After waiting for this period, a command will not use lvmetad, and
# will revert to disk scanning.
# This configuration option has an automatic default value.
@@ -1018,7 +1013,7 @@ global {
# Configuration option global/cache_disabled_features.
# Features to not use in the cache driver.
# This can be helpful for testing, or to avoid using a feature that is
# causing problems. Features include: policy_mq, policy_smq, metadata2.
# causing problems. Features include: policy_mq, policy_smq.
#
# Example
# cache_disabled_features = [ "policy_smq" ]
@@ -1063,12 +1058,6 @@ global {
# This configuration option has an automatic default value.
# cache_repair_options = [ "" ]
# Configuration option global/fsadm_executable.
# The full path to the fsadm command.
# LVM uses this command to help with lvresize -r operations.
# This configuration option has an automatic default value.
# fsadm_executable = "@FSADM_PATH@"
# Configuration option global/system_id_source.
# The method LVM uses to set the local system ID.
# Volume Groups can also be given a system ID (by vgcreate, vgchange,
@@ -1288,10 +1277,9 @@ activation {
# Configuration option activation/raid_region_size.
# Size in KiB of each raid or mirror synchronization region.
# The clean/dirty state of data is tracked for each region.
# The value is rounded down to a power of two if necessary, and
# is ignored if it is not a multiple of the machine memory page size.
raid_region_size = 2048
# For raid or mirror segment types, this is the amount of data that is
# copied at once when initializing, or moved at once by pvmove.
raid_region_size = 512
# Configuration option activation/error_when_full.
# Return errors if a thin pool runs out of space.
@@ -2066,7 +2054,6 @@ dmeventd {
# or metadata volume gets above 50%.
# Command which starts with 'lvm ' prefix is internal lvm command.
# You can write your own handler to customise behaviour in more details.
# User handler is specified with the full path starting with '/'.
# This configuration option has an automatic default value.
# thin_command = "lvm lvextend --use-policies"

19
conf/lvmlocal.conf.base Normal file
View File

@@ -0,0 +1,19 @@
# This is a local configuration file template for the LVM2 system
# which should be installed as @DEFAULT_SYS_DIR@/lvmlocal.conf .
#
# Refer to 'man lvm.conf' for information about the file layout.
#
# To put this file in a different directory and override
# @DEFAULT_SYS_DIR@ set the environment variable LVM_SYSTEM_DIR before
# running the tools.
#
# The lvmlocal.conf file is normally expected to contain only the
# "local" section which contains settings that should not be shared or
# repeated among different hosts. (But if other sections are present,
# they *will* get processed. Settings in this file override equivalent
# ones in lvm.conf and are in turn overridden by ones in any enabled
# lvm_<tag>.conf files.)
#
# Please take care that each setting only appears once if uncommenting
# example settings in this file and never copy this file between hosts.

811
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,6 @@ AC_PREREQ(2.69)
################################################################################
dnl -- Process this file with autoconf to produce a configure script.
AC_INIT
CONFIGURE_LINE="$0 $@"
AC_CONFIG_SRCDIR([lib/device/dev-cache.h])
AC_CONFIG_HEADERS([include/configure.h])
@@ -31,7 +30,6 @@ AS_IF([test -z "$CFLAGS"], [COPTIMISE_FLAG="-O2"])
case "$host_os" in
linux*)
CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
# equivalent to -rdynamic
ELDFLAGS="-Wl,--export-dynamic"
# FIXME Generate list and use --dynamic-list=.dlopen.sym
CLDWHOLEARCHIVE="-Wl,-whole-archive"
@@ -77,7 +75,6 @@ AC_PROG_CC
AC_PROG_CXX
CFLAGS=$save_CFLAGS
CXXFLAGS=$save_CXXFLAGS
PATH_SBIN="$PATH:/usr/sbin:/sbin"
dnl probably no longer needed in 2008, but...
AC_PROG_GCC_TRADITIONAL
@@ -86,12 +83,9 @@ AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PROG_MKDIR_P
AC_PROG_RANLIB
AC_CHECK_TOOL(AR, ar)
AC_PATH_TOOL(CFLOW_CMD, cflow)
AC_PATH_TOOL(CSCOPE_CMD, cscope)
AC_PATH_TOOL(CHMOD, chmod)
AC_PATH_TOOL(WC, wc)
AC_PATH_TOOL(SORT, sort)
################################################################################
dnl -- Check for header files.
@@ -103,13 +97,13 @@ AC_HEADER_SYS_WAIT
AC_HEADER_TIME
AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
getopt.h inttypes.h langinfo.h libaio.h libgen.h limits.h locale.h paths.h \
getopt.h inttypes.h langinfo.h libgen.h limits.h locale.h paths.h \
signal.h stdarg.h stddef.h stdio.h stdlib.h string.h sys/file.h \
sys/ioctl.h syslog.h sys/mman.h sys/param.h sys/resource.h sys/stat.h \
sys/time.h sys/types.h sys/utsname.h sys/wait.h time.h \
unistd.h], , [AC_MSG_ERROR(bailing out)])
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h sys/vfs.h linux/magic.h linux/fiemap.h)
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h linux/magic.h linux/fiemap.h)
case "$host_os" in
linux*)
@@ -124,7 +118,6 @@ AC_C_CONST
AC_C_INLINE
AC_CHECK_MEMBERS([struct stat.st_rdev])
AC_CHECK_TYPES([ptrdiff_t])
AC_STRUCT_ST_BLOCKS
AC_STRUCT_TM
AC_TYPE_OFF_T
AC_TYPE_PID_T
@@ -192,15 +185,9 @@ AC_SUBST(HAVE_FULL_RELRO)
################################################################################
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
AC_PREFIX_DEFAULT(/usr)
################################################################################
dnl -- Clear default exec_prefix - install into /sbin rather than /usr/sbin
test "$exec_prefix" = NONE -a "$prefix" = NONE && exec_prefix=""
test "x$prefix" = xNONE && prefix=$ac_default_prefix
# Let make expand exec_prefix.
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
if test "$prefix" = NONE; then
datarootdir=${ac_default_prefix}/share
fi
################################################################################
dnl -- Setup the ownership of the files
@@ -384,6 +371,13 @@ esac
################################################################################
dnl -- raid inclusion type
AC_MSG_CHECKING(whether to include raid)
AC_ARG_WITH(raid,
AC_HELP_STRING([--with-raid=TYPE],
[raid support: internal/shared/none [internal]]),
RAID=$withval, RAID=internal)
AC_MSG_RESULT($RAID)
AC_ARG_WITH(default-mirror-segtype,
AC_HELP_STRING([--with-default-mirror-segtype=TYPE],
[default mirror segtype: raid1/mirror [raid1]]),
@@ -392,9 +386,14 @@ AC_ARG_WITH(default-raid10-segtype,
AC_HELP_STRING([--with-default-raid10-segtype=TYPE],
[default mirror segtype: raid10/mirror [raid10]]),
DEFAULT_RAID10_SEGTYPE=$withval, DEFAULT_RAID10_SEGTYPE="raid10")
AC_DEFINE([RAID_INTERNAL], 1,
[Define to 1 to include built-in support for raid.])
case "$RAID" in
none) test "$DEFAULT_MIRROR_SEGTYPE" = "raid1" && DEFAULT_MIRROR_SEGTYPE="mirror"
test "$DEFAULT_RAID10_SEGTYPE" = "raid10" && DEFAULT_RAID10_SEGTYPE="mirror" ;;
shared) ;;
internal) AC_DEFINE([RAID_INTERNAL], 1,
[Define to 1 to include built-in support for raid.]) ;;
*) AC_MSG_ERROR([--with-raid parameter invalid]) ;;
esac
AC_DEFINE_UNQUOTED([DEFAULT_MIRROR_SEGTYPE], ["$DEFAULT_MIRROR_SEGTYPE"],
[Default segtype used for mirror volumes.])
@@ -403,6 +402,22 @@ AC_DEFINE_UNQUOTED([DEFAULT_RAID10_SEGTYPE], ["$DEFAULT_RAID10_SEGTYPE"],
[Default segtype used for raid10 volumes.])
################################################################################
dnl -- asynchronous volume replicator inclusion type
AC_MSG_CHECKING(whether to include replicators)
AC_ARG_WITH(replicators,
AC_HELP_STRING([--with-replicators=TYPE],
[replicator support: internal/shared/none [none]]),
REPLICATORS=$withval, REPLICATORS=none)
AC_MSG_RESULT($REPLICATORS)
case "$REPLICATORS" in
none|shared) ;;
internal) AC_DEFINE([REPLICATOR_INTERNAL], 1,
[Define to 1 to include built-in support for replicators.]) ;;
*) AC_MSG_ERROR([--with-replicators parameter invalid ($REPLICATORS)]) ;;
esac
AC_ARG_WITH(default-sparse-segtype,
AC_HELP_STRING([--with-default-sparse-segtype=TYPE],
[default sparse segtype: thin/snapshot [thin]]),
@@ -457,7 +472,7 @@ case "$THIN" in
internal|shared)
# Empty means a config way to ignore thin checking
if test "$THIN_CHECK_CMD" = "autodetect"; then
AC_PATH_TOOL(THIN_CHECK_CMD, thin_check, [], [$PATH_SBIN])
AC_PATH_TOOL(THIN_CHECK_CMD, thin_check)
if test -z "$THIN_CHECK_CMD"; then
AC_MSG_WARN([thin_check not found in path $PATH])
THIN_CHECK_CMD=/usr/sbin/thin_check
@@ -481,7 +496,7 @@ case "$THIN" in
fi
# Empty means a config way to ignore thin dumping
if test "$THIN_DUMP_CMD" = "autodetect"; then
AC_PATH_TOOL(THIN_DUMP_CMD, thin_dump, [], [$PATH_SBIN])
AC_PATH_TOOL(THIN_DUMP_CMD, thin_dump)
test -z "$THIN_DUMP_CMD" && {
AC_MSG_WARN(thin_dump not found in path $PATH)
THIN_DUMP_CMD=/usr/sbin/thin_dump
@@ -490,7 +505,7 @@ case "$THIN" in
fi
# Empty means a config way to ignore thin repairing
if test "$THIN_REPAIR_CMD" = "autodetect"; then
AC_PATH_TOOL(THIN_REPAIR_CMD, thin_repair, [], [$PATH_SBIN])
AC_PATH_TOOL(THIN_REPAIR_CMD, thin_repair)
test -z "$THIN_REPAIR_CMD" && {
AC_MSG_WARN(thin_repair not found in path $PATH)
THIN_REPAIR_CMD=/usr/sbin/thin_repair
@@ -499,7 +514,7 @@ case "$THIN" in
fi
# Empty means a config way to ignore thin restoring
if test "$THIN_RESTORE_CMD" = "autodetect"; then
AC_PATH_TOOL(THIN_RESTORE_CMD, thin_restore, [], [$PATH_SBIN])
AC_PATH_TOOL(THIN_RESTORE_CMD, thin_restore)
test -z "$THIN_RESTORE_CMD" && {
AC_MSG_WARN(thin_restore not found in path $PATH)
THIN_RESTORE_CMD=/usr/sbin/thin_restore
@@ -571,7 +586,7 @@ case "$CACHE" in
internal|shared)
# Empty means a config way to ignore cache checking
if test "$CACHE_CHECK_CMD" = "autodetect"; then
AC_PATH_TOOL(CACHE_CHECK_CMD, cache_check, [], [$PATH_SBIN])
AC_PATH_TOOL(CACHE_CHECK_CMD, cache_check)
if test -z "$CACHE_CHECK_CMD"; then
AC_MSG_WARN([cache_check not found in path $PATH])
CACHE_CHECK_CMD=/usr/sbin/cache_check
@@ -598,15 +613,11 @@ case "$CACHE" in
CACHE_CHECK_VERSION_WARN=y
CACHE_CHECK_NEEDS_CHECK=no
fi
if test "$CACHE_CHECK_VSN_MINOR" -lt 7 ; then
AC_MSG_WARN([$CACHE_CHECK_CMD: Old version "$CACHE_CHECK_VSN" does not support new cache format V2])
CACHE_CHECK_VERSION_WARN=y
fi
fi
fi
# Empty means a config way to ignore cache dumping
if test "$CACHE_DUMP_CMD" = "autodetect"; then
AC_PATH_TOOL(CACHE_DUMP_CMD, cache_dump, [], [$PATH_SBIN])
AC_PATH_TOOL(CACHE_DUMP_CMD, cache_dump)
test -z "$CACHE_DUMP_CMD" && {
AC_MSG_WARN(cache_dump not found in path $PATH)
CACHE_DUMP_CMD=/usr/sbin/cache_dump
@@ -615,7 +626,7 @@ case "$CACHE" in
fi
# Empty means a config way to ignore cache repairing
if test "$CACHE_REPAIR_CMD" = "autodetect"; then
AC_PATH_TOOL(CACHE_REPAIR_CMD, cache_repair, [], [$PATH_SBIN])
AC_PATH_TOOL(CACHE_REPAIR_CMD, cache_repair)
test -z "$CACHE_REPAIR_CMD" && {
AC_MSG_WARN(cache_repair not found in path $PATH)
CACHE_REPAIR_CMD=/usr/sbin/cache_repair
@@ -624,7 +635,7 @@ case "$CACHE" in
fi
# Empty means a config way to ignore cache restoring
if test "$CACHE_RESTORE_CMD" = "autodetect"; then
AC_PATH_TOOL(CACHE_RESTORE_CMD, cache_restore, [], [$PATH_SBIN])
AC_PATH_TOOL(CACHE_RESTORE_CMD, cache_restore)
test -z "$CACHE_RESTORE_CMD" && {
AC_MSG_WARN(cache_restore not found in path $PATH)
CACHE_RESTORE_CMD=/usr/sbin/cache_restore
@@ -655,9 +666,11 @@ AC_DEFINE_UNQUOTED([CACHE_RESTORE_CMD], ["$CACHE_RESTORE_CMD"],
################################################################################
dnl -- Disable readline
AC_MSG_CHECKING(whether to enable readline)
AC_ARG_ENABLE([readline],
AC_HELP_STRING([--disable-readline], [disable readline support]),
READLINE=$enableval, READLINE=maybe)
AC_MSG_RESULT($READLINE)
################################################################################
dnl -- Disable realtime clock support
@@ -1055,6 +1068,20 @@ if test "$PROFILING" = yes; then
fi
fi
################################################################################
dnl -- Enable testing
AC_MSG_CHECKING(whether to enable unit testing)
AC_ARG_ENABLE(testing,
AC_HELP_STRING([--enable-testing],
[enable testing targets in the makefile]),
TESTING=$enableval, TESTING=no)
AC_MSG_RESULT($TESTING)
if test "$TESTING" = yes; then
pkg_config_init
PKG_CHECK_MODULES(CUNIT, cunit >= 2.0)
fi
################################################################################
dnl -- Set LVM2 testsuite data
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
@@ -1119,10 +1146,10 @@ AC_MSG_RESULT($BUILD_LVMPOLLD)
################################################################################
BUILD_LVMLOCKD=no
dnl -- Build lvmlockdsanlock
AC_MSG_CHECKING(whether to build lvmlockdsanlock)
AC_ARG_ENABLE(lvmlockd-sanlock,
AC_HELP_STRING([--enable-lvmlockd-sanlock],
dnl -- Build lockdsanlock
AC_MSG_CHECKING(whether to build lockdsanlock)
AC_ARG_ENABLE(lockd-sanlock,
AC_HELP_STRING([--enable-lockd-sanlock],
[enable the LVM lock daemon using sanlock]),
LOCKDSANLOCK=$enableval)
AC_MSG_RESULT($LOCKDSANLOCK)
@@ -1137,10 +1164,10 @@ if test "$BUILD_LOCKDSANLOCK" = yes; then
fi
################################################################################
dnl -- Build lvmlockddlm
AC_MSG_CHECKING(whether to build lvmlockddlm)
AC_ARG_ENABLE(lvmlockd-dlm,
AC_HELP_STRING([--enable-lvmlockd-dlm],
dnl -- Build lockddlm
AC_MSG_CHECKING(whether to build lockddlm)
AC_ARG_ENABLE(lockd-dlm,
AC_HELP_STRING([--enable-lockd-dlm],
[enable the LVM lock daemon using dlm]),
LOCKDDLM=$enableval)
AC_MSG_RESULT($LOCKDDLM)
@@ -1247,14 +1274,10 @@ dnl -- Check dmfilemapd
AC_MSG_CHECKING(whether to build dmfilemapd)
AC_ARG_ENABLE(dmfilemapd, AC_HELP_STRING([--enable-dmfilemapd],
[enable the dmstats filemap daemon]),
BUILD_DMFILEMAPD=$enableval, BUILD_DMFILEMAPD=no)
AC_MSG_RESULT($BUILD_DMFILEMAPD)
AC_DEFINE([DMFILEMAPD], $BUILD_DMFILEMAPD, [Define to 1 to enable the device-mapper filemap daemon.])
dnl -- dmfilemapd requires FIEMAP
if test "$BUILD_DMFILEMAPD" = yes; then
AC_CHECK_HEADER([linux/fiemap.h], , [AC_MSG_ERROR(--enable-dmfilemapd requires fiemap.h)])
fi
DMFILEMAPD=$enableval)
AC_MSG_RESULT($DMFILEMAPD)
BUILD_DMFILEMAPD=$DMFILEMAPD
AC_DEFINE([DMFILEMAPD], 1, [Define to 1 to enable the device-mapper filemap daemon.])
################################################################################
dnl -- Build notifydbus
@@ -1262,60 +1285,69 @@ AC_MSG_CHECKING(whether to build notifydbus)
AC_ARG_ENABLE(notify-dbus,
AC_HELP_STRING([--enable-notify-dbus],
[enable LVM notification using dbus]),
NOTIFYDBUS_SUPPORT=$enableval, NOTIFYDBUS_SUPPORT=no)
AC_MSG_RESULT($NOTIFYDBUS_SUPPORT)
NOTIFYDBUS=$enableval)
AC_MSG_RESULT($NOTIFYDBUS)
if test "$NOTIFYDBUS_SUPPORT" = yes; then
BUILD_NOTIFYDBUS=$NOTIFYDBUS
if test "$BUILD_NOTIFYDBUS" = yes; then
AC_DEFINE([NOTIFYDBUS_SUPPORT], 1, [Define to 1 to include code that uses dbus notification.])
SYSTEMD_LIBS="-lsystemd"
LIBS="-lsystemd $LIBS"
fi
################################################################################
dnl -- Look for dbus libraries
if test "$NOTIFYDBUS_SUPPORT" = yes; then
if test "$BUILD_NOTIFYDBUS" = yes; then
PKG_CHECK_MODULES(NOTIFY_DBUS, systemd >= 221, [HAVE_NOTIFY_DBUS=yes], $bailout)
fi
################################################################################
dnl -- Enable blkid wiping functionality
AC_MSG_CHECKING(whether to enable libblkid detection of signatures when wiping)
AC_ARG_ENABLE(blkid_wiping,
AC_HELP_STRING([--disable-blkid_wiping],
[disable libblkid detection of signatures when wiping and use native code instead]),
BLKID_WIPING=$enableval, BLKID_WIPING=maybe)
AC_MSG_RESULT($BLKID_WIPING)
DEFAULT_USE_BLKID_WIPING=0
if test "$BLKID_WIPING" != no; then
pkg_config_init
PKG_CHECK_MODULES(BLKID, blkid >= 2.24,
[ BLKID_WIPING=yes
BLKID_PC="blkid"
DEFAULT_USE_BLKID_WIPING=1
AC_DEFINE([BLKID_WIPING_SUPPORT], 1, [Define to 1 to use libblkid detection of signatures when wiping.])
], [if test "$BLKID_WIPING" = maybe; then
[test "$BLKID_WIPING" = maybe && BLKID_WIPING=yes],
[if test "$BLKID_WIPING" = maybe; then
BLKID_WIPING=no
else
AC_MSG_ERROR([bailing out... blkid library >= 2.24 is required])
fi])
if test "$BLKID_WIPING" = yes; then
BLKID_PC="blkid"
DEFAULT_USE_BLKID_WIPING=1
AC_DEFINE([BLKID_WIPING_SUPPORT], 1, [Define to 1 to use libblkid detection of signatures when wiping.])
else
DEFAULT_USE_BLKID_WIPING=0
fi
else
DEFAULT_USE_BLKID_WIPING=0
fi
AC_MSG_CHECKING([whether to enable libblkid detection of signatures when wiping])
AC_MSG_RESULT($BLKID_WIPING)
AC_DEFINE_UNQUOTED(DEFAULT_USE_BLKID_WIPING, [$DEFAULT_USE_BLKID_WIPING],
[Use blkid wiping by default.])
################################################################################
dnl -- Enable udev-systemd protocol to instantiate a service for background jobs
dnl -- Requires systemd version 205 at least (including support for systemd-run)
AC_MSG_CHECKING(whether to use udev-systemd protocol for jobs in background)
AC_ARG_ENABLE(udev-systemd-background-jobs,
AC_HELP_STRING([--disable-udev-systemd-background-jobs],
[disable udev-systemd protocol to instantiate a service for background job]),
UDEV_SYSTEMD_BACKGROUND_JOBS=$enableval,
UDEV_SYSTEMD_BACKGROUND_JOBS=maybe)
AC_MSG_RESULT($UDEV_SYSTEMD_BACKGROUND_JOBS)
if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" != no; then
pkg_config_init
PKG_CHECK_MODULES(SYSTEMD, systemd >= 205,
[UDEV_SYSTEMD_BACKGROUND_JOBS=yes],
[test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe && UDEV_SYSTEMD_BACKGROUND_JOBS=yes],
[if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe; then
UDEV_SYSTEMD_BACKGROUND_JOBS=no
else
@@ -1323,9 +1355,6 @@ if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" != no; then
fi])
fi
AC_MSG_CHECKING(whether to use udev-systemd protocol for jobs in background)
AC_MSG_RESULT($UDEV_SYSTEMD_BACKGROUND_JOBS)
################################################################################
dnl -- Enable udev synchronisation
AC_MSG_CHECKING(whether to enable synchronisation with udev processing)
@@ -1429,8 +1458,6 @@ AC_SUBST([LVM2APP_LIB])
test "$APPLIB" = yes \
&& LVM2APP_LIB=-llvm2app \
|| LVM2APP_LIB=
AS_IF([test "$APPLIB"],
[AC_MSG_WARN([liblvm2app is deprecated. Use D-Bus API])])
################################################################################
dnl -- Enable cmdlib
@@ -1451,8 +1478,6 @@ AC_ARG_ENABLE(dbus-service,
AC_HELP_STRING([--enable-dbus-service], [install D-Bus support]),
BUILD_LVMDBUSD=$enableval, BUILD_LVMDBUSD=no)
AC_MSG_RESULT($BUILD_LVMDBUSD)
AS_IF([test "$NOTIFYDBUS_SUPPORT" = yes && test "BUILD_LVMDBUSD" = yes],
[AC_MSG_WARN([Building D-Bus support without D-Bus notifications.])])
################################################################################
dnl -- Enable Python liblvm2app bindings
@@ -1505,7 +1530,7 @@ if test "$PYTHON3_BINDINGS" = yes -o "$BUILD_LVMDBUSD" = yes; then
PYTHON3_INCDIRS=`"$PYTHON3_CONFIG" --includes`
PYTHON3_LIBDIRS=`"$PYTHON3_CONFIG" --libs`
PYTHON3DIR=$pythondir
test "$PYTHON3_BINDINGS" = yes && PYTHON_BINDINGS=yes
PYTHON_BINDINGS=yes
fi
if test "$BUILD_LVMDBUSD" = yes; then
@@ -1515,7 +1540,6 @@ if test "$BUILD_LVMDBUSD" = yes; then
fi
if test "$PYTHON_BINDINGS" = yes -o "$PYTHON2_BINDINGS" = yes -o "$PYTHON3_BINDINGS" = yes; then
AC_MSG_WARN([Python bindings are deprecated. Use D-Bus API])
test "$APPLIB" != yes && AC_MSG_ERROR([Python_bindings require --enable-applib])
fi
@@ -1551,11 +1575,13 @@ dnl -- enable dmeventd handling
AC_MSG_CHECKING(whether to use dmeventd)
AC_ARG_ENABLE(dmeventd, AC_HELP_STRING([--enable-dmeventd],
[enable the device-mapper event daemon]),
BUILD_DMEVENTD=$enableval, BUILD_DMEVENTD=no)
AC_MSG_RESULT($BUILD_DMEVENTD)
DMEVENTD=$enableval)
AC_MSG_RESULT($DMEVENTD)
BUILD_DMEVENTD=$DMEVENTD
dnl -- dmeventd currently requires internal mirror support
if test "$BUILD_DMEVENTD" = yes; then
if test "$DMEVENTD" = yes; then
if test "$MIRRORS" != internal; then
AC_MSG_ERROR([--enable-dmeventd currently requires --with-mirrors=internal])
fi
@@ -1579,6 +1605,10 @@ AC_CHECK_LIB(c, canonicalize_file_name,
AC_DEFINE([HAVE_CANONICALIZE_FILE_NAME], 1,
[Define to 1 if canonicalize_file_name is available.]))
################################################################################
dnl -- Clear default exec_prefix - install into /sbin rather than /usr/sbin
test "$exec_prefix" = NONE -a "$prefix" = NONE && exec_prefix=""
################################################################################
dnl -- Check for dlopen
AC_CHECK_LIB(dl, dlopen,
@@ -1591,6 +1621,8 @@ AC_CHECK_LIB(dl, dlopen,
################################################################################
dnl -- Check for shared/static conflicts
if [[ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
-o "$SNAPSHOTS" = shared -o "$MIRRORS" = shared \
-o "$RAID" = shared -o "$CACHE" = shared \
\) -a "$STATIC_LINK" = yes ]]; then
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
fi
@@ -1633,16 +1665,13 @@ fi
################################################################################
dnl -- Check for realtime clock support
RT_LIBS=
HAVE_REALTIME=no
if test "$REALTIME" = yes; then
AC_CHECK_FUNCS([clock_gettime], HAVE_REALTIME=yes)
AS_IF([test "$HAVE_REALTIME" != yes], [ # try again with -lrt
AC_CHECK_LIB([rt], [clock_gettime], RT_LIBS="-lrt"; HAVE_REALTIME=yes)])
AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no)
if test "$HAVE_REALTIME" = yes; then
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
LIBS="-lrt $LIBS"
RT_LIB="-lrt"
else
AC_MSG_WARN(Disabling realtime clock)
fi
@@ -1686,7 +1715,6 @@ Note: (n)curses also seems to work as a substitute for termcap. This was
AC_DEFINE([READLINE_SUPPORT], 1,
[Define to 1 to include the LVM readline shell.])
dnl -- Try only with -lreadline and check for different symbol
READLINE=yes
LIBS=$lvm_saved_libs
AC_CHECK_LIB([readline], [rl_line_buffer],
[ READLINE_LIBS="-lreadline" ], [
@@ -1793,16 +1821,13 @@ dnl -- Ensure additional headers required
if test "$READLINE" = yes; then
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,hard_bailout)
fi
AC_MSG_CHECKING(whether to enable readline)
AC_MSG_RESULT($READLINE)
if test "$BUILD_CMIRRORD" = yes; then
AC_CHECK_FUNCS(atexit,,hard_bailout)
fi
if test "$BUILD_LVMLOCKD" = yes; then
AS_IF([test "$HAVE_REALTIME" != yes], [AC_MSG_ERROR([Realtime clock support is mandatory for lvmlockd.])])
AC_CHECK_FUNCS(strtoull,,hard_bailout)
AC_CHECK_FUNCS(clock_gettime strtoull,,hard_bailout)
fi
if test "$BUILD_LVMPOLLD" = yes; then
@@ -1822,7 +1847,7 @@ if test "$CLUSTER" != none; then
AC_CHECK_FUNCS(socket,,hard_bailout)
fi
if test "$BUILD_DMEVENTD" = yes; then
if test "$DMEVENTD" = yes; then
AC_CHECK_HEADERS(arpa/inet.h,,hard_bailout)
fi
@@ -1838,30 +1863,29 @@ if test "$UDEV_SYNC" = yes; then
AC_CHECK_HEADERS(sys/ipc.h sys/sem.h,,hard_bailout)
fi
if test "$BUILD_DMFILEMAPD" = yes; then
if test "$DMFILEMAPD" = yes; then
AC_CHECK_HEADERS([sys/inotify.h],,hard_bailout)
fi
################################################################################
AC_PATH_TOOL(MODPROBE_CMD, modprobe, [], [$PATH_SBIN])
AC_PATH_TOOL(MODPROBE_CMD, modprobe)
if test -n "$MODPROBE_CMD"; then
AC_DEFINE_UNQUOTED([MODPROBE_CMD], ["$MODPROBE_CMD"], [The path to 'modprobe', if available.])
fi
SYSCONFDIR="$(eval echo $(eval echo $sysconfdir))"
SBINDIR="$(eval echo $(eval echo $sbindir))"
LVM_PATH="$SBINDIR/lvm"
lvm_exec_prefix=$exec_prefix
test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$prefix
test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$ac_default_prefix
LVM_PATH="$lvm_exec_prefix/sbin/lvm"
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
USRSBINDIR="$(eval echo $(eval echo $usrsbindir))"
CLVMD_PATH="$USRSBINDIR/clvmd"
clvmd_prefix=$ac_default_prefix
test "$prefix" != NONE && clvmd_prefix=$prefix
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
FSADM_PATH="$SBINDIR/fsadm"
AC_DEFINE_UNQUOTED(FSADM_PATH, ["$FSADM_PATH"], [Path to fsadm binary.])
################################################################################
dnl -- dmeventd pidfile and executable path
if test "$BUILD_DMEVENTD" = yes; then
@@ -1879,7 +1903,7 @@ if test "$BUILD_DMEVENTD" = yes; then
AC_HELP_STRING([--with-dmeventd-path=PATH],
[dmeventd path [EPREFIX/sbin/dmeventd]]),
DMEVENTD_PATH=$withval,
DMEVENTD_PATH="$SBINDIR/dmeventd")
DMEVENTD_PATH="$lvm_exec_prefix/sbin/dmeventd")
AC_DEFINE_UNQUOTED(DMEVENTD_PATH, ["$DMEVENTD_PATH"],
[Path to dmeventd binary.])
fi
@@ -1922,17 +1946,13 @@ AC_ARG_WITH(default-cache-subdir,
AC_DEFINE_UNQUOTED(DEFAULT_CACHE_SUBDIR, ["$DEFAULT_CACHE_SUBDIR"],
[Name of default metadata cache subdirectory.])
# Select default system locking dir, prefer /run/lock over /var/lock
DEFAULT_SYS_LOCK_DIR="$RUN_DIR/lock"
test -d "$DEFAULT_SYS_LOCK_DIR" || DEFAULT_SYS_LOCK_DIR="/var/lock"
# Support configurable locking subdir for lvm
AC_ARG_WITH(default-locking-dir,
AC_HELP_STRING([--with-default-locking-dir=DIR],
[default locking directory [autodetect_lock_dir/lvm]]),
DEFAULT_LOCK_DIR=$withval,
[AC_MSG_CHECKING(for default lock directory)
DEFAULT_LOCK_DIR="$DEFAULT_SYS_LOCK_DIR/lvm"
DEFAULT_LOCK_DIR="$RUN_DIR/lock/lvm"
test -d "$RUN_DIR/lock" || DEFAULT_LOCK_DIR="/var/lock/lvm"
AC_MSG_RESULT($DEFAULT_LOCK_DIR)])
AC_DEFINE_UNQUOTED(DEFAULT_LOCK_DIR, ["$DEFAULT_LOCK_DIR"],
[Name of default locking directory.])
@@ -1974,8 +1994,6 @@ LVM_MINOR=`echo "$VER" | $AWK -F '.' '{print $2}'`
LVM_PATCHLEVEL=`echo "$VER" | $AWK -F '[[(.]]' '{print $3}'`
LVM_LIBAPI=`echo "$VER" | $AWK -F '[[()]]' '{print $2}'`
AC_DEFINE_UNQUOTED(LVM_CONFIGURE_LINE, "$CONFIGURE_LINE", [configure command line used])
################################################################################
AC_SUBST(APPLIB)
AC_SUBST(AWK)
@@ -1989,6 +2007,7 @@ AC_SUBST(BUILD_LVMLOCKD)
AC_SUBST(BUILD_LOCKDSANLOCK)
AC_SUBST(BUILD_LOCKDDLM)
AC_SUBST(BUILD_DMFILEMAPD)
AC_SUBST(BUILD_NOTIFYDBUS)
AC_SUBST(CACHE)
AC_SUBST(CFLAGS)
AC_SUBST(CFLOW_CMD)
@@ -2027,7 +2046,6 @@ AC_SUBST(DEFAULT_RAID10_SEGTYPE)
AC_SUBST(DEFAULT_RUN_DIR)
AC_SUBST(DEFAULT_SPARSE_SEGTYPE)
AC_SUBST(DEFAULT_SYS_DIR)
AC_SUBST(DEFAULT_SYS_LOCK_DIR)
AC_SUBST(DEFAULT_USE_BLKID_WIPING)
AC_SUBST(DEFAULT_USE_LVMETAD)
AC_SUBST(DEFAULT_USE_LVMPOLLD)
@@ -2036,11 +2054,12 @@ AC_SUBST(DEVMAPPER)
AC_SUBST(DLM_CFLAGS)
AC_SUBST(DLM_LIBS)
AC_SUBST(DL_LIBS)
AC_SUBST(DMEVENTD)
AC_SUBST(DMEVENTD_PATH)
AC_SUBST(DMFILEMAPD)
AC_SUBST(DM_LIB_PATCHLEVEL)
AC_SUBST(ELDFLAGS)
AC_SUBST(FSADM)
AC_SUBST(FSADM_PATH)
AC_SUBST(BLKDEACTIVATE)
AC_SUBST(HAVE_LIBDL)
AC_SUBST(HAVE_REALTIME)
@@ -2084,21 +2103,20 @@ AC_SUBST(PYTHON2DIR)
AC_SUBST(PYTHON3DIR)
AC_SUBST(QUORUM_CFLAGS)
AC_SUBST(QUORUM_LIBS)
AC_SUBST(RT_LIBS)
AC_SUBST(RAID)
AC_SUBST(RT_LIB)
AC_SUBST(READLINE_LIBS)
AC_SUBST(REPLICATORS)
AC_SUBST(SACKPT_CFLAGS)
AC_SUBST(SACKPT_LIBS)
AC_SUBST(SALCK_CFLAGS)
AC_SUBST(SALCK_LIBS)
AC_SUBST(SBINDIR)
AC_SUBST(SELINUX_LIBS)
AC_SUBST(SELINUX_PC)
AC_SUBST(SYSCONFDIR)
AC_SUBST(SYSTEMD_LIBS)
AC_SUBST(SNAPSHOTS)
AC_SUBST(STATICDIR)
AC_SUBST(STATIC_LINK)
AC_SUBST(TESTING)
AC_SUBST(TESTSUITE_DATA)
AC_SUBST(THIN)
AC_SUBST(THIN_CHECK_CMD)
@@ -2116,7 +2134,6 @@ AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
AC_SUBST(USE_TRACKING)
AC_SUBST(USRSBINDIR)
AC_SUBST(VALGRIND_POOL)
AC_SUBST(WRITE_INSTALL)
AC_SUBST(DMEVENTD_PIDFILE)
@@ -2157,14 +2174,10 @@ daemons/dmeventd/plugins/snapshot/Makefile
daemons/dmeventd/plugins/thin/Makefile
daemons/dmfilemapd/Makefile
daemons/lvmdbusd/Makefile
daemons/lvmdbusd/lvmdbusd
daemons/lvmdbusd/lvmdb.py
daemons/lvmdbusd/lvm_shell_proxy.py
daemons/lvmdbusd/path.py
daemons/lvmetad/Makefile
daemons/lvmpolld/Makefile
daemons/lvmlockd/Makefile
device_mapper/Makefile
conf/Makefile
conf/example.conf
conf/lvmlocal.conf
@@ -2176,7 +2189,13 @@ lib/Makefile
lib/format1/Makefile
lib/format_pool/Makefile
lib/locking/Makefile
lib/mirror/Makefile
lib/replicator/Makefile
include/lvm-version.h
lib/raid/Makefile
lib/snapshot/Makefile
lib/thin/Makefile
lib/cache_segtype/Makefile
libdaemon/Makefile
libdaemon/client/Makefile
libdaemon/server/Makefile
@@ -2217,10 +2236,12 @@ scripts/lvmdump.sh
scripts/Makefile
test/Makefile
test/api/Makefile
test/api/python_lvm_unit.py
test/unit/Makefile
tools/Makefile
udev/Makefile
unit-tests/datastruct/Makefile
unit-tests/regex/Makefile
unit-tests/mm/Makefile
])
AC_OUTPUT
@@ -2228,14 +2249,10 @@ AS_IF([test -n "$THIN_CONFIGURE_WARN"],
[AC_MSG_WARN([Support for thin provisioning is limited since some thin provisioning tools are missing!])])
AS_IF([test -n "$THIN_CHECK_VERSION_WARN"],
[AC_MSG_WARN([You should also install latest thin_check vsn 0.7.0 (or later) for lvm2 thin provisioning])])
[AC_MSG_WARN([You should also install thin_check vsn 0.3.2 (or later) to use lvm2 thin provisioning])])
AS_IF([test -n "$CACHE_CONFIGURE_WARN"],
[AC_MSG_WARN([Support for cache is limited since some cache tools are missing!])])
AS_IF([test -n "$CACHE_CHECK_VERSION_WARN"],
[AC_MSG_WARN([You should install latest cache_check vsn 0.7.0 to use lvm2 cache metadata format 2])])
AS_IF([test "$ODIRECT" != yes],
[AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])])

View File

@@ -41,19 +41,6 @@ struct lv_segment *last_seg(const struct logical_volume *lv)
return ((struct lv_segment **)lv)[0];
}
const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile)
{
return "STRING";
}
struct logical_volume *origin_from_cow(const struct logical_volume *lv)
{
if (lv)
return lv;
__coverity_panic__();
}
/* simple_memccpy() from glibc */
void *memccpy(void *dest, const void *src, int c, size_t n)
{
@@ -84,17 +71,6 @@ void model_FD_ZERO(void *fdset)
((long*)fdset)[i] = 0;
}
/* Resent Coverity reports quite weird errors... */
int *__errno_location(void)
{
}
const unsigned short **__ctype_b_loc (void)
{
}
/*
* Added extra pointer check to not need these models,
* for now just keep then in file

View File

@@ -31,9 +31,9 @@ SALCK_LIBS = @SALCK_LIBS@
SALCK_CFLAGS = @SALCK_CFLAGS@
SOURCES = \
clvmd-command.c\
clvmd.c\
lvm-functions.c\
clvmd-command.c \
clvmd.c \
lvm-functions.c \
refresh_clvmd.c
ifneq (,$(findstring cman,, "@CLVMD@,"))
@@ -72,17 +72,26 @@ endif
TARGETS = \
clvmd
LVMLIBS = $(LVMINTERNAL_LIBS)
ifeq ("@DMEVENTD@", "yes")
LVMLIBS += -ldevmapper-event
endif
include $(top_builddir)/make.tmpl
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS) -laio
LVMLIBS += -ldevmapper
LIBS += $(PTHREAD_LIBS)
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
LDFLAGS += $(EXTRA_EXEC_LDFLAGS)
INSTALL_TARGETS = \
install_clvmd
clvmd: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
-o clvmd $(OBJECTS) $(LMLIBS) $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o clvmd $(OBJECTS) \
$(LVMLIBS) $(LMLIBS) $(LIBS)
.PHONY: install_clvmd

View File

@@ -171,10 +171,8 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
/* Check the status of the command and return the error text */
if (status) {
if (*buf)
*retlen = dm_snprintf(*buf, buflen, "%s", strerror(status)) + 1;
else
*retlen = 0;
*retlen = 1 + ((*buf) ? dm_snprintf(*buf, buflen, "%s",
strerror(status)) : -1);
}
return status;
@@ -208,7 +206,7 @@ static int lock_vg(struct local_client *client)
lock_mode = ((int) lock_cmd & LCK_TYPE_MASK);
/* lock_flags = args[1]; */
lockname = &args[2];
DEBUGLOG("(%p) doing PRE command LOCK_VG '%s' at %x\n", client, lockname, lock_cmd);
DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client);
if (lock_mode == LCK_UNLOCK) {
if (!(lkid = (int) (long) dm_hash_lookup(lock_hash, lockname)))
@@ -325,7 +323,7 @@ void cmd_client_cleanup(struct local_client *client)
int lkid;
char *lockname;
DEBUGLOG("(%p) Client thread cleanup\n", client);
DEBUGLOG("Client thread cleanup (%p)\n", client);
if (!client->bits.localsock.private)
return;
@@ -334,7 +332,7 @@ void cmd_client_cleanup(struct local_client *client)
dm_hash_iterate(v, lock_hash) {
lkid = (int)(long)dm_hash_get_data(lock_hash, v);
lockname = dm_hash_get_key(lock_hash, v);
DEBUGLOG("(%p) Cleanup: Unlocking lock %s %x\n", client, lockname, lkid);
DEBUGLOG("Cleanup (%p): Unlocking lock %s %x\n", client, lockname, lkid);
(void) sync_unlock(lockname, lkid);
}

View File

@@ -425,6 +425,8 @@ static void _add_up_node(const char *csid)
DEBUGLOG("openais_add_up_node %d\n", ninfo->nodeid);
ninfo->state = NODE_CLVMD;
return;
}
/* Call a callback for each node, so the caller knows whether it's up or down */

View File

@@ -58,7 +58,6 @@
/* Head of the fd list. Also contains
the cluster_socket details */
static struct local_client local_client_head;
static int _local_client_count = 0;
static unsigned short global_xid = 0; /* Last transaction ID issued */
@@ -69,37 +68,6 @@ static unsigned max_csid_len;
static unsigned max_cluster_message;
static unsigned max_cluster_member_name_len;
static void _add_client(struct local_client *new_client, struct local_client *existing_client)
{
_local_client_count++;
DEBUGLOG("(%p) Adding listener for fd %d. (Now %d monitored fds.)\n", new_client, new_client->fd, _local_client_count);
new_client->next = existing_client->next;
existing_client->next = new_client;
}
int add_client(struct local_client *new_client)
{
_add_client(new_client, &local_client_head);
return 0;
}
/* Returns 0 if delfd is found and removed from list */
static int _del_client(struct local_client *delfd)
{
struct local_client *lastfd, *thisfd;
for (lastfd = &local_client_head; (thisfd = lastfd->next); lastfd = thisfd)
if (thisfd == delfd) {
DEBUGLOG("(%p) Removing listener for fd %d\n", thisfd, thisfd->fd);
lastfd->next = delfd->next;
_local_client_count--;
return 0;
}
return 1;
}
/* Structure of items on the LVM thread list */
struct lvm_thread_cmd {
struct dm_list list;
@@ -124,7 +92,6 @@ static const size_t STACK_SIZE = 128 * 1024;
static pthread_attr_t stack_attr;
static int lvm_thread_exit = 0;
static pthread_mutex_t lvm_thread_mutex;
static pthread_mutex_t _debuglog_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t lvm_thread_cond;
static pthread_barrier_t lvm_start_barrier;
static struct dm_list lvm_cmd_head;
@@ -251,17 +218,14 @@ void debuglog(const char *fmt, ...)
switch (clvmd_get_debug()) {
case DEBUG_STDERR:
pthread_mutex_lock(&_debuglog_mutex);
va_start(ap,fmt);
time(&P);
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime_r(&P, buf_ctime) + 4);
vfprintf(stderr, fmt, ap);
va_end(ap);
fflush(stderr);
pthread_mutex_unlock(&_debuglog_mutex);
break;
case DEBUG_SYSLOG:
pthread_mutex_lock(&_debuglog_mutex);
if (!syslog_init) {
openlog("clvmd", LOG_PID, LOG_DAEMON);
syslog_init = 1;
@@ -270,7 +234,6 @@ void debuglog(const char *fmt, ...)
va_start(ap,fmt);
vsyslog(LOG_DEBUG, fmt, ap);
va_end(ap);
pthread_mutex_unlock(&_debuglog_mutex);
break;
case DEBUG_OFF:
break;
@@ -554,7 +517,7 @@ int main(int argc, char *argv[])
/* Initialise the LVM thread variables */
dm_list_init(&lvm_cmd_head);
if (pthread_attr_init(&stack_attr) ||
pthread_attr_setstacksize(&stack_attr, STACK_SIZE + getpagesize())) {
pthread_attr_setstacksize(&stack_attr, STACK_SIZE)) {
log_sys_error("pthread_attr_init", "");
exit(1);
}
@@ -621,7 +584,6 @@ int main(int argc, char *argv[])
local_client_head.fd = clops->get_main_cluster_fd();
local_client_head.type = CLUSTER_MAIN_SOCK;
local_client_head.callback = clops->cluster_fd_callback;
_local_client_count++;
/* Add the local socket to the list */
if (!(newfd = dm_zalloc(sizeof(struct local_client)))) {
@@ -632,14 +594,14 @@ int main(int argc, char *argv[])
newfd->fd = local_sock;
newfd->type = LOCAL_RENDEZVOUS;
newfd->callback = local_rendezvous_callback;
(void) add_client(newfd);
newfd->next = local_client_head.next;
local_client_head.next = newfd;
/* This needs to be started after cluster initialisation
as it may need to take out locks */
DEBUGLOG("Starting LVM thread\n");
DEBUGLOG("(%p) Main cluster socket fd %d with local socket %d (%p)\n",
&local_client_head, local_client_head.fd, newfd->fd, newfd);
DEBUGLOG("Main cluster socket fd %d (%p) with local socket %d (%p)\n",
local_client_head.fd, &local_client_head, newfd->fd, newfd);
/* Don't let anyone else to do work until we are started */
if (pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params)) {
@@ -675,7 +637,6 @@ int main(int argc, char *argv[])
while ((delfd = local_client_head.next)) {
local_client_head.next = delfd->next;
_local_client_count--;
/* Failing cleanup_zombie leaks... */
if (delfd->type == LOCAL_SOCK && !cleanup_zombie(delfd))
cmd_client_cleanup(delfd); /* calls sync_unlock */
@@ -737,13 +698,13 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
pthread_mutex_init(&newfd->bits.localsock.mutex, NULL);
if (fcntl(client_fd, F_SETFD, 1))
DEBUGLOG("(%p) Setting CLOEXEC on client fd %d failed: %s\n", thisfd, client_fd, strerror(errno));
DEBUGLOG("Setting CLOEXEC on client fd failed: %s\n", strerror(errno));
newfd->fd = client_fd;
newfd->type = LOCAL_SOCK;
newfd->callback = local_sock_callback;
newfd->bits.localsock.all_success = 1;
DEBUGLOG("(%p) Got new connection on fd %d\n", newfd, newfd->fd);
DEBUGLOG("Got new connection on fd %d (%p)\n", newfd->fd, newfd);
*new_client = newfd;
}
return 1;
@@ -765,8 +726,8 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
if (len == sizeof(int))
memcpy(&status, buffer, sizeof(int));
DEBUGLOG("(%p) Read on pipe %d, %d bytes, status %d\n",
thisfd, thisfd->fd, len, status);
DEBUGLOG("Read on pipe %d, %d bytes, status %d\n",
thisfd->fd, len, status);
/* EOF on pipe or an error, close it */
if (len <= 0) {
@@ -789,11 +750,11 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
}
return -1;
} else {
DEBUGLOG("(%p) Background routine status was %d, sock_client %p\n",
thisfd, status, sock_client);
DEBUGLOG("Background routine status was %d, sock_client (%p)\n",
status, sock_client);
/* But has the client gone away ?? */
if (!sock_client) {
DEBUGLOG("(%p) Got pipe response for dead client, ignoring it\n", thisfd);
DEBUGLOG("Got pipe response for dead client, ignoring it\n");
} else {
/* If error then just return that code */
if (status)
@@ -833,7 +794,7 @@ static void timedout_callback(struct local_client *client, const char *csid,
return;
clops->name_from_csid(csid, nodename);
DEBUGLOG("(%p) Checking for a reply from %s\n", client, nodename);
DEBUGLOG("Checking for a reply from %s\n", nodename);
pthread_mutex_lock(&client->bits.localsock.mutex);
reply = client->bits.localsock.replies;
@@ -843,7 +804,7 @@ static void timedout_callback(struct local_client *client, const char *csid,
pthread_mutex_unlock(&client->bits.localsock.mutex);
if (!reply) {
DEBUGLOG("(%p) Node %s timed-out\n", client, nodename);
DEBUGLOG("Node %s timed-out\n", nodename);
add_reply_to_list(client, ETIMEDOUT, csid,
"Command timed out", 18);
}
@@ -858,7 +819,7 @@ static void timedout_callback(struct local_client *client, const char *csid,
*/
static void request_timed_out(struct local_client *client)
{
DEBUGLOG("(%p) Request timed-out. padding\n", client);
DEBUGLOG("Request timed-out. padding\n");
clops->cluster_do_node_callback(client, timedout_callback);
if (!client->bits.localsock.threadid)
@@ -892,11 +853,13 @@ static void main_loop(int cmd_timeout)
while (!quit) {
fd_set in;
int select_status;
struct local_client *thisfd, *nextfd;
struct local_client *thisfd;
struct timeval tv = { cmd_timeout, 0 };
int quorate = clops->is_quorate();
int client_count = 0;
int max_fd = 0;
struct local_client *lastfd = &local_client_head;
struct local_client *nextfd = local_client_head.next;
/* Wait on the cluster FD and all local sockets/pipes */
local_client_head.fd = clops->get_main_cluster_fd();
@@ -912,22 +875,21 @@ static void main_loop(int cmd_timeout)
fprintf(stderr, "WARNING: Your cluster may freeze up if the number of clvmd file descriptors (%d) exceeds %d.\n", max_fd + 1, FD_SETSIZE);
}
for (thisfd = &local_client_head; thisfd; thisfd = nextfd) {
nextfd = thisfd->next;
for (thisfd = &local_client_head; thisfd; thisfd = nextfd, nextfd = thisfd ? thisfd->next : NULL) {
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
/* cleanup_zombie might have removed the next list element */
nextfd = thisfd->next;
(void) _del_client(thisfd);
DEBUGLOG("(%p) removeme set with %d monitored fds remaining\n", thisfd, _local_client_count);
struct local_client *free_fd = thisfd;
lastfd->next = nextfd;
DEBUGLOG("removeme set for %p with %d monitored fds remaining\n", free_fd, client_count - 1);
/* Queue cleanup, this also frees the client struct */
add_to_lvmqueue(thisfd, NULL, 0, NULL);
add_to_lvmqueue(free_fd, NULL, 0, NULL);
continue;
}
lastfd = thisfd;
if (thisfd->removeme)
continue;
@@ -977,15 +939,16 @@ static void main_loop(int cmd_timeout)
type == CLUSTER_INTERNAL)
goto closedown;
DEBUGLOG("(%p) ret == %d, errno = %d. removing client\n",
thisfd, ret, errno);
DEBUGLOG("ret == %d, errno = %d. removing client\n",
ret, errno);
thisfd->removeme = 1;
continue;
}
/* New client...simply add it to the list */
if (newfd) {
_add_client(newfd, thisfd);
newfd->next = thisfd->next;
thisfd->next = newfd;
thisfd = newfd;
}
}
@@ -1003,8 +966,8 @@ static void main_loop(int cmd_timeout)
thisfd->bits.localsock.expected_replies !=
thisfd->bits.localsock.num_replies) {
/* Send timed out message + replies we already have */
DEBUGLOG("Request to client %p timed-out (send: %ld, now: %ld)\n",
thisfd, thisfd->bits.localsock.sent_time, the_time);
DEBUGLOG("Request timed-out (send: %ld, now: %ld)\n",
thisfd->bits.localsock.sent_time, the_time);
thisfd->bits.localsock.all_success = 0;
@@ -1105,31 +1068,31 @@ static void be_daemon(int timeout)
break;
default: /* Parent */
(void) close(devnull);
(void) close(child_pipe[1]);
wait_for_child(child_pipe[0], timeout); /* noreturn */
wait_for_child(child_pipe[0], timeout);
}
/* Detach ourself from the calling environment */
if ((dup2(devnull, STDIN_FILENO) == -1) ||
(dup2(devnull, STDOUT_FILENO) == -1) ||
(dup2(devnull, STDERR_FILENO) == -1)) {
if (close(0) || close(1) || close(2)) {
perror("Error closing terminal FDs");
exit(4);
}
setsid();
if (dup2(devnull, 0) < 0 || dup2(devnull, 1) < 0
|| dup2(devnull, 2) < 0) {
perror("Error setting terminal FDs to /dev/null");
log_error("Error setting terminal FDs to /dev/null: %m");
exit(5);
}
if ((devnull > STDERR_FILENO) && close(devnull)) {
log_sys_error("close", "/dev/null");
exit(7);
}
if (chdir("/")) {
log_error("Error setting current directory to /: %m");
exit(6);
}
setsid();
}
static int verify_message(char *buf, int len)
@@ -1216,8 +1179,8 @@ static int cleanup_zombie(struct local_client *thisfd)
if (!thisfd->bits.localsock.cleanup_needed)
return 0;
DEBUGLOG("(%p) EOF on local socket %d: inprogress=%d\n",
thisfd, thisfd->fd, thisfd->bits.localsock.in_progress);
DEBUGLOG("EOF on local socket: inprogress=%d\n",
thisfd->bits.localsock.in_progress);
if ((pipe_client = thisfd->bits.localsock.pipe_client))
pipe_client = pipe_client->bits.pipe.client;
@@ -1239,7 +1202,7 @@ static int cleanup_zombie(struct local_client *thisfd)
/* Kill the subthread & free resources */
if (thisfd->bits.localsock.threadid) {
DEBUGLOG("(%p) Waiting for pre&post thread\n", pipe_client);
DEBUGLOG("Waiting for pre&post thread (%p)\n", pipe_client);
pthread_mutex_lock(&thisfd->bits.localsock.mutex);
thisfd->bits.localsock.state = PRE_COMMAND;
thisfd->bits.localsock.finished = 1;
@@ -1250,22 +1213,26 @@ static int cleanup_zombie(struct local_client *thisfd)
(void **) &status)))
log_sys_error("pthread_join", "");
DEBUGLOG("(%p) Joined pre&post thread\n", pipe_client);
DEBUGLOG("Joined pre&post thread\n");
thisfd->bits.localsock.threadid = 0;
/* Remove the pipe client */
if (thisfd->bits.localsock.pipe_client) {
struct local_client *delfd = thisfd->bits.localsock.pipe_client;
struct local_client *delfd;
struct local_client *lastfd;
(void) close(delfd->fd); /* Close pipe */
(void) close(thisfd->bits.localsock.pipe_client->fd); /* Close pipe */
(void) close(thisfd->bits.localsock.pipe);
/* Remove pipe client */
if (!_del_client(delfd)) {
dm_free(delfd);
thisfd->bits.localsock.pipe_client = NULL;
}
for (lastfd = &local_client_head; (delfd = lastfd->next); lastfd = delfd)
if (thisfd->bits.localsock.pipe_client == delfd) {
thisfd->bits.localsock.pipe_client = NULL;
lastfd->next = delfd->next;
dm_free(delfd);
break;
}
}
}
@@ -1296,7 +1263,7 @@ static int read_from_local_sock(struct local_client *thisfd)
if (len == -1 && errno == EINTR)
return 1;
DEBUGLOG("(%p) Read on local socket %d, len = %d\n", thisfd, thisfd->fd, len);
DEBUGLOG("Read on local socket %d, len = %d\n", thisfd->fd, len);
if (len && verify_message(buffer, len) < 0) {
log_error("read_from_local_sock from %d len %d bad verify.",
@@ -1370,15 +1337,15 @@ static int read_from_local_sock(struct local_client *thisfd)
char *argptr = inheader->node + strlen(inheader->node) + 1;
while (missing_len > 0) {
DEBUGLOG("(%p) got %d bytes, need another %d (total %d)\n",
thisfd, argslen, missing_len, inheader->arglen);
DEBUGLOG("got %d bytes, need another %d (total %d)\n",
argslen, missing_len, inheader->arglen);
len = read(thisfd->fd, argptr + argslen, missing_len);
if (len == -1 && errno == EINTR)
continue;
if (len <= 0) {
/* EOF or error on socket */
DEBUGLOG("(%p) EOF on local socket\n", thisfd);
DEBUGLOG("EOF on local socket\n");
dm_free(thisfd->bits.localsock.cmd);
thisfd->bits.localsock.cmd = NULL;
return 0;
@@ -1406,7 +1373,7 @@ static int read_from_local_sock(struct local_client *thisfd)
.status = ENOENT
};
DEBUGLOG("(%p) Unknown node: '%s'\n", thisfd, inheader->node);
DEBUGLOG("Unknown node: '%s'\n", inheader->node);
send_message(&reply, sizeof(reply), our_csid, thisfd->fd,
"Error sending ENOENT reply to local user");
thisfd->bits.localsock.expected_replies = 0;
@@ -1432,7 +1399,7 @@ static int read_from_local_sock(struct local_client *thisfd)
.status = EBUSY
};
DEBUGLOG("(%p) Creating pipe failed: %s\n", thisfd, strerror(errno));
DEBUGLOG("Creating pipe failed: %s\n", strerror(errno));
send_message(&reply, sizeof(reply), our_csid, thisfd->fd,
"Error sending EBUSY reply to local user");
return len;
@@ -1452,7 +1419,7 @@ static int read_from_local_sock(struct local_client *thisfd)
return len;
}
DEBUGLOG("(%p) Creating pipe, [%d, %d]\n", thisfd, comms_pipe[0], comms_pipe[1]);
DEBUGLOG("Creating pipe, [%d, %d]\n", comms_pipe[0], comms_pipe[1]);
if (fcntl(comms_pipe[0], F_SETFD, 1))
DEBUGLOG("setting CLOEXEC on pipe[0] failed: %s\n", strerror(errno));
@@ -1463,8 +1430,8 @@ static int read_from_local_sock(struct local_client *thisfd)
newfd->type = THREAD_PIPE;
newfd->callback = local_pipe_callback;
newfd->bits.pipe.client = thisfd;
_add_client(newfd, thisfd);
newfd->next = thisfd->next;
thisfd->next = newfd;
/* Store a cross link to the pipe */
thisfd->bits.localsock.pipe_client = newfd;
@@ -1477,10 +1444,10 @@ static int read_from_local_sock(struct local_client *thisfd)
thisfd->bits.localsock.in_progress = TRUE;
thisfd->bits.localsock.state = PRE_COMMAND;
thisfd->bits.localsock.cleanup_needed = 1;
DEBUGLOG("(%p) Creating pre&post thread for pipe fd %d\n", newfd, newfd->fd);
DEBUGLOG("Creating pre&post thread for pipe fd %d (%p)\n", newfd->fd, newfd);
status = pthread_create(&thisfd->bits.localsock.threadid,
&stack_attr, pre_and_post_thread, thisfd);
DEBUGLOG("(%p) Created pre&post thread, state = %d\n", newfd, status);
DEBUGLOG("Created pre&post thread, state = %d\n", status);
return len;
}
@@ -1488,6 +1455,13 @@ static int read_from_local_sock(struct local_client *thisfd)
/* Add a file descriptor from the cluster or comms interface to
our list of FDs for select
*/
int add_client(struct local_client *new_client)
{
new_client->next = local_client_head.next;
local_client_head.next = new_client;
return 0;
}
/* Called when the pre-command has completed successfully - we
now execute the real command on all the requested nodes */
@@ -1498,8 +1472,8 @@ static int distribute_command(struct local_client *thisfd)
int len = thisfd->bits.localsock.cmd_len;
thisfd->xid = global_xid++;
DEBUGLOG("(%p) distribute command: XID = %d, flags=0x%x (%s%s)\n",
thisfd, thisfd->xid, inheader->flags,
DEBUGLOG("distribute command: XID = %d, flags=0x%x (%s%s)\n",
thisfd->xid, inheader->flags,
(inheader->flags & CLVMD_FLAG_LOCAL) ? "LOCAL" : "",
(inheader->flags & CLVMD_FLAG_REMOTE) ? "REMOTE" : "");
@@ -1521,7 +1495,7 @@ static int distribute_command(struct local_client *thisfd)
*/
add_to_lvmqueue(thisfd, inheader, len, NULL);
DEBUGLOG("(%p) Sending message to all cluster nodes\n", thisfd);
DEBUGLOG("Sending message to all cluster nodes\n");
inheader->xid = thisfd->xid;
send_message(inheader, len, NULL, -1,
"Error forwarding message to cluster");
@@ -1540,11 +1514,11 @@ static int distribute_command(struct local_client *thisfd)
/* Are we the requested node ?? */
if (memcmp(csid, our_csid, max_csid_len) == 0) {
DEBUGLOG("(%p) Doing command on local node only\n", thisfd);
DEBUGLOG("Doing command on local node only\n");
add_to_lvmqueue(thisfd, inheader, len, NULL);
} else {
DEBUGLOG("(%p) Sending message to single node: %s\n",
thisfd, inheader->node);
DEBUGLOG("Sending message to single node: %s\n",
inheader->node);
inheader->xid = thisfd->xid;
send_message(inheader, len, csid, -1,
"Error forwarding message to cluster node");
@@ -1555,7 +1529,7 @@ static int distribute_command(struct local_client *thisfd)
thisfd->bits.localsock.in_progress = TRUE;
thisfd->bits.localsock.expected_replies = 1;
thisfd->bits.localsock.num_replies = 0;
DEBUGLOG("(%p) Doing command explicitly on local node only\n", thisfd);
DEBUGLOG("Doing command explicitly on local node only\n");
add_to_lvmqueue(thisfd, inheader, len, NULL);
}
@@ -1681,7 +1655,7 @@ static void add_reply_to_list(struct local_client *client, int status,
reply->status = status;
clops->name_from_csid(csid, reply->node);
DEBUGLOG("(%p) Reply from node %s: %d bytes\n", client, reply->node, len);
DEBUGLOG("Reply from node %s: %d bytes\n", reply->node, len);
if (len > 0) {
if (!(reply->replymsg = dm_malloc(len)))
@@ -1708,8 +1682,8 @@ static void add_reply_to_list(struct local_client *client, int status,
client->bits.localsock.state = POST_COMMAND;
pthread_cond_signal(&client->bits.localsock.cond);
}
DEBUGLOG("(%p) Got %d replies, expecting: %d\n",
client, client->bits.localsock.num_replies,
DEBUGLOG("Got %d replies, expecting: %d\n",
client->bits.localsock.num_replies,
client->bits.localsock.expected_replies);
}
pthread_mutex_unlock(&client->bits.localsock.mutex);
@@ -1724,7 +1698,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
sigset_t ss;
int pipe_fd = client->bits.localsock.pipe;
DEBUGLOG("(%p) Pre&post thread pipe fd %d\n", client, pipe_fd);
DEBUGLOG("Pre&post thread (%p), pipe fd %d\n", client, pipe_fd);
pthread_mutex_lock(&client->bits.localsock.mutex);
/* Ignore SIGUSR1 (handled by master process) but enable
@@ -1744,7 +1718,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
if ((status = do_pre_command(client)))
client->bits.localsock.all_success = 0;
DEBUGLOG("(%p) Pre&post thread writes status %d down to pipe fd %d\n",
DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe fd %d\n",
client, status, pipe_fd);
/* Tell the parent process we have finished this bit */
@@ -1762,13 +1736,13 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
/* We may need to wait for the condition variable before running the post command */
if (client->bits.localsock.state != POST_COMMAND &&
!client->bits.localsock.finished) {
DEBUGLOG("(%p) Pre&post thread waiting to do post command, state = %d\n",
DEBUGLOG("Pre&post thread (%p) waiting to do post command, state = %d\n",
client, client->bits.localsock.state);
pthread_cond_wait(&client->bits.localsock.cond,
&client->bits.localsock.mutex);
}
DEBUGLOG("(%p) Pre&post thread got post command condition...\n", client);
DEBUGLOG("Pre&post thread (%p) got post command condition...\n", client);
/* POST function must always run, even if the client aborts */
status = 0;
@@ -1782,15 +1756,15 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
next_pre:
if (client->bits.localsock.state != PRE_COMMAND &&
!client->bits.localsock.finished) {
DEBUGLOG("(%p) Pre&post thread waiting for next pre command\n", client);
DEBUGLOG("Pre&post thread (%p) waiting for next pre command\n", client);
pthread_cond_wait(&client->bits.localsock.cond,
&client->bits.localsock.mutex);
}
DEBUGLOG("(%p) Pre&post thread got pre command condition...\n", client);
DEBUGLOG("Pre&post thread (%p) got pre command condition...\n", client);
}
pthread_mutex_unlock(&client->bits.localsock.mutex);
DEBUGLOG("(%p) Pre&post thread finished\n", client);
DEBUGLOG("Pre&post thread (%p) finished\n", client);
pthread_exit(NULL);
}
@@ -1808,8 +1782,8 @@ static int process_local_command(struct clvm_header *msg, int msglen,
if (!(replybuf = dm_malloc(max_cluster_message)))
return -1;
DEBUGLOG("(%p) process_local_command: %s msg=%p, msglen =%d\n",
client, decode_cmd(msg->cmd), msg, msglen);
DEBUGLOG("process_local_command: %s msg=%p, msglen =%d, client=%p\n",
decode_cmd(msg->cmd), msg, msglen, client);
/* If remote flag is set, just set a successful status code. */
if (msg->flags & CLVMD_FLAG_REMOTE)
@@ -1824,8 +1798,8 @@ static int process_local_command(struct clvm_header *msg, int msglen,
if (xid == client->xid)
add_reply_to_list(client, status, our_csid, replybuf, replylen);
else
DEBUGLOG("(%p) Local command took too long, discarding xid %d, current is %d\n",
client, xid, client->xid);
DEBUGLOG("Local command took too long, discarding xid %d, current is %d\n",
xid, client->xid);
dm_free(replybuf);
@@ -1867,7 +1841,7 @@ static void send_local_reply(struct local_client *client, int status, int fd)
char *ptr;
int message_len = 0;
DEBUGLOG("(%p) Send local reply\n", client);
DEBUGLOG("Send local reply\n");
/* Work out the total size of the reply */
while (thisreply) {
@@ -1884,7 +1858,7 @@ static void send_local_reply(struct local_client *client, int status, int fd)
/* Add in the size of our header */
message_len = message_len + sizeof(struct clvm_header);
if (!(replybuf = dm_malloc(message_len))) {
DEBUGLOG("(%p) Memory allocation fails\n", client);
DEBUGLOG("Memory allocation fails\n");
return;
}
@@ -1999,9 +1973,6 @@ static int send_message(void *buf, int msglen, const char *csid, int fd,
return clops->cluster_send_message(buf, msglen, csid, errtext);
}
if (fd < 0)
return 0;
/* Make sure it all goes */
for (ptr = 0; ptr < msglen;) {
if ((len = write(fd, (char*)buf + ptr, msglen - ptr)) <= 0) {
@@ -2016,7 +1987,6 @@ static int send_message(void *buf, int msglen, const char *csid, int fd,
(void) nanosleep (&delay, &remtime);
continue;
}
DEBUGLOG("%s", errtext);
log_error("%s", errtext);
break;
}
@@ -2030,7 +2000,7 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
{
/* If msg is NULL then this is a cleanup request */
if (cmd->msg == NULL) {
DEBUGLOG("(%p) process_work_item: free\n", cmd->client);
DEBUGLOG("process_work_item: free %p\n", cmd->client);
cmd_client_cleanup(cmd->client);
pthread_mutex_destroy(&cmd->client->bits.localsock.mutex);
pthread_cond_destroy(&cmd->client->bits.localsock.cond);
@@ -2039,11 +2009,11 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
}
if (!cmd->remote) {
DEBUGLOG("(%p) process_work_item: local\n", cmd->client);
DEBUGLOG("process_work_item: local\n");
process_local_command(cmd->msg, cmd->msglen, cmd->client,
cmd->xid);
} else {
DEBUGLOG("(%p) process_work_item: remote\n", cmd->client);
DEBUGLOG("process_work_item: remote\n");
process_remote_command(cmd->msg, cmd->msglen, cmd->client->fd,
cmd->csid);
}
@@ -2137,8 +2107,8 @@ static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
} else
cmd->remote = 0;
DEBUGLOG("(%p) add_to_lvmqueue: cmd=%p, msg=%p, len=%d, csid=%p, xid=%d\n",
client, cmd, msg, msglen, csid, cmd->xid);
DEBUGLOG("add_to_lvmqueue: cmd=%p. client=%p, msg=%p, len=%d, csid=%p, xid=%d\n",
cmd, client, msg, msglen, csid, cmd->xid);
pthread_mutex_lock(&lvm_thread_mutex);
if (lvm_thread_exit) {
pthread_mutex_unlock(&lvm_thread_mutex);
@@ -2154,14 +2124,6 @@ static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
}
/* Return 0 if we can talk to an existing clvmd */
/*
* FIXME:
*
* This function returns only -1 or 0, but there are
* different levels of errors, some of them should stop
* further execution of clvmd thus another state is needed
* and some error message need to be only informational.
*/
static int check_local_clvmd(void)
{
int local_socket;
@@ -2181,11 +2143,7 @@ static int check_local_clvmd(void)
if (connect(local_socket,(struct sockaddr *) &sockaddr,
sizeof(sockaddr))) {
/* connection failure is expected state */
if (errno == ENOENT)
log_sys_debug("connect", "local socket");
else
log_sys_error("connect", "local socket");
log_sys_error("connect", "local socket");
ret = -1;
}
@@ -2286,8 +2244,7 @@ static void check_all_callback(struct local_client *client, const char *csid,
If not, returns -1 and prints out a list of errant nodes */
static int check_all_clvmds_running(struct local_client *client)
{
DEBUGLOG("(%p) check_all_clvmds_running\n", client);
DEBUGLOG("check_all_clvmds_running\n");
return clops->cluster_do_node_callback(client, check_all_callback);
}
@@ -2326,11 +2283,13 @@ static void ntoh_clvm(struct clvm_header *hdr)
static void sigusr2_handler(int sig)
{
DEBUGLOG("SIGUSR2 received\n");
return;
}
static void sigterm_handler(int sig)
{
quit = 1;
return;
}
static void sighup_handler(int sig)

View File

@@ -661,9 +661,10 @@ int do_refresh_cache(void)
return -1;
}
init_full_scan_done(0);
init_ignore_suspended_devices(1);
lvmcache_force_next_label_scan();
lvmcache_label_scan(cmd);
label_scan_destroy(cmd); /* destroys bcache (to close devs), keeps lvmcache */
dm_pool_empty(cmd->mem);
pthread_mutex_unlock(&lvm_lock);
@@ -806,7 +807,8 @@ static void lvm2_log_fn(int level, const char *file, int line, int dm_errno,
if (level != _LOG_ERR && level != _LOG_FATAL)
return;
(void) dm_strncpy(last_error, message, sizeof(last_error));
strncpy(last_error, message, sizeof(last_error));
last_error[sizeof(last_error)-1] = '\0';
}
/* This checks some basic cluster-LVM configuration stuff */

View File

@@ -29,7 +29,7 @@ include $(top_builddir)/make.tmpl
LIBS += -ldevmapper
LMLIBS += $(CPG_LIBS) $(SACKPT_LIBS)
CFLAGS += $(CPG_CFLAGS) $(SACKPT_CFLAGS) $(EXTRA_EXEC_CFLAGS)
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
LDFLAGS += $(EXTRA_EXEC_LDFLAGS)
cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \

View File

@@ -166,9 +166,6 @@ int cluster_send(struct clog_request *rq)
{
int r;
int found = 0;
#if CMIRROR_HAS_CHECKPOINT
int count = 0;
#endif
struct iovec iov;
struct clog_cpg *entry;
@@ -185,7 +182,7 @@ int cluster_send(struct clog_request *rq)
}
/*
* Once the request heads for the cluster, the luid loses
* Once the request heads for the cluster, the luid looses
* all its meaning.
*/
rq->u_rq.luid = 0;
@@ -206,6 +203,8 @@ int cluster_send(struct clog_request *rq)
#if CMIRROR_HAS_CHECKPOINT
do {
int count = 0;
r = cpg_mcast_joined(entry->handle, CPG_TYPE_AGREED, &iov, 1);
if (r != SA_AIS_ERR_TRY_AGAIN)
break;
@@ -1631,7 +1630,7 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
size = ((strlen(uuid) + 1) > CPG_MAX_NAME_LENGTH) ?
CPG_MAX_NAME_LENGTH : (strlen(uuid) + 1);
(void) dm_strncpy(new->name.value, uuid, size);
strncpy(new->name.value, uuid, size);
new->name.length = (uint32_t)size;
new->luid = luid;

View File

@@ -377,7 +377,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
uint32_t block_on_error = 0;
int disk_log;
char disk_path[PATH_MAX];
char disk_path[128];
int unlink_path = 0;
long page_size;
int pages;
@@ -451,19 +451,15 @@ static int _clog_ctr(char *uuid, uint64_t luid,
lc->skip_bit_warning = region_count;
lc->disk_fd = -1;
lc->log_dev_failed = 0;
if (!dm_strncpy(lc->uuid, uuid, DM_UUID_LEN)) {
LOG_ERROR("Cannot use too long UUID %s.", uuid);
r = -EINVAL;
goto fail;
}
strncpy(lc->uuid, uuid, DM_UUID_LEN);
lc->luid = luid;
if (get_log(lc->uuid, lc->luid) ||
get_pending_log(lc->uuid, lc->luid)) {
LOG_ERROR("[%s/%" PRIu64 "u] Log already exists, unable to create.",
SHORT_UUID(lc->uuid), lc->luid);
r = -EINVAL;
goto fail;
dm_free(lc);
return -EINVAL;
}
dm_list_init(&lc->mark_list);

View File

@@ -14,6 +14,7 @@
#define _LVM_CLOG_LOGGING_H
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include "configure.h"
#include <stdio.h>

View File

@@ -56,16 +56,18 @@ include $(top_builddir)/make.tmpl
all: device-mapper
device-mapper: $(TARGETS)
LIBS += -ldevmapper
LVMLIBS += -ldevmapper-event $(PTHREAD_LIBS)
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
LIBS += -ldevmapper $(PTHREAD_LIBS)
dmeventd: $(LIB_SHARED) dmeventd.o
$(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -L. -o $@ dmeventd.o \
$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a
$(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L. -L$(interfacebuilddir) -o $@ \
dmeventd.o $(DL_LIBS) $(LVMLIBS) $(LIBS) $(STATIC_LIBS)
ifeq ("@PKGCONFIG@", "yes")
INSTALL_LIB_TARGETS += install_pkgconfig

View File

@@ -62,8 +62,6 @@
#include <syslog.h>
#define DM_SIGNALED_EXIT 1
#define DM_SCHEDULED_EXIT 2
static volatile sig_atomic_t _exit_now = 0; /* set to '1' when signal is given to exit */
/* List (un)link macros. */
@@ -470,7 +468,7 @@ static int _pthread_create_smallstack(pthread_t *t, void *(*fun)(void *), void *
/*
* We use a smaller stack since it gets preallocated in its entirety
*/
pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE + getpagesize());
pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
/*
* If no-one will be waiting, we need to detach.
@@ -754,7 +752,6 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
struct thread_status *thread;
struct timespec timeout;
time_t curr_time;
int ret;
DEBUGLOG("Timeout thread starting.");
pthread_cleanup_push(_exit_timeout, NULL);
@@ -776,10 +773,7 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
} else {
DEBUGLOG("Sending SIGALRM to Thr %x for timeout.",
(int) thread->thread);
ret = pthread_kill(thread->thread, SIGALRM);
if (ret && (ret != ESRCH))
log_error("Unable to wakeup Thr %x for timeout: %s.",
(int) thread->thread, strerror(ret));
pthread_kill(thread->thread, SIGALRM);
}
_unlock_mutex();
}
@@ -869,7 +863,6 @@ static int _event_wait(struct thread_status *thread)
* This is so that you can break out of waiting on an event,
* either for a timeout event, or to cancel the thread.
*/
sigemptyset(&old);
sigemptyset(&set);
sigaddset(&set, SIGALRM);
if (pthread_sigmask(SIG_UNBLOCK, &set, &old) != 0) {
@@ -1757,7 +1750,7 @@ static void _init_thread_signals(void)
*/
static void _exit_handler(int sig __attribute__((unused)))
{
_exit_now = DM_SIGNALED_EXIT;
_exit_now = 1;
}
#ifdef __linux__
@@ -2255,14 +2248,11 @@ int main(int argc, char *argv[])
for (;;) {
if (_idle_since) {
if (_exit_now) {
if (_exit_now == DM_SCHEDULED_EXIT)
break; /* Only prints shutdown message */
log_info("dmeventd detected break while being idle "
"for %ld second(s), exiting.",
(long) (time(NULL) - _idle_since));
break;
}
if (idle_exit_timeout) {
} else if (idle_exit_timeout) {
now = time(NULL);
if (now < _idle_since)
_idle_since = now; /* clock change? */
@@ -2273,14 +2263,15 @@ int main(int argc, char *argv[])
break;
}
}
} else if (_exit_now == DM_SIGNALED_EXIT) {
_exit_now = DM_SCHEDULED_EXIT;
} else if (_exit_now) {
_exit_now = 0;
/*
* When '_exit_now' is set, signal has been received,
* but can not simply exit unless all
* threads are done processing.
*/
log_info("dmeventd received break, scheduling exit.");
log_warn("WARNING: There are still devices being monitored.");
log_warn("WARNING: Refusing to exit.");
}
_process_request(&fifos);
_cleanup_unused_threads();

View File

@@ -250,9 +250,10 @@ static int _daemon_read(struct dm_event_fifos *fifos,
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
log_error("Unable to read from event server.");
return 0;
else {
log_error("Unable to read from event server.");
return 0;
}
}
bytes += ret;
@@ -328,9 +329,10 @@ static int _daemon_write(struct dm_event_fifos *fifos,
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
log_error("Unable to talk to event daemon.");
return 0;
else {
log_error("Unable to talk to event daemon.");
return 0;
}
}
bytes += ret;
@@ -452,8 +454,7 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
if (close(fifos->client))
log_sys_debug("close", fifos->client_path);
return 1;
}
if (errno != ENXIO && errno != ENOENT) {
} else if (errno != ENXIO && errno != ENOENT) {
/* problem */
log_sys_error("open", fifos->client_path);
return 0;
@@ -754,10 +755,11 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
uuid = dm_task_get_uuid(dmt);
/* FIXME Distinguish errors connecting to daemon */
if ((ret = _do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
&msg, dmevh->dso, uuid, dmevh->mask, 0))) {
if (_do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
&msg, dmevh->dso, uuid, dmevh->mask, 0)) {
log_debug("%s: device not registered.", dm_task_get_name(dmt));
ret = -ENOENT;
goto fail;
}

View File

@@ -16,7 +16,23 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SUBDIRS += lvm2 snapshot raid thin mirror
SUBDIRS += lvm2
ifneq ("@MIRRORS@", "none")
SUBDIRS += mirror
endif
ifneq ("@SNAPSHOTS@", "none")
SUBDIRS += snapshot
endif
ifneq ("@RAID@", "none")
SUBDIRS += raid
endif
ifneq ("@THIN@", "none")
SUBDIRS += thin
endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS = lvm2 mirror snapshot raid thin

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2017 Red Hat, Inc. All rights reserved.
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -25,6 +25,7 @@
struct dso_state {
struct dm_pool *mem;
char cmd_lvscan[512];
char cmd_lvconvert[512];
};
@@ -98,8 +99,12 @@ static int _get_mirror_event(struct dso_state *state, char *params)
return r;
}
static int _remove_failed_devices(const char *cmd_lvconvert, const char *device)
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert,
const char *device)
{
if (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
log_warn("WARNING: Re-scan of mirrored device %s failed.", device);
/* if repair goes OK, report success even if lvscan has failed */
if (!dmeventd_lvm2_run_with_lock(cmd_lvconvert)) {
log_error("Repair of mirrored device %s failed.", device);
@@ -146,7 +151,9 @@ void process_event(struct dm_task *dmt,
break;
case ME_FAILURE:
log_error("Device failure in %s.", device);
if (!_remove_failed_devices(state->cmd_lvconvert, device))
if (!_remove_failed_devices(state->cmd_lvscan,
state->cmd_lvconvert,
device))
/* FIXME Why are all the error return codes unused? Get rid of them? */
log_error("Failed to remove faulty devices in %s.",
device);
@@ -176,10 +183,17 @@ int register_device(const char *device,
if (!dmeventd_lvm2_init_with_pool("mirror_state", state))
goto_bad;
/* CANNOT use --config as this disables cached content */
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
"lvconvert --repair --use-policies", device))
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
"lvscan --cache", device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
"lvconvert --repair --use-policies", device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
*user = state;
@@ -189,9 +203,6 @@ int register_device(const char *device,
bad:
log_error("Failed to monitor mirror %s.", device);
if (state)
dmeventd_lvm2_exit_with_pool(state);
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2017 Red Hat, Inc. All rights reserved.
* Copyright (C) 2005-2016 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -22,6 +22,7 @@
struct dso_state {
struct dm_pool *mem;
char cmd_lvscan[512];
char cmd_lvconvert[512];
uint64_t raid_devs[RAID_DEVS_ELEMS];
int failed;
@@ -58,23 +59,6 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
dead = 1;
}
/*
* if we are converting from non-RAID to RAID (e.g. linear -> raid1)
* and too many original devices die, such that we cannot continue
* the "recover" operation, the sync action will go to "idle", the
* unsynced devs will remain at 'a', and the original devices will
* NOT SWITCH TO 'D', but will remain at 'A' - hoping to be revived.
*
* This is simply the way the kernel works...
*/
if (!strcmp(status->sync_action, "idle") &&
(status->dev_health[0] == 'a') &&
(status->insync_regions < status->total_regions)) {
log_error("Primary sources for new RAID, %s, have failed.",
device);
dead = 1; /* run it through LVM repair */
}
if (dead) {
if (status->insync_regions < status->total_regions) {
if (!state->warned) {
@@ -90,6 +74,8 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
goto out; /* already reported */
state->failed = 1;
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvscan))
log_warn("WARNING: Re-scan of RAID device %s failed.", device);
/* if repair goes OK, report success even if lvscan has failed */
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
@@ -98,8 +84,6 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
}
} else {
state->failed = 0;
if (status->insync_regions == status->total_regions)
memset(&state->raid_devs, 0, sizeof(state->raid_devs));
log_info("%s array, %s, is %s in-sync.",
status->raid_type, device,
(status->insync_regions == status->total_regions) ? "now" : "not");
@@ -152,9 +136,14 @@ int register_device(const char *device,
if (!dmeventd_lvm2_init_with_pool("raid_state", state))
goto_bad;
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
"lvconvert --repair --use-policies", device))
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
"lvscan --cache", device) ||
!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
"lvconvert --config devices{ignore_suspended_devices=1} "
"--repair --use-policies", device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
*user = state;
@@ -164,9 +153,6 @@ int register_device(const char *device,
bad:
log_error("Failed to monitor RAID %s.", device);
if (state)
dmeventd_lvm2_exit_with_pool(state);
return 0;
}

View File

@@ -231,7 +231,7 @@ void process_event(struct dm_task *dmt,
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
log_warn("WARNING: Snapshot %s is now %.2f%% full.",
device, dm_percent_to_round_float(percent, 2));
device, dm_percent_to_float(percent));
/* Try to extend the snapshot, in accord with user-set policies */
if (!_extend(state->cmd_lvextend))
@@ -254,8 +254,10 @@ int register_device(const char *device,
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvextend,
sizeof(state->cmd_lvextend),
"lvextend --use-policies", device))
"lvextend --use-policies", device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
state->percent_check = CHECK_MINIMUM;
*user = state;
@@ -266,9 +268,6 @@ int register_device(const char *device,
bad:
log_error("Failed to monitor snapshot %s.", device);
if (state)
dmeventd_lvm2_exit_with_pool(state);
return 0;
}

View File

@@ -18,6 +18,7 @@
#include <sys/wait.h>
#include <stdarg.h>
#include <pthread.h>
/* TODO - move this mountinfo code into library to be reusable */
#ifdef __linux__
@@ -47,8 +48,10 @@ struct dso_state {
struct dm_pool *mem;
int metadata_percent_check;
int metadata_percent;
int metadata_warn_once;
int data_percent_check;
int data_percent;
int data_warn_once;
uint64_t known_metadata_size;
uint64_t known_data_size;
unsigned fails;
@@ -56,32 +59,34 @@ struct dso_state {
int restore_sigset;
sigset_t old_sigset;
pid_t pid;
char *argv[3];
char *cmd_str;
char **argv;
char cmd_str[1024];
};
DM_EVENT_LOG_FN("thin")
#define UUID_PREFIX "LVM-"
static int _run_command(struct dso_state *state)
{
char val[16];
char val[3][36];
char *env[] = { val[0], val[1], val[2], NULL };
int i;
/* Mark for possible lvm2 command we are running from dmeventd
* lvm2 will not try to talk back to dmeventd while processing it */
(void) setenv("LVM_RUN_BY_DMEVENTD", "1", 1);
(void) dm_snprintf(val[0], sizeof(val[0]), "LVM_RUN_BY_DMEVENTD=1");
if (state->data_percent) {
/* Prepare some known data to env vars for easy use */
if (dm_snprintf(val, sizeof(val), "%d",
state->data_percent / DM_PERCENT_1) != -1)
(void) setenv("DMEVENTD_THIN_POOL_DATA", val, 1);
if (dm_snprintf(val, sizeof(val), "%d",
state->metadata_percent / DM_PERCENT_1) != -1)
(void) setenv("DMEVENTD_THIN_POOL_METADATA", val, 1);
(void) dm_snprintf(val[1], sizeof(val[1]), "DMEVENTD_THIN_POOL_DATA=%d",
state->data_percent / DM_PERCENT_1);
(void) dm_snprintf(val[2], sizeof(val[2]), "DMEVENTD_THIN_POOL_METADATA=%d",
state->metadata_percent / DM_PERCENT_1);
} else {
/* For an error event it's for a user to check status and decide */
log_debug("Error event processing.");
env[1] = NULL;
log_debug("Error event processing");
}
log_verbose("Executing command: %s", state->cmd_str);
@@ -95,7 +100,7 @@ static int _run_command(struct dso_state *state)
/* child */
(void) close(0);
for (i = 3; i < 255; ++i) (void) close(i);
execvp(state->argv[0], state->argv);
execve(state->argv[0], state->argv, env);
_exit(errno);
} else if (state->pid == -1) {
log_error("Can't fork command %s.", state->cmd_str);
@@ -111,7 +116,7 @@ static int _use_policy(struct dm_task *dmt, struct dso_state *state)
#if THIN_DEBUG
log_debug("dmeventd executes: %s.", state->cmd_str);
#endif
if (state->argv[0])
if (state->argv)
return _run_command(state);
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
@@ -170,8 +175,8 @@ void process_event(struct dm_task *dmt,
#if THIN_DEBUG
log_debug("Watch for tp-data:%.2f%% tp-metadata:%.2f%%.",
dm_percent_to_round_float(state->data_percent_check, 2),
dm_percent_to_round_float(state->metadata_percent_check, 2));
dm_percent_to_float(state->data_percent_check),
dm_percent_to_float(state->metadata_percent_check));
#endif
if (!_wait_for_pid(state)) {
log_warn("WARNING: Skipping event, child %d is still running (%s).",
@@ -249,10 +254,11 @@ void process_event(struct dm_task *dmt,
* action is called for: >50%, >55% ... >95%, 100%
*/
state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
if ((state->metadata_percent > WARNING_THRESH) &&
(state->metadata_percent > state->metadata_percent_check))
if (state->metadata_percent <= WARNING_THRESH)
state->metadata_warn_once = 0; /* Dropped bellow threshold, reset warn once */
else if (!state->metadata_warn_once++) /* Warn once when raised above threshold */
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
device, dm_percent_to_round_float(state->metadata_percent, 2));
device, dm_percent_to_float(state->metadata_percent));
if (state->metadata_percent > CHECK_MINIMUM) {
/* Run action when usage raised more than CHECK_STEP since the last time */
if (state->metadata_percent > state->metadata_percent_check)
@@ -264,10 +270,11 @@ void process_event(struct dm_task *dmt,
state->metadata_percent_check = CHECK_MINIMUM;
state->data_percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
if ((state->data_percent > WARNING_THRESH) &&
(state->data_percent > state->data_percent_check))
if (state->data_percent <= WARNING_THRESH)
state->data_warn_once = 0;
else if (!state->data_warn_once++)
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
device, dm_percent_to_round_float(state->data_percent, 2));
device, dm_percent_to_float(state->data_percent));
if (state->data_percent > CHECK_MINIMUM) {
/* Run action when usage raised more than CHECK_STEP since the last time */
if (state->data_percent > state->data_percent_check)
@@ -346,41 +353,34 @@ int register_device(const char *device,
void **user)
{
struct dso_state *state;
int maxcmd;
char *str;
char cmd_str[PATH_MAX + 128 + 2]; /* cmd ' ' vg/lv \0 */
if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
goto_bad;
if (!dmeventd_lvm2_command(state->mem, cmd_str, sizeof(cmd_str),
"_dmeventd_thin_command", device))
if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
sizeof(state->cmd_str),
"_dmeventd_thin_command", device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
if (strncmp(cmd_str, "lvm ", 4) == 0) {
if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str + 4))) {
log_error("Failed to copy lvm command.");
goto bad;
}
} else if (cmd_str[0] == '/') {
if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str))) {
log_error("Failed to copy thin command.");
if (strncmp(state->cmd_str, "lvm ", 4)) {
maxcmd = 2; /* space for last NULL element */
for (str = state->cmd_str; *str; str++)
if (*str == ' ')
maxcmd++;
if (!(str = dm_pool_strdup(state->mem, state->cmd_str)) ||
!(state->argv = dm_pool_zalloc(state->mem, maxcmd * sizeof(char *)))) {
log_error("Failed to allocate memory for command.");
goto bad;
}
/* Find last space before 'vg/lv' */
if (!(str = strrchr(state->cmd_str, ' ')))
goto inval;
if (!(state->argv[0] = dm_pool_strndup(state->mem, state->cmd_str,
str - state->cmd_str))) {
log_error("Failed to copy command.");
goto bad;
}
state->argv[1] = str + 1; /* 1 argument - vg/lv */
dm_split_words(str, maxcmd - 1, 0, state->argv);
_init_thread_signals(state);
} else /* Unuspported command format */
goto inval;
} else
memmove(state->cmd_str, state->cmd_str + 4, strlen(state->cmd_str + 4) + 1);
state->pid = -1;
*user = state;
@@ -388,14 +388,9 @@ int register_device(const char *device,
log_info("Monitoring thin pool %s.", device);
return 1;
inval:
log_error("Invalid command for monitoring: %s.", cmd_str);
bad:
log_error("Failed to monitor thin pool %s.", device);
if (state)
dmeventd_lvm2_exit_with_pool(state);
return 0;
}

View File

@@ -19,7 +19,7 @@ SOURCES = dmfilemapd.c
TARGETS = dmfilemapd
.PHONY: install_dmfilemapd install_dmfilemapd_static
.PHONY: install_dmeventd install_dmeventd_static
INSTALL_DMFILEMAPD_TARGETS = install_dmfilemapd_dynamic
@@ -34,16 +34,18 @@ include $(top_builddir)/make.tmpl
all: device-mapper
device-mapper: $(TARGETS)
CFLAGS_dmfilemapd.o += $(EXTRA_EXEC_CFLAGS)
LIBS += -ldevmapper
LVMLIBS += -ldevmapper-event $(PTHREAD_LIBS)
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
dmfilemapd: $(LIB_SHARED) dmfilemapd.o
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -L. -o $@ dmfilemapd.o \
$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
dmfilemapd.static: $(LIB_STATIC) dmfilemapd.o $(interfacebuilddir)/libdevmapper.a
$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L$(interfacebuilddir) \
-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS) $(STATIC_LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L. -L$(interfacebuilddir) -o $@ \
dmfilemapd.o $(DL_LIBS) $(LVMLIBS) $(LIBS) $(STATIC_LIBS)
ifneq ("$(CFLOW_CMD)", "")
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
@@ -59,8 +61,9 @@ install_dmfilemapd_dynamic: dmfilemapd
install_dmfilemapd_static: dmfilemapd.static
$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
install_dmfilemapd: $(INSTALL_DMFILEMAPD_TARGETS)
install_dmfilemapd: $(INSTALL_DMEVENTD_TARGETS)
install: install_dmfilemapd
install_device-mapper: install_dmfilemapd

View File

@@ -18,8 +18,6 @@
#include "dm-logging.h"
#include "defaults.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -45,24 +43,24 @@
struct filemap_monitor {
dm_filemapd_mode_t mode;
const char *program_id;
/* group_id to update */
uint64_t group_id;
char *path;
int fd;
int inotify_fd;
int inotify_watch_fd;
/* file to monitor */
int fd;
/* monitoring heuristics */
int64_t blocks; /* allocated blocks, from stat.st_blocks */
uint64_t nr_regions;
int64_t nr_regions;
int deleted;
};
static int _foreground;
static int _verbose;
const char *const _usage = "dmfilemapd <fd> <group_id> <abs_path> <mode> "
const char *const _usage = "dmfilemapd <fd> <group_id> <path> <mode> "
"[<foreground>[<log_level>]]";
/*
@@ -131,7 +129,7 @@ static void _setup_logging(void)
dm_log_with_errno_init(_dmfilemapd_log_with_errno);
}
#define PROC_FD_DELETED_STR "(deleted)"
#define PROC_FD_DELETED_STR " (deleted)"
/*
* Scan the /proc/<pid>/fd directory for pid and check for an fd
* symlink whose contents match path.
@@ -148,25 +146,23 @@ static int _is_open_in_pid(pid_t pid, const char *path)
if (pid == getpid())
return 0;
if (dm_snprintf(path_buf, sizeof(path_buf),
DEFAULT_PROC_DIR "%d/fd", pid) < 0) {
if (dm_snprintf(path_buf, sizeof(path_buf), "/proc/%d/fd", pid) < 0) {
log_error("Could not format pid path.");
return 0;
goto bad;
}
/*
* Test for the kernel 'file (deleted)' form when scanning.
*/
if (dm_snprintf(deleted_path, sizeof(deleted_path), "%s %s",
if (dm_snprintf(deleted_path, sizeof(deleted_path), "%s%s",
path, PROC_FD_DELETED_STR) < 0) {
log_error("Could not format check path.");
return 0;
}
pid_d = opendir(path_buf);
if (!pid_d) {
log_error("Could not open proc path: %s.", path_buf);
return 0;
goto bad;
}
while ((pid_dp = readdir(pid_d)) != NULL) {
@@ -174,27 +170,23 @@ static int _is_open_in_pid(pid_t pid, const char *path)
continue;
if ((len = readlinkat(dirfd(pid_d), pid_dp->d_name, link_buf,
sizeof(link_buf))) < 0) {
log_error("readlink failed for " DEFAULT_PROC_DIR
"/%d/fd/.", pid);
log_error("readlink failed for /proc/%d/fd/.", pid);
goto bad;
}
link_buf[len] = '\0';
if (!strcmp(deleted_path, link_buf)) {
if (closedir(pid_d))
log_sys_error("closedir", path_buf);
closedir(pid_d);
return 1;
}
}
bad:
if (closedir(pid_d))
log_sys_error("closedir", path_buf);
closedir(pid_d);
return 0;
}
/*
* Attempt to determine whether a file is open by any process by
* Attempt to guess detect whether a file is open by any process by
* scanning symbolic links in /proc/<pid>/fd.
*
* This is a heuristic since it cannot guarantee to detect brief
@@ -210,7 +202,7 @@ bad:
* files can no longer be newly opened by processes.
*
* In this situation !is_open(path) provides an indication that
* the daemon should shut down: the file has been unlinked from
* the daemon should shut down: the file has been unlinked form
* the file system and we appear to hold the final reference.
*/
static int _is_open(const char *path)
@@ -219,26 +211,21 @@ static int _is_open(const char *path)
DIR *proc_d = NULL;
pid_t pid;
proc_d = opendir(DEFAULT_PROC_DIR);
proc_d = opendir("/proc");
if (!proc_d)
return 0;
while ((proc_dp = readdir(proc_d)) != NULL) {
if (!isdigit(proc_dp->d_name[0]))
continue;
errno = 0;
pid = (pid_t) strtol(proc_dp->d_name, NULL, 10);
if (errno || !pid)
pid = strtol(proc_dp->d_name, NULL, 10);
if (!pid)
continue;
if (_is_open_in_pid(pid, path)) {
if (closedir(proc_d))
log_sys_error("closedir", DEFAULT_PROC_DIR);
closedir(proc_d);
return 1;
}
}
if (closedir(proc_d))
log_sys_error("closedir", DEFAULT_PROC_DIR);
closedir(proc_d);
return 0;
}
@@ -246,9 +233,9 @@ static void _filemap_monitor_wait(uint64_t usecs)
{
if (_verbose) {
if (usecs == FILEMAPD_WAIT_USECS)
log_very_verbose("Waiting for check interval");
log_very_verbose("waiting for FILEMAPD_WAIT");
if (usecs == FILEMAPD_NOFILE_WAIT_USECS)
log_very_verbose("Waiting for unlinked path");
log_very_verbose("waiting for FILEMAPD_NOFILE_WAIT");
}
usleep((useconds_t) usecs);
}
@@ -264,9 +251,11 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
if (argc < 5) {
_early_log("Wrong number of arguments.");
_early_log("usage: %s", _usage);
return 0;
return 1;
}
memset(fm, 0, sizeof(*fm));
/*
* We don't know the true nr_regions at daemon start time,
* and it is not worth a dm_stats_list()/group walk to count:
@@ -279,9 +268,8 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
fm->nr_regions = 1;
/* parse <fd> */
errno = 0;
fm->fd = (int) strtol(argv[0], &endptr, 10);
if (errno || *endptr) {
fm->fd = strtol(argv[0], &endptr, 10);
if (*endptr) {
_early_log("Could not parse file descriptor: %s", argv[0]);
return 0;
}
@@ -290,9 +278,8 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
argv++;
/* parse <group_id> */
errno = 0;
fm->group_id = strtoull(argv[0], &endptr, 10);
if (*endptr || errno) {
if (*endptr) {
_early_log("Could not parse group identifier: %s", argv[0]);
return 0;
}
@@ -305,12 +292,6 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
_early_log("Path argument is required.");
return 0;
}
if (*argv[0] != '/') {
_early_log("Path argument must specify an absolute path.");
return 0;
}
fm->path = dm_strdup(argv[0]);
if (!fm->path) {
_early_log("Could not allocate memory for path argument.");
@@ -335,9 +316,8 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
/* parse [<foreground>[<verbose>]] */
if (argc) {
errno = 0;
_foreground = (int) strtol(argv[0], &endptr, 10);
if (errno || *endptr) {
_foreground = strtol(argv[0], &endptr, 10);
if (*endptr) {
_early_log("Could not parse debug argument: %s.",
argv[0]);
return 0;
@@ -345,9 +325,8 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
argc--;
argv++;
if (argc) {
errno = 0;
_verbose = (int) strtol(argv[0], &endptr, 10);
if (errno || *endptr) {
_verbose = strtol(argv[0], &endptr, 10);
if (*endptr) {
_early_log("Could not parse verbose "
"argument: %s", argv[0]);
return 0;
@@ -362,47 +341,39 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
return 1;
}
static int _filemap_fd_update_blocks(struct filemap_monitor *fm)
static int _filemap_fd_check_changed(struct filemap_monitor *fm)
{
int64_t blocks, old_blocks;
struct stat buf;
if (fm->fd < 0) {
log_error("Filemap fd is not open.");
return 0;
return -1;
}
if (fstat(fm->fd, &buf)) {
log_error("Failed to fstat filemap file descriptor.");
return 0;
return -1;
}
fm->blocks = buf.st_blocks;
blocks = buf.st_blocks;
return 1;
}
/* first check? */
if (fm->blocks < 0)
old_blocks = buf.st_blocks;
else
old_blocks = fm->blocks;
static int _filemap_fd_check_changed(struct filemap_monitor *fm)
{
int64_t old_blocks;
old_blocks = fm->blocks;
if (!_filemap_fd_update_blocks(fm))
return -1;
fm->blocks = blocks;
return (fm->blocks != old_blocks);
}
static void _filemap_monitor_close_fd(struct filemap_monitor *fm)
{
if (close(fm->fd))
log_error("Error closing file descriptor.");
fm->fd = -1;
}
static void _filemap_monitor_end_notify(struct filemap_monitor *fm)
{
inotify_rm_watch(fm->inotify_fd, fm->inotify_watch_fd);
if (close(fm->inotify_fd))
log_error("Error closing inotify fd.");
}
static int _filemap_monitor_set_notify(struct filemap_monitor *fm)
@@ -415,13 +386,13 @@ static int _filemap_monitor_set_notify(struct filemap_monitor *fm)
* and does not fork or exec.
*/
if ((inotify_fd = inotify_init1(IN_NONBLOCK)) < 0) {
log_sys_error("inotify_init1", "IN_NONBLOCK");
_early_log("Failed to initialise inotify.");
return 0;
}
if ((watch_fd = inotify_add_watch(inotify_fd, fm->path,
IN_MODIFY | IN_DELETE_SELF)) < 0) {
log_sys_error("inotify_add_watch", fm->path);
_early_log("Failed to add inotify watch.");
return 0;
}
fm->inotify_fd = inotify_fd;
@@ -429,6 +400,13 @@ static int _filemap_monitor_set_notify(struct filemap_monitor *fm)
return 1;
}
static void _filemap_monitor_close_fd(struct filemap_monitor *fm)
{
if (close(fm->fd))
log_error("Error closing file descriptor.");
fm->fd = -1;
}
static int _filemap_monitor_reopen_fd(struct filemap_monitor *fm)
{
int tries = FILEMAPD_NOFILE_WAIT_TRIES;
@@ -440,6 +418,7 @@ static int _filemap_monitor_reopen_fd(struct filemap_monitor *fm)
*
* FIXME: stat file and skip if inode is unchanged.
*/
_filemap_monitor_end_notify(fm);
if (fm->fd > 0)
log_error("Filemap file descriptor already open.");
@@ -466,16 +445,8 @@ static int _filemap_monitor_get_events(struct filemap_monitor *fm)
ssize_t len;
char *ptr;
/*
* Close the file descriptor for the file being monitored here
* when mode=path: this will allow the inode to be de-allocated,
* and an IN_DELETE_SELF event generated in the case that the
* daemon is holding the last open reference to the file.
*/
if (fm->mode == DM_FILEMAPD_FOLLOW_PATH) {
_filemap_monitor_end_notify(fm);
if (fm->mode == DM_FILEMAPD_FOLLOW_PATH)
_filemap_monitor_close_fd(fm);
}
len = read(fm->inotify_fd, (void *) &buf, sizeof(buf));
@@ -536,10 +507,9 @@ static void _filemap_monitor_destroy(struct filemap_monitor *fm)
{
if (fm->fd > 0) {
_filemap_monitor_end_notify(fm);
_filemap_monitor_close_fd(fm);
if (close(fm->fd))
log_error("Error closing fd %d.", fm->fd);
}
dm_free((void *) fm->program_id);
dm_free(fm->path);
}
static int _filemap_monitor_check_same_file(int fd1, int fd2)
@@ -566,23 +536,19 @@ static int _filemap_monitor_check_file_unlinked(struct filemap_monitor *fm)
{
char path_buf[PATH_MAX];
char link_buf[PATH_MAX];
int same, fd;
ssize_t len;
int same, fd, len;
fm->deleted = 0;
same = 0;
if ((fd = open(fm->path, O_RDONLY)) < 0)
goto check_unlinked;
same = _filemap_monitor_check_same_file(fm->fd, fd);
if ((same = _filemap_monitor_check_same_file(fm->fd, fd)) < 0)
return 0;
if (close(fd))
log_error("Error closing fd %d", fd);
if (same < 0)
return 0;
if (same)
return 1;
@@ -592,32 +558,29 @@ check_unlinked:
* whether it is still reachable in the filesystem, or if it is
* unlinked and anonymous.
*/
if (dm_snprintf(path_buf, sizeof(path_buf), DEFAULT_PROC_DIR
"/%d/fd/%d", getpid(), fm->fd) < 0) {
if (dm_snprintf(path_buf, sizeof(path_buf),
"/proc/%d/fd/%d", getpid(), fm->fd) < 0) {
log_error("Could not format pid path.");
return 0;
}
if ((len = readlink(path_buf, link_buf, sizeof(link_buf) - 1)) < 0) {
log_error("readlink failed for " DEFAULT_PROC_DIR "/%d/fd/%d.",
if ((len = readlink(path_buf, link_buf, sizeof(link_buf))) < 0) {
log_error("readlink failed for /proc/%d/fd/%d.",
getpid(), fm->fd);
return 0;
}
link_buf[len] = '\0';
/*
* Try to re-open the file, from the path now reported in /proc/pid/fd.
*/
if ((fd = open(link_buf, O_RDONLY)) < 0)
fm->deleted = 1;
else
same = _filemap_monitor_check_same_file(fm->fd, fd);
if ((fd >= 0) && close(fd))
log_error("Error closing fd %d", fd);
if (same < 0)
if ((same = _filemap_monitor_check_same_file(fm->fd, fd)) < 0)
return 0;
if ((fd > 0) && close(fd))
log_error("Error closing fd %d", fd);
/* Should not happen with normal /proc. */
if ((fd > 0) && !same) {
log_error("File descriptor mismatch: %d and %s (read from %s) "
@@ -667,11 +630,11 @@ static int _daemonise(struct filemap_monitor *fm)
return 0;
}
}
/* TODO: Use libdaemon/server/daemon-server.c _daemonise() */
for (fd = (int) sysconf(_SC_OPEN_MAX) - 1; fd > STDERR_FILENO; fd--) {
for (fd = sysconf(_SC_OPEN_MAX) - 1; fd > STDERR_FILENO; fd--) {
if (fd == fm->fd)
continue;
(void) close(fd);
close(fd);
}
return 1;
@@ -691,15 +654,12 @@ static int _update_regions(struct dm_stats *dms, struct filemap_monitor *fm)
for (region = regions; *region != DM_STATS_REGIONS_ALL; region++)
nr_regions++;
if (!nr_regions)
log_warn("File contains no extents: exiting.");
if (nr_regions && (regions[0] != fm->group_id)) {
if (regions[0] != fm->group_id) {
log_warn("group_id changed from " FMTu64 " to " FMTu64,
fm->group_id, regions[0]);
fm->group_id = regions[0];
}
dm_free(regions);
fm->nr_regions = nr_regions;
return 1;
}
@@ -707,16 +667,9 @@ static int _update_regions(struct dm_stats *dms, struct filemap_monitor *fm)
static int _dmfilemapd(struct filemap_monitor *fm)
{
int running = 1, check = 0, open = 0;
const char *program_id;
struct dm_stats *dms;
/*
* The correct program_id is retrieved from the group leader
* following the call to dm_stats_list().
*/
if (!(dms = dm_stats_create(NULL)))
goto_bad;
dms = dm_stats_create("dmstats"); /* FIXME */
if (!dm_stats_bind_from_fd(dms, fm->fd)) {
log_error("Could not bind dm_stats handle to file descriptor "
"%d", fm->fd);
@@ -726,27 +679,12 @@ static int _dmfilemapd(struct filemap_monitor *fm)
if (!_filemap_monitor_set_notify(fm))
goto bad;
if (!_filemap_fd_update_blocks(fm))
goto bad;
if (!dm_stats_list(dms, DM_STATS_ALL_PROGRAMS)) {
log_error("Failed to list stats handle.");
goto bad;
}
/*
* Take the program_id for new regions (created by calls to
* dm_stats_update_regions_from_fd()) from the value used by
* the group leader.
*/
program_id = dm_stats_get_region_program_id(dms, fm->group_id);
if (program_id)
fm->program_id = dm_strdup(program_id);
else
fm->program_id = NULL;
dm_stats_set_program_id(dms, 1, program_id);
do {
if (!dm_stats_list(dms, NULL)) {
log_error("Failed to list stats handle.");
goto bad;
}
if (!dm_stats_group_present(dms, fm->group_id)) {
log_info("Filemap group removed: exiting.");
running = 0;
@@ -762,16 +700,17 @@ static int _dmfilemapd(struct filemap_monitor *fm)
if ((check = _filemap_fd_check_changed(fm)) < 0)
goto bad;
if (check && !_update_regions(dms, fm))
goto bad;
if (!check)
goto wait;
running = !!fm->nr_regions;
if (!running)
continue;
if (!_update_regions(dms, fm))
goto bad;
wait:
_filemap_monitor_wait(FILEMAPD_WAIT_USECS);
running = !!fm->nr_regions;
/* mode=inode termination condions */
if (fm->mode == DM_FILEMAPD_FOLLOW_INODE) {
if (!_filemap_monitor_check_file_unlinked(fm))
@@ -784,11 +723,6 @@ wait:
"continuing.");
}
if (!dm_stats_list(dms, NULL)) {
log_error("Failed to list stats handle.");
goto bad;
}
} while (running);
_filemap_monitor_destroy(fm);
@@ -802,7 +736,7 @@ bad:
return 1;
}
static const char * const _mode_names[] = {
static const char * _mode_names[] = {
"inode",
"path"
};
@@ -814,12 +748,8 @@ int main(int argc, char **argv)
{
struct filemap_monitor fm;
memset(&fm, 0, sizeof(fm));
if (!_parse_args(argc, argv, &fm)) {
dm_free(fm.path);
if (!_parse_args(argc, argv, &fm))
return 1;
}
_setup_logging();
@@ -827,10 +757,8 @@ int main(int argc, char **argv)
"mode=%s, path=%s", fm.fd, fm.group_id,
_mode_names[fm.mode], fm.path);
if (!_foreground && !_daemonise(&fm)) {
dm_free(fm.path);
if (!_foreground && !_daemonise(&fm))
return 1;
}
return _dmfilemapd(&fm);
}

View File

@@ -1,4 +1 @@
path.py
lvmdbusd
lvmdb.py
lvm_shell_proxy.py

View File

@@ -26,7 +26,9 @@ LVMDBUS_SRCDIR_FILES = \
__init__.py \
job.py \
loader.py \
lvmdb.py \
main.py \
lvm_shell_proxy.py \
lv.py \
manager.py \
objectmanager.py \
@@ -38,19 +40,14 @@ LVMDBUS_SRCDIR_FILES = \
vg.py
LVMDBUS_BUILDDIR_FILES = \
lvmdb.py \
lvm_shell_proxy.py \
path.py
LVMDBUSD = lvmdbusd
LVMDBUSD = $(srcdir)/lvmdbusd
include $(top_builddir)/make.tmpl
.PHONY: install_lvmdbusd
all:
test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
install_lvmdbusd:
$(INSTALL_DIR) $(sbindir)
$(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
@@ -66,5 +63,4 @@ install_lvm2: install_lvmdbusd
install: install_lvm2
DISTCLEAN_TARGETS+= \
$(LVMDBUS_BUILDDIR_FILES) \
$(LVMDBUSD)
$(LVMDBUS_BUILDDIR_FILES)

View File

@@ -38,7 +38,7 @@ class AutomatedProperties(dbus.service.Object):
props = {}
for i in self.interface():
props[i] = AutomatedProperties._get_all_prop(self, i)
props[i] = self.GetAll(i)
return self._ap_o_path, props
@@ -65,52 +65,31 @@ class AutomatedProperties(dbus.service.Object):
return self._ap_interface
@staticmethod
def _get_prop(obj, interface_name, property_name):
value = getattr(obj, property_name)
# Properties
# noinspection PyUnusedLocal
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='ss', out_signature='v')
def Get(self, interface_name, property_name):
value = getattr(self, property_name)
# Note: If we get an exception in this handler we won't know about it,
# only the side effect of no returned value!
log_debug('Get (%s), type (%s), value(%s)' %
(property_name, str(type(value)), str(value)))
return value
# Properties
# noinspection PyUnusedLocal
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='ss', out_signature='v',
async_callbacks=('cb', 'cbe'))
def Get(self, interface_name, property_name, cb, cbe):
# Note: If we get an exception in this handler we won't know about it,
# only the side effect of no returned value!
r = cfg.create_request_entry(
-1, AutomatedProperties._get_prop,
(self, interface_name, property_name),
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _get_all_prop(obj, interface_name):
if interface_name in obj.interface(True):
in_signature='s', out_signature='a{sv}')
def GetAll(self, interface_name):
if interface_name in self.interface(True):
# Using introspection, lets build this dynamically
properties = get_properties(obj)
properties = get_properties(self)
if interface_name in properties:
return properties[interface_name][1]
return {}
raise dbus.exceptions.DBusException(
obj._ap_interface,
self._ap_interface,
'The object %s does not implement the %s interface'
% (obj.__class__, interface_name))
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='s', out_signature='a{sv}',
async_callbacks=('cb', 'cbe'))
def GetAll(self, interface_name, cb, cbe):
r = cfg.create_request_entry(
-1, AutomatedProperties._get_all_prop,
(self, interface_name),
cb, cbe, False)
cfg.worker_q.put(r)
% (self.__class__, interface_name))
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='ssv')

View File

@@ -9,13 +9,11 @@
import subprocess
from . import cfg
from .cmdhandler import options_to_cli_args, LvmExecutionMeta
from .cmdhandler import options_to_cli_args
import dbus
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
add_no_notify
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
import os
import threading
import time
def pv_move_lv_cmd(move_options, lv_full_name,
@@ -44,15 +42,6 @@ def _move_merge(interface_name, command, job_state):
# the command always as we will be getting periodic output from them on
# the status of the long running operation.
command.insert(0, cfg.LVM_CMD)
# Instruct lvm to not register an event with us
command = add_no_notify(command)
#(self, start, ended, cmd, ec, stdout_txt, stderr_txt)
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
cfg.blackbox.add(meta)
process = subprocess.Popen(command, stdout=subprocess.PIPE,
env=os.environ,
stderr=subprocess.PIPE, close_fds=True)
@@ -70,21 +59,12 @@ def _move_merge(interface_name, command, job_state):
(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:
@@ -158,6 +138,5 @@ def _run_cmd(req):
def cmd_runner(request):
t = threading.Thread(target=_run_cmd, args=(request,),
name="cmd_runner %s" % str(request.method))
t = threading.Thread(target=_run_cmd, args=(request,))
t.start()

View File

@@ -26,7 +26,7 @@ bus = None
args = None
# Set to true if we are depending on external events for updates
got_external_event = False
ee = False
# Shared state variable across all processes
run = multiprocessing.Value('i', 1)
@@ -84,6 +84,3 @@ db = None
# lvm flight recorder
blackbox = None
# RequestEntry ctor
create_request_entry = None

View File

@@ -16,7 +16,7 @@ import traceback
import os
from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
try:
@@ -37,7 +37,6 @@ cmd_lock = threading.RLock()
class LvmExecutionMeta(object):
def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
self.lock = threading.RLock()
self.start = start
self.ended = ended
self.cmd = cmd
@@ -46,13 +45,12 @@ class LvmExecutionMeta(object):
self.stderr_txt = stderr_txt
def __str__(self):
with self.lock:
return "EC= %d for %s\n" \
"STARTED: %f, ENDED: %f\n" \
"STDOUT=%s\n" \
"STDERR=%s\n" % \
(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
self.stderr_txt)
return "EC= %d for %s\n" \
"STARTED: %f, ENDED: %f\n" \
"STDOUT=%s\n" \
"STDERR=%s\n" % \
(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
self.stderr_txt)
class LvmFlightRecorder(object):
@@ -95,7 +93,6 @@ def call_lvm(command, debug=False):
# Prepend the full lvm executable so that we can run different versions
# in different locations on the same box
command.insert(0, cfg.LVM_CMD)
command = add_no_notify(command)
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
env=os.environ)
@@ -281,7 +278,7 @@ def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name, '--yes'])
cmd.extend(['--name', name, vg_name])
pv_dest_ranges(cmd, pv_dests)
return call(cmd)
@@ -306,8 +303,6 @@ def _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool):
cmd.extend(['--size', str(size_bytes) + 'B'])
else:
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
cmd.extend(['--yes'])
return cmd
@@ -344,7 +339,7 @@ def _vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
if stripe_size_kb != 0:
cmd.extend(['--stripesize', str(stripe_size_kb)])
cmd.extend(['--name', name, vg_name, '--yes'])
cmd.extend(['--name', name, vg_name])
return call(cmd)
@@ -365,7 +360,7 @@ def vg_lv_create_mirror(
cmd.extend(['--type', 'mirror'])
cmd.extend(['--mirrors', str(num_copies)])
cmd.extend(['--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name, '--yes'])
cmd.extend(['--name', name, vg_name])
return call(cmd)
@@ -419,7 +414,7 @@ def lv_lv_create(lv_full_name, create_options, name, size_bytes):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--virtualsize', str(size_bytes) + 'B', '-T'])
cmd.extend(['--name', name, lv_full_name, '--yes'])
cmd.extend(['--name', name, lv_full_name])
return call(cmd)
@@ -555,7 +550,7 @@ def pv_resize(device, size_bytes, create_options):
cmd.extend(options_to_cli_args(create_options))
if size_bytes != 0:
cmd.extend(['--yes', '--setphysicalvolumesize', str(size_bytes) + 'B'])
cmd.extend(['--setphysicalvolumesize', str(size_bytes) + 'B'])
cmd.extend([device])
return call(cmd)
@@ -620,10 +615,10 @@ def vg_reduce(vg_name, missing, pv_devices, reduce_options):
cmd = ['vgreduce']
cmd.extend(options_to_cli_args(reduce_options))
if len(pv_devices) == 0:
cmd.append('--all')
if missing:
cmd.append('--removemissing')
elif len(pv_devices) == 0:
cmd.append('--all')
cmd.append(vg_name)
cmd.extend(pv_devices)

View File

@@ -82,10 +82,10 @@ class StateUpdate(object):
@staticmethod
def update_thread(obj):
queued_requests = []
while cfg.run.value != 0:
# noinspection PyBroadException
try:
queued_requests = []
refresh = True
emit_signal = True
cache_refresh = True
@@ -96,7 +96,7 @@ class StateUpdate(object):
wait = not obj.deferred
obj.deferred = False
if len(queued_requests) == 0 and wait:
if wait:
queued_requests.append(obj.queue.get(True, 2))
# Ok we have one or the deferred queue has some,
@@ -131,17 +131,11 @@ class StateUpdate(object):
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 = []
except queue.Empty:
pass
except Exception:
st = traceback.format_exc()
log_error("update_thread exception: \n%s" % st)
cfg.blackbox.dump()
def __init__(self):
self.lock = threading.RLock()
@@ -152,8 +146,7 @@ class StateUpdate(object):
load(refresh=False, emit_signal=False, need_main_thread=False)
self.thread = threading.Thread(target=StateUpdate.update_thread,
args=(self,),
name="StateUpdate.update_thread")
args=(self,))
def load(self, refresh=True, emit_signal=True, cache_refresh=True,
log=True, need_main_thread=True):

View File

@@ -8,7 +8,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from .utils import job_obj_path_generate, mt_async_call
from .utils import job_obj_path_generate, mt_async_result, mt_run_no_wait
from . import cfg
from .cfg import JOB_INTERFACE
import dbus
@@ -30,7 +30,7 @@ class WaitingClient(object):
# Remove ourselves from waiting client
wc.job_state.remove_waiting_client(wc)
wc.timer_id = -1
mt_async_call(wc.cb, wc.job_state.Complete)
mt_async_result(wc.cb, wc.job_state.Complete)
wc.job_state = None
def __init__(self, job_state, tmo, cb, cbe):
@@ -55,7 +55,7 @@ class WaitingClient(object):
GLib.source_remove(self.timer_id)
self.timer_id = -1
mt_async_call(self.cb, self.job_state.Complete)
mt_async_result(self.cb, self.job_state.Complete)
self.job_state = None
@@ -188,7 +188,7 @@ class Job(AutomatedProperties):
@Complete.setter
def Complete(self, value):
self.state.Complete = value
mt_async_call(Job._signal_complete, self)
mt_run_no_wait(Job._signal_complete, self)
@property
def GetError(self):

View File

@@ -232,6 +232,7 @@ class LvState(State):
@utils.dbus_property(LV_COMMON_INTERFACE, 'Attr', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SnapPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'MetaDataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'CopyPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SyncPercent', 'u')

View File

@@ -1,4 +1,4 @@
#!@PYTHON3@
#!/usr/bin/env python3
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
@@ -29,7 +29,7 @@ except ImportError:
from lvmdbusd.cfg import LVM_CMD
from lvmdbusd.utils import log_debug, log_error, add_no_notify
from lvmdbusd.utils import log_debug, log_error
SHELL_PROMPT = "lvm> "
@@ -206,8 +206,6 @@ class LVMShellProxy(object):
self.lvm_shell.returncode,
"Underlying lvm shell process is not present!")
argv = add_no_notify(argv)
# create the command string
cmd = " ".join(_quote_arg(arg) for arg in argv)
cmd += "\n"

View File

@@ -1,4 +1,4 @@
#!@PYTHON3@
#!/usr/bin/env python3
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#

View File

@@ -1,4 +1,4 @@
#!@PYTHON3@
#!/usr/bin/env python3
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#

View File

@@ -30,7 +30,6 @@ import argparse
import os
import sys
from .cmdhandler import LvmFlightRecorder
from .request import RequestEntry
class Lvm(objectmanager.ObjectManager):
@@ -63,24 +62,6 @@ def check_bb_size(value):
return v
def install_signal_handlers():
# Because of the glib main loop stuff the python signal handler code is
# apparently not usable and we need to use the glib calls instead
signal_add = None
if hasattr(GLib, 'unix_signal_add'):
signal_add = GLib.unix_signal_add
elif hasattr(GLib, 'unix_signal_add_full'):
signal_add = GLib.unix_signal_add_full
if signal_add:
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)
else:
log_error("GLib.unix_signal_[add|add_full] are NOT available!")
def main():
start = time.time()
# Add simple command line handling
@@ -116,7 +97,6 @@ def main():
os.environ["LC_ALL"] = "C"
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
@@ -130,7 +110,12 @@ def main():
# List of threads that we start up
thread_list = []
install_signal_handlers()
# Install signal handlers
for s in [signal.SIGHUP, signal.SIGINT]:
try:
signal.signal(s, utils.handler)
except RuntimeError:
pass
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
dbus.mainloop.glib.threads_init()
@@ -151,8 +136,7 @@ def main():
# Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface
thread_list.append(threading.Thread(target=process_request,
name='process_request'))
thread_list.append(threading.Thread(target=process_request))
# Have a single thread handling updating lvm and the dbus model so we
# don't have multiple threads doing this as the same time
@@ -160,6 +144,7 @@ def main():
thread_list.append(updater.thread)
cfg.load = updater.load
cfg.event = updater.event
cfg.loop = GLib.MainLoop()
@@ -190,7 +175,5 @@ def main():
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)
utils.handler(signal.SIGINT, None)
return 0

View File

@@ -6,6 +6,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from . import utils
@@ -47,7 +48,7 @@ class Manager(AutomatedProperties):
pv = cfg.om.get_object_path_by_uuid_lvm_id(device, device)
if pv:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE, "PV %s Already exists!" % device)
MANAGER_INTERFACE, "PV Already exists!")
rc, out, err = cmdhandler.pv_create(create_options, [device])
Manager.handle_execute(rc, out, err)
@@ -131,28 +132,11 @@ class Manager(AutomatedProperties):
r = RequestEntry(-1, Manager._refresh, (), cb, cbe, False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE)
def FlightRecorderDump(self):
"""
Dump the flight recorder to syslog
"""
cfg.blackbox.dump()
@staticmethod
def _lookup_by_lvm_id(key):
p = cfg.om.get_object_path_by_uuid_lvm_id(key, key)
if not p:
p = '/'
utils.log_debug('LookUpByLvmId: key = %s, result = %s' % (key, p))
return p
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='s',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def LookUpByLvmId(self, key, cb, cbe):
out_signature='o')
def LookUpByLvmId(self, key):
"""
Given a lvm id in one of the forms:
@@ -166,8 +150,10 @@ class Manager(AutomatedProperties):
:param key: The lookup value
:return: Return the object path. If object not found you will get '/'
"""
r = RequestEntry(-1, Manager._lookup_by_lvm_id, (key,), cb, cbe, False)
cfg.worker_q.put(r)
p = cfg.om.get_object_path_by_uuid_lvm_id(key, key)
if p:
return p
return '/'
@staticmethod
def _use_lvm_shell(yes_no):
@@ -183,33 +169,25 @@ class Manager(AutomatedProperties):
:param yes_no:
:param cb: dbus python call back parameter, not client visible
:param cbe: dbus python error call back parameter, not client visible
:return: Boolean
:return: Nothing
"""
r = RequestEntry(-1, Manager._use_lvm_shell, (yes_no,), cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _external_event(command):
utils.log_debug("Processing _external_event= %s" % command,
'bg_black', 'fg_orange')
cfg.load()
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='s', out_signature='i')
def ExternalEvent(self, command):
utils.log_debug("ExternalEvent %s" % command)
# If a user didn't explicitly specify udev, we will turn it off now.
if not cfg.args.use_udev:
if udevwatch.remove():
utils.log_debug("ExternalEvent received, disabling "
"udev monitoring")
# We are dependent on external events now to stay current!
cfg.got_external_event = True
r = RequestEntry(
-1, Manager._external_event, (command,), None, None, False)
cfg.worker_q.put(r)
cfg.ee = True
utils.log_debug("ExternalEvent %s" % command)
cfg.event()
return dbus.Int32(0)
@staticmethod

View File

@@ -32,12 +32,14 @@ class ObjectManager(AutomatedProperties):
self._id_to_object_path = {}
self.rlock = threading.RLock()
@staticmethod
def _get_managed_objects(obj):
with obj.rlock:
@dbus.service.method(
dbus_interface="org.freedesktop.DBus.ObjectManager",
out_signature='a{oa{sa{sv}}}')
def GetManagedObjects(self):
with self.rlock:
rc = {}
try:
for k, v in list(obj._objects.items()):
for k, v in list(self._objects.items()):
path, props = v[0].emit_data()
rc[path] = props
except Exception:
@@ -45,14 +47,6 @@ class ObjectManager(AutomatedProperties):
sys.exit(1)
return rc
@dbus.service.method(
dbus_interface="org.freedesktop.DBus.ObjectManager",
out_signature='a{oa{sa{sv}}}', async_callbacks=('cb', 'cbe'))
def GetManagedObjects(self, cb, cbe):
r = cfg.create_request_entry(-1, ObjectManager._get_managed_objects,
(self, ), cb, cbe, False)
cfg.worker_q.put(r)
def locked(self):
"""
If some external code need to run across a number of different
@@ -223,9 +217,8 @@ class ObjectManager(AutomatedProperties):
:param lvm_id: The lvm identifier
"""
with self.rlock:
lookup_rc = self._id_lookup(lvm_id)
if lookup_rc:
return self.get_object_by_path(lookup_rc)
if lvm_id in self._id_to_object_path:
return self.get_object_by_path(self._id_to_object_path[lvm_id])
return None
def get_object_path_by_lvm_id(self, lvm_id):
@@ -235,9 +228,8 @@ class ObjectManager(AutomatedProperties):
:return: Object path or '/' if not found
"""
with self.rlock:
lookup_rc = self._id_lookup(lvm_id)
if lookup_rc:
return lookup_rc
if lvm_id in self._id_to_object_path:
return self._id_to_object_path[lvm_id]
return '/'
def _uuid_verify(self, path, uuid, lvm_id):

View File

@@ -79,9 +79,7 @@ class PvState(State):
self.lv = self._lv_object_list(vg_name)
# It's possible to have a vg_name and no uuid with the main example
# being when the vg_name == '[unknown]'
if vg_uuid and vg_name:
if vg_name:
self.vg_path = cfg.om.get_object_path_by_uuid_lvm_id(
vg_uuid, vg_name, vg_obj_path_generate)
else:

View File

@@ -13,7 +13,7 @@ from gi.repository import GLib
from .job import Job
from . import cfg
import traceback
from .utils import log_error, mt_async_call
from .utils import log_error, mt_async_result
class RequestEntry(object):
@@ -116,9 +116,9 @@ class RequestEntry(object):
if error_rc == 0:
if self.cb:
if self._return_tuple:
mt_async_call(self.cb, (result, '/'))
mt_async_result(self.cb, (result, '/'))
else:
mt_async_call(self.cb, result)
mt_async_result(self.cb, result)
else:
if self.cb_error:
if not error_exception:
@@ -129,7 +129,7 @@ class RequestEntry(object):
else:
error_exception = Exception(error_msg)
mt_async_call(self.cb_error, error_exception)
mt_async_result(self.cb_error, error_exception)
else:
# We have a job and it's complete, indicate that it's done.
self._job.Complete = True

View File

@@ -10,41 +10,10 @@
import pyudev
import threading
from . import cfg
from .request import RequestEntry
from . import utils
observer = None
observer_lock = threading.RLock()
_udev_lock = threading.RLock()
_udev_count = 0
def udev_add():
global _udev_count
with _udev_lock:
if _udev_count == 0:
_udev_count += 1
# Place this on the queue so any other operations will sequence
# behind it
r = RequestEntry(
-1, _udev_event, (), None, None, False)
cfg.worker_q.put(r)
def udev_complete():
global _udev_count
with _udev_lock:
if _udev_count > 0:
_udev_count -= 1
def _udev_event():
utils.log_debug("Processing udev event")
udev_complete()
cfg.load()
# noinspection PyUnusedLocal
def filter_event(action, device):
@@ -68,7 +37,7 @@ def filter_event(action, device):
refresh = True
if refresh:
udev_add()
cfg.event()
def add():

View File

@@ -20,8 +20,7 @@ from lvmdbusd import cfg
# noinspection PyUnresolvedReferences
from gi.repository import GLib
import threading
import traceback
import signal
STDOUT_TTY = os.isatty(sys.stdout.fileno())
@@ -282,47 +281,12 @@ def log_error(msg, *attributes):
_common_log(msg, *attributes)
def dump_threads_stackframe():
ident_to_name = {}
for thread_object in threading.enumerate():
ident_to_name[thread_object.ident] = thread_object
stacks = []
for thread_ident, frame in sys._current_frames().items():
stack = traceback.format_list(traceback.extract_stack(frame))
# There is a possibility that a thread gets created after we have
# enumerated all threads, so this lookup table may be incomplete, so
# account for this
if thread_ident in ident_to_name:
thread_name = ident_to_name[thread_ident].name
else:
thread_name = "unknown"
stacks.append("Thread: %s" % (thread_name))
stacks.append("".join(stack))
log_error("Dumping thread stack frames!\n" + "\n".join(stacks))
# noinspection PyUnusedLocal
def handler(signum):
try:
if signum == signal.SIGUSR1:
dump_threads_stackframe()
else:
cfg.run.value = 0
log_debug('Exiting daemon with signal %d' % signum)
if cfg.loop is not None:
cfg.loop.quit()
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
# handler to continue to work, especially for signal 10 (SIGUSR1)
return True
def handler(signum, frame):
cfg.run.value = 0
log_debug('Signal handler called with signal %d' % signum)
if cfg.loop is not None:
cfg.loop.quit()
def pv_obj_path_generate():
@@ -535,62 +499,27 @@ def validate_tag(interface, tag):
% (tag, _ALLOWABLE_TAG_CH))
def add_no_notify(cmdline):
"""
Given a command line to execute we will see if `--config` is present, if it
is we will add the global/notify_dbus=0 to it, otherwise we will append it
to the end of the list.
:param: cmdline: The command line to inspect
:type: cmdline: list
:return: cmdline with notify_dbus config option present
:rtype: list
"""
# Only after we have seen an external event will be disable lvm from sending
# us one when we call lvm
if cfg.got_external_event:
if 'help' in cmdline:
return cmdline
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 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!
def _async_handler(call_back, parameters):
params_str = ", ".join(str(x) for x in parameters)
log_debug('Main thread execution, callback = %s, parameters = (%s)' %
(str(call_back), params_str))
try:
if parameters:
call_back(*parameters)
else:
call_back()
except:
st = traceback.format_exc()
log_error("mt_async_call: exception (logged, not reported!) \n %s" % st)
def _async_result(call_back, results):
log_debug('Results = %s' % str(results))
call_back(results)
# Execute the function on the main thread with the provided parameters, do
# not return *any* value or wait for the execution to complete!
def mt_async_call(function_call_back, *parameters):
GLib.idle_add(_async_handler, function_call_back, parameters)
# Return result in main thread
def mt_async_result(call_back, results):
GLib.idle_add(_async_result, call_back, results)
# Take the supplied function and run it on the main thread and not wait for
# a result!
def mt_run_no_wait(function, param):
GLib.idle_add(function, param)
# Run the supplied function and arguments on the main thread and wait for them
# to complete while allowing the ability to get the return value too.
#
@@ -610,7 +539,6 @@ class MThreadRunner(object):
def __init__(self, function, *args):
self.f = function
self.rc = None
self.exception = None
self.args = args
self.function_complete = False
self.cond = threading.Condition(threading.Lock())
@@ -620,21 +548,13 @@ class MThreadRunner(object):
with self.cond:
if not self.function_complete:
self.cond.wait()
if self.exception:
raise self.exception
return self.rc
def _run(self):
try:
if self.args:
self.rc = self.f(*self.args)
else:
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!")
if len(self.args):
self.rc = self.f(*self.args)
else:
self.rc = self.f()
def _remove_objects(dbus_objects_rm):

View File

@@ -16,7 +16,7 @@ top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SOURCES = lvmetad-core.c
SOURCES2 = lvmetactl.c
SOURCES2 = testclient.c
TARGETS = lvmetad lvmetactl
@@ -28,19 +28,22 @@ CFLOW_TARGET = lvmetad
include $(top_builddir)/make.tmpl
CFLAGS_lvmetactl.o += $(EXTRA_EXEC_CFLAGS)
CFLAGS_lvmetad-core.o += $(EXTRA_EXEC_CFLAGS)
INCLUDES += -I$(top_srcdir)/libdaemon/server
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
LIBS += $(PTHREAD_LIBS)
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS)
CLDFLAGS += -L$(top_builddir)/libdaemon/server
CFLAGS += $(EXTRA_EXEC_CFLAGS)
lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) -ldaemonserver $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LVMLIBS)
CLEAN_TARGETS += lvmetactl.o

View File

@@ -25,7 +25,6 @@
#define LVMETAD_DISABLE_REASON_LVM1 "LVM1"
#define LVMETAD_DISABLE_REASON_DUPLICATES "DUPLICATES"
#define LVMETAD_DISABLE_REASON_VGRESTORE "VGRESTORE"
#define LVMETAD_DISABLE_REASON_REPAIR "REPAIR"
struct volume_group;

View File

@@ -203,9 +203,8 @@ struct vg_info {
#define GLFL_DISABLE_REASON_LVM1 0x00000008
#define GLFL_DISABLE_REASON_DUPLICATES 0x00000010
#define GLFL_DISABLE_REASON_VGRESTORE 0x00000020
#define GLFL_DISABLE_REASON_REPAIR 0x00000040
#define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_REPAIR | GLFL_DISABLE_REASON_LVM1 | GLFL_DISABLE_REASON_DUPLICATES | GLFL_DISABLE_REASON_VGRESTORE)
#define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_LVM1 | GLFL_DISABLE_REASON_DUPLICATES | GLFL_DISABLE_REASON_VGRESTORE)
#define VGFL_INVALID 0x00000001
@@ -258,21 +257,6 @@ static void destroy_metadata_hashes(lvmetad_state *s)
dm_hash_iterate(n, s->pvid_to_pvmeta)
dm_config_destroy(dm_hash_get_data(s->pvid_to_pvmeta, n));
dm_hash_iterate(n, s->vgid_to_vgname)
dm_free(dm_hash_get_data(s->vgid_to_vgname, n));
dm_hash_iterate(n, s->vgname_to_vgid)
dm_free(dm_hash_get_data(s->vgname_to_vgid, n));
dm_hash_iterate(n, s->vgid_to_info)
dm_free(dm_hash_get_data(s->vgid_to_info, n));
dm_hash_iterate(n, s->device_to_pvid)
dm_free(dm_hash_get_data(s->device_to_pvid, n));
dm_hash_iterate(n, s->pvid_to_vgid)
dm_free(dm_hash_get_data(s->pvid_to_vgid, n));
dm_hash_destroy(s->pvid_to_pvmeta);
dm_hash_destroy(s->vgid_to_metadata);
dm_hash_destroy(s->vgid_to_vgname);
@@ -808,8 +792,7 @@ static int _update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
if ((mode == REMOVE_EMPTY) && vgid_old) {
/* This copies the vgid_old string, doesn't reference it. */
if ((dm_hash_lookup(to_check, vgid_old) != (void*) 1) &&
!dm_hash_insert(to_check, vgid_old, (void*) 1)) {
if (!dm_hash_insert(to_check, vgid_old, (void*) 1)) {
ERROR(s, "update_pvid_to_vgid out of memory for hash insert vgid_old %s", vgid_old);
goto abort_daemon;
}
@@ -885,13 +868,16 @@ static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
/* free the unmapped data */
if (info_lookup)
dm_free(info_lookup);
if (meta_lookup)
dm_config_destroy(meta_lookup);
if (name_lookup)
dm_free(name_lookup);
if (outdated_pvs_lookup)
dm_config_destroy(outdated_pvs_lookup);
dm_free(info_lookup);
dm_free(name_lookup);
dm_free(vgid_lookup);
if (vgid_lookup)
dm_free(vgid_lookup);
return 1;
}
@@ -1218,8 +1204,10 @@ static int _update_metadata_add_new(lvmetad_state *s, const char *new_name, cons
out:
out_free:
if (!new_name_dup || !new_vgid_dup || abort_daemon) {
dm_free(new_name_dup);
dm_free(new_vgid_dup);
if (new_name_dup)
dm_free(new_name_dup);
if (new_vgid_dup)
dm_free(new_vgid_dup);
ERROR(s, "lvmetad could not be updated and is aborting.");
exit(EXIT_FAILURE);
}
@@ -1809,7 +1797,8 @@ static response pv_gone(lvmetad_state *s, request r)
}
dm_config_destroy(pvmeta);
dm_free(old_pvid);
if (old_pvid)
dm_free(old_pvid);
return daemon_reply_simple("OK", NULL );
}
@@ -1922,7 +1911,7 @@ static response pv_found(lvmetad_state *s, request r)
const char *arg_pvid = NULL;
const char *arg_pvid_lookup = NULL;
const char *new_pvid = NULL;
char *new_pvid_dup = NULL;
const char *new_pvid_dup = NULL;
const char *arg_name = NULL;
const char *arg_vgid = NULL;
const char *arg_vgid_lookup = NULL;
@@ -2085,7 +2074,7 @@ static response pv_found(lvmetad_state *s, request r)
if (!(new_pvid_dup = dm_strdup(new_pvid)))
goto nomem_free1;
if (!dm_hash_insert_binary(s->device_to_pvid, &new_device, sizeof(new_device), new_pvid_dup))
if (!dm_hash_insert_binary(s->device_to_pvid, &new_device, sizeof(new_device), (char *)new_pvid_dup))
goto nomem_free2;
if (!dm_hash_insert(s->pvid_to_pvmeta, new_pvid, new_pvmeta))
@@ -2121,8 +2110,6 @@ static response pv_found(lvmetad_state *s, request r)
DEBUGLOG(s, "pv_found ignore duplicate device %" PRIu64 " of existing PV for pvid %s",
arg_device, arg_pvid);
dm_config_destroy(new_pvmeta);
/* device_to_pvid no longer references prev_pvid_lookup */
dm_free((void*)prev_pvid_on_dev);
s->flags |= GLFL_DISABLE;
s->flags |= GLFL_DISABLE_REASON_DUPLICATES;
return reply_fail("Ignore duplicate PV");
@@ -2133,7 +2120,7 @@ static response pv_found(lvmetad_state *s, request r)
if (!(new_pvid_dup = dm_strdup(new_pvid)))
goto nomem_free1;
if (!dm_hash_insert_binary(s->device_to_pvid, &arg_device, sizeof(arg_device), new_pvid_dup))
if (!dm_hash_insert_binary(s->device_to_pvid, &arg_device, sizeof(arg_device), (char *)new_pvid_dup))
goto nomem_free2;
if (!dm_hash_insert(s->pvid_to_pvmeta, new_pvid, new_pvmeta))
@@ -2233,7 +2220,8 @@ static response pv_found(lvmetad_state *s, request r)
}
/* This was unhashed from device_to_pvid above. */
dm_free((void *)prev_pvid_on_dev);
if (prev_pvid_on_dev)
dm_free((void *)prev_pvid_on_dev);
return daemon_reply_simple("OK",
"status = %s", vg_status,
@@ -2245,7 +2233,7 @@ static response pv_found(lvmetad_state *s, request r)
NULL);
nomem_free2:
dm_free(new_pvid_dup);
dm_free((char *)new_pvid_dup);
nomem_free1:
dm_config_destroy(new_pvmeta);
nomem:
@@ -2367,8 +2355,6 @@ static response set_global_info(lvmetad_state *s, request r)
if ((reason = daemon_request_str(r, "disable_reason", NULL))) {
if (strstr(reason, LVMETAD_DISABLE_REASON_DIRECT))
reason_flags |= GLFL_DISABLE_REASON_DIRECT;
if (strstr(reason, LVMETAD_DISABLE_REASON_REPAIR))
reason_flags |= GLFL_DISABLE_REASON_REPAIR;
if (strstr(reason, LVMETAD_DISABLE_REASON_LVM1))
reason_flags |= GLFL_DISABLE_REASON_LVM1;
if (strstr(reason, LVMETAD_DISABLE_REASON_DUPLICATES))
@@ -2421,17 +2407,19 @@ static response set_global_info(lvmetad_state *s, request r)
static response get_global_info(lvmetad_state *s, request r)
{
/* This buffer should be large enough to hold all the possible reasons. */
char reason[REASON_BUF_SIZE] = { 0 };
char reason[REASON_BUF_SIZE];
char flag_str[64];
int pid;
/* This buffer should be large enough to hold all the possible reasons. */
memset(reason, 0, sizeof(reason));
pid = (int)daemon_request_int(r, "pid", 0);
if (s->flags & GLFL_DISABLE) {
snprintf(reason, REASON_BUF_SIZE, "%s%s%s%s%s",
snprintf(reason, REASON_BUF_SIZE - 1, "%s%s%s%s",
(s->flags & GLFL_DISABLE_REASON_DIRECT) ? LVMETAD_DISABLE_REASON_DIRECT "," : "",
(s->flags & GLFL_DISABLE_REASON_REPAIR) ? LVMETAD_DISABLE_REASON_REPAIR "," : "",
(s->flags & GLFL_DISABLE_REASON_LVM1) ? LVMETAD_DISABLE_REASON_LVM1 "," : "",
(s->flags & GLFL_DISABLE_REASON_DUPLICATES) ? LVMETAD_DISABLE_REASON_DUPLICATES "," : "",
(s->flags & GLFL_DISABLE_REASON_VGRESTORE) ? LVMETAD_DISABLE_REASON_VGRESTORE "," : "");
@@ -2528,8 +2516,10 @@ inval:
info = dm_hash_lookup(s->vgid_to_info, uuid);
if (!info) {
if (!(info = dm_zalloc(sizeof(struct vg_info))))
info = malloc(sizeof(struct vg_info));
if (!info)
goto bad;
memset(info, 0, sizeof(struct vg_info));
if (!dm_hash_insert(s->vgid_to_info, uuid, (void*)info))
goto bad;
}
@@ -2567,12 +2557,14 @@ static void _dump_pairs(struct buffer *buf, struct dm_hash_table *ht, const char
dm_hash_iterate(n, ht) {
const char *key = dm_hash_get_key(ht, n),
*val = dm_hash_get_data(ht, n);
buffer_append(buf, " ");
if (int_key)
(void) dm_asprintf(&append, " %d = \"%s\"\n", *(const int*)key, val);
(void) dm_asprintf(&append, "%d = \"%s\"", *(const int*)key, val);
else
(void) dm_asprintf(&append, " %s = \"%s\"\n", key, val);
(void) dm_asprintf(&append, "%s = \"%s\"", key, val);
if (append)
buffer_append(buf, append);
buffer_append(buf, "\n");
dm_free(append);
}
buffer_append(buf, "}\n");
@@ -2590,9 +2582,11 @@ static void _dump_info_version(struct buffer *buf, struct dm_hash_table *ht, con
while (n) {
const char *key = dm_hash_get_key(ht, n);
info = dm_hash_get_data(ht, n);
(void) dm_asprintf(&append, " %s = %lld\n", key, (long long)info->external_version);
buffer_append(buf, " ");
(void) dm_asprintf(&append, "%s = %lld", key, (long long)info->external_version);
if (append)
buffer_append(buf, append);
buffer_append(buf, "\n");
dm_free(append);
n = dm_hash_get_next(ht, n);
}
@@ -2611,9 +2605,11 @@ static void _dump_info_flags(struct buffer *buf, struct dm_hash_table *ht, const
while (n) {
const char *key = dm_hash_get_key(ht, n);
info = dm_hash_get_data(ht, n);
(void) dm_asprintf(&append, " %s = %llx\n", key, (long long)info->flags);
buffer_append(buf, " ");
(void) dm_asprintf(&append, "%s = %llx", key, (long long)info->flags);
if (append)
buffer_append(buf, append);
buffer_append(buf, "\n");
dm_free(append);
n = dm_hash_get_next(ht, n);
}
@@ -2700,8 +2696,9 @@ static response handler(daemon_state s, client_handle h, request r)
if (!prev_in_progress && this_in_progress) {
/* New update is starting (filter token is replaced by update token) */
(void) dm_strncpy(prev_token, state->token, sizeof(prev_token));
(void) dm_strncpy(state->token, token, sizeof(state->token));
memcpy(prev_token, state->token, 128);
strncpy(state->token, token, 128);
state->token[127] = 0;
state->update_begin = _monotonic_seconds();
state->update_timeout = update_timeout;
state->update_pid = pid;
@@ -2722,8 +2719,9 @@ static response handler(daemon_state s, client_handle h, request r)
(int)(_monotonic_seconds() - state->update_begin),
state->update_cmd);
(void) dm_strncpy(prev_token, state->token, sizeof(prev_token));
(void) dm_strncpy(state->token, token, sizeof(state->token));
memcpy(prev_token, state->token, 128);
strncpy(state->token, token, 128);
state->token[127] = 0;
state->update_begin = _monotonic_seconds();
state->update_timeout = update_timeout;
state->update_pid = pid;
@@ -2755,8 +2753,9 @@ static response handler(daemon_state s, client_handle h, request r)
(int)(_monotonic_seconds() - state->update_begin),
state->update_pid, token);
(void) dm_strncpy(prev_token, state->token, sizeof(prev_token));
(void) dm_strncpy(state->token, token, sizeof(state->token));
memcpy(prev_token, state->token, 128);
strncpy(state->token, token, 128);
state->token[127] = 0;
state->update_begin = 0;
state->update_timeout = 0;
state->update_pid = 0;

View File

@@ -19,33 +19,41 @@ SOURCES = lvmlockd-core.c
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
SOURCES += lvmlockd-sanlock.c
LOCK_LIBS += -lsanlock_client
endif
ifeq ("@BUILD_LOCKDDLM@", "yes")
SOURCES += lvmlockd-dlm.c
LOCK_LIBS += -ldlm_lt
endif
SOURCES2 = lvmlockctl.c
TARGETS = lvmlockd 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 += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
LIBS += $(PTHREAD_LIBS)
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
LIBS += -lsanlock_client
endif
ifeq ("@BUILD_LOCKDDLM@", "yes")
LIBS += -ldlm_lt
endif
LDFLAGS += -L$(top_builddir)/libdaemon/server
CLDFLAGS += -L$(top_builddir)/libdaemon/server
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LOCK_LIBS) -ldaemonserver $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(LIBS)
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(LVMLIBS)
install_lvmlockd: lvmlockd
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)

View File

@@ -379,7 +379,7 @@ static int setup_dump_socket(void)
rv = bind(s, (struct sockaddr *) &dump_addr, dump_addrlen);
if (rv < 0) {
rv = -errno;
if (close(s))
if (!close(s))
log_error("failed to close dump socket");
return rv;
}

View File

@@ -48,7 +48,5 @@ static inline void lvmlockd_close(daemon_handle h)
#define EVGKILLED 217 /* sanlock lost access to leases and VG is killed. */
#define ELOCKIO 218 /* sanlock io errors during lock op, may be transient. */
#define EREMOVED 219
#define EDEVOPEN 220 /* sanlock failed to open lvmlock LV */
#define ELMERR 221
#endif /* _LVM_LVMLOCKD_CLIENT_H */

View File

@@ -19,7 +19,6 @@
#include "lvm-version.h"
#include "lvmetad-client.h"
#include "lvmlockd-client.h"
#include "dm-ioctl.h" /* for DM_UUID_LEN */
/* #include <assert.h> */
#include <errno.h>
@@ -1389,11 +1388,12 @@ static int res_convert(struct lockspace *ls, struct resource *r,
}
rv = lm_convert(ls, r, act->mode, act, r_version);
log_debug("S %s R %s res_convert rv %d", ls->name, r->name, rv);
if (rv < 0)
if (rv < 0) {
log_error("S %s R %s res_convert lm error %d", ls->name, r->name, rv);
return rv;
}
log_debug("S %s R %s res_convert lm done", ls->name, r->name);
if (lk->mode == LD_LK_EX && act->mode == LD_LK_SH) {
r->sh_count = 1;
@@ -2651,16 +2651,10 @@ out_act:
ls->drop_vg = drop_vg;
if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm))
global_dlm_lockspace_exists = 0;
/*
* Avoid a name collision of the same lockspace is added again before
* this thread is cleaned up. We just set ls->name to a "junk" value
* for the short period until the struct is freed. We could make it
* blank or fill it with garbage, but instead set it to REM:<name>
* to make it easier to follow progress of freeing is via log_debug.
*/
dm_strncpy(tmp_name, ls->name, sizeof(tmp_name));
snprintf(ls->name, sizeof(ls->name), "REM:%s", tmp_name);
/* Avoid a name collision of the same lockspace is added again before this thread is cleaned up. */
memset(tmp_name, 0, sizeof(tmp_name));
snprintf(tmp_name, MAX_NAME, "REM:%s", ls->name);
memcpy(ls->name, tmp_name, MAX_NAME);
pthread_mutex_unlock(&lockspaces_mutex);
/* worker_thread will join this thread, and free the ls */
@@ -3309,6 +3303,7 @@ static int work_init_lv(struct action *act)
lm_type = ls->lm_type;
memcpy(vg_args, ls->vg_args, MAX_ARGS);
free_offset = ls->free_lock_offset;
ls->free_lock_offset = 0;
}
pthread_mutex_unlock(&lockspaces_mutex);
@@ -3538,15 +3533,11 @@ static int setup_worker_thread(void)
static void close_worker_thread(void)
{
int perrno;
pthread_mutex_lock(&worker_mutex);
worker_stop = 1;
pthread_cond_signal(&worker_cond);
pthread_mutex_unlock(&worker_mutex);
if ((perrno = pthread_join(worker_thread, NULL)))
log_error("pthread_join worker_thread error %d", perrno);
pthread_join(worker_thread, NULL);
}
/* client_mutex is locked */
@@ -3675,17 +3666,7 @@ static int client_send_result(struct client *cl, struct action *act)
if (!gl_lsname_dlm[0])
strcat(result_flags, "NO_GL_LS,");
} else {
int found_lm = 0;
if (lm_support_dlm() && lm_is_running_dlm())
found_lm++;
if (lm_support_sanlock() && lm_is_running_sanlock())
found_lm++;
if (!found_lm)
strcat(result_flags, "NO_GL_LS,NO_LM");
else
strcat(result_flags, "NO_GL_LS");
strcat(result_flags, "NO_GL_LS,");
}
}
@@ -3782,8 +3763,7 @@ static int client_send_result(struct client *cl, struct action *act)
if (dump_fd >= 0) {
/* To avoid deadlock, send data here after the reply. */
send_dump_buf(dump_fd, dump_len);
if (close(dump_fd))
log_error("failed to close dump socket %d", dump_fd);
close(dump_fd);
}
return rv;
@@ -3856,9 +3836,8 @@ static int add_lock_action(struct action *act)
pthread_mutex_lock(&lockspaces_mutex);
if (ls_name[0])
ls = find_lockspace_name(ls_name);
pthread_mutex_unlock(&lockspaces_mutex);
if (!ls) {
pthread_mutex_unlock(&lockspaces_mutex);
if (act->op == LD_OP_UPDATE && act->rt == LD_RT_VG) {
log_debug("lockspace \"%s\" not found ignored for vg update", ls_name);
return -ENOLS;
@@ -4775,8 +4754,8 @@ static void *client_thread_main(void *arg_in)
} else {
pthread_mutex_unlock(&cl->mutex);
}
} else
pthread_mutex_unlock(&client_mutex);
}
pthread_mutex_unlock(&client_mutex);
}
out:
return NULL;
@@ -4800,15 +4779,11 @@ static int setup_client_thread(void)
static void close_client_thread(void)
{
int perrno;
pthread_mutex_lock(&client_mutex);
client_stop = 1;
pthread_cond_signal(&client_cond);
pthread_mutex_unlock(&client_mutex);
if ((perrno = pthread_join(client_thread, NULL)))
log_error("pthread_join client_thread error %d", perrno);
pthread_join(client_thread, NULL);
}
/*
@@ -4932,10 +4907,14 @@ static int get_lockd_vgs(struct list_head *vg_lockd)
continue;
for (lv_cn = md_cn->child; lv_cn; lv_cn = lv_cn->sib) {
snprintf(find_str_path, PATH_MAX, "%s/lock_type", lv_cn->key);
lock_type = dm_config_find_str(lv_cn, find_str_path, NULL);
if (!lock_type)
continue;
snprintf(find_str_path, PATH_MAX, "%s/lock_args", lv_cn->key);
lock_args = dm_config_find_str(lv_cn, find_str_path, NULL);
if (!lock_args)
continue;
snprintf(find_str_path, PATH_MAX, "%s/id", lv_cn->key);
lv_uuid = dm_config_find_str(lv_cn, find_str_path, NULL);
@@ -4981,7 +4960,7 @@ out:
return rv;
}
static char _dm_uuid[DM_UUID_LEN];
static char _dm_uuid[64];
static char *get_dm_uuid(char *dm_name)
{
@@ -5200,17 +5179,20 @@ static void adopt_locks(void)
* Get list of lockspaces from lock managers.
* Get list of VGs from lvmetad with a lockd type.
* Get list of active lockd type LVs from /dev.
*
* ECONNREFUSED means the lock manager is not running.
* This is expected for at least one of them.
*/
if (lm_support_dlm() && lm_is_running_dlm()) {
if (lm_support_dlm()) {
rv = lm_get_lockspaces_dlm(&ls_found);
if (rv < 0)
if ((rv < 0) && (rv != -ECONNREFUSED))
goto fail;
}
if (lm_support_sanlock() && lm_is_running_sanlock()) {
if (lm_support_sanlock()) {
rv = lm_get_lockspaces_sanlock(&ls_found);
if (rv < 0)
if ((rv < 0) && (rv != -ECONNREFUSED))
goto fail;
}
@@ -5287,7 +5269,7 @@ static void adopt_locks(void)
list_for_each_entry_safe(ls1, l1safe, &ls_found, list) {
/* The dlm global lockspace is special and doesn't match a VG. */
if ((ls1->lm_type == LD_LM_DLM) && !strcmp(ls1->name, gl_lsname_dlm)) {
if (!strcmp(ls1->name, gl_lsname_dlm)) {
list_del(&ls1->list);
free(ls1);
continue;

View File

@@ -508,7 +508,7 @@ lockrv:
}
if (rv < 0) {
log_error("S %s R %s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
return -ELMERR;
return rv;
}
if (rdd->vb) {
@@ -581,7 +581,6 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
}
if (rv < 0) {
log_error("S %s R %s convert_dlm error %d", ls->name, r->name, rv);
rv = -ELMERR;
}
return rv;
}
@@ -655,7 +654,6 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
0, NULL, NULL, NULL);
if (rv < 0) {
log_error("S %s R %s unlock_dlm error %d", ls->name, r->name, rv);
rv = -ELMERR;
}
return rv;
@@ -699,7 +697,7 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
return 0;
memset(ls_nodes_path, 0, sizeof(ls_nodes_path));
snprintf(ls_nodes_path, PATH_MAX, "%s/%s/nodes",
snprintf(ls_nodes_path, PATH_MAX-1, "%s/%s/nodes",
DLM_LOCKSPACES_PATH, ls->name);
if (!(ls_dir = opendir(ls_nodes_path)))

View File

@@ -224,10 +224,7 @@ static int lock_lv_offset_from_args(char *lv_args, uint64_t *lock_lv_offset)
if (rv < 0)
return rv;
errno = 0;
*lock_lv_offset = strtoull(offset_str, NULL, 10);
if (errno)
return -1;
return 0;
}
@@ -294,36 +291,6 @@ out:
return host_id;
}
/* Prepare valid /dev/mapper/vgname-lvname with all the mangling */
static int build_dm_path(char *path, size_t path_len,
const char *vg_name, const char *lv_name)
{
struct dm_pool *mem;
char *dm_name;
int rv = 0;
if (!(mem = dm_pool_create("namepool", 1024))) {
log_error("Failed to create mempool.");
return -ENOMEM;
}
if (!(dm_name = dm_build_dm_name(mem, vg_name, lv_name, NULL))) {
log_error("Failed to build dm name for %s/%s.", vg_name, lv_name);
rv = -EINVAL;
goto fail;
}
if ((dm_snprintf(path, path_len, "%s/%s", dm_dir(), dm_name) < 0)) {
log_error("Failed to create path %s/%s.", dm_dir(), dm_name);
rv = -EINVAL;
}
fail:
dm_pool_destroy(mem);
return rv;
}
/*
* vgcreate
*
@@ -366,8 +333,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
if (strlen(lock_lv_name) + strlen(lock_args_version) + 2 > MAX_ARGS)
return -EARGS;
if ((rv = build_dm_path(disk.path, SANLK_PATH_LEN, vg_name, lock_lv_name)))
return rv;
snprintf(disk.path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
log_debug("S %s init_vg_san path %s", ls_name, disk.path);
@@ -387,19 +353,12 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
log_debug("sanlock daemon version %08x proto %08x",
daemon_version, daemon_proto);
rv = sanlock_align(&disk);
if (rv <= 0) {
if (rv == -EACCES) {
log_error("S %s init_vg_san sanlock error -EACCES: no permission to access %s",
ls_name, disk.path);
return -EDEVOPEN;
} else {
log_error("S %s init_vg_san sanlock error %d trying to get align size of %s",
ls_name, rv, disk.path);
return -EARGS;
}
} else
align_size = rv;
align_size = sanlock_align(&disk);
if (align_size <= 0) {
log_error("S %s init_vg_san bad disk align size %d %s",
ls_name, align_size, disk.path);
return -EARGS;
}
strncpy(ss.name, ls_name, SANLK_NAME_LEN);
memcpy(ss.host_id_disk.path, disk.path, SANLK_PATH_LEN);
@@ -544,8 +503,7 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
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;
snprintf(rd.rs.disks[0].path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
align_size = sanlock_align(&rd.rs.disks[0]);
if (align_size <= 0) {
@@ -644,8 +602,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
return rv;
}
if ((rv = build_dm_path(disk.path, SANLK_PATH_LEN, vg_name, lock_lv_name)))
return rv;
snprintf(disk.path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
log_debug("S %s rename_vg_san path %s", ls_name, disk.path);
@@ -978,9 +935,7 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
struct sanlk_resourced rd;
uint64_t offset;
uint64_t start_offset;
int rv;
int round = 0;
if (daemon_test) {
*free_offset = (1048576 * LV_LOCK_BEGIN) + (1048576 * (daemon_test_lv_count + 1));
@@ -993,22 +948,9 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
rd.rs.num_disks = 1;
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
if (ls->free_lock_offset)
offset = ls->free_lock_offset;
else
offset = lms->align_size * LV_LOCK_BEGIN;
start_offset = offset;
offset = lms->align_size * LV_LOCK_BEGIN;
while (1) {
if (offset >= start_offset && round) {
/* This indicates the all space are allocated. */
log_debug("S %s init_lv_san read back to start offset %llu",
ls->name, (unsigned long long)offset);
rv = -EMSGSIZE;
return rv;
}
rd.rs.disks[0].offset = offset;
memset(rd.rs.name, 0, SANLK_NAME_LEN);
@@ -1018,14 +960,7 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
/* This indicates the end of the device is reached. */
log_debug("S %s find_free_lock_san read limit offset %llu",
ls->name, (unsigned long long)offset);
/* remember the NO SPACE offset, if no free area left,
* search from this offset after extend */
*free_offset = offset;
offset = lms->align_size * LV_LOCK_BEGIN;
round = 1;
continue;
return -EMSGSIZE;
}
/*
@@ -1102,10 +1037,10 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
* and appending "lockctl" to get /path/to/lvmlockctl.
*/
memset(killpath, 0, sizeof(killpath));
snprintf(killpath, SANLK_PATH_LEN, "%slockctl", LVM_PATH);
snprintf(killpath, SANLK_PATH_LEN - 1, "%slockctl", LVM_PATH);
memset(killargs, 0, sizeof(killargs));
snprintf(killargs, SANLK_PATH_LEN, "--kill %s", ls->vg_name);
snprintf(killargs, SANLK_PATH_LEN - 1, "--kill %s", ls->vg_name);
rv = check_args_version(ls->vg_args, VG_LOCK_ARGS_MAJOR);
if (rv < 0) {
@@ -1121,8 +1056,8 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
goto fail;
}
if ((ret = build_dm_path(disk_path, SANLK_PATH_LEN, ls->vg_name, lock_lv_name)))
goto fail;
snprintf(disk_path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s",
ls->vg_name, lock_lv_name);
/*
* When a vg is started, the internal sanlock lv should be
@@ -1493,12 +1428,6 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
rv = sanlock_acquire(lms->sock, -1, flags, 1, &rs, &opt);
/*
* errors: translate the sanlock error number to an lvmlockd error.
* We don't want to return an sanlock-specific error number from
* this function to code that doesn't recognize sanlock error numbers.
*/
if (rv == -EAGAIN) {
/*
* It appears that sanlock_acquire returns EAGAIN when we request
@@ -1567,26 +1496,6 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
return -EAGAIN;
}
if (rv == SANLK_AIO_TIMEOUT) {
/*
* sanlock got an i/o timeout when trying to acquire the
* lease on disk.
*/
log_debug("S %s R %s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
*retry = 0;
return -EAGAIN;
}
if (rv == SANLK_DBLOCK_LVER || rv == SANLK_DBLOCK_MBAL) {
/*
* There was contention with another host for the lease,
* and we lost.
*/
log_debug("S %s R %s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
*retry = 0;
return -EAGAIN;
}
if (rv == SANLK_ACQUIRE_OWNED_RETRY) {
/*
* The lock is held by a failed host, and will eventually
@@ -1637,25 +1546,15 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
if (rv == -ENOSPC)
rv = -ELOCKIO;
/*
* generic error number for sanlock errors that we are not
* catching above.
*/
return -ELMERR;
return rv;
}
/*
* sanlock acquire success (rv 0)
*/
if (rds->vb) {
rv = sanlock_get_lvb(0, rs, (char *)&vb, sizeof(vb));
if (rv < 0) {
log_error("S %s R %s lock_san get_lvb error %d", ls->name, r->name, rv);
memset(rds->vb, 0, sizeof(struct val_blk));
memset(vb_out, 0, sizeof(struct val_blk));
/* the lock is still acquired, the vb values considered invalid */
rv = 0;
goto out;
}
@@ -1708,7 +1607,6 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
if (rv < 0) {
log_error("S %s R %s convert_san set_lvb error %d",
ls->name, r->name, rv);
return -ELMERR;
}
}
@@ -1721,35 +1619,14 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
if (daemon_test)
return 0;
/*
* Don't block waiting for a failed lease to expire since it causes
* sanlock_convert to block for a long time, which would prevent this
* thread from processing other lock requests.
*
* FIXME: SANLK_CONVERT_OWNER_NOWAIT is the same as SANLK_ACQUIRE_OWNER_NOWAIT.
* Change to use the CONVERT define when the latest sanlock version has it.
*/
flags |= SANLK_ACQUIRE_OWNER_NOWAIT;
rv = sanlock_convert(lms->sock, -1, flags, rs);
if (!rv)
return 0;
switch (rv) {
case -EAGAIN:
case SANLK_ACQUIRE_IDLIVE:
case SANLK_ACQUIRE_OWNED:
case SANLK_ACQUIRE_OWNED_RETRY:
case SANLK_ACQUIRE_OTHER:
case SANLK_AIO_TIMEOUT:
case SANLK_DBLOCK_LVER:
case SANLK_DBLOCK_MBAL:
/* expected errors from known/normal cases like lock contention or io timeouts */
log_debug("S %s R %s convert_san error %d", ls->name, r->name, rv);
if (rv == -EAGAIN) {
/* FIXME: When could this happen? Should something different be done? */
log_error("S %s R %s convert_san EAGAIN", ls->name, r->name);
return -EAGAIN;
default:
}
if (rv < 0) {
log_error("S %s R %s convert_san convert error %d", ls->name, r->name, rv);
rv = -ELMERR;
}
return rv;
@@ -1786,7 +1663,6 @@ static int release_rename(struct lockspace *ls, struct resource *r)
rv = sanlock_release(lms->sock, -1, SANLK_REL_RENAME, 2, res_args);
if (rv < 0) {
log_error("S %s R %s unlock_san release rename error %d", ls->name, r->name, rv);
rv = -ELMERR;
}
free(res_args);
@@ -1843,7 +1719,6 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
if (rv < 0) {
log_error("S %s R %s unlock_san set_lvb error %d",
ls->name, r->name, rv);
return -ELMERR;
}
}
@@ -1862,8 +1737,6 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
if (rv == -EIO)
rv = -ELOCKIO;
else if (rv < 0)
rv = -ELMERR;
return rv;
}

View File

@@ -27,14 +27,18 @@ CFLOW_TARGET = lvmpolld
include $(top_builddir)/make.tmpl
CFLAGS += $(EXTRA_EXEC_CFLAGS)
INCLUDES += -I$(top_srcdir)/libdaemon/server
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
LIBS += $(DAEMON_LIBS) -ldaemonserver -ldevmapper $(PTHREAD_LIBS)
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
LIBS += $(PTHREAD_LIBS)
LDFLAGS += -L$(top_builddir)/libdaemon/server $(DAEMON_LDFLAGS)
CLDFLAGS += -L$(top_builddir)/libdaemon/server
CFLAGS += $(DAEMON_CFLAGS)
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
install_lvmpolld: lvmpolld
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)

View File

@@ -19,12 +19,10 @@
#define MIN_ARGV_SIZE 8
static const char *const polling_ops[] = {
[PVMOVE] = LVMPD_REQ_PVMOVE,
[CONVERT] = LVMPD_REQ_CONVERT,
[MERGE] = LVMPD_REQ_MERGE,
[MERGE_THIN] = LVMPD_REQ_MERGE_THIN
};
static const char *const const polling_ops[] = { [PVMOVE] = LVMPD_REQ_PVMOVE,
[CONVERT] = LVMPD_REQ_CONVERT,
[MERGE] = LVMPD_REQ_MERGE,
[MERGE_THIN] = LVMPD_REQ_MERGE_THIN };
const char *polling_op(enum poll_type type)
{

View File

@@ -1,248 +0,0 @@
#include "target.h"
// For DM_ARRAY_SIZE!
#include "libdevmapper.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
//----------------------------------------------------------------
static char *_tok_cpy(const char *b, const char *e)
{
char *new = malloc((e - b) + 1);
char *ptr = new;
if (new) {
while (b != e)
*ptr++ = *b++;
*ptr = '\0';
}
return new;
}
static bool _tok_eq(const char *b, const char *e, const char *str)
{
while (b != e) {
if (!*str || *b != *str)
return false;
b++;
str++;
}
return !*str;
}
static bool _parse_operating_mode(const char *b, const char *e, void *context)
{
static struct {
const char *str;
enum vdo_operating_mode mode;
} _table[] = {
{"recovering", VDO_MODE_RECOVERING},
{"read-only", VDO_MODE_READ_ONLY},
{"normal", VDO_MODE_NORMAL}
};
enum vdo_operating_mode *r = context;
unsigned i;
for (i = 0; i < DM_ARRAY_SIZE(_table); i++) {
if (_tok_eq(b, e, _table[i].str)) {
*r = _table[i].mode;
return true;
}
}
return false;
}
static bool _parse_compression_state(const char *b, const char *e, void *context)
{
static struct {
const char *str;
enum vdo_compression_state state;
} _table[] = {
{"online", VDO_COMPRESSION_ONLINE},
{"offline", VDO_COMPRESSION_OFFLINE}
};
enum vdo_compression_state *r = context;
unsigned i;
for (i = 0; i < DM_ARRAY_SIZE(_table); i++) {
if (_tok_eq(b, e, _table[i].str)) {
*r = _table[i].state;
return true;
}
}
return false;
}
static bool _parse_recovering(const char *b, const char *e, void *context)
{
bool *r = context;
if (_tok_eq(b, e, "recovering"))
*r = true;
else if (_tok_eq(b, e, "-"))
*r = false;
else
return false;
return true;
}
static bool _parse_index_state(const char *b, const char *e, void *context)
{
static struct {
const char *str;
enum vdo_index_state state;
} _table[] = {
{"error", VDO_INDEX_ERROR},
{"closed", VDO_INDEX_CLOSED},
{"opening", VDO_INDEX_OPENING},
{"closing", VDO_INDEX_CLOSING},
{"offline", VDO_INDEX_OFFLINE},
{"online", VDO_INDEX_ONLINE},
{"unknown", VDO_INDEX_UNKNOWN}
};
enum vdo_index_state *r = context;
unsigned i;
for (i = 0; i < DM_ARRAY_SIZE(_table); i++) {
if (_tok_eq(b, e, _table[i].str)) {
*r = _table[i].state;
return true;
}
}
return false;
}
static bool _parse_uint64(const char *b, const char *e, void *context)
{
uint64_t *r = context, n;
n = 0;
while (b != e) {
if (!isdigit(*b))
return false;
n = (n * 10) + (*b - '0');
b++;
}
*r = n;
return true;
}
static const char *_eat_space(const char *b, const char *e)
{
while (b != e && isspace(*b))
b++;
return b;
}
static const char *_next_tok(const char *b, const char *e)
{
const char *te = b;
while (te != e && !isspace(*te))
te++;
return te == b ? NULL : te;
}
static void _set_error(struct vdo_status_parse_result *result, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
static void _set_error(struct vdo_status_parse_result *result, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(result->error, sizeof(result->error), fmt, ap);
va_end(ap);
}
static bool _parse_field(const char **b, const char *e,
bool (*p_fn)(const char *, const char *, void *),
void *field, const char *field_name,
struct vdo_status_parse_result *result)
{
const char *te;
te = _next_tok(*b, e);
if (!te) {
_set_error(result, "couldn't get token for '%s'", field_name);
return false;
}
if (!p_fn(*b, te, field)) {
_set_error(result, "couldn't parse '%s'", field_name);
return false;
}
*b = _eat_space(te, e);
return true;
}
bool vdo_status_parse(const char *input, struct vdo_status_parse_result *result)
{
const char *b = b = input;
const char *e = input + strlen(input);
const char *te;
struct vdo_status *s = malloc(sizeof(*s));
if (!s) {
_set_error(result, "out of memory");
return false;
}
b = _eat_space(b, e);
te = _next_tok(b, e);
if (!te) {
_set_error(result, "couldn't get token for device");
free(s);
return false;
}
s->device = _tok_cpy(b, te);
if (!s->device) {
_set_error(result, "out of memory");
free(s);
return false;
}
b = _eat_space(te, e);
#define XX(p, f, fn) if (!_parse_field(&b, e, p, f, fn, result)) goto bad;
XX(_parse_operating_mode, &s->operating_mode, "operating mode");
XX(_parse_recovering, &s->recovering, "recovering");
XX(_parse_index_state, &s->index_state, "index state");
XX(_parse_compression_state, &s->compression_state, "compression state");
XX(_parse_uint64, &s->used_blocks, "used blocks");
XX(_parse_uint64, &s->total_blocks, "total blocks");
#undef XX
if (b != e) {
_set_error(result, "too many tokens");
goto bad;
}
result->status = s;
return true;
bad:
free(s->device);
free(s);
return false;
}
//----------------------------------------------------------------

View File

@@ -1,68 +0,0 @@
/*
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef DEVICE_MAPPER_VDO_TARGET_H
#define DEVICE_MAPPER_VDO_TARGET_H
#include <stdbool.h>
#include <stdint.h>
//----------------------------------------------------------------
enum vdo_operating_mode {
VDO_MODE_RECOVERING,
VDO_MODE_READ_ONLY,
VDO_MODE_NORMAL
};
enum vdo_compression_state {
VDO_COMPRESSION_ONLINE,
VDO_COMPRESSION_OFFLINE
};
enum vdo_index_state {
VDO_INDEX_ERROR,
VDO_INDEX_CLOSED,
VDO_INDEX_OPENING,
VDO_INDEX_CLOSING,
VDO_INDEX_OFFLINE,
VDO_INDEX_ONLINE,
VDO_INDEX_UNKNOWN
};
struct vdo_status {
char *device;
enum vdo_operating_mode operating_mode;
bool recovering;
enum vdo_index_state index_state;
enum vdo_compression_state compression_state;
uint64_t used_blocks;
uint64_t total_blocks;
};
void vdo_status_destroy(struct vdo_status *s);
#define VDO_MAX_ERROR 256
struct vdo_status_parse_result {
char error[VDO_MAX_ERROR];
struct vdo_status *status;
};
// Parses the status line from the kernel target.
bool vdo_status_parse(const char *input, struct vdo_status_parse_result *result);
//----------------------------------------------------------------
#endif

View File

@@ -207,10 +207,6 @@ Optional feature arguments are:
block, then the cache block is invalidated.
To enable passthrough mode the cache must be clean.
metadata2 : use version 2 of the metadata. This stores the dirty bits
in a separate btree, which improves speed of shutting
down the cache.
A policy called 'default' is always registered. This is an alias for
the policy we currently think is giving best all round performance.
@@ -290,7 +286,7 @@ message, which takes an arbitrary number of cblock ranges. Each cblock
range's end value is "one past the end", meaning 5-10 expresses a range
of values from 5 to 9. Each cblock must be expressed as a decimal
value, in the future a variant message that takes cblock ranges
expressed in hexadecimal may be needed to better support efficient
expressed in hexidecimal may be needed to better support efficient
invalidation of larger caches. The cache must be in passthrough mode
when invalidate_cblocks is used.

View File

@@ -11,57 +11,23 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
<offset> [<#opt_params> <opt_params>]
<cipher>
Encryption cipher, encryption mode and Initial Vector (IV) generator.
The cipher specifications format is:
cipher[:keycount]-chainmode-ivmode[:ivopts]
Encryption cipher and an optional IV generation mode.
(In format cipher[:keycount]-chainmode-ivmode[:ivopts]).
Examples:
des
aes-cbc-essiv:sha256
aes-xts-plain64
serpent-xts-plain64
twofish-ecb
Cipher format also supports direct specification with kernel crypt API
format (selected by capi: prefix). The IV specification is the same
as for the first format type.
This format is mainly used for specification of authenticated modes.
The crypto API cipher specifications format is:
capi:cipher_api_spec-ivmode[:ivopts]
Examples:
capi:cbc(aes)-essiv:sha256
capi:xts(aes)-plain64
Examples of authenticated modes:
capi:gcm(aes)-random
capi:authenc(hmac(sha256),xts(aes))-random
capi:rfc7539(chacha20,poly1305)-random
The /proc/crypto contains a list of curently loaded crypto modes.
/proc/crypto contains supported crypto modes
<key>
Key used for encryption. It is encoded either as a hexadecimal number
or it can be passed as <key_string> prefixed with single colon
character (':') for keys residing in kernel keyring service.
Key used for encryption. It is encoded as a hexadecimal number.
You can only use key sizes that are valid for the selected cipher
in combination with the selected iv mode.
Note that for some iv modes the key string can contain additional
keys (for example IV seed) so the key contains more parts concatenated
into a single string.
<key_string>
The kernel keyring key is identified by string in following format:
<key_size>:<key_type>:<key_description>.
<key_size>
The encryption key size in bytes. The kernel key payload size must match
the value passed in <key_size>.
<key_type>
Either 'logon' or 'user' kernel key type.
<key_description>
The kernel keyring key description crypt target should look for
when loading key of <key_type>.
<keycount>
Multi-key compatibility mode. You can define <keycount> keys and
then sectors are encrypted according to their offsets (sector 0 uses key0;
@@ -110,32 +76,6 @@ submit_from_crypt_cpus
thread because it benefits CFQ to have writes submitted using the
same context.
integrity:<bytes>:<type>
The device requires additional <bytes> metadata per-sector stored
in per-bio integrity structure. This metadata must by provided
by underlying dm-integrity target.
The <type> can be "none" if metadata is used only for persistent IV.
For Authenticated Encryption with Additional Data (AEAD)
the <type> is "aead". An AEAD mode additionally calculates and verifies
integrity for the encrypted device. The additional space is then
used for storing authentication tag (and persistent IV if needed).
sector_size:<bytes>
Use <bytes> as the encryption unit instead of 512 bytes sectors.
This option can be in range 512 - 4096 bytes and must be power of two.
Virtual device will announce this size as a minimal IO and logical sector.
iv_large_sectors
IV generators will use sector number counted in <sector_size> units
instead of default 512 bytes sectors.
For example, if <sector_size> is 4096 bytes, plain64 IV for the second
sector will be 8 (without flag) and 1 if iv_large_sectors is present.
The <iv_offset> must be multiple of <sector_size> (in 512 bytes units)
if this flag is specified.
Example scripts
===============
LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
@@ -145,13 +85,7 @@ https://gitlab.com/cryptsetup/cryptsetup
[[
#!/bin/sh
# Create a crypt device using dmsetup
dmsetup create crypt1 --table "0 `blockdev --getsz $1` crypt aes-cbc-essiv:sha256 babebabebabebabebabebabebabebabe 0 $1 0"
]]
[[
#!/bin/sh
# Create a crypt device using dmsetup when encryption key is stored in keyring service
dmsetup create crypt2 --table "0 `blockdev --getsize $1` crypt aes-cbc-essiv:sha256 :32:logon:my_prefix:my_key 0 $1 0"
dmsetup create crypt1 --table "0 `blockdev --getsize $1` crypt aes-cbc-essiv:sha256 babebabebabebabebabebabebabebabe 0 $1 0"
]]
[[

View File

@@ -16,12 +16,12 @@ Example scripts
[[
#!/bin/sh
# Create device delaying rw operation for 500ms
echo "0 `blockdev --getsz $1` delay $1 0 500" | dmsetup create delayed
echo "0 `blockdev --getsize $1` delay $1 0 500" | dmsetup create delayed
]]
[[
#!/bin/sh
# Create device delaying only write operation for 500ms and
# splitting reads and writes to different devices $1 $2
echo "0 `blockdev --getsz $1` delay $1 0 0 $2 0 500" | dmsetup create delayed
echo "0 `blockdev --getsize $1` delay $1 0 0 $2 0 500" | dmsetup create delayed
]]

View File

@@ -42,7 +42,7 @@ Optional feature parameters:
<direction>: Either 'r' to corrupt reads or 'w' to corrupt writes.
'w' is incompatible with drop_writes.
<value>: The value (from 0-255) to write.
<flags>: Perform the replacement only if bio->bi_opf has all the
<flags>: Perform the replacement only if bio->bi_rw has all the
selected flags set.
Examples:

View File

@@ -1,199 +0,0 @@
The dm-integrity target emulates a block device that has additional
per-sector tags that can be used for storing integrity information.
A general problem with storing integrity tags with every sector is that
writing the sector and the integrity tag must be atomic - i.e. in case of
crash, either both sector and integrity tag or none of them is written.
To guarantee write atomicity, the dm-integrity target uses journal, it
writes sector data and integrity tags into a journal, commits the journal
and then copies the data and integrity tags to their respective location.
The dm-integrity target can be used with the dm-crypt target - in this
situation the dm-crypt target creates the integrity data and passes them
to the dm-integrity target via bio_integrity_payload attached to the bio.
In this mode, the dm-crypt and dm-integrity targets provide authenticated
disk encryption - if the attacker modifies the encrypted device, an I/O
error is returned instead of random data.
The dm-integrity target can also be used as a standalone target, in this
mode it calculates and verifies the integrity tag internally. In this
mode, the dm-integrity target can be used to detect silent data
corruption on the disk or in the I/O path.
When loading the target for the first time, the kernel driver will format
the device. But it will only format the device if the superblock contains
zeroes. If the superblock is neither valid nor zeroed, the dm-integrity
target can't be loaded.
To use the target for the first time:
1. overwrite the superblock with zeroes
2. load the dm-integrity target with one-sector size, the kernel driver
will format the device
3. unload the dm-integrity target
4. read the "provided_data_sectors" value from the superblock
5. load the dm-integrity target with the the target size
"provided_data_sectors"
6. if you want to use dm-integrity with dm-crypt, load the dm-crypt target
with the size "provided_data_sectors"
Target arguments:
1. the underlying block device
2. the number of reserved sector at the beginning of the device - the
dm-integrity won't read of write these sectors
3. the size of the integrity tag (if "-" is used, the size is taken from
the internal-hash algorithm)
4. mode:
D - direct writes (without journal) - in this mode, journaling is
not used and data sectors and integrity tags are written
separately. In case of crash, it is possible that the data
and integrity tag doesn't match.
J - journaled writes - data and integrity tags are written to the
journal and atomicity is guaranteed. In case of crash,
either both data and tag or none of them are written. The
journaled mode degrades write throughput twice because the
data have to be written twice.
R - recovery mode - in this mode, journal is not replayed,
checksums are not checked and writes to the device are not
allowed. This mode is useful for data recovery if the
device cannot be activated in any of the other standard
modes.
5. the number of additional arguments
Additional arguments:
journal_sectors:number
The size of journal, this argument is used only if formatting the
device. If the device is already formatted, the value from the
superblock is used.
interleave_sectors:number
The number of interleaved sectors. This values is rounded down to
a power of two. If the device is already formatted, the value from
the superblock is used.
buffer_sectors:number
The number of sectors in one buffer. The value is rounded down to
a power of two.
The tag area is accessed using buffers, the buffer size is
configurable. The large buffer size means that the I/O size will
be larger, but there could be less I/Os issued.
journal_watermark:number
The journal watermark in percents. When the size of the journal
exceeds this watermark, the thread that flushes the journal will
be started.
commit_time:number
Commit time in milliseconds. When this time passes, the journal is
written. The journal is also written immediatelly if the FLUSH
request is received.
internal_hash:algorithm(:key) (the key is optional)
Use internal hash or crc.
When this argument is used, the dm-integrity target won't accept
integrity tags from the upper target, but it will automatically
generate and verify the integrity tags.
You can use a crc algorithm (such as crc32), then integrity target
will protect the data against accidental corruption.
You can also use a hmac algorithm (for example
"hmac(sha256):0123456789abcdef"), in this mode it will provide
cryptographic authentication of the data without encryption.
When this argument is not used, the integrity tags are accepted
from an upper layer target, such as dm-crypt. The upper layer
target should check the validity of the integrity tags.
journal_crypt:algorithm(:key) (the key is optional)
Encrypt the journal using given algorithm to make sure that the
attacker can't read the journal. You can use a block cipher here
(such as "cbc(aes)") or a stream cipher (for example "chacha20",
"salsa20", "ctr(aes)" or "ecb(arc4)").
The journal contains history of last writes to the block device,
an attacker reading the journal could see the last sector nubmers
that were written. From the sector numbers, the attacker can infer
the size of files that were written. To protect against this
situation, you can encrypt the journal.
journal_mac:algorithm(:key) (the key is optional)
Protect sector numbers in the journal from accidental or malicious
modification. To protect against accidental modification, use a
crc algorithm, to protect against malicious modification, use a
hmac algorithm with a key.
This option is not needed when using internal-hash because in this
mode, the integrity of journal entries is checked when replaying
the journal. Thus, modified sector number would be detected at
this stage.
block_size:number
The size of a data block in bytes. The larger the block size the
less overhead there is for per-block integrity metadata.
Supported values are 512, 1024, 2048 and 4096 bytes. If not
specified the default block size is 512 bytes.
The journal mode (D/J), buffer_sectors, journal_watermark, commit_time can
be changed when reloading the target (load an inactive table and swap the
tables with suspend and resume). The other arguments should not be changed
when reloading the target because the layout of disk data depend on them
and the reloaded target would be non-functional.
The layout of the formatted block device:
* reserved sectors (they are not used by this target, they can be used for
storing LUKS metadata or for other purpose), the size of the reserved
area is specified in the target arguments
* superblock (4kiB)
* magic string - identifies that the device was formatted
* version
* log2(interleave sectors)
* integrity tag size
* the number of journal sections
* provided data sectors - the number of sectors that this target
provides (i.e. the size of the device minus the size of all
metadata and padding). The user of this target should not send
bios that access data beyond the "provided data sectors" limit.
* flags - a flag is set if journal_mac is used
* journal
The journal is divided into sections, each section contains:
* metadata area (4kiB), it contains journal entries
every journal entry contains:
* logical sector (specifies where the data and tag should
be written)
* last 8 bytes of data
* integrity tag (the size is specified in the superblock)
every metadata sector ends with
* mac (8-bytes), all the macs in 8 metadata sectors form a
64-byte value. It is used to store hmac of sector
numbers in the journal section, to protect against a
possibility that the attacker tampers with sector
numbers in the journal.
* commit id
* data area (the size is variable; it depends on how many journal
entries fit into the metadata area)
every sector in the data area contains:
* data (504 bytes of data, the last 8 bytes are stored in
the journal entry)
* commit id
To test if the whole journal section was written correctly, every
512-byte sector of the journal ends with 8-byte commit id. If the
commit id matches on all sectors in a journal section, then it is
assumed that the section was written correctly. If the commit id
doesn't match, the section was written partially and it should not
be replayed.
* one or more runs of interleaved tags and data. Each run contains:
* tag area - it contains integrity tags. There is one tag for each
sector in the data area
* data area - it contains data sectors. The number of data sectors
in one run must be a power of two. log2 of this value is stored
in the superblock.

View File

@@ -16,15 +16,15 @@ Example scripts
[[
#!/bin/sh
# Create an identity mapping for a device
echo "0 `blockdev --getsz $1` linear $1 0" | dmsetup create identity
echo "0 `blockdev --getsize $1` linear $1 0" | dmsetup create identity
]]
[[
#!/bin/sh
# Join 2 devices together
size1=`blockdev --getsz $1`
size2=`blockdev --getsz $2`
size1=`blockdev --getsize $1`
size2=`blockdev --getsize $2`
echo "0 $size1 linear $1 0
$size1 $size2 linear $2 0" | dmsetup create joined
]]
@@ -44,7 +44,7 @@ if (!defined($dev)) {
die("Please specify a device.\n");
}
my $dev_size = `blockdev --getsz $dev`;
my $dev_size = `blockdev --getsize $dev`;
my $extents = int($dev_size / $extent_size) -
(($dev_size % $extent_size) ? 1 : 0);

View File

@@ -14,14 +14,14 @@ Log Ordering
We log things in order of completion once we are sure the write is no longer in
cache. This means that normal WRITE requests are not actually logged until the
next REQ_PREFLUSH request. This is to make it easier for userspace to replay
the log in a way that correlates to what is on disk and not what is in cache,
to make it easier to detect improper waiting/flushing.
next REQ_FLUSH request. This is to make it easier for userspace to replay the
log in a way that correlates to what is on disk and not what is in cache, to
make it easier to detect improper waiting/flushing.
This works by attaching all WRITE requests to a list once the write completes.
Once we see a REQ_PREFLUSH request we splice this list onto the request and once
Once we see a REQ_FLUSH request we splice this list onto the request and once
the FLUSH request completes we log all of the WRITEs and then the FLUSH. Only
completed WRITEs, at the time the REQ_PREFLUSH is issued, are added in order to
completed WRITEs, at the time the REQ_FLUSH is issued, are added in order to
simulate the worst case scenario with regard to power failures. Consider the
following example (W means write, C means complete):

View File

@@ -14,12 +14,8 @@ The target is named "raid" and it accepts the following parameters:
<#raid_devs> <metadata_dev0> <dev0> [.. <metadata_devN> <devN>]
<raid_type>:
raid0 RAID0 striping (no resilience)
raid1 RAID1 mirroring
raid4 RAID4 with dedicated last parity disk
raid5_n RAID5 with dedicated last parity disk supporting takeover
Same as raid4
-Transitory layout
raid4 RAID4 dedicated parity disk
raid5_la RAID5 left asymmetric
- rotating parity 0 with data continuation
raid5_ra RAID5 right asymmetric
@@ -34,19 +30,7 @@ The target is named "raid" and it accepts the following parameters:
- rotating parity N (right-to-left) with data restart
raid6_nc RAID6 N continue
- rotating parity N (right-to-left) with data continuation
raid6_n_6 RAID6 with dedicate parity disks
- parity and Q-syndrome on the last 2 disks;
layout for takeover from/to raid4/raid5_n
raid6_la_6 Same as "raid_la" plus dedicated last Q-syndrome disk
- layout for takeover from raid5_la from/to raid6
raid6_ra_6 Same as "raid5_ra" dedicated last Q-syndrome disk
- layout for takeover from raid5_ra from/to raid6
raid6_ls_6 Same as "raid5_ls" dedicated last Q-syndrome disk
- layout for takeover from raid5_ls from/to raid6
raid6_rs_6 Same as "raid5_rs" dedicated last Q-syndrome disk
- layout for takeover from raid5_rs from/to raid6
raid10 Various RAID10 inspired algorithms chosen by additional params
(see raid10_format and raid10_copies below)
- RAID10: Striped Mirrors (aka 'Striping on top of mirrors')
- RAID1E: Integrated Adjacent Stripe Mirroring
- RAID1E: Integrated Offset Stripe Mirroring
@@ -132,57 +116,10 @@ The target is named "raid" and it accepts the following parameters:
Here we see layouts closely akin to 'RAID1E - Integrated
Offset Stripe Mirroring'.
[delta_disks <N>]
The delta_disks option value (-251 < N < +251) triggers
device removal (negative value) or device addition (positive
value) to any reshape supporting raid levels 4/5/6 and 10.
RAID levels 4/5/6 allow for addition of devices (metadata
and data device tuple), raid10_near and raid10_offset only
allow for device addition. raid10_far does not support any
reshaping at all.
A minimum of devices have to be kept to enforce resilience,
which is 3 devices for raid4/5 and 4 devices for raid6.
[data_offset <sectors>]
This option value defines the offset into each data device
where the data starts. This is used to provide out-of-place
reshaping space to avoid writing over data whilst
changing the layout of stripes, hence an interruption/crash
may happen at any time without the risk of losing data.
E.g. when adding devices to an existing raid set during
forward reshaping, the out-of-place space will be allocated
at the beginning of each raid device. The kernel raid4/5/6/10
MD personalities supporting such device addition will read the data from
the existing first stripes (those with smaller number of stripes)
starting at data_offset to fill up a new stripe with the larger
number of stripes, calculate the redundancy blocks (CRC/Q-syndrome)
and write that new stripe to offset 0. Same will be applied to all
N-1 other new stripes. This out-of-place scheme is used to change
the RAID type (i.e. the allocation algorithm) as well, e.g.
changing from raid5_ls to raid5_n.
[journal_dev <dev>]
This option adds a journal device to raid4/5/6 raid sets and
uses it to close the 'write hole' caused by the non-atomic updates
to the component devices which can cause data loss during recovery.
The journal device is used as writethrough thus causing writes to
be throttled versus non-journaled raid4/5/6 sets.
Takeover/reshape is not possible with a raid4/5/6 journal device;
it has to be deconfigured before requesting these.
[journal_mode <mode>]
This option sets the caching mode on journaled raid4/5/6 raid sets
(see 'journal_dev <dev>' above) to 'writethrough' or 'writeback'.
If 'writeback' is selected the journal device has to be resilient
and must not suffer from the 'write hole' problem itself (e.g. use
raid1 or raid10) to avoid a single point of failure.
<#raid_devs>: The number of devices composing the array.
Each device consists of two entries. The first is the device
containing the metadata (if any); the second is the one containing the
data. A Maximum of 64 metadata/data device entries are supported
up to target version 1.8.0.
1.9.0 supports up to 253 which is enforced by the used MD kernel runtime.
data.
If a drive has failed or is missing at creation time, a '-' can be
given for both the metadata and data drives for a given position.
@@ -258,14 +195,6 @@ recovery. Here is a fuller description of the individual fields:
in RAID1/10 or wrong parity values found in RAID4/5/6.
This value is valid only after a "check" of the array
is performed. A healthy array has a 'mismatch_cnt' of 0.
<data_offset> The current data offset to the start of the user data on
each component device of a raid set (see the respective
raid parameter to support out-of-place reshaping).
<journal_char> 'A' - active write-through journal device.
'a' - active write-back journal device.
'D' - dead journal device.
'-' - no journal device.
Message Interface
-----------------
@@ -278,6 +207,7 @@ include:
"recover"- Initiate/continue a recover process.
"check" - Initiate a check (i.e. a "scrub") of the array.
"repair" - Initiate a repair of the array.
"reshape"- Currently unsupported (-EINVAL).
Discard Support
@@ -327,19 +257,3 @@ Version History
1.5.2 'mismatch_cnt' is zero unless [last_]sync_action is "check".
1.6.0 Add discard support (and devices_handle_discard_safely module param).
1.7.0 Add support for MD RAID0 mappings.
1.8.0 Explicitly check for compatible flags in the superblock metadata
and reject to start the raid set if any are set by a newer
target version, thus avoiding data corruption on a raid set
with a reshape in progress.
1.9.0 Add support for RAID level takeover/reshape/region size
and set size reduction.
1.9.1 Fix activation of existing RAID 4/10 mapped devices
1.9.2 Don't emit '- -' on the status table line in case the constructor
fails reading a superblock. Correctly emit 'maj:min1 maj:min2' and
'D' on the status line. If '- -' is passed into the constructor, emit
'- -' on the table line and '-' as the status line health character.
1.10.0 Add support for raid4/5/6 journal device
1.10.1 Fix data corruption on reshape request
1.11.0 Fix table line argument order
(wrong raid10_copies/raid10_format sequence)
1.11.1 Add raid4/5/6 journal write-back support via journal_mode option

View File

@@ -37,9 +37,9 @@ if (!$num_devs) {
die("Specify at least one device\n");
}
$min_dev_size = `blockdev --getsz $devs[0]`;
$min_dev_size = `blockdev --getsize $devs[0]`;
for ($i = 1; $i < $num_devs; $i++) {
my $this_size = `blockdev --getsz $devs[$i]`;
my $this_size = `blockdev --getsize $devs[$i]`;
$min_dev_size = ($min_dev_size < $this_size) ?
$min_dev_size : $this_size;
}

View File

@@ -123,7 +123,7 @@ Assume that you have volumes vg1/switch0 vg1/switch1 vg1/switch2 with
the same size.
Create a switch device with 64kB region size:
dmsetup create switch --table "0 `blockdev --getsz /dev/vg1/switch0`
dmsetup create switch --table "0 `blockdev --getsize /dev/vg1/switch0`
switch 3 128 0 /dev/vg1/switch0 0 /dev/vg1/switch1 0 /dev/vg1/switch2 0"
Set mappings for the first 7 entries to point to devices switch0, switch1,

View File

@@ -1,144 +0,0 @@
dm-zoned
========
The dm-zoned device mapper target exposes a zoned block device (ZBC and
ZAC compliant devices) as a regular block device without any write
pattern constraints. In effect, it implements a drive-managed zoned
block device which hides from the user (a file system or an application
doing raw block device accesses) the sequential write constraints of
host-managed zoned block devices and can mitigate the potential
device-side performance degradation due to excessive random writes on
host-aware zoned block devices.
For a more detailed description of the zoned block device models and
their constraints see (for SCSI devices):
http://www.t10.org/drafts.htm#ZBC_Family
and (for ATA devices):
http://www.t13.org/Documents/UploadedDocuments/docs2015/di537r05-Zoned_Device_ATA_Command_Set_ZAC.pdf
The dm-zoned implementation is simple and minimizes system overhead (CPU
and memory usage as well as storage capacity loss). For a 10TB
host-managed disk with 256 MB zones, dm-zoned memory usage per disk
instance is at most 4.5 MB and as little as 5 zones will be used
internally for storing metadata and performaing reclaim operations.
dm-zoned target devices are formatted and checked using the dmzadm
utility available at:
https://github.com/hgst/dm-zoned-tools
Algorithm
=========
dm-zoned implements an on-disk buffering scheme to handle non-sequential
write accesses to the sequential zones of a zoned block device.
Conventional zones are used for caching as well as for storing internal
metadata.
The zones of the device are separated into 2 types:
1) Metadata zones: these are conventional zones used to store metadata.
Metadata zones are not reported as useable capacity to the user.
2) Data zones: all remaining zones, the vast majority of which will be
sequential zones used exclusively to store user data. The conventional
zones of the device may be used also for buffering user random writes.
Data in these zones may be directly mapped to the conventional zone, but
later moved to a sequential zone so that the conventional zone can be
reused for buffering incoming random writes.
dm-zoned exposes a logical device with a sector size of 4096 bytes,
irrespective of the physical sector size of the backend zoned block
device being used. This allows reducing the amount of metadata needed to
manage valid blocks (blocks written).
The on-disk metadata format is as follows:
1) The first block of the first conventional zone found contains the
super block which describes the on disk amount and position of metadata
blocks.
2) Following the super block, a set of blocks is used to describe the
mapping of the logical device blocks. The mapping is done per chunk of
blocks, with the chunk size equal to the zoned block device size. The
mapping table is indexed by chunk number and each mapping entry
indicates the zone number of the device storing the chunk of data. Each
mapping entry may also indicate if the zone number of a conventional
zone used to buffer random modification to the data zone.
3) A set of blocks used to store bitmaps indicating the validity of
blocks in the data zones follows the mapping table. A valid block is
defined as a block that was written and not discarded. For a buffered
data chunk, a block is always valid only in the data zone mapping the
chunk or in the buffer zone of the chunk.
For a logical chunk mapped to a conventional zone, all write operations
are processed by directly writing to the zone. If the mapping zone is a
sequential zone, the write operation is processed directly only if the
write offset within the logical chunk is equal to the write pointer
offset within of the sequential data zone (i.e. the write operation is
aligned on the zone write pointer). Otherwise, write operations are
processed indirectly using a buffer zone. In that case, an unused
conventional zone is allocated and assigned to the chunk being
accessed. Writing a block to the buffer zone of a chunk will
automatically invalidate the same block in the sequential zone mapping
the chunk. If all blocks of the sequential zone become invalid, the zone
is freed and the chunk buffer zone becomes the primary zone mapping the
chunk, resulting in native random write performance similar to a regular
block device.
Read operations are processed according to the block validity
information provided by the bitmaps. Valid blocks are read either from
the sequential zone mapping a chunk, or if the chunk is buffered, from
the buffer zone assigned. If the accessed chunk has no mapping, or the
accessed blocks are invalid, the read buffer is zeroed and the read
operation terminated.
After some time, the limited number of convnetional zones available may
be exhausted (all used to map chunks or buffer sequential zones) and
unaligned writes to unbuffered chunks become impossible. To avoid this
situation, a reclaim process regularly scans used conventional zones and
tries to reclaim the least recently used zones by copying the valid
blocks of the buffer zone to a free sequential zone. Once the copy
completes, the chunk mapping is updated to point to the sequential zone
and the buffer zone freed for reuse.
Metadata Protection
===================
To protect metadata against corruption in case of sudden power loss or
system crash, 2 sets of metadata zones are used. One set, the primary
set, is used as the main metadata region, while the secondary set is
used as a staging area. Modified metadata is first written to the
secondary set and validated by updating the super block in the secondary
set, a generation counter is used to indicate that this set contains the
newest metadata. Once this operation completes, in place of metadata
block updates can be done in the primary metadata set. This ensures that
one of the set is always consistent (all modifications committed or none
at all). Flush operations are used as a commit point. Upon reception of
a flush request, metadata modification activity is temporarily blocked
(for both incoming BIO processing and reclaim process) and all dirty
metadata blocks are staged and updated. Normal operation is then
resumed. Flushing metadata thus only temporarily delays write and
discard requests. Read requests can be processed concurrently while
metadata flush is being executed.
Usage
=====
A zoned block device must first be formatted using the dmzadm tool. This
will analyze the device zone configuration, determine where to place the
metadata sets on the device and initialize the metadata sets.
Ex:
dmzadm --format /dev/sdxx
For a formatted device, the target can be created normally with the
dmsetup utility. The only parameter that dm-zoned requires is the
underlying zoned block device name. Ex:
echo "0 `blockdev --getsize ${dev}` zoned ${dev}" | dmsetup create dmz-`basename ${dev}`

View File

@@ -1,338 +0,0 @@
LVM disk reading
Reading disks happens in two phases. The first is a discovery phase,
which determines what's on the disks. The second is a working phase,
which does a particular job for the command.
Phase 1: Discovery
------------------
Read all the disks on the system to find out:
- What are the LVM devices?
- What VG's exist on those devices?
This phase is called "label scan" (although it reads and scans everything,
not just the label.) It stores the information it discovers (what LVM
devices exist, and what VGs exist on them) in lvmcache. The devs/VGs info
in lvmcache is the starting point for phase two.
Phase 1 in outline:
For each device:
a. Read the first <N> KB of the device. (N is configurable.)
b. Look for the lvm label_header in the first four sectors,
if none exists, it's not an lvm device, so quit looking at it.
(By default, label_header is in the second sector.)
c. Look at the pv_header, which follows the label_header.
This tells us the location of VG metadata on the device.
There can be 0, 1 or 2 copies of VG metadata. The first
is always at the start of the device, the second (if used)
is at the end.
d. Look at the first mda_header (location came from pv_header
in the previous step). This is by default in sector 8,
4096 bytes from the start of the device. This tells us the
location of the actual VG metadata text.
e. Look at the first copy of the text VG metadata (location came
from mda_header in the previous step). This is by default
in sector 9, 4608 bytes from the start of the device.
The VG metadata is only partially analyzed to create a basic
summary of the VG.
f. Store an "info" entry in lvmcache for this device,
indicating that it is an lvm device, and store a "vginfo"
entry in lvmcache indicating the name of the VG seen
in the metadata in step e.
g. If the pv_header in step c shows a second mda_header
location at the end of the device, then read that as
in step d, and repeat steps e-f for it.
At the end of phase 1, lvmcache will have a list of devices
that belong to LVM, and a list of VG names that exist on
those devices. Each device (info struct) is associated
with the VG (vginfo struct) it is used in.
Phase 1 in code:
The most relevant functions are listed for each step in the outline.
lvmcache_label_scan()
label_scan()
. dev_cache_scan()
choose which devices on the system to look at
. for each dev in dev_cache: bcache prefetch/read
. _process_block() to process data from bcache
_find_lvm_header() checks if this is an lvm dev by looking at label_header
_text_read() via ops->read() looks at mda/pv/vg data to populate lvmcache
. _read_mda_header_and_metadata()
raw_read_mda_header()
. _read_mda_header_and_metadata()
read_metadata_location()
text_read_metadata_summary()
config_file_read_fd()
_read_vgsummary() via ops->read_vgsummary()
. _text_read(): lvmcache_add()
[adds this device to list of lvm devices]
_read_mda_header_and_metadata(): lvmcache_update_vgname_and_id()
[adds the VG name to list of VGs]
Phase 2: Work
-------------
This phase carries out the operation requested by the command that was
run.
Whereas the first phase is based on iterating through each device on the
system, this phase is based on iterating through each VG name. The list
of VG names comes from phase 1, which stored the list in lvmcache to be
used by phase 2.
Some commands may need to iterate through all VG names, while others may
need to iterate through just one or two.
This phase includes locking each VG as work is done on it, so that two
commands do not interfere with each other.
Phase 2 in outline:
For each VG name:
a. Lock the VG.
b. Repeat the phase 1 scan steps for each device in this VG.
The phase 1 information in lvmcache may have changed because no VG lock
was held during phase 1. So, repeat the phase 1 steps, but only for the
devices in this VG. N.B. for commands that are just reporting data,
we skip this step if the data from phase 1 was complete and consistent.
c. Get the list of on-disk metadata locations for this VG.
Phase 1 created this list in lvmcache to be used here. At this
point we copy it out of lvmcache. In the simple/common case,
this is a list of devices in the VG. But, some devices may
have 0 or 2 metadata locations instead of the default 1, so it
is not always equal to the list of devices. We want to read
every copy of the metadata for this VG.
d. For each metadata location on each device in the VG
(the list from the previous step):
1) Look at the mda_header. The location of the mda_header was saved
in the lvmcache info struct by phase 1 (where it came from the
pv_header.) The mda_header tells us where the text VG metadata is
located.
2) Look at the text VG metadata. The location came from mda_header
in the previous step. The VG metadata is fully analyzed and used
to create an in-memory 'struct volume_group'.
e. Compare the copies of VG metadata that were found in each location.
If some copies are older, choose the newest one to use, and update
any older copies.
f. Update details about the devices/VG in lvmcache.
g. Pass the 'vg' struct to the command-specific code to work with.
Phase 2 in code:
The most relevant functions are listed for each step in the outline.
For each VG name:
process_each_vg()
. vg_read()
lock_vol()
. vg_read()
lvmcache_label_rescan_vg() (if needed)
[insert phase 1 steps for scanning devs, but only devs in this vg]
. vg_read()
create_instance()
_text_create_text_instance()
_create_vg_text_instance()
lvmcache_fid_add_mdas_vg()
[Copies mda locations from info->mdas where it was saved
by phase 1, into fid->metadata_areas_in_use. This is
the key connection between phase 1 and phase 2.]
. dm_list_iterate_items(mda, &fid->metadata_areas_in_use)
. _vg_read_raw() via ops->vg_read()
raw_read_mda_header()
. _vg_read_raw()
text_read_metadata()
config_file_read_fd()
_read_vg() via ops->read_vg()
. return the 'vg' struct from vg_read() and use it to do
command-specific work
Filter i/o
----------
Some filters must be applied before reading a device, and other filters
must be applied after reading a device. In all cases, the filters must be
applied before lvm processes the device, i.e. before it looks for an lvm
label.
1. Some filters need to be applied prior to reading any devices
because the purpose of the filter is to avoid submitting any
io on the excluded devices. The regex filter is the primary
example. Other filters benefit from being applied prior to
reading devices because they can tell which devices to
exclude without doing io to the device. An example of this
is the mpath filter.
2. Some filters need to be applied after reading a device because
they are based on data/signatures seen on the device.
The partitioned filter is an example of this; lvm needs to
read a device to see if it has a partition table before it can
know whether to exclude the device from further processing.
We apply filters from 1 before reading devices, and we apply filters from
2 after populating bcache, but before processing the device (i.e. before
checking for an lvm label, which is the first step in processing.)
The current implementation of this makes filters return -EAGAIN if they
want to read the device, but bcache data is not yet available. This will
happen when filtering runs prior to populating bcache. In this case the
device is flagged. After bcache is populated, the filters are reapplied
to the flagged devices. The filters which need to look at device content
are now able to get it from bcache. Devices that do not pass filters at
this point are excluded just like devices which were excluded earlier.
(Some filters from 2 can be skipped by consulting udev for the information
instead of reading the device. This is not entirely reliable, so it is
disabled by default with the config setting external_device_info_source.
It may be worthwhile to change the filters to use the udev info as a hint,
or only use udev info for filtering in reporting commands where
inaccuracies are not a big problem.)
I/O Performance
---------------
. 400 loop devices used as PVs
. 40 VGs each with 10 PVs
. each VG has one active LV
. each of the 10 PVs in vg0 has an artificial 100 ms read delay
. read/write/io_submit are system call counts using strace
. old is lvm 2.2.175
. new is lvm 2.2.178 (shortly before)
Command: pvs
------------
old: 0m17.422s
new: 0m0.331s
old: read 7773 write 497
new: read 2807 write 495 io_submit 448
Command: vgs
------------
old: 0m20.383s
new: 0m0.325s
old: read 10684 write 129
new: read 2807 write 129 io_submit 448
Command: vgck vg0
-----------------
old: 0m16.212s
new: 0m1.290s
old: read 6372 write 4
new: read 2807 write 4 io_submit 458
Command: lvcreate -n test -l1 -an vg0
-------------------------------------
old: 0m29.271s
new: 0m1.351s
old: read 6503 write 39
new: read 2808 write 9 io_submit 488
Command: lvremove vg0/test
--------------------------
old: 0m29.262s
new: 0m1.348s
old: read 6502 write 36
new: read 2807 write 6 io_submit 488
io_submit sources
-----------------
vgs:
reads:
- 400 for each PV
- 40 for each LV
- 8 for other devs on the system
vgck vg0:
reads:
- 400 for each PV
- 40 for each LV
- 10 for each PV in vg0 (rescan)
- 8 for other devs on the system
lvcreate -n test -l1 -an vg0
reads:
- 400 for each PV
- 40 for each LV
- 10 for each PV in vg0 (rescan)
- 8 for other devs on the system
writes:
- 10 for metadata on each PV in vg0
- 10 for precommit on each PV in vg0
- 10 for commit on each PV in vg0
With lvmetad
------------
Command: pvs
------------
old: 0m5.405s
new: 0m1.404s
Command: vgs
------------
old: 0m0.222s
new: 0m0.223s
Command: lvcreate -n test -l1 -an vg0
-------------------------------------
old: 0m10.128s
new: 0m1.137s

View File

@@ -1,158 +0,0 @@
Over time, I'd like to refactor the LVM code into these high level modules.
+-------------------------------------------+
| |
| User Interface |
| |
| |
+-------------------+-----------------------+
|
+--------------------v-----------------------+
| |
| LVM Core |
| |
| |
+----+----------------+-----------------+----+
| | |
+-----v-----+ +-----v------+ +------v----+
| | | | | |
| Device | | Metadata | | System |
| Mapper | | | | |
| | | | | |
| | | | | |
| | | | | |
+-----------+ +------------+ +-----------+
+---------------------------------------------------------+
+------------------------------------+
| |
| Base |
| |
| |
| |
| |
+------------------------------------+
Going from the bottom up we have:
Base
----
This holds all our general purpose code such as data structures, regex engine,
memory allocators. In fact pretty much everything in libdevmapper apart from
the dm code and config.
This can be used by any code in the system, which is why I've drawn a line
between it and the code above rather than using arrows.
If anyone can come up with a better name please do. I'm trying to stay away
from 'utils'.
Device mapper
-------------
As well as the low level dm-ioctl driving code we need to have all our dm 'best
practise' stuff in here. For instance this is the code that decides to use the
mirror target to move some data around; that knows to suspend a thin volume
before taking a snapshot of it. This module is going to have a lot more code
in it than the current libdevmapper.
It should not know anything about the LVM abstractions or metadata (no PVs, LVs
or VGs). It just knows about the dm world.
Code in here is only allowed to use base.
Metadata model
--------------
Here we have all the format handling, labelling, config parsing etc. We try
and put *everything* to do with LVM in here that doesn't actually require dm.
System
------
Code that interfaces with the system (udev etc).
LVM Core
--------
[terrible name]
This ties together the last 3 units. It should just be glue. We need to be
strict about pushing code down from here to keep this as small as possible.
User interface
--------------
Self explanatory.
Headers
-------
Headers will be included using sub directories to make it clearer where they
are in the tree.
eg,
#include "base/mm/pool.h"
#include "base/data-struct/list.h"
#include "dm/thin-provisioning.h"
#include "core/pvmove.h"
Getting there
=============
+-------------------------------------------+
| |
| |
| Tools |
| |
| |
| |
+---------+------------------------------+--+
| |
| +---------------v---------------------------+
| | |
| | |
| | Lib |
| | |
| | |
| | |
| | |
| +----------------+--------------------------+
| |
| |
+-----v-------------------------------v-----+
| |
| |
| libdevmapper |
| |
| |
| |
| |
+-------------------------------------------+
This is where I see us now.
'base' should be easy to factor out, it's just the non-dm part of libdevmapper
(ie. the bulk of it). But we have the problem that libdevmapper is a public
interface to get round.
'lib' is where the bulk of our code currently is. Dependency-wise the code is
a bit like a ball of string. So splitting it up is going to take time. We can
probably pull code pretty quickly into the 'metadata model' dir. But factoring
out the dm best practises stuff is going to require splitting at least
files, and probably functions. Certainly not something that can be done in one
go. System should just be a question of cherry picking functions.
I'm not too familiar with the tools dir. Hopefully it just corresponds with
the User Interface module and doesn't contain any business logic.

View File

@@ -1,257 +0,0 @@
Building unit tests
===================
make unit-unit/unit-test
Running unit tests
==================
The tests leave no artifacts at the moment, so you can just run
unit-test/unit-test from wherever you want.
./unit-test <list|run> [pattern]
Listing tests
-------------
Every test has a symbolic path associated with it. Just like file paths they
are split into components separated by '/'s. The 'list' command will show you
a tree of these tests, along with some description text.
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list
base
data-struct
bitset
and ................................................. and all bits
equal ............................................... equality
get_next ............................................ get next set bit
list
splice .............................................. joining lists together
string
asprint ............................................. tests asprint
strncpy ............................................. tests string copying
device
bcache
block-size-multiple-page ............................ block size must be a multiple of page size
block-size-positive ................................. block size must be positive
blocks-get-evicted .................................. block get evicted with many reads
cache-blocks-positive ............................... nr cache blocks must be positive
create-destroy ...................................... simple create/destroy
flush-waits ......................................... flush waits for all dirty
get-reads ........................................... bcache_get() triggers read
prefetch-never-waits ................................ too many prefetches does not trigger a wait
prefetch-reads ...................................... prefetch issues a read
read-multiple-files ................................. read from multiple files
reads-cached ........................................ repeated reads are cached
writeback-occurs .................................... dirty data gets written back
zero-flag-dirties ................................... zeroed data counts as dirty
formatting
percent
0 ................................................... Pretty printing of percentages near 0%
100 ................................................. Pretty printing of percentages near 100%
regex
fingerprints .......................................... not sure
matching .............................................. test the matcher with a variety of regexes
dm
target
mirror
status .............................................. parsing mirror status
metadata
config
cascade ............................................... cascade
clone ................................................. duplicating a config tree
parse ................................................. parsing various
An optional 'pattern' argument may be specified to select subsets of tests.
This pattern is a posix regex and does a substring match, so you will need to
use anchors if you particularly want the match at the beginning or end of the
string.
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list data-struct
base
data-struct
bitset
and ................................................. and all bits
equal ............................................... equality
get_next ............................................ get next set bit
list
splice .............................................. joining lists together
string
asprint ............................................. tests asprint
strncpy ............................................. tests string copying
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list s$
base
device
bcache
flush-waits ......................................... flush waits for all dirty
get-reads ........................................... bcache_get() triggers read
prefetch-never-waits ................................ too many prefetches does not trigger a wait
prefetch-reads ...................................... prefetch issues a read
read-multiple-files ................................. read from multiple files
writeback-occurs .................................... dirty data gets written back
zero-flag-dirties ................................... zeroed data counts as dirty
regex
fingerprints .......................................... not sure
dm
target
mirror
status .............................................. parsing mirror status
Running tests
=============
'make run-unit-test' from the top level will run all unit tests. But I tend to
run it by hand to I can select just the tests I'm working on.
Use the 'run' command to run the tests. Currently all logging goes to stderr,
so the test runner prints a line at the start of the test and a line
indicating success or failure at the end.
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test run bcache/block-size
[RUN ] /base/device/bcache/block-size-multiple-page
bcache block size must be a multiple of page size
bcache block size must be a multiple of page size
bcache block size must be a multiple of page size
bcache block size must be a multiple of page size
[ OK] /base/device/bcache/block-size-multiple-page
[RUN ] /base/device/bcache/block-size-positive
bcache must have a non zero block size
[ OK] /base/device/bcache/block-size-positive
2/2 tests passed
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test run data-struct
[RUN ] /base/data-struct/bitset/and
[ OK] /base/data-struct/bitset/and
[RUN ] /base/data-struct/bitset/equal
[ OK] /base/data-struct/bitset/equal
[RUN ] /base/data-struct/bitset/get_next
[ OK] /base/data-struct/bitset/get_next
[RUN ] /base/data-struct/list/splice
[ OK] /base/data-struct/list/splice
[RUN ] /base/data-struct/string/asprint
[ OK] /base/data-struct/string/asprint
[RUN ] /base/data-struct/string/strncpy
[ OK] /base/data-struct/string/strncpy
6/6 tests passed
Writing tests
=============
[See unit-test/framework.h and unit-test/units.h for the details]
Tests are grouped together into 'suites', all tests in a suite share a
'fixture'. A fixture is a void * to any object you want; use it to set up any
common environment that you need for the tests to run (eg, creating a dm_pool).
Test suites have nothing to do with the test paths, you can have tests from
different suites with similar paths, the runner sorts things for you.
Put your tests in a file in unit-test/, with '_t' at the end of the name
(convention only, nothing relies on this).
#include "units.h"
Then write any fixtures you need:
eg,
static void *_mem_init(void) {
struct dm_pool *mem = dm_pool_create("bitset test", 1024);
if (!mem) {
fprintf(stderr, "out of memory\n");
exit(1);
}
return mem;
}
static void _mem_exit(void *mem)
{
dm_pool_destroy(mem);
}
Then write your tests, which should take the void * that was returned by your
fixture. Use the T_ASSERT* macros to indicate failure.
eg,
static void test_equal(void *fixture)
{
struct dm_pool *mem = fixture;
dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
int i, j;
for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
dm_bit_set(bs1, i);
dm_bit_set(bs2, i);
}
T_ASSERT(dm_bitset_equal(bs1, bs2));
T_ASSERT(dm_bitset_equal(bs2, bs1));
for (i = 0; i < NR_BITS; i++) {
bit_flip(bs1, i);
T_ASSERT(!dm_bitset_equal(bs1, bs2));
T_ASSERT(!dm_bitset_equal(bs2, bs1));
T_ASSERT(dm_bitset_equal(bs1, bs1)); /* comparing with self */
bit_flip(bs1, i);
}
}
At the end of your test file you should write a function that builds one or
more test suites and adds them to the list of all suites that is passed in. I
tend to write a little macro (T) to save typing the same test path repeatedly.
eg,
#define T(path, desc, fn) register_test(ts, "/base/data-struct/bitset/" path, desc, fn)
void bitset_tests(struct dm_list *all_tests)
{
struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
if (!ts) {
fprintf(stderr, "out of memory\n");
exit(1);
}
T("get_next", "get next set bit", test_get_next);
T("equal", "equality", test_equal);
T("and", "and all bits", test_and);
dm_list_add(all_tests, &ts->list);
}
Then you need to declare your registration function and call it in units.h.
// Declare the function that adds tests suites here ...
...
void bitset_tests(struct dm_list *suites);
...
// ... and call it in here.
static inline void register_all_tests(struct dm_list *suites)
{
...
bitset_tests(suites);
...
}
Finally add your test file to the Makefile.in and rerun configure.

View File

@@ -1,104 +0,0 @@
# VDO - Compression and deduplication.
Currently device stacking looks like this:
Physical x [multipath] x [partition] x [mdadm] x [LUKS] x [LVS] x [LUKS] x [FS|Database|...]
Adding VDO:
Physical x [multipath] x [partition] x [mdadm] x [LUKS] x [LVS] x [LUKS] x VDO x [LVS] x [FS|Database|...]
## Where VDO fits (and where it does not):
### Backing devices for VDO volumes:
1. Physical x [multipath] x [partition] x [mdadm],
2. LUKS over (1) - full disk encryption.
3. LVs (raids|mirror|stripe|linear) x [cache] over (1).
4. LUKS over (3) - especially when using raids.
Usual limitations apply:
- Never layer LUKS over another LUKS - it makes no sense.
- LUKS is better over the raids, than under.
Devices which are not best suitable as backing device:
- thin volumes - at the moment it is not possible to take snapshot of active VDO volume on top of thin volume.
### Using VDO as a PV:
1. under tdata
- The best fit - it will deduplicate additional redundancies among all
snapshots and will reduce the footprint.
- Risks: Resize! dmevent will not be able to handle resizing of tpool ATM.
2. under corig
- This is useful to keep the most frequently used data in cache
uncompressed or without deduplication if that happens to be a bottleneck.
- Cache may fit better under VDO device, depending on compressibility and
amount of duplicates, as
- compression will reduce amount of data, thus effectively increasing
size of cache,
- and deduplication may emphasize hotspots.
- Performance testing of your particular workload is strongly recommended.
3. under (multiple) linear LVs - e.g. used for VMs.
### And where VDO does not fit:
- *never* use VDO under LUKS volumes
- these are random data and do not compress nor deduplicate well,
- *never* use VDO under cmeta and tmeta LVs
- these are random data and do not compress nor deduplicate well,
- under raids
- raid{4,5,6} scrambles data, so they do not deduplicate well,
- raid{1,4,5,6,10} also causes amount of data grow, so more (duplicit in
case of raid{1,10}) work has to be done in order to find less duplicates.
### And where it could be useful:
- under snapshot CoW device - when there are multiple of those it could deduplicate
## Development
### Things to decide
- under integrity devices
- VDO should work well for data blocks,
- but hashes are mostly unique and not compressible - were it possible it
would make sense to have separate imeta and idata volumes for integrity
devices.
### Future Integration of VDO into LVM:
One issue is using both LUKS and RAID under VDO. We have two options:
- use mdadm x LUKS x VDO+LV
- use LV RAID x LUKS x VDO+LV
In both cases dmeventd will not be able to resize the volume at the moment.
Another issue is duality of VDO - it can be used as a top level LV (with a
filesystem on top) but it can be used as "pool" for multiple devices too.
This will be solved in similar way thin pools allow multiple volumes.
Also VDO, has two sizes - its physical size and virtual size - and when
overprovisioning, just like tpool, we face same problems - VDO can get full,
without exposing it to a FS. dmeventd monitoring will be needed.
Another possible RFE is to split data and metadata - keep data on HDD and metadata on SSD.
## Issues / Testing
- fstrim/discard pass down - does it work with VDO?
- VDO can run in synchronous vs. asynchronous mode:
- synchronous for devices where write is safe after it is confirmed. Some
devices are lying.
- asynchronous for devices requiring flush.
- Multiple devices under VDO - need to find and expose common properties, or
not allow grouping them together. (This is same for all volumes with more
physical devices below.)
- pvmove changing characteristics of underlying device.
- autoactivation during boot?
- Q: can we use VDO for RootFS? Dracut!

View File

@@ -14,7 +14,6 @@
@top_srcdir@/lib/config/defaults.h
@top_srcdir@/lib/datastruct/btree.h
@top_srcdir@/lib/datastruct/str_list.h
@top_srcdir@/lib/device/bcache.h
@top_srcdir@/lib/device/dev-cache.h
@top_srcdir@/lib/device/dev-ext-udev-constants.h
@top_srcdir@/lib/device/dev-type.h

View File

@@ -1,4 +1,4 @@
/* include/configure.h.in. Generated from configure.ac by autoheader. */
/* include/configure.h.in. Generated from configure.in by autoheader. */
/* Define to 1 to use libblkid detection of signatures when wiping. */
#undef BLKID_WIPING_SUPPORT
@@ -148,9 +148,6 @@
/* Library version */
#undef DM_LIB_VERSION
/* Path to fsadm binary. */
#undef FSADM_PATH
/* Define to 1 if you have the `alarm' function. */
#undef HAVE_ALARM
@@ -249,9 +246,6 @@
/* Define to 1 if you have the <langinfo.h> header file. */
#undef HAVE_LANGINFO_H
/* Define to 1 if you have the <libaio.h> header file. */
#undef HAVE_LIBAIO_H
/* Define to 1 if you have the <libcman.h> header file. */
#undef HAVE_LIBCMAN_H
@@ -350,6 +344,9 @@
/* Define to 1 if the system has the type `ptrdiff_t'. */
#undef HAVE_PTRDIFF_T
/* Define to 1 if the compiler has the `__builtin_clz` builtin. */
#undef HAVE___BUILTIN_CLZ
/* Define to 1 if you have the <readline/history.h> header file. */
#undef HAVE_READLINE_HISTORY_H
@@ -478,16 +475,9 @@
/* Define to 1 if you have the `strtoull' function. */
#undef HAVE_STRTOULL
/* Define to 1 if `st_blocks' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_BLOCKS
/* Define to 1 if `st_rdev' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_RDEV
/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use
`HAVE_STRUCT_STAT_ST_BLOCKS' instead. */
#undef HAVE_ST_BLOCKS
/* Define to 1 if you have the <syslog.h> header file. */
#undef HAVE_SYSLOG_H
@@ -501,9 +491,6 @@
/* Define to 1 if you have the <sys/file.h> header file. */
#undef HAVE_SYS_FILE_H
/* Define to 1 if you have the <sys/inotify.h> header file. */
#undef HAVE_SYS_INOTIFY_H
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H
@@ -559,9 +546,6 @@
/* Define to 1 if you have the <sys/utsname.h> header file. */
#undef HAVE_SYS_UTSNAME_H
/* Define to 1 if you have the <sys/vfs.h> header file. */
#undef HAVE_SYS_VFS_H
/* Define to 1 if you have the <sys/wait.h> header file. */
#undef HAVE_SYS_WAIT_H
@@ -601,9 +585,6 @@
/* Define to 1 if the system has the type `_Bool'. */
#undef HAVE__BOOL
/* Define to 1 if the system has the `__builtin_clz' built-in function */
#undef HAVE___BUILTIN_CLZ
/* Internalization package */
#undef INTL_PACKAGE
@@ -645,9 +626,6 @@
/* Define to 1 to include code that uses lvmpolld. */
#undef LVMPOLLD_SUPPORT
/* configure command line used */
#undef LVM_CONFIGURE_LINE
/* Path to lvm binary. */
#undef LVM_PATH
@@ -698,6 +676,9 @@
/* Define to 1 to include the LVM readline shell. */
#undef READLINE_SUPPORT
/* Define to 1 to include built-in support for replicators. */
#undef REPLICATOR_INTERNAL
/* Define as the return type of signal handlers (`int' or `void'). */
#undef RETSIGTYPE

View File

@@ -24,20 +24,37 @@ ifeq ("@POOL@", "shared")
SUBDIRS += format_pool
endif
ifeq ("@CLUSTER@", "shared")
SUBDIRS += locking
ifeq ("@SNAPSHOTS@", "shared")
SUBDIRS += snapshot
endif
ifeq ("@MIRRORS@", "shared")
SUBDIRS += mirror
endif
ifeq ("@RAID@", "shared")
SUBDIRS += raid
endif
ifeq ("@REPLICATORS@", "shared")
SUBDIRS += replicator
endif
ifeq ("@THIN@", "shared")
SUBDIRS += thin
endif
ifeq ("@CACHE@", "shared")
SUBDIRS += cache_segtype
endif
SOURCES =\
activate/activate.c \
cache/lvmcache.c \
cache_segtype/cache.c \
commands/toolcontext.c \
config/config.c \
datastruct/btree.c \
datastruct/str_list.c \
device/bcache.c \
device/bcache-utils.c \
device/dev-cache.c \
device/dev-ext.c \
device/dev-io.c \
@@ -46,7 +63,6 @@ SOURCES =\
device/dev-type.c \
device/dev-luks.c \
device/dev-dasd.c \
device/dev-lvm1-pool.c \
display/display.c \
error/errseg.c \
unknown/unknown.c \
@@ -61,7 +77,6 @@ SOURCES =\
filters/filter-type.c \
filters/filter-usable.c \
filters/filter-internal.c \
filters/filter-signature.c \
format_text/archive.c \
format_text/archiver.c \
format_text/export.c \
@@ -81,18 +96,17 @@ SOURCES =\
metadata/lv_manip.c \
metadata/merge.c \
metadata/metadata.c \
metadata/metadata-liblvm.c \
metadata/mirror.c \
metadata/pool_manip.c \
metadata/pv.c \
metadata/pv_manip.c \
metadata/pv_map.c \
metadata/raid_manip.c \
metadata/replicator_manip.c \
metadata/segtype.c \
metadata/snapshot_manip.c \
metadata/thin_manip.c \
metadata/vg.c \
mirror/mirrored.c \
misc/crc.c \
misc/lvm-exec.c \
misc/lvm-file.c \
@@ -106,12 +120,9 @@ SOURCES =\
mm/memlock.c \
notify/lvmnotify.c \
properties/prop_common.c \
raid/raid.c \
report/properties.c \
report/report.c \
snapshot/snapshot.c \
striped/striped.c \
thin/thin.c \
uuid/uuid.c \
zero/zero.c
@@ -138,6 +149,34 @@ ifeq ("@CLUSTER@", "internal")
SOURCES += locking/cluster_locking.c
endif
ifeq ("@CLUSTER@", "shared")
SUBDIRS += locking
endif
ifeq ("@SNAPSHOTS@", "internal")
SOURCES += snapshot/snapshot.c
endif
ifeq ("@MIRRORS@", "internal")
SOURCES += mirror/mirrored.c
endif
ifeq ("@RAID@", "internal")
SOURCES += raid/raid.c
endif
ifeq ("@REPLICATORS@", "internal")
SOURCES += replicator/replicator.c
endif
ifeq ("@THIN@", "internal")
SOURCES += thin/thin.c
endif
ifeq ("@CACHE@", "internal")
SOURCES += cache_segtype/cache.c
endif
ifeq ("@DEVMAPPER@", "yes")
SOURCES +=\
activate/dev_manager.c \
@@ -165,6 +204,11 @@ ifeq ("@BUILD_LVMLOCKD@", "yes")
locking/lvmlockd.c
endif
ifeq ("@DMEVENTD@", "yes")
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
LIBS += -ldevmapper-event
endif
LIB_NAME = liblvm-internal
LIB_STATIC = $(LIB_NAME).a
@@ -172,17 +216,23 @@ ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS =\
format1 \
format_pool \
snapshot \
mirror \
notify \
raid \
replicator \
thin \
cache_segtype \
locking
endif
CFLOW_LIST = $(SOURCES)
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
PROGS_CFLAGS = $(BLKID_CFLAGS) $(UDEV_CFLAGS)
include $(top_builddir)/make.tmpl
CFLAGS += $(BLKID_CFLAGS) $(UDEV_CFLAGS) $(VALGRIND_CFLAGS)
$(SUBDIRS): $(LIB_STATIC)
CLEAN_TARGETS += misc/configure.h misc/lvm-version.h

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -83,7 +83,6 @@ struct lv_activate_opts {
* flags are persistent in udev db for any spurious event
* that follows. */
unsigned resuming; /* Set when resuming after a suspend. */
const struct logical_volume *component_lv;
};
void set_activation(int activation, int silent);
@@ -169,13 +168,11 @@ int lv_snapshot_percent(const struct logical_volume *lv, dm_percent_t *percent);
int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv,
int wait, dm_percent_t *percent, uint32_t *event_nr);
int lv_raid_percent(const struct logical_volume *lv, dm_percent_t *percent);
int lv_raid_dev_count(const struct logical_volume *lv, uint32_t *dev_cnt);
int lv_raid_data_offset(const struct logical_volume *lv, uint64_t *data_offset);
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_cache_status(const struct logical_volume *cache_lv,
int lv_cache_status(const struct logical_volume *lv,
struct lv_status_cache **status);
int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
dm_percent_t *percent);
@@ -199,22 +196,17 @@ int lv_is_active_exclusive(const struct logical_volume *lv);
int lv_is_active_exclusive_locally(const struct logical_volume *lv);
int lv_is_active_exclusive_remotely(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);
int deactivate_lv_with_sub_lv(const struct logical_volume *lv);
int lv_has_target_type(struct dm_pool *mem, const struct logical_volume *lv,
const char *layer, const char *target_type);
int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume *lv,
const struct lv_activate_opts *laopts, int monitor);
const struct lv_activate_opts *laopts, int do_reg);
#ifdef DMEVENTD
# include "libdevmapper-event.h"
char *get_monitor_dso_path(struct cmd_context *cmd, int id);
int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
const struct logical_volume *lv, int *pending, int *monitored);
char *get_monitor_dso_path(struct cmd_context *cmd, const char *libpath);
int target_registered_with_dmeventd(struct cmd_context *cmd, const char *libpath,
const struct logical_volume *lv, int *pending);
int target_register_events(struct cmd_context *cmd, const char *dso, const struct logical_volume *lv,
int evmask __attribute__((unused)), int set, int timeout);
#endif

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -32,8 +32,6 @@
#define MAX_TARGET_PARAMSIZE 50000
#define LVM_UDEV_NOSCAN_FLAG DM_SUBSYSTEM_UDEV_FLAG0
#define CRYPT_TEMP "CRYPT-TEMP"
#define STRATIS "stratis-"
typedef enum {
PRELOAD,
@@ -74,17 +72,10 @@ struct dev_manager {
struct lv_layer {
const struct logical_volume *lv;
const char *old_name;
int visible_component;
};
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts, const char *layer)
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts)
{
if (layer && lv_is_cow(lv))
return 0; /* Keep snapshot's COW volume writable */
if (lv_is_raid_image(lv) || lv_is_raid_metadata(lv))
return 0; /* Keep RAID SubLvs writable */
return (laopts->read_only || !(lv->status & LVM_WRITE));
}
@@ -223,14 +214,6 @@ typedef enum {
STATUS, /* DM_DEVICE_STATUS ioctl */
} info_type_t;
/* Return length of segment depending on type and reshape_len */
static uint32_t _seg_len(const struct lv_segment *seg)
{
uint32_t reshape_len = seg_is_raid(seg) ? ((seg->area_count - seg->segtype->parity_devs) * seg->reshape_len) : 0;
return seg->len - reshape_len;
}
static int _info_run(const char *dlid, struct dm_info *dminfo,
uint32_t *read_ahead,
struct lv_seg_status *seg_status,
@@ -267,12 +250,7 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
if (seg_status && dminfo->exists) {
start = length = seg_status->seg->lv->vg->extent_size;
start *= seg_status->seg->le;
length *= _seg_len(seg_status->seg);
/* Uses max DM_THIN_MAX_METADATA_SIZE sectors for metadata device */
if (lv_is_thin_pool_metadata(seg_status->seg->lv) &&
(length > DM_THIN_MAX_METADATA_SIZE))
length = DM_THIN_MAX_METADATA_SIZE;
length *= seg_status->seg->len;
do {
target = dm_get_next_target(dmt, target, &target_start,
@@ -284,8 +262,7 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
target_params = NULL; /* Marking this target_params unusable */
} while (target);
if (!target_name ||
!_get_segment_status_from_target_params(target_name, target_params, seg_status))
if (!_get_segment_status_from_target_params(target_name, target_params, seg_status))
stack;
}
@@ -450,21 +427,15 @@ static int _ignore_suspended_snapshot_component(struct device *dev)
do {
next = dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
if (!target_type)
continue;
if (!strcmp(target_type, TARGET_NAME_SNAPSHOT)) {
if (!target_type || !strcmp(target_type, TARGET_NAME_SNAPSHOT)) {
if (!params || sscanf(params, "%d:%d %d:%d", &major1, &minor1, &major2, &minor2) != 4) {
log_warn("WARNING: Incorrect snapshot table found for %d:%d.",
(int)MAJOR(dev->dev), (int)MINOR(dev->dev));
log_error("Incorrect snapshot table found.");
goto out;
}
r = r || _device_is_suspended(major1, minor1) || _device_is_suspended(major2, minor2);
} else if (!strcmp(target_type, TARGET_NAME_SNAPSHOT_ORIGIN)) {
if (!params || sscanf(params, "%d:%d", &major1, &minor1) != 2) {
log_warn("WARNING: Incorrect snapshot-origin table found for %d:%d.",
(int)MAJOR(dev->dev), (int)MINOR(dev->dev));
log_error("Incorrect snapshot-origin table found.");
goto out;
}
r = r || _device_is_suspended(major1, minor1);
@@ -499,7 +470,7 @@ static int _ignore_unusable_thins(struct device *dev)
dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
if (!params || sscanf(params, "%d:%d", &major, &minor) != 2) {
log_warn("WARNING: Cannot get thin-pool major:minor for thin device %d:%d.",
log_error("Failed to get thin-pool major:minor for thin device %d:%d.",
(int)MAJOR(dev->dev), (int)MINOR(dev->dev));
goto out;
}
@@ -529,47 +500,6 @@ out:
return r;
}
static int _ignore_invalid_snapshot(const char *params)
{
struct dm_status_snapshot *s;
struct dm_pool *mem;
int r = 0;
if (!(mem = dm_pool_create("invalid snapshots", 128)))
return_0;
if (!dm_get_status_snapshot(mem, params, &s))
stack;
else
r = s->invalid;
dm_pool_destroy(mem);
return r;
}
static int _ignore_frozen_raid(struct device *dev, const char *params)
{
struct dm_status_raid *s;
struct dm_pool *mem;
int r = 0;
if (!(mem = dm_pool_create("frozen raid", 128)))
return_0;
if (!dm_get_status_raid(mem, params, &s))
stack;
else if (s->sync_action && !strcmp(s->sync_action, "frozen")) {
log_warn("WARNING: %s frozen raid device (%d:%d) needs inspection.",
dev_name(dev), (int)MAJOR(dev->dev), (int)MINOR(dev->dev));
r = 1;
}
dm_pool_destroy(mem);
return r;
}
/*
* device_is_usable
* @dev
@@ -639,26 +569,12 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check)
}
}
if (check.check_reserved && uuid &&
(!strncmp(uuid, CRYPT_TEMP, sizeof(CRYPT_TEMP) - 1) ||
!strncmp(uuid, STRATIS, sizeof(STRATIS) - 1))) {
/* Skip private crypto devices */
log_debug_activation("%s: Reserved uuid %s on %s device %s not usable.",
dev_name(dev), uuid,
uuid[0] == 'C' ? "crypto" : "stratis",
name);
goto out;
}
/* FIXME Also check for mpath no paths */
do {
next = dm_get_next_target(dmt, next, &start, &length,
&target_type, &params);
if (!target_type)
continue;
if (check.check_blocked && !strcmp(target_type, TARGET_NAME_MIRROR)) {
if (check.check_blocked && target_type && !strcmp(target_type, TARGET_NAME_MIRROR)) {
if (ignore_lvm_mirrors()) {
log_debug_activation("%s: Scanning mirror devices is disabled.", dev_name(dev));
goto out;
@@ -692,33 +608,21 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check)
* correctly, not just snapshots but any cobimnation possible
* in a stack - use proper dm tree to check this instead.
*/
if (check.check_suspended &&
if (check.check_suspended && target_type &&
(!strcmp(target_type, TARGET_NAME_SNAPSHOT) || !strcmp(target_type, TARGET_NAME_SNAPSHOT_ORIGIN)) &&
_ignore_suspended_snapshot_component(dev)) {
log_debug_activation("%s: %s device %s not usable.", dev_name(dev), target_type, name);
goto out;
}
if (!strcmp(target_type, TARGET_NAME_SNAPSHOT) &&
_ignore_invalid_snapshot(params)) {
log_debug_activation("%s: Invalid %s device %s not usable.", dev_name(dev), target_type, name);
goto out;
}
if (!strncmp(target_type, TARGET_NAME_RAID, 4) && _ignore_frozen_raid(dev, params)) {
log_debug_activation("%s: Frozen %s device %s not usable.",
dev_name(dev), target_type, name);
goto out;
}
/* TODO: extend check struct ? */
if (!strcmp(target_type, TARGET_NAME_THIN) &&
if (target_type && !strcmp(target_type, TARGET_NAME_THIN) &&
!_ignore_unusable_thins(dev)) {
log_debug_activation("%s: %s device %s not usable.", dev_name(dev), target_type, name);
goto out;
}
if (strcmp(target_type, TARGET_NAME_ERROR))
if (target_type && strcmp(target_type, TARGET_NAME_ERROR))
only_error_target = 0;
} while (next);
@@ -1120,8 +1024,7 @@ static int _percent_run(struct dev_manager *dm, const char *name,
goto_out;
}
log_debug_activation("LV percent: %s",
display_percent(dm->cmd, *overall_percent));
log_debug_activation("LV percent: %.2f", dm_percent_to_float(*overall_percent));
r = 1;
out:
@@ -1138,11 +1041,10 @@ static int _percent(struct dev_manager *dm, const char *name, const char *dlid,
if (_percent_run(dm, NULL, dlid, target_type, wait, lv, percent,
event_nr, fail_if_percent_unsupported))
return 1;
if (_original_uuid_format_check_required(dm->cmd) &&
_percent_run(dm, NULL, dlid + sizeof(UUID_PREFIX) - 1,
target_type, wait, lv, percent,
event_nr, fail_if_percent_unsupported))
else if (_original_uuid_format_check_required(dm->cmd) &&
_percent_run(dm, NULL, dlid + sizeof(UUID_PREFIX) - 1,
target_type, wait, lv, percent,
event_nr, fail_if_percent_unsupported))
return 1;
}
@@ -1406,13 +1308,14 @@ int dev_manager_raid_message(struct dev_manager *dm,
return 0;
}
/* These are the supported RAID messages for dm-raid v1.9.0 */
/* These are the supported RAID messages for dm-raid v1.5.0 */
if (strcmp(msg, "idle") &&
strcmp(msg, "frozen") &&
strcmp(msg, "resync") &&
strcmp(msg, "recover") &&
strcmp(msg, "check") &&
strcmp(msg, "repair")) {
strcmp(msg, "repair") &&
strcmp(msg, "reshape")) {
log_error(INTERNAL_ERROR "Unknown RAID message: %s.", msg);
return 0;
}
@@ -1672,8 +1575,7 @@ int dev_manager_mknodes(const struct logical_volume *lv)
return_0;
if (dminfo.exists) {
/* read-only component LV is also made visible */
if (_lv_has_mknode(lv) || (dminfo.read_only && lv_is_component(lv)))
if (_lv_has_mknode(lv))
r = _dev_manager_lv_mknodes(lv);
} else
r = _dev_manager_lv_rmnodes(lv);
@@ -1735,8 +1637,7 @@ static int _check_udev_fallback(struct cmd_context *cmd)
#endif /* UDEV_SYNC_SUPPORT */
static uint16_t _get_udev_flags(struct dev_manager *dm, const struct logical_volume *lv,
const char *layer, int noscan, int temporary,
int visible_component)
const char *layer, int noscan, int temporary)
{
uint16_t udev_flags = 0;
@@ -1752,7 +1653,7 @@ static uint16_t _get_udev_flags(struct dev_manager *dm, const struct logical_vol
* If not, create just the /dev/mapper content.
*/
/* FIXME: add target's method for this */
if (lv_is_new_thin_pool(lv) || visible_component)
if (lv_is_new_thin_pool(lv))
/* New thin-pool is regular LV with -tpool UUID suffix. */
udev_flags |= DM_UDEV_DISABLE_DISK_RULES_FLAG |
DM_UDEV_DISABLE_OTHER_RULES_FLAG;
@@ -1801,114 +1702,6 @@ static uint16_t _get_udev_flags(struct dev_manager *dm, const struct logical_vol
return udev_flags;
}
static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
const struct logical_volume *lv, int origin_only);
static int _check_holder(struct dev_manager *dm, struct dm_tree *dtree,
const struct logical_volume *lv, uint32_t major,
const char *d_name)
{
const char *default_uuid_prefix = dm_uuid_prefix();
const size_t default_uuid_prefix_len = strlen(default_uuid_prefix);
const char *name;
const char *uuid;
struct dm_info info;
struct dm_task *dmt;
struct logical_volume *lv_det;
union lvid id;
int dev, r = 0;
errno = 0;
dev = strtoll(d_name + 3, NULL, 10);
if (errno) {
log_error("Failed to parse dm device minor number from %s.", d_name);
return 0;
}
if (!(dmt = _setup_task_run(DM_DEVICE_INFO, &info, NULL, NULL, NULL,
major, dev, 0, 0, 0)))
return_0;
if (info.exists) {
uuid = dm_task_get_uuid(dmt);
name = dm_task_get_name(dmt);
log_debug_activation("Checking holder of %s %s (" FMTu32 ":" FMTu32 ") %s.",
display_lvname(lv), uuid, info.major, info.minor,
name);
/* Skip common uuid prefix */
if (!strncmp(default_uuid_prefix, uuid, default_uuid_prefix_len))
uuid += default_uuid_prefix_len;
if (!strncmp(uuid, (char*)&lv->vg->id, sizeof(lv->vg->id)) &&
!dm_tree_find_node_by_uuid(dtree, uuid)) {
dm_strncpy((char*)&id, uuid, 2 * sizeof(struct id) + 1);
/* If UUID is not yet in dtree, look for matching LV */
if (!(lv_det = find_lv_in_vg_by_lvid(lv->vg, &id))) {
log_error("Cannot find holder with device name %s in VG %s.",
name, lv->vg->name);
goto out;
}
if (lv_is_cow(lv_det))
lv_det = origin_from_cow(lv_det);
log_debug_activation("Found holder %s of %s.",
display_lvname(lv_det),
display_lvname(lv));
if (!_add_lv_to_dtree(dm, dtree, lv_det, 0))
goto_out;
}
}
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
/*
* Add exiting devices which holds given LV device open.
* This is used in case when metadata already do not contain information
* i.e. PVMOVE is being finished and final table is going to be resumed.
*/
static int _add_holders_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
const struct logical_volume *lv, struct dm_info *info)
{
const char *sysfs_dir = dm_sysfs_dir();
char sysfs_path[PATH_MAX];
struct dirent *dirent;
DIR *d;
int r = 0;
/* Sysfs path of holders */
if (dm_snprintf(sysfs_path, sizeof(sysfs_path), "%sblock/dm-" FMTu32
"/holders", sysfs_dir, info->minor) < 0) {
log_error("sysfs_path dm_snprintf failed.");
return 0;
}
if (!(d = opendir(sysfs_path))) {
log_sys_error("opendir", sysfs_path);
return 0;
}
while ((dirent = readdir(d)))
/* Expects minor is added to 'dm-' prefix */
if (!strncmp(dirent->d_name, "dm-", 3) &&
!_check_holder(dm, dtree, lv, info->major, dirent->d_name))
goto_out;
r = 1;
out:
if (closedir(d))
log_sys_debug("closedir", "holders");
return r;
}
static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
const struct logical_volume *lv, const char *layer)
{
@@ -1950,8 +1743,7 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
}
if (info.exists && !dm_tree_add_dev_with_udev_flags(dtree, info.major, info.minor,
_get_udev_flags(dm, lv, layer,
0, 0, 0))) {
_get_udev_flags(dm, lv, layer, 0, 0))) {
log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to dtree.",
info.major, info.minor);
return 0;
@@ -1964,14 +1756,83 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
return_0;
}
/*
* Find holders of existing active LV where name starts with 'pvmove',
* but it's not anymore PVMOVE LV and also it's not PVMOVE _mimage
*/
if (info.exists && !lv_is_pvmove(lv) &&
!strchr(lv->name, '_') && !strncmp(lv->name, "pvmove", 6))
if (!_add_holders_to_dtree(dm, dtree, lv, &info))
return 1;
}
/*
* Add replicator devices
*
* Using _add_dev_to_dtree() directly instead of _add_lv_to_dtree()
* to avoid extra checks with extensions.
*/
static int _add_partial_replicator_to_dtree(struct dev_manager *dm,
struct dm_tree *dtree,
const struct logical_volume *lv)
{
struct logical_volume *rlv = first_seg(lv)->replicator;
struct replicator_device *rdev;
struct replicator_site *rsite;
struct dm_tree_node *rep_node, *rdev_node;
const char *uuid;
if (!lv_is_active_replicator_dev(lv)) {
if (!_add_dev_to_dtree(dm, dtree, lv->rdevice->lv,
NULL))
return_0;
return 1;
}
/* Add _rlog and replicator device */
if (!_add_dev_to_dtree(dm, dtree, first_seg(rlv)->rlog_lv, NULL))
return_0;
if (!_add_dev_to_dtree(dm, dtree, rlv, NULL))
return_0;
if (!(uuid = build_dm_uuid(dm->mem, rlv, NULL)))
return_0;
rep_node = dm_tree_find_node_by_uuid(dtree, uuid);
/* Add all related devices for replicator */
dm_list_iterate_items(rsite, &rlv->rsites)
dm_list_iterate_items(rdev, &rsite->rdevices) {
if (rsite->state == REPLICATOR_STATE_ACTIVE) {
/* Add _rimage LV */
if (!_add_dev_to_dtree(dm, dtree, rdev->lv, NULL))
return_0;
/* Add replicator-dev LV, except of the already added one */
if ((lv != rdev->replicator_dev->lv) &&
!_add_dev_to_dtree(dm, dtree,
rdev->replicator_dev->lv, NULL))
return_0;
/* If replicator exists - try connect existing heads */
if (rep_node) {
uuid = build_dm_uuid(dm->mem,
rdev->replicator_dev->lv,
NULL);
if (!uuid)
return_0;
rdev_node = dm_tree_find_node_by_uuid(dtree, uuid);
if (rdev_node)
dm_tree_node_set_presuspend_node(rdev_node,
rep_node);
}
}
if (!rdev->rsite->vg_name)
continue;
if (!_add_dev_to_dtree(dm, dtree, rdev->lv, NULL))
return_0;
if (rdev->slog &&
!_add_dev_to_dtree(dm, dtree, rdev->slog, NULL))
return_0;
}
return 1;
}
@@ -1983,60 +1844,13 @@ struct pool_cb_data {
int skip_zero; /* to skip zeroed device header (check first 64B) */
int exec; /* which binary to call */
int opts;
struct {
unsigned maj;
unsigned min;
unsigned patch;
} version;
const char *global;
};
/*
* Simple version of check function calling 'tool -V'
*
* Returns 1 if the tool's version is equal or better to given.
* Otherwise it returns 0.
*/
static int _check_tool_version(struct cmd_context *cmd, const char *tool,
unsigned maj, unsigned min, unsigned patch)
{
const char *argv[] = { tool, "-V", NULL };
struct pipe_data pdata;
FILE *f;
char buf[128] = { 0 };
char *nl;
unsigned v_maj, v_min, v_patch;
int ret = 0;
if (!(f = pipe_open(cmd, argv, 0, &pdata))) {
log_warn("WARNING: Cannot read output from %s.", argv[0]);
} else {
if (fgets(buf, sizeof(buf) - 1, f) &&
(sscanf(buf, "%u.%u.%u", &v_maj, &v_min, &v_patch) == 3)) {
if ((v_maj > maj) ||
((v_maj == maj) &&
((v_min > min) ||
(v_min == min && v_patch >= patch))))
ret = 1;
if ((nl = strchr(buf, '\n')))
nl[0] = 0; /* cut newline away */
log_verbose("Found version of %s %s is %s then requested %u.%u.%u.",
argv[0], buf, ret ? "better" : "older", maj, min, patch);
} else
log_warn("WARNING: Cannot parse output '%s' from %s.", buf, argv[0]);
(void) pipe_close(&pdata);
}
return ret;
}
static int _pool_callback(struct dm_tree_node *node,
dm_node_callback_t type, void *cb_data)
{
int ret, status = 0, fd;
int ret, status, fd;
const struct dm_config_node *cn;
const struct dm_config_value *cv;
const struct pool_cb_data *data = cb_data;
@@ -2044,45 +1858,12 @@ static int _pool_callback(struct dm_tree_node *node,
const struct logical_volume *mlv = first_seg(pool_lv)->metadata_lv;
long buf[64 / sizeof(long)]; /* buffer for short disk header (64B) */
int args = 0;
char *mpath;
const char *argv[19] = { /* Max supported 15 args */
find_config_tree_str_allow_empty(pool_lv->vg->cmd, data->exec, NULL)
find_config_tree_str_allow_empty(pool_lv->vg->cmd, data->exec, NULL) /* argv[0] */
};
if (!*argv[0]) /* *_check tool is unconfigured/disabled with "" setting */
return 1;
if (!(mpath = lv_dmpath_dup(data->dm->mem, mlv))) {
log_error("Failed to build device path for checking pool metadata %s.",
display_lvname(mlv));
return 0;
}
if (data->skip_zero) {
if ((fd = open(mpath, O_RDONLY)) < 0) {
log_sys_error("open", mpath);
return 0;
}
/* let's assume there is no problem to read 64 bytes */
if (read(fd, buf, sizeof(buf)) < (int)sizeof(buf)) {
log_sys_error("read", mpath);
if (close(fd))
log_sys_error("close", mpath);
return 0;
}
for (ret = 0; ret < (int) DM_ARRAY_SIZE(buf); ++ret)
if (buf[ret])
break;
if (close(fd))
log_sys_error("close", mpath);
if (ret == (int) DM_ARRAY_SIZE(buf)) {
log_debug_activation("Metadata checking skipped, detected empty disk header on %s.",
mpath);
return 1;
}
}
if (!*argv[0])
return 1; /* Checking disabled */
if (!(cn = find_config_tree_array(mlv->vg->cmd, data->opts, NULL))) {
log_error(INTERNAL_ERROR "Unable to find configuration for pool check options.");
@@ -2104,23 +1885,39 @@ static int _pool_callback(struct dm_tree_node *node,
return 0;
}
argv[++args] = mpath;
if (!(argv[++args] = lv_dmpath_dup(data->dm->mem, mlv))) {
log_error("Failed to build pool metadata path.");
return 0;
}
if (data->skip_zero) {
if ((fd = open(argv[args], O_RDONLY)) < 0) {
log_sys_error("open", argv[args]);
return 0;
}
/* let's assume there is no problem to read 64 bytes */
if (read(fd, buf, sizeof(buf)) < (int)sizeof(buf)) {
log_sys_error("read", argv[args]);
if (close(fd))
log_sys_error("close", argv[args]);
return 0;
}
for (ret = 0; ret < (int) DM_ARRAY_SIZE(buf); ++ret)
if (buf[ret])
break;
if (close(fd))
log_sys_error("close", argv[args]);
if (ret == (int) DM_ARRAY_SIZE(buf)) {
log_debug_activation("%s skipped, detect empty disk header on %s.",
argv[0], argv[args]);
return 1;
}
}
if (!(ret = exec_cmd(pool_lv->vg->cmd, (const char * const *)argv,
&status, 0))) {
if (status == ENOENT) {
log_warn("WARNING: Check is skipped, please install recommended missing binary %s!",
argv[0]);
return 1;
}
if ((data->version.maj || data->version.min || data->version.patch) &&
!_check_tool_version(pool_lv->vg->cmd, argv[0],
data->version.maj, data->version.min, data->version.patch)) {
log_warn("WARNING: Check is skipped, please upgrade installed version of %s!",
argv[0]);
return 1;
}
switch (type) {
case DM_NODE_CALLBACK_PRELOADED:
log_err_once("Check of pool %s failed (status:%d). "
@@ -2178,10 +1975,6 @@ static int _pool_register_callback(struct dev_manager *dm,
data->exec = global_cache_check_executable_CFG;
data->opts = global_cache_check_options_CFG;
data->global = "cache";
if (first_seg(first_seg(lv)->pool_lv)->cache_metadata_format > 1) {
data->version.maj = 0;
data->version.min = 7;
}
} else {
log_error(INTERNAL_ERROR "Registering unsupported pool callback.");
return 0;
@@ -2209,10 +2002,6 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
struct lv_segment *seg;
struct dm_tree_node *node;
const char *uuid;
const struct logical_volume *plv;
if (lv_is_pvmove(lv) && (dm->track_pvmove_deps == 2))
return 1; /* Avoid rechecking of already seen pvmove LV */
if (lv_is_cache_pool(lv)) {
if (!dm_list_empty(&lv->segs_using_this_lv)) {
@@ -2333,14 +2122,11 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
return_0;
/* Add any LVs referencing a PVMOVE LV unless told not to. */
if ((dm->track_pvmove_deps == 1) && lv_is_pvmove(lv)) {
dm->track_pvmove_deps = 2; /* Mark as already seen */
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
/* If LV is snapshot COW - whole snapshot needs reload */
plv = lv_is_cow(sl->seg->lv) ? origin_from_cow(sl->seg->lv) : sl->seg->lv;
if (!_add_lv_to_dtree(dm, dtree, plv, 0))
if (dm->track_pvmove_deps && lv_is_pvmove(lv)) {
dm->track_pvmove_deps = 0;
dm_list_iterate_items(sl, &lv->segs_using_this_lv)
if (!_add_lv_to_dtree(dm, dtree, sl->seg->lv, origin_only))
return_0;
}
dm->track_pvmove_deps = 1;
}
@@ -2355,6 +2141,11 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
}
}
/* Adding LV head of replicator adds all other related devs */
if (lv_is_replicator_dev(lv) &&
!_add_partial_replicator_to_dtree(dm, dtree, lv))
return_0;
/* Add any LVs used by segments in this LV */
dm_list_iterate_items(seg, &lv->segments) {
if (seg->external_lv && dm->track_external_lv_deps &&
@@ -2423,7 +2214,7 @@ static char *_add_error_or_zero_device(struct dev_manager *dm, struct dm_tree *d
struct lv_segment *seg_i;
struct dm_info info;
int segno = -1, i = 0;
uint64_t size = (uint64_t) _seg_len(seg) * seg->lv->vg->extent_size;
uint64_t size = (uint64_t) seg->len * seg->lv->vg->extent_size;
dm_list_iterate_items(seg_i, &seg->lv->segments) {
if (seg == seg_i) {
@@ -2709,7 +2500,7 @@ static int _add_target_to_dtree(struct dev_manager *dm,
return seg->segtype->ops->add_target_line(dm, dm->mem, dm->cmd,
&dm->target_state, seg,
laopts, dnode,
extent_size * _seg_len(seg),
extent_size * seg->len,
&dm->pvmove_mirror_count);
}
@@ -2718,6 +2509,64 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
struct lv_activate_opts *laopts,
const char *layer);
/* Add all replicators' LVs */
static int _add_replicator_dev_target_to_dtree(struct dev_manager *dm,
struct dm_tree *dtree,
struct lv_segment *seg,
struct lv_activate_opts *laopts)
{
struct replicator_device *rdev;
struct replicator_site *rsite;
/* For inactive replicator add linear mapping */
if (!lv_is_active_replicator_dev(seg->lv)) {
if (!_add_new_lv_to_dtree(dm, dtree, seg->lv->rdevice->lv, laopts, NULL))
return_0;
return 1;
}
/* Add rlog and replicator nodes */
if (!seg->replicator ||
!first_seg(seg->replicator)->rlog_lv ||
!_add_new_lv_to_dtree(dm, dtree,
first_seg(seg->replicator)->rlog_lv,
laopts, NULL) ||
!_add_new_lv_to_dtree(dm, dtree, seg->replicator, laopts, NULL))
return_0;
/* Activation of one replicator_dev node activates all other nodes */
dm_list_iterate_items(rsite, &seg->replicator->rsites) {
dm_list_iterate_items(rdev, &rsite->rdevices) {
if (rdev->lv &&
!_add_new_lv_to_dtree(dm, dtree, rdev->lv,
laopts, NULL))
return_0;
if (rdev->slog &&
!_add_new_lv_to_dtree(dm, dtree, rdev->slog,
laopts, NULL))
return_0;
}
}
/* Add remaining replicator-dev nodes in the second loop
* to avoid multiple retries for inserting all elements */
dm_list_iterate_items(rsite, &seg->replicator->rsites) {
if (rsite->state != REPLICATOR_STATE_ACTIVE)
continue;
dm_list_iterate_items(rdev, &rsite->rdevices) {
if (rdev->replicator_dev->lv == seg->lv)
continue;
if (!rdev->replicator_dev->lv ||
!_add_new_lv_to_dtree(dm, dtree,
rdev->replicator_dev->lv,
laopts, NULL))
return_0;
}
}
return 1;
}
static int _add_new_external_lv_to_dtree(struct dev_manager *dm,
struct dm_tree *dtree,
struct logical_volume *external_lv,
@@ -2818,6 +2667,11 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
lv_layer(seg->pool_lv)))
return_0;
if (seg_is_replicator_dev(seg)) {
if (!_add_replicator_dev_target_to_dtree(dm, dtree, seg, laopts))
return_0;
}
/* Add any LVs used by this segment */
for (s = 0; s < seg->area_count; ++s) {
if ((seg_type(seg, s) == AREA_LV) &&
@@ -2839,7 +2693,7 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
/* Replace target and all its used devs with error mapping */
log_debug_activation("Using error for pending delete %s.",
display_lvname(seg->lv));
if (!dm_tree_node_add_error_target(dnode, (uint64_t)seg->lv->vg->extent_size * _seg_len(seg)))
if (!dm_tree_node_add_error_target(dnode, (uint64_t)seg->lv->vg->extent_size * seg->len))
return_0;
} else if (!_add_target_to_dtree(dm, dnode, seg, laopts))
return_0;
@@ -2955,7 +2809,6 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
}
lvlayer->lv = lv;
lvlayer->visible_component = (laopts->component_lv == lv) ? 1 : 0;
/*
* Add LV to dtree.
@@ -2969,11 +2822,10 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
if (!(dnode = dm_tree_add_new_dev_with_udev_flags(dtree, name, dlid,
layer ? UINT32_C(0) : (uint32_t) lv->major,
layer ? UINT32_C(0) : (uint32_t) lv->minor,
read_only_lv(lv, laopts, layer),
read_only_lv(lv, laopts),
((lv->vg->status & PRECOMMITTED) | laopts->revert) ? 1 : 0,
lvlayer,
_get_udev_flags(dm, lv, layer, laopts->noscan, laopts->temporary,
lvlayer->visible_component))))
_get_udev_flags(dm, lv, layer, laopts->noscan, laopts->temporary))))
return_0;
/* Store existing name so we can do rename later */
@@ -3117,7 +2969,7 @@ static int _create_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root
r = 0;
continue;
}
if (_lv_has_mknode(lvlayer->lv) || lvlayer->visible_component) {
if (_lv_has_mknode(lvlayer->lv)) {
if (!_dev_manager_lv_mknodes(lvlayer->lv))
r = 0;
continue;
@@ -3289,6 +3141,8 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
if (!dm_tree_preload_children(root, dlid, DLID_SIZE))
goto_out;
//if (action == PRELOAD) { log_debug("SLEEP"); sleep(7); }
if ((dm_tree_node_size_changed(root) < 0))
dm->flush_required = 1;
/* Currently keep the code require flush for any
@@ -3311,6 +3165,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
log_error(INTERNAL_ERROR "_tree_action: Action %u not supported.", action);
goto out;
}
r = 1;
out:

View File

@@ -27,7 +27,7 @@ struct dm_info;
struct device;
struct lv_seg_status;
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts, const char *layer);
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts);
/*
* Constructor and destructor.

View File

@@ -186,11 +186,11 @@ static int _mk_link(const char *dev_dir, const char *vg_name,
!stat(lv_path, &buf)) {
if (buf_lp.st_rdev == buf.st_rdev)
return 1;
log_warn("Symlink %s that should have been "
"created by udev does not have "
"correct target. Falling back to "
"direct link creation", lv_path);
else
log_warn("Symlink %s that should have been "
"created by udev does not have "
"correct target. Falling back to "
"direct link creation", lv_path);
} else
log_warn("Symlink %s that should have been "
"created by udev could not be checked "
@@ -239,9 +239,7 @@ static int _rm_link(const char *dev_dir, const char *vg_name,
return 1;
log_sys_error("lstat", lv_path);
return 0;
}
if (dm_udev_get_sync_support() && udev_checking() && check_udev)
} else if (dm_udev_get_sync_support() && udev_checking() && check_udev)
log_warn("The link %s should have been removed by udev "
"but it is still present. Falling back to "
"direct link removal.", lv_path);
@@ -441,7 +439,7 @@ static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
const char *lv_name, const char *dev, const char *old_lv_name,
int check_udev)
{
if (prioritized_section()) {
if (critical_section()) {
if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev,
old_lv_name, check_udev))
return_0;
@@ -480,14 +478,14 @@ int fs_rename_lv(const struct logical_volume *lv, const char *dev,
_fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name,
lv->name, dev, "", lv->vg->cmd->current_settings.udev_rules));
}
return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
dev, old_lvname, lv->vg->cmd->current_settings.udev_rules);
else
return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
dev, old_lvname, lv->vg->cmd->current_settings.udev_rules);
}
void fs_unlock(void)
{
if (!prioritized_section()) {
if (!critical_section()) {
log_debug_activation("Syncing device names");
/* Wait for all processed udev devices */
if (!dm_udev_wait(_fs_cookie))

1402
lib/cache/lvmcache.c vendored

File diff suppressed because it is too large Load Diff

48
lib/cache/lvmcache.h vendored
View File

@@ -59,17 +59,21 @@ struct lvmcache_vgsummary {
const char *lock_type;
uint32_t mda_checksum;
size_t mda_size;
int zero_offset;
int seqno;
};
int lvmcache_init(struct cmd_context *cmd);
int lvmcache_init(void);
void lvmcache_allow_reads_with_lvmetad(void);
void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset);
/*
* lvmcache_label_scan() will scan labels the first time it's
* called, but not on subsequent calls, unless
* lvmcache_force_next_label_scan() is called first
* to force the next lvmcache_label_scan() to scan again.
*/
void lvmcache_force_next_label_scan(void);
int lvmcache_label_scan(struct cmd_context *cmd);
int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid);
/* Add/delete a device */
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
@@ -78,7 +82,6 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
uint32_t vgstatus);
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 lvmcache_info *info,
@@ -102,8 +105,10 @@ 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);
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_pvid(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector);
const char *lvmcache_pvid_from_devname(struct cmd_context *cmd, const char *devname);
struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
unsigned *scan_done_once, uint64_t *label_sector);
const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
const char *devname);
char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid);
const char *lvmcache_vgname_from_info(struct lvmcache_info *info);
const struct format_type *lvmcache_fmt_from_info(struct lvmcache_info *info);
@@ -129,16 +134,20 @@ int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
const char *vgid);
/* Returns cached volume group metadata. */
struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname,
const char *vgid, unsigned precommitted);
void lvmcache_drop_metadata(const char *vgname, int drop_precommitted);
void lvmcache_commit_metadata(const char *vgname);
int lvmcache_pvid_is_locked(const char *pvid);
int lvmcache_fid_add_mdas(struct lvmcache_info *info, struct format_instance *fid,
const char *id, int id_len);
int lvmcache_fid_add_mdas_pv(struct lvmcache_info *info, struct format_instance *fid);
int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_instance *fid);
int lvmcache_populate_pv_fields(struct lvmcache_info *info,
struct volume_group *vg,
struct physical_volume *pv);
struct physical_volume *pv,
int scan_label_only);
int lvmcache_check_format(struct lvmcache_info *info, const struct format_type *fmt);
void lvmcache_del_mdas(struct lvmcache_info *info);
void lvmcache_del_das(struct lvmcache_info *info);
@@ -155,8 +164,6 @@ uint32_t lvmcache_ext_flags(struct lvmcache_info *info);
const struct format_type *lvmcache_fmt(struct lvmcache_info *info);
struct label *lvmcache_get_label(struct lvmcache_info *info);
struct label *lvmcache_get_dev_label(struct device *dev);
int lvmcache_has_dev_info(struct device *dev);
void lvmcache_update_pv(struct lvmcache_info *info, struct physical_volume *pv,
const struct format_type *fmt);
@@ -174,12 +181,13 @@ int lvmcache_foreach_ba(struct lvmcache_info *info,
int (*fun)(struct disk_locn *, void *),
void *baton);
int lvmcache_foreach_pv(struct lvmcache_vginfo *vginfo,
int lvmcache_foreach_pv(struct lvmcache_vginfo *vg,
int (*fun)(struct lvmcache_info *, void *), void * baton);
uint64_t lvmcache_device_size(struct lvmcache_info *info);
void lvmcache_set_device_size(struct lvmcache_info *info, uint64_t size);
struct device *lvmcache_device(struct lvmcache_info *info);
void lvmcache_make_valid(struct lvmcache_info *info);
int lvmcache_is_orphan(struct lvmcache_info *info);
int lvmcache_uncertain_ownership(struct lvmcache_info *info);
unsigned lvmcache_mda_count(struct lvmcache_info *info);
@@ -207,20 +215,4 @@ void lvmcache_remove_unchosen_duplicate(struct device *dev);
int lvmcache_pvid_in_unchosen_duplicates(const char *pvid);
int lvmcache_get_vg_devs(struct cmd_context *cmd,
struct lvmcache_vginfo *vginfo,
struct dm_list *devs);
void lvmcache_set_independent_location(const char *vgname);
int lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid);
/*
* These are clvmd-specific functions and are not related to lvmcache.
* FIXME: rename these with a clvm_ prefix in place of lvmcache_
*/
void lvmcache_save_vg(struct volume_group *vg, int precommitted);
struct volume_group *lvmcache_get_saved_vg(const char *vgid, int precommitted);
struct volume_group *lvmcache_get_saved_vg_latest(const char *vgid);
void lvmcache_drop_saved_vgid(const char *vgid);
#endif

558
lib/cache/lvmetad.c vendored
View File

@@ -39,7 +39,7 @@ static int64_t _lvmetad_update_timeout;
static int _found_lvm1_metadata = 0;
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg, const char *vgid, struct format_type *fmt);
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
static uint64_t _monotonic_seconds(void)
{
@@ -66,7 +66,7 @@ static int _log_debug_inequality(const char *name, struct dm_config_node *a, str
log_debug_lvmetad("VG %s metadata inequality at %s / %s: %s / %s",
name, a->key, b->key, av->v.str, bv->v.str);
else if (a->v->type == DM_CFG_INT && b->v->type == DM_CFG_INT)
log_debug_lvmetad("VG %s metadata inequality at %s / %s: " FMTd64 " / " FMTd64,
log_debug_lvmetad("VG %s metadata inequality at %s / %s: " FMTi64 " / " FMTi64,
name, a->key, b->key, av->v.i, bv->v.i);
else
log_debug_lvmetad("VG %s metadata inequality at %s / %s: type %d / type %d",
@@ -145,14 +145,13 @@ int lvmetad_connect(struct cmd_context *cmd)
_lvmetad_use = 1;
_lvmetad_cmd = cmd;
return 1;
} else {
log_debug_lvmetad("Failed to connect to lvmetad: %s", strerror(_lvmetad.error));
_lvmetad_connected = 0;
_lvmetad_use = 0;
_lvmetad_cmd = NULL;
return 0;
}
log_debug_lvmetad("Failed to connect to lvmetad: %s", strerror(_lvmetad.error));
_lvmetad_connected = 0;
_lvmetad_use = 0;
_lvmetad_cmd = NULL;
return 0;
}
int lvmetad_used(void)
@@ -551,7 +550,6 @@ static int _token_update(int *replaced_update)
daemon_reply reply;
const char *token_expected;
const char *prev_token;
const char *reply_str;
int update_pid;
int ending_our_update;
@@ -568,14 +566,13 @@ static int _token_update(int *replaced_update)
}
update_pid = (int)daemon_reply_int(reply, "update_pid", 0);
reply_str = daemon_reply_str(reply, "response", "");
/*
* A mismatch can only happen when this command attempts to set the
* token to filter:<hash> at the end of its update, but the update has
* been preempted in lvmetad by a new one (from update_pid).
*/
if (!strcmp(reply_str, "token_mismatch")) {
if (!strcmp(daemon_reply_str(reply, "response", ""), "token_mismatch")) {
token_expected = daemon_reply_str(reply, "expected", "");
ending_our_update = strcmp(_lvmetad_token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS);
@@ -601,7 +598,7 @@ static int _token_update(int *replaced_update)
return 0;
}
if (strcmp(reply_str, "OK")) {
if (strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
log_error("Failed response from lvmetad for token update.");
daemon_reply_destroy(reply);
return 0;
@@ -628,7 +625,6 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
{
const char *token_expected;
const char *action;
const char *reply_str;
int action_modifies = 0;
int daemon_in_update;
int we_are_in_update;
@@ -666,15 +662,15 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
}
if (reply.error) {
log_error("lvmetad cannot be used due to error: %s", strerror(reply.error));
log_warn("WARNING: lvmetad cannot be used due to error: %s", strerror(reply.error));
goto fail;
}
/*
* Errors related to token mismatch.
*/
reply_str = daemon_reply_str(reply, "response", "");
if (!strcmp(reply_str, "token_mismatch")) {
if (!strcmp(daemon_reply_str(reply, "response", ""), "token_mismatch")) {
token_expected = daemon_reply_str(reply, "expected", "");
update_pid = (int)daemon_reply_int(reply, "update_pid", 0);
@@ -772,14 +768,14 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
*/
/* All OK? */
if (!strcmp(reply_str, "OK")) {
if (!strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
if (found)
*found = 1;
return 1;
}
/* Unknown device permitted? */
if (found && !strcmp(reply_str, "unknown")) {
if (found && !strcmp(daemon_reply_str(reply, "response", ""), "unknown")) {
log_very_verbose("Request to %s %s%sin lvmetad did not find any matching object.",
action, object, *object ? " " : "");
*found = 0;
@@ -787,7 +783,7 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
}
/* Multiple VGs with the same name were found. */
if (found && !strcmp(reply_str, "multiple")) {
if (found && !strcmp(daemon_reply_str(reply, "response", ""), "multiple")) {
log_very_verbose("Request to %s %s%sin lvmetad found multiple matching objects.",
action, object, *object ? " " : "");
if (found)
@@ -1093,17 +1089,14 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
* invalidated the cached vg.
*/
if (rescan) {
if (!(vg2 = _lvmetad_pvscan_vg(cmd, vg, vgid, fmt))) {
if (!(vg2 = lvmetad_pvscan_vg(cmd, vg))) {
log_debug_lvmetad("VG %s from lvmetad not found during rescan.", vgname);
fid = NULL;
release_vg(vg);
vg = NULL;
goto out;
}
fid->ref_count++;
release_vg(vg);
fid->ref_count--;
fmt->ops->destroy_instance(fid);
vg = vg2;
fid = vg2->fid;
}
@@ -1111,14 +1104,14 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
dm_list_iterate_items(pvl, &vg->pvs) {
if (!_pv_update_struct_pv(pvl->pv, fid)) {
vg = NULL;
goto_out; /* FIXME: use an error path that disables lvmetad */
goto_out; /* FIXME error path */
}
}
dm_list_iterate_items(pvl, &vg->pvs_outdated) {
if (!_pv_update_struct_pv(pvl->pv, fid)) {
vg = NULL;
goto_out; /* FIXME: use an error path that disables lvmetad */
goto_out; /* FIXME error path */
}
}
@@ -1287,7 +1280,7 @@ int lvmetad_vg_update_finish(struct volume_group *vg)
if (pvl->pv->dev && !lvmetad_pv_found(vg->cmd, &pvl->pv->id, pvl->pv->dev,
vgu->fid ? vgu->fid->fmt : pvl->pv->fmt,
pvl->pv->label_sector, NULL, NULL, NULL))
return_0;
return 0;
}
vg->lvmetad_update_pending = 0;
@@ -1311,7 +1304,7 @@ int lvmetad_vg_remove_pending(struct volume_group *vg)
reply = _lvmetad_send(vg->cmd, "set_vg_info",
"name = %s", vg->name,
"uuid = %s", uuid,
"version = %"PRId64, (int64_t)0,
"version = %d", 0,
NULL);
if (!_lvmetad_handle_reply(reply, "set_vg_info", vg->name, NULL)) {
@@ -1522,7 +1515,7 @@ int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd)
return 1;
}
struct extract_dl_baton {
struct _extract_dl_baton {
int i;
struct dm_config_tree *cft;
struct dm_config_node *pre_sib;
@@ -1530,7 +1523,7 @@ struct extract_dl_baton {
static int _extract_mda(struct metadata_area *mda, void *baton)
{
struct extract_dl_baton *b = baton;
struct _extract_dl_baton *b = baton;
struct dm_config_node *cn;
char id[32];
@@ -1551,7 +1544,7 @@ static int _extract_mda(struct metadata_area *mda, void *baton)
static int _extract_disk_location(const char *name, struct disk_locn *dl, void *baton)
{
struct extract_dl_baton *b = baton;
struct _extract_dl_baton *b = baton;
struct dm_config_node *cn;
char id[32];
@@ -1586,7 +1579,7 @@ static int _extract_ba(struct disk_locn *ba, void *baton)
static int _extract_mdas(struct lvmcache_info *info, struct dm_config_tree *cft,
struct dm_config_node *pre_sib)
{
struct extract_dl_baton baton = { .cft = cft };
struct _extract_dl_baton baton = { .cft = cft };
if (!lvmcache_foreach_mda(info, &_extract_mda, &baton))
return 0;
@@ -1613,7 +1606,7 @@ int lvmetad_pv_found(struct cmd_context *cmd, const struct id *pvid, struct devi
struct dm_config_tree *pvmeta, *vgmeta;
const char *status = NULL, *vgname = NULL;
int64_t changed = 0;
int result, seqno_after;
int result;
if (!lvmetad_used() || test_mode())
return 1;
@@ -1678,12 +1671,10 @@ int lvmetad_pv_found(struct cmd_context *cmd, const struct id *pvid, struct devi
result = _lvmetad_handle_reply(reply, "pv_found", uuid, NULL);
if (vg && result) {
seqno_after = daemon_reply_int(reply, "seqno_after", -1);
if ((seqno_after != (int) vg->seqno) ||
(seqno_after != daemon_reply_int(reply, "seqno_before", -1)))
log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
}
if (vg && result &&
(daemon_reply_int(reply, "seqno_after", -1) != vg->seqno ||
daemon_reply_int(reply, "seqno_after", -1) != daemon_reply_int(reply, "seqno_before", -1)))
log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
if (result && found_vgnames) {
status = daemon_reply_str(reply, "status", NULL);
@@ -1764,7 +1755,6 @@ int lvmetad_pv_gone_by_dev(struct device *dev)
*/
struct _lvmetad_pvscan_baton {
struct cmd_context *cmd;
struct volume_group *vg;
struct format_instance *fid;
};
@@ -1775,7 +1765,7 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
struct volume_group *vg;
if (mda_is_ignored(mda) ||
!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL)))
!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1)))
return 1;
/* FIXME Also ensure contents match etc. */
@@ -1787,33 +1777,6 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
return 1;
}
/*
* FIXME: handle errors and do proper comparison of metadata from each area
* like vg_read and fall back to real vg_read from disk if there's any problem.
*/
static int _lvmetad_pvscan_vg_single(struct metadata_area *mda, void *baton)
{
struct _lvmetad_pvscan_baton *b = baton;
struct volume_group *vg = NULL;
if (mda_is_ignored(mda))
return 1;
if (!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL)))
return 1;
if (!b->vg)
b->vg = vg;
else if (vg->seqno > b->vg->seqno) {
release_vg(b->vg);
b->vg = vg;
} else
release_vg(vg);
return 1;
}
/*
* The lock manager may detect that the vg cached in lvmetad is out of date,
* due to something like an lvcreate from another host.
@@ -1823,41 +1786,41 @@ static int _lvmetad_pvscan_vg_single(struct metadata_area *mda, void *baton)
* the VG, and that PV may have been reused for another VG.
*/
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg,
const char *vgid, struct format_type *fmt)
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
{
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
char uuid[64] __attribute__((aligned(8)));
struct label *label;
struct volume_group *vg_ret = NULL;
struct dm_config_tree *vgmeta_ret = NULL;
struct dm_config_tree *vgmeta;
struct pv_list *pvl, *pvl_new;
struct device_list *devl, *devlsafe;
struct device_list *devl, *devl_new, *devlsafe;
struct dm_list pvs_scan;
struct dm_list pvs_drop;
struct lvmcache_vginfo *vginfo = NULL;
struct dm_list pvs_new;
struct lvmcache_info *info = NULL;
struct format_instance *fid;
struct format_instance_ctx fic = { .type = 0 };
struct _lvmetad_pvscan_baton baton;
struct volume_group *save_vg;
struct dm_config_tree *save_meta;
struct device *save_dev = NULL;
uint32_t save_seqno = 0;
int found_new_pvs = 0;
int retried_reads = 0;
int missing_devs = 0;
int check_new_pvs = 0;
int found;
save_vg = NULL;
save_meta = NULL;
save_dev = NULL;
save_seqno = 0;
dm_list_init(&pvs_scan);
dm_list_init(&pvs_drop);
dm_list_init(&pvs_new);
log_debug_lvmetad("Rescan VG %s to update lvmetad (seqno %u).", vg->name, vg->seqno);
log_debug_lvmetad("Rescanning VG %s (seqno %u).", vg->name, vg->seqno);
/*
* Make sure this command knows about all PVs from lvmetad.
* Another host may have added a PV to the VG, and some
* commands do not always populate their lvmcache with
* all devs from lvmetad, so they would fail to find
* the new PV when scanning the VG. So make sure this
* command knows about all PVs from lvmetad.
*/
lvmcache_seed_infos_from_lvmetad(cmd);
@@ -1872,111 +1835,54 @@ static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct v
dm_list_add(&pvs_scan, &devl->list);
}
/*
* Rescan labels/metadata only from devs that we previously
* saw in the VG. If we find below that there are new PVs
* in the VG, we'll have to rescan all devices to find which
* device(s) are now being used.
*/
log_debug_lvmetad("Rescan VG %s scanning data from devs in previous metadata.", vg->name);
label_scan_devs(cmd, cmd->full_filter, &pvs_scan);
scan_more:
/*
* Check if any pvs_scan entries are no longer PVs.
* In that case, label_read/_find_label_header will have
* found no label_header, and would have dropped the
* info struct for the device from lvmcache. So, if
* we look up the info struct here and don't find it,
* we can infer it's no longer a PV.
*
* FIXME: we should record specific results from the
* label_read and then check specifically for whatever
* result means "no label was found", rather than going
* about this indirectly via the lvmcache side effects.
*/
dm_list_iterate_items_safe(devl, devlsafe, &pvs_scan) {
if (!(info = lvmcache_info_from_pvid(devl->dev->pvid, devl->dev, 0))) {
/* Another host removed this PV from the VG. */
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no label).",
vg->name, dev_name(devl->dev));
dm_list_move(&pvs_drop, &devl->list);
}
}
fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
fic.context.vg_ref.vg_name = vg->name;
fic.context.vg_ref.vg_id = vgid;
retry_reads:
if (!(fid = fmt->ops->create_instance(fmt, &fic))) {
/* FIXME: are there only internal reasons for failures here? */
log_error("Reading VG %s failed to create format instance.", vg->name);
return NULL;
}
/* FIXME: not sure if this is necessary */
fid->ref_count++;
baton.fid = fid;
baton.cmd = cmd;
/*
* FIXME: this vg_read path does not have the ability to repair
* any problems with the VG, e.g. VG on one dev has an older
* seqno. When vg_read() is reworked, we need to fall back
* to using that from here (and vg_read's from lvmetad) when
* there is a problem. Perhaps by disabling lvmetad when a
* VG problem is detected, causing commands to fully fall
* back to disk, which will repair the VG. Then lvmetad can
* be repopulated and re-enabled (possibly automatically.)
*/
/*
* Do a low level vg_read on each dev, verify the vg returned
* from metadata on each device is for the VG being read
* (the PV may have been removed from the VG being read and
* added to a different one), and return this vg to the caller
* as the current vg to use.
*
* The label scan above will have saved in lvmcache which
* vg each device is used in, so we could figure that part
* out without doing the vg_read.
* Run the equivalent of lvmetad_pvscan_single on each dev in the VG.
*/
dm_list_iterate_items_safe(devl, devlsafe, &pvs_scan) {
if (!devl->dev)
continue;
log_debug_lvmetad("Rescan VG %s getting metadata from %s.",
vg->name, dev_name(devl->dev));
log_debug_lvmetad("Rescan VG %s scanning %s.", vg->name, dev_name(devl->dev));
if (!label_read(devl->dev, &label, 0)) {
/* Another host removed this PV from the VG. */
log_debug_lvmetad("Rescan VG %s found %s was removed.", vg->name, dev_name(devl->dev));
if ((info = lvmcache_info_from_pvid(devl->dev->pvid, NULL, 0)))
lvmcache_del(info);
/*
* The info struct for this dev knows what and where
* the mdas are for this dev (the label scan saved
* the mda locations for this dev on the lvmcache info struct).
*/
if (!(info = lvmcache_info_from_pvid(devl->dev->pvid, devl->dev, 0))) {
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no info).",
vg->name, dev_name(devl->dev));
dm_list_move(&pvs_drop, &devl->list);
continue;
}
info = (struct lvmcache_info *) label->info;
baton.vg = NULL;
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
if (!baton.fid)
return_NULL;
if (baton.fid->fmt->features & FMT_OBSOLETE) {
log_debug_lvmetad("Ignoring obsolete format on PV %s in VG %s.", dev_name(devl->dev), vg->name);
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
dm_list_move(&pvs_drop, &devl->list);
continue;
}
/*
* Read VG metadata from this dev's mdas.
*/
lvmcache_foreach_mda(info, _lvmetad_pvscan_vg_single, &baton);
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
/*
* The PV may have been removed from the VG by another host
* since we last read the VG.
*/
if (!baton.vg) {
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no metadata).",
vg->name, dev_name(devl->dev));
log_debug_lvmetad("Rescan VG %s did not find %s.", vg->name, dev_name(devl->dev));
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
dm_list_move(&pvs_drop, &devl->list);
continue;
}
@@ -1986,15 +1892,10 @@ static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct v
* different VG since we last read the VG.
*/
if (strcmp(baton.vg->name, vg->name)) {
log_debug_lvmetad("Rescan VG %s from %s dropping dev (other VG %s).",
vg->name, dev_name(devl->dev), baton.vg->name);
release_vg(baton.vg);
continue;
}
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
log_error("VG export to config tree failed");
log_debug_lvmetad("Rescan VG %s found different VG %s on PV %s.",
vg->name, baton.vg->name, dev_name(devl->dev));
release_vg(baton.vg);
dm_list_move(&pvs_drop, &devl->list);
continue;
}
@@ -2004,35 +1905,20 @@ static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct v
* read from each other dev.
*/
if (save_vg && (save_seqno != baton.vg->seqno)) {
/* FIXME: fall back to vg_read to correct this. */
log_warn("WARNING: inconsistent metadata for VG %s on devices %s seqno %u and %s seqno %u.",
vg->name, dev_name(save_dev), save_seqno,
dev_name(devl->dev), baton.vg->seqno);
log_warn("WARNING: temporarily disable lvmetad to repair metadata.");
if (!save_seqno)
save_seqno = baton.vg->seqno;
/* Use the most recent */
if (save_seqno < baton.vg->seqno) {
release_vg(save_vg);
dm_config_destroy(save_meta);
save_vg = baton.vg;
save_meta = vgmeta;
save_seqno = baton.vg->seqno;
save_dev = devl->dev;
} else {
release_vg(baton.vg);
dm_config_destroy(vgmeta);
}
continue;
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
log_error("VG export to config tree failed");
release_vg(baton.vg);
return NULL;
}
if (!save_vg) {
save_vg = baton.vg;
save_meta = vgmeta;
save_seqno = baton.vg->seqno;
if (!vgmeta_ret) {
vgmeta_ret = vgmeta;
save_dev = devl->dev;
} else {
struct dm_config_node *meta1 = save_meta->root;
struct dm_config_node *meta1 = vgmeta_ret->root;
struct dm_config_node *meta2 = vgmeta->root;
struct dm_config_node *sib1 = meta1->sib;
struct dm_config_node *sib2 = meta2->sib;
@@ -2057,128 +1943,73 @@ static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct v
meta2->sib = NULL;
if (compare_config(meta1, meta2)) {
/* FIXME: fall back to vg_read to correct this. */
log_warn("WARNING: inconsistent metadata for VG %s on devices %s seqno %u and %s seqno %u.",
vg->name, dev_name(save_dev), save_seqno,
dev_name(devl->dev), baton.vg->seqno);
log_warn("WARNING: temporarily disable lvmetad to repair metadata.");
log_error("VG %s metadata comparison failed for device %s vs %s",
vg->name, dev_name(devl->dev), save_dev ? dev_name(save_dev) : "none");
_log_debug_inequality(vg->name, save_meta->root, vgmeta->root);
_log_debug_inequality(vg->name, vgmeta_ret->root, vgmeta->root);
meta1->sib = sib1;
meta2->sib = sib2;
/* no right choice, just use the previous copy */
release_vg(baton.vg);
dm_config_destroy(vgmeta);
dm_config_destroy(vgmeta_ret);
release_vg(baton.vg);
return NULL;
}
meta1->sib = sib1;
meta2->sib = sib2;
release_vg(baton.vg);
dm_config_destroy(vgmeta);
}
}
/* FIXME: see above */
fid->ref_count--;
/*
* Look for any new PVs in the VG metadata that were not in our
* previous version of the VG.
*
* (Don't look for new PVs after a rescan and retry.)
*/
found_new_pvs = 0;
if (save_vg && !retried_reads) {
dm_list_iterate_items(pvl_new, &save_vg->pvs) {
found = 0;
dm_list_iterate_items(pvl, &vg->pvs) {
if (pvl_new->pv->dev != pvl->pv->dev)
continue;
found = 1;
break;
}
/*
* PV in new VG metadata not found in old VG metadata.
* There's a good chance we don't know about this new
* PV or what device it's on; a label scan is needed
* of all devices so we know which device the VG is
* now using.
*/
if (!found) {
found_new_pvs++;
strncpy(pvid_s, (char *) &pvl_new->pv->id, sizeof(pvid_s) - 1);
if (!id_write_format((const struct id *)&pvid_s, uuid, sizeof(uuid)))
stack;
log_debug_lvmetad("Rescan VG %s found new PV %s.", vg->name, uuid);
}
}
}
if (!save_vg && retried_reads) {
log_error("VG %s not found after rescanning devices.", vg->name);
goto out;
}
/*
* Do a full rescan of devices, then look up which devices the
* scan found for this VG name, and select those devices to
* read metadata from in the loop above (rather than the list
* of devices we created from our last copy of the vg metadata.)
*
* Case 1: VG we knew is no longer on any of the devices we knew it
* to be on (save_vg is NULL, which means the metadata wasn't found
* when reading mdas on each of the initial pvs_scan devices).
* Rescan all devs and then retry reading metadata from the devs that
* the scan finds associated with this VG.
*
* Case 2: VG has new PVs but we don't know what devices they are
* so rescan all devs and then retry reading metadata from the devs
* that the scan finds associated with this VG.
*
* (N.B. after a retry, we don't check for found_new_pvs.)
*/
if (!save_vg || found_new_pvs) {
if (!save_vg)
log_debug_lvmetad("Rescan VG %s did not find VG on previous devs.", vg->name);
if (found_new_pvs)
log_debug_lvmetad("Rescan VG %s scanning all devs to find new PVs.", vg->name);
label_scan(cmd);
if (!(vginfo = lvmcache_vginfo_from_vgname(vg->name, NULL))) {
log_error("VG %s vg info not found after rescanning devices.", vg->name);
goto out;
}
/*
* Set pvs_scan to devs that the label scan found
* in the VG and retry the metadata reading loop.
* Look for any new PVs in the VG metadata that were not in our
* previous version of the VG. Add them to pvs_new to be
* scanned in this loop just like the old PVs.
*/
dm_list_init(&pvs_scan);
if (!lvmcache_get_vg_devs(cmd, vginfo, &pvs_scan)) {
log_error("VG %s info devs not found after rescanning devices.", vg->name);
goto out;
if (!check_new_pvs) {
check_new_pvs = 1;
dm_list_iterate_items(pvl_new, &baton.vg->pvs) {
found = 0;
dm_list_iterate_items(pvl, &vg->pvs) {
if (pvl_new->pv->dev != pvl->pv->dev)
continue;
found = 1;
break;
}
if (found)
continue;
if (!pvl_new->pv->dev) {
strncpy(pvid_s, (char *) &pvl_new->pv->id, sizeof(pvid_s) - 1);
if (!id_write_format((const struct id *)&pvid_s, uuid, sizeof(uuid)))
stack;
log_error("Device not found for PV %s in VG %s", uuid, vg->name);
missing_devs++;
continue;
}
if (!(devl_new = dm_pool_zalloc(cmd->mem, sizeof(*devl_new))))
return_NULL;
devl_new->dev = pvl_new->pv->dev;
dm_list_add(&pvs_new, &devl_new->list);
log_debug_lvmetad("Rescan VG %s found %s was added.", vg->name, dev_name(devl_new->dev));
}
}
log_debug_lvmetad("Rescan VG %s has %d PVs after label scan.",
vg->name, dm_list_size(&pvs_scan));
release_vg(baton.vg);
}
if (save_vg)
release_vg(save_vg);
if (save_meta)
dm_config_destroy(save_meta);
save_vg = NULL;
save_meta = NULL;
save_dev = NULL;
save_seqno = 0;
found_new_pvs = 0;
retried_reads = 1;
goto retry_reads;
/*
* Do the same scanning above for any new PVs.
*/
if (!dm_list_empty(&pvs_new)) {
dm_list_init(&pvs_scan);
dm_list_splice(&pvs_scan, &pvs_new);
dm_list_init(&pvs_new);
log_debug_lvmetad("Rescan VG %s found new PVs to scan.", vg->name);
goto scan_more;
}
if (missing_devs) {
if (vgmeta_ret)
dm_config_destroy(vgmeta_ret);
return_NULL;
}
/*
@@ -2187,50 +2018,52 @@ static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct v
dm_list_iterate_items(devl, &pvs_drop) {
if (!devl->dev)
continue;
log_debug_lvmetad("Rescan VG %s removing %s from lvmetad.", vg->name, dev_name(devl->dev));
if (!lvmetad_pv_gone_by_dev(devl->dev)) {
/* FIXME: use an error path that disables lvmetad */
log_error("Failed to remove %s from lvmetad.", dev_name(devl->dev));
}
log_debug_lvmetad("Rescan VG %s dropping %s.", vg->name, dev_name(devl->dev));
if (!lvmetad_pv_gone_by_dev(devl->dev))
return_NULL;
}
/*
* Update lvmetad with the newly read version of the VG.
* When the seqno is unchanged the cached VG can be left.
* Update the VG in lvmetad.
*/
if (save_vg && (save_seqno != vg->seqno)) {
dm_list_iterate_items(devl, &pvs_scan) {
if (!devl->dev)
continue;
log_debug_lvmetad("Rescan VG %s removing %s from lvmetad to replace.",
vg->name, dev_name(devl->dev));
if (!lvmetad_pv_gone_by_dev(devl->dev)) {
/* FIXME: use an error path that disables lvmetad */
log_error("Failed to remove %s from lvmetad.", dev_name(devl->dev));
}
if (vgmeta_ret) {
fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
if (!(vg_ret = import_vg_from_config_tree(vgmeta_ret, fid))) {
log_error("VG import from config tree failed");
lvmcache_fmt(info)->ops->destroy_instance(fid);
goto out;
}
log_debug_lvmetad("Rescan VG %s updating lvmetad from seqno %u to seqno %u.",
vg->name, vg->seqno, save_seqno);
/*
* If this vg_update fails the cached metadata in
* lvmetad will remain invalid.
* Update lvmetad with the newly read version of the VG.
* When the seqno is unchanged the cached VG can be left.
*/
save_vg->lvmetad_update_pending = 1;
if (!lvmetad_vg_update_finish(save_vg)) {
/* FIXME: use an error path that disables lvmetad */
log_error("Failed to update lvmetad with new VG meta");
if (save_seqno != vg->seqno) {
dm_list_iterate_items(devl, &pvs_scan) {
if (!devl->dev)
continue;
log_debug_lvmetad("Rescan VG %s dropping to replace %s.", vg->name, dev_name(devl->dev));
if (!lvmetad_pv_gone_by_dev(devl->dev))
return_NULL;
}
log_debug_lvmetad("Rescan VG %s updating lvmetad from seqno %u to seqno %u.",
vg->name, vg->seqno, save_seqno);
/*
* If this vg_update fails the cached metadata in
* lvmetad will remain invalid.
*/
vg_ret->lvmetad_update_pending = 1;
if (!lvmetad_vg_update_finish(vg_ret))
log_error("Failed to update lvmetad with new VG meta");
}
dm_config_destroy(vgmeta_ret);
}
out:
if (!save_vg && fid)
fmt->ops->destroy_instance(fid);
if (save_meta)
dm_config_destroy(save_meta);
if (save_vg)
log_debug_lvmetad("Rescan VG %s done (new seqno %u).", save_vg->name, save_vg->seqno);
return save_vg;
if (vg_ret)
log_debug_lvmetad("Rescan VG %s done (seqno %u).", vg_ret->name, vg_ret->seqno);
return vg_ret;
}
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
@@ -2240,12 +2073,9 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
struct label *label;
struct lvmcache_info *info;
struct _lvmetad_pvscan_baton baton;
const struct format_type *fmt;
/* Create a dummy instance. */
struct format_instance_ctx fic = { .type = 0 };
log_debug_lvmetad("Scan metadata from dev %s", dev_name(dev));
if (!lvmetad_used()) {
log_error("Cannot proceed since lvmetad is not active.");
return 0;
@@ -2256,31 +2086,23 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
return 1;
}
if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
log_print_unless_silent("No PV info found on %s for PVID %s.", dev_name(dev), dev->pvid);
if (!label_read(dev, &label, 0)) {
log_print_unless_silent("No PV label found on %s.", dev_name(dev));
if (!lvmetad_pv_gone_by_dev(dev))
goto_bad;
return 1;
}
if (!(label = lvmcache_get_label(info))) {
log_print_unless_silent("No PV label found for %s.", dev_name(dev));
if (!lvmetad_pv_gone_by_dev(dev))
goto_bad;
return 1;
}
info = (struct lvmcache_info *) label->info;
fmt = lvmcache_fmt(info);
baton.cmd = cmd;
baton.vg = NULL;
baton.fid = fmt->ops->create_instance(fmt, &fic);
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
if (!baton.fid)
goto_bad;
if (fmt->features & FMT_OBSOLETE) {
fmt->ops->destroy_instance(baton.fid);
if (baton.fid->fmt->features & FMT_OBSOLETE) {
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
log_warn("WARNING: Disabling lvmetad cache which does not support obsolete (lvm1) metadata.");
lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_LVM1);
_found_lvm1_metadata = 1;
@@ -2294,9 +2116,9 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
if (!baton.vg)
fmt->ops->destroy_instance(baton.fid);
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
if (!lvmetad_pv_found(cmd, (const struct id *) &dev->pvid, dev, fmt,
if (!lvmetad_pv_found(cmd, (const struct id *) &dev->pvid, dev, lvmcache_fmt(info),
label->sector, baton.vg, found_vgnames, changed_vgnames)) {
release_vg(baton.vg);
goto_bad;
@@ -2362,13 +2184,6 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
replacing_other_update = 1;
}
label_scan(cmd);
if (lvmcache_found_duplicate_pvs()) {
log_warn("WARNING: Scan found duplicate PVs.");
return 0;
}
log_verbose("Scanning all devices to update lvmetad.");
if (!(iter = dev_iter_create(cmd->lvmetad_filter, 1))) {
@@ -2551,18 +2366,11 @@ static int _lvmetad_get_pv_cache_list(struct cmd_context *cmd, struct dm_list *p
*/
static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
{
/*
* FIXME: this is diabled as part of removing dev_opens
* to integrate bcache. If this is really needed, we
* can do a separate open/close here.
*/
log_debug_devs("SKIP device %d:%d open to update udev",
(int)MAJOR(devt), (int)MINOR(devt));
#if 0
struct device *dev;
log_debug_devs("device %d:%d open to update udev",
(int)MAJOR(devt), (int)MINOR(devt));
if (!(dev = dev_cache_get_by_devt(devt, cmd->lvmetad_filter))) {
log_error("_update_pv_in_udev no dev found");
return;
@@ -2575,7 +2383,6 @@ static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
if (!dev_close(dev))
stack;
#endif
}
/*
@@ -2747,8 +2554,6 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
*/
_lvmetad_get_pv_cache_list(cmd, &pvc_before);
log_debug_lvmetad("Rescan all devices to validate global cache.");
/*
* Update the local lvmetad cache so it correctly reflects any
* changes made on remote hosts. (It's possible that this command
@@ -2817,7 +2622,7 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
_update_changed_pvs_in_udev(cmd, &pvc_before, &pvc_after);
}
log_debug_lvmetad("Rescanned all devices");
log_debug_lvmetad("Validating global lvmetad cache finished");
}
int lvmetad_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const char *vgid)
@@ -3069,9 +2874,6 @@ int lvmetad_is_disabled(struct cmd_context *cmd, const char **reason)
} else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_DIRECT)) {
*reason = "the disable flag was set directly";
} else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_REPAIR)) {
*reason = "a repair command was run";
} else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_LVM1)) {
*reason = "LVM1 metadata was found";

76
lib/cache/lvmetad.h vendored
View File

@@ -17,8 +17,6 @@
#include "config-util.h"
#include <stdint.h>
struct volume_group;
struct cmd_context;
struct dm_config_tree;
@@ -165,48 +163,38 @@ void lvmetad_clear_disabled(struct cmd_context *cmd);
# else /* LVMETAD_SUPPORT */
static inline int lvmetad_connect(struct cmd_context *cmd) {return 0;}
static inline void lvmetad_disconnect(void) {}
static inline void lvmetad_make_unused(struct cmd_context *cmd) {}
static inline int lvmetad_used(void) {return 0;}
static inline void lvmetad_set_socket(const char *thing) {}
static inline int lvmetad_socket_present(void) {return 0;}
static inline int lvmetad_pidfile_present(void) {return 0;}
static inline void lvmetad_set_token(const struct dm_config_value *filter) {}
static inline void lvmetad_release_token(void) {}
static inline int lvmetad_vg_update_pending(struct volume_group *vg) {return 1;}
static inline int lvmetad_vg_update_finish(struct volume_group *vg) {return 1;}
static inline int lvmetad_vg_remove_pending(struct volume_group *vg) {return 1;}
static inline int lvmetad_vg_remove_finish(struct volume_group *vg) {return 1;}
static inline int lvmetad_pv_found(struct cmd_context *cmd, const struct id *pvid, struct device *dev,
const struct format_type *fmt, uint64_t label_sector,
struct volume_group *vg,
struct dm_list *found_vgnames,
struct dm_list *changed_vgnames) {return 1;}
static inline int lvmetad_pv_gone(dev_t devno, const char *pv_name) {return 1;}
static inline int lvmetad_pv_gone_by_dev(struct device *dev) {return 1;}
static inline int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd) {return 1;}
static inline int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid, int *found) {return 0;}
static inline int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *found) {return 0;}
static inline int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd) {return 1;}
static inline int lvmetad_get_vgnameids(struct cmd_context *cmd, struct dm_list *vgnameids) {return 0;}
static inline struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd,
const char *vgname, const char *vgid) {return NULL;}
static inline int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
struct dm_list *found_vgnames,
struct dm_list *changed_vgnames) {return 0;}
static inline int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait) {return 0;}
static inline int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg) {return 0;}
static inline void lvmetad_validate_global_cache(struct cmd_context *cmd, int force) {}
static inline int lvmetad_token_matches(struct cmd_context *cmd) {return 1;}
static inline int lvmetad_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const char *vgid) {return 0;}
static inline int lvmetad_is_disabled(struct cmd_context *cmd, const char **reason) {return 0;}
static inline void lvmetad_set_disabled(struct cmd_context *cmd, const char *reason) {}
static inline void lvmetad_clear_disabled(struct cmd_context *cmd) {}
# define lvmetad_disconnect() do { } while (0)
# define lvmetad_connect(cmd) (0)
# define lvmetad_make_unused(cmd) do { } while (0)
# define lvmetad_used() (0)
# define lvmetad_set_socket(a) do { } while (0)
# define lvmetad_socket_present() (0)
# define lvmetad_pidfile_present() (0)
# define lvmetad_set_token(a) do { } while (0)
# define lvmetad_release_token() do { } while (0)
# define lvmetad_vg_update(vg) (1)
# define lvmetad_vg_update_pending(vg) (1)
# define lvmetad_vg_update_finish(vg) (1)
# define lvmetad_vg_remove_pending(vg) (1)
# define lvmetad_vg_remove_finish(vg) (1)
# define lvmetad_pv_found(cmd, pvid, dev, fmt, label_sector, vg, found_vgnames, changed_vgnames) (1)
# define lvmetad_pv_gone(devno, pv_name) (1)
# define lvmetad_pv_gone_by_dev(dev) (1)
# define lvmetad_pv_list_to_lvmcache(cmd) (1)
# define lvmetad_pv_lookup(cmd, pvid, found) (0)
# define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0)
# define lvmetad_vg_list_to_lvmcache(cmd) (1)
# define lvmetad_get_vgnameids(cmd, vgnameids) do { } while (0)
# define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL)
# define lvmetad_pvscan_single(cmd, dev, found_vgnames, changed_vgnames) (0)
# define lvmetad_pvscan_all_devs(cmd, do_wait) (0)
# define lvmetad_vg_clear_outdated_pvs(vg) do { } while (0)
# define lvmetad_validate_global_cache(cmd, force) do { } while (0)
# define lvmetad_vg_is_foreign(cmd, vgname, vgid) (0)
# define lvmetad_token_matches(cmd) (1)
# define lvmetad_is_disabled(cmd, reason) (0)
# define lvmetad_set_disabled(cmd, reason) do { } while (0)
# define lvmetad_clear_disabled(cmd) do { } while (0)
# endif /* LVMETAD_SUPPORT */

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