1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-08-20 21:49:28 +03:00

Compare commits

..

4 Commits

Author SHA1 Message Date
5e48b04561 pvscan: only add device args to dev cache
Optimize the common pvscan --cache command by only adding
the necessary devs to dev-cache.
2021-10-18 16:24:24 -05:00
3e893b9b09 hints: new pvs_online type
Use a new form of hints to reduce device scanning in
vgchange -aay run by the udev rule for event based
autoactivation.

Standard hints allow a command with a named VG arg to scan
only the PVs in the named VG, rather than scanning all
available PVs.  Standard hints are useful with a stable set
of system devices.  When new devices are arriving, as occurs
during system startup, the hints are repeatedly invalidated,
which makes standard hints unhelpful while devices are
regularly appearing.  This is the situation in which
vgchange -aay is used, so standard hints are not generally
helpful for autoactivation.

In the context of system startup, pvscan --cache is keeping
track of available PVs using the pvs_online files, similar
to what the hints file does for a running system.  Given this,
a new hint mode, hints = "pvs_online", is added which derives
an equivalent to standard hints, based on pvs_online files
that are being created by udev-run pvscans.  This hint mode
is useful while devices are appearing, e.g. during system
startup, and vgchange -aay can benefit from it.

pvscan --cache -aay autoactivation already has a similar
optimization (the "quick" activation case) that is based
on the pvs_online file, but it is not implemented as a
form of hints.

This new form of hints is mainly useful in the context of
event based autoactivation, during which standard hints are
not useful.  Once the system is in a steady state after startup
(devices are not regularly appearing), the standard hints are
most useful.  The pvs_online hint method could be used on a
running system, but would be no better than standard hints,
and may be inferior because pvs_online files are not rigidly
updated after system startup.
2021-10-15 16:27:04 -05:00
c06d5fe28e add fixed event activation services
Add two new fixed activation services for startup:
lvm-activate-vgs-main and lvm-activate-vgs-last.

The -main service runs early, without service dependencies.
The -last service runs later, after other services have
started (other services that may set up devices for PVs,
like mulitpathd.)

The lvm-activate-vgs services both run "vgchange -aay"
to activate all VGs that are preset and complete at the
time of system startup.  When there are many VGs, these
two vgchange commands will replace many per-VG vgchange
commands.

The last service enables event activation by creating
the file /run/lvm/event-activation-on.  After that,
new devices that appear will be processed by event based
autoactivation commands.  Prior to the existence of the
event-activation-on file, event-based commands do nothing.

lvm.conf event_activation_options can be used to
configure service-based activation only, or event-based
activation only, or the approach described above which
begins with service based activation and then switches
to event-based.

service_only: only the -main and -last services will
activate VGs.  VGs on devices that appear later will
not be autoactivated.

event_only: the -main and -last services will not
activate any VGs, and all VGs will be activated
from per-VG event-based activation commands.

service_to_event: the -main and -last services will
activate VGs that are complete at the time the
services run, and VGs that appear later will be
activated from per-VG event-based activation
commands.
2021-10-15 16:25:01 -05:00
4f1957ee50 vgchange: add vgonline option
Using --vgonline with vgchange -aay makes vgchange use
/run/lvm/vgs_online/ files in the same way as pvscan.
If the online file for the vg does not exist and the
command is able to exclusively create it, then it will
activate the VG.  If the online file exists or the create
fails, then the VG will not be activated.
2021-10-15 12:59:03 -05:00
492 changed files with 18543 additions and 41206 deletions

23
.gitignore vendored
View File

@ -16,10 +16,6 @@
*.sw*
*~
# gcov files:
*.gcda
*.gcno
.export.sym
.exported_symbols_generated
.gdb_history
@ -43,11 +39,9 @@ make.tmpl
coverity/coverity_model.xml
/libdm/.symver_check
daemons/clvmd
daemons/dmfilemapd
daemons/lvmetad/
# gcov files:
*.gcda
*.gcno
tools/man-generator
tools/man-generator.c
@ -108,8 +102,6 @@ test/api/thin_percent.t
test/api/vglist.t
test/api/vgtest.t
test/lib/aux
test/lib/cache-mq.profile
test/lib/cache-smq.profile
test/lib/check
test/lib/clvmd
test/lib/dm-version-expected
@ -119,7 +111,6 @@ test/lib/dmstats
test/lib/fail
test/lib/flavour-ndev-cluster
test/lib/flavour-ndev-cluster-lvmpolld
test/lib/flavour-ndev-devicesfile
test/lib/flavour-ndev-lvmetad
test/lib/flavour-ndev-lvmetad-lvmpolld
test/lib/flavour-ndev-lvmpolld
@ -129,7 +120,6 @@ test/lib/flavour-udev-cluster-lvmpolld
test/lib/flavour-udev-lvmetad
test/lib/flavour-udev-lvmetad-lvmpolld
test/lib/flavour-udev-lvmlockd-dlm
test/lib/flavour-udev-lvmlockd-idm
test/lib/flavour-udev-lvmlockd-sanlock
test/lib/flavour-udev-lvmlockd-test
test/lib/flavour-udev-lvmpolld
@ -142,13 +132,8 @@ test/lib/lvm
test/lib/lvm-wrapper
test/lib/lvmchange
test/lib/lvmdbusd.profile
test/lib/lvmdevices
test/lib/lvmetad
test/lib/lvmlockctl
test/lib/lvmlockd
test/lib/lvmpolld
test/lib/lvm_import_vdo
test/lib/lvm_vdo_wrapper
test/lib/not
test/lib/paths
test/lib/paths-common
@ -158,7 +143,5 @@ test/lib/test
test/lib/thin-performance.profile
test/lib/utils
test/lib/version-expected
test/lib/vgimportdevices
test/unit/dmraid_t.c
test/unit/unit-test

View File

@ -1,87 +0,0 @@
stages:
- approve
- test
approve1:
stage: approve
script:
- echo "Approved..."
rules:
# TODO: Filter only safe repositories, or user in developers
- if: $CI_PROJECT_PATH != "csonto/lvm2" && $CI_PROJECT_PATH != "lvmteam/lvm2"
when: manual
# TODO: for other branches than main/rhel: run pipeline only when requested:
- if: $CI_COMMIT_BRANCH != "main" && $CI_COMMIT_BRANCH !~ "^rhel.*"
when: manual
- when: on_success
allow_failure: false
# TODO:
# - check results of autoreconf and make generate - may need additional commit
# - we need a particular setup (rawhide OR latest supported fedora?)
# - do make rpm and publish results as artifacts - we will use packit/COPR for this eventually
# Run on any commits to main (master), rhel8, rhel9 branches
test-job:
stage: test
parallel:
matrix:
- TAG: rhel8
CONFIGURE: >
--with-cluster=internal
--enable-cmirrord
- TAG: rhel9
CONFIGURE: >
--with-default-use-devices-file=1
--enable-app-machineid
--enable-editline
--disable-readline
artifacts:
paths:
- test/results/
expire_in: 1 week
tags:
- ${TAG}
timeout: 2h
script:
# Common options go here, diffs to the above matrix
- >
./configure ${CONFIGURE}
--enable-fsadm
--enable-write_install
--enable-pkgconfig
--enable-cmdlib
--enable-dmeventd
--enable-blkid_wiping
--enable-udev_sync
--with-thin=internal
--with-cache=internal
--enable-lvmpolld
--enable-lvmlockd-dlm --enable-lvmlockd-dlmcontrol
--enable-lvmlockd-sanlock
--enable-dbus-service --enable-notify-dbus
--enable-dmfilemapd
--with-writecache=internal
--with-vdo=internal --with-vdo-format=/usr/bin/vdoformat
--with-integrity=internal
--disable-silent-rules
- make
- rm -rf test/results
- mkdir -p /dev/shm/lvm2-test
- mount -o remount,dev /dev/shm
# TODO: Need to distinguish failed test from failed harness
# TODO: Also need a way to find if run is incomplete, e.g. full disk resulting in many skipped tests
- VERBOSE=0 BATCH=1 LVM_TEST_DIR=/dev/shm/lvm2-test make check || true
- rm -rf /dev/shm/lvm2-test
- cut -d' ' -f2 test/results/list | sort | uniq -c
# Filter artifacts - keep only logs from tests which are not pass
- cd test/results && rm $(grep 'passed$' list | cut -d' ' -f1 | sed -e 's|/|_|g' -e 's|.*|\0.txt|')
# TODO: Keep a list of known failures, and translate into regexp - or simply use python...
- if grep failed test/results/list | grep -v '\\\(dbustest\|lvconvert-mirror\)\.sh' | sort; then false; else true; fi
rules:
# Filter only safe repositories, or user in developers:
# NOTE: Already done in approve stage, may be more caution than necessary
- if: $CI_PROJECT_PATH != "csonto/lvm2" && $CI_PROJECT_PATH != "lvmteam/lvm2"
when: manual
- when: on_success

View File

@ -38,7 +38,7 @@ ifeq ($(MAKECMDGOALS),distclean)
udev po
tools.distclean: test.distclean
endif
DISTCLEAN_DIRS += lcov_reports* autom4te.cache
DISTCLEAN_DIRS += lcov_reports*
DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
include make.tmpl
@ -47,7 +47,7 @@ include $(top_srcdir)/base/Makefile
include $(top_srcdir)/device_mapper/Makefile
include $(top_srcdir)/test/unit/Makefile
lib: include libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
daemons: lib libdaemon tools
scripts: lib
tools: lib libdaemon
@ -127,7 +127,6 @@ all_man:
install_system_dirs:
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)/devices
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_BACKUP_DIR)
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_CACHE_DIR)
@ -172,7 +171,6 @@ help:
@echo " lcov-dated Generate lcov with timedate suffix."
@echo " lcov-reset Reset lcov counters"
@echo " man Build man pages."
@echo " print-VARIABLE Resolve make variable."
@echo " rpm Build rpm."
@echo " run-unit-test Run unit tests."
@echo " tags Generate c/etags."

27
README
View File

@ -12,30 +12,20 @@ Tarballs are available from:
https://github.com/lvmteam/lvm2/releases
The source code is stored in git:
https://gitlab.com/lvmteam/lvm2
Clone:
git clone git@gitlab.com:lvmteam/lvm2.git
Anonymous access:
git clone https://gitlab.com/lvmteam/lvm2.git
Mirrored to:
* https://github.com/lvmteam/lvm2
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
* https://sourceware.org/git/?p=lvm2.git
git clone https://sourceware.org/git/lvm2.git
git clone git://sourceware.org/git/lvm2.git
Mailing list for general discussion related to LVM2:
linux-lvm@lists.linux.dev
Subscribe via email to: linux-lvm+subscribe@lists.linux.dev
Archive https://lore.kernel.org/linux-lvm/
Older archive https://listman.redhat.com/archives/linux-lvm/
linux-lvm@redhat.com
Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm
Mailing lists for LVM2 development, patches and commits:
lvm-devel@lists.linux.dev
Subscribe via email to: lvm-devel+subscribe@lists.linux.dev
Archive https://lore.kernel.org/lvm-devel/
Older archive https://listman.redhat.com/archives/lvm-devel/
lvm-devel@redhat.com
Subscribe from https://www.redhat.com/mailman/listinfo/lvm-devel
lvm2-commits@lists.fedorahosted.org (Read-only archive of commits)
Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits
@ -51,7 +41,6 @@ Website:
Report upstream bugs at:
https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper
or open issues at:
https://gitlab.com/groups/lvmteam/-/issues
https://github.com/lvmteam/lvm2/issues
The source code repository used until 7th June 2012 is accessible using CVS:

View File

@ -24,7 +24,7 @@ You MUST disable (or mask) any LVM daemons:
For running cluster tests, we are using singlenode locking. Pass
`--with-clvmd=singlenode` to configure.
NOTE: This is useful only for testing, and should not be used in production
NOTE: This is useful only for testing, and should not be used in produciton
code.
To run D-Bus daemon tests, existing D-Bus session is required.

View File

@ -1 +1 @@
2.03.23(2) (2023-11-21)
2.03.14(2)-git (2021-08-11)

View File

@ -1 +1 @@
1.02.197 (2023-11-21)
1.02.181-git (2021-08-11)

133
WHATS_NEW
View File

@ -1,128 +1,5 @@
Version 2.03.23 - 21st November 2023
====================================
Set the first lv_attr flag for raid integrity images to i or I.
Add -A option for pvs and pvscan to show PVs outside devices file.
Improve searched_devnames temp file usage to prevent redundant scanning.
Change default search_for_devnames from auto to all.
Add lvmdevices --refresh to search for missing PVIDs on all devices.
Add comparison between old and new entries in lvmdevices --check.
Fix device_id matching order - match non-devname first.
Fix "lvconvert -m 0" when there is other than first in-sync leg.
Use system.devices as default for dmeventd when dmeventd.devices is undefined.
Accept WWIDs containing QEMU HARDDISK for device_id.
Improve handling of non-standard WWID prefixes used for device_id.
Configure automatically enables cmdlib for dmeventd and notify-dbus for dbus.
Fix hint calculation for pools with zero or error segment.
Configure supports --disable-shared to build only static binaries.
Configure supports --without-{blkid|systemd|udev} for easier static build.
Refresh device ids if the system changes.
Fix pvmove when specifying raid components as moved LVs.
Enhance error detection for lvm_import_vdo.
Support PV lists with thin lvconvert.
Fix support for lvm_import_vdo with SCSI VDO volumes.
Fix locking issue leading to hanging concurrent vgchange --refresh.
Recognize lvm.conf report/headings=2 for full column names in report headings.
Add --headings none|abbrev|full cmd line option to set report headings type.
Fix conversion to thin pool using lvmlockd.
Fix conversion from thick into thin volume using lvmlockd.
Require writable LV for conversion to vdo pool.
Fix return value from lvconvert integrity remove.
Preserve UUID for pool metadata spare.
Preserve UUID for swapped pool metadata.
Rewrite validation of device name entries used as device_id.
version 2.03.22 - 02nd August 2023
Version 2.03.14 -
==================================
Fix pv_major/pv_minor report field types so they are integers, not strings.
Add lvmdevices --delnotfound to delete entries for missing devices.
Always use cachepool name for metadata backup LV for lvconvert --repair.
Make metadata backup LVs read-only after pool's lvconvert --repair.
Improve VDO and Thin support with lvmlockd.
Handle 'lvextend --usepolicies' for pools for all activation variants.
Fix memleak in vgchange autoactivation setup.
Update py-compile building script.
Support conversion from thick to fully provisioned thin LV.
Cache/Thin-pool can use error and zero volumes for testing.
Individual thin volume can be cached, but cannot take snapshot.
Better internal support for handling error and zero target (for testing).
Resize COW above trimmed maximal size is does not return error.
Support parsing of vdo geometry format version 4.
Add lvm.conf thin_restore and cache_restore settings.
Handle multiple mounts while resizing volume with a FS.
Handle leading/trailing spaces in sys_wwid and sys_serial used by device_id.
Enhance lvm_import_vdo and use snapshot when converting VDO volume.
Fix parsing of VDO metadata.
Fix failing -S|--select for non-reporting cmds if using LV info/status fields.
Allow snapshots of raid+integrity LV.
Fix multisegment RAID1 allocator to prevent using single disk for more legs.
version 2.03.21 - 21st April 2023
=================================
Fix activation of vdo-pool for with 0 length headers (converted pools).
Avoid printing internal init messages when creation integration devices.
Allow (write)cache over raid+integrity LV.
version 2.03.20 - 21st March 2023
=================================
Fix segfault if using -S|--select with log/report_command_log=1 setting.
Configure now fails when requested lvmlockd dependencies are missing.
Add some configure Gentoo enhancements for static builds.
version 2.03.19 - 21st February 2023
====================================
Configure supports --with-systemd-run executed from udev rules.
Enhancement for build with MuslC systemd and non-bash system shells (dash).
Do not reset SYSTEMD_READY variable in udev for PVs on MD and loop devices.
Ensure udev is processing origin LV before its thick snapshots LVs.
Fix and improve runtime memory size detection for VDO volumes.
version 2.03.18 - 22nd December 2022
====================================
Fix issues reported by coverity scan.
Fix warning for thin pool overprovisioning on lvextend (2.03.17).
Add support for writecache metadata_only and pause_writeback settings.
Fix missing error messages in lvmdbusd.
Version 2.03.17 - 10th November 2022
====================================
Add new options (--fs, --fsmode) for FS handling when resizing LVs.
Fix 'lvremove -S|--select LV' to not also remove its historical LV right away.
Fix lv_active field type to binary so --select and --binary applies properly.
Switch to use mallinfo2 and use it only with glibc.
Error out in lvm shell if using a cmd argument not supported in the shell.
Fix lvm shell's lastlog command to report previous pre-command failures.
Extend VDO and VDOPOOL without flushing and locking fs.
Add --valuesonly option to lvmconfig to print only values without keys.
Updates configure with recent autoconf tooling.
Fix lvconvert --test --type vdo-pool execution.
Add json_std output format for more JSON standard compliant version of output.
Fix vdo_slab_size_mb value for converted VDO volume.
Fix many corner cases in device_id, including handling of S/N duplicates.
Fix various issues in lvmdbusd.
Version 2.03.16 - 18th May 2022
===============================
Fix segfault when handling selection with historical LVs.
Add support --vdosettings with lvcreate, lvconvert, lvchange.
Filtering multipath devices respects blacklist setting from multipath
configuration.
lvmdevices support for removing by device id using --deviceidtype and
--deldev.
Display writecache block size with lvs -o writecache_block_size.
Improve cachesettings description in man lvmcache.
Fix lossing of delete message on thin-pool extension.
Version 2.03.15 - 07th February 2022
====================================
Remove service based autoactivation. global/event_activation = 0 is NOOP.
Improve support for metadata profiles for --type writecache.
Use cache or active DM device when available with new kernels.
Introduce function to utilize UUIDs from DM_DEVICE_LIST.
Increase some hash table size to better support large device sets.
Version 2.03.14 - 20th October 2021
===================================
Device scanning is skipping directories on different filesystems.
Print info message with too many or too large archived files.
Reduce metadata readings during scanning phase.
Optimize computation of crc32 check sum with multiple PVs.
@ -130,7 +7,7 @@ Version 2.03.14 - 20th October 2021
Filter out unsupported MQ/SMQ cache policy setting.
Fix memleak in mpath filter.
Support newer location for VDO statistics.
Add support for VDO async-unsafe write policy.
Add support for VDO async-unsage write policy.
Improve lvm_import_vdo script.
Support VDO LV with lvcreate -ky.
Fix lvconvert for VDO LV bigger then 2T.
@ -198,7 +75,7 @@ Version 2.03.12 - 07th May 2021
Fix IMSM MD RAID detection on 4k devices.
Check for presence of VDO target before starting any conversion.
Support metatadata profiles with volume VDO pool conversions.
Support -Zn for conversion of already formatted VDO pools.
Support -Zn for conversion of already formated VDO pools.
Avoid removing LVs on error path of lvconvert during creation volumes.
Fix crashing lvdisplay when thin volume was waiting for merge.
Support option --errorwhenfull when converting volume to thin-pool.
@ -271,7 +148,7 @@ Version 2.03.10 - 09th August 2020
Version 2.03.09 - 26th March 2020
=================================
Fix formatting of vdopool (vdo_slab_size_mb was smaller by 2 bits).
Fix formating of vdopool (vdo_slab_size_mb was smaller by 2 bits).
Fix showing of a dm kernel error when uncaching a volume with cachevol.
Version 2.03.08 - 11th February 2020
@ -3284,7 +3161,7 @@ Version 2.02.68 - 23rd June 2010
Add device name and offset to raw_read_mda_header error messages.
Honour log argument when down-converting stacked mirror.
Sleep to workaround clvmd -S race: socket closed early and server drops cmd.
Use early udev synchronization and update of dev nodes for clustered mirrors.
Use early udev synchronisation and update of dev nodes for clustered mirrors.
Remove incorrect inclusion of kdev_t.h from cmirrord/functions.h.
Add man pages for lvmconf and non-existent lvmsadc and lvmsar tools.
Exit successfully when using -o help (but not -o +help) with LVM reports.

View File

@ -1,45 +1,5 @@
Version 1.02.197 - 21st November 2023
=====================================
Fix invalid JSON report if using DM_REPORT_OUTPUT_MULTIPLE_TIMES and selection.
Propagate ioctl errno from dm_task_run when creating new table line.
Add support for group aliases in dmstats.
Add support for exit-on file for dmeventd to reduce shutdown delays.
Add configure option --with-dmeventd-exit-on-path to specify default path.
Add dmsetup --headings none|abbrev|full to set report headings type.
Add DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS to provide alternative headings.
Version 1.02.196 - 02nd August 2023
Version 1.02.181 -
===================================
Version 1.02.195 - 21st April 2023
==================================
Version 1.02.193 - 21st March 2023
==================================
Version 1.02.191 - 21st February 2023
=====================================
Improve parallel creation of /dev/mapper/control device node.
Import previous ID_FS_* udev records in 13-dm-disk.rules for suspended DM dev.
Remove NAME="mapper/control" rule from 10-dm.rules to avoid udev warnings.
Version 1.02.189 - 22nd December 2022
=====================================
Improve 'dmsetup create' without given table line with new kernels.
Version 1.02.187 - 10th November 2022
=====================================
Add DM_REPORT_GROUP_JSON_STD for more JSON standard compliant output format.
Version 1.02.185 - 18th May 2022
================================
Version 1.02.183 - 07th February 2022
=====================================
Unmangle UUIDs for DM_DEVICE_LIST ioctl.
Version 1.02.181 - 20th October 2021
====================================
Add IMA support with 'dmsetup measure' command.
Add defines DM_NAME_LIST_FLAG_HAS_UUID, DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID.
Enhance tracking of activated devices when preloading dm tree.
@ -1132,7 +1092,7 @@ Version 1.02.37 - 15th September 2009
Version 1.02.36 - 6th August 2009
=================================
Add udevcookies, udevcomplete, udevcomplete_all and --noudevwait to dmsetup.
Add libdevmapper functions to support synchronization with udev.
Add libdevmapper functions to support synchronisation with udev.
Version 1.02.35 - 28th July 2009
================================

View File

@ -62,24 +62,6 @@ AC_DEFUN([AC_TRY_LDFLAGS],
fi
])
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.
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
_PKG_CONFIG([$1], [variable="][$3]["], [$2])
AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])dnl PKG_CHECK_VAR
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html
# ===========================================================================

306
aclocal.m4 vendored
View File

@ -1,6 +1,6 @@
# generated automatically by aclocal 1.16.5 -*- Autoconf -*-
# generated automatically by aclocal 1.16.2 -*- Autoconf -*-
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
# Copyright (C) 1996-2020 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -69,8 +69,8 @@ AC_DEFUN([AX_PYTHON_MODULE],[
fi
])
# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*-
# serial 12 (pkg-config-0.29.2)
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 11 (pkg-config-0.29.1)
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
@ -112,7 +112,7 @@ 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.2])
[m4_define([PKG_MACROS_VERSION], [0.29.1])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ
@ -157,7 +157,7 @@ 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 occurrence in configure.ac, so if the first place
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
AC_DEFUN([PKG_CHECK_EXISTS],
@ -213,7 +213,7 @@ AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no
AC_MSG_CHECKING([for $2])
AC_MSG_CHECKING([for $1])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
@ -223,17 +223,17 @@ and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
AC_MSG_RESULT([no])
AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
# Put the nasty error message in config.log where it belongs
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
m4_default([$4], [AC_MSG_ERROR(
m4_default([$4], [AC_MSG_ERROR(
[Package requirements ($2) were not met:
$$1_PKG_ERRORS
@ -244,8 +244,8 @@ installed software in a non-standard prefix.
_PKG_TEXT])[]dnl
])
elif test $pkg_failed = untried; then
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
@ -255,10 +255,10 @@ _PKG_TEXT
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
])
else
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
AC_MSG_RESULT([yes])
$3
$3
fi[]dnl
])dnl PKG_CHECK_MODULES
@ -413,7 +413,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
])dnl PKG_HAVE_DEFINE_WITH_MODULES
# Copyright (C) 1999-2021 Free Software Foundation, Inc.
# Copyright (C) 1999-2020 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -492,7 +492,7 @@ AC_DEFUN([AM_PATH_PYTHON],
])
if test "$PYTHON" = :; then
dnl Run any user-specified action, or abort.
dnl Run any user-specified action, or abort.
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
else
@ -501,132 +501,27 @@ AC_DEFUN([AM_PATH_PYTHON],
dnl trailing zero was eliminated. So now we output just the major
dnl and minor version numbers, as numbers. Apparently the tertiary
dnl version is not of interest.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
[am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[[:2]])"`])
[am_cv_python_version=`$PYTHON -c "import sys; print('%u.%u' % sys.version_info[[:2]])"`])
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
dnl At times, e.g., when building shared libraries, you may want
dnl Use the values of $prefix and $exec_prefix for the corresponding
dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
dnl distinct variables so they can be overridden if need be. However,
dnl general consensus is that you shouldn't need this ability.
AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
dnl At times (like when building shared libraries) you may want
dnl to know which OS platform Python thinks this is.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
[am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
dnl emacs-page
dnl If --with-python-sys-prefix is given, use the values of sys.prefix
dnl and sys.exec_prefix for the corresponding values of PYTHON_PREFIX
dnl and PYTHON_EXEC_PREFIX. Otherwise, use the GNU ${prefix} and
dnl ${exec_prefix} variables.
dnl
dnl The two are made distinct variables so they can be overridden if
dnl need be, although general consensus is that you shouldn't need
dnl this separation.
dnl
dnl Also allow directly setting the prefixes via configure options,
dnl overriding any default.
dnl
if test "x$prefix" = xNONE; then
am__usable_prefix=$ac_default_prefix
else
am__usable_prefix=$prefix
fi
# Allow user to request using sys.* values from Python,
# instead of the GNU $prefix values.
AC_ARG_WITH([python-sys-prefix],
[AS_HELP_STRING([--with-python-sys-prefix],
[use Python's sys.prefix and sys.exec_prefix values])],
[am_use_python_sys=:],
[am_use_python_sys=false])
# Allow user to override whatever the default Python prefix is.
AC_ARG_WITH([python_prefix],
[AS_HELP_STRING([--with-python_prefix],
[override the default PYTHON_PREFIX])],
[am_python_prefix_subst=$withval
am_cv_python_prefix=$withval
AC_MSG_CHECKING([for explicit $am_display_PYTHON prefix])
AC_MSG_RESULT([$am_cv_python_prefix])],
[
if $am_use_python_sys; then
# using python sys.prefix value, not GNU
AC_CACHE_CHECK([for python default $am_display_PYTHON prefix],
[am_cv_python_prefix],
[am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"`])
dnl If sys.prefix is a subdir of $prefix, replace the literal value of
dnl $prefix with a variable reference so it can be overridden.
case $am_cv_python_prefix in
$am__usable_prefix*)
am__strip_prefix=`echo "$am__usable_prefix" | sed 's|.|.|g'`
am_python_prefix_subst=`echo "$am_cv_python_prefix" | sed "s,^$am__strip_prefix,\\${prefix},"`
;;
*)
am_python_prefix_subst=$am_cv_python_prefix
;;
esac
else # using GNU prefix value, not python sys.prefix
am_python_prefix_subst='${prefix}'
am_python_prefix=$am_python_prefix_subst
AC_MSG_CHECKING([for GNU default $am_display_PYTHON prefix])
AC_MSG_RESULT([$am_python_prefix])
fi])
# Substituting python_prefix_subst value.
AC_SUBST([PYTHON_PREFIX], [$am_python_prefix_subst])
# emacs-page Now do it all over again for Python exec_prefix, but with yet
# another conditional: fall back to regular prefix if that was specified.
AC_ARG_WITH([python_exec_prefix],
[AS_HELP_STRING([--with-python_exec_prefix],
[override the default PYTHON_EXEC_PREFIX])],
[am_python_exec_prefix_subst=$withval
am_cv_python_exec_prefix=$withval
AC_MSG_CHECKING([for explicit $am_display_PYTHON exec_prefix])
AC_MSG_RESULT([$am_cv_python_exec_prefix])],
[
# no explicit --with-python_exec_prefix, but if
# --with-python_prefix was given, use its value for python_exec_prefix too.
AS_IF([test -n "$with_python_prefix"],
[am_python_exec_prefix_subst=$with_python_prefix
am_cv_python_exec_prefix=$with_python_prefix
AC_MSG_CHECKING([for python_prefix-given $am_display_PYTHON exec_prefix])
AC_MSG_RESULT([$am_cv_python_exec_prefix])],
[
# Set am__usable_exec_prefix whether using GNU or Python values,
# since we use that variable for pyexecdir.
if test "x$exec_prefix" = xNONE; then
am__usable_exec_prefix=$am__usable_prefix
else
am__usable_exec_prefix=$exec_prefix
fi
#
if $am_use_python_sys; then # using python sys.exec_prefix, not GNU
AC_CACHE_CHECK([for python default $am_display_PYTHON exec_prefix],
[am_cv_python_exec_prefix],
[am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"`])
dnl If sys.exec_prefix is a subdir of $exec_prefix, replace the
dnl literal value of $exec_prefix with a variable reference so it can
dnl be overridden.
case $am_cv_python_exec_prefix in
$am__usable_exec_prefix*)
am__strip_prefix=`echo "$am__usable_exec_prefix" | sed 's|.|.|g'`
am_python_exec_prefix_subst=`echo "$am_cv_python_exec_prefix" | sed "s,^$am__strip_prefix,\\${exec_prefix},"`
;;
*)
am_python_exec_prefix_subst=$am_cv_python_exec_prefix
;;
esac
else # using GNU $exec_prefix, not python sys.exec_prefix
am_python_exec_prefix_subst='${exec_prefix}'
am_python_exec_prefix=$am_python_exec_prefix_subst
AC_MSG_CHECKING([for GNU default $am_display_PYTHON exec_prefix])
AC_MSG_RESULT([$am_python_exec_prefix])
fi])])
# Substituting python_exec_prefix_subst.
AC_SUBST([PYTHON_EXEC_PREFIX], [$am_python_exec_prefix_subst])
# Factor out some code duplication into this shell variable.
# Just factor out some code duplication.
am_python_setup_sysconfig="\
import sys
# Prefer sysconfig over distutils.sysconfig, for better compatibility
@ -646,95 +541,96 @@ try:
except ImportError:
pass"
dnl emacs-page Set up 4 directories:
dnl Set up 4 directories:
dnl 1. pythondir: where to install python scripts. This is the
dnl site-packages directory, not the python standard library
dnl directory like in previous automake betas. This behavior
dnl is more consistent with lispdir.m4 for example.
dnl pythondir -- where to install python scripts. This is the
dnl site-packages directory, not the python standard library
dnl directory like in previous automake betas. This behavior
dnl is more consistent with lispdir.m4 for example.
dnl Query distutils for this directory.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON script directory (pythondir)],
[am_cv_python_pythondir],
[if test "x$am_cv_python_prefix" = x; then
am_py_prefix=$am__usable_prefix
else
am_py_prefix=$am_cv_python_prefix
fi
am_cv_python_pythondir=`$PYTHON -c "
AC_CACHE_CHECK([for $am_display_PYTHON script directory],
[am_cv_python_pythondir],
[if test "x$prefix" = xNONE
then
am_py_prefix=$ac_default_prefix
else
am_py_prefix=$prefix
fi
am_cv_python_pythondir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
else:
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"`
#
case $am_cv_python_pythondir in
$am_py_prefix*)
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,\\${PYTHON_PREFIX},"`
;;
*)
case $am_py_prefix in
/usr|/System*) ;;
*) am_cv_python_pythondir="\${PYTHON_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
;;
case $am_cv_python_pythondir in
$am_py_prefix*)
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
;;
*)
case $am_py_prefix in
/usr|/System*) ;;
*)
am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
;;
esac
;;
esac
;;
esac
])
])
AC_SUBST([pythondir], [$am_cv_python_pythondir])
dnl 2. pkgpythondir: $PACKAGE directory under pythondir. Was
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
dnl more consistent with the rest of automake.
dnl
dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
dnl more consistent with the rest of automake.
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
dnl 3. pyexecdir: directory for installing python extension modules
dnl (shared libraries).
dnl pyexecdir -- directory for installing python extension modules
dnl (shared libraries)
dnl Query distutils for this directory.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory (pyexecdir)],
[am_cv_python_pyexecdir],
[if test "x$am_cv_python_exec_prefix" = x; then
am_py_exec_prefix=$am__usable_exec_prefix
else
am_py_exec_prefix=$am_cv_python_exec_prefix
fi
am_cv_python_pyexecdir=`$PYTHON -c "
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
[am_cv_python_pyexecdir],
[if test "x$exec_prefix" = xNONE
then
am_py_exec_prefix=$am_py_prefix
else
am_py_exec_prefix=$exec_prefix
fi
am_cv_python_pyexecdir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_exec_prefix'})
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
else:
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix')
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"`
#
case $am_cv_python_pyexecdir in
$am_py_exec_prefix*)
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,\\${PYTHON_EXEC_PREFIX},"`
;;
*)
case $am_py_exec_prefix in
/usr|/System*) ;;
*) am_cv_python_pyexecdir="\${PYTHON_EXEC_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
;;
case $am_cv_python_pyexecdir in
$am_py_exec_prefix*)
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
;;
*)
case $am_py_exec_prefix in
/usr|/System*) ;;
*)
am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
;;
esac
;;
esac
;;
esac
])
])
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
dnl 4. pkgpyexecdir: $(pyexecdir)/$(PACKAGE)
dnl
dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
dnl Run any user-specified action.
$2
fi
])
@ -757,7 +653,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
sys.exit(sys.hexversion < minverhex)"
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
# Copyright (C) 2001-2020 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,

1712
autoconf/config.guess vendored

File diff suppressed because it is too large Load Diff

2881
autoconf/config.sub vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
#!/usr/bin/sh
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2020-11-14.01; # UTC
scriptversion=2006-10-14.15
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@ -35,62 +35,57 @@ scriptversion=2020-11-14.01; # UTC
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
IFS=" "" $nl"
# Set DOITPROG to "echo" to test this script.
# set DOITPROG to echo to test this script
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
posix_glob=
posix_mkdir=
# Desired mode of installed file.
mode=0755
# Create dirs (including intermediate dirs) using mode 755.
# This is like GNU 'install' as of coreutils 8.32 (2020).
mkdir_umask=22
backupsuffix=
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
chgrpcmd=
stripcmd=
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=
dst=
dir_arg=
dst_arg=
dstarg=
no_target_directory=
copy_on_change=false
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
@ -100,116 +95,91 @@ In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-p pass -p to $cpprog.
-s $stripprog installed files.
-S SUFFIX attempt to back up existing files, with suffix SUFFIX.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
-c (ignored)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
--help display this help and exit.
--version display version info and exit.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
By default, rm is invoked with -f; when overridden with RMPROG,
it's up to you to specify -f if you want it.
If -S is not specified, no backups are attempted.
Email bug reports to bug-automake@gnu.org.
Automake home page: https://www.gnu.org/software/automake/
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-c) shift
continue;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-d) dir_arg=true
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
shift
shift
continue;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
shift
shift
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
continue;;
-o) chowncmd="$chownprog $2"
shift;;
shift
shift
continue;;
-p) cpprog="$cpprog -p";;
-s) stripcmd=$stripprog
shift
continue;;
-s) stripcmd=$stripprog;;
-t) dstarg=$2
shift
shift
continue;;
-S) backupsuffix="$2"
shift;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
-T) no_target_directory=true
shift
continue;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
if test $# -ne 0 && test -z "$dir_arg$dstarg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
if test -n "$dstarg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
set fnord "$@" "$dstarg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
dstarg=$arg
done
fi
@ -218,26 +188,13 @@ if test $# -eq 0; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
trap '(exit $?); exit' 1 2 13 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
@ -248,16 +205,16 @@ if test -z "$dir_arg"; then
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
u_plus_rw=
else
u_plus_rw='% 200'
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
u_plus_rw=
else
u_plus_rw=,u+rw
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
@ -265,9 +222,9 @@ fi
for src
do
# Protect names problematic for 'test' and other utilities.
# Protect names starting with `-'.
case $src in
-* | [=\(\)!]) src=./$src;;
-*) src=./$src ;;
esac
if test -n "$dir_arg"; then
@ -275,10 +232,6 @@ do
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
# Don't chown directories that already exist.
if test $dstdir_status = 0; then
chowncmd=""
fi
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
@ -289,154 +242,196 @@ do
exit 1
fi
if test -z "$dst_arg"; then
if test -z "$dstarg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename.
dst=$dstarg
# Protect names starting with `-'.
case $dst in
-*) dst=./$dst ;;
esac
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
if test -n "$no_target_directory"; then
echo "$0: $dstarg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dstbase=`basename "$src"`
case $dst in
*/) dst=$dst$dstbase;;
*) dst=$dst/$dstbase;;
esac
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
dstdir=`dirname "$dst"`
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir"
dstdir_status=$?
fi
fi
case $dstdir in
*/) dstdirslash=$dstdir;;
*) dstdirslash=$dstdir/;;
esac
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
posix_mkdir=false
# The $RANDOM variable is not portable (e.g., dash). Use it
# here however when possible just to lower collision chance.
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
trap '
ret=$?
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
exit $ret
' 0
# Because "mkdir -p" follows existing symlinks and we likely work
# directly in world-writeable /tmp, make sure that the '$tmpdir'
# directory is successfully created first before we actually test
# 'mkdir -p'.
if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a"
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
mkdir_mode=
fi
trap '' 0;;
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writeable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# mkdir does not conform to POSIX,
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
/*) prefix=/ ;;
-*) prefix=./ ;;
*) prefix= ;;
esac
case $posix_glob in
'')
if (set -f) 2>/dev/null; then
posix_glob=true
else
posix_glob=false
fi ;;
esac
oIFS=$IFS
IFS=/
set -f
$posix_glob && set -f
set fnord $dstdir
shift
set +f
$posix_glob && set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
test -z "$d" && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
@ -449,25 +444,14 @@ do
else
# Make a couple of temp file names in the proper directory.
dsttmp=${dstdirslash}_inst.$$_
rmtmp=${dstdirslash}_rm.$$_
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask &&
{ test -z "$stripcmd" || {
# Create $dsttmp read-write so that cp doesn't create it read-only,
# which would cause strip to fail.
if test -z "$doit"; then
: >"$dsttmp" # No need to fork-exec 'touch'.
else
$doit touch "$dsttmp"
fi
}
} &&
$doit_exec $cpprog "$src" "$dsttmp") &&
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
@ -475,67 +459,49 @@ do
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# If $backupsuffix is set, and the file being installed
# already exists, attempt a backup. Don't worry if it fails,
# e.g., if mv doesn't support -f.
if test -n "$backupsuffix" && test -f "$dst"; then
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
fi
# Now rename the file to the real destination.
{ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
|| {
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
if test -f "$dst"; then
$doit $rmcmd -f "$dst" 2>/dev/null \
|| { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \
&& { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\
|| {
echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
else
:
fi
} &&
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
} || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp)
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# time-stamp-end: "$"
# End:

View File

@ -1,9 +1,9 @@
#!/bin/sh
# py-compile - Compile a Python program
scriptversion=2023-03-30.00; # UTC
scriptversion=2011-06-08.12; # UTC
# Copyright (C) 2000-2023 Free Software Foundation, Inc.
# Copyright (C) 2000-2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -16,7 +16,7 @@ scriptversion=2023-03-30.00; # UTC
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@ -27,7 +27,7 @@ scriptversion=2023-03-30.00; # UTC
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
if test -z "$PYTHON"; then
if [ -z "$PYTHON" ]; then
PYTHON=python
fi
@ -62,19 +62,13 @@ while test $# -ne 0; do
;;
-h|--help)
cat <<\EOF
Usage: py-compile [options] FILES...
Usage: py-compile [--help] [--version] [--basedir DIR] [--destdir DIR] FILES..."
Byte compile some python scripts FILES. Use --destdir to specify any
leading directory path to the FILES that you don't want to include in the
byte compiled file. Specify --basedir for any additional path information you
do want to be shown in the byte compiled file.
Options:
--basedir DIR Prefix all FILES with DIR, and include in error messages.
--destdir DIR Prefix all FILES with DIR before compiling.
-v, --version Display version information.
-h, --help This help screen.
Example:
py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py
@ -100,143 +94,77 @@ EOF
shift
done
if test $# -eq 0; then
usage_error "no files given"
files=$*
if test -z "$files"; then
usage_error "no files given"
fi
# if basedir was given, then it should be prepended to filenames before
# byte compilation.
if test -z "$basedir"; then
pathtrans="path = file"
if [ -z "$basedir" ]; then
pathtrans="path = file"
else
pathtrans="path = os.path.join('$basedir', file)"
pathtrans="path = os.path.join('$basedir', file)"
fi
# if destdir was given, then it needs to be prepended to the filename to
# byte compile but not go into the compiled file.
if test -z "$destdir"; then
filetrans="filepath = path"
if [ -z "$destdir" ]; then
filetrans="filepath = path"
else
filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)"
fi
python_major=`$PYTHON -c 'import sys; print(sys.version_info[0])'`
if test -z "$python_major"; then
usage_error "could not determine $PYTHON major version"
fi
case $python_major in
[01])
usage_error "python version 0.x and 1.x not supported"
;;
esac
python_minor=`$PYTHON -c 'import sys; print(sys.version_info[1])'`
# NB: When adding support for newer versions, prefer copying & adding new cases
# rather than try to keep things merged with shell variables.
# First byte compile (no optimization) all the modules.
# This works for all currently known Python versions.
$PYTHON -c "
import sys, os, py_compile
import sys, os, py_compile, imp
try:
import importlib
except ImportError:
importlib = None
# importlib.util.cache_from_source was added in 3.4
if (
hasattr(importlib, 'util')
and hasattr(importlib.util, 'cache_from_source')
):
destpath = importlib.util.cache_from_source
else:
destpath = lambda filepath: filepath + 'c'
files = '''$files'''
sys.stdout.write('Byte-compiling python modules...\n')
for file in sys.argv[1:]:
for file in files.split():
$pathtrans
$filetrans
if (
not os.path.exists(filepath)
or not (len(filepath) >= 3 and filepath[-3:] == '.py')
):
continue
sys.stdout.write(file + ' ')
if not os.path.exists(filepath) or not (len(filepath) >= 3
and filepath[-3:] == '.py'):
continue
sys.stdout.write(file)
sys.stdout.flush()
py_compile.compile(filepath, destpath(filepath), path)
sys.stdout.write('\n')" "$@" || exit $?
if hasattr(imp, 'get_tag'):
py_compile.compile(filepath, imp.cache_from_source(filepath), path)
else:
py_compile.compile(filepath, filepath + 'c', path)
sys.stdout.write('\n')" || exit $?
# Then byte compile w/optimization all the modules.
# this will fail for python < 1.5, but that doesn't matter ...
$PYTHON -O -c "
import sys, os, py_compile
import sys, os, py_compile, imp
try:
import importlib
except ImportError:
importlib = None
# importlib.util.cache_from_source was added in 3.4
if (
hasattr(importlib, 'util')
and hasattr(importlib.util, 'cache_from_source')
):
destpath = importlib.util.cache_from_source
else:
destpath = lambda filepath: filepath + 'o'
# pypy2 does not use .pyo optimization
if sys.version_info.major <= 2 and hasattr(sys, 'pypy_translation_info'):
# pypy does not use .pyo optimization
if hasattr(sys, 'pypy_translation_info'):
sys.exit(0)
files = '''$files'''
sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n')
for file in sys.argv[1:]:
for file in files.split():
$pathtrans
$filetrans
if (
not os.path.exists(filepath)
or not (len(filepath) >= 3 and filepath[-3:] == '.py')
):
continue
sys.stdout.write(file + ' ')
if not os.path.exists(filepath) or not (len(filepath) >= 3
and filepath[-3:] == '.py'):
continue
sys.stdout.write(file)
sys.stdout.flush()
py_compile.compile(filepath, destpath(filepath), path)
sys.stdout.write('\n')" "$@" 2>/dev/null || exit $?
# Then byte compile w/more optimization.
# Only do this for Python 3.5+, see https://bugs.gnu.org/38043 for background.
case $python_major.$python_minor in
2.*|3.[0-4])
;;
*)
$PYTHON -OO -c "
import sys, os, py_compile, importlib
sys.stdout.write('Byte-compiling python modules (more optimized versions)'
' ...\n')
for file in sys.argv[1:]:
$pathtrans
$filetrans
if (
not os.path.exists(filepath)
or not (len(filepath) >= 3 and filepath[-3:] == '.py')
):
continue
sys.stdout.write(file + ' ')
sys.stdout.flush()
py_compile.compile(filepath, importlib.util.cache_from_source(filepath), path)
sys.stdout.write('\n')" "$@" 2>/dev/null || exit $?
;;
esac
if hasattr(imp, 'get_tag'):
py_compile.compile(filepath, imp.cache_from_source(filepath, False), path)
else:
py_compile.compile(filepath, filepath + 'o', path)
sys.stdout.write('\n')" 2>/dev/null || :
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp)
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -126,7 +126,7 @@ devices {
# be used, regardless of this setting, when the --devicesfile
# option is set to a specific file name.
# This configuration option has an automatic default value.
# use_devicesfile = @DEFAULT_USE_DEVICES_FILE@
# use_devicesfile = 0
# Configuration option devices/devicesfile.
# The name of the system devices file, listing devices that LVM should use.
@ -149,27 +149,7 @@ devices {
# at other devices, but only those that are likely to have the PV.
# If "all", lvm will look at all devices on the system.
# This configuration option has an automatic default value.
# search_for_devnames = "all"
# Configuration option devices/device_ids_refresh.
# Find PVs on new devices and update the device IDs in the devices file.
# If PVs are restored or moved to a new system with new devices, but
# an old system.devices remains with old device IDs, then search for
# the PVIDs on new devices and update the device IDs in system.devices.
# The original device IDs must also not be found on the new system.
# See device_ids_refresh_check for conditions that trigger the refresh.
# This configuration option has an automatic default value.
# device_ids_refresh = 1
# Configuration option devices/device_ids_refresh_checks.
# Conditions that trigger device_ids_refresh to locate PVIDs on new devices.
# product_uuid: refresh if /sys/devices/virtual/dmi/id/product_uuid does not
# match the value saved in system.devices.
# hostname: refresh if hostname does not match the value saved in system.devices.
# (hostname is used if product_uuid is not available.)
# Remove values from this list to prevent lvm from using them.
# This configuration option has an automatic default value.
# device_ids_refresh_checks = [ "product_uuid", "hostname" ]
# search_for_devnames = "auto"
# Configuration option devices/filter.
# Limit the block devices that are used by LVM commands.
@ -645,12 +625,13 @@ allocation {
# Enables or disables whether VDO volume should tag its latency-critical
# writes with the REQ_SYNC flag. Some device mapper targets such as dm-raid5
# process writes with this flag at a higher priority.
# Default is enabled.
# This configuration option has an automatic default value.
# vdo_use_metadata_hints = 1
# Configuration option allocation/vdo_minimum_io_size.
# The minimum IO size for VDO volume to accept, in bytes.
# Valid values are 512 or 4096. The recommended value is 4096.
# Valid values are 512 or 4096. The recommended and default value is 4096.
# This configuration option has an automatic default value.
# vdo_minimum_io_size = 4096
@ -670,6 +651,11 @@ allocation {
# This configuration option has an automatic default value.
# vdo_block_map_period = 16380
# Configuration option allocation/vdo_check_point_frequency.
# The default check point frequency for VDO volume.
# This configuration option has an automatic default value.
# vdo_check_point_frequency = 0
# Configuration option allocation/vdo_use_sparse_index.
# Enables sparse indexing for VDO volume.
# This configuration option has an automatic default value.
@ -698,7 +684,7 @@ allocation {
# Configuration option allocation/vdo_bio_threads.
# Specifies the number of threads to use for submitting I/O
# operations to the storage device of VDO volume.
# The value must be in range [1..100].
# The value must be in range [1..100]
# Each additional thread after the first will use an additional 18MiB of RAM,
# plus 1.12 MiB of RAM per megabyte of configured read cache size.
# This configuration option has an automatic default value.
@ -712,7 +698,7 @@ allocation {
# Configuration option allocation/vdo_cpu_threads.
# Specifies the number of threads to use for CPU-intensive work such as
# hashing or compression for VDO volume. The value must be in range [1..100].
# hashing or compression for VDO volume. The value must be in range [1..100]
# This configuration option has an automatic default value.
# vdo_cpu_threads = 2
@ -730,7 +716,7 @@ allocation {
# processing based on the hash value computed from the block data.
# A logical thread count of 9 or more will require explicitly specifying
# a sufficiently large block map cache size, as well.
# The value must be in range [0..60].
# The value must be in range [0..100].
# vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
# either all zero or all non-zero.
# This configuration option has an automatic default value.
@ -772,7 +758,7 @@ allocation {
# vdo_max_discard = 1
# Configuration option allocation/vdo_pool_header_size.
# Specified the empty header size in KiB at the front and end of vdo pool device.
# Specified the emptry header size in KiB at the front and end of vdo pool device.
# This configuration option has an automatic default value.
# vdo_pool_header_size = 512
}
@ -951,7 +937,7 @@ backup {
# archive = 1
# Configuration option backup/archive_dir.
# Location of the metadata archive files.
# Location of the metdata archive files.
# Remember to back up this directory regularly!
# This configuration option has an automatic default value.
# archive_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@"
@ -1165,11 +1151,16 @@ global {
# lvdisplay_shows_full_device_path = 0
# Configuration option global/event_activation.
# Disable event based autoactivation commands.
# WARNING: setting this to zero may cause machine startup to fail.
# Previously, setting this to zero would enable static autoactivation
# services (via the lvm2-activation-generator), but the autoactivation
# services and generator have been removed.
# Activate LVs based on system-generated device events.
# When a PV appears on the system, a system-generated uevent triggers
# the lvm2-pvscan service which runs the pvscan --cache -aay command.
# If the new PV completes a VG, pvscan autoactivates LVs in the VG.
# When event_activation is disabled, the lvm2-activation services are
# generated and run at fixed points during system startup. These
# services run vgchange -aay to autoactivate LVs in VGs that happen
# to be present at that point in time.
# See the --setautoactivation option or the auto_activation_volume_list
# setting to configure autoactivation for specific VGs or LVs.
# This configuration option has an automatic default value.
# event_activation = 1
@ -1216,7 +1207,7 @@ global {
# Configuration option global/thin_check_executable.
# The full path to the thin_check command.
# LVM uses this command to check that a thin pool metadata device is in a
# LVM uses this command to check that a thin metadata device is in a
# usable state. When a thin pool is activated and after it is
# deactivated, this command is run. Activation will only proceed if
# the command has an exit status of 0. Set to "" to skip this check.
@ -1240,14 +1231,6 @@ global {
# This configuration option has an automatic default value.
# thin_repair_executable = "@THIN_REPAIR_CMD@"
# Configuration option global/thin_restore_executable.
# The full path to the thin_restore command.
# LVM uses this command to restore generated data for a thin pool metadata device.
# Also see thin_restore_options.
# (See package device-mapper-persistent-data or thin-provisioning-tools)
# This configuration option has an automatic default value.
# thin_restore_executable = "@THIN_RESTORE_CMD@"
# Configuration option global/thin_check_options.
# List of options passed to the thin_check command.
# With thin_check version 2.1 or newer you can add the option
@ -1262,11 +1245,6 @@ global {
# This configuration option has an automatic default value.
# thin_repair_options = [ "" ]
# Configuration option global/thin_restore_options.
# List of options passed to the thin_restore command.
# This configuration option has an automatic default value.
# thin_restore_options = [ "" ]
# Configuration option global/thin_disabled_features.
# Features to not use in the thin driver.
# This can be helpful for testing, or to avoid using a feature that is
@ -1315,14 +1293,6 @@ global {
# This configuration option has an automatic default value.
# cache_repair_executable = "@CACHE_REPAIR_CMD@"
# Configuration option global/cache_restore_executable.
# The full path to the cache_restore command.
# LVM uses this command to restore generated data for a cache metadata device.
# Also see cache_restore_options.
# (See package device-mapper-persistent-data or thin-provisioning-tools)
# This configuration option has an automatic default value.
# cache_restore_executable = "@CACHE_RESTORE_CMD@"
# Configuration option global/cache_check_options.
# List of options passed to the cache_check command.
# With cache_check version 5.0 or newer you should include the option
@ -1335,11 +1305,6 @@ global {
# This configuration option has an automatic default value.
# cache_repair_options = [ "" ]
# Configuration option global/cache_restore_options.
# List of options passed to the cache_restore command.
# This configuration option has an automatic default value.
# cache_restore_options = [ "" ]
# Configuration option global/vdo_format_executable.
# The full path to the vdoformat command.
# LVM uses this command to initial data volume for VDO type logical volume
@ -1354,10 +1319,10 @@ global {
# Configuration option global/vdo_disabled_features.
# Features to not use in the vdo driver.
# This can be helpful for testing, or to avoid using a feature that is
# causing problems. Features include: online_rename, version4
# causing problems. Features include: online_rename
#
# Example
# vdo_disabled_features = [ "online_rename", "version4" ]
# vdo_disabled_features = [ "online_rename" ]
#
# This configuration option does not have a default value defined.
@ -1504,13 +1469,13 @@ activation {
# Configuration option activation/reserved_stack.
# Stack size in KiB to reserve for use while devices are suspended.
# Insufficient reserve risks I/O deadlock during device suspension.
# Insufficent reserve risks I/O deadlock during device suspension.
# This configuration option has an automatic default value.
# reserved_stack = 64
# Configuration option activation/reserved_memory.
# Memory size in KiB to reserve for use while devices are suspended.
# Insufficient reserve risks I/O deadlock during device suspension.
# Insufficent reserve risks I/O deadlock during device suspension.
# This configuration option has an automatic default value.
# reserved_memory = 8192
@ -1645,7 +1610,7 @@ activation {
# This includes LVs that have the following segment types:
# raid1, raid4, raid5*, and raid6*.
# If a device in the LV fails, the policy determines the steps
# performed by dmeventd automatically, and the steps performed by the
# performed by dmeventd automatically, and the steps perfomed by the
# manual command lvconvert --repair --use-policies.
# Automatic handling requires dmeventd to be monitoring the LV.
#
@ -1669,7 +1634,7 @@ activation {
# (copies) and a mirror log. A disk log ensures that a mirror LV does
# not need to be re-synced (all copies made the same) every time a
# machine reboots or crashes. If a device in the LV fails, this policy
# determines the steps performed by dmeventd automatically, and the steps
# determines the steps perfomed by dmeventd automatically, and the steps
# performed by the manual command lvconvert --repair --use-policies.
# Automatic handling requires dmeventd to be monitoring the LV.
#
@ -1831,7 +1796,7 @@ activation {
# Configuration option activation/polling_interval.
# Check pvmove or lvconvert progress at this interval (seconds).
# When pvmove or lvconvert must wait for the kernel to finish
# synchronizing or merging data, they check and report progress at
# synchronising or merging data, they check and report progress at
# intervals of this number of seconds. If this is set to 0 and there
# is only one thing to wait for, there are no progress reports, but
# the process is awoken immediately once the operation is complete.
@ -1992,12 +1957,6 @@ activation {
# name for identification.
# json
# JSON format.
# json_std
# JSON format that is more compliant with JSON standard.
# Compared to original "json" format:
# - it does not use double quotes around numeric values,
# - it uses 'null' for undefined numeric values,
# - it prints string list as proper JSON array of strings instead of a single string.
# This configuration option has an automatic default value.
# output_format = "basic"
@ -2037,11 +1996,7 @@ activation {
# buffered = 1
# Configuration option report/headings.
# Format of LVM command's report output headings.
# Accepted values:
# 0 no headings,
# 1 headings with column abbreviations,
# 2 headings with full column names.
# Show headings for columns on report.
# This configuration option has an automatic default value.
# headings = 1

View File

@ -8,6 +8,7 @@ allocation {
vdo_minimum_io_size=4096
vdo_block_map_cache_size_mb=128
vdo_block_map_period=16380
vdo_check_point_frequency=0
vdo_use_sparse_index=0
vdo_index_memory_size_mb=256
vdo_slab_size_mb=2048

12737
configure vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -108,7 +108,7 @@ static SaVersionT version = { 'B', 1, 1 };
#endif
#define DEBUGGING_HISTORY 100
#define DEBUGGING_BUFLEN 270
#define DEBUGGING_BUFLEN 128
#define LOG_SPRINT(cc, f, arg...) do { \
cc->idx++; \
cc->idx = cc->idx % DEBUGGING_HISTORY; \
@ -1091,7 +1091,6 @@ static void cpg_message_callback(cpg_handle_t handle, const struct cpg_name *gna
(rq->u_rq.request_type != DM_ULOG_RESUME) &&
(rq->u_rq.request_type != DM_ULOG_CLEAR_REGION) &&
(rq->u_rq.request_type != DM_ULOG_CHECKPOINT_READY)) {
/* coverity[suspicious_sizeof] allocation is using varargs data @end */
tmp_rq = malloc(DM_ULOG_REQUEST_SIZE);
if (!tmp_rq) {
/*
@ -1341,7 +1340,6 @@ static void cpg_join_callback(struct clog_cpg *match,
goto out;
}
/* coverity[suspicious_sizeof] allocation is using varargs data @end */
rq = malloc(DM_ULOG_REQUEST_SIZE);
if (!rq) {
LOG_ERROR("cpg_config_callback: "

View File

@ -34,7 +34,7 @@
#define LOG_OFFSET 2
#define RESYNC_HISTORY 50
#define RESYNC_BUFLEN 270
#define RESYNC_BUFLEN 128
//static char resync_history[RESYNC_HISTORY][128];
//static int idx = 0;
#define LOG_SPRINT(_lc, f, arg...) do { \
@ -67,7 +67,7 @@ struct log_c {
uint32_t recoverer;
uint64_t recovering_region; /* -1 means not recovering */
uint64_t skip_bit_warning; /* used to warn if region skipped */
unsigned sync_search;
int sync_search;
int resume_override;
@ -220,7 +220,7 @@ static int rw_log(struct log_c *lc, int do_write)
if (r < 0)
LOG_ERROR("[%s] rw_log: read failure: %s",
SHORT_UUID(lc->uuid), strerror(errno));
if ((unsigned) r != lc->disk_size)
if (r != lc->disk_size)
return -EIO; /* Failed disk read */
return 0;
}
@ -298,7 +298,7 @@ static int find_disk_path(char *major_minor_str, char *path_rtn, int *unlink_pat
DIR *dp;
struct dirent *dep;
struct stat statbuf;
unsigned major, minor;
int major, minor;
if (!strstr(major_minor_str, ":")) {
r = stat(major_minor_str, &statbuf);

View File

@ -266,7 +266,7 @@ static int do_local_work(void *data __attribute__((unused)))
RQ_TYPE(u_rq->request_type));
break;
}
/* ELSE */ /* fall through */
/* ELSE, fall through */
case DM_ULOG_IS_CLEAN:
case DM_ULOG_FLUSH:
case DM_ULOG_MARK_REGION:

View File

@ -76,7 +76,7 @@ dmeventd: $(LIB_SHARED) dmeventd.o
dmeventd.static: $(LIB_STATIC) dmeventd.o
@echo " [CC] $@"
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(STATIC_LDFLAGS) -static dmeventd.o \
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static dmeventd.o \
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
ifeq ("@PKGCONFIG@", "yes")

View File

@ -98,7 +98,6 @@ static int _systemd_activation = 0;
static int _foreground = 0;
static int _restart = 0;
static time_t _idle_since = 0;
static const char *_exit_on = DEFAULT_DMEVENTD_EXIT_ON_PATH;
static char **_initial_registrations = 0;
/* FIXME Make configurable at runtime */
@ -724,18 +723,12 @@ static int _get_status(struct message_data *message_data)
static int _get_parameters(struct message_data *message_data) {
struct dm_event_daemon_message *msg = message_data->msg;
int size;
char idle_buf[32] = "";
if (_idle_since)
(void)dm_snprintf(idle_buf, sizeof(idle_buf), " idle=%lu", (long unsigned) (time(NULL) - _idle_since));
free(msg->data);
if ((size = dm_asprintf(&msg->data, "%s pid=%d daemon=%s exec_method=%s exit_on=\"%s\"%s",
if ((size = dm_asprintf(&msg->data, "%s pid=%d daemon=%s exec_method=%s",
message_data->id, getpid(),
_foreground ? "no" : "yes",
_systemd_activation ? "systemd" : "direct",
_exit_on,
idle_buf)) < 0) {
_systemd_activation ? "systemd" : "direct")) < 0) {
stack;
return -ENOMEM;
}
@ -994,7 +987,6 @@ static void _monitor_unregister(void *arg)
DEBUGLOG("Unregistering monitor for %s.", thread->device.name);
_unregister_for_timeout(thread);
/* coverity[missing_lock] no missing lock here */
if ((thread->status != DM_THREAD_REGISTERING) &&
!_do_unregister_device(thread))
log_error("%s: %s unregister failed.", __func__,
@ -1005,8 +997,6 @@ static void _monitor_unregister(void *arg)
_lock_mutex();
thread->status = DM_THREAD_DONE; /* Last access to thread memory! */
_unlock_mutex();
if (_exit_now) /* Exit is already in-progress, wake-up sleeping select() */
kill(getpid(), SIGINT);
}
/* Device monitoring thread. */
@ -1053,9 +1043,9 @@ static void *_monitor_thread(void *arg)
_unlock_mutex();
_do_process_event(thread);
thread->current_events = 0; /* Current events processed */
_lock_mutex();
thread->current_events = 0; /* Current events processed */
thread->processing = 0;
/*
@ -1171,36 +1161,6 @@ static int _unregister_for_event(struct message_data *message_data)
return ret;
}
static void _unregister_all_threads(void)
{
struct thread_status *thread, *tmp;
_lock_mutex();
dm_list_iterate_items_safe(thread, tmp, &_thread_registry)
_update_events(thread, 0);
_unlock_mutex();
}
static void _wait_for_new_pid(void)
{
unsigned long st_ino = 0;
struct stat st;
int i;
for (i = 0; i < 400000; ++i) {
if (lstat(DMEVENTD_PIDFILE, &st) == 0) {
if (!st_ino)
st_ino = st.st_ino;
else if (st_ino != st.st_ino)
break; /* different pidfile */
} else if (errno == ENOENT)
break; /* pidfile is removed */
usleep(100);
}
}
/*
* Register for an event.
*
@ -1717,9 +1677,9 @@ static void _process_request(struct dm_event_fifos *fifos)
free(msg.data);
if (cmd == DM_EVENT_CMD_DIE) {
_unregister_all_threads();
_exit_now = DM_SCHEDULED_EXIT;
log_info("dmeventd exiting for restart.");
if (unlink(DMEVENTD_PIDFILE))
log_sys_error("unlink", DMEVENTD_PIDFILE);
_exit(0);
}
}
@ -1766,7 +1726,7 @@ static void _cleanup_unused_threads(void)
DEBUGLOG("Destroying Thr %x.", (int)thread->thread);
if (pthread_join(thread->thread, NULL))
log_sys_debug("pthread_join", "");
log_sys_error("pthread_join", "");
_free_thread_status(thread);
_lock_mutex();
@ -1797,7 +1757,7 @@ static void _init_thread_signals(void)
sigdelset(&my_sigset, SIGQUIT);
if (pthread_sigmask(SIG_BLOCK, &my_sigset, NULL))
log_sys_debug("pthread_sigmask", "SIG_BLOCK");
log_sys_error("pthread_sigmask", "SIG_BLOCK");
}
/*
@ -1809,8 +1769,7 @@ static void _init_thread_signals(void)
*/
static void _exit_handler(int sig __attribute__((unused)))
{
if (!_exit_now)
_exit_now = DM_SIGNALED_EXIT;
_exit_now = DM_SIGNALED_EXIT;
}
#ifdef __linux__
@ -1826,7 +1785,7 @@ static int _set_oom_adj(const char *oom_adj_path, int val)
fprintf(fp, "%i", val);
if (dm_fclose(fp))
log_sys_debug("fclose", oom_adj_path);
log_sys_error("fclose", oom_adj_path);
return 1;
}
@ -1840,11 +1799,11 @@ static int _protect_against_oom_killer(void)
if (stat(OOM_ADJ_FILE, &st) == -1) {
if (errno != ENOENT)
log_sys_debug("stat", OOM_ADJ_FILE);
log_sys_error("stat", OOM_ADJ_FILE);
/* Try old oom_adj interface as a fallback */
if (stat(OOM_ADJ_FILE_OLD, &st) == -1) {
log_sys_debug("stat", OOM_ADJ_FILE_OLD);
log_sys_error("stat", OOM_ADJ_FILE_OLD);
return 1;
}
@ -1933,14 +1892,14 @@ out:
static void _remove_files_on_exit(void)
{
if (unlink(DMEVENTD_PIDFILE))
log_sys_debug("unlink", DMEVENTD_PIDFILE);
log_sys_error("unlink", DMEVENTD_PIDFILE);
if (!_systemd_activation) {
if (unlink(DM_EVENT_FIFO_CLIENT))
log_sys_debug("unlink", DM_EVENT_FIFO_CLIENT);
log_sys_error("unlink", DM_EVENT_FIFO_CLIENT);
if (unlink(DM_EVENT_FIFO_SERVER))
log_sys_debug("unlink", DM_EVENT_FIFO_SERVER);
log_sys_error("unlink", DM_EVENT_FIFO_SERVER);
}
}
@ -2010,7 +1969,6 @@ static void _daemonize(void)
(void) close(fd);
}
/* coverity[leaked_handle] dont't care */
if ((open("/dev/null", O_RDONLY) < 0) ||
(open("/dev/null", O_WRONLY) < 0) ||
(open("/dev/null", O_WRONLY) < 0))
@ -2072,68 +2030,6 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
return 1;
}
static int _info_dmeventd(const char *name, struct dm_event_fifos *fifos)
{
struct dm_event_daemon_message msg = { 0 };
int i, count = 0;
char *line;
int version;
int ret = 0;
/* Get the list of registrations from the running daemon. */
if (!init_fifos(fifos)) {
fprintf(stderr, "Could not initiate communication with existing dmeventd.\n");
return 0;
}
if (!dm_event_get_version(fifos, &version)) {
fprintf(stderr, "Could not communicate with existing dmeventd.\n");
goto out;
}
if (version < 1) {
fprintf(stderr, "The running dmeventd instance is too old.\n"
"Protocol version %d (required: 1). Action cancelled.\n", version);
goto out;
}
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_STATUS, "-", "-", 0, 0)) {
fprintf(stderr, "Failed to acquire status from existing dmeventd.\n");
goto out;
}
line = strchr(msg.data, ' ') + 1;
for (i = 0; msg.data[i]; ++i)
if (msg.data[i] == ';') {
msg.data[i] = 0;
if (!count)
printf("%s is monitoring:\n", name);
printf("%s\n", line);
line = msg.data + i + 1;
++count;
}
free(msg.data);
if (!count)
printf("%s does not monitor any device.\n", name);
if (version >= 2) {
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
fprintf(stderr, "Failed to acquire parameters from existing dmeventd.\n");
goto out;
}
printf("%s internal status: %s\n", name, msg.data);
free(msg.data);
}
ret = 1;
out:
fini_fifos(fifos);
return ret;
}
static void _restart_dmeventd(void)
{
struct dm_event_fifos fifos = {
@ -2220,15 +2116,19 @@ static void _restart_dmeventd(void)
((e = getenv(SD_ACTIVATION_ENV_VAR_NAME)) && strcmp(e, "1")))
_systemd_activation = 1;
fini_fifos(&fifos);
for (i = 0; i < 10; ++i) {
if ((access(DMEVENTD_PIDFILE, F_OK) == -1) && (errno == ENOENT))
break;
usleep(10);
}
/* Give a few seconds dmeventd to finish */
_wait_for_new_pid();
if (!_systemd_activation)
if (!_systemd_activation) {
fini_fifos(&fifos);
return;
}
/* Reopen fifos. */
fini_fifos(&fifos);
if (!init_fifos(&fifos)) {
fprintf(stderr, "Could not initiate communication with new instance of dmeventd.\n");
exit(EXIT_FAILURE);
@ -2249,12 +2149,10 @@ bad:
static void _usage(char *prog, FILE *file)
{
fprintf(file, "Usage:\n"
"%s [-d [-d [-d]]] [-e path] [-f] [-h] [i] [-l] [-R] [-V] [-?]\n\n"
"%s [-d [-d [-d]]] [-f] [-h] [-l] [-R] [-V] [-?]\n\n"
" -d Log debug messages to syslog (-d, -dd, -ddd)\n"
" -e Select a file path checked on exit\n"
" -f Don't fork, run in the foreground\n"
" -h Show this help information\n"
" -i Query running instance of dmeventd for info\n"
" -l Log to stdout,stderr instead of syslog\n"
" -? Show this help information on stderr\n"
" -R Restart dmeventd\n"
@ -2271,29 +2169,20 @@ int main(int argc, char *argv[])
.server_path = DM_EVENT_FIFO_SERVER
};
time_t now, idle_exit_timeout = DMEVENTD_IDLE_EXIT_TIMEOUT;
opterr = 0;
optind = 0;
optopt = optind = opterr = 0;
optarg = (char*) "";
while ((opt = getopt(argc, argv, ":?e:fhiVdlR")) != EOF) {
while ((opt = getopt(argc, argv, "?fhVdlR")) != EOF) {
switch (opt) {
case 'h':
_usage(argv[0], stdout);
return EXIT_SUCCESS;
exit(EXIT_SUCCESS);
case '?':
_usage(argv[0], stderr);
return EXIT_SUCCESS;
case 'i':
return _info_dmeventd(argv[0], &fifos) ? EXIT_SUCCESS : EXIT_FAILURE;
exit(EXIT_SUCCESS);
case 'R':
_restart++;
break;
case 'e':
if (strchr(optarg, '"')) {
fprintf(stderr, "dmeventd: option -e does not accept path \"%s\" with '\"' character.\n", optarg);
return EXIT_FAILURE;
}
_exit_on=optarg;
break;
case 'f':
_foreground++;
break;
@ -2305,10 +2194,7 @@ int main(int argc, char *argv[])
break;
case 'V':
printf("dmeventd version: %s\n", DM_LIB_VERSION);
return EXIT_SUCCESS;
case ':':
fprintf(stderr, "dmeventd: option -%c requires an argument.\n", optopt);
return EXIT_FAILURE;
exit(EXIT_SUCCESS);
}
}
@ -2399,28 +2285,15 @@ int main(int argc, char *argv[])
break;
}
}
} else
switch (_exit_now) {
case DM_SIGNALED_EXIT:
_exit_now = DM_SCHEDULED_EXIT;
/*
* 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.");
/* fall through */
case DM_SCHEDULED_EXIT:
/* While exit is scheduled, check for exit_on file */
DEBUGLOG("Checking exit on file \"%s\".", _exit_on);
if (_exit_on[0] && (access(_exit_on, F_OK) == 0)) {
log_info("dmeventd detected exit on file %s, unregistering all monitored devices.",
_exit_on);
_unregister_all_threads();
}
break;
}
} else if (_exit_now == DM_SIGNALED_EXIT) {
_exit_now = DM_SCHEDULED_EXIT;
/*
* 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.");
}
_process_request(&fifos);
_cleanup_unused_threads();
}
@ -2430,9 +2303,9 @@ int main(int argc, char *argv[])
log_notice("dmeventd shutting down.");
if (fifos.client >= 0 && close(fifos.client))
log_sys_debug("client close", fifos.client_path);
log_sys_error("client close", fifos.client_path);
if (fifos.server >= 0 && close(fifos.server))
log_sys_debug("server close", fifos.server_path);
log_sys_error("server close", fifos.server_path);
if (_use_syslog)
closelog();

View File

@ -552,8 +552,6 @@ void fini_fifos(struct dm_event_fifos *fifos)
if (close(fifos->server))
log_sys_debug("close", fifos->server_path);
}
fifos->client = fifos->server = -1;
}
/* Get uuid of a device */
@ -846,7 +844,6 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
char *p;
struct dm_event_daemon_message msg = { 0 };
int ret = 0;
if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0))
return 0;
@ -854,17 +851,13 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
*version = 0;
if (!p || !(p = strchr(p, ' '))) /* Message ID */
goto out;
return 0;
if (!(p = strchr(p + 1, ' '))) /* HELLO */
goto out;
return 0;
if ((p = strchr(p + 1, ' '))) /* HELLO, once more */
*version = atoi(p);
ret = 1;
out:
free(msg.data);
return ret;
return 1;
}
void dm_event_log_set(int debug_log_level, int use_syslog)
@ -879,11 +872,11 @@ void dm_event_log(const char *subsys, int level, const char *file,
{
static int _abort_on_internal_errors = -1;
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
static long long _start = 0;
static time_t start = 0;
const char *indent = "";
FILE *stream = log_stderr(level) ? stderr : stdout;
int prio;
long long now, now_nsec;
time_t now;
int log_with_debug = 0;
if (subsys[0] == '#') {
@ -930,28 +923,17 @@ void dm_event_log(const char *subsys, int level, const char *file,
if (_use_syslog) {
vsyslog(prio, format, ap);
} else {
if (_debug_level) {
#define _NSEC_PER_SEC (1000000000LL)
#ifdef HAVE_REALTIME
struct timespec mono_time = { 0 };
if (clock_gettime(CLOCK_MONOTONIC, &mono_time) == 0)
now = mono_time.tv_sec * _NSEC_PER_SEC + mono_time.tv_nsec;
else
#endif
now = time(NULL) * _NSEC_PER_SEC;
if (!_start)
_start = now;
now -= _start;
now_nsec = now %_NSEC_PER_SEC;
now /= _NSEC_PER_SEC;
fprintf(stream, "[%2lld:%02lld.%06lld] %8x:%-6s%s",
now / 60, now % 60, now_nsec / 1000,
now = time(NULL);
if (!start)
start = now;
now -= start;
if (_debug_level)
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
(int)now / 60, (int)now % 60,
// TODO: Maybe use shorter ID
// ((int)(pthread_self()) >> 6) & 0xffff,
(int)pthread_self(), subsys,
(_debug_level > 3) ? "" : indent);
}
if (_debug_level > 3)
fprintf(stream, "%28s:%4d %s", file, line, indent);
vfprintf(stream, _(format), ap);

View File

@ -123,7 +123,6 @@ struct dm_pool *dmeventd_lvm2_pool(void)
int dmeventd_lvm2_run(const char *cmdline)
{
/* coverity[missing_lock] no locking for run part */
return (lvm2_run(_lvm_handle, cmdline) == LVM2_COMMAND_SUCCEEDED);
}

View File

@ -51,14 +51,18 @@ include $(top_builddir)/make.tmpl
.PHONY: install_lvmdbusd
all:
$(Q) test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
install_lvmdbusd: $(LVMDBUSD)
@echo " [INSTALL] $<"
$(Q) $(INSTALL_DIR) $(sbindir)
$(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
$(Q) $(INSTALL_DIR) $(lvmdbusdir) $(lvmdbusdir)/__pycache__
$(Q) $(INSTALL_DIR) $(lvmdbusdir)
$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(lvmdbusdir))
$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir)
$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbuspydir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
$(Q) $(CHMOD) 755 $(lvmdbusdir)/__pycache__
$(Q) $(CHMOD) 444 $(lvmdbusdir)/__pycache__/*.py[co]
install_lvm2: install_lvmdbusd

View File

@ -44,10 +44,10 @@ class AutomatedProperties(dbus.service.Object):
def set_interface(self, interface):
"""
With inheritance, we can't easily tell what interfaces a class provides,
With inheritance we can't easily tell what interfaces a class provides
so we will have each class that implements an interface tell the
base AutomatedProperties what it is they do provide. This is kind of
clunky, and perhaps we can figure out a better way to do this later.
clunky and perhaps we can figure out a better way to do this later.
:param interface: An interface the object supports
:return:
"""
@ -88,6 +88,7 @@ class AutomatedProperties(dbus.service.Object):
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _get_all_prop(obj, interface_name):
if interface_name in obj.interface(True):

View File

@ -7,13 +7,16 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import subprocess
from . import cfg
from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm
import dbus
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
mt_async_call
from .request import RequestEntry
import threading
import time
import traceback
def pv_move_lv_cmd(move_options, lv_full_name,
@ -62,15 +65,18 @@ def _move_callback(job_state, line_str):
def _move_merge(interface_name, command, job_state):
# We need to execute these command stand alone by forking & exec'ing
# the command always as we will be getting periodic output from them on
# the status of the long-running operation.
# the status of the long running operation.
meta = LvmExecutionMeta(time.time(), 0, command)
cfg.flightrecorder.add(meta)
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
cfg.blackbox.add(meta)
ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
cb_data=job_state)
ended = time.time()
meta.completed(ended, ec, stdout, stderr)
with meta.lock:
meta.ended = time.time()
meta.ec = ec
meta.stderr_txt = stderr
if ec == 0:
job_state.Percent = 100

View File

@ -11,18 +11,11 @@ import os
import multiprocessing
import queue
import itertools
from lvmdbusd.utils import LvmDebugData
from lvmdbusd import path
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
LOCK_FILE = os.getenv("LVM_DBUSD_LOCKFILE", "/var/lock/lvm/lvmdbusd")
# Save off the debug data needed for lvm team to debug issues
# only used for 'fullreport' at this time.
lvmdebug = LvmDebugData(os.getenv('LVM_DBUSD_COLLECT_LVM_DEBUG', False))
# This is the global object manager
om = None
@ -32,13 +25,13 @@ bus = None
# Command line args
args = None
# Set to true if we depend on external events for updates
# Set to true if we are depending on external events for updates
got_external_event = False
# Shared state variable across all processes
run = multiprocessing.Value('i', 1)
# If this is set to true, the current setup support lvm shell, and we are
# If this is set to true, the current setup support lvm shell and we are
# running in that mode of operation
SHELL_IN_USE = None
@ -50,9 +43,6 @@ worker_q = queue.Queue()
# Main event loop
loop = None
# Used to instruct the daemon if we should ignore SIGTERM
ignore_sigterm = False
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
BASE_INTERFACE = 'com.redhat.lvmdbus1'
PV_INTERFACE = BASE_INTERFACE + '.Pv'
@ -100,14 +90,11 @@ vdo_support = False
db = None
# lvm flight recorder
flightrecorder = None
blackbox = None
# RequestEntry ctor
create_request_entry = None
# Circular debug log
debug = None
def exit_daemon():
"""
@ -117,6 +104,3 @@ def exit_daemon():
if run and loop:
run.value = 0
loop.quit()
systemd = False

View File

@ -6,18 +6,19 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import errno
from subprocess import Popen, PIPE
import select
import time
import threading
from itertools import chain
import collections
import traceback
import os
from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
make_non_block, read_decoded, extract_stack_trace, LvmBug, add_config_option, get_error_msg
make_non_block, read_decoded
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
try:
@ -25,6 +26,7 @@ try:
except ImportError:
import json
SEP = '{|}'
total_time = 0.0
total_count = 0
@ -36,7 +38,7 @@ cmd_lock = threading.RLock()
class LvmExecutionMeta(object):
def __init__(self, start, ended, cmd, ec=-1000, stdout_txt=None, stderr_txt=None):
def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
self.lock = threading.RLock()
self.start = start
self.ended = ended
@ -47,49 +49,32 @@ class LvmExecutionMeta(object):
def __str__(self):
with self.lock:
if self.ended == 0:
ended_txt = "still running"
self.ended = time.time()
else:
ended_txt = str(time.ctime(self.ended))
return 'EC= %d for "%s"\n' \
"STARTED: %s, ENDED: %s, DURATION: %f\n" \
return "EC= %d for %s\n" \
"STARTED: %f, ENDED: %f\n" \
"STDOUT=%s\n" \
"STDERR=%s\n" % \
(self.ec, " ".join(self.cmd), time.ctime(self.start), ended_txt, float(self.ended) - self.start,
self.stdout_txt,
self.stderr_txt)
def completed(self, end_time, ec, stdout_txt, stderr_txt):
with self.lock:
self.ended = end_time
self.ec = ec
self.stdout_txt = stdout_txt
self.stderr_txt = stderr_txt
(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
self.stderr_txt)
class LvmFlightRecorder(object):
def __init__(self, size=16):
self.queue = collections.deque(maxlen=size)
self.lock = threading.RLock()
def add(self, lvm_exec_meta):
with self.lock:
self.queue.append(lvm_exec_meta)
self.queue.append(lvm_exec_meta)
def dump(self):
with self.lock:
with cmd_lock:
if len(self.queue):
log_error("LVM dbus flight recorder START (in order of newest to oldest)")
log_error("LVM dbus flight recorder START")
for c in reversed(self.queue):
log_error(str(c))
log_error("LVM dbus flight recorder END")
self.queue.clear()
cfg.flightrecorder = LvmFlightRecorder()
cfg.blackbox = LvmFlightRecorder()
def _debug_c(cmd, exit_code, out):
@ -109,7 +94,7 @@ def call_lvm(command, debug=False, line_cb=None,
stdin, CALL MUST EXECUTE QUICKLY and not *block*
otherwise call_lvm function will fail to read
stdin/stdout. Return value of call back is ignored
:param cb_data: Supplied to call back to allow caller access to
:param cb_data: Supplied to callback to allow caller access to
its own data
# Callback signature
@ -121,9 +106,6 @@ def call_lvm(command, debug=False, line_cb=None,
command.insert(0, cfg.LVM_CMD)
command = add_no_notify(command)
# Ensure we get an error message when we fork & exec the lvm command line
command = add_config_option(command, "--config", 'log/command_log_selection="log_context!=''"')
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
env=os.environ)
@ -133,7 +115,7 @@ def call_lvm(command, debug=False, line_cb=None,
make_non_block(process.stdout)
make_non_block(process.stderr)
while True and cfg.run.value != 0:
while True:
try:
rd_fd = [process.stdout.fileno(), process.stderr.fileno()]
ready = select.select(rd_fd, [], [], 2)
@ -151,8 +133,8 @@ def call_lvm(command, debug=False, line_cb=None,
if i != -1:
try:
line_cb(cb_data, stdout_text[stdout_index:i])
except BaseException as be:
st = extract_stack_trace(be)
except:
st = traceback.format_exc()
log_error("call_lvm: line_cb exception: \n %s" % st)
stdout_index = i + 1
else:
@ -163,31 +145,12 @@ def call_lvm(command, debug=False, line_cb=None,
break
except IOError as ioe:
log_debug("call_lvm:" + str(ioe))
break
pass
if process.returncode is not None:
cfg.lvmdebug.lvm_complete()
if debug or (process.returncode != 0 and (process.returncode != 5 and "fullreport" in command)):
_debug_c(command, process.returncode, (stdout_text, stderr_text))
try:
report_json = json.loads(stdout_text)
except json.decoder.JSONDecodeError:
# Some lvm commands don't return json even though we are asking for it to do so.
return process.returncode, stdout_text, stderr_text
error_msg = get_error_msg(report_json)
if error_msg:
stderr_text += error_msg
return process.returncode, report_json, stderr_text
else:
if cfg.run.value == 0:
raise SystemExit
# We can bail out before the lvm command finished when we get a signal
# which is requesting we exit
return -errno.EINTR, "", "operation interrupted"
if debug or process.returncode != 0:
_debug_c(command, process.returncode, (stdout_text, stderr_text))
return process.returncode, stdout_text, stderr_text
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
@ -202,18 +165,18 @@ def _shell_cfg():
_t_call = lvm_shell.call_lvm
cfg.SHELL_IN_USE = lvm_shell
return True
except Exception as e:
except Exception:
_t_call = call_lvm
cfg.SHELL_IN_USE = None
log_error("Unable to utilize lvm shell, dropping "
"back to fork & exec\n%s" % extract_stack_trace(e))
log_error(traceback.format_exc())
log_error("Unable to utilize lvm shell, dropping back to fork & exec")
return False
def set_execution(shell):
global _t_call
with cmd_lock:
# If the user requested lvm shell, and we are currently setup that
# If the user requested lvm shell and we are currently setup that
# way, just return
if cfg.SHELL_IN_USE and shell:
return True
@ -237,15 +200,11 @@ def time_wrapper(command, debug=False):
with cmd_lock:
start = time.time()
meta = LvmExecutionMeta(start, 0, command)
# Add the partial metadata to flight recorder, so if the command hangs
# we will see what it was.
cfg.flightrecorder.add(meta)
results = _t_call(command, debug)
ended = time.time()
total_time += (ended - start)
total_count += 1
meta.completed(ended, *results)
cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
return results
@ -255,11 +214,44 @@ call = time_wrapper
# Default cmd
# Place default arguments for every command here.
def _dc(cmd, args):
c = [cmd, '--nosuffix', '--unbuffered', '--units', 'b']
c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
'--unbuffered', '--units', 'b']
c.extend(args)
return c
def parse(out):
rc = []
for line in out.split('\n'):
# This line includes separators, so process them
if SEP in line:
elem = line.split(SEP)
cleaned_elem = []
for e in elem:
e = e.strip()
cleaned_elem.append(e)
if len(cleaned_elem) > 1:
rc.append(cleaned_elem)
else:
t = line.strip()
if len(t) > 0:
rc.append(t)
return rc
def parse_column_names(out, column_names):
lines = parse(out)
rc = []
for i in range(0, len(lines)):
d = dict(list(zip(column_names, lines[i])))
rc.append(d)
return rc
def options_to_cli_args(options):
rc = []
for k, v in list(dict(options).items()):
@ -324,12 +316,10 @@ def vg_rename(vg_uuid, new_name, rename_options):
return call(cmd)
def vg_remove(vg_id, remove_options):
def vg_remove(vg_name, remove_options):
cmd = ['vgremove']
cmd.extend(options_to_cli_args(remove_options))
cmd.extend(['-f', vg_id])
# https://bugzilla.redhat.com/show_bug.cgi?id=2175220 is preventing us from doing the following
# cmd.extend(['-f', "--select", "vg_uuid=%s" % vg_id])
cmd.extend(['-f', vg_name])
return call(cmd)
@ -623,25 +613,68 @@ def lvm_full_report_json():
'--configreport', 'vg', '-o', ','.join(vg_columns),
'--configreport', 'lv', '-o', ','.join(lv_columns),
'--configreport', 'seg', '-o', ','.join(lv_seg_columns),
'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns)
'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns),
'--reportformat', 'json'
])
# We are running the fullreport command, we will ask lvm to output the debug
# data, so we can have the required information for lvm to debug the fullreport failures.
# Note: this is disabled by default and can be enabled with env. var.
# LVM_DBUSD_COLLECT_LVM_DEBUG=True
fn = cfg.lvmdebug.setup()
if fn is not None:
add_config_option(cmd, "--config", "log {level=7 file=%s syslog=0}" % fn)
rc, out, err = call(cmd)
# When we have an exported vg the exit code of lvs or fullreport will be 5
if rc == 0 or rc == 5:
if type(out) != dict:
raise LvmBug("lvm likely returned invalid JSON, lvm exit code = %d, output = %s, err= %s" %
(rc, str(out), str(err)))
return out
raise LvmBug("'fullreport' exited with code '%d'" % rc)
# With the current implementation, if we are using the shell then we
# are using JSON and JSON is returned back to us as it was parsed to
# figure out if we completed OK or not
if cfg.SHELL_IN_USE:
assert(type(out) == dict)
return out
else:
try:
return json.loads(out)
except json.decoder.JSONDecodeError as joe:
log_error("JSONDecodeError %s, \n JSON=\n%s\n" %
(str(joe), out))
raise joe
return None
def pv_retrieve_with_segs(device=None):
d = []
err = ""
out = ""
rc = 0
columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing']
# Lvm has some issues where it returns failure when querying pvs when other
# operations are in process, see:
# https://bugzilla.redhat.com/show_bug.cgi?id=1274085
for i in range(0, 10):
cmd = _dc('pvs', ['-o', ','.join(columns)])
if device:
cmd.extend(device)
rc, out, err = call(cmd)
if rc == 0:
d = parse_column_names(out, columns)
break
else:
time.sleep(0.2)
log_debug("LVM Bug workaround, retrying pvs command...")
if rc != 0:
msg = "We were unable to get pvs to return without error after " \
"trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \
(rc, err, out)
log_error(msg)
raise RuntimeError(msg)
return d
def pv_resize(device, size_bytes, create_options):
@ -787,10 +820,6 @@ def activate_deactivate(op, name, activate, control_flags, options):
if (1 << 5) & control_flags:
cmd.append('--ignoreactivationskip')
# Shared locking (Cluster)
if (1 << 6) & control_flags:
op += 's'
if activate:
op += 'y'
else:
@ -802,6 +831,53 @@ def activate_deactivate(op, name, activate, control_flags, options):
return call(cmd)
def vg_retrieve(vg_specific):
if vg_specific:
assert isinstance(vg_specific, list)
columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free',
'vg_sysid', 'vg_extent_size', 'vg_extent_count',
'vg_free_count', 'vg_profile', 'max_lv', 'max_pv',
'pv_count', 'lv_count', 'snap_count', 'vg_seqno',
'vg_mda_count', 'vg_mda_free', 'vg_mda_size',
'vg_mda_used_count', 'vg_attr', 'vg_tags']
cmd = _dc('vgs', ['-o', ','.join(columns)])
if vg_specific:
cmd.extend(vg_specific)
d = []
rc, out, err = call(cmd)
if rc == 0:
d = parse_column_names(out, columns)
return d
def lv_retrieve_with_segments():
columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size',
'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid',
'origin', 'data_percent',
'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
'metadata_lv', 'seg_pe_ranges', 'segtype', 'lv_parent',
'lv_role', 'lv_layout',
'snap_percent', 'metadata_percent', 'copy_percent',
'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
cmd = _dc('lvs', ['-a', '-o', ','.join(columns)])
rc, out, err = call(cmd)
d = []
if rc == 0:
d = parse_column_names(out, columns)
return d
if __name__ == '__main__':
# Leave this for future debug as needed
pass
pv_data = pv_retrieve_with_segs()
for p in pv_data:
print(str(p))

View File

@ -6,16 +6,16 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import errno
from .pv import load_pvs
from .vg import load_vgs
from .lv import load_lvs
from . import cfg
from .utils import MThreadRunner, log_debug, log_error, LvmBug, extract_stack_trace
from .utils import MThreadRunner, log_debug, log_error
import threading
import queue
import time
import traceback
def _main_thread_load(refresh=True, emit_signal=True):
@ -120,125 +120,89 @@ class StateUpdate(object):
@staticmethod
def update_thread(obj):
exception_count = 0
queued_requests = []
def set_results(val):
nonlocal queued_requests
for idx in queued_requests:
idx.set_result(val)
# Only clear out the requests after we have given them a result
# otherwise we can orphan the waiting threads, and they never
# wake up if we get an exception
queued_requests = []
def bailing(rv):
set_results(rv)
try:
while True:
item = obj.queue.get(False)
item.set_result(rv)
except queue.Empty:
pass
def _load_args(requests):
"""
If we have multiple requests in the queue, they might not all have the same options. If any of the requests
have an option set we need to honor it.
"""
refresh = any([r.refresh for r in requests])
emit_signal = any([r.emit_signal for r in requests])
cache_refresh = any([r.cache_refresh for r in requests])
log = any([r.log for r in requests])
need_main_thread = any([r.need_main_thread for r in requests])
return refresh, emit_signal, cache_refresh, log, need_main_thread
def _drain_queue(queued, incoming):
try:
while True:
queued.append(incoming.get(block=False))
except queue.Empty:
pass
def _handle_error():
nonlocal exception_count
exception_count += 1
if exception_count >= 5:
log_error("Too many errors in update_thread, exiting daemon")
cfg.debug.dump()
cfg.flightrecorder.dump()
bailing(errno.EFAULT)
cfg.exit_daemon()
else:
# Slow things down when encountering errors
cfg.lvmdebug.complete()
time.sleep(1)
while cfg.run.value != 0:
# noinspection PyBroadException
try:
refresh = True
emit_signal = True
cache_refresh = True
log = True
need_main_thread = True
with obj.lock:
wait = not obj.deferred
obj.deferred = False
if len(queued_requests) == 0 and wait:
# Note: If we don't have anything for 2 seconds we will
# get a queue.Empty exception raised here
queued_requests.append(obj.queue.get(block=True, timeout=2))
queued_requests.append(obj.queue.get(True, 2))
# Ok we have one or the deferred queue has some,
# check if any others and grab them too
_drain_queue(queued_requests, obj.queue)
# check if any others
try:
while True:
queued_requests.append(obj.queue.get(False))
except queue.Empty:
pass
if len(queued_requests) > 1:
log_debug("Processing %d updates!" % len(queued_requests),
'bg_black', 'fg_light_green')
num_changes = load(*_load_args(queued_requests))
# We have what we can, run the update with the needed options
for i in queued_requests:
if not i.refresh:
refresh = False
if not i.emit_signal:
emit_signal = False
if not i.cache_refresh:
cache_refresh = False
if not i.log:
log = False
if not i.need_main_thread:
need_main_thread = False
num_changes = load(refresh, emit_signal, cache_refresh, log,
need_main_thread)
# Update is done, let everyone know!
set_results(num_changes)
for i in queued_requests:
i.set_result(num_changes)
# Only clear out the requests after we have given them a result
# otherwise we can orphan the waiting threads and they never
# wake up if we get an exception
queued_requests = []
# We retrieved OK, clear exception count
exception_count = 0
except queue.Empty:
pass
except SystemExit:
break
except LvmBug as bug:
# If a lvm bug occurred, we will dump the lvm debug data if
# we have it.
cfg.lvmdebug.dump()
log_error(str(bug))
_handle_error()
except Exception as e:
log_error("update_thread: \n%s" % extract_stack_trace(e))
_handle_error()
finally:
cfg.lvmdebug.complete()
st = traceback.format_exc()
log_error("update_thread exception: \n%s" % st)
cfg.blackbox.dump()
exception_count += 1
if exception_count >= 5:
for i in queued_requests:
i.set_result(e)
# Make sure to unblock any that may be waiting before we exit this thread
# otherwise they hang forever ...
bailing(Exception("update thread exiting"))
log_debug("update thread exiting!")
log_error("Too many errors in update_thread, exiting daemon")
cfg.exit_daemon()
else:
# Slow things down when encountering errors
time.sleep(1)
def __init__(self):
self.lock = threading.RLock()
self.queue = queue.Queue()
self.deferred = False
# Do initial load, with retries. During error injection testing we can and do fail here.
count = 0
need_refresh = False # First attempt we are building from new, any subsequent will be true
while count < 5:
try:
load(refresh=need_refresh, emit_signal=False, need_main_thread=False)
break
except LvmBug as bug:
count += 1
need_refresh = True
log_error("We encountered an lvm bug on initial load, trying again %s" % str(bug))
# Do initial load
load(refresh=False, emit_signal=False, need_main_thread=False)
self.thread = threading.Thread(target=StateUpdate.update_thread,
args=(self,),

View File

@ -44,7 +44,7 @@ class WaitingClient(object):
self.timer_id = GLib.timeout_add_seconds(
tmo, WaitingClient._timeout, self)
# The job finished before the timer popped, and we are being notified that
# The job finished before the timer popped and we are being notified that
# it's done
def notify(self):
with self.rlock:
@ -71,7 +71,7 @@ class JobState(object):
self._stderr = ''
self._waiting_clients = []
# This is a lvm command that is just taking too long and doesn't
# This is an lvm command that is just taking too long and doesn't
# support background operation
if self._request:
# Faking the percentage when we don't have one
@ -138,7 +138,7 @@ class JobState(object):
# If a waiting client timer pops before the job is done we will allow
# the client to remove themselves from the list. As we have a lock
# here and a lock in the waiting client too, and they can be obtained
# in different orders, a deadlock can occur.
# in different orders, a dead lock can occur.
# As this remove is really optional, we will try to acquire the lock
# and remove. If we are unsuccessful it's not fatal, we just delay
# the time when the objects can be garbage collected by python
@ -226,21 +226,3 @@ class Job(AutomatedProperties):
def Uuid(self):
import uuid
return uuid.uuid1()
# Override the property "getters" implementation for the job interface, so a user can query a job while the queue
# is processing items. Originally all the property get methods were this way, but we changed this in
# e53454d6de07de56736303dd2157c3859f6fa848
# Properties
# noinspection PyUnusedLocal
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='ss', out_signature='v')
def Get(self, interface_name, property_name):
# Note: If we get an exception in this handler we won't know about it,
# only the side effect of no returned value!
return AutomatedProperties._get_prop(self, interface_name, property_name)
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='s', out_signature='a{sv}')
def GetAll(self, interface_name):
return AutomatedProperties._get_all_prop(self, interface_name)

View File

@ -42,7 +42,7 @@ def common(retrieve, o_type, search_keys,
existing_paths = cfg.om.object_paths_by_type(o_type)
for o in objects:
# Assume we need to add this one to dbus, unless we are refreshing,
# Assume we need to add this one to dbus, unless we are refreshing
# and it's already present
return_object = True

View File

@ -10,7 +10,7 @@
from .automatedproperties import AutomatedProperties
from . import utils
from .utils import vg_obj_path_generate, log_error, _handle_execute, LvmBug
from .utils import vg_obj_path_generate, log_error, _handle_execute
import dbus
from . import cmdhandler
from . import cfg
@ -21,12 +21,14 @@ from .utils import n, n32, d
from .loader import common
from .state import State
from . import background
from .utils import round_size, mt_remove_dbus_objects, lvm_column_key
from .utils import round_size, mt_remove_dbus_objects
from .job import JobState
import traceback
# Try and build a key for a LV, so that we sort the LVs with the least dependencies
# first. This may be error-prone because of the flexibility LVM
# Try and build a key for a LV, so that we sort the LVs with least dependencies
# first. This may be error prone because of the flexibility LVM
# provides and what you can stack.
def get_key(i):
@ -65,80 +67,73 @@ def lvs_state_retrieve(selection, cache_refresh=True):
if cache_refresh:
cfg.db.refresh()
try:
# When building up the model, it's best to process LVs with the least
# dependencies to those that are dependant upon other LVs. Otherwise, when
# we are trying to gather information we could be in a position where we
# don't have information available yet.
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
# When building up the model, it's best to process LVs with the least
# dependencies to those that are dependant upon other LVs. Otherwise, when
# we are trying to gather information we could be in a position where we
# don't have information available yet.
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
for l in lvs:
if cfg.vdo_support:
rc.append(LvStateVdo(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid'],
l['vdo_operating_mode'],
l['vdo_compression_state'],
l['vdo_index_state'],
n(l['vdo_used_size']),
d(l['vdo_saving_percent']),
l['vdo_compression'],
l['vdo_deduplication'],
l['vdo_use_metadata_hints'],
n32(l['vdo_minimum_io_size']),
n(l['vdo_block_map_cache_size']),
n32(l['vdo_block_map_era_length']),
l['vdo_use_sparse_index'],
n(l['vdo_index_memory_size']),
n(l['vdo_slab_size']),
n32(l['vdo_ack_threads']),
n32(l['vdo_bio_threads']),
n32(l['vdo_bio_rotation']),
n32(l['vdo_cpu_threads']),
n32(l['vdo_hash_zone_threads']),
n32(l['vdo_logical_threads']),
n32(l['vdo_physical_threads']),
n32(l['vdo_max_discard']),
l['vdo_write_policy'],
n32(l['vdo_header_size'])))
else:
rc.append(LvState(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid']))
except KeyError as ke:
# Sometimes lvm omits returning one of the keys we requested.
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
for l in lvs:
if cfg.vdo_support:
rc.append(LvStateVdo(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid'],
l['vdo_operating_mode'],
l['vdo_compression_state'],
l['vdo_index_state'],
n(l['vdo_used_size']),
d(l['vdo_saving_percent']),
l['vdo_compression'],
l['vdo_deduplication'],
l['vdo_use_metadata_hints'],
n32(l['vdo_minimum_io_size']),
n(l['vdo_block_map_cache_size']),
n32(l['vdo_block_map_era_length']),
l['vdo_use_sparse_index'],
n(l['vdo_index_memory_size']),
n(l['vdo_slab_size']),
n32(l['vdo_ack_threads']),
n32(l['vdo_bio_threads']),
n32(l['vdo_bio_rotation']),
n32(l['vdo_cpu_threads']),
n32(l['vdo_hash_zone_threads']),
n32(l['vdo_logical_threads']),
n32(l['vdo_physical_threads']),
n32(l['vdo_max_discard']),
l['vdo_write_policy'],
n32(l['vdo_header_size'])))
else:
rc.append(LvState(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid']))
return rc
@ -279,15 +274,15 @@ class LvStateVdo(LvState):
MetaDataPercent, CopyPercent, SyncPercent,
MetaDataSizeBytes, move_pv, move_pv_uuid,
vdo_operating_mode, vdo_compression_state, vdo_index_state,
vdo_used_size, vdo_saving_percent, vdo_compression,
vdo_deduplication, vdo_use_metadata_hints,
vdo_minimum_io_size, vdo_block_map_cache_size,
vdo_block_map_era_length, vdo_use_sparse_index,
vdo_index_memory_size, vdo_slab_size, vdo_ack_threads,
vdo_bio_threads, vdo_bio_rotation, vdo_cpu_threads,
vdo_hash_zone_threads, vdo_logical_threads,
vdo_physical_threads, vdo_max_discard,
vdo_write_policy, vdo_header_size):
vdo_used_size,vdo_saving_percent,vdo_compression,
vdo_deduplication,vdo_use_metadata_hints,
vdo_minimum_io_size,vdo_block_map_cache_size,
vdo_block_map_era_length,vdo_use_sparse_index,
vdo_index_memory_size,vdo_slab_size,vdo_ack_threads,
vdo_bio_threads,vdo_bio_rotation,vdo_cpu_threads,
vdo_hash_zone_threads,vdo_logical_threads,
vdo_physical_threads,vdo_max_discard,
vdo_write_policy,vdo_header_size):
super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
@ -376,8 +371,8 @@ class LvCommon(AutomatedProperties):
return dbus.Struct((self.state.Attr[index],
type_map.get(self.state.Attr[index], default)),
signature="(ss)")
except BaseException as b:
st = utils.extract_stack_trace(b)
except BaseException:
st = traceback.format_exc()
log_error("attr_struct: \n%s" % st)
return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
@ -600,7 +595,7 @@ class Lv(LvCommon):
optional_size = space + 512 - remainder
LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
lv_name, snapshot_options, name, optional_size))
lv_name, snapshot_options,name, optional_size))
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
return cfg.om.get_object_path_by_lvm_id(full_name)
@ -640,7 +635,7 @@ class Lv(LvCommon):
size_change = new_size_bytes - dbo.SizeBytes
LvCommon.handle_execute(*cmdhandler.lv_resize(
dbo.lvm_id, size_change, pv_dests, resize_options))
dbo.lvm_id, size_change,pv_dests, resize_options))
return "/"
@dbus.service.method(
@ -749,7 +744,7 @@ class Lv(LvCommon):
cfg.worker_q.put(r)
@staticmethod
def _caching_common(method, lv_uuid, lv_name, lv_object_path, cache_options):
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
# Make sure we have a dbus object representing it
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
@ -758,7 +753,7 @@ class Lv(LvCommon):
if lv_to_cache:
fcn = lv_to_cache.lv_full_name()
rc, out, err = method(
rc, out, err = cmdhandler.lv_writecache_lv(
dbo.lv_full_name(), fcn, cache_options)
if rc == 0:
# When we cache an LV, the cache pool and the lv that is getting
@ -775,14 +770,9 @@ class Lv(LvCommon):
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE, 'LV to cache with object path %s not present!' %
lv_object_path)
lv_object_path)
return lv_converted
@staticmethod
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
return Lv._caching_common(cmdhandler.lv_writecache_lv, lv_uuid,
lv_name, lv_object_path, cache_options)
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='oia{sv}',
@ -855,10 +845,10 @@ class LvVdoPool(Lv):
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def DisableCompression(self, tmo, comp_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_compression,
@ -888,10 +878,10 @@ class LvVdoPool(Lv):
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_deduplication,
@ -962,8 +952,33 @@ class LvCachePool(Lv):
@staticmethod
def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
return Lv._caching_common(cmdhandler.lv_cache_lv, lv_uuid, lv_name,
lv_object_path, cache_options)
# Make sure we have a dbus object representing cache pool
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
# Make sure we have dbus object representing lv to cache
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
if lv_to_cache:
fcn = lv_to_cache.lv_full_name()
rc, out, err = cmdhandler.lv_cache_lv(
dbo.lv_full_name(), fcn, cache_options)
if rc == 0:
# When we cache an LV, the cache pool and the lv that is getting
# cached need to be removed from the object manager and
# re-created as their interfaces have changed!
mt_remove_dbus_objects((dbo, lv_to_cache))
cfg.load()
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE, 'LV to cache with object path %s not present!' %
lv_object_path)
return lv_converted
@dbus.service.method(
dbus_interface=CACHE_POOL_INTERFACE,

View File

@ -14,12 +14,12 @@
import subprocess
import shlex
import os
import pty
import traceback
import sys
import tempfile
import time
import threading
import select
import copy
try:
import simplejson as json
@ -27,9 +27,9 @@ except ImportError:
import json
import lvmdbusd.cfg as cfg
from lvmdbusd.cfg import LVM_CMD
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
read_decoded, extract_stack_trace, LvmBug, get_error_msg
read_decoded
SHELL_PROMPT = "lvm> "
@ -43,11 +43,10 @@ def _quote_arg(arg):
class LVMShellProxy(object):
# Read REPORT FD until we have a complete and valid JSON record or give
# up trying to get one.
#
# Returns stdout, report (JSON), stderr
def _read_response(self, no_output=False):
# Read until we get prompt back and a result
# @param: no_output Caller expects no output to report FD
# Returns stdout, report, stderr (report is JSON!)
def _read_until_prompt(self, no_output=False):
stdout = ""
report = ""
stderr = ""
@ -59,27 +58,24 @@ class LVMShellProxy(object):
# Try reading from all FDs to prevent one from filling up and causing
# a hang. Keep reading until we get the prompt back and the report
# FD does not contain valid JSON
while keep_reading and cfg.run.value != 0:
while keep_reading:
try:
rd_fd = [
self.parent_stdout_fd,
self.lvm_shell.stdout.fileno(),
self.report_stream.fileno(),
self.parent_stderr_fd]
self.lvm_shell.stderr.fileno()]
ready = select.select(rd_fd, [], [], 2)
for r in ready[0]:
if r == self.parent_stdout_fd:
for line in self.parent_stdout.readlines():
stdout += line
if r == self.lvm_shell.stdout.fileno():
stdout += read_decoded(self.lvm_shell.stdout)
elif r == self.report_stream.fileno():
report += read_decoded(self.report_stream)
elif r == self.parent_stderr_fd:
for line in self.parent_stderr.readlines():
stderr += line
elif r == self.lvm_shell.stderr.fileno():
stderr += read_decoded(self.lvm_shell.stderr)
# Check to see if the lvm process died on us
if self.lvm_shell.poll() is not None:
if self.lvm_shell.poll():
raise Exception(self.lvm_shell.returncode, "%s" % stderr)
if stdout.endswith(SHELL_PROMPT):
@ -103,106 +99,91 @@ class LVMShellProxy(object):
extra_passes -= 1
if extra_passes <= 0:
if len(report):
raise LvmBug("Invalid json: %s" %
raise ValueError("Invalid json: %s" %
report)
else:
raise LvmBug(
raise ValueError(
"lvm returned no JSON output!")
except Exception as e:
log_error("While reading from lvm shell we encountered an error %s" % str(e))
log_error("stdout= %s\nstderr= %s\n" % (stdout, stderr))
if self.lvm_shell.poll() is not None:
log_error("Underlying lvm shell process unexpectedly exited: %d" % self.lvm_shell.returncode)
else:
log_error("Underlying lvm shell process is still present!")
raise e
if keep_reading and cfg.run.value == 0:
# We didn't complete as we are shutting down
# Try to clean up lvm shell process
log_debug("exiting lvm shell as we are shutting down")
self.exit_shell()
raise SystemExit
except IOError as ioe:
log_debug(str(ioe))
pass
return stdout, report_json, stderr
def _write_cmd(self, cmd):
self.parent_stdin.write(cmd)
self.parent_stdin.flush()
cmd_bytes = bytes(cmd, "utf-8")
num_written = self.lvm_shell.stdin.write(cmd_bytes)
assert (num_written == len(cmd_bytes))
self.lvm_shell.stdin.flush()
def __init__(self):
# Create a temp directory
tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
tmp_file = "%s/lvmdbus_report" % (tmp_dir)
# Create a lock so that we don't step on each other when we are waiting for a command
# to finish and some other request comes in concurrently, like to exit the shell.
self.shell_lock = threading.RLock()
try:
# Lets create fifo for the report output
os.mkfifo(tmp_file, 0o600)
except FileExistsError:
pass
# Create a fifo for the report output
os.mkfifo(tmp_file, 0o600)
# Open the fifo for use to read and for lvm child process to write to.
# We have to open non-blocking as the other side isn't open until
# we actually fork the process.
self.report_fd = os.open(tmp_file, os.O_NONBLOCK)
self.report_stream = os.fdopen(self.report_fd, 'rb', 0)
lvm_fd = os.open(tmp_file, os.O_WRONLY)
# Set up the environment for using our own socket for reporting and disable the abort
# logic if lvm logs too much, which easily happens when utilizing the lvm shell.
local_env = {"LC_ALL": "C", "LVM_REPORT_FD": "%s" % lvm_fd, "LVM_COMMAND_PROFILE": "lvmdbusd",
"LVM_LOG_FILE_MAX_LINES": "0"}
# Setup the environment for using our own socket for reporting
local_env = copy.deepcopy(os.environ)
local_env["LVM_REPORT_FD"] = "32"
local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd"
# If any env variables contain LVM we will propagate them too
for k, v in os.environ.items():
if "PATH" in k:
local_env[k] = v
if "LVM" in k:
local_env[k] = v
self.parent_stdin_fd, child_stdin_fd = pty.openpty()
self.parent_stdout_fd, child_stdout_fd = pty.openpty()
self.parent_stderr_fd, child_stderr_fd = pty.openpty()
self.parent_stdin = os.fdopen(self.parent_stdin_fd, "w")
self.parent_stdout = os.fdopen(self.parent_stdout_fd, "r")
self.parent_stderr = os.fdopen(self.parent_stderr_fd, "r")
# Disable the abort logic if lvm logs too much, which easily happens
# when utilizing the lvm shell.
local_env["LVM_LOG_FILE_MAX_LINES"] = "0"
# run the lvm shell
self.lvm_shell = subprocess.Popen(
[cfg.LVM_CMD],
stdin=child_stdin_fd,
stdout=child_stdout_fd, env=local_env,
stderr=child_stderr_fd, close_fds=True,
pass_fds=(lvm_fd,), shell=False)
[LVM_CMD + " 32>%s" % tmp_file],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env,
stderr=subprocess.PIPE, close_fds=True, shell=True)
try:
make_non_block(self.parent_stdout_fd)
make_non_block(self.parent_stderr_fd)
# Close our copies of the child FDs there were created with the fork, we don't need them open.
os.close(lvm_fd)
os.close(child_stdin_fd)
os.close(child_stdout_fd)
os.close(child_stderr_fd)
make_non_block(self.lvm_shell.stdout)
make_non_block(self.lvm_shell.stderr)
# wait for the first prompt
log_debug("waiting for first prompt...")
errors = self._read_response(no_output=True)[2]
errors = self._read_until_prompt(no_output=True)[2]
if errors and len(errors):
raise LvmBug(errors)
log_debug("lvm prompt read!!!")
raise RuntimeError(errors)
except:
raise
finally:
# These will get deleted when the FD count goes to zero, so we
# These will get deleted when the FD count goes to zero so we
# can be sure to clean up correctly no matter how we finish
os.unlink(tmp_file)
os.rmdir(tmp_dir)
def _get_last_log(self):
# Precondition, lock is held
def get_error_msg(self):
# We got an error, lets go fetch the error message
self._write_cmd('lastlog\n')
report_json = self._read_response()[1]
return get_error_msg(report_json)
# read everything from the STDOUT to the next prompt
stdout, report_json, stderr = self._read_until_prompt()
if 'log' in report_json:
error_msg = ""
# Walk the entire log array and build an error string
for log_entry in report_json['log']:
if log_entry['log_type'] == "error":
if error_msg:
error_msg += ', ' + log_entry['log_message']
else:
error_msg = log_entry['log_message']
return error_msg
return 'No error reason provided! (missing "log" section)'
def call_lvm(self, argv, debug=False):
rc = 1
@ -220,94 +201,60 @@ class LVMShellProxy(object):
cmd += "\n"
# run the command by writing it to the shell's STDIN
with self.shell_lock:
self._write_cmd(cmd)
self._write_cmd(cmd)
# read everything from the STDOUT to the next prompt
stdout, report_json, stderr = self._read_response()
# read everything from the STDOUT to the next prompt
stdout, report_json, stderr = self._read_until_prompt()
# Parse the report to see what happened
if 'log' in report_json:
ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
# If we have an exported vg we get a log_ret_code == 5 when
# we do a 'fullreport'
# Note: 0 == error
if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
rc = 0
else:
# Depending on where lvm fails the command, it may not have anything
# to report for "lastlog", so we need to check for a message in the
# report json too.
error_msg = self._get_last_log()
if error_msg is None:
error_msg = get_error_msg(report_json)
if error_msg is None:
error_msg = 'No error reason provided! (missing "log" section)'
# Parse the report to see what happened
if 'log' in report_json:
ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
# If we have an exported vg we get a log_ret_code == 5 when
# we do a 'fullreport'
if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
rc = 0
else:
error_msg = self.get_error_msg()
if debug or rc != 0:
log_error(("CMD= %s" % cmd))
log_error(("EC= %d" % rc))
log_error(('CMD: %s' % cmd))
log_error(("EC = %d" % rc))
log_error(("ERROR_MSG=\n %s\n" % error_msg))
return rc, report_json, error_msg
def exit_shell(self):
with self.shell_lock:
try:
if self.lvm_shell is not None:
self._write_cmd('exit\n')
self.lvm_shell.wait(1)
self.lvm_shell = None
except Exception as _e:
log_error("exit_shell: %s" % (str(_e)))
try:
self._write_cmd('exit\n')
except Exception as e:
log_error(str(e))
def __del__(self):
# Note: When we are shutting down the daemon and the main process has already exited
# and this gets called we have a limited set of things we can do, like we cannot call
# log_error as _common_log is None!!!
if self.lvm_shell is not None:
try:
self.lvm_shell.wait(1)
except subprocess.TimeoutExpired:
print("lvm shell child process did not exit as instructed, sending SIGTERM")
cfg.ignore_sigterm = True
self.lvm_shell.terminate()
child_exit_code = self.lvm_shell.wait(1)
print("lvm shell process exited with %d" % child_exit_code)
try:
self.lvm_shell.terminate()
except:
pass
if __name__ == "__main__":
print("USING LVM BINARY: %s " % cfg.LVM_CMD)
shell = LVMShellProxy()
in_line = "start"
try:
if len(sys.argv) > 1 and sys.argv[1] == "bisect":
shell = LVMShellProxy()
shell.exit_shell()
else:
shell = LVMShellProxy()
in_line = "start"
try:
while in_line:
in_line = input("lvm> ")
if in_line:
if in_line == "exit":
shell.exit_shell()
sys.exit(0)
start = time.time()
ret, out, err = shell.call_lvm(in_line.split())
end = time.time()
while in_line:
in_line = input("lvm> ")
if in_line:
start = time.time()
ret, out, err = shell.call_lvm(in_line.split())
end = time.time()
print(("RC: %d" % ret))
print(("OUT:\n%s" % out))
print(("ERR:\n%s" % err))
print(("RC: %d" % ret))
print(("OUT:\n%s" % out))
print(("ERR:\n%s" % err))
print("Command = %f seconds" % (end - start))
except KeyboardInterrupt:
pass
except EOFError:
pass
except Exception as e:
log_error("main process exiting on exception!\n%s" % extract_stack_trace(e))
sys.exit(1)
sys.exit(0)
print("Command = %f seconds" % (end - start))
except KeyboardInterrupt:
pass
except EOFError:
pass
except Exception:
traceback.print_exc(file=sys.stdout)

View File

@ -13,13 +13,14 @@ from collections import OrderedDict
import pprint as prettyprint
import os
import sys
from lvmdbusd import cmdhandler
from lvmdbusd.utils import log_debug, log_error, lvm_column_key, LvmBug
from lvmdbusd.utils import log_debug, log_error
class DataStore(object):
def __init__(self, vdo_support=False):
def __init__(self, usejson=True, vdo_support=False):
self.pvs = {}
self.vgs = {}
self.lvs = {}
@ -34,9 +35,41 @@ class DataStore(object):
self.lvs_in_vgs = {}
self.pvs_in_vgs = {}
# self.refresh()
self.num_refreshes = 0
if usejson:
self.json = cmdhandler.supports_json()
else:
self.json = usejson
self.vdo_support = vdo_support
@staticmethod
def _insert_record(table, key, record, allowed_multiple):
if key in table:
existing = table[key]
for rec_k, rec_v in record.items():
if rec_k in allowed_multiple:
# This column name allows us to store multiple value for
# each type
if not isinstance(existing[rec_k], list):
existing_value = existing[rec_k]
existing[rec_k] = [existing_value, rec_v]
else:
existing[rec_k].append(rec_v)
else:
# If something is not expected to have changing values
# lets ensure that
if existing[rec_k] != rec_v:
raise RuntimeError(
"existing[%s]=%s != %s" %
(rec_k, str(existing[rec_k]),
str(rec_v)))
else:
table[key] = record
@staticmethod
def _pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup):
for p in c_pvs.values():
@ -51,6 +84,22 @@ class DataStore(object):
# Lookup for translating between /dev/<name> and pv uuid
c_lookup[p['pv_name']] = p['pv_uuid']
@staticmethod
def _parse_pvs(_pvs):
pvs = sorted(_pvs, key=lambda pk: pk['pv_name'])
c_pvs = OrderedDict()
c_lookup = {}
c_pvs_in_vgs = {}
for p in pvs:
DataStore._insert_record(
c_pvs, p['pv_uuid'], p,
['pvseg_start', 'pvseg_size', 'segtype'])
DataStore._pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup)
return c_pvs, c_lookup, c_pvs_in_vgs
@staticmethod
def _parse_pvs_json(_all):
@ -58,7 +107,7 @@ class DataStore(object):
c_lookup = {}
c_pvs_in_vgs = {}
# Each item in the report is a collection of information pertaining
# Each item item in the report is a collection of information pertaining
# to the vg
for r in _all['report']:
tmp_pv = []
@ -92,6 +141,28 @@ class DataStore(object):
return c_pvs, c_lookup, c_pvs_in_vgs
@staticmethod
def _parse_vgs(_vgs):
vgs = sorted(_vgs, key=lambda vk: vk['vg_uuid'])
c_vgs = OrderedDict()
c_lookup = {}
for i in vgs:
vg_name = i['vg_name']
# Lvm allows duplicate vg names. When this occurs, each subsequent
# matching VG name will be called vg_name:vg_uuid. Note: ':' is an
# invalid character for lvm VG names
if vg_name in c_lookup:
vg_name = "%s:%s" % (vg_name, i['vg_uuid'])
i['vg_name'] = vg_name
c_lookup[vg_name] = i['vg_uuid']
DataStore._insert_record(c_vgs, i['vg_uuid'], i, [])
return c_vgs, c_lookup
@staticmethod
def _parse_vgs_json(_all):
@ -156,12 +227,28 @@ class DataStore(object):
return c_lvs, c_lvs_in_vgs, c_lvs_hidden, c_lv_full_lookup
@staticmethod
def _parse_lvs(_lvs):
lvs = sorted(_lvs, key=lambda vk: vk['lv_name'])
c_lvs = OrderedDict()
c_lv_full_lookup = OrderedDict()
for i in lvs:
full_name = "%s/%s" % (i['vg_name'], i['lv_name'])
c_lv_full_lookup[full_name] = i['lv_uuid']
DataStore._insert_record(
c_lvs, i['lv_uuid'], i,
['seg_pe_ranges', 'segtype'])
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
def _parse_lvs_json(self, _all):
c_lvs = OrderedDict()
c_lv_full_lookup = {}
# Each item in the report is a collection of information pertaining
# Each item item in the report is a collection of information pertaining
# to the vg
for r in _all['report']:
# Get the lv data for this VG.
@ -309,12 +396,12 @@ class DataStore(object):
:param log Add debug log entry/exit messages
:return: None
"""
try:
self.num_refreshes += 1
if log:
log_debug("lvmdb - refresh entry")
self.num_refreshes += 1
if log:
log_debug("lvmdb - refresh entry")
# Grab everything first then parse it
# Grab everything first then parse it
if self.json:
# Do a single lvm retrieve for everything in json
a = cmdhandler.lvm_full_report_json()
@ -322,25 +409,29 @@ class DataStore(object):
_vgs, _vgs_lookup = self._parse_vgs_json(a)
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs_json(a)
# Set all
self.pvs = _pvs
self.pv_path_to_uuid = _pvs_lookup
self.vg_name_to_uuid = _vgs_lookup
self.lv_full_name_to_uuid = _lvs_lookup
else:
_raw_pvs = cmdhandler.pv_retrieve_with_segs()
_raw_vgs = cmdhandler.vg_retrieve(None)
_raw_lvs = cmdhandler.lv_retrieve_with_segments()
self.vgs = _vgs
self.lvs = _lvs
self.lvs_in_vgs = _lvs_in_vgs
self.pvs_in_vgs = _pvs_in_vgs
self.lvs_hidden = _lvs_hidden
_pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs(_raw_pvs)
_vgs, _vgs_lookup = self._parse_vgs(_raw_vgs)
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs(_raw_lvs)
# Create lookup table for which LV and segments are on each PV
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
except KeyError as ke:
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
# Set all
self.pvs = _pvs
self.pv_path_to_uuid = _pvs_lookup
self.vg_name_to_uuid = _vgs_lookup
self.lv_full_name_to_uuid = _lvs_lookup
self.vgs = _vgs
self.lvs = _lvs
self.lvs_in_vgs = _lvs_in_vgs
self.pvs_in_vgs = _pvs_in_vgs
self.lvs_hidden = _lvs_hidden
# Create lookup table for which LV and segments are on each PV
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
if log:
log_debug("lvmdb - refresh exit")
@ -360,13 +451,10 @@ class DataStore(object):
return rc
def pv_missing(self, pv_uuid):
# The uuid might not be a PV, default to false
if pv_uuid in self.pvs:
if self.pvs[pv_uuid]['pv_missing'] == '':
return False
else:
return True
return False
return True
def fetch_vgs(self, vg_name):
if not vg_name:
@ -437,11 +525,15 @@ class DataStore(object):
if __name__ == "__main__":
os.environ["LC_ALL"] = "C"
os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
pp = prettyprint.PrettyPrinter(indent=4)
ds = DataStore()
use_json = False
if len(sys.argv) != 1:
print(len(sys.argv))
use_json = True
ds = DataStore(use_json)
ds.refresh()
print("PVS")

View File

@ -22,13 +22,14 @@ from . import lvmdb
from gi.repository import GLib
from .fetch import StateUpdate
from .manager import Manager
import traceback
import queue
from . import udevwatch
from .utils import log_debug, log_error, log_msg, DebugMessages
from .utils import log_debug, log_error
import argparse
import os
import sys
from .cmdhandler import LvmFlightRecorder, supports_vdo, supports_json
from .cmdhandler import LvmFlightRecorder, supports_vdo
from .request import RequestEntry
@ -49,15 +50,12 @@ def process_request():
log_debug("Method complete: %s" % str(req.method))
except queue.Empty:
pass
except SystemExit:
break
except Exception as e:
st = utils.extract_stack_trace(e)
except Exception:
st = traceback.format_exc()
utils.log_error("process_request exception: \n%s" % st)
log_debug("process_request thread exiting!")
def check_fr_size(value):
def check_bb_size(value):
v = int(value)
if v < 0:
raise argparse.ArgumentTypeError(
@ -67,7 +65,7 @@ def check_fr_size(value):
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
# apparently not usable and we need to use the glib calls instead
signal_add = None
if hasattr(GLib, 'unix_signal_add'):
@ -79,13 +77,13 @@ def install_signal_handlers():
signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP, utils.handler, signal.SIGHUP)
signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, utils.handler, signal.SIGINT)
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR1, utils.handler, signal.SIGUSR1)
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR2, utils.handler, signal.SIGUSR2)
signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, utils.handler, signal.SIGTERM)
else:
log_error("GLib.unix_signal_[add|add_full] are NOT available!")
def process_args():
def main():
start = time.time()
# Add simple command line handling
parser = argparse.ArgumentParser()
parser.add_argument(
"--udev", action='store_true',
@ -106,137 +104,101 @@ def process_args():
default=False,
dest='use_lvm_shell')
parser.add_argument(
"--frsize",
help="Size of the flight recorder (num. entries), 0 to disable (signal 12 to dump)",
"--blackboxsize",
help="Size of the black box flight recorder, 0 to disable",
default=10,
type=check_fr_size,
dest='fr_size')
type=check_bb_size,
dest='bb_size')
args = parser.parse_args()
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
if not args.use_json:
log_error("Daemon no longer supports lvm without JSON support, exiting!")
sys.exit(1)
else:
if not supports_json():
log_error("Un-supported version of LVM, daemon requires JSON output, exiting!")
sys.exit(1)
# Add udev watching
if args.use_udev:
# Make sure this msg ends up in the journal, so we know
log_msg('The --udev option is no longer supported,'
'the daemon always uses a combination of dbus notify from lvm tools and udev')
return args
def running_under_systemd():
""""
Checks to see if we are running under systemd, by checking damon fd 0, 1
systemd sets stdin to /dev/null and 1 & 2 are a socket
"""
base = "/proc/self/fd"
stdout = os.readlink("%s/0" % base)
if stdout == "/dev/null":
stdout = os.readlink("%s/1" % base)
if "socket" in stdout:
return True
return False
def main():
start = time.time()
use_session = os.getenv('LVM_DBUSD_USE_SESSION', False)
# Ensure that we get consistent output for parsing stdout/stderr and that we
# are using the lvmdbusd profile.
# Ensure that we get consistent output for parsing stdout/stderr
os.environ["LC_ALL"] = "C"
os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
# Indicator if we are running under systemd
cfg.systemd = running_under_systemd()
# Add simple command line handling
cfg.args = process_args()
cfg.args = parser.parse_args()
cfg.create_request_entry = RequestEntry
# We create a flight recorder in cmdhandler too, but we replace it here
# as the user may be specifying a different size. The default one in
# cmdhandler is for when we are running other code with a different main.
cfg.flightrecorder = LvmFlightRecorder(cfg.args.fr_size)
cfg.blackbox = LvmFlightRecorder(cfg.args.bb_size)
# Create a circular buffer for debug logs
cfg.debug = DebugMessages()
log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
if cfg.args.use_lvm_shell and not cfg.args.use_json:
log_error("You cannot specify --lvmshell and --nojson")
sys.exit(1)
# We will dynamically add interfaces which support vdo if it
# exists.
cfg.vdo_support = supports_vdo()
if cfg.vdo_support and not cfg.args.use_json:
log_error("You cannot specify --nojson when lvm has VDO support")
sys.exit(1)
# List of threads that we start up
thread_list = []
install_signal_handlers()
with utils.LockFile(cfg.LOCK_FILE):
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
dbus.mainloop.glib.threads_init()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
dbus.mainloop.glib.threads_init()
cmdhandler.set_execution(cfg.args.use_lvm_shell)
cmdhandler.set_execution(cfg.args.use_lvm_shell)
if use_session:
cfg.bus = dbus.SessionBus()
else:
cfg.bus = dbus.SystemBus()
# The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal
base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
cfg.om = Lvm(BASE_OBJ_PATH)
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
if use_session:
cfg.bus = dbus.SessionBus()
else:
cfg.bus = dbus.SystemBus()
# The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal
base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
cfg.om = Lvm(BASE_OBJ_PATH)
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
cfg.db = lvmdb.DataStore(vdo_support=cfg.vdo_support)
cfg.db = lvmdb.DataStore(cfg.args.use_json, cfg.vdo_support)
# Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface
thread_list.append(
threading.Thread(target=process_request, name='process_request'))
# Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface
thread_list.append(
threading.Thread(target=process_request, name='process_request'))
# Have a single thread handling updating lvm and the dbus model, so we
# don't have multiple threads doing this as the same time
updater = StateUpdate()
thread_list.append(updater.thread)
# Have a single thread handling updating lvm and the dbus model so we
# don't have multiple threads doing this as the same time
updater = StateUpdate()
thread_list.append(updater.thread)
cfg.load = updater.load
cfg.load = updater.load
cfg.loop = GLib.MainLoop()
cfg.loop = GLib.MainLoop()
for thread in thread_list:
thread.damon = True
thread.start()
for thread in thread_list:
thread.damon = True
thread.start()
# In all cases we are going to monitor for udev until we get an
# ExternalEvent. In the case where we get an external event and the user
# didn't specify --udev we will stop monitoring udev
udevwatch.add()
# Add udev watching
if cfg.args.use_udev:
log_debug('Utilizing udev to trigger updates')
end = time.time()
log_debug(
'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
# In all cases we are going to monitor for udev until we get an
# ExternalEvent. In the case where we get an external event and the user
# didn't specify --udev we will stop monitoring udev
udevwatch.add()
try:
if cfg.run.value != 0:
cfg.loop.run()
udevwatch.remove()
end = time.time()
log_debug(
'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
for thread in thread_list:
thread.join()
except KeyboardInterrupt:
# If we are unable to register signal handler, we will end up here when
# the service gets a ^C or a kill -2 <parent pid>
utils.handler(signal.SIGINT)
try:
if cfg.run.value != 0:
cfg.loop.run()
udevwatch.remove()
for thread in thread_list:
thread.join()
except KeyboardInterrupt:
# If we are unable to register signal handler, we will end up here when
# the service gets a ^C or a kill -2 <parent pid>
utils.handler(signal.SIGINT)
return 0

View File

@ -137,8 +137,7 @@ class Manager(AutomatedProperties):
"""
Dump the flight recorder to syslog
"""
cfg.debug.dump()
cfg.flightrecorder.dump()
cfg.blackbox.dump()
@staticmethod
def _lookup_by_lvm_id(key):
@ -195,7 +194,6 @@ class Manager(AutomatedProperties):
def _external_event(command):
utils.log_debug("Processing _external_event= %s" % command,
'bg_black', 'fg_orange')
cfg.got_external_event = True
cfg.load()
@dbus.service.method(
@ -203,6 +201,14 @@ class Manager(AutomatedProperties):
in_signature='s', out_signature='i')
def ExternalEvent(self, command):
utils.log_debug("ExternalEvent %s" % command)
# If a user didn't explicitly specify udev, we will turn it off now.
if not cfg.args.use_udev:
if udevwatch.remove():
utils.log_debug("ExternalEvent received, disabling "
"udev monitoring")
# We are dependent on external events now to stay current!
cfg.got_external_event = True
r = RequestEntry(
-1, Manager._external_event, (command,), None, None, False)
cfg.worker_q.put(r)

View File

@ -9,11 +9,12 @@
import sys
import threading
import traceback
import dbus
import os
import copy
from . import cfg
from .utils import log_debug, log_error, extract_stack_trace
from .utils import log_debug, pv_obj_path_generate, log_error
from .automatedproperties import AutomatedProperties
@ -39,8 +40,8 @@ class ObjectManager(AutomatedProperties):
for k, v in list(obj._objects.items()):
path, props = v[0].emit_data()
rc[path] = props
except Exception as e:
log_error("_get_managed_objects exception, bailing: \n%s" % extract_stack_trace(e))
except Exception:
traceback.print_exc(file=sys.stdout)
sys.exit(1)
return rc
@ -52,6 +53,15 @@ class ObjectManager(AutomatedProperties):
(self, ), cb, cbe, False)
cfg.worker_q.put(r)
def locked(self):
"""
If some external code need to run across a number of different
calls into ObjectManager while blocking others they can use this method
to lock others out.
:return:
"""
return ObjectManagerLock(self.rlock)
@dbus.service.signal(
dbus_interface="org.freedesktop.DBus.ObjectManager",
signature='oa{sa{sv}}')
@ -159,7 +169,7 @@ class ObjectManager(AutomatedProperties):
# print('Registering object path %s for %s' %
# (path, dbus_object.lvm_id))
# We want fast access to the object by a number of different ways,
# We want fast access to the object by a number of different ways
# so we use multiple hashs with different keys
self._lookup_add(dbus_object, path, dbus_object.lvm_id,
dbus_object.Uuid)
@ -209,7 +219,7 @@ class ObjectManager(AutomatedProperties):
def get_object_by_lvm_id(self, lvm_id):
"""
Given a lvm identifier, return the object registered for it
Given an lvm identifier, return the object registered for it
:param lvm_id: The lvm identifier
"""
with self.rlock:
@ -220,7 +230,7 @@ class ObjectManager(AutomatedProperties):
def get_object_path_by_lvm_id(self, lvm_id):
"""
Given a lvm identifier, return the object path for it
Given an lvm identifier, return the object path for it
:param lvm_id: The lvm identifier
:return: Object path or '/' if not found
"""
@ -277,7 +287,7 @@ class ObjectManager(AutomatedProperties):
register it with the object manager for the specified uuid & lvm_id.
Note: If path create is not None, uuid and lvm_id cannot be equal
:param uuid: The uuid for the lvm object we are searching for
:param lvm_id: The lvm name (e.g. pv device path, vg name, lv full name)
:param lvm_id: The lvm name (eg. pv device path, vg name, lv full name)
:param path_create: If not None, create the path using this function if
we fail to find the object by uuid or lvm_id.
:returns None if lvm asset not found and path_create == None otherwise
@ -295,17 +305,18 @@ class ObjectManager(AutomatedProperties):
if uuid == lvm_id:
path = self._id_lookup(lvm_id)
else:
# We have an uuid and a lvm_id we can do sanity checks to ensure
# We have a uuid and a lvm_id we can do sanity checks to ensure
# that they are consistent
# If a PV is missing its device path is '[unknown]' or some
# If a PV is missing it's device path is '[unknown]' or some
# other text derivation of unknown. When we find that a PV is
# missing we will clear out the lvm_id as it's not unique
# and thus not useful and harmful for lookups.
if cfg.db.pv_missing(uuid):
# missing we will clear out the lvm_id as it's likely not unique
# and thus not useful and potentially harmful for lookups.
if path_create == pv_obj_path_generate and \
cfg.db.pv_missing(uuid):
lvm_id = None
# Let's check for the uuid first
# Lets check for the uuid first
path = self._id_lookup(uuid)
if path:
# Ensure table lookups are correct
@ -326,3 +337,29 @@ class ObjectManager(AutomatedProperties):
# (uuid, lvm_id, str(path_create), path))
return path
class ObjectManagerLock(object):
"""
The sole purpose of this class is to allow other code the ability to
lock the object manager using a `with` statement, eg.
with cfg.om.locked():
# Do stuff with object manager
This will ensure that the lock is always released (assuming this is done
correctly)
"""
def __init__(self, recursive_lock):
self._lock = recursive_lock
def __enter__(self):
# Acquire lock
self._lock.acquire()
# noinspection PyUnusedLocal
def __exit__(self, e_type, e_value, e_traceback):
# Release lock
self._lock.release()
self._lock = None

View File

@ -14,11 +14,11 @@ import dbus
from .cfg import PV_INTERFACE
from . import cmdhandler
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
lv_object_path_method, _handle_execute, lvm_column_key
lv_object_path_method, _handle_execute
from .loader import common
from .request import RequestEntry
from .state import State
from .utils import round_size, LvmBug
from .utils import round_size
# noinspection PyUnusedLocal
@ -28,23 +28,16 @@ def pvs_state_retrieve(selection, cache_refresh=True):
if cache_refresh:
cfg.db.refresh()
try:
for p in cfg.db.fetch_pvs(selection):
rc.append(
PvState(
p["pv_name"], p["pv_uuid"], p["pv_name"],
p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]),
n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]),
n(p["pv_mda_free"]), int(p["pv_ba_start"]),
n(p["pv_ba_size"]), n(p["pe_start"]),
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
except KeyError as ke:
# Sometimes lvm omits returning one of the keys we requested.
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
for p in cfg.db.fetch_pvs(selection):
rc.append(
PvState(
p["pv_name"], p["pv_uuid"], p["pv_name"],
p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]),
n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]),
n(p["pv_mda_free"]), int(p["pv_ba_start"]),
n(p["pv_ba_size"]), n(p["pe_start"]),
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
return rc

View File

@ -7,13 +7,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import dbus
import threading
# noinspection PyUnresolvedReferences
from gi.repository import GLib
from .job import Job
from . import cfg
from .utils import log_error, mt_async_call, extract_stack_trace
import traceback
from .utils import log_error, mt_async_call
class RequestEntry(object):
@ -71,23 +71,13 @@ class RequestEntry(object):
try:
result = self.method(*self.arguments)
self.register_result(result)
except SystemExit as se:
self.register_error(-1, str(se), se)
raise se
except dbus.exceptions.DBusException as dbe:
# This is an expected error path when something goes awry that
# we handled
self.register_error(-1, str(dbe), dbe)
except Exception as e:
# Use the request entry to return the result as the client may
# have gotten a job by the time we hit an error
# Lets set the exception text as the error message and log the
# exception in the journal for figuring out what went wrong.
cfg.debug.dump()
cfg.flightrecorder.dump()
tb = extract_stack_trace(e)
log_error("While processing %s: we encountered\n%s" % (str(self.method), tb))
log_error("Error returned to client: %s" % str(e))
# Lets get the stacktrace and set that to the error message
st = traceback.format_exc()
cfg.blackbox.dump()
log_error("Exception returned to client: \n%s" % st)
self.register_error(-1, str(e), e)
def is_done(self):
@ -141,7 +131,7 @@ class RequestEntry(object):
mt_async_call(self.cb_error, error_exception)
else:
# We have a job, and it's complete, indicate that it's done.
# We have a job and it's complete, indicate that it's done.
self._job.Complete = True
self._job = None

View File

@ -52,30 +52,20 @@ def filter_event(action, device):
# when appropriate.
refresh = False
# Ignore everything but change
if action != 'change':
return
if 'ID_FS_TYPE' in device:
fs_type_new = device['ID_FS_TYPE']
if 'LVM' in fs_type_new:
# If we get a lvm related udev event for a block device
# we don't know about, it's either a pvcreate which we
# would handle with the dbus notification or something
# copied a pv signature onto a block device, this is
# required to catch the latter.
if not cfg.om.get_object_by_lvm_id(device['DEVNAME']):
refresh = True
refresh = True
elif fs_type_new == '':
# Check to see if the device was one we knew about
if 'DEVNAME' in device:
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
found = cfg.om.get_object_by_lvm_id(device['DEVNAME'])
if found:
refresh = True
else:
# This handles the wipefs -a path
if not refresh and 'DEVNAME' in device:
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
refresh = True
if 'DM_LV_NAME' in device:
refresh = True
if refresh:
udev_add()

View File

@ -10,14 +10,11 @@
import xml.etree.ElementTree as Et
import sys
import inspect
import collections
import errno
import fcntl
import ctypes
import os
import stat
import string
import datetime
import tempfile
from fcntl import fcntl, F_GETFL, F_SETFL
import dbus
from lvmdbusd import cfg
@ -89,7 +86,7 @@ def init_class_from_arguments(
nt = k
# If the current attribute has a value, but the incoming does
# not, don't overwrite it. Otherwise, the default values on the
# not, don't overwrite it. Otherwise the default values on the
# property decorator don't work as expected.
cur = getattr(obj_instance, nt, v)
@ -109,7 +106,7 @@ def init_class_from_arguments(
def get_properties(f):
"""
Walks through an object instance, or it's parent class(es) and determines
Walks through an object instance or it's parent class(es) and determines
which attributes are properties and if they were created to be used for
dbus.
:param f: Object to inspect
@ -193,7 +190,7 @@ def add_properties(xml, interface, props):
interface_element = c
break
# Interface is not present, lets create it, so we have something to
# Interface is not present, lets create it so we have something to
# attach the properties too
if interface_element is None:
interface_element = Et.Element("interface", name=interface)
@ -283,64 +280,25 @@ def parse_tags(tags):
return dbus.Array([], signature='s')
class DebugMessages(object):
def _common_log(msg, *attributes):
cfg.stdout_lock.acquire()
tid = ctypes.CDLL('libc.so.6').syscall(186)
def __init__(self, size=5000):
self.queue = collections.deque(maxlen=size)
self.lock = threading.RLock()
def add(self, message):
with self.lock:
self.queue.append(message)
def dump(self):
if cfg.args and not cfg.args.debug:
with self.lock:
if len(self.queue):
log_error("LVM dbus debug messages START last (%d max) messages" % self.queue.maxlen)
for m in self.queue:
print(m)
log_error("LVM dbus debug messages END")
self.queue.clear()
def _get_tid():
try:
# Only 3.8 and later have this
return threading.get_native_id()
except:
return -1
def _format_log_entry(msg):
tid = _get_tid()
if not cfg.systemd and STDOUT_TTY:
if STDOUT_TTY:
msg = "%s: %d:%d - %s" % \
(datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"),
os.getpid(), tid, msg)
else:
if cfg.systemd:
# Systemd already puts the daemon pid in the log, we'll just add the tid
msg = "[%d]: %s" % (tid, msg)
else:
msg = "[%d:%d]: %s" % (os.getpid(), tid, msg)
return msg
def _common_log(msg, *attributes):
msg = _format_log_entry(msg)
cfg.stdout_lock.acquire()
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
if STDOUT_TTY and attributes:
print(color(msg, *attributes))
else:
print(msg)
sys.stdout.flush()
cfg.stdout_lock.release()
sys.stdout.flush()
# Serializes access to stdout to prevent interleaved output
@ -349,19 +307,12 @@ def _common_log(msg, *attributes):
def log_debug(msg, *attributes):
if cfg.args and cfg.args.debug:
_common_log(msg, *attributes)
else:
if cfg.debug:
cfg.debug.add(_format_log_entry(msg))
def log_error(msg, *attributes):
_common_log(msg, *attributes)
def log_msg(msg, *attributes):
_common_log(msg, *attributes)
def dump_threads_stackframe():
ident_to_name = {}
@ -389,32 +340,15 @@ def dump_threads_stackframe():
# noinspection PyUnusedLocal
def handler(signum):
try:
# signal 10
if signum == signal.SIGUSR1:
cfg.debug.dump()
dump_threads_stackframe()
# signal 12
elif signum == signal.SIGUSR2:
cfg.debug.dump()
cfg.flightrecorder.dump()
else:
# If we are getting a SIGTERM, and we sent one to the lvm shell we
# will ignore this and keep running.
if signum == signal.SIGTERM and cfg.ignore_sigterm:
# Clear the flag, so we will exit on SIGTERM if we didn't
# send it.
cfg.ignore_sigterm = False
return True
# If lvm shell is in use, tell it to exit
if cfg.SHELL_IN_USE is not None:
cfg.SHELL_IN_USE.exit_shell()
cfg.run.value = 0
log_error('Exiting daemon with signal %d' % signum)
log_debug('Exiting daemon with signal %d' % signum)
if cfg.loop is not None:
cfg.loop.quit()
except BaseException as be:
st = extract_stack_trace(be)
except:
st = traceback.format_exc()
log_error("signal handler: exception (logged, not reported!) \n %s" % st)
# It's important we report that we handled the exception for the exception
@ -543,7 +477,7 @@ def round_size(size_bytes):
return size_bytes + bs - remainder
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_/%'
_ALLOWABLE_CH = string.ascii_letters + string.digits + '#+-.:=@_\/%'
_ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
@ -638,23 +572,6 @@ def validate_tag(interface, tag):
% (tag, _ALLOWABLE_TAG_CH))
def add_config_option(cmdline, key, value):
if 'help' in cmdline:
return cmdline
if key in cmdline:
for i, arg in enumerate(cmdline):
if arg == key:
if len(cmdline) <= i + 1:
raise dbus.exceptions.DBusException("Missing value for --config option.")
cmdline[i + 1] += " %s" % value
break
else:
cmdline.extend([key, value])
return cmdline
def add_no_notify(cmdline):
"""
Given a command line to execute we will see if `--config` is present, if it
@ -666,18 +583,27 @@ def add_no_notify(cmdline):
:rtype: list
"""
# Only after we have seen an external event will we disable lvm from sending
# Only after we have seen an external event will be disable lvm from sending
# us one when we call lvm
rv = cmdline
if cfg.got_external_event:
rv = add_config_option(rv, "--config", "global/notify_dbus=0")
if 'help' in cmdline:
return cmdline
return rv
if '--config' in cmdline:
for i, arg in enumerate(cmdline):
if arg == '--config':
if len(cmdline) <= i+1:
raise dbus.exceptions.DBusException("Missing value for --config option.")
cmdline[i+1] += " global/notify_dbus=0"
break
else:
cmdline.extend(['--config', 'global/notify_dbus=0'])
return cmdline
# The methods below which start with mt_* are used to execute the desired code
# on the main thread of execution to alleviate any issues the dbus-python
# library with regard to multithreaded access. Essentially, we are trying to
# on the the main thread of execution to alleviate any issues the dbus-python
# library with regards to multi-threaded access. Essentially, we are trying to
# ensure all dbus library interaction is done from the same thread!
@ -691,8 +617,9 @@ def _async_handler(call_back, parameters):
call_back(*parameters)
else:
call_back()
except BaseException as be:
log_error("mt_async_call: exception (logged, not reported!) \n %s" % extract_stack_trace(be))
except:
st = traceback.format_exc()
log_error("mt_async_call: exception (logged, not reported!) \n %s" % st)
# Execute the function on the main thread with the provided parameters, do
@ -742,6 +669,9 @@ class MThreadRunner(object):
self.rc = self.f()
except BaseException as be:
self.exception = be
st = traceback.format_exc()
log_error("MThreadRunner: exception \n %s" % st)
log_error("Exception will be raised in calling thread!")
def _remove_objects(dbus_objects_rm):
@ -756,8 +686,8 @@ def mt_remove_dbus_objects(objs):
# Make stream non-blocking
def make_non_block(stream):
flags = fcntl.fcntl(stream, fcntl.F_GETFL)
fcntl.fcntl(stream, fcntl.F_SETFL, flags | os.O_NONBLOCK)
flags = fcntl(stream, F_GETFL)
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
def read_decoded(stream):
@ -765,127 +695,3 @@ def read_decoded(stream):
if tmp:
return tmp.decode("utf-8")
return ''
class LockFile(object):
"""
Simple lock file class
Based on Pg.1144 "The Linux Programming Interface" by Michael Kerrisk
"""
def __init__(self, lock_file):
self.fd = 0
self.lock_file = lock_file
def __enter__(self):
try:
self.fd = os.open(self.lock_file, os.O_CREAT | os.O_RDWR, stat.S_IRUSR | stat.S_IWUSR)
# Get and set the close on exec and lock the file
flags = fcntl.fcntl(self.fd, fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(self.fd, fcntl.F_SETFL, flags)
fcntl.lockf(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except OSError as e:
if e.errno == errno.EAGAIN:
log_error("Daemon already running, exiting!")
else:
log_error("Error during creation of lock file(%s): errno(%d), exiting!" % (self.lock_file, e.errno))
sys.exit(114)
def __exit__(self, _type, _value, _traceback):
os.close(self.fd)
def extract_stack_trace(exception):
return ''.join(traceback.format_exception(None, exception, exception.__traceback__))
def lvm_column_key(key):
# Check LV
if key.startswith("lv_") or key.startswith("vg_") or key.startswith("pool_") or \
key.endswith("_percent") or key.startswith("move_") or key.startswith("vdo_") or \
key in ["origin_uuid", "segtype", "origin", "data_lv", "metadata_lv"]:
return True
# Check VG
if key.startswith("vg_") or key.startswith("lv_") or key.startswith("pv_") or \
key in ["max_lv", "max_pv", "snap_count"]:
return True
# Check PV
if key.startswith("pv") or key.startswith("vg") or (key in ['dev_size', 'pe_start']):
return True
return False
class LvmBug(RuntimeError):
"""
Things that are clearly a bug with lvm itself.
"""
def __init__(self, msg):
super().__init__(msg)
def __str__(self):
return "lvm bug encountered: %s" % ' '.join(self.args)
class LvmDebugData:
def __init__(self, do_collection):
self.fd = -1
self.fn = None
self.collect = do_collection
if self.collect:
log_msg("Collecting lvm debug data!")
def _remove_file(self):
if self.fn is not None:
os.unlink(self.fn)
self.fn = None
def _close_fd(self):
if self.fd != -1:
os.close(self.fd)
self.fd = -1
def setup(self):
# Create a secure filename
if self.collect:
self.fd, self.fn = tempfile.mkstemp(suffix=".log", prefix="lvmdbusd.lvm.debug.")
return self.fn
return None
def lvm_complete(self):
# Remove the file ASAP, so we decrease our odds of leaving it
# around if the daemon gets killed by a signal -9
self._remove_file()
def dump(self):
# Read the file and log it to log_err
if self.fd != -1:
# How big could the verbose debug get?
debug = os.read(self.fd, 1024*1024*5)
debug_txt = debug.decode("utf-8")
for line in debug_txt.split("\n"):
log_error("lvm debug >>> %s" % line)
self._close_fd()
# In case lvm_complete doesn't get called.
self._remove_file()
def complete(self):
self._close_fd()
# In case lvm_complete doesn't get called.
self._remove_file()
def get_error_msg(report_json):
# Get the error message from the returned JSON
if 'log' in report_json:
error_msg = ""
# Walk the entire log array and build an error string
for log_entry in report_json['log']:
if log_entry['log_type'] == "error":
if error_msg:
error_msg += ', ' + log_entry['log_message']
else:
error_msg = log_entry['log_message']
return error_msg
return None

View File

@ -20,7 +20,7 @@ from .request import RequestEntry
from .loader import common
from .state import State
from . import background
from .utils import round_size, mt_remove_dbus_objects, LvmBug, lvm_column_key
from .utils import round_size, mt_remove_dbus_objects
from .job import JobState
@ -31,24 +31,17 @@ def vgs_state_retrieve(selection, cache_refresh=True):
if cache_refresh:
cfg.db.refresh()
try:
for v in cfg.db.fetch_vgs(selection):
rc.append(
VgState(
v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
n(v['vg_extent_count']), n(v['vg_free_count']),
v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
n(v['vg_seqno']), n(v['vg_mda_count']),
n(v['vg_mda_free']), n(v['vg_mda_size']),
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
except KeyError as ke:
# Sometimes lvm omits returning one of the keys we requested.
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
for v in cfg.db.fetch_vgs(selection):
rc.append(
VgState(
v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
n(v['vg_extent_count']), n(v['vg_free_count']),
v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
n(v['vg_seqno']), n(v['vg_mda_count']),
n(v['vg_mda_free']), n(v['vg_mda_size']),
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
return rc
@ -151,7 +144,6 @@ class Vg(AutomatedProperties):
_AllocNormal_meta = ('b', VG_INTERFACE)
_AllocAnywhere_meta = ('b', VG_INTERFACE)
_Clustered_meta = ('b', VG_INTERFACE)
_Shared_meta = ('b', VG_INTERFACE)
_Name_meta = ('s', VG_INTERFACE)
# noinspection PyUnusedLocal,PyPep8Naming
@ -786,10 +778,6 @@ class Vg(AutomatedProperties):
def Clustered(self):
return self._attribute(5, 'c')
@property
def Shared(self):
return self._attribute(5, 's')
class VgVdo(Vg):

View File

@ -15,44 +15,45 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
USE_SD_NOTIFY=yes
SOURCES = lvmlockd-core.c
SOURCES2 = lvmlockctl.c
TARGETS = lvmlockd lvmlockctl
include $(top_builddir)/make.tmpl
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
SOURCES += lvmlockd-sanlock.c
CFLAGS += $(LIBSANLOCKCLIENT_CFLAGS)
LOCK_LIBS += $(LIBSANLOCKCLIENT_LIBS)
LOCK_LIBS += -lsanlock_client
endif
ifeq ("@BUILD_LOCKDDLM@", "yes")
SOURCES += lvmlockd-dlm.c
CFLAGS += $(LIBDLM) $(LIBDLMCONTROL_CFLAGS)
# LOCK_LIBS += $(LIBDLM_LIBS) $(LIBDLMCONTROL_LIBS)
LOCK_LIBS += -ldlm_lt $(LIBDLMCONTROL_LIBS)
LOCK_LIBS += -ldlm_lt
LOCK_LIBS += -ldlmcontrol
endif
ifeq ("@BUILD_LOCKDIDM@", "yes")
SOURCES += lvmlockd-idm.c
LOCK_LIBS += $(LIBSEAGATEILM_LIBS) $(BLKID_LIBS)
LOCK_LIBS += -lseagate_ilm -lblkid
endif
SOURCES2 = lvmlockctl.c
TARGETS = lvmlockd lvmlockctl
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
CFLOW_TARGET = lvmlockd
.PHONY: install_lvmlockd install_lvmlockctl
include $(top_builddir)/make.tmpl
CFLAGS += $(EXTRA_EXEC_CFLAGS)
INCLUDES += -I$(top_srcdir)/libdaemon/server
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
ifneq (,$(firstword $(LIBSYSTEMD_LIBS)))
CFLAGS += $(LIBSYSTEMD_CFLAGS) -DUSE_SD_NOTIFY
LIBS += $(LIBSYSTEMD_LIBS)
ifeq ($(USE_SD_NOTIFY),yes)
CFLAGS += $(shell pkg-config --cflags libsystemd) -DUSE_SD_NOTIFY
LIBS += $(shell pkg-config --libs libsystemd)
endif
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)

View File

@ -1279,7 +1279,7 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
* be invalidated. When we need to invalidate the lvmetad
* cache, but don't have a usable r_version from the lvb,
* send lvmetad new_version 0 which causes it to invalidate
* the VG metadata without comparing against the currently
* the VG metdata without comparing against the currently
* cached VG seqno.
*/
@ -3016,7 +3016,9 @@ static int add_lockspace_thread(const char *ls_name,
!alloc_and_copy_pvs_path(&ls2->pvs, &ls->pvs)) {
log_debug("add_lockspace_thread %s fails to allocate pvs", ls->name);
rv = -ENOMEM;
} else if (ls2->thread_stop) {
}
if (ls2->thread_stop) {
log_debug("add_lockspace_thread %s exists and stopping", ls->name);
rv = -EAGAIN;
} else if (!ls2->create_fail && !ls2->create_done) {
@ -4690,12 +4692,9 @@ static int dump_info(int *dump_len)
/*
* clients
* Proper lock order is client_mutex then cl->mutex,
* but cl->mutex is already held so skip client info
* if it would block.
*/
if (pthread_mutex_trylock(&client_mutex))
goto print_ls;
pthread_mutex_lock(&client_mutex);
list_for_each_entry(cl, &client_list, list) {
ret = print_client(cl, "client", pos, len);
if (ret >= len - pos) {
@ -4709,7 +4708,6 @@ static int dump_info(int *dump_len)
if (rv < 0)
return rv;
print_ls:
/*
* lockspaces with their action/resource/lock info
*/
@ -4781,7 +4779,7 @@ static void client_recv_action(struct client *cl)
const char *path;
const char *str;
struct pvs pvs;
char buf[18]; /* "path[%d]\0", %d outputs signed integer so max to 10 bytes */
char buf[17]; /* "path[%d]\0", %d outputs signed integer so max to 10 bytes */
int64_t val;
uint32_t opts = 0;
int result = 0;
@ -5284,7 +5282,7 @@ static int match_dm_uuid(char *dm_uuid, char *lv_lock_uuid)
{
char buf1[64];
char buf2[64];
unsigned i, j;
int i, j;
memset(buf1, 0, sizeof(buf1));
memset(buf2, 0, sizeof(buf2));
@ -5958,18 +5956,7 @@ static void adopt_locks(void)
}
/* Try to purge the orphan locks when lock manager is dlm */
if (lm_support_dlm() && lm_is_running_dlm()) {
list_for_each_entry(ls, &ls_found, list) {
pthread_mutex_lock(&lockspaces_mutex);
ls1 = find_lockspace_name(ls->name);
if (ls1) {
log_debug("ls: %s purge locks", ls->name);
lm_purge_locks_dlm(ls1);
}
pthread_mutex_unlock(&lockspaces_mutex);
}
}
/* FIXME: purge any remaining orphan locks in each rejoined ls? */
if (count_start_fail || count_adopt_fail)
goto fail;
@ -6007,7 +5994,7 @@ static void process_listener(int poll_fd)
return;
if (!(cl = alloc_client())) {
if (close(fd))
if (!close(fd))
log_error("failed to close lockd poll fd");
return;
}
@ -6284,8 +6271,9 @@ int main(int argc, char *argv[])
.daemon_fini = NULL,
.daemon_main = main_loop,
};
daemon_host_id_file = NULL;
static const struct option long_options[] = {
static struct option long_options[] = {
{"help", no_argument, 0, 'h' },
{"version", no_argument, 0, 'V' },
{"test", no_argument, 0, 'T' },
@ -6303,8 +6291,6 @@ int main(int argc, char *argv[])
{0, 0, 0, 0 }
};
daemon_host_id_file = NULL;
while (1) {
int c;
int lm;

View File

@ -220,91 +220,6 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
return 0;
}
#define DLM_COMMS_PATH "/sys/kernel/config/dlm/cluster/comms"
#define LOCK_LINE_MAX 1024
static int get_local_nodeid(void)
{
struct dirent *de;
DIR *ls_dir;
char ls_comms_path[PATH_MAX] = { 0 };
char path[PATH_MAX] = { 0 };
FILE *file;
char line[LOCK_LINE_MAX];
char *str1, *str2;
int rv = -1, val;
snprintf(ls_comms_path, sizeof(ls_comms_path), "%s", DLM_COMMS_PATH);
if (!(ls_dir = opendir(ls_comms_path)))
return -ECONNREFUSED;
while ((de = readdir(ls_dir))) {
if (de->d_name[0] == '.')
continue;
snprintf(path, sizeof(path), "%s/%s/local",
DLM_COMMS_PATH, de->d_name);
if (!(file = fopen(ls_comms_path, "r")))
continue;
str1 = fgets(line, sizeof(line), file);
if (fclose(file))
log_sys_debug("fclose", path);
if (str1) {
rv = sscanf(line, "%d", &val);
if ((rv == 1) && (val == 1 )) {
snprintf(path, sizeof(path), "%s/%s/nodeid",
DLM_COMMS_PATH, de->d_name);
if (!(file = fopen(path, "r")))
continue;
str2 = fgets(line, sizeof(line), file);
if (fclose(file))
log_sys_debug("fclose", path);
if (str2) {
rv = sscanf(line, "%d", &val);
if (rv == 1) {
if (closedir(ls_dir))
log_sys_debug("closedir", ls_comms_path);
return val;
}
}
}
}
}
if (closedir(ls_dir))
log_sys_debug("closedir", ls_comms_path);
return rv;
}
int lm_purge_locks_dlm(struct lockspace *ls)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
int nodeid;
int rv = -1;
if (!lmd || !lmd->dh) {
log_error("purge_locks_dlm %s no dlm_handle_t error", ls->name);
goto fail;
}
nodeid = get_local_nodeid();
if (nodeid < 0) {
log_error("failed to get local nodeid");
goto fail;
}
if (dlm_ls_purge(lmd->dh, nodeid, 0)) {
log_error("purge_locks_dlm %s error", ls->name);
goto fail;
}
rv = 0;
fail:
return rv;
}
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;

View File

@ -363,8 +363,6 @@ void log_level(int level, const char *fmt, ...) __attribute__((format(printf, 2
#define log_debug(fmt, args...) log_level(LOG_DEBUG, fmt, ##args)
#define log_error(fmt, args...) log_level(LOG_ERR, fmt, ##args)
#define log_warn(fmt, args...) log_level(LOG_WARNING, fmt, ##args)
#define log_sys_debug(x, y) \
log_debug("%s: %s failed: %s", y, x, strerror(errno))
struct lockspace *alloc_lockspace(void);
int lockspaces_empty(void);
@ -394,7 +392,6 @@ static inline const char *mode_str(int x)
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_prepare_lockspace_dlm(struct lockspace *ls);
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
int lm_purge_locks_dlm(struct lockspace *ls);
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int adopt);
@ -432,11 +429,6 @@ static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
return -1;
}
static inline int lm_purge_locks_dlm(struct lockspace *ls)
{
return -1;
}
static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
{
return -1;

View File

@ -684,10 +684,10 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
break;
}
if (rv < 0) {
if (rv) {
log_error("clear lv resource area %llu error %d",
(unsigned long long)offset, rv);
return rv;
break;
}
offset += align_size;
}
@ -1576,8 +1576,10 @@ int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
goto out;
rv = sanlock_rem_lockspace(&lms->ss, 0);
if (rv < 0)
if (rv < 0) {
log_error("S %s rem_lockspace_san error %d", ls->name, rv);
return rv;
}
if (free_vg) {
/*

View File

@ -52,7 +52,7 @@ static pthread_key_t key;
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
{
#if defined(_GNU_SOURCE) && defined(STRERROR_R_CHAR_P)
#ifdef _GNU_SOURCE
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;

View File

@ -45,18 +45,18 @@ struct lvmpolld_lv {
* accessing following vars doesn't
* require struct lvmpolld_lv lock
*/
struct lvmpolld_state *ls;
struct lvmpolld_state *const ls;
const enum poll_type type;
const char *lvid;
const char *lvmpolld_id;
const char *devicesfile;
const char *lvname; /* full vg/lv name */
const char *const lvid;
const char *const lvmpolld_id;
const char *const devicesfile;
const char *const lvname; /* full vg/lv name */
const unsigned pdtimeout; /* in seconds */
const char *sinterval;
const char *lvm_system_dir_env;
struct lvmpolld_store *pdst;
const char **cmdargv;
const char **cmdenvp;
const char *const sinterval;
const char *const lvm_system_dir_env;
struct lvmpolld_store *const pdst;
const char *const *cmdargv;
const char *const *cmdenvp;
/* only used by write */
pid_t cmd_pid;
@ -66,7 +66,7 @@ struct lvmpolld_lv {
/* block of shared variables protected by lock */
struct lvmpolld_cmd_stat cmd_state;
unsigned init_rq_count; /* for debugging purposes only */
unsigned init_rq_count; /* for debuging purposes only */
unsigned polling_finished:1; /* no more updates */
unsigned error:1; /* unrecoverable error occured in lvmpolld */
};

View File

@ -1,4 +1,4 @@
# Copyright (C) 2018 - 2022 Red Hat, Inc. All rights reserved.
# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
#
# This file is part of the device-mapper userspace tools.
#
@ -29,7 +29,6 @@ DEVICE_MAPPER_SOURCE=\
device_mapper/regex/parse_rx.c \
device_mapper/regex/ttree.c \
device_mapper/vdo/status.c \
device_mapper/vdo/vdo_reader.c \
device_mapper/vdo/vdo_target.c
DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a

View File

@ -173,16 +173,6 @@ struct dm_names {
char name[];
};
struct dm_active_device {
struct dm_list list;
int major;
int minor;
char *name; /* device name */
uint32_t event_nr; /* valid when DM_DEVICE_LIST_HAS_EVENT_NR is set */
char *uuid; /* valid uuid when DM_DEVICE_LIST_HAS_UUID is set */
};
struct dm_versions {
uint32_t next; /* Offset to next struct from start of this struct */
uint32_t version[3];
@ -220,25 +210,6 @@ const char *dm_task_get_message_response(struct dm_task *dmt);
*/
const char *dm_task_get_name(const struct dm_task *dmt);
struct dm_names *dm_task_get_names(struct dm_task *dmt);
/*
* Retrieve the list of devices and put them into easily accessible
* struct dm_active_device list elements.
* devs_features provides flag-set with used features so it's easy to check
* whether the kernel provides i.e. UUID info together with DM names
*/
#define DM_DEVICE_LIST_HAS_EVENT_NR 1
#define DM_DEVICE_LIST_HAS_UUID 2
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
unsigned *devs_features);
/*
* -1: no idea about uuid (not provided by DM_DEVICE_LIST ioctl)
* 0: uuid not present
* 1: listed and dm_active_device will be set for not NULL pointer
*/
int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
const struct dm_active_device **dev);
/* Release all associated memory with list of active DM devices */
void dm_device_list_destroy(struct dm_list **devs_list);
int dm_task_set_ro(struct dm_task *dmt);
int dm_task_set_newname(struct dm_task *dmt, const char *newname);
@ -982,9 +953,7 @@ struct writecache_settings {
uint32_t fua;
uint32_t nofua;
uint32_t cleaner;
uint32_t max_age; /* in milliseconds */
uint32_t metadata_only;
uint32_t pause_writeback; /* in milliseconds */
uint32_t max_age;
/*
* Allow an unrecognized key and its val to be passed to the kernel for
@ -1006,8 +975,6 @@ struct writecache_settings {
unsigned nofua_set:1;
unsigned cleaner_set:1;
unsigned max_age_set:1;
unsigned metadata_only_set:1;
unsigned pause_writeback_set:1;
};
int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
@ -1053,7 +1020,6 @@ int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
*/
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
uint64_t size,
uint32_t vdo_version,
const char *vdo_pool_name,
const char *data_uuid,
uint64_t data_size,
@ -1875,7 +1841,6 @@ const void *dm_report_value_cache_get(struct dm_report *rh, const char *name);
#define DM_REPORT_OUTPUT_FIELD_UNQUOTED 0x00000010
#define DM_REPORT_OUTPUT_COLUMNS_AS_ROWS 0x00000020
#define DM_REPORT_OUTPUT_MULTIPLE_TIMES 0x00000040
#define DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS 0x00000080
struct dm_report *dm_report_init(uint32_t *report_types,
const struct dm_report_object_type *types,
@ -1988,8 +1953,7 @@ struct dm_report_group;
typedef enum {
DM_REPORT_GROUP_SINGLE,
DM_REPORT_GROUP_BASIC,
DM_REPORT_GROUP_JSON,
DM_REPORT_GROUP_JSON_STD
DM_REPORT_GROUP_JSON
} dm_report_group_type_t;
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data);
@ -2244,7 +2208,7 @@ struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
int dm_cookie_supported(void);
/*
* Udev synchronization functions.
* Udev synchronisation functions.
*/
void dm_udev_set_sync_support(int sync_with_udev);
int dm_udev_get_sync_support(void);

View File

@ -139,6 +139,7 @@ static char *_align(char *ptr, unsigned int a)
return (char *) (((unsigned long) ptr + agn) & ~agn);
}
#ifdef DM_IOCTLS
static unsigned _kernel_major = 0;
static unsigned _kernel_minor = 0;
static unsigned _kernel_release = 0;
@ -181,9 +182,6 @@ int get_uname_version(unsigned *major, unsigned *minor, unsigned *release)
return 1;
}
#ifdef DM_IOCTLS
/*
* Set number to NULL to populate _dm_bitset - otherwise first
* match is returned.
@ -312,13 +310,8 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
old_umask = umask(DM_CONTROL_NODE_UMASK);
if (mknod(control, S_IFCHR | S_IRUSR | S_IWUSR,
MKDEV(major, minor)) < 0) {
if (errno != EEXIST) {
log_sys_error("mknod", control);
ret = 0;
} else if (_control_exists(control, major, minor) != 1) {
stack; /* Invalid control node created by parallel command ? */
ret = 0;
}
log_sys_error("mknod", control);
ret = 0;
}
umask(old_umask);
(void) dm_prepare_selinux_context(NULL, 0);
@ -404,7 +397,7 @@ static void _close_control_fd(void)
{
if (_control_fd != -1) {
if (close(_control_fd) < 0)
log_sys_debug("close", "_control_fd");
log_sys_error("close", "_control_fd");
_control_fd = -1;
}
}
@ -623,7 +616,8 @@ int dm_check_version(void)
int dm_cookie_supported(void)
{
return (dm_check_version() &&
((_dm_version == 4) ? _dm_version_minor >= 15 : _dm_version > 4));
_dm_version >= 4 &&
_dm_version_minor >= 15);
}
static int _dm_inactive_supported(void)
@ -761,160 +755,6 @@ struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
dmt->dmi.v4->data_start);
}
/*
* Round up the ptr to an 8-byte boundary.
* Follow kernel pattern.
*/
#define ALIGN_MASK 7
static size_t _align_val(size_t val)
{
return (val + ALIGN_MASK) & ~ALIGN_MASK;
}
static void *_align_ptr(void *ptr)
{
return (void *)_align_val((size_t)ptr);
}
static int _check_has_event_nr(void) {
static int _has_event_nr = -1;
if (_has_event_nr < 0)
_has_event_nr = dm_check_version() &&
((_dm_version == 4) ? _dm_version_minor >= 38 : _dm_version > 4);
return _has_event_nr;
}
struct dm_device_list {
struct dm_list list;
unsigned count;
unsigned features;
struct dm_hash_table *uuids;
};
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
unsigned *devs_features)
{
struct dm_names *names, *names1;
struct dm_active_device *dm_dev, *dm_new_dev;
struct dm_device_list *devs;
unsigned next = 0;
uint32_t *event_nr;
char *uuid_ptr;
size_t len;
int cnt = 0;
*devs_list = 0;
*devs_features = 0;
if ((names = dm_task_get_names(dmt)) && names->dev) {
names1 = names;
if (!names->name[0])
cnt = -1; /* -> cnt == 0 when no device is really present */
do {
names1 = (struct dm_names *)((char *) names1 + next);
next = names1->next;
++cnt;
} while (next);
}
if (!(devs = malloc(sizeof(*devs) + (cnt ? cnt * sizeof(*dm_dev) + (char*)names1 - (char*)names + 256 : 0))))
return_0;
dm_list_init(&devs->list);
devs->count = cnt;
devs->uuids = NULL;
if (!cnt) {
/* nothing in the list -> mark all features present */
*devs_features |= (DM_DEVICE_LIST_HAS_EVENT_NR | DM_DEVICE_LIST_HAS_UUID);
goto out; /* nothing else to do */
}
dm_dev = (struct dm_active_device *) (devs + 1);
do {
names = (struct dm_names *)((char *) names + next);
dm_dev->major = MAJOR(names->dev);
dm_dev->minor = MINOR(names->dev);
dm_dev->name = (char*)(dm_dev + 1);
dm_dev->event_nr = 0;
dm_dev->uuid = NULL;
len = strlen(names->name) + 1;
memcpy(dm_dev->name, names->name, len);
dm_new_dev = _align_ptr((char*)(dm_dev + 1) + len);
if (_check_has_event_nr()) {
/* Hash for UUIDs with some more bits to reduce colision count */
if (!devs->uuids && !(devs->uuids = dm_hash_create(cnt * 8))) {
free(devs);
return_0;
}
*devs_features |= DM_DEVICE_LIST_HAS_EVENT_NR;
event_nr = _align_ptr(names->name + len);
dm_dev->event_nr = event_nr[0];
if ((event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
*devs_features |= DM_DEVICE_LIST_HAS_UUID;
uuid_ptr = _align_ptr(event_nr + 2);
dm_dev->uuid = (char*) dm_new_dev;
len = strlen(uuid_ptr) + 1;
dm_new_dev = _align_ptr((char*)dm_new_dev + len);
memcpy(dm_dev->uuid, uuid_ptr, len);
if (!dm_hash_insert(devs->uuids, dm_dev->uuid, dm_dev))
return_0; // FIXME
#if 0
log_debug("Active %s (%s) %d:%d event:%u",
dm_dev->name, dm_dev->uuid,
dm_dev->major, dm_dev->minor, dm_dev->event_nr);
#endif
}
}
dm_list_add(&devs->list, &dm_dev->list);
dm_dev = dm_new_dev;
next = names->next;
} while (next);
out:
*devs_list = (struct dm_list *)devs;
return 1;
}
int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
const struct dm_active_device **dev)
{
struct dm_device_list *devs = (struct dm_device_list *) devs_list;
struct dm_active_device *dm_dev;
if (devs->uuids &&
(dm_dev = dm_hash_lookup(devs->uuids, uuid))) {
if (dev)
*dev = dm_dev;
return 1;
}
return 0;
}
void dm_device_list_destroy(struct dm_list **devs_list)
{
struct dm_device_list *devs = (struct dm_device_list *) *devs_list;
if (devs) {
if (devs->uuids)
dm_hash_destroy(devs->uuids);
free(devs);
*devs_list = NULL;
}
}
struct dm_names *dm_task_get_names(struct dm_task *dmt)
{
return (struct dm_names *) (((char *) dmt->dmi.v4) +
@ -1202,10 +1042,9 @@ static char *_add_target(struct target *t, char *out, char *end)
while (*pt)
if (*pt++ == '\\')
backslash_count++;
len = strlen(t->params) + backslash_count;
len = strlen(t->params) + 1;
if ((out >= end) || (out + len + backslash_count) >= end) {
if ((out >= end) || (out + len + 1) >= end) {
log_error("Ran out of memory building ioctl parameter");
return NULL;
}
@ -1221,8 +1060,8 @@ static char *_add_target(struct target *t, char *out, char *end)
*out++ = '\0';
}
else {
memcpy(out, t->params, len);
out += len + backslash_count;
strcpy(out, t->params);
out += len + 1;
}
/* align next block */
@ -1293,7 +1132,6 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
struct target *t;
struct dm_target_msg *tmsg;
size_t len = sizeof(struct dm_ioctl);
size_t message_len = 0, newname_len = 0, geometry_len = 0;
char *b, *e;
int count = 0;
@ -1354,20 +1192,14 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
return NULL;
}
if (dmt->newname) {
newname_len = strlen(dmt->newname) + 1;
len += newname_len;
}
if (dmt->newname)
len += strlen(dmt->newname) + 1;
if (dmt->message) {
message_len = strlen(dmt->message) + 1;
len += sizeof(struct dm_target_msg) + message_len;
}
if (dmt->message)
len += sizeof(struct dm_target_msg) + strlen(dmt->message) + 1;
if (dmt->geometry) {
geometry_len = strlen(dmt->geometry) + 1;
len += geometry_len;
}
if (dmt->geometry)
len += strlen(dmt->geometry) + 1;
/*
* Give len a minimum size so that we have space to store
@ -1489,16 +1321,16 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
goto_bad;
if (dmt->newname)
memcpy(b, dmt->newname, newname_len);
strcpy(b, dmt->newname);
if (dmt->message) {
tmsg = (struct dm_target_msg *) b;
tmsg->sector = dmt->sector;
memcpy(tmsg->message, dmt->message, message_len);
strcpy(tmsg->message, dmt->message);
}
if (dmt->geometry)
memcpy(b, dmt->geometry, geometry_len);
strcpy(b, dmt->geometry);
return dmi;
@ -1609,7 +1441,8 @@ static int _udev_complete(struct dm_task *dmt)
static int _check_uevent_generated(struct dm_ioctl *dmi)
{
if (!dm_check_version() ||
((_dm_version == 4) ? _dm_version_minor < 17 : _dm_version < 4))
_dm_version < 4 ||
_dm_version_minor < 17)
/* can't check, assume uevent is generated */
return 1;
@ -1620,7 +1453,7 @@ static int _check_uevent_generated(struct dm_ioctl *dmi)
static int _create_and_load_v4(struct dm_task *dmt)
{
struct dm_task *task;
int r, ioctl_errno = 0;
int r;
uint32_t cookie;
/* Use new task struct to create the device */
@ -1646,10 +1479,8 @@ static int _create_and_load_v4(struct dm_task *dmt)
task->cookie_set = dmt->cookie_set;
task->add_node = dmt->add_node;
if (!dm_task_run(task)) {
ioctl_errno = task->ioctl_errno;
if (!dm_task_run(task))
goto_bad;
}
dm_task_destroy(task);
@ -1675,8 +1506,6 @@ static int _create_and_load_v4(struct dm_task *dmt)
task->ima_measurement = dmt->ima_measurement;
r = dm_task_run(task);
if (!r)
ioctl_errno = task->ioctl_errno;
task->head = NULL;
task->tail = NULL;
@ -1723,18 +1552,12 @@ static int _create_and_load_v4(struct dm_task *dmt)
if (!dm_task_run(dmt))
log_error("Failed to revert device creation.");
if (ioctl_errno != 0)
dmt->ioctl_errno = ioctl_errno;
return 0;
bad:
dm_task_destroy(task);
_udev_complete(dmt);
if (ioctl_errno != 0)
dmt->ioctl_errno = ioctl_errno;
return 0;
}
@ -1985,34 +1808,23 @@ static int _do_dm_ioctl_unmangle_string(char *str, const char *str_name,
static int _dm_ioctl_unmangle_names(int type, struct dm_ioctl *dmi)
{
char buf[DM_NAME_LEN];
char buf_uuid[DM_UUID_LEN];
struct dm_name_list *names;
struct dm_names *names;
unsigned next = 0;
char *name;
int r = 1;
uint32_t *event_nr;
char *uuid_ptr;
dm_string_mangling_t mangling_mode = dm_get_name_mangling_mode();
if ((name = dmi->name))
r &= _do_dm_ioctl_unmangle_string(name, "name", buf, sizeof(buf),
mangling_mode);
r = _do_dm_ioctl_unmangle_string(name, "name", buf, sizeof(buf),
dm_get_name_mangling_mode());
if (type == DM_DEVICE_LIST &&
((names = ((struct dm_name_list *) ((char *)dmi + dmi->data_start)))) &&
((names = ((struct dm_names *) ((char *)dmi + dmi->data_start)))) &&
names->dev) {
do {
names = (struct dm_name_list *)((char *) names + next);
event_nr = _align_ptr(names->name + strlen(names->name) + 1);
r &= _do_dm_ioctl_unmangle_string(names->name, "name",
buf, sizeof(buf), mangling_mode);
/* Unmangle also UUID within same loop */
if (_check_has_event_nr() &&
(event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
uuid_ptr = _align_ptr(event_nr + 2);
r &= _do_dm_ioctl_unmangle_string(uuid_ptr, "UUID", buf_uuid,
sizeof(buf_uuid), mangling_mode);
}
names = (struct dm_names *)((char *) names + next);
r = _do_dm_ioctl_unmangle_string(names->name, "name",
buf, sizeof(buf),
dm_get_name_mangling_mode());
next = names->next;
} while (next);
}
@ -2076,7 +1888,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
/*
* Prevent udev vs. libdevmapper race when processing nodes
* and symlinks. This can happen when the udev rules are
* installed and udev synchronization code is enabled in
* installed and udev synchronisation code is enabled in
* libdevmapper but the software using libdevmapper does not
* make use of it (by not calling dm_task_set_cookie before).
* We need to instruct the udev rules not to be applied at
@ -2086,7 +1898,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
if (!dmt->cookie_set && dm_udev_get_sync_support()) {
log_debug_activation("Cookie value is not set while trying to call %s "
"ioctl. Please, consider using libdevmapper's udev "
"synchronization interface or disable it explicitly "
"synchronisation interface or disable it explicitly "
"by calling dm_udev_set_sync_support(0).",
dmt->type == DM_DEVICE_RESUME ? "DM_DEVICE_RESUME" :
dmt->type == DM_DEVICE_REMOVE ? "DM_DEVICE_REMOVE" :

View File

@ -2311,7 +2311,7 @@ static int _check_semaphore_is_supported(void)
if (maxid < 0) {
log_warn("Kernel not configured for semaphores (System V IPC). "
"Not using udev synchronization code.");
"Not using udev synchronisation code.");
return 0;
}
@ -2334,7 +2334,7 @@ static int _check_udev_is_running(void)
if (!(r = udev_queue_get_udev_is_active(udev_queue)))
log_debug_activation("Udev is not running. "
"Not using udev synchronization code.");
"Not using udev synchronisation code.");
udev_queue_unref(udev_queue);
udev_unref(udev);

View File

@ -214,7 +214,6 @@ struct load_segment {
uint32_t device_id; /* Thin */
// VDO params
uint32_t vdo_version; /* VDO - version of target table line */
struct dm_tree_node *vdo_data; /* VDO */
struct dm_vdo_target_params vdo_params; /* VDO */
const char *vdo_name; /* VDO - device name is ALSO passed as table arg */
@ -294,10 +293,6 @@ struct load_properties {
unsigned send_messages;
/* Skip suspending node's children, used when sending messages to thin-pool */
int skip_suspend;
/* Suspend and Resume siblings after node activation with udev flags*/
unsigned reactivate_siblings;
uint16_t reactivate_udev_flags;
};
/* Two of these used to join two nodes with uses and used_by. */
@ -2034,68 +2029,6 @@ static int _rename_conflict_exists(struct dm_tree_node *parent,
return 0;
}
/*
* Reactivation of sibling nodes
*
* Function is used when activating origin and its thick snapshots
* to ensure udev is processing first the origin LV and all the
* snapshot LVs are processed afterwards.
*/
static int _reactivate_siblings(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len)
{
struct dm_tree_node *child;
const char *uuid;
void *handle = NULL;
int r = 1;
/* Wait for udev before reactivating siblings */
if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
stack;
dm_tree_set_cookie(dnode, 0);
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
if (child->props.reactivate_siblings) {
/* Skip 'leading' device in this group, marked with flag */
child->props.reactivate_siblings = 0;
continue;
}
if (!(uuid = dm_tree_node_get_uuid(child))) {
stack;
continue;
}
if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
continue;
if (!_suspend_node(child->name, child->info.major, child->info.minor,
child->dtree->skip_lockfs,
child->dtree->no_flush, &child->info)) {
log_error("Unable to suspend %s (" FMTu32
":" FMTu32 ")", child->name,
child->info.major, child->info.minor);
r = 0;
continue;
}
if (!_resume_node(child->name, child->info.major, child->info.minor,
child->props.read_ahead, child->props.read_ahead_flags,
&child->info, &child->dtree->cookie,
child->props.reactivate_udev_flags, // use these flags
child->info.suspended)) {
log_error("Failed to suspend %s (" FMTu32
":" FMTu32 ")", child->name,
child->info.major, child->info.minor);
r = 0;
continue;
}
}
return r;
}
int dm_tree_activate_children(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len)
@ -2106,7 +2039,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
struct dm_tree_node *child = dnode;
const char *name;
const char *uuid;
int priority, next_priority;
int priority;
/* Activate children first */
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
@ -2124,16 +2057,12 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
}
handle = NULL;
for (priority = 0; priority < 3; priority++) {
awaiting_peer_rename = 0;
next_priority = 0;
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
if (priority != child->activation_priority) {
if ((next_priority < child->activation_priority) &&
(child->activation_priority > priority))
next_priority = child->activation_priority;
if (priority != child->activation_priority)
continue;
}
if (!(uuid = dm_tree_node_get_uuid(child))) {
stack;
@ -2188,16 +2117,9 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
if (r && (child->props.send_messages > 1) &&
!(r = _node_send_messages(child, uuid_prefix, uuid_prefix_len, 1)))
stack;
/* Reactivate only for fresh activated origin */
if (r && child->props.reactivate_siblings &&
(!(r = _reactivate_siblings(dnode, uuid_prefix, uuid_prefix_len))))
stack;
}
if (awaiting_peer_rename)
priority--; /* redo priority level */
else if (!next_priority)
break; /* no more work, higher priority was not found in the chain */
}
return r;
@ -2756,10 +2678,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
count += 1;
if (seg->writecache_settings.max_age_set)
count += 2;
if (seg->writecache_settings.metadata_only_set)
count += 1;
if (seg->writecache_settings.pause_writeback_set)
count += 2;
if (seg->writecache_settings.new_key)
count += 2;
@ -2811,14 +2729,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age);
}
if (seg->writecache_settings.metadata_only_set) {
EMIT_PARAMS(pos, " metadata_only");
}
if (seg->writecache_settings.pause_writeback_set) {
EMIT_PARAMS(pos, " pause_writeback %u", seg->writecache_settings.pause_writeback);
}
if (seg->writecache_settings.new_key) {
EMIT_PARAMS(pos, " %s %s",
seg->writecache_settings.new_key,
@ -2939,18 +2849,13 @@ static int _thin_pool_emit_segment_line(struct dm_task *dmt,
return 1;
}
static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t minor,
static int _vdo_emit_segment_line(struct dm_task *dmt,
struct load_segment *seg,
char *params, size_t paramsize)
{
int pos = 0;
char data[DM_FORMAT_DEV_BUFSIZE];
char data_dev[128]; // for /dev/dm-XXXX
uint64_t logical_blocks;
struct dm_task *vdo_dmt;
uint64_t start, length = 0;
char *type = NULL;
char *vdo_params = NULL;
if (!_build_dev_string(data, sizeof(data), seg->vdo_data))
return_0;
@ -2960,59 +2865,18 @@ static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t
return 0;
}
/*
* If there is already running VDO target, read 'existing' virtual size out of table line
* and avoid reading it them from VDO metadata device
*
* NOTE: ATM VDO virtual size can be ONLY extended thus it's simple to recongnize 'right' size.
* However if there would be supported also reduction, this check would need to check range.
*/
if ((vdo_dmt = dm_task_create(DM_DEVICE_TABLE))) {
if (dm_task_set_major(vdo_dmt, major) &&
dm_task_set_minor(vdo_dmt, minor) &&
dm_task_run(vdo_dmt)) {
(void) dm_get_next_target(vdo_dmt, NULL, &start, &length, &type, &vdo_params);
if (!type || strcmp(type, "vdo"))
length = 0;
}
dm_task_destroy(vdo_dmt);
}
if (!length && dm_vdo_parse_logical_size(data_dev, &logical_blocks))
length = logical_blocks * 8;
if (seg->size < length) {
log_debug_activation("Correcting VDO virtual volume size from " FMTu64 " to " FMTu64 ".",
seg->size, length);
seg->size = length;
}
if (seg->vdo_version < 4) {
EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s ",
data_dev,
seg->vdo_data_size / 8, // this parameter is in 4K units
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
seg->vdo_params.block_map_era_length,
seg->vdo_params.use_metadata_hints ? "on" : "off" ,
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_SYNC) ? "sync" :
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC) ? "async" :
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
seg->vdo_name);
} else {
EMIT_PARAMS(pos, "V4 %s " FMTu64 " %u " FMTu64 " %u "
"deduplication %s compression %s ",
data_dev,
seg->vdo_data_size / 8, // this parameter is in 4K units
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
seg->vdo_params.block_map_era_length,
seg->vdo_params.use_deduplication ? "on" : "off",
seg->vdo_params.use_compression ? "on" : "off");
}
EMIT_PARAMS(pos, "maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s "
"maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
data_dev,
seg->vdo_data_size / 8, // this parameter is in 4K units
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
seg->vdo_params.block_map_era_length,
seg->vdo_params.use_metadata_hints ? "on" : "off" ,
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_SYNC) ? "sync" :
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC) ? "async" :
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
seg->vdo_name,
seg->vdo_params.max_discard,
seg->vdo_params.ack_threads,
seg->vdo_params.bio_threads,
@ -3087,7 +2951,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size);
break;
case SEG_VDO:
if (!_vdo_emit_segment_line(dmt, major, minor, seg, params, paramsize))
if (!_vdo_emit_segment_line(dmt, seg, params, paramsize))
return_0;
break;
case SEG_CRYPT:
@ -3526,10 +3390,6 @@ int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
/* Resume snapshot origins after new snapshots */
dnode->activation_priority = 1;
if (!dnode->info.exists)
/* Reactivate siblings for this origin after being resumed */
dnode->props.reactivate_siblings = 1;
/*
* Don't resume the origin immediately in case it is a non-trivial
* target that must not be active more than once concurrently!
@ -3592,20 +3452,6 @@ static int _add_snapshot_target(struct dm_tree_node *node,
/* Resume merging snapshot after snapshot-merge */
seg->merge->activation_priority = 2;
}
} else if (!origin_node->info.exists) {
/* Keep original udev_flags for reactivation. */
node->props.reactivate_udev_flags = node->udev_flags;
/* Reactivation is needed if the origin's -real device is not in DM table.
* For this case after the resume of its origin LV we resume its snapshots
* with updated udev_flags to completely avoid udev scanning for the first resume.
* Reactivation then resumes snapshots with original udev_flags.
*/
node->udev_flags |= DM_SUBSYSTEM_UDEV_FLAG0 |
DM_UDEV_DISABLE_DISK_RULES_FLAG |
DM_UDEV_DISABLE_OTHER_RULES_FLAG;
log_debug_activation("Using udev_flags 0x%x for activation of %s.",
node->udev_flags, node->name);
}
return 1;
@ -4477,7 +4323,6 @@ void dm_tree_node_set_callback(struct dm_tree_node *dnode,
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
uint64_t size,
uint32_t vdo_version,
const char *vdo_pool_name,
const char *data_uuid,
uint64_t data_size,
@ -4499,13 +4344,11 @@ int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
if (!_link_tree_nodes(node, seg->vdo_data))
return_0;
seg->vdo_version = vdo_version;
seg->vdo_params = *vtp;
seg->vdo_name = vdo_pool_name;
seg->vdo_data_size = data_size;
if (seg->vdo_version < 4)
node->props.send_messages = 2;
node->props.send_messages = 2;
return 1;
}

View File

@ -223,6 +223,7 @@ retry_fcntl:
}
/* coverity[leaked_handle] intentional leak of fd handle here */
return 1;
fail_close_unlink:

View File

@ -384,246 +384,172 @@ int dm_report_field_percent(struct dm_report *rh,
return 1;
}
struct pos_len {
struct str_list_sort_value_item {
unsigned pos;
size_t len;
};
struct str_pos_len {
const char *str;
struct pos_len item;
};
struct str_list_sort_value {
const char *value;
struct pos_len *items;
struct str_list_sort_value_item *items;
};
static int _str_sort_cmp(const void *a, const void *b)
{
return strcmp(((const struct str_pos_len *) a)->str, ((const struct str_pos_len *) b)->str);
}
struct str_list_sort_item {
const char *str;
struct str_list_sort_value_item item;
};
#define FIELD_STRING_LIST_DEFAULT_DELIMITER ","
static int _str_list_sort_item_cmp(const void *a, const void *b)
{
const struct str_list_sort_item *slsi_a = (const struct str_list_sort_item *) a;
const struct str_list_sort_item *slsi_b = (const struct str_list_sort_item *) b;
return strcmp(slsi_a->str, slsi_b->str);
}
static int _report_field_string_list(struct dm_report *rh,
struct dm_report_field *field,
const struct dm_list *data,
const char *delimiter,
int sort_repstr)
int sort)
{
static const char _error_msg_prefix[] = "_report_field_string_list: ";
unsigned int list_size, i, pos;
struct str_pos_len *arr = NULL;
static const char _string_list_grow_object_failed_msg[] = "dm_report_field_string_list: dm_pool_grow_object_failed";
struct str_list_sort_value *sort_value = NULL;
unsigned int list_size, pos, i;
struct str_list_sort_item *arr = NULL;
struct dm_str_list *sl;
size_t delimiter_len, repstr_str_len, repstr_size;
char *repstr = NULL;
struct pos_len *repstr_extra;
struct str_list_sort_value *sortval = NULL;
size_t delimiter_len, len;
void *object;
int r = 0;
/*
* The 'field->report_string' has 2 parts:
*
* - string representing the whole string list
* (terminated by '\0' at its end as usual)
*
* - extra info beyond the end of the string representing
* position and length of each list item within the
* field->report_string (array of 'struct pos_len')
*
* We can use the extra info to unambiguously identify list items,
* the delimiter is not enough here as it's not assured it won't appear
* in list item itself. We will make use of this extra info in case
* we need to apply further formatting to the list in dm_report_output
* where the pure field->report_string is not enough for printout.
*
*
* The 'field->sort_value' contains a value of type 'struct
* str_list_sort_value' ('sortval'). This one has a pointer to the
* 'field->report_string' string ('sortval->value') and info
* about position and length of each list item within the string
* (array of 'struct pos_len').
*
*
* The 'field->report_string' is either in sorted or unsorted form,
* depending on 'sort_repstr' arg.
*
* The 'field->sort_value.items' is always in sorted form because
* we need that for effective sorting and selection.
*
* If 'field->report_string' is sorted, then field->report_string
* and field->sort_value.items share the same array of
* 'struct pos_len' (because they're both sorted the same way),
* otherwise, each one has its own array.
*
* The very first item in the array of 'struct pos_len' is always
* a pair denoting '[list_size,strlen(field->report_string)]'. The
* rest of items denote start and lenght of each item in the list.
*
*
* For example, if we have a list with "abc", "xy", "defgh"
* as input and delimiter is ",", we end up with either:
*
* A) if we don't want the report string sorted ('sort_repstr == 0'):
*
* - field->report_string = repstr
*
* repstr repstr_extra
* | |
* V V
* abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
* |____________||________________________|
* string array of struct pos_len
* |____||________________|
* #items items
*
* - field->sort_value = sortval
*
* sortval->value = repstr
* sortval->items = {[3,12],[0,3],[7,5],[4,2]}
* (that is 'abc,defgh,xy')
*
*
* B) if we want the report string sorted ('sort_repstr == 1'):
*
* - field->report_string = repstr
*
* repstr repstr_extra
* | |
* V V
* abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
* |____________||________________________|
* string array of struct pos_len
* |____||________________|
* #items items
*
* - field->sort_value = sortval
*
* sortval->value = repstr
* sortval->items = repstr_extra
* (that is 'abc,defgh,xy')
*/
if (!delimiter)
delimiter = FIELD_STRING_LIST_DEFAULT_DELIMITER;
delimiter_len = strlen(delimiter);
list_size = dm_list_size(data);
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(struct str_list_sort_value)))) {
log_error("%s failed to allocate sort value structure", _error_msg_prefix);
goto out;
if (!(sort_value = dm_pool_zalloc(rh->mem, sizeof(struct str_list_sort_value)))) {
log_error("dm_report_field_string_list: dm_pool_zalloc failed for sort_value");
return 0;
}
list_size = dm_list_size(data);
/*
* Sort value stores the pointer to the report_string and then
* position and length for each list element withing the report_string.
* The first element stores number of elements in 'len' (therefore
* list_size + 1 is used below for the extra element).
* For example, with this input:
* sort = 0; (we don't want to report sorted)
* report_string = "abc,xy,defgh"; (this is reported)
*
* ...we end up with:
* sort_value->value = report_string; (we'll use the original report_string for indices)
* sort_value->items[0] = {0,3}; (we have 3 items)
* sort_value->items[1] = {0,3}; ("abc")
* sort_value->items[2] = {7,5}; ("defgh")
* sort_value->items[3] = {4,2}; ("xy")
*
* The items alone are always sorted while in report_string they can be
* sorted or not (based on "sort" arg) - it depends on how we prefer to
* display the list. Having items sorted internally helps with searching
* through them.
*/
if (!(sort_value->items = dm_pool_zalloc(rh->mem, (list_size + 1) * sizeof(struct str_list_sort_value_item)))) {
log_error("dm_report_fiel_string_list: dm_pool_zalloc failed for sort value items");
goto out;
}
sort_value->items[0].len = list_size;
/* zero items */
if (list_size == 0) {
field->report_string = sortval->value = "";
sortval->items = NULL;
field->sort_value = sortval;
if (!list_size) {
sort_value->value = field->report_string = "";
field->sort_value = sort_value;
return 1;
}
/* one item */
if (list_size == 1) {
sl = (struct dm_str_list *) dm_list_first(data);
repstr_str_len = strlen(sl->str);
repstr_size = repstr_str_len + 1 + (2 * sizeof(struct pos_len));
if (!(repstr = dm_pool_alloc(rh->mem, repstr_size))) {
log_error("%s failed to allocate report string structure", _error_msg_prefix);
if (!sl ||
!(sort_value->value = field->report_string = dm_pool_strdup(rh->mem, sl->str))) {
log_error("dm_report_field_string_list: dm_pool_strdup failed");
goto out;
}
repstr_extra = (struct pos_len *) (repstr + repstr_str_len + 1);
memcpy(repstr, sl->str, repstr_str_len + 1);
memcpy(repstr_extra, &((struct pos_len) {.pos = 1, .len = repstr_str_len}), sizeof(struct pos_len));
memcpy(repstr_extra + 1, &((struct pos_len) {.pos = 0, .len = repstr_str_len}), sizeof(struct pos_len));
sortval->value = field->report_string = repstr;
sortval->items = repstr_extra;
field->sort_value = sortval;
sort_value->items[1].pos = 0;
sort_value->items[1].len = strlen(sl->str);
field->sort_value = sort_value;
return 1;
}
/* more than one item - allocate temporary array for string list items for further processing */
if (!(arr = malloc(list_size * sizeof(struct str_pos_len)))) {
log_error("%s failed to allocate temporary array for processing", _error_msg_prefix);
/* more than one item - sort the list */
if (!(arr = malloc(sizeof(struct str_list_sort_item) * list_size))) {
log_error("dm_report_field_string_list: malloc failed");
goto out;
}
i = 0;
repstr_size = 0;
if (!(dm_pool_begin_object(rh->mem, 256))) {
log_error(_string_list_grow_object_failed_msg);
goto out;
}
if (!delimiter)
delimiter = ",";
delimiter_len = strlen(delimiter);
i = pos = 0;
dm_list_iterate_items(sl, data) {
arr[i].str = sl->str;
repstr_size += (arr[i].item.len = strlen(sl->str));
if (!sort) {
/* sorted outpud not required - report the list as it is */
len = strlen(sl->str);
if (!dm_pool_grow_object(rh->mem, arr[i].str, len) ||
(i+1 != list_size && !dm_pool_grow_object(rh->mem, delimiter, delimiter_len))) {
log_error(_string_list_grow_object_failed_msg);
goto out;
}
arr[i].item.pos = pos;
arr[i].item.len = len;
pos = i+1 == list_size ? pos+len : pos+len+delimiter_len;
}
i++;
}
/*
* At this point, repstr_size contains sum of lengths of all string list items.
* Now, add these to the repstr_size:
*
* --> sum of character count used by all delimiters: + ((list_size - 1) * delimiter_len)
*
* --> '\0' used at the end of the string list: + 1
*
* --> sum of structures used to keep info about pos and length of each string list item:
* [0, <list_size>] [<pos1>,<size1>] [<pos2>,<size2>] ...
* That is: + ((list_size + 1) * sizeof(struct pos_len))
*/
repstr_size += ((list_size - 1) * delimiter_len);
repstr_str_len = repstr_size;
repstr_size += 1 + ((list_size + 1) * sizeof(struct pos_len));
qsort(arr, i, sizeof(struct str_list_sort_item), _str_list_sort_item_cmp);
if (sort_repstr)
qsort(arr, list_size, sizeof(struct str_pos_len), _str_sort_cmp);
for (i = 0, pos = 0; i < list_size; i++) {
if (sort) {
/* sorted output required - report the list as sorted */
len = strlen(arr[i].str);
if (!dm_pool_grow_object(rh->mem, arr[i].str, len) ||
(i+1 != list_size && !dm_pool_grow_object(rh->mem, delimiter, delimiter_len))) {
log_error(_string_list_grow_object_failed_msg);
goto out;
}
/*
* Save position and length of the string
* element in report_string for sort_value.
* Use i+1 here since items[0] stores list size!!!
*/
sort_value->items[i+1].pos = pos;
sort_value->items[i+1].len = len;
pos = i+1 == list_size ? pos+len : pos+len+delimiter_len;
} else {
sort_value->items[i+1].pos = arr[i].item.pos;
sort_value->items[i+1].len = arr[i].item.len;
}
}
if (!(repstr = dm_pool_alloc(rh->mem, repstr_size))) {
log_error("%s failed to allocate report string structure", _error_msg_prefix);
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
log_error(_string_list_grow_object_failed_msg);
goto out;
}
repstr_extra = (struct pos_len *) (repstr + repstr_str_len + 1);
memcpy(repstr_extra, &(struct pos_len) {.pos = list_size, .len = repstr_str_len}, sizeof(struct pos_len));
for (i = 0, pos = 0; i < list_size; i++) {
arr[i].item.pos = pos;
memcpy(repstr + pos, arr[i].str, arr[i].item.len);
memcpy(repstr_extra + i + 1, &arr[i].item, sizeof(struct pos_len));
pos += arr[i].item.len;
if (i + 1 < list_size) {
memcpy(repstr + pos, delimiter, delimiter_len);
pos += delimiter_len;
}
}
*(repstr + pos) = '\0';
sortval->value = repstr;
if (sort_repstr)
sortval->items = repstr_extra;
else {
if (!(sortval->items = dm_pool_alloc(rh->mem, (list_size + 1) * sizeof(struct pos_len)))) {
log_error("%s failed to allocate array of items inside sort value structure",
_error_msg_prefix);
goto out;
}
qsort(arr, list_size, sizeof(struct str_pos_len), _str_sort_cmp);
sortval->items[0] = (struct pos_len) {.pos = list_size, .len = repstr_str_len};
for (i = 0; i < list_size; i++)
sortval->items[i+1] = arr[i].item;
}
field->report_string = repstr;
field->sort_value = sortval;
object = dm_pool_end_object(rh->mem);
sort_value->value = object;
field->sort_value = sort_value;
field->report_string = object;
r = 1;
out:
if (!r && sortval)
dm_pool_free(rh->mem, sortval);
if (!r && sort_value)
dm_pool_free(rh->mem, sort_value);
free(arr);
return r;
}
@ -1762,7 +1688,7 @@ static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *v
struct dm_str_list *sel_item;
unsigned int i = 1;
if (!val->items) {
if (!val->items[0].len) {
if (sel_list_size == 1) {
/* match blank string list with selection defined as blank string only */
sel_item = dm_list_item(dm_list_first(&sel->str_list.list), struct dm_str_list);
@ -1772,7 +1698,7 @@ static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *v
}
/* if item count differs, it's clear the lists do not match */
if (val->items[0].pos != sel_list_size)
if (val->items[0].len != sel_list_size)
return 0;
/* both lists are sorted so they either match 1:1 or not */
@ -1795,7 +1721,7 @@ static int _cmp_field_string_list_subset_all(const struct str_list_sort_value *v
unsigned int i, last_found = 1;
int r = 0;
if (!val->items) {
if (!val->items[0].len) {
if (sel_list_size == 1) {
/* match blank string list with selection defined as blank string only */
sel_item = dm_list_item(dm_list_first(&sel->str_list.list), struct dm_str_list);
@ -1807,7 +1733,7 @@ static int _cmp_field_string_list_subset_all(const struct str_list_sort_value *v
/* check selection is a subset of the value */
dm_list_iterate_items(sel_item, &sel->str_list.list) {
r = 0;
for (i = last_found; i <= val->items[0].pos; i++) {
for (i = last_found; i <= val->items[0].len; i++) {
if ((strlen(sel_item->str) == val->items[i].len) &&
!strncmp(sel_item->str, val->value + val->items[i].pos, val->items[i].len)) {
last_found = i;
@ -1829,7 +1755,7 @@ static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
unsigned int i;
/* match blank string list with selection that contains blank string */
if (!val->items) {
if (!val->items[0].len) {
dm_list_iterate_items(sel_item, &sel->str_list.list) {
if (!strcmp(sel_item->str, ""))
return 1;
@ -1842,7 +1768,7 @@ static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
* TODO: Optimize this so we don't need to compare the whole lists' content.
* Make use of the fact that the lists are sorted!
*/
for (i = 1; i <= val->items[0].pos; i++) {
for (i = 1; i <= val->items[0].len; i++) {
if ((strlen(sel_item->str) == val->items[i].len) &&
!strncmp(sel_item->str, val->value + val->items[i].pos, val->items[i].len))
return 1;
@ -4263,9 +4189,7 @@ static int _report_headings(struct dm_report *rh)
fields = fp->implicit ? _implicit_report_fields : rh->fields;
heading = rh->flags & DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS ?
fields[fp->field_num].id : fields[fp->field_num].heading;
heading = fields[fp->field_num].heading;
if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
if (dm_snprintf(buf, buf_size, "%-*.*s",
fp->width, fp->width, heading) < 0) {
@ -4317,7 +4241,6 @@ static void _recalculate_fields(struct dm_report *rh)
struct row *row;
struct dm_report_field *field;
int len;
size_t id_len;
dm_list_iterate_items(row, &rh->rows) {
dm_list_iterate_items(field, &row->fields) {
@ -4332,12 +4255,6 @@ static void _recalculate_fields(struct dm_report *rh)
field->props->width = len;
}
if (rh->flags & DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS) {
id_len = strlen(rh->fields[field->props->field_num].id);
if (field->props->width < id_len)
field->props->width = id_len;
}
}
}
@ -4443,7 +4360,6 @@ static int _sort_rows(struct dm_report *rh)
#define JSON_ARRAY_START "["
#define JSON_ARRAY_END "]"
#define JSON_ESCAPE_CHAR "\\"
#define JSON_NULL "null"
#define UNABLE_TO_EXTEND_OUTPUT_LINE_MSG "dm_report: Unable to extend output line"
@ -4453,42 +4369,38 @@ static int _is_basic_report(struct dm_report *rh)
(rh->group_item->group->type == DM_REPORT_GROUP_BASIC);
}
static int _is_json_std_report(struct dm_report *rh)
{
return rh->group_item &&
rh->group_item->group->type == DM_REPORT_GROUP_JSON_STD;
}
static int _is_json_report(struct dm_report *rh)
{
return rh->group_item &&
(rh->group_item->group->type == DM_REPORT_GROUP_JSON ||
rh->group_item->group->type == DM_REPORT_GROUP_JSON_STD);
(rh->group_item->group->type == DM_REPORT_GROUP_JSON);
}
static int _is_pure_numeric_field(struct dm_report_field *field)
{
return field->props->flags & (DM_REPORT_FIELD_TYPE_NUMBER | DM_REPORT_FIELD_TYPE_PERCENT);
}
static const char *_get_field_id(struct dm_report *rh, struct dm_report_field *field)
/*
* Produce report output
*/
static int _output_field(struct dm_report *rh, struct dm_report_field *field)
{
const struct dm_report_field_type *fields = field->props->implicit ? _implicit_report_fields
: rh->fields;
return fields[field->props->field_num].id;
}
static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field *field)
{
char *field_id;
int32_t width;
uint32_t align;
const char *repstr;
const char *p1_repstr, *p2_repstr;
char *buf = NULL;
size_t buf_size = 0;
if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
if (!(field_id = strdup(_get_field_id(rh, field)))) {
if (_is_json_report(rh)) {
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
!dm_pool_grow_object(rh->mem, fields[field->props->field_num].id, 0) ||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
!dm_pool_grow_object(rh->mem, JSON_PAIR, 1) ||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error("dm_report: Unable to extend output line");
return 0;
}
} else if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
if (!(field_id = strdup(fields[field->props->field_num].id))) {
log_error("dm_report: Failed to copy field name");
return 0;
}
@ -4519,14 +4431,43 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
}
}
if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
repstr = field->report_string;
width = field->props->width;
if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) {
if (_is_json_report(rh)) {
/* Escape any JSON_QUOTE that may appear in reported string. */
p1_repstr = repstr;
while ((p2_repstr = strstr(p1_repstr, JSON_QUOTE))) {
if (p2_repstr > p1_repstr) {
if (!dm_pool_grow_object(rh->mem, p1_repstr, p2_repstr - p1_repstr)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (!dm_pool_grow_object(rh->mem, JSON_ESCAPE_CHAR, 1) ||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
p1_repstr = p2_repstr + 1;
}
if (!dm_pool_grow_object(rh->mem, p1_repstr, 0)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
} else {
if (!dm_pool_grow_object(rh->mem, repstr, 0)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
} else {
if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
align = ((field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ||
(field->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) ?
(field->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) ?
DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
width = field->props->width;
/* Including trailing '\0'! */
buf_size = width + 1;
if (!(buf = malloc(buf_size))) {
@ -4536,7 +4477,7 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
if (align & DM_REPORT_FIELD_ALIGN_LEFT) {
if (dm_snprintf(buf, buf_size, "%-*.*s",
width, width, field->report_string) < 0) {
width, width, repstr) < 0) {
log_error("dm_report: left-aligned snprintf() failed");
goto bad;
}
@ -4546,7 +4487,7 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
}
} else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) {
if (dm_snprintf(buf, buf_size, "%*.*s",
width, width, field->report_string) < 0) {
width, width, repstr) < 0) {
log_error("dm_report: right-aligned snprintf() failed");
goto bad;
}
@ -4555,11 +4496,6 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
goto bad;
}
}
} else {
if (!dm_pool_grow_object(rh->mem, field->report_string, 0)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
@ -4569,164 +4505,21 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
goto bad;
}
}
} else if (_is_json_report(rh)) {
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
goto bad;
}
}
free(buf);
return 1;
bad:
free(buf);
return 0;
}
static int _safe_repstr_output(struct dm_report *rh, const char *repstr, size_t len)
{
const char *p_repstr;
const char *repstr_end = len ? repstr + len : repstr + strlen(repstr);
/* Escape any JSON_QUOTE that may appear in reported string. */
while (1) {
if (!(p_repstr = memchr(repstr, JSON_QUOTE[0], repstr_end - repstr)))
break;
if (p_repstr > repstr) {
if (!dm_pool_grow_object(rh->mem, repstr, p_repstr - repstr)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (!dm_pool_grow_object(rh->mem, JSON_ESCAPE_CHAR, 1) ||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
repstr = p_repstr + 1;
}
if (!dm_pool_grow_object(rh->mem, repstr, repstr_end - repstr)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
return 1;
}
static int _output_field_json_fmt(struct dm_report *rh, struct dm_report_field *field)
{
const char *repstr;
size_t list_size, i;
struct pos_len *pos_len;
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
!dm_pool_grow_object(rh->mem, _get_field_id(rh, field), 0) ||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
!dm_pool_grow_object(rh->mem, JSON_PAIR, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
if (field->props->flags & DM_REPORT_FIELD_TYPE_STRING_LIST) {
if (!_is_json_std_report(rh)) {
/* string list in JSON - report whole list as simple string in quotes */
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
if (!_safe_repstr_output(rh, field->report_string, 0))
return_0;
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
return 1;
}
/* string list in JSON_STD - report list as proper JSON array */
if (!dm_pool_grow_object(rh->mem, JSON_ARRAY_START, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
if (*field->report_string != 0) {
pos_len = (struct pos_len *) (field->report_string +
((struct str_list_sort_value *) field->sort_value)->items[0].len + 1);
list_size = pos_len->pos;
} else
list_size = 0;
for (i = 0; i < list_size; i++) {
pos_len++;
if (i != 0) {
if (!dm_pool_grow_object(rh->mem, JSON_SEPARATOR, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
if (!_safe_repstr_output(rh, field->report_string + pos_len->pos, pos_len->len))
return_0;
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (!dm_pool_grow_object(rh->mem, JSON_ARRAY_END, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
return 1;
}
/* all other types than string list - handle both JSON and JSON_STD */
if (!(_is_json_std_report(rh) && _is_pure_numeric_field(field))) {
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (_is_json_std_report(rh) && _is_pure_numeric_field(field) && !*field->report_string)
repstr = JSON_NULL;
else
repstr = field->report_string;
if (!_safe_repstr_output(rh, repstr, 0))
return_0;
if (!(_is_json_std_report(rh) && _is_pure_numeric_field(field))) {
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
return 1;
}
/*
* Produce report output
*/
static int _output_field(struct dm_report *rh, struct dm_report_field *field)
{
return _is_json_report(rh) ? _output_field_json_fmt(rh, field)
: _output_field_basic_fmt(rh, field);
}
static void _destroy_rows(struct dm_report *rh)
{
/*
@ -4749,7 +4542,6 @@ static int _output_as_rows(struct dm_report *rh)
struct field_properties *fp;
struct dm_report_field *field;
struct row *row;
const char *heading;
dm_list_iterate_items(fp, &rh->field_props) {
if (fp->flags & FLD_HIDDEN) {
@ -4768,10 +4560,7 @@ static int _output_as_rows(struct dm_report *rh)
}
if ((rh->flags & DM_REPORT_OUTPUT_HEADINGS)) {
heading = rh->flags & DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS ?
fields[fp->field_num].id : fields[fp->field_num].heading;
if (!dm_pool_grow_object(rh->mem, heading, 0)) {
if (!dm_pool_grow_object(rh->mem, fields[fp->field_num].heading, 0)) {
log_error("dm_report: Failed to extend row for field name");
goto bad;
}
@ -4811,36 +4600,12 @@ static int _output_as_rows(struct dm_report *rh)
return 0;
}
static struct dm_list *_get_last_displayed_rowh(struct dm_report *rh)
{
struct dm_list *rowh;
struct row *row;
/*
* We need to find 'last displayed row', not just 'last row'.
*
* This is because the report may be marked with
* DM_REPORT_OUTPUT_MULTIPLE_TIMES flag. In that case, the report
* may be used more than once and with different selection
* criteria each time. Therefore, such report may also contain
* rows which we do not display on output with current selection
* criteria.
*/
for (rowh = dm_list_last(&rh->rows); rowh; rowh = dm_list_prev(&rh->rows, rowh)) {
row = dm_list_item(rowh, struct row);
if (_should_display_row(row))
return rowh;
}
return NULL;
}
static int _output_as_columns(struct dm_report *rh)
{
struct dm_list *fh, *rowh, *ftmp, *rtmp;
struct row *row = NULL;
struct dm_report_field *field;
struct dm_list *last_rowh;
struct dm_list *last_row;
int do_field_delim;
char *line;
@ -4849,7 +4614,7 @@ static int _output_as_columns(struct dm_report *rh)
_report_headings(rh);
/* Print and clear buffer */
last_rowh = _get_last_displayed_rowh(rh);
last_row = dm_list_last(&rh->rows);
dm_list_iterate_safe(rowh, rtmp, &rh->rows) {
row = dm_list_item(rowh, struct row);
@ -4903,7 +4668,7 @@ static int _output_as_columns(struct dm_report *rh)
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
goto bad;
}
if (rowh != last_rowh &&
if (rowh != last_row &&
!dm_pool_grow_object(rh->mem, JSON_SEPARATOR, 0)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
goto bad;
@ -5218,7 +4983,6 @@ int dm_report_group_push(struct dm_report_group *group, struct dm_report *report
goto_bad;
break;
case DM_REPORT_GROUP_JSON:
case DM_REPORT_GROUP_JSON_STD:
if (!_report_group_push_json(item, data))
goto_bad;
break;
@ -5282,7 +5046,6 @@ int dm_report_group_pop(struct dm_report_group *group)
return_0;
break;
case DM_REPORT_GROUP_JSON:
case DM_REPORT_GROUP_JSON_STD:
if (!_report_group_pop_json(item))
return_0;
break;
@ -5319,7 +5082,7 @@ int dm_report_group_output_and_pop_all(struct dm_report_group *group)
return_0;
}
if (group->type == DM_REPORT_GROUP_JSON || group->type == DM_REPORT_GROUP_JSON_STD) {
if (group->type == DM_REPORT_GROUP_JSON) {
_json_output_start(group);
log_print(JSON_OBJECT_END);
group->indent -= JSON_INDENT_UNIT;

View File

@ -192,7 +192,7 @@ int dm_asprintf(char **result, const char *format, ...)
}
/*
* Count occurrences of 'c' in 'str' until we reach a null char.
* Count occurences of 'c' in 'str' until we reach a null char.
*
* Returns:
* len - incremented for each char we encounter.

View File

@ -106,22 +106,26 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
/* Second field holds the device count */
msg_fields = "<#devs> ";
if (!(pp = _skip_fields(params, 1)) || (sscanf(pp, "%d", &i) != 1) || !(p = _skip_fields(pp, 1)))
if (!(p = _skip_fields(params, 1)) || (sscanf(p, "%d", &i) != 1))
goto_bad;
msg_fields = "";
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid))))
goto_bad;
msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> ";
if (!(s->raid_type = dm_pool_strndup(mem, params, pp - params - 1)))
if (!(s->raid_type = dm_pool_zalloc(mem, p - params)))
goto_bad; /* memory is freed when pool is destroyed */
if (!(s->dev_health = dm_pool_strndup(mem, p, i)) || !(p = _skip_fields(p, 1))) /* health chars */
if (!(s->dev_health = dm_pool_zalloc(mem, i + 1))) /* Space for health chars */
goto_bad;
s->dev_count = i;
if (sscanf(p, FMTu64 "/" FMTu64, &s->insync_regions, &s->total_regions) != 2)
msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> ";
if (sscanf(params, "%s %u %s " FMTu64 "/" FMTu64,
s->raid_type,
&s->dev_count,
s->dev_health,
&s->insync_regions,
&s->total_regions) != 5)
goto_bad;
/*
@ -137,13 +141,13 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
msg_fields = "<sync_action> and <mismatch_cnt> ";
/* Skip pre-1.5.0 params */
if (!(pp = _skip_fields(params, 4)) || !(p = _skip_fields(pp, 1)))
if (!(p = _skip_fields(params, 4)) || !(pp = _skip_fields(p, 1)))
goto_bad;
if (!(s->sync_action = dm_pool_strndup(mem, pp, p - pp - 1)))
if (!(s->sync_action = dm_pool_zalloc(mem, pp - p)))
goto_bad;
if (sscanf(p, FMTu64, &s->mismatch_count) != 1)
if (sscanf(p, "%s " FMTu64, s->sync_action, &s->mismatch_count) != 2)
goto_bad;
if (num_fields < 7)
@ -162,35 +166,23 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
if (sscanf(p, FMTu64, &s->data_offset) != 1)
goto bad;
/* <journal_char> - 'A' - active write-through journal device.
* - 'a' - active write-back journal device.
* - 'D' - dead journal device.
* - '-' - no journal device.
*/
out:
*status = s;
while (i-- > 0)
if (s->dev_health[i] == 'a')
a++; /* Count number of 'a' */
if (s->insync_regions == s->total_regions) {
/* FIXME: kernel gives misleading info here
* Trying to recognize a true state */
while (i-- > 0)
if (s->dev_health[i] == 'a')
a++; /* Count number of 'a' */
if (a) {
if ((a < s->dev_count) && /* SOME legs are in 'a' */
/* FIXME: kernel gives misleading info here
* Trying to recognize a true state */
(s->insync_regions == s->total_regions) &&
(!strcasecmp(s->sync_action, "recover") ||
!strcasecmp(s->sync_action, "idle"))) {
/* Kernel may possibly start some action
* in near-by future, do not report 100% */
s->insync_regions--;
}
if ((a == s->dev_count) && /* all legs are in 'a' */
(!strcasecmp(s->sync_action, "resync") ||
!strcasecmp(s->sync_action, "idle"))) {
/* Mark 1st. leg in sync */
s->dev_health[0] = 'A';
if (a && a < s->dev_count) {
/* SOME legs are in 'a' */
if (!strcasecmp(s->sync_action, "recover")
|| !strcasecmp(s->sync_action, "idle"))
/* Kernel may possibly start some action
* in near-by future, do not report 100% */
s->insync_regions--;
}
}

View File

@ -77,10 +77,9 @@ enum dm_vdo_write_policy {
struct dm_vdo_target_params {
uint32_t minimum_io_size; // in sectors
uint32_t block_map_cache_size_mb;
union {
uint32_t block_map_era_length; // format period
uint32_t block_map_period; // supported alias
};
uint32_t block_map_era_length; // format period
uint32_t check_point_frequency;
uint32_t index_memory_size_mb; // format
uint32_t slab_size_mb; // format
@ -107,8 +106,6 @@ struct dm_vdo_target_params {
bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
uint64_t vdo_size);
bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks);
//----------------------------------------------------------------
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
@ -15,52 +15,49 @@
#ifndef DEVICE_MAPPER_VDO_LIMITS_H
#define DEVICE_MAPPER_VDO_LIMITS_H
#ifndef SECTOR_SHIFT
#define SECTOR_SHIFT 9L
#endif
#define DM_VDO_BLOCK_SIZE UINT64_C(8) // 4KiB in sectors
#define DM_VDO_BLOCK_SIZE_KB (DM_VDO_BLOCK_SIZE << SECTOR_SHIFT)
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB (128) // 128MiB
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB (16 * 1024 * 1024 - 1) // 16TiB - 1
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_PER_LOGICAL_THREAD (4096 * DM_VDO_BLOCK_SIZE_KB)
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM 1
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM 16380
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM (1)
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM (16380)
#define DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB 256 // 0.25 GiB
#define DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB (256) // 0.25 GiB
#define DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB (1024 * 1024 * 1024) // 1TiB
#define DM_VDO_SLAB_SIZE_MINIMUM_MB 128 // 128MiB
//#define DM_VDO_READ_CACHE_SIZE_MINIMUM_MB (0)
#define DM_VDO_READ_CACHE_SIZE_MAXIMUM_MB (16 * 1024 * 1024 - 1) // 16TiB - 1
#define DM_VDO_SLAB_SIZE_MINIMUM_MB (128) // 128MiB
#define DM_VDO_SLAB_SIZE_MAXIMUM_MB (32 * 1024) // 32GiB
#define DM_VDO_SLABS_MAXIMUM 8192
#define DM_VDO_LOGICAL_SIZE_MAXIMUM (UINT64_C(4) * 1024 * 1024 * 1024 * 1024 * 1024 >> SECTOR_SHIFT) // 4PiB
#define DM_VDO_PHYSICAL_SIZE_MAXIMUM (UINT64_C(64) * DM_VDO_BLOCK_SIZE_KB * 1024 * 1024 * 1024 >> SECTOR_SHIFT) // 256TiB
//#define DM_VDO_LOGICAL_SIZE_MINIMUM_MB (0)
#define DM_VDO_LOGICAL_SIZE_MAXIMUM_MB (UINT64_C(4) * 1024 * 1024 * 1024) // 4PiB
#define DM_VDO_ACK_THREADS_MINIMUM 0
#define DM_VDO_ACK_THREADS_MAXIMUM 100
//#define DM_VDO_ACK_THREADS_MINIMUM (0)
#define DM_VDO_ACK_THREADS_MAXIMUM (100)
#define DM_VDO_BIO_THREADS_MINIMUM 1
#define DM_VDO_BIO_THREADS_MAXIMUM 100
#define DM_VDO_BIO_THREADS_MINIMUM (1)
#define DM_VDO_BIO_THREADS_MAXIMUM (100)
#define DM_VDO_BIO_ROTATION_MINIMUM 1
#define DM_VDO_BIO_ROTATION_MAXIMUM 1024
#define DM_VDO_BIO_ROTATION_MINIMUM (1)
#define DM_VDO_BIO_ROTATION_MAXIMUM (1024)
#define DM_VDO_CPU_THREADS_MINIMUM 1
#define DM_VDO_CPU_THREADS_MAXIMUM 100
#define DM_VDO_CPU_THREADS_MINIMUM (1)
#define DM_VDO_CPU_THREADS_MAXIMUM (100)
#define DM_VDO_HASH_ZONE_THREADS_MINIMUM 0
#define DM_VDO_HASH_ZONE_THREADS_MAXIMUM 100
//#define DM_VDO_HASH_ZONE_THREADS_MINIMUM (0)
#define DM_VDO_HASH_ZONE_THREADS_MAXIMUM (100)
#define DM_VDO_LOGICAL_THREADS_MINIMUM 0
#define DM_VDO_LOGICAL_THREADS_MAXIMUM 60
//#define DM_VDO_LOGICAL_THREADS_MINIMUM (0)
#define DM_VDO_LOGICAL_THREADS_MAXIMUM (100)
#define DM_VDO_PHYSICAL_THREADS_MINIMUM 0
#define DM_VDO_PHYSICAL_THREADS_MAXIMUM 16
//#define DM_VDO_PHYSICAL_THREADS_MINIMUM (0)
#define DM_VDO_PHYSICAL_THREADS_MAXIMUM (16)
#define DM_VDO_MAX_DISCARD_MINIMUM 1
#define DM_VDO_MAX_DISCARD_MAXIMUM (UINT32_MAX / (uint32_t)(DM_VDO_BLOCK_SIZE_KB))
#define DM_VDO_MAX_DISCARD_MINIMUM (1)
#define DM_VDO_MAX_DISCARD_MAXIMUM (UINT32_MAX / 4096)
#endif // DEVICE_MAPPER_VDO_LIMITS_H

View File

@ -1,308 +0,0 @@
/*
* Copyright (C) 2022 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Based on VDO sources: https://github.com/dm-vdo/vdo
*
* Simplified parser of VDO superblock to obtain basic VDO parameteers
*
* TODO: maybe switch to some library in the future
*/
//#define _GNU_SOURCE 1
//#define _LARGEFILE64_SOURCE 1
#include "device_mapper/misc/dmlib.h"
#include "target.h"
#include "lib/mm/xlate.h"
//#include "linux/byteorder/big_endian.h"
//#include "linux/byteorder/little_endian.h"
//#define le32_to_cpu __le32_to_cpu
//#define le64_to_cpu __le64_to_cpu
#include <errno.h>
#include <fcntl.h>
#include <linux/fs.h> /* For block ioctl definitions */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
typedef unsigned char uuid_t[16];
#define __packed __attribute__((packed))
static const char _MAGIC_NUMBER[] = "dmvdo001";
#define MAGIC_NUMBER_SIZE (sizeof(_MAGIC_NUMBER) - 1)
struct vdo_version_number {
uint32_t major_version;
uint32_t minor_version;
} __packed;
/*
* The registry of component ids for use in headers
*/
enum {
SUPER_BLOCK = 0,
FIXED_LAYOUT = 1,
RECOVERY_JOURNAL = 2,
SLAB_DEPOT = 3,
BLOCK_MAP = 4,
GEOMETRY_BLOCK = 5,
}; /* ComponentID */
struct vdo_header {
uint32_t id; /* The component this is a header for */
struct vdo_version_number version; /* The version of the data format */
size_t size; /* The size of the data following this header */
} __packed;
struct vdo_geometry_block {
char magic_number[MAGIC_NUMBER_SIZE];
struct vdo_header header;
uint32_t checksum;
} __packed;
struct vdo_config {
uint64_t logical_blocks; /* number of logical blocks */
uint64_t physical_blocks; /* number of physical blocks */
uint64_t slab_size; /* number of blocks in a slab */
uint64_t recovery_journal_size; /* number of recovery journal blocks */
uint64_t slab_journal_blocks; /* number of slab journal blocks */
} __packed;
struct vdo_component_41_0 {
uint32_t state;
uint64_t complete_recoveries;
uint64_t read_only_recoveries;
struct vdo_config config; /* packed */
uint64_t nonce;
} __packed;
enum vdo_volume_region_id {
VDO_INDEX_REGION = 0,
VDO_DATA_REGION = 1,
VDO_VOLUME_REGION_COUNT,
};
struct vdo_volume_region {
/* The ID of the region */
enum vdo_volume_region_id id;
/*
* The absolute starting offset on the device. The region continues
* until the next region begins.
*/
uint64_t start_block;
} __packed;
struct vdo_index_config {
uint32_t mem;
uint32_t unused;
uint8_t sparse;
} __packed;
struct vdo_volume_geometry {
uint32_t release_version;
uint64_t nonce;
uuid_t uuid;
uint64_t bio_offset;
struct vdo_volume_region regions[VDO_VOLUME_REGION_COUNT];
struct vdo_index_config index_config;
} __packed;
struct vdo_volume_geometry_4 {
uint32_t release_version;
uint64_t nonce;
uuid_t uuid;
struct vdo_volume_region regions[VDO_VOLUME_REGION_COUNT];
struct vdo_index_config index_config;
} __packed;
/* Decoding mostly only some used stucture members */
static void _vdo_decode_version(struct vdo_version_number *v)
{
v->major_version = le32_to_cpu(v->major_version);
v->minor_version = le32_to_cpu(v->minor_version);
}
static void _vdo_decode_header(struct vdo_header *h)
{
h->id = le32_to_cpu(h->id);
_vdo_decode_version(&h->version);
h->size = le64_to_cpu(h->size);
}
static void _vdo_decode_geometry_region(struct vdo_volume_region *vr)
{
vr->id = le32_to_cpu(vr->id);
vr->start_block = le64_to_cpu(vr->start_block);
}
static void _vdo_decode_volume_geometry(struct vdo_volume_geometry *vg)
{
vg->release_version = le32_to_cpu(vg->release_version);
vg->nonce = le64_to_cpu(vg->nonce);
vg->bio_offset = le64_to_cpu(vg->bio_offset);
_vdo_decode_geometry_region(&vg->regions[VDO_DATA_REGION]);
}
static void _vdo_decode_volume_geometry_4(struct vdo_volume_geometry *vg,
struct vdo_volume_geometry_4 *vg_4)
{
vg->release_version = le32_to_cpu(vg_4->release_version);
vg->nonce = le64_to_cpu(vg_4->nonce);
vg->bio_offset = 0;
vg->regions[VDO_DATA_REGION] = vg_4->regions[VDO_DATA_REGION];
_vdo_decode_geometry_region(&vg->regions[VDO_DATA_REGION]);
}
static void _vdo_decode_config(struct vdo_config *vc)
{
vc->logical_blocks = le64_to_cpu(vc->logical_blocks);
vc->physical_blocks = le64_to_cpu(vc->physical_blocks);
vc->slab_size = le64_to_cpu(vc->slab_size);
vc->recovery_journal_size = le64_to_cpu(vc->recovery_journal_size);
vc->slab_journal_blocks = le64_to_cpu(vc->slab_journal_blocks);
}
static void _vdo_decode_pvc(struct vdo_component_41_0 *pvc)
{
_vdo_decode_config(&pvc->config);
pvc->nonce = le64_to_cpu(pvc->nonce);
}
bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)
{
char buffer[4096];
int fh;
bool r = false;
struct stat st;
uint64_t size;
uint64_t regpos;
struct vdo_header h;
struct vdo_version_number vn;
struct vdo_volume_geometry vg;
struct vdo_volume_geometry_4 vg_4;
struct vdo_component_41_0 pvc;
*logical_blocks = 0;
if ((fh = open(vdo_path, O_RDONLY)) == -1) {
log_sys_debug("Failed to open VDO backend %s.", vdo_path);
return false;
}
if (ioctl(fh, BLKGETSIZE64, &size) == -1) {
if (errno != ENOTTY) {
log_sys_debug("ioctl", vdo_path);
goto err;
}
/* lets retry for file sizes */
if (fstat(fh, &st) < 0) {
log_sys_debug("fstat", vdo_path);
goto err;
}
size = st.st_size;
}
if (read(fh, buffer, sizeof(buffer)) < 0) {
log_sys_debug("read", vdo_path);
goto err;
}
if (strncmp(buffer, _MAGIC_NUMBER, MAGIC_NUMBER_SIZE)) {
log_debug_activation("Found mismatching VDO magic header in %s.", vdo_path);
goto err;
}
memcpy(&h, buffer + MAGIC_NUMBER_SIZE, sizeof(h));
_vdo_decode_header(&h);
if (h.id != 5) {
log_debug_activation("Expected geometry VDO block instead of block %u.", h.id);
goto err;
}
switch (h.version.major_version) {
case 4:
memcpy(&vg_4, buffer + MAGIC_NUMBER_SIZE + sizeof(h), sizeof(vg_4));
_vdo_decode_volume_geometry_4(&vg, &vg_4);
break;
case 5:
memcpy(&vg, buffer + MAGIC_NUMBER_SIZE + sizeof(h), sizeof(vg));
_vdo_decode_volume_geometry(&vg);
break;
default:
log_debug_activation("Unsupported VDO version %u.%u.", h.version.major_version, h.version.minor_version);
goto err;
}
regpos = (vg.regions[VDO_DATA_REGION].start_block - vg.bio_offset) * 4096;
if ((regpos + sizeof(buffer)) > size) {
log_debug_activation("File/Device is shorter and can't provide requested VDO volume region at " FMTu64 " > " FMTu64 ".", regpos, size);
goto err;
}
if (lseek(fh, regpos, SEEK_SET) < 0) {
log_sys_debug("lseek", vdo_path);
goto err;
}
if (read(fh, buffer, sizeof(buffer)) < 0) {
log_sys_debug("read", vdo_path);
goto err;
}
memcpy(&vn, buffer + sizeof(struct vdo_geometry_block), sizeof(vn));
_vdo_decode_version(&vn);
if (vn.major_version > 41) {
log_debug_activation("Unknown VDO component version %u.", vn.major_version); // should be 41!
goto err;
}
memcpy(&pvc, buffer + sizeof(struct vdo_geometry_block) + sizeof(vn), sizeof(pvc));
_vdo_decode_pvc(&pvc);
if (pvc.nonce != vg.nonce) {
log_debug_activation("VDO metadata has mismatching VDO nonces " FMTu64 " != " FMTu64 ".", pvc.nonce, vg.nonce);
goto err;
}
#if 0
log_debug_activation("LogBlocks " FMTu64 ".", pvc.config.logical_blocks);
log_debug_activation("PhyBlocks " FMTu64 ".", pvc.config.physical_blocks);
log_debug_activation("SlabSize " FMTu64 ".", pvc.config.slab_size);
log_debug_activation("RecJourSize " FMTu64 ".", pvc.config.recovery_journal_size);
log_debug_activation("SlabJouSize " FMTu64 ".", pvc.config.slab_journal_blocks);
#endif
*logical_blocks = pvc.config.logical_blocks;
r = true;
err:
(void) close(fh);
return r;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@ -18,117 +18,82 @@
#include "vdo_limits.h"
#include "target.h"
/* validate vdo target parameters and 'vdo_size' in sectors */
bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
uint64_t vdo_size)
{
bool valid = true;
/* 512 or 4096 bytes only ATM */
if ((vtp->minimum_io_size != (512 >> SECTOR_SHIFT)) &&
(vtp->minimum_io_size != (4096 >> SECTOR_SHIFT))) {
log_error("VDO minimum io size %u is unsupported [512, 4096].",
if ((vtp->minimum_io_size != 1) &&
(vtp->minimum_io_size != 8)) {
log_error("VDO minimum io size %u is unsupported.",
vtp->minimum_io_size);
valid = false;
}
if ((vtp->block_map_cache_size_mb < DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB) ||
(vtp->block_map_cache_size_mb > DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB)) {
log_error("VDO block map cache size %u MiB is out of range [%u..%u].",
vtp->block_map_cache_size_mb,
DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB,
DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB);
valid = false;
}
if ((vtp->block_map_era_length < DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM) ||
(vtp->block_map_era_length > DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM)) {
log_error("VDO block map era length %u is out of range [%u..%u].",
vtp->block_map_era_length,
DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM,
DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM);
log_error("VDO block map cache size %u out of range.",
vtp->block_map_cache_size_mb);
valid = false;
}
if ((vtp->index_memory_size_mb < DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB) ||
(vtp->index_memory_size_mb > DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB)) {
log_error("VDO index memory size %u MiB is out of range [%u..%u].",
vtp->index_memory_size_mb,
DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB,
DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB);
log_error("VDO index memory size %u out of range.",
vtp->index_memory_size_mb);
valid = false;
}
if ((vtp->slab_size_mb < DM_VDO_SLAB_SIZE_MINIMUM_MB) ||
(vtp->slab_size_mb > DM_VDO_SLAB_SIZE_MAXIMUM_MB)) {
log_error("VDO slab size %u MiB is out of range [%u..%u].",
vtp->slab_size_mb,
DM_VDO_SLAB_SIZE_MINIMUM_MB,
DM_VDO_SLAB_SIZE_MAXIMUM_MB);
log_error("VDO slab size %u out of range.",
vtp->slab_size_mb);
valid = false;
}
if ((vtp->max_discard < DM_VDO_MAX_DISCARD_MINIMUM) ||
(vtp->max_discard > DM_VDO_MAX_DISCARD_MAXIMUM)) {
log_error("VDO max discard %u is out of range [%u..%u].",
vtp->max_discard,
DM_VDO_MAX_DISCARD_MINIMUM,
DM_VDO_MAX_DISCARD_MAXIMUM);
log_error("VDO max discard %u out of range.",
vtp->max_discard);
valid = false;
}
if (vtp->ack_threads > DM_VDO_ACK_THREADS_MAXIMUM) {
log_error("VDO ack threads %u is out of range [0..%u].",
vtp->ack_threads,
DM_VDO_ACK_THREADS_MAXIMUM);
log_error("VDO ack threads %u out of range.", vtp->ack_threads);
valid = false;
}
if ((vtp->bio_threads < DM_VDO_BIO_THREADS_MINIMUM) ||
(vtp->bio_threads > DM_VDO_BIO_THREADS_MAXIMUM)) {
log_error("VDO bio threads %u is out of range [%u..%u].",
vtp->bio_threads,
DM_VDO_BIO_THREADS_MINIMUM,
DM_VDO_BIO_THREADS_MAXIMUM);
log_error("VDO bio threads %u out of range.", vtp->bio_threads);
valid = false;
}
if ((vtp->bio_rotation < DM_VDO_BIO_ROTATION_MINIMUM) ||
(vtp->bio_rotation > DM_VDO_BIO_ROTATION_MAXIMUM)) {
log_error("VDO bio rotation %u is out of range [%u..%u].",
vtp->bio_rotation,
DM_VDO_BIO_ROTATION_MINIMUM,
DM_VDO_BIO_ROTATION_MAXIMUM);
log_error("VDO bio rotation %u out of range.", vtp->bio_rotation);
valid = false;
}
if ((vtp->cpu_threads < DM_VDO_CPU_THREADS_MINIMUM) ||
(vtp->cpu_threads > DM_VDO_CPU_THREADS_MAXIMUM)) {
log_error("VDO cpu threads %u is out of range [%u..%u].",
vtp->cpu_threads,
DM_VDO_CPU_THREADS_MINIMUM,
DM_VDO_CPU_THREADS_MAXIMUM);
log_error("VDO cpu threads %u out of range.", vtp->cpu_threads);
valid = false;
}
if (vtp->hash_zone_threads > DM_VDO_HASH_ZONE_THREADS_MAXIMUM) {
log_error("VDO hash zone threads %u is out of range [0..%u].",
vtp->hash_zone_threads,
DM_VDO_HASH_ZONE_THREADS_MAXIMUM);
log_error("VDO hash zone threads %u out of range.", vtp->hash_zone_threads);
valid = false;
}
if (vtp->logical_threads > DM_VDO_LOGICAL_THREADS_MAXIMUM) {
log_error("VDO logical threads %u is out of range [0..%u].",
vtp->logical_threads,
DM_VDO_LOGICAL_THREADS_MAXIMUM);
log_error("VDO logical threads %u out of range.", vtp->logical_threads);
valid = false;
}
if (vtp->physical_threads > DM_VDO_PHYSICAL_THREADS_MAXIMUM) {
log_error("VDO physical threads %u is out of range [0..%u].",
vtp->physical_threads,
DM_VDO_PHYSICAL_THREADS_MAXIMUM);
log_error("VDO physical threads %u out of range.", vtp->physical_threads);
valid = false;
}
@ -155,10 +120,10 @@ bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
valid = false;
}
if (vdo_size > DM_VDO_LOGICAL_SIZE_MAXIMUM) {
log_error("VDO logical size is larger than limit " FMTu64 " TiB by " FMTu64 " KiB.",
DM_VDO_LOGICAL_SIZE_MAXIMUM / (UINT64_C(1024) * 1024 * 1024 * 1024 >> SECTOR_SHIFT),
(vdo_size - DM_VDO_LOGICAL_SIZE_MAXIMUM) / 2);
if (vdo_size >= (DM_VDO_LOGICAL_SIZE_MAXIMUM_MB * UINT64_C(1024 * 2))) {
log_error("VDO logical size is by " FMTu64 "KiB bigger then limit " FMTu64 "TiB.",
(vdo_size - (DM_VDO_LOGICAL_SIZE_MAXIMUM_MB * UINT64_C(1024 * 2))) / 2,
DM_VDO_LOGICAL_SIZE_MAXIMUM_MB / UINT64_C(1024) / UINT64_C(1024));
valid = false;
}

View File

@ -67,7 +67,7 @@ the entries (each hotspot block covers a larger area than a single
cache block).
All this means smq uses ~25bytes per cache block. Still a lot of
memory, but a substantial improvement nonetheless.
memory, but a substantial improvement nontheless.
Level balancing:
mq placed entries in different levels of the multiqueue structures

View File

@ -35,7 +35,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
capi:authenc(hmac(sha256),xts(aes))-random
capi:rfc7539(chacha20,poly1305)-random
The /proc/crypto contains a list of currently loaded crypto modes.
The /proc/crypto contains a list of curently loaded crypto modes.
<key>
Key used for encryption. It is encoded either as a hexadecimal number
@ -81,7 +81,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
<#opt_params>
Number of optional parameters. If there are no optional parameters,
the optional parameters section can be skipped or #opt_params can be zero.
the optional paramaters section can be skipped or #opt_params can be zero.
Otherwise #opt_params is the number of following arguments.
Example of optional parameters section:

View File

@ -120,7 +120,7 @@ journal_crypt:algorithm(:key) (the key is optional)
"salsa20", "ctr(aes)" or "ecb(arc4)").
The journal contains history of last writes to the block device,
an attacker reading the journal could see the last sector numbers
an attacker reading the journal could see the last sector nubmers
that were written. From the sector numbers, the attacker can infer
the size of files that were written. To protect against this
situation, you can encrypt the journal.

View File

@ -65,7 +65,7 @@ Construction Parameters
<#opt_params>
Number of optional parameters. If there are no optional parameters,
the optional parameters section can be skipped or #opt_params can be zero.
the optional paramaters section can be skipped or #opt_params can be zero.
Otherwise #opt_params is the number of following arguments.
Example of optional parameters section:

View File

@ -37,7 +37,7 @@ segment type. The available RAID types are:
"raid6_nr" - RAID6 Rotating parity N with data restart
"raid6_nc" - RAID6 Rotating parity N with data continuation
The exception to 'no shorthand options' will be where the RAID implementations
can displace traditional targets. This is the case with 'mirror' and 'raid1'.
can displace traditional tagets. This is the case with 'mirror' and 'raid1'.
In this case, "mirror_segtype_default" - found under the "global" section in
lvm.conf - can be set to "mirror" or "raid1". The segment type inferred when
the '-m' option is used will be taken from this setting. The default segment
@ -104,7 +104,7 @@ and 4 devices for RAID 6/10.
lvconvert should work exactly as it does now when dealing with mirrors -
even if(when) we switch to MD RAID1. Of course, there are no plans to
allow the presence of the metadata area to be configurable (e.g. --corelog).
allow the presense of the metadata area to be configurable (e.g. --corelog).
It will be simple enough to detect if the LV being up/down-converted is
new or old-style mirroring.
@ -120,7 +120,7 @@ RAID4 to RAID5 or RAID5 to RAID6.
Line 02/03/04:
These are familiar options - all of which would now be available as options
for change. (However, it'd be nice if we didn't have regionsize in there.
It's simple on the kernel side, but is just an extra - often unnecessary -
It's simple on the kernel side, but is just an extra - often unecessary -
parameter to many functions in the LVM codebase.)
Line 05:
@ -375,8 +375,8 @@ the slot. Even the names of the images will be renamed to properly reflect
their index in the array. Unlike the "mirror" segment type, you will never have
an image named "*_rimage_1" occupying the index position 0.
As with adding images, removing images holds off on committing LVM metadata
until all possible changes have been made. This reduces the likelihood of bad
As with adding images, removing images holds off on commiting LVM metadata
until all possible changes have been made. This reduces the likelyhood of bad
intermediate stages being left due to a failure of operation or machine crash.
RAID1 '--splitmirrors', '--trackchanges', and '--merge' operations

View File

@ -87,7 +87,7 @@ are as follows:
/etc/lvm/lvm.conf. Once this operation is complete, the logical volumes
will be consistent. However, the volume group will still be inconsistent -
due to the refernced-but-missing device/PV - and operations will still be
restricted to the aforementioned actions until either the device is
restricted to the aformentioned actions until either the device is
restored or 'vgreduce --removemissing' is run.
Device Revival (transient failures):
@ -135,9 +135,9 @@ If a mirror is not 'in-sync', a read failure will produce an I/O error.
This error will propagate all the way up to the applications above the
logical volume (e.g. the file system). No automatic intervention will
take place in this case either. It is up to the user to decide what
can be done/salvaged in this scenario. If the user is confident that the
can be done/salvaged in this senario. If the user is confident that the
images of the mirror are the same (or they are willing to simply attempt
to retrieve whatever data they can), 'lvconvert' can be used to eliminate
to retreive whatever data they can), 'lvconvert' can be used to eliminate
the failed image and proceed.
Mirror resynchronization errors:
@ -191,11 +191,11 @@ command are set in the LVM configuration file. They are:
3-way mirror fails, the mirror will be converted to a 2-way mirror.
The "allocate" policy takes the further action of trying to replace
the failed image using space that is available in the volume group.
Replacing a failed mirror image will incur the cost of
Replacing a failed mirror image will incure the cost of
resynchronizing - degrading the performance of the mirror. The
default policy for handling an image failure is "remove". This
allows the mirror to still function, but gives the administrator the
choice of when to incur the extra performance costs of replacing
choice of when to incure the extra performance costs of replacing
the failed image.
RAID logical volume device failures are handled differently from the "mirror"

View File

@ -63,7 +63,7 @@ classical snapshot merge, thin snapshot merge.
The second store is suited only for pvmove --abort operations in-progress. Both
stores are independent and identical LVs (pvmove /dev/sda3 and pvmove --abort /dev/sda3)
can be run concurrently from lvmpolld point of view (on lvm2 side the consistency is
can be run concurently from lvmpolld point of view (on lvm2 side the consistency is
guaranteed by lvm2 locking mechanism).
Locking order

View File

@ -126,7 +126,7 @@ Usage Examples
followed by 'vgchange -ay vg2'
Option (ii) - localised admin & configuration
Option (ii) - localised admin & configuation
(i.e. each host holds *locally* which classes of volumes to activate)
# Add @database tag to vg1's metadata
vgchange --addtag @database vg1

View File

@ -35,7 +35,7 @@ VGs from PVs as they appear, and at the same time collect information on what is
already available. A command, pvscan --cache is expected to be used to
implement udev rules. It is relatively easy to make this command print out a
list of VGs (and possibly LVs) that have been made available by adding any
particular device to the set of visible devices. In other words, udev says "hey,
particular device to the set of visible devices. In othe words, udev says "hey,
/dev/sdb just appeared", calls pvscan --cache, which talks to lvmetad, which
says "cool, that makes vg0 complete". Pvscan takes this info and prints it out,
and the udev rule can then somehow decide whether anything needs to be done

View File

@ -1,6 +1,6 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2023 Red Hat, Inc. All rights reserved.
# Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@ -18,23 +18,8 @@ top_builddir = @top_builddir@
include $(top_builddir)/make.tmpl
.DELETE_ON_ERROR:
cmds.h: $(top_srcdir)/tools/command-lines.in $(top_srcdir)/tools/license.inc Makefile
@echo " [GEN] $@"
$(Q) \
( cat $(top_srcdir)/tools/license.inc && \
echo "/* Do not edit. This file is generated by the Makefile. */" && \
echo "cmd(CMD_NONE, none)" && \
trap "$(RM) $@-t" EXIT INT QUIT TERM && \
$(AWK) '/^ID:/ {print "cmd(" $$2 "_CMD, " $$2 ")"}' $< >$@-t && \
LC_ALL=C $(SORT) -u $@-t && \
echo "cmd(CMD_COUNT, count)" \
) > $@
all: cmds.h
DISTCLEAN_TARGETS += configure.h lvm-version.h
CLEAN_TARGETS += cmds.h cmds.h-t \
CLEAN_TARGETS += \
.symlinks \
.symlinks_created \
activate.h \
@ -86,8 +71,6 @@ CLEAN_TARGETS += cmds.h cmds.h-t \
lvm2app.h \
lvm2cmd.h \
lvmcache.h \
lvmetad-client.h \
lvmetad.h \
lvmlockd-client.h \
lvmlockd.h \
lvmnotify.h \
@ -116,5 +99,4 @@ CLEAN_TARGETS += cmds.h cmds.h-t \
util.h \
uuid.h \
vg.h \
xlate.h \
cmds.h
xlate.h

View File

@ -25,13 +25,18 @@
/* The path to 'cache_restore', if available. */
#undef CACHE_RESTORE_CMD
/* Define to 1 if the `closedir' function returns void instead of int. */
/* Define to 1 if the `closedir' function returns void instead of `int'. */
#undef CLOSEDIR_VOID
/* Path to cmirrord pidfile. */
#undef CMIRRORD_PIDFILE
/* Define to 1 if using 'alloca.c'. */
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
systems. This function is required for `alloca.c' support on those systems.
*/
#undef CRAY_STACKSEG_END
/* Define to 1 if using `alloca.c'. */
#undef C_ALLOCA
/* Name of default metadata archive subdirectory. */
@ -43,9 +48,6 @@
/* Name of default metadata cache subdirectory. */
#undef DEFAULT_CACHE_SUBDIR
/* Path to exit-on dmeventd file. */
#undef DEFAULT_DMEVENTD_EXIT_ON_PATH
/* Define default node creation behavior with dmsetup create */
#undef DEFAULT_DM_ADD_NODE
@ -88,7 +90,7 @@
/* Use blkid wiping by default. */
#undef DEFAULT_USE_BLKID_WIPING
/* Default for lvm.conf use_devicesfile. */
/* Default for lvm.conf use_devicefile. */
#undef DEFAULT_USE_DEVICES_FILE
/* Use lvmlockd by default. */
@ -112,6 +114,9 @@
/* Define to 1 to enable the device-mapper filemap daemon. */
#undef DMFILEMAPD
/* Define to enable compat protocol */
#undef DM_COMPAT
/* Define default group for device node */
#undef DM_DEVICE_GID
@ -139,10 +144,11 @@
/* Define to 1 if you have the `alarm' function. */
#undef HAVE_ALARM
/* Define to 1 if you have 'alloca', as a function or macro. */
/* Define to 1 if you have `alloca', as a function or macro. */
#undef HAVE_ALLOCA
/* Define to 1 if <alloca.h> works. */
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
*/
#undef HAVE_ALLOCA_H
/* Define to 1 if you have the <arpa/inet.h> header file. */
@ -157,9 +163,6 @@
/* Define to 1 if you have the `atexit' function. */
#undef HAVE_ATEXIT
/* Define if blkid.h has BLKID_SUBLKS_FSINFO */
#undef HAVE_BLKID_SUBLKS_FSINFO
/* Define if ioctl BLKZEROOUT can be used for device zeroing. */
#undef HAVE_BLKZEROOUT
@ -273,9 +276,6 @@
/* Define to 1 if you have the <machine/endian.h> header file. */
#undef HAVE_MACHINE_ENDIAN_H
/* Define to 1 if you have the `mallinfo2' function. */
#undef HAVE_MALLINFO2
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#undef HAVE_MALLOC
@ -286,6 +286,9 @@
/* Define to 1 if you have the `memchr' function. */
#undef HAVE_MEMCHR
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `memset' function. */
#undef HAVE_MEMSET
@ -402,7 +405,7 @@
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define if you have `strerror_r'. */
/* Define to 1 if you have the `strerror_r' function. */
#undef HAVE_STRERROR_R
/* Define to 1 if you have the <strings.h> header file. */
@ -604,9 +607,6 @@
/* Path to lvm binary. */
#undef LVM_PATH
/* Path to lvresize_fs_helper script. */
#undef LVRESIZE_FS_HELPER_PATH
/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
*/
#undef MAJOR_IN_MKDEV
@ -651,6 +651,9 @@
/* Define to 1 to include the LVM readline shell. */
#undef READLINE_SUPPORT
/* Define as the return type of signal handlers (`int' or `void'). */
#undef RETSIGTYPE
/* Define to 1 to include built-in support for snapshots. */
#undef SNAPSHOT_INTERNAL
@ -662,9 +665,7 @@
STACK_DIRECTION = 0 => direction of growth unknown */
#undef STACK_DIRECTION
/* Define to 1 if all of the C90 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if strerror_r returns char *. */
@ -695,10 +696,13 @@
/* The path to 'thin_restore', if available. */
#undef THIN_RESTORE_CMD
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
/* Define to 1 to enable synchronization with udev processing. */
/* Define to 1 to enable synchronisation with udev processing. */
#undef UDEV_SYNC_SUPPORT
/* Enable a valgrind aware build of pool */
@ -771,7 +775,7 @@
/* Define to `long int' if <sys/types.h> does not define. */
#undef off_t
/* Define as a signed integer type capable of holding a process identifier. */
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
/* Define to rpl_realloc if the replacement function should be used. */

View File

@ -40,10 +40,6 @@ SOURCES =\
device/dev-luks.c \
device/dev-dasd.c \
device/dev-lvm1-pool.c \
device/filesystem.c \
device/online.c \
device/parse_vpd.c \
device/dev_util.c \
display/display.c \
error/errseg.c \
unknown/unknown.c \
@ -57,6 +53,7 @@ SOURCES =\
filters/filter-partitioned.c \
filters/filter-type.c \
filters/filter-usable.c \
filters/filter-internal.c \
filters/filter-signature.c \
filters/filter-deviceid.c \
format_text/archive.c \

View File

@ -322,11 +322,6 @@ int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent)
{
return 0;
}
int lv_vdo_pool_size_config(const struct logical_volume *lv,
struct vdo_pool_size_config *cfg)
{
return 0;
}
int lvs_in_vg_activated(const struct volume_group *vg)
{
return 0;
@ -418,7 +413,7 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
{
return 0;
}
int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usable_check_params check, int *is_lv)
int device_is_usable(struct device *dev, struct dev_usable_check_params check, int *is_lv)
{
return 0;
}
@ -491,20 +486,12 @@ int library_version(char *version, size_t size)
int driver_version(char *version, size_t size)
{
static char _vsn[80] = { 0 };
if (!activation())
return 0;
log_very_verbose("Getting driver version");
if (!_vsn[0] &&
!dm_driver_version(_vsn, sizeof(_vsn)))
return_0;
(void) dm_strncpy(version, _vsn, size);
return 1;
return dm_driver_version(version, size);
}
int target_version(const char *target_name, uint32_t *maj,
@ -629,15 +616,6 @@ int target_present(struct cmd_context *cmd, const char *target_name,
&maj, &min, &patchlevel);
}
int get_device_list(const struct volume_group *vg, struct dm_list **devs,
unsigned *devs_features)
{
if (!activation())
return 0;
return dev_manager_get_device_list(NULL, devs, devs_features);
}
/*
* When '*info' is NULL, returns 1 only when LV is active.
* When '*info' != NULL, returns 1 when info structure is populated.
@ -1368,32 +1346,6 @@ int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent)
return 1;
}
/*
* lv_vdo_pool_size_config obtains size configuration from active VDO table line
*
* If the 'params' string has been already retrieved, use it.
* If the mempool already exists, use it.
*
*/
int lv_vdo_pool_size_config(const struct logical_volume *lv,
struct vdo_pool_size_config *cfg)
{
struct dev_manager *dm;
int r;
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
return 1; /* Inactive VDO pool -> no runtime config */
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, !lv_is_pvmove(lv))))
return_0;
r = dev_manager_vdo_pool_size_config(dm, lv, cfg);
dev_manager_destroy(dm);
return r;
}
static int _lv_active(struct cmd_context *cmd, const struct logical_volume *lv)
{
struct lvinfo info;
@ -2172,11 +2124,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
* TODO: Relax this limiting condition further */
if (!flush_required &&
(lv_is_pvmove(lv) || pvmove_lv ||
(!lv_is_mirror(lv) &&
!lv_is_thin_volume(lv) &&
!lv_is_thin_pool(lv) &&
!lv_is_vdo(lv) &&
!lv_is_vdo_pool(lv)))) {
(!lv_is_mirror(lv) && !lv_is_thin_pool(lv) && !lv_is_thin_volume(lv)))) {
log_debug("Requiring flush for LV %s.", display_lvname(lv));
flush_required = 1;
}
@ -2426,7 +2374,6 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
static const struct lv_activate_opts laopts = { .skip_in_use = 1 };
struct dm_list *snh;
int r = 0;
unsigned tmp_state;
if (!activation())
return 1;
@ -2499,17 +2446,12 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
}
critical_section_dec(cmd, "deactivated");
tmp_state = cmd->disable_dm_devs;
cmd->disable_dm_devs = 1;
if (!lv_info(cmd, lv, 0, &info, 0, 0) || info.exists) {
/* Turn into log_error, but we do not log error */
log_debug_activation("Deactivated volume is still %s present.",
display_lvname(lv));
r = 0;
}
cmd->disable_dm_devs = tmp_state;
out:
return r;
@ -2555,7 +2497,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
lv_is_partial(lv) && lv_is_raid(lv) && lv_raid_has_integrity((struct logical_volume *)lv)) {
cmd->partial_activation = 0;
cmd->degraded_activation = 0;
log_print_unless_silent("No degraded or partial activation for raid with integrity.");
log_print("No degraded or partial activation for raid with integrity.");
}
if ((!lv->vg->cmd->partial_activation) && lv_is_partial(lv)) {
@ -2605,8 +2547,6 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
if (!lv_is_visible(lv) && lv_is_component(lv)) {
laopts->read_only = 1;
laopts->component_lv = lv;
} else if (lv_is_pool_metadata_spare(lv)) {
laopts->component_lv = lv;
} else if (filter)
laopts->read_only = _passes_readonly_filter(cmd, lv);
@ -2723,16 +2663,16 @@ static int _remove_dm_dev_by_name(const char *name)
/* Work all segments of @lv removing any existing, closed "*-missing_N_0" sub devices. */
static int _lv_remove_any_missing_subdevs(struct logical_volume *lv)
{
char name[NAME_LEN];
struct lv_segment *seg;
uint32_t seg_no = 0;
if (lv) {
uint32_t seg_no = 0;
char name[257];
struct lv_segment *seg;
dm_list_iterate_items(seg, &lv->segments) {
if (dm_snprintf(name, sizeof(name), "%s-%s-missing_%u_0", seg->lv->vg->name, seg->lv->name, seg_no) < 0)
return_0;
if (!_remove_dm_dev_by_name(name))
return_0;
return 0;
seg_no++;
}
@ -2750,10 +2690,10 @@ int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv)
for (s = 0; s < seg->area_count; s++) {
if (seg_type(seg, s) == AREA_LV &&
!_lv_remove_any_missing_subdevs(seg_lv(seg, s)))
return_0;
return 0;
if (seg->meta_areas && seg_metatype(seg, s) == AREA_LV &&
!_lv_remove_any_missing_subdevs(seg_metalv(seg, s)))
return_0;
return 0;
}
return 1;
@ -2797,7 +2737,7 @@ static int _component_cb(struct logical_volume *lv, void *data)
if (lv_is_locked(lv) || lv_is_pvmove(lv) ||/* ignoring */
/* thin-pool is special and it's using layered device */
(lv_is_thin_pool(lv) && thin_pool_is_active(lv)))
(lv_is_thin_pool(lv) && pool_is_active(lv)))
return -1;
/* External origin is activated through thinLV and uses -real suffix.

View File

@ -106,10 +106,6 @@ int target_present(struct cmd_context *cmd, const char *target_name,
int use_modprobe);
int target_version(const char *target_name, uint32_t *maj,
uint32_t *min, uint32_t *patchlevel);
int get_device_list(const struct volume_group *vg, struct dm_list **devs,
unsigned *devs_features);
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype);
int lvm_dm_prefix_check(int major, int minor, const char *prefix);
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
@ -204,8 +200,6 @@ int lv_thin_pool_status(const struct logical_volume *lv, int flush,
int lv_vdo_pool_status(const struct logical_volume *lv, int flush,
struct lv_status_vdo **status);
int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent);
int lv_vdo_pool_size_config(const struct logical_volume *lv,
struct vdo_pool_size_config *cfg);
/*
* Return number of LVs in the VG that are active.
@ -260,7 +254,7 @@ struct dev_usable_check_params {
* Returns 1 if mapped device is not suspended, blocked or
* is using a reserved name.
*/
int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usable_check_params check, int *is_lv);
int device_is_usable(struct device *dev, struct dev_usable_check_params check, int *is_lv);
/*
* Declaration moved here from fs.h to keep header fs.h hidden

View File

@ -107,8 +107,6 @@ static struct dm_task *_setup_task_run(int task, struct dm_info *info,
int with_flush,
int query_inactive)
{
char vsn[80];
unsigned maj, min;
struct dm_task *dmt;
if (!(dmt = dm_task_create(task)))
@ -140,20 +138,8 @@ static struct dm_task *_setup_task_run(int task, struct dm_info *info,
if (!with_flush && !dm_task_no_flush(dmt))
log_warn("WARNING: Failed to set no_flush.");
switch (task) {
case DM_DEVICE_TARGET_MSG:
if (task == DM_DEVICE_TARGET_MSG)
return dmt; /* TARGET_MSG needs more local tweaking before task_run() */
case DM_DEVICE_LIST:
/* Use 'newuuid' only with DM version that supports it */
if (driver_version(vsn, sizeof(vsn)) &&
(sscanf(vsn, "%u.%u", &maj, &min) == 2) &&
(maj == 4 ? min >= 19 : maj > 4) &&
!dm_task_set_newuuid(dmt, " ")) // new uuid has no meaning here
log_warn("WARNING: Failed to query uuid with LIST.");
break;
default:
break;
}
if (!dm_task_run(dmt))
goto_out;
@ -204,7 +190,7 @@ static int _get_segment_status_from_target_params(const char *target_name,
/* If kernel's type isn't an exact match is it compatible? */
(!segtype->ops->target_status_compatible ||
!segtype->ops->target_status_compatible(target_name))) {
log_warn("WARNING: Detected %s segment type does not match expected type %s for %s.",
log_warn(INTERNAL_ERROR "WARNING: Segment type %s found does not match expected type %s for %s.",
target_name, segtype->name, display_lvname(seg_status->seg->lv));
return 0;
}
@ -277,7 +263,7 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
int dmtask;
int with_flush; /* TODO: arg for _info_run */
void *target = NULL;
uint64_t target_start, target_length, start, extent_size, length, length_crop = 0;
uint64_t target_start, target_length, start, length, length_crop = 0;
char *target_name, *target_params;
const char *devname;
@ -306,8 +292,8 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
/* Query status only for active device */
if (seg_status && dminfo->exists) {
extent_size = length = seg_status->seg->lv->vg->extent_size;
start = extent_size * seg_status->seg->le;
start = length = seg_status->seg->lv->vg->extent_size;
start *= seg_status->seg->le;
length *= _seg_len(seg_status->seg);
/* Uses max DM_THIN_MAX_METADATA_SIZE sectors for metadata device */
@ -328,8 +314,6 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
if ((start == target_start) &&
((length == target_length) ||
((lv_is_vdo_pool(seg_status->seg->lv)) && /* should fit within extent size */
(length < target_length) && ((length + extent_size) > target_length)) ||
(length_crop && (length_crop == target_length))))
break; /* Keep target_params when matching segment is found */
@ -375,8 +359,7 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
*
* Returns: 1 if mirror should be ignored, 0 if safe to use
*/
static int _ignore_blocked_mirror_devices(struct cmd_context *cmd,
struct device *dev,
static int _ignore_blocked_mirror_devices(struct device *dev,
uint64_t start, uint64_t length,
char *mirror_status_str)
{
@ -419,7 +402,7 @@ static int _ignore_blocked_mirror_devices(struct cmd_context *cmd,
goto_out;
tmp_dev->dev = MKDEV(sm->logs[0].major, sm->logs[0].minor);
if (device_is_usable(cmd, tmp_dev, (struct dev_usable_check_params)
if (device_is_usable(tmp_dev, (struct dev_usable_check_params)
{ .check_empty = 1,
.check_blocked = 1,
.check_suspended = ignore_suspended_devices(),
@ -623,60 +606,6 @@ static int _ignore_frozen_raid(struct device *dev, const char *params)
return r;
}
static int _is_usable_uuid(const struct device *dev, const char *name, const char *uuid, int check_reserved, int check_lv, int *is_lv)
{
char *vgname, *lvname, *layer;
char vg_name[NAME_LEN];
if (!check_reserved && !check_lv)
return 1;
if (!strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1)) { /* with LVM- prefix */
if (check_reserved) {
/* Check internal lvm devices */
if (strlen(uuid) > (sizeof(UUID_PREFIX) + 2 * ID_LEN)) { /* 68 with suffix */
log_debug_activation("%s: Reserved uuid %s on internal LV device %s not usable.",
dev_name(dev), uuid, name);
return 0;
}
/* Recognize some older reserved LVs just from the LV name (snapshot, pvmove...) */
vgname = vg_name;
if (!dm_strncpy(vg_name, name, sizeof(vg_name)) ||
!dm_split_lvm_name(NULL, NULL, &vgname, &lvname, &layer))
return_0;
/* FIXME: fails to handle dev aliases i.e. /dev/dm-5, replace with UUID suffix */
if (lvname && (is_reserved_lvname(lvname) || *layer)) {
log_debug_activation("%s: Reserved internal LV device %s/%s%s%s not usable.",
dev_name(dev), vgname, lvname, *layer ? "-" : "", layer);
return 0;
}
}
if (check_lv) {
/* Skip LVs */
if (is_lv)
*is_lv = 1;
return 0;
}
}
if (check_reserved &&
(!strncmp(uuid, CRYPT_TEMP, sizeof(CRYPT_TEMP) - 1) ||
!strncmp(uuid, CRYPT_SUBDEV, sizeof(CRYPT_SUBDEV) - 1) ||
!strncmp(uuid, STRATIS, sizeof(STRATIS) - 1))) {
/* Skip private crypto devices */
log_debug_activation("%s: Reserved uuid %s on %s device %s not usable.",
dev_name(dev), uuid,
uuid[0] == 'C' ? "crypto" : "stratis",
name);
return 0;
}
return 1;
}
/*
* device_is_usable
* @dev
@ -693,14 +622,15 @@ static int _is_usable_uuid(const struct device *dev, const char *name, const cha
*
* Returns: 1 if usable, 0 otherwise
*/
int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usable_check_params check, int *is_lv)
int device_is_usable(struct device *dev, struct dev_usable_check_params check, int *is_lv)
{
struct dm_task *dmt;
struct dm_info info;
const char *name, *uuid;
uint64_t start, length;
char *target_type = NULL;
char *params;
char *params, *vgname, *lvname, *layer;
char vg_name[NAME_LEN];
void *next = NULL;
int only_error_or_zero_target = 1;
int r = 0;
@ -725,9 +655,50 @@ int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usa
goto out;
}
if (uuid &&
!_is_usable_uuid(dev, name, uuid, check.check_reserved, check.check_lv, is_lv))
goto out;
if (uuid && (check.check_reserved || check.check_lv)) {
if (!strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1)) { /* with LVM- prefix */
if (check.check_reserved) {
/* Check internal lvm devices */
if (strlen(uuid) > (sizeof(UUID_PREFIX) + 2 * ID_LEN)) { /* 68 with suffix */
log_debug_activation("%s: Reserved uuid %s on internal LV device %s not usable.",
dev_name(dev), uuid, name);
goto out;
}
/* Recognize some older reserved LVs just from the LV name (snapshot, pvmove...) */
vgname = vg_name;
if (!dm_strncpy(vg_name, name, sizeof(vg_name)) ||
!dm_split_lvm_name(NULL, NULL, &vgname, &lvname, &layer))
goto_out;
/* FIXME: fails to handle dev aliases i.e. /dev/dm-5, replace with UUID suffix */
if (lvname && (is_reserved_lvname(lvname) || *layer)) {
log_debug_activation("%s: Reserved internal LV device %s/%s%s%s not usable.",
dev_name(dev), vgname, lvname, *layer ? "-" : "", layer);
goto out;
}
}
if (check.check_lv) {
/* Skip LVs */
if (is_lv)
*is_lv = 1;
goto out;
}
}
if (check.check_reserved &&
(!strncmp(uuid, CRYPT_TEMP, sizeof(CRYPT_TEMP) - 1) ||
!strncmp(uuid, CRYPT_SUBDEV, sizeof(CRYPT_SUBDEV) - 1) ||
!strncmp(uuid, STRATIS, sizeof(STRATIS) - 1))) {
/* Skip private crypto devices */
log_debug_activation("%s: Reserved uuid %s on %s device %s not usable.",
dev_name(dev), uuid,
uuid[0] == 'C' ? "crypto" : "stratis",
name);
goto out;
}
}
/* FIXME Also check for mpath no paths */
do {
@ -742,7 +713,7 @@ int device_is_usable(struct cmd_context *cmd, struct device *dev, struct dev_usa
log_debug_activation("%s: Scanning mirror devices is disabled.", dev_name(dev));
goto out;
}
if (!_ignore_blocked_mirror_devices(cmd, dev, start,
if (!_ignore_blocked_mirror_devices(dev, start,
length, params)) {
log_debug_activation("%s: Mirror device %s not usable.",
dev_name(dev), name);
@ -938,25 +909,6 @@ int dev_manager_check_prefix_dm_major_minor(uint32_t major, uint32_t minor, cons
return r;
}
int dev_manager_get_device_list(const char *prefix, struct dm_list **devs, unsigned *devs_features)
{
struct dm_task *dmt;
int r = 1;
if (!(dmt = _setup_task_run(DM_DEVICE_LIST, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0)))
return_0;
if (!dm_task_get_device_list(dmt, devs, devs_features)) {
r = 0;
goto_out;
}
out:
dm_task_destroy(dmt);
return r;
}
int dev_manager_info(struct cmd_context *cmd,
const struct logical_volume *lv, const char *layer,
int with_open_count, int with_read_ahead, int with_name_check,
@ -972,16 +924,6 @@ int dev_manager_info(struct cmd_context *cmd,
if (!(dlid = build_dm_uuid(cmd->mem, lv, layer)))
goto_out;
if (!cmd->disable_dm_devs &&
cmd->cache_dm_devs &&
!dm_device_list_find_by_uuid(cmd->cache_dm_devs, dlid, NULL)) {
log_debug("Cached as inactive %s.", name);
if (dminfo)
memset(dminfo, 0, sizeof(*dminfo));
r = 1;
goto out;
}
if (!(r = _info(cmd, name, dlid,
with_open_count, with_read_ahead, with_name_check,
dminfo, read_ahead, seg_status)))
@ -1070,7 +1012,7 @@ bad:
return r;
}
static int _lv_has_thin_device_id(struct dm_pool *mem, const struct logical_volume *lv,
static int _thin_lv_has_device_id(struct dm_pool *mem, const struct logical_volume *lv,
const char *layer, unsigned device_id)
{
char *dlid;
@ -1957,71 +1899,6 @@ out:
return r;
}
int dev_manager_vdo_pool_size_config(struct dev_manager *dm,
const struct logical_volume *lv,
struct vdo_pool_size_config *cfg)
{
const char *dlid;
struct dm_info info;
uint64_t start, length;
struct dm_task *dmt = NULL;
char *type = NULL;
char *params = NULL;
int r = 0;
unsigned version = 0;
memset(cfg, 0, sizeof(*cfg));
if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
return_0;
if (!(dmt = _setup_task_run(DM_DEVICE_TABLE, &info, NULL, dlid, 0, 0, 0, 0, 0, 0)))
return_0;
if (!info.exists)
goto inactive; /* VDO device is not active, should not happen here... */
log_debug_activation("Checking VDO pool table line for LV %s.",
display_lvname(lv));
if (dm_get_next_target(dmt, NULL, &start, &length, &type, &params)) {
log_error("More then one table line found for %s.",
display_lvname(lv));
goto out;
}
if (!type || strcmp(type, TARGET_NAME_VDO)) {
log_error("Expected %s segment type but got %s instead.",
TARGET_NAME_VDO, type ? type : "NULL");
goto out;
}
if (sscanf(params, "V%u %*s " FMTu64 " %*u " FMTu32,
&version, &cfg->physical_size, &cfg->block_map_cache_size_mb) != 3) {
log_error("Failed to parse VDO parameters %s for LV %s.",
params, display_lvname(lv));
goto out;
}
switch (version) {
case 2: break;
case 4: break;
default: log_warn("WARNING: Unknown VDO table line version %u.", version);
}
cfg->virtual_size = length;
cfg->physical_size *= 8; // From 4K unit to 512B
cfg->block_map_cache_size_mb /= 256; // From 4K unit to MiB
cfg->index_memory_size_mb = first_seg(lv)->vdo_params.index_memory_size_mb; // Preserved
inactive:
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
/*************************/
/* NEW CODE STARTS HERE */
@ -2066,8 +1943,6 @@ int dev_manager_mknodes(const struct logical_volume *lv)
/* read-only component LV is also made visible */
if (_lv_has_mknode(lv) || (dminfo.read_only && lv_is_component(lv)))
r = _dev_manager_lv_mknodes(lv);
else
r = 1;
} else
r = _dev_manager_lv_rmnodes(lv);
@ -2323,7 +2198,6 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
{
char *dlid, *name;
struct dm_info info, info2;
const struct dm_active_device *dev;
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
return_0;
@ -2331,21 +2205,9 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
if (!(dlid = build_dm_uuid(dm->track_pending_delete ? dm->cmd->pending_delete_mem : dm->mem, lv, layer)))
return_0;
if (!dm->cmd->disable_dm_devs &&
dm->cmd->cache_dm_devs) {
if (!dm_device_list_find_by_uuid(dm->cmd->cache_dm_devs, dlid, &dev)) {
log_debug("Cached as not present %s.", name);
return 1;
}
info = (struct dm_info) {
.exists = 1,
.major = dev->major,
.minor = dev->minor,
};
log_debug("Cached as present %s %s (%d:%d).",
name, dlid, info.major, info.minor);
} else if (!_info(dm->cmd, name, dlid, 0, 0, 0, &info, NULL, NULL))
if (!_info(dm->cmd, name, dlid, 1, 0, 0, &info, NULL, NULL))
return_0;
/*
* For top level volumes verify that existing device match
* requested major/minor and that major/minor pair is available for use
@ -2459,6 +2321,8 @@ static int _pool_callback(struct dm_tree_node *node,
dm_node_callback_t type, void *cb_data)
{
int ret, status = 0, fd;
const struct dm_config_node *cn;
const struct dm_config_value *cv;
const struct pool_cb_data *data = cb_data;
const struct logical_volume *pool_lv = data->pool_lv;
const struct logical_volume *mlv = first_seg(pool_lv)->metadata_lv;
@ -2466,11 +2330,11 @@ static int _pool_callback(struct dm_tree_node *node,
long buf[64 / sizeof(long)]; /* buffer for short disk header (64B) */
int args = 0;
char *mpath;
const char *argv[DEFAULT_MAX_EXEC_ARGS + 7] = { /* Max supported 15 args */
const char *argv[19] = { /* Max supported 15 args */
find_config_tree_str_allow_empty(cmd, data->exec, NULL)
};
if (!argv[0] || !*argv[0]) /* *_check tool is unconfigured/disabled with "" setting */
if (!*argv[0]) /* *_check tool is unconfigured/disabled with "" setting */
return 1;
if (lv_is_cache_vol(pool_lv)) {
@ -2486,9 +2350,6 @@ static int _pool_callback(struct dm_tree_node *node,
return 0;
}
}
dm_device_list_destroy(&cmd->cache_dm_devs); /* Cache no longer valid */
log_debug("Running check command on %s", mpath);
if (data->skip_zero) {
@ -2517,8 +2378,25 @@ static int _pool_callback(struct dm_tree_node *node,
}
}
if (!prepare_exec_args(cmd, argv, &args, data->opts))
return_0;
if (!(cn = find_config_tree_array(cmd, data->opts, NULL))) {
log_error(INTERNAL_ERROR "Unable to find configuration for pool check options.");
return 0;
}
for (cv = cn->v; cv && args < 16; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
log_error("Invalid string in config file: "
"global/%s_check_options.",
data->global);
return 0;
}
argv[++args] = cv->v.str;
}
if (args == 16) {
log_error("Too many options for %s command.", argv[0]);
return 0;
}
argv[++args] = mpath;
@ -2983,51 +2861,30 @@ static int _add_error_area(struct dev_manager *dm, struct dm_tree_node *node,
return 1;
}
static int _bad_pv_area(struct lv_segment *seg, uint32_t s)
{
struct stat info;
const char *name;
struct device *dev;
if (!seg_pvseg(seg, s))
return 1;
if (!seg_pv(seg, s))
return 1;
if (!(dev = seg_dev(seg, s)))
return 1;
if (dm_list_empty(&dev->aliases))
return 1;
/* FIXME Avoid repeating identical stat in dm_tree_node_add_target_area */
name = dev_name(dev);
if (stat(name, &info) < 0)
return 1;
if (!S_ISBLK(info.st_mode))
return 1;
return 0;
}
int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
struct dm_tree_node *node, uint32_t start_area,
uint32_t areas)
{
struct cmd_context *cmd = seg->lv->vg->cmd;
uint64_t extent_size = seg->lv->vg->extent_size;
uint32_t s;
char *dlid;
struct stat info;
const char *name;
unsigned num_error_areas = 0;
unsigned num_existing_areas = 0;
/* FIXME Avoid repeating identical stat in dm_tree_node_add_target_area */
for (s = start_area; s < areas; s++) {
if (((seg_type(seg, s) == AREA_PV) && _bad_pv_area(seg, s)) ||
((seg_type(seg, s) == AREA_LV) && !seg_lv(seg, s))) {
if (!cmd->partial_activation) {
if (!cmd->degraded_activation ||
(!lv_is_raid_type(seg->lv) &&
!lv_is_integrity(seg->lv) &&
!lv_is_integrity_metadata(seg->lv) &&
!lv_is_integrity_origin(seg->lv))) {
log_error("Aborting. LV %s is incomplete and --activationmode partial was not specified.",
if ((seg_type(seg, s) == AREA_PV &&
(!seg_pvseg(seg, s) || !seg_pv(seg, s) || !seg_dev(seg, s) ||
!(name = dev_name(seg_dev(seg, s))) || !*name ||
stat(name, &info) < 0 || !S_ISBLK(info.st_mode))) ||
(seg_type(seg, s) == AREA_LV && !seg_lv(seg, s))) {
if (!seg->lv->vg->cmd->partial_activation) {
if (!seg->lv->vg->cmd->degraded_activation ||
!lv_is_raid_type(seg->lv)) {
log_error("Aborting. LV %s is now incomplete "
"and '--activationmode partial' was not specified.",
display_lvname(seg->lv));
return 0;
}
@ -3036,10 +2893,7 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
return_0;
num_error_areas++;
} else if (seg_type(seg, s) == AREA_PV) {
struct device *dev = seg_dev(seg, s);
name = dm_list_empty(&dev->aliases) ? NULL : dev_name(dev);
if (!dm_tree_node_add_target_area(node, name, NULL,
if (!dm_tree_node_add_target_area(node, dev_name(seg_dev(seg, s)), NULL,
(seg_pv(seg, s)->pe_start + (extent_size * seg_pe(seg, s)))))
return_0;
num_existing_areas++;
@ -3115,7 +2969,7 @@ static int _add_layer_target_to_dtree(struct dev_manager *dm,
/* Add linear mapping over layered LV */
/* From VDO layer expose ONLY vdo pool header, we would need to use virtual size otherwise */
if (!add_linear_area_to_dtree(dnode, lv_is_vdo_pool(lv) ? 8 : lv->size,
if (!add_linear_area_to_dtree(dnode, lv_is_vdo_pool(lv) ? first_seg(lv)->vdo_pool_header_size : lv->size,
lv->vg->extent_size,
lv->vg->cmd->use_linear_target,
lv->vg->name, lv->name) ||
@ -3529,7 +3383,7 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
*/
if ((dinfo = _cached_dm_info(dm->mem, dtree, lv, NULL))) {
/* Merging origin LV is present, check if mergins is already running. */
if ((seg_is_thin_volume(seg) && _lv_has_thin_device_id(dm->mem, lv, NULL, seg->device_id)) ||
if ((seg_is_thin_volume(seg) && _thin_lv_has_device_id(dm->mem, lv, NULL, seg->device_id)) ||
(!seg_is_thin_volume(seg) && lv_has_target_type(dm->mem, lv, NULL, TARGET_NAME_SNAPSHOT_MERGE))) {
log_debug_activation("Merging of snapshot volume %s to origin %s is in progress.",
display_lvname(seg->lv), display_lvname(seg->lv));
@ -3588,6 +3442,9 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
dm_tree_node_get_context(dnode))
return 1;
lvlayer->lv = lv;
lvlayer->visible_component = (laopts->component_lv == lv) ? 1 : 0;
/*
* Add LV to dtree.
* If we're working with precommitted metadata, clear any
@ -3691,8 +3548,6 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
if (lv_is_cache(lv) && lv_is_cache_vol(first_seg(lv)->pool_lv) &&
/* Register callback only for layer activation or non-layered cache LV */
(layer || !lv_layer(lv)) &&
/* Register callback when cachevol LV is NOT already active */
!_cached_dm_info(dm->mem, dtree, first_seg(lv)->pool_lv, NULL) &&
!_pool_register_callback(dm, dnode, lv))
return_0;
@ -3882,7 +3737,6 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
struct dm_tree_node *root;
char *dlid;
int r = 0;
unsigned tmp_state;
if (action < DM_ARRAY_SIZE(_action_names))
log_debug_activation("Creating %s%s tree for %s.",
@ -3902,16 +3756,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
dm->suspend = (action == SUSPEND_WITH_LOCKFS) || (action == SUSPEND);
dm->track_external_lv_deps = 1;
/* ATM do not use caching for anything else then striped target.
* And also skip for CLEAN action */
tmp_state = dm->cmd->disable_dm_devs;
if (!seg_is_striped_target(first_seg(lv)) || (action == CLEAN))
dm->cmd->disable_dm_devs = 1;
dtree = _create_partial_dtree(dm, lv, laopts->origin_only);
dm->cmd->disable_dm_devs = tmp_state;
if (!dtree)
if (!(dtree = _create_partial_dtree(dm, lv, laopts->origin_only)))
return_0;
if (!(root = dm_tree_find_node(dtree, 0, 0))) {
@ -3974,8 +3819,6 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
* non 'thin pool/volume' and size increase */
else if (!lv_is_thin_volume(lv) &&
!lv_is_thin_pool(lv) &&
!lv_is_vdo(lv) &&
!lv_is_vdo_pool(lv) &&
dm_tree_node_size_changed(root))
dm->flush_required = 1;
@ -4094,78 +3937,3 @@ out:
return r;
}
/*
* crypt offset is usually the LUKS header size but can be larger.
* The LUKS header is usually 2MB for LUKS1 and 16MB for LUKS2.
* The offset needs to be subtracted from the LV size to get the
* size used to resize the crypt device.
*/
int get_crypt_table_offset(dev_t crypt_devt, uint32_t *offset_bytes)
{
struct dm_task *dmt = dm_task_create(DM_DEVICE_TABLE);
uint64_t start, length;
char *target_type = NULL;
void *next = NULL;
char *params = NULL;
char offset_str[32] = { 0 };
int copy_offset = 0;
int spaces = 0;
unsigned i, i_off = 0;
if (!dmt)
return_0;
if (!dm_task_set_major_minor(dmt, (int)MAJOR(crypt_devt), (int)MINOR(crypt_devt), 0)) {
dm_task_destroy(dmt);
return_0;
}
/* Non-blocking status read */
if (!dm_task_no_flush(dmt))
log_warn("WARNING: Can't set no_flush for dm status.");
if (!dm_task_run(dmt)) {
dm_task_destroy(dmt);
return_0;
}
next = dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
if (!target_type || !params || strcmp(target_type, "crypt")) {
dm_task_destroy(dmt);
return_0;
}
/*
* get offset from params string:
* <cipher> <key> <iv_offset> <device> <offset> [<#opt_params> <opt_params>]
* <offset> is reported in 512 byte sectors.
*/
for (i = 0; i < strlen(params); i++) {
if (params[i] == ' ') {
spaces++;
if (spaces == 4)
copy_offset = 1;
if (spaces == 5)
break;
continue;
}
if (!copy_offset)
continue;
offset_str[i_off++] = params[i];
if (i_off == sizeof(offset_str)) {
offset_str[0] = '\0';
break;
}
}
dm_task_destroy(dmt);
if (!offset_str[0])
return_0;
*offset_bytes = ((uint32_t)strtoul(offset_str, NULL, 0) * 512);
return 1;
}

View File

@ -29,8 +29,6 @@ struct lv_seg_status;
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts, const char *layer);
int get_crypt_table_offset(dev_t crypt_devt, uint32_t *offset_bytes);
/*
* Constructor and destructor.
*/
@ -83,9 +81,6 @@ int dev_manager_thin_pool_status(struct dev_manager *dm,
int dev_manager_vdo_pool_status(struct dev_manager *dm,
const struct logical_volume *lv, int flush,
struct lv_status_vdo **status, int *exists);
int dev_manager_vdo_pool_size_config(struct dev_manager *dm,
const struct logical_volume *lv,
struct vdo_pool_size_config *cfg);
int dev_manager_suspend(struct dev_manager *dm, const struct logical_volume *lv,
struct lv_activate_opts *laopts, int lockfs, int flush_required);
int dev_manager_activate(struct dev_manager *dm, const struct logical_volume *lv,
@ -108,7 +103,5 @@ int dev_manager_device_uses_vg(struct device *dev,
int dev_manager_remove_dm_major_minor(uint32_t major, uint32_t minor);
int dev_manager_check_prefix_dm_major_minor(uint32_t major, uint32_t minor, const char *prefix);
int dev_manager_get_device_list(const char *prefix, struct dm_list **devs,
unsigned *devs_features);
#endif

View File

@ -318,10 +318,9 @@ struct fs_op_parms {
static void _store_str(char **pos, char **ptr, const char *str)
{
size_t len = strlen(str) + 1;
memcpy(*pos, str, len);
strcpy(*pos, str);
*ptr = *pos;
*pos += len;
*pos += strlen(*ptr) + 1;
}
static void _del_fs_op(struct fs_op_parms *fsp)

564
lib/cache/lvmcache.c vendored
View File

@ -144,6 +144,28 @@ int lvmcache_found_duplicate_vgnames(void)
return _found_duplicate_vgnames;
}
static struct device_list *_get_devl_in_device_list(struct device *dev, struct dm_list *head)
{
struct device_list *devl;
dm_list_iterate_items(devl, head) {
if (devl->dev == dev)
return devl;
}
return NULL;
}
int dev_in_device_list(struct device *dev, struct dm_list *head)
{
struct device_list *devl;
dm_list_iterate_items(devl, head) {
if (devl->dev == dev)
return 1;
}
return 0;
}
bool lvmcache_has_duplicate_devs(void)
{
if (dm_list_empty(&_unused_duplicates) && dm_list_empty(&_initial_duplicates))
@ -170,11 +192,11 @@ void lvmcache_del_dev_from_duplicates(struct device *dev)
{
struct device_list *devl;
if ((devl = device_list_find_dev(&_initial_duplicates, dev))) {
if ((devl = _get_devl_in_device_list(dev, &_initial_duplicates))) {
log_debug_cache("delete dev from initial duplicates %s", dev_name(dev));
dm_list_del(&devl->list);
}
if ((devl = device_list_find_dev(&_unused_duplicates, dev))) {
if ((devl = _get_devl_in_device_list(dev, &_unused_duplicates))) {
log_debug_cache("delete dev from unused duplicates %s", dev_name(dev));
dm_list_del(&devl->list);
}
@ -332,11 +354,9 @@ static struct lvmcache_vginfo *_vginfo_lookup(const char *vgname, const char *vg
if (vgid_arg) {
if ((vginfo = dm_hash_lookup(_vgid_hash, vgid))) {
if (vgname && strcmp(vginfo->vgname, vgname)) {
log_warn("WARNING: lookup found duplicate VGID %s for VGs %s and %s.", vgid, vginfo->vgname, vgname);
if ((vginfo = dm_hash_lookup(_vgname_hash, vgname))) {
if (!memcmp(vginfo->vgid, vgid, ID_LEN))
return vginfo;
}
/* should never happen */
log_error(INTERNAL_ERROR "vginfo_lookup vgid %s has two names %s %s",
vgid, vginfo->vgname, vgname);
return NULL;
}
return vginfo;
@ -401,10 +421,10 @@ const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgnam
if (_found_duplicate_vgnames) {
if (!(vginfo = _search_vginfos_list(vgname, NULL)))
return NULL;
return_NULL;
} else {
if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname)))
return NULL;
return_NULL;
}
if (vginfo->has_duplicate_local_vgname) {
@ -552,16 +572,6 @@ static const char *_get_pvsummary_device_id(const char *pvid_arg, const char **d
return NULL;
}
int lvmcache_pvsummary_count(const char *vgname)
{
struct lvmcache_vginfo *vginfo;
if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
return_0;
return dm_list_size(&vginfo->pvsummaries);
}
/*
* Check if any PVs in vg->pvs have the same PVID as any
* entries in _unused_duplicates.
@ -583,7 +593,7 @@ int vg_has_duplicate_pvs(struct volume_group *vg)
bool lvmcache_dev_is_unused_duplicate(struct device *dev)
{
return device_list_find_dev(&_unused_duplicates, dev) ? true : false;
return dev_in_device_list(dev, &_unused_duplicates) ? true : false;
}
static void _warn_unused_duplicates(struct cmd_context *cmd)
@ -615,167 +625,6 @@ static void _warn_unused_duplicates(struct cmd_context *cmd)
}
}
static int _all_multipath_components(struct cmd_context *cmd, struct lvmcache_info *info, const char *pvid,
struct dm_list *altdevs, struct device **dev_mpath)
{
struct device_list *devl;
struct device *dev_mp = NULL;
struct device *dev1 = NULL;
struct device *dev;
char wwid1_buf[DEV_WWID_SIZE] = { 0 };
char wwid_buf[DEV_WWID_SIZE] = { 0 };
const char *wwid1 = NULL;
const char *wwid = NULL;
int diff_wwid = 0;
int same_wwid = 0;
int dev_is_mp;
*dev_mpath = NULL;
if (!find_config_tree_bool(cmd, devices_multipath_component_detection_CFG, NULL))
return 0;
/* This function only makes sense with more than one dev. */
if ((info && dm_list_empty(altdevs)) || (!info && (dm_list_size(altdevs) == 1))) {
log_debug("Skip multipath component checks with single device for PVID %s", pvid);
return 0;
}
log_debug("Checking for multipath components for duplicate PVID %s", pvid);
if (info) {
dev = info->dev;
dev_is_mp = (cmd->dev_types->device_mapper_major == MAJOR(dev->dev)) && dev_has_mpath_uuid(cmd, dev, NULL);
/*
* dev_mpath_component_wwid allocates wwid from dm_pool,
* device_id_system_read does not and needs free.
*/
if (dev_is_mp) {
if ((wwid1 = dev_mpath_component_wwid(cmd, dev))) {
strncpy(wwid1_buf, wwid1, DEV_WWID_SIZE-1);
dev_mp = dev;
dev1 = dev;
}
} else {
if ((wwid1 = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_WWID))) {
strncpy(wwid1_buf, wwid1, DEV_WWID_SIZE-1);
free((char *)wwid1);
dev1 = dev;
}
}
}
dm_list_iterate_items(devl, altdevs) {
dev = devl->dev;
dev_is_mp = (cmd->dev_types->device_mapper_major == MAJOR(dev->dev)) && dev_has_mpath_uuid(cmd, dev, NULL);
if (dev_is_mp) {
if ((wwid = dev_mpath_component_wwid(cmd, dev)))
strncpy(wwid_buf, wwid, DEV_WWID_SIZE-1);
} else {
if ((wwid = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_WWID))) {
strncpy(wwid_buf, wwid, DEV_WWID_SIZE-1);
free((char *)wwid);
}
}
if (!wwid_buf[0] && wwid1_buf[0]) {
log_debug("Different wwids for duplicate PVs %s %s %s none",
dev_name(dev1), wwid1_buf, dev_name(dev));
diff_wwid++;
continue;
}
if (!wwid_buf[0])
continue;
if (!wwid1_buf[0]) {
memcpy(wwid1_buf, wwid_buf, DEV_WWID_SIZE-1);
dev1 = dev;
continue;
}
/* Different wwids indicates these are not multipath components. */
if (strcmp(wwid1_buf, wwid_buf)) {
log_debug("Different wwids for duplicate PVs %s %s %s %s",
dev_name(dev1), wwid1_buf, dev_name(dev), wwid_buf);
diff_wwid++;
continue;
}
/* Different mpath devs with the same wwid shouldn't happen. */
if (dev_is_mp && dev_mp) {
log_print_unless_silent("Found multiple multipath devices for PVID %s WWID %s: %s %s.",
pvid, wwid1_buf, dev_name(dev_mp), dev_name(dev));
continue;
}
log_debug("Same wwids for duplicate PVs %s %s", dev_name(dev1), dev_name(dev));
same_wwid++;
/* Save the mpath device so it can be used as the PV. */
if (dev_is_mp)
dev_mp = dev;
}
if (diff_wwid || !same_wwid)
return 0;
if (dev_mp)
log_debug("Found multipath device %s for PVID %s WWID %s.", dev_name(dev_mp), pvid, wwid1_buf);
*dev_mpath = dev_mp;
return 1;
}
static int _all_md_components(struct cmd_context *cmd, struct lvmcache_info *info, const char *pvid,
struct dm_list *altdevs, struct device **dev_md_out)
{
struct device_list *devl;
struct device *dev_md = NULL;
struct device *dev;
int real_dup = 0;
*dev_md_out = NULL;
/* There will often be no info struct because of the extra_md_checks function. */
if (info && (cmd->dev_types->md_major == MAJOR(info->dev->dev)))
dev_md = info->dev;
dm_list_iterate_items(devl, altdevs) {
dev = devl->dev;
if (cmd->dev_types->md_major == MAJOR(dev->dev)) {
if (dev_md) {
/* md devs themselves are dups */
log_debug("Found multiple md devices for PVID %s: %s %s",
pvid, dev_name(dev_md), dev_name(dev));
real_dup = 1;
break;
} else
dev_md = dev;
} else {
if (!dev_is_md_component(cmd, dev, NULL, 1)) {
/* md dev copied to another device */
real_dup = 1;
break;
}
}
}
if (real_dup)
return 0;
if (dev_md)
log_debug("Found md device %s for PVID %s.", dev_name(dev_md), pvid);
*dev_md_out = dev_md;
return 1;
}
/*
* If we've found devices with the same PVID, decide which one
* to use.
@ -831,8 +680,6 @@ static void _choose_duplicates(struct cmd_context *cmd,
struct device_list *devl, *devl_safe, *devl_add, *devl_del;
struct lvmcache_info *info;
struct device *dev1, *dev2;
struct device *dev_mpath, *dev_md;
struct device *dev_drop;
const char *device_id = NULL, *device_id_type = NULL;
const char *idname1 = NULL, *idname2 = NULL;
uint32_t dev1_major, dev1_minor, dev2_major, dev2_minor;
@ -855,8 +702,6 @@ static void _choose_duplicates(struct cmd_context *cmd,
next:
dm_list_init(&altdevs);
pvid = NULL;
dev_mpath = NULL;
dev_md = NULL;
dm_list_iterate_items_safe(devl, devl_safe, &_initial_duplicates) {
if (!pvid) {
@ -875,174 +720,31 @@ next:
return;
}
/*
* Get rid of any md components before comparing alternatives.
* (Since an md component can never be used, it's not an
* option to use like other kinds of alternatives.)
*/
info = lvmcache_info_from_pvid(pvid, NULL, 0);
/*
* Usually and ideally, components of md and multipath devs should have
* been excluded by filters, and not scanned for a PV. In some unusual
* cases the components can get through the filters, and a PV can be
* found on them. Detecting the same PVID on both the component and
* the md/mpath device gives us a last chance to drop the component.
* An md/mpath component device is completely ignored, as if it had
* been filtered, and not kept in the list unused duplicates.
*
* One issue related to eliminating mpath/md duplicate PVs here is
* that it occurs after label_scan, and hints are created based
* on what label_scan finds, so hints are disabled due to duplicate
* PVs that are later resolved here.
*/
/*
* Get rid of multipath components based on matching wwids.
*/
if (_all_multipath_components(cmd, info, pvid, &altdevs, &dev_mpath)) {
if (info && dev_mpath && (info->dev != dev_mpath)) {
/*
* info should be dropped from lvmcache and info->dev
* should be treated as if it had been excluded by a filter.
* dev_mpath should be added to lvmcache by the caller.
*/
dev_drop = info->dev;
/* Have caller add dev_mpath to lvmcache. */
log_debug("Using multipath device %s for PVID %s.", dev_name(dev_mpath), pvid);
if ((devl_add = zalloc(sizeof(*devl_add)))) {
devl_add->dev = dev_mpath;
dm_list_add(add_cache_devs, &devl_add->list);
}
/* Remove dev_mpath from altdevs. */
if ((devl = device_list_find_dev(&altdevs, dev_mpath)))
dm_list_del(&devl->list);
/* Remove info from lvmcache that came from the component dev. */
log_debug("Ignoring multipath component %s with PVID %s (dropping info)", dev_name(dev_drop), pvid);
lvmcache_del(info);
info = NULL;
/* Make the component dev look like it was filtered. */
cmd->filter->wipe(cmd, cmd->filter, dev_drop, NULL);
dev_drop->flags &= ~DEV_SCAN_FOUND_LABEL;
}
if (info && !dev_mpath) {
/*
* Only mpath component devs were found and no actual
* multipath dev, so drop the component from lvmcache.
*/
dev_drop = info->dev;
log_debug("Ignoring multipath component %s with PVID %s (dropping info)", dev_name(dev_drop), pvid);
lvmcache_del(info);
info = NULL;
/* Make the component dev look like it was filtered. */
cmd->filter->wipe(cmd, cmd->filter, dev_drop, NULL);
dev_drop->flags &= ~DEV_SCAN_FOUND_LABEL;
}
dm_list_iterate_items_safe(devl, devl_safe, &altdevs) {
/*
* The altdevs are all mpath components that should look
* like they were filtered, they are not in lvmcache.
*/
dev_drop = devl->dev;
log_debug("Ignoring multipath component %s with PVID %s (dropping duplicate)", dev_name(dev_drop), pvid);
dm_list_del(&devl->list);
cmd->filter->wipe(cmd, cmd->filter, dev_drop, NULL);
dev_drop->flags &= ~DEV_SCAN_FOUND_LABEL;
}
goto next;
if (info && dev_is_md_component(cmd, info->dev, NULL, 1)) {
/* does not go in del_cache_devs which become unused_duplicates */
log_debug_cache("PV %s drop MD component from scan selection %s", pvid, dev_name(info->dev));
lvmcache_del(info);
info = NULL;
}
/*
* Get rid of any md components.
*/
if (_all_md_components(cmd, info, pvid, &altdevs, &dev_md)) {
if (info && dev_md && (info->dev != dev_md)) {
/*
* info should be dropped from lvmcache and info->dev
* should be treated as if it had been excluded by a filter.
* dev_md should be added to lvmcache by the caller.
* Often this info struct has been removed by
* lvmcache_extra_md_component_checks.
*/
dev_drop = info->dev;
/* Have caller add dev_md to lvmcache. */
log_debug("Using md device %s for PVID %s.", dev_name(dev_md), pvid);
if ((devl_add = zalloc(sizeof(*devl_add)))) {
devl_add->dev = dev_md;
dm_list_add(add_cache_devs, &devl_add->list);
}
/* Remove dev_md from altdevs. */
if ((devl = device_list_find_dev(&altdevs, dev_md)))
dm_list_del(&devl->list);
/* Remove info from lvmcache that came from the component dev. */
log_debug("Ignoring md component %s with PVID %s (dropping info)", dev_name(dev_drop), pvid);
lvmcache_del(info);
info = NULL;
/* Make the component dev look like it was filtered. */
cmd->filter->wipe(cmd, cmd->filter, dev_drop, NULL);
dev_drop->flags &= ~DEV_SCAN_FOUND_LABEL;
}
if (!info && dev_md) {
/*
* The info struct was from a component and was dropped
* and the actual md dev was found on initial_duplicates
* and the caller should add it to lvmcache.
*/
/* Have caller add dev_md to lvmcache. */
log_debug("Using md device %s for PVID %s.", dev_name(dev_md), pvid);
if ((devl_add = zalloc(sizeof(*devl_add)))) {
devl_add->dev = dev_md;
dm_list_add(add_cache_devs, &devl_add->list);
}
/* Remove dev_md from altdevs. */
if ((devl = device_list_find_dev(&altdevs, dev_md)))
dm_list_del(&devl->list);
}
if (info && !dev_md) {
/*
* Only md component devs were found and no actual
* md dev, so drop the component from lvmcache.
*/
dev_drop = info->dev;
log_debug("Ignoring md component %s with PVID %s (dropping info)", dev_name(dev_drop), pvid);
lvmcache_del(info);
info = NULL;
/* Make the component dev look like it was filtered. */
cmd->filter->wipe(cmd, cmd->filter, dev_drop, NULL);
dev_drop->flags &= ~DEV_SCAN_FOUND_LABEL;
}
dm_list_iterate_items_safe(devl, devl_safe, &altdevs) {
/*
* The altdevs are all md components that should look
* like they were filtered, they are not in lvmcache.
*/
dev_drop = devl->dev;
log_debug("Ignoring md component %s with PVID %s (dropping duplicate)", dev_name(dev_drop), pvid);
dm_list_iterate_items_safe(devl, devl_safe, &altdevs) {
if (dev_is_md_component(cmd, devl->dev, NULL, 1)) {
log_debug_cache("PV %s drop MD component from scan duplicates %s", pvid, dev_name(devl->dev));
dm_list_del(&devl->list);
cmd->filter->wipe(cmd, cmd->filter, dev_drop, NULL);
dev_drop->flags &= ~DEV_SCAN_FOUND_LABEL;
}
goto next;
}
if (dm_list_empty(&altdevs))
goto next;
/*
* Find the device for the pvid that's currently in lvmcache.
*/
@ -1085,8 +787,8 @@ next:
if (dev1 == dev2)
continue;
prev_unchosen1 = device_list_find_dev(&_unused_duplicates, dev1) ? 1 :0;
prev_unchosen2 = device_list_find_dev(&_unused_duplicates, dev2) ? 1 :0;
prev_unchosen1 = dev_in_device_list(dev1, &_unused_duplicates);
prev_unchosen2 = dev_in_device_list(dev2, &_unused_duplicates);
if (!prev_unchosen1 && !prev_unchosen2) {
/*
@ -1096,8 +798,8 @@ next:
* want the same duplicate preference to be preserved
* in each instance of lvmcache for a single command.
*/
prev_unchosen1 = device_list_find_dev(&_prev_unused_duplicate_devs, dev1) ? 1 :0;
prev_unchosen2 = device_list_find_dev(&_prev_unused_duplicate_devs, dev2) ? 1 : 0;
prev_unchosen1 = dev_in_device_list(dev1, &_prev_unused_duplicate_devs);
prev_unchosen2 = dev_in_device_list(dev2, &_prev_unused_duplicate_devs);
}
dev1_major = MAJOR(dev1->dev);
@ -1274,7 +976,7 @@ next:
if (!info) {
log_debug_cache("PV %s with duplicates will use %s.", pvid, dev_name(dev1));
if (!(devl_add = device_list_find_dev(&altdevs, dev1))) {
if (!(devl_add = _get_devl_in_device_list(dev1, &altdevs))) {
/* shouldn't happen */
log_error(INTERNAL_ERROR "PV %s with duplicates no alternate list entry for %s", pvid, dev_name(dev1));
dm_list_splice(&new_unused, &altdevs);
@ -1293,7 +995,7 @@ next:
* for the current lvmcache device to drop.
*/
if (!(devl_add = device_list_find_dev(&altdevs, dev1))) {
if (!(devl_add = _get_devl_in_device_list(dev1, &altdevs))) {
/* shouldn't happen */
log_error(INTERNAL_ERROR "PV %s with duplicates no alternate list entry for %s", pvid, dev_name(dev1));
dm_list_splice(&new_unused, &altdevs);
@ -1447,18 +1149,6 @@ int lvmcache_label_reopen_vg_rw(struct cmd_context *cmd, const char *vgname, con
* times it can be a clue that label_scan mistakenly read the pv from an md
* component device instead of from the md device itself. So for unmatching
* sizes, we do a full md component check on the device.
*
* It might be nice to do this checking in the filter (when passes_filter is
* called after the initial read), but that doesn't work because passes_filter
* is called before _text_read so metadata/pvsummary info is not yet available
* which this function uses.
*
* The unique value of this function is that it can eliminate md components
* without there being duplicate PVs. But, there will often be duplicate PVs,
* handled by _all_md_components(), where other devs with the same pvid will be
* in _initial_duplicates. One could be the md device itself which will be
* added to lvmcache by choose_duplicates, and other duplicates that are
* components will be dropped.
*/
void lvmcache_extra_md_component_checks(struct cmd_context *cmd)
@ -1503,9 +1193,6 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd)
*/
dm_list_iterate_items_safe(vginfo, vginfo2, &_vginfos) {
char vgid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
memcpy(vgid, vginfo->vgid, ID_LEN);
dm_list_iterate_items_safe(info, info2, &vginfo->infos) {
dev = info->dev;
device_hint = _get_pvsummary_device_hint(dev->pvid);
@ -1523,8 +1210,7 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd)
*/
if (pvsize && devsize && (pvsize != devsize))
do_check_size = 1;
if (device_hint && !strncmp(device_hint, "/dev/md", 7) &&
(MAJOR(info->dev->dev) != cmd->dev_types->md_major))
if (device_hint && !strncmp(device_hint, "/dev/md", 7))
do_check_name = 1;
if (!do_check_size && !do_check_name)
@ -1554,16 +1240,12 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd)
device_hint ?: "none", dev_name(dev));
if (dev_is_md_component(cmd, dev, NULL, 1)) {
log_debug("Ignoring PV from md component %s with PVID %s (metadata %s %llu)",
dev_name(dev), dev->pvid, device_hint ?: "none", (unsigned long long)pvsize);
log_debug("dropping PV from md component %s", dev_name(dev));
dev->flags &= ~DEV_SCAN_FOUND_LABEL;
/* lvmcache_del will also delete vginfo if info was last one */
lvmcache_del(info);
lvmcache_del_dev_from_duplicates(dev);
cmd->filter->wipe(cmd, cmd->filter, dev, NULL);
/* If vginfo was deleted don't continue using vginfo->infos */
if (!_search_vginfos_list(NULL, vgid))
break;
}
}
}
@ -1597,9 +1279,12 @@ int lvmcache_label_scan(struct cmd_context *cmd)
{
struct dm_list del_cache_devs;
struct dm_list add_cache_devs;
struct dm_list renamed_devs;
struct lvmcache_info *info;
struct device_list *devl;
dm_list_init(&renamed_devs);
log_debug_cache("lvmcache label scan begin");
/*
@ -1613,57 +1298,22 @@ int lvmcache_label_scan(struct cmd_context *cmd)
* with infos/vginfos based on reading headers from
* each device, and a vg summary from each mda.
*/
if (!label_scan(cmd))
return_0;
label_scan(cmd);
/*
* device_ids_validate() found devices using a sys_serial device id
* which had a PVID on disk that did not match the PVID in the devices
* file. Serial numbers may not always be unique, so any device with
* the same serial number is found and searched for the correct PVID.
* If the PVID is found on a device that has not been scanned, then
* it needs to be scanned so it can be used.
* When devnames are used as device ids (which is dispreferred),
* changing/unstable devnames can lead to entries in the devices file
* not being matched to a dev even if the PV is present on the system.
* Or, a devices file entry may have been matched to the wrong device
* (with the previous name) that does not have the PVID specified in
* the entry. This function detects that problem, scans labels on all
* devs on the system to find the missing PVIDs, and corrects the
* devices file. We then need to run label scan on these correct
* devices.
*/
if (!dm_list_empty(&cmd->device_ids_check_serial)) {
struct dm_list scan_devs;
dm_list_init(&scan_devs);
device_ids_check_serial(cmd, &scan_devs, 0, NULL);
if (!dm_list_empty(&scan_devs))
label_scan_devs(cmd, cmd->filter, &scan_devs);
}
/*
* device_ids_invalid is set by device_ids_validate() when there
* are entries in the devices file that need to be corrected,
* i.e. device IDs read from the system and/or PVIDs read from
* disk do not match info in the devices file. This is usually
* related to incorrect device names which routinely change on
* reboot. When device names change for entries that use
* IDTYPE=devname, it often means that all devs on the system
* need to be scanned to find the new device for the PVIDs.
* device_ids_validate() will update the devices file to correct
* some info, but to locate new devices for PVIDs, it defers
* to device_ids_search() which involves label scanning.
*
* device_ids_refresh_trigger is set by device_ids_read() when
* it sees that the local machine doesn't match the machine
* that wrote the devices file, and device IDs of all types
* may need to be replaced for the PVIDs in the devices file.
* This also means that all devs on the system need to be
* scanned to find the new devices for the PVIDs.
*
* When device_ids_search() locates the correct devices
* for the PVs in the devices file, it returns those new
* devices in the refresh_devs list. Those devs need to
* be passed to label_scan to populate lvmcache info.
*/
if (cmd->device_ids_invalid || cmd->device_ids_refresh_trigger) {
struct dm_list new_devs;
dm_list_init(&new_devs);
device_ids_search(cmd, &new_devs, 0, 0, NULL);
if (!dm_list_empty(&new_devs))
label_scan_devs(cmd, cmd->filter, &new_devs);
}
device_ids_find_renamed_devs(cmd, &renamed_devs, NULL, 0);
if (!dm_list_empty(&renamed_devs))
label_scan_devs(cmd, cmd->filter, &renamed_devs);
/*
* _choose_duplicates() returns:
@ -1922,17 +1572,7 @@ static int _lvmcache_update_vgname(struct cmd_context *cmd,
_drop_vginfo(info, info->vginfo);
vginfo = lvmcache_vginfo_from_vgid(vgid);
if (vginfo && strcmp(vginfo->vgname, vgname)) {
log_warn("WARNING: fix duplicate VGID %s for VGs %s and %s (see vgchange -u).", vgid_dashed, vgname, vginfo->vgname);
vginfo = lvmcache_vginfo_from_vgname(vgname, NULL);
if (vginfo && memcmp(vginfo->vgid, vgid, ID_LEN)) {
log_error("Ignoring %s with conflicting VG info %s %s.", dev_name(info->dev), vgid_dashed, vgname);
return_0;
}
}
if (!vginfo) {
if (!(vginfo = lvmcache_vginfo_from_vgid(vgid))) {
/*
* Create a vginfo struct for this VG and put the vginfo
* into the hash table.
@ -2287,13 +1927,57 @@ int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info
return 1;
}
/*
* FIXME: quit trying to mirror changes that a command is making into lvmcache.
*
* First, it's complicated and hard to ensure it's done correctly in every case
* (it would be much easier and safer to just toss out what's in lvmcache and
* reread the info to recreate it from scratch instead of trying to make sure
* every possible discrete state change is correct.)
*
* Second, it's unnecessary if commands just use the vg they are modifying
* rather than also trying to get info from lvmcache. The lvmcache state
* should be populated by label_scan, used to perform vg_read's, and then
* ignored (or dropped so it can't be used).
*
* lvmcache info is already used very little after a command begins its
* operation. The code that's supposed to keep the lvmcache in sync with
* changes being made to disk could be half wrong and we wouldn't know it.
* That creates a landmine for someone who might try to use a bit of it that
* isn't being updated correctly.
*/
int lvmcache_update_vg_from_write(struct volume_group *vg)
{
char vgid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
struct pv_list *pvl;
struct lvmcache_info *info;
struct lvmcache_vgsummary vgsummary = {
.vgname = vg->name,
.vgstatus = vg->status,
.system_id = vg->system_id,
.lock_type = vg->lock_type
};
memcpy(vgid, &vg->id, ID_LEN);
memcpy(vgsummary.vgid, vgid, ID_LEN);
dm_list_iterate_items(pvl, &vg->pvs) {
if ((info = lvmcache_info_from_pv_id(&pvl->pv->id, pvl->pv->dev, 0)) &&
!lvmcache_update_vgname_and_id(vg->cmd, info, &vgsummary))
return_0;
}
return 1;
}
/*
* The lvmcache representation of a VG after label_scan can be incorrect
* because the label_scan does not use the full VG metadata to construct
* vginfo/info. PVs that don't hold VG metadata weren't attached to the vginfo
* during label scan, and PVs with outdated metadata (claiming to be in the VG,
* but not listed in the latest metadata) were attached to the vginfo, but
* shouldn't be. After vg_read() gets the full metadata in the form of a 'vg',
* shouldn't be. After vg_read() gets the full metdata in the form of a 'vg',
* this function is called to fix up the lvmcache representation of the VG
* using the 'vg'.
*/
@ -2530,7 +2214,7 @@ struct lvmcache_info *lvmcache_add(struct cmd_context *cmd, struct labeller *lab
memcpy(dev->pvid, pvid, ID_LEN);
/* shouldn't happen */
if (device_list_find_dev(&_initial_duplicates, dev))
if (dev_in_device_list(dev, &_initial_duplicates))
log_debug_cache("Initial duplicate already in list %s", dev_name(dev));
else {
/*
@ -3026,11 +2710,9 @@ void lvmcache_get_max_name_lengths(struct cmd_context *cmd,
*pv_max_name_len = 0;
dm_list_iterate_items(vginfo, &_vginfos) {
if (!is_orphan_vg(vginfo->vgname)) {
len = strlen(vginfo->vgname);
if (*vg_max_name_len < len)
*vg_max_name_len = len;
}
len = strlen(vginfo->vgname);
if (*vg_max_name_len < len)
*vg_max_name_len = len;
dm_list_iterate_items(info, &vginfo->infos) {
len = strlen(dev_name(info->dev));

View File

@ -84,6 +84,7 @@ void lvmcache_del_dev(struct device *dev);
int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info *info,
struct lvmcache_vgsummary *vgsummary);
int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted);
int lvmcache_update_vg_from_write(struct volume_group *vg);
void lvmcache_lock_vgname(const char *vgname, int read_only);
void lvmcache_unlock_vgname(const char *vgname);
@ -186,6 +187,8 @@ int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, const char *pvid_ar
uint64_t lvmcache_max_metadata_size(void);
void lvmcache_save_metadata_size(uint64_t val);
int dev_in_device_list(struct device *dev, struct dm_list *head);
bool lvmcache_has_bad_metadata(struct device *dev);
bool lvmcache_has_old_metadata(struct cmd_context *cmd, const char *vgname, const char *vgid, struct device *dev);
@ -226,6 +229,4 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd);
unsigned int lvmcache_vg_info_count(void);
int lvmcache_pvsummary_count(const char *vgname);
#endif

View File

@ -1,19 +0,0 @@
#ifndef _CMD_ENUM_H
#define _CMD_ENUM_H
/*
* include/cmds.h is generated by the Makefile. For each command definition
* in command-lines.in, cmds.h contains:
* cmd(foo_CMD, foo)
*
* This header adds each of the foo_CMD's into an enum, so there's
* a unique integer identifier for each command definition.
*/
enum {
#define cmd(a, b) a ,
#include "cmds.h"
#undef cmd
};
#endif

View File

@ -159,11 +159,9 @@ static const char *_system_id_from_source(struct cmd_context *cmd, const char *s
#ifdef APP_MACHINEID_SUPPORT
if (!strcasecmp(source, "appmachineid")) {
sd_id128_t id = { 0 };
sd_id128_t id;
if (sd_id128_get_machine_app_specific(LVM_APPLICATION_ID, &id) != 0)
log_warn("WARNING: sd_id128_get_machine_app_specific() failed %s (%d).",
strerror(errno), errno);
sd_id128_get_machine_app_specific(LVM_APPLICATION_ID, &id);
if (dm_snprintf(buf, PATH_MAX, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)) < 0)
stack;
@ -608,46 +606,6 @@ static int _init_system_id(struct cmd_context *cmd)
return 1;
}
static void _init_device_ids_refresh(struct cmd_context *cmd)
{
const struct dm_config_node *cn;
const struct dm_config_value *cv;
int check_product_uuid = 0;
int check_hostname = 0;
char path[PATH_MAX];
char uuid[128] = { 0 };
cmd->device_ids_check_product_uuid = 0;
cmd->device_ids_check_hostname = 0;
if (!find_config_tree_bool(cmd, devices_device_ids_refresh_CFG, NULL))
return;
if (!(cn = find_config_tree_array(cmd, devices_device_ids_refresh_checks_CFG, NULL)))
return;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING)
continue;
if (!strcmp(cv->v.str, "product_uuid"))
check_product_uuid = 1;
if (!strcmp(cv->v.str, "hostname"))
check_hostname = 1;
}
if (check_product_uuid) {
const char *sysfs_dir = cmd->device_id_sysfs_dir ?: dm_sysfs_dir();
if (dm_snprintf(path, sizeof(path), "%sdevices/virtual/dmi/id/product_uuid", sysfs_dir) < 0)
return;
if (get_sysfs_value(path, uuid, sizeof(uuid), 0) && uuid[0])
cmd->product_uuid = dm_pool_strdup(cmd->libmem, uuid);;
if (cmd->product_uuid)
cmd->device_ids_check_product_uuid = 1;
}
if (check_hostname && cmd->hostname)
cmd->device_ids_check_hostname = 1;
}
static int _process_config(struct cmd_context *cmd)
{
mode_t old_umask;
@ -683,7 +641,6 @@ static int _process_config(struct cmd_context *cmd)
if (!dm_set_uuid_prefix(UUID_PREFIX))
return_0;
#endif
cmd->device_id_sysfs_dir = find_config_tree_str(cmd, devices_device_id_sysfs_dir_CFG, NULL);
dev_ext_info_src = find_config_tree_str(cmd, devices_external_device_info_source_CFG, NULL);
@ -819,8 +776,6 @@ static int _process_config(struct cmd_context *cmd)
if (!_init_system_id(cmd))
return_0;
_init_device_ids_refresh(cmd);
init_io_memory_size(find_config_tree_int(cmd, global_io_memory_size_CFG, NULL));
return 1;
@ -1171,7 +1126,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
return 1;
}
#define MAX_FILTERS 10
#define MAX_FILTERS 11
static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
{
@ -1186,6 +1141,26 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
* Update MAX_FILTERS definition above when adding new filters.
*/
/*
* sysfs filter. Only available on 2.6 kernels. Non-critical.
* Listed first because it's very efficient at eliminating
* unavailable devices.
*
* TODO: I suspect that using the lvm_type and device_id
* filters before this one may be more efficient.
*/
if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
if ((filters[nr_filt] = sysfs_filter_create()))
nr_filt++;
}
/* internal filter used by command processing. */
if (!(filters[nr_filt] = internal_filter_create())) {
log_error("Failed to create internal device filter");
goto bad;
}
nr_filt++;
/* global regex filter. Optional. */
if ((cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL))) {
if (!(filters[nr_filt] = regex_filter_create(cn->v, 0, 1))) {
@ -1218,17 +1193,6 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
}
nr_filt++;
/*
* sysfs filter. Only available on 2.6 kernels. Non-critical.
* Eliminates unavailable devices.
* TODO: this may be unnecessary now with device ids
* (currently not used for devs match to device id using syfs)
*/
if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
if ((filters[nr_filt] = sysfs_filter_create(dm_sysfs_dir())))
nr_filt++;
}
/* usable device filter. Required. */
if (!(filters[nr_filt] = usable_filter_create(cmd, cmd->dev_types, FILTER_MODE_NO_LVMETAD))) {
log_error("Failed to create usabled device filter");
@ -1548,7 +1512,7 @@ static void _init_rand(struct cmd_context *cmd)
return;
}
cmd->rand_seed = (unsigned) ((time(NULL) + getpid()) & 0xffffffff);
cmd->rand_seed = (unsigned) time(NULL) + (unsigned) getpid();
reset_lvm_errno(1);
}
@ -1623,7 +1587,7 @@ struct cmd_context *create_config_context(void)
if (!(cmd = zalloc(sizeof(*cmd))))
goto_out;
strncpy(cmd->system_dir, DEFAULT_SYS_DIR, sizeof(cmd->system_dir) - 1);
strcpy(cmd->system_dir, DEFAULT_SYS_DIR);
if (!_get_env_vars(cmd))
goto_out;
@ -1639,6 +1603,7 @@ struct cmd_context *create_config_context(void)
dm_list_init(&cmd->config_files);
dm_list_init(&cmd->tags);
dm_list_init(&cmd->hints);
if (!_init_lvm_conf(cmd))
goto_out;
@ -1703,6 +1668,7 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
dm_list_init(&cmd->formats);
dm_list_init(&cmd->segtypes);
dm_list_init(&cmd->tags);
dm_list_init(&cmd->hints);
dm_list_init(&cmd->config_files);
label_init();
@ -1755,8 +1721,10 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
/*
* Environment variable LVM_SYSTEM_DIR overrides this below.
*/
strncpy(cmd->system_dir, (system_dir) ? system_dir : DEFAULT_SYS_DIR,
sizeof(cmd->system_dir) - 1);
if (system_dir)
strncpy(cmd->system_dir, system_dir, sizeof(cmd->system_dir) - 1);
else
strcpy(cmd->system_dir, DEFAULT_SYS_DIR);
if (!_get_env_vars(cmd))
goto_out;
@ -1946,6 +1914,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);
devices_file_exit(cmd);
if (!dev_cache_exit())
stack;
_destroy_dev_types(cmd);
@ -2074,17 +2043,25 @@ void destroy_toolcontext(struct cmd_context *cmd)
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);
_destroy_filters(cmd);
if (cmd->mem)
dm_pool_destroy(cmd->mem);
devices_file_exit(cmd);
dev_cache_exit();
_destroy_dev_types(cmd);
_destroy_tags(cmd);
if ((cft_cmdline = remove_config_tree_by_source(cmd, CONFIG_STRING)))
config_destroy(cft_cmdline);
_destroy_config(cmd);
if (cmd->cft_def_hash)
dm_hash_destroy(cmd->cft_def_hash);
dm_device_list_destroy(&cmd->cache_dm_devs);
if (cmd->libmem)
dm_pool_destroy(cmd->libmem);
if (cmd->pending_delete_mem)
dm_pool_destroy(cmd->pending_delete_mem);
#ifndef VALGRIND_POOL
if (cmd->linebuffer) {
/* Reset stream buffering to defaults */
@ -2109,7 +2086,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
free(cmd->linebuffer);
}
#endif
destroy_config_context(cmd);
free(cmd);
lvmpolld_disconnect();

View File

@ -18,7 +18,6 @@
#include "lib/device/dev-cache.h"
#include "lib/device/dev-type.h"
#include "lib/commands/cmd_enum.h"
#include <limits.h>
@ -95,7 +94,6 @@ struct cmd_context {
const char *name; /* needed before cmd->command is set */
struct command_name *cname;
struct command *command;
int command_enum; /* duplicate from command->command_enum for lib code */
char **argv;
struct arg_values *opt_arg_values;
struct dm_list arg_value_groups;
@ -120,7 +118,6 @@ struct cmd_context {
* Machine and system identification.
*/
const char *system_id;
const char *product_uuid;
const char *hostname;
const char *kernel_vsn;
@ -147,7 +144,6 @@ struct cmd_context {
unsigned degraded_activation:1;
unsigned auto_set_activation_skip:1;
unsigned si_unit_consistency:1;
unsigned report_strict_type_mode:1;
unsigned report_binary_values_as_numeric:1;
unsigned report_mark_hidden_devices:1;
unsigned metadata_read_only:1;
@ -178,7 +174,7 @@ struct cmd_context {
unsigned activate_component:1; /* command activates component LV */
unsigned process_component_lvs:1; /* command processes also component LVs */
unsigned mirror_warn_printed:1; /* command already printed warning about non-monitored mirrors */
unsigned expect_missing_vg_device:1; /* when reading a vg it's expected that a dev for a pv isn't found */
unsigned pvscan_cache_single:1;
unsigned can_use_one_scan:1;
unsigned is_clvmd:1;
unsigned md_component_detection:1;
@ -187,6 +183,7 @@ struct cmd_context {
unsigned enable_hints:1; /* hints are enabled for cmds in general */
unsigned use_hints:1; /* if hints are enabled this cmd can use them */
unsigned pvscan_recreate_hints:1; /* enable special case hint handling for pvscan --cache */
unsigned hints_pvs_online:1; /* hints="pvs_online" */
unsigned scan_lvs:1;
unsigned wipe_outdated_pvs:1;
unsigned enable_devices_list:1; /* command is using --devices option */
@ -195,7 +192,6 @@ struct cmd_context {
unsigned create_edit_devices_file:1; /* command expects to create and/or edit devices file */
unsigned edit_devices_file:1; /* command expects to edit devices file */
unsigned filter_deviceid_skip:1; /* don't use filter-deviceid */
unsigned filter_regex_skip:1; /* don't use filter-regex */
unsigned filter_regex_with_devices_file:1; /* use filter-regex even when devices file is enabled */
unsigned filter_nodata_only:1; /* only use filters that do not require data from the dev */
unsigned run_by_dmeventd:1; /* command is being run by dmeventd */
@ -206,28 +202,18 @@ struct cmd_context {
unsigned ignore_device_name_mismatch:1; /* skip updating devices file names */
unsigned backup_disabled:1; /* skip repeated debug message */
unsigned event_activation:1; /* whether event_activation is set */
unsigned udevoutput:1;
unsigned online_vg_file_removed:1;
unsigned disable_dm_devs:1; /* temporarily disable use of dm devs cache */
unsigned filter_regex_set_preferred_name_disable:1; /* prevent dev_set_preferred_name */
unsigned device_ids_check_product_uuid:1;
unsigned device_ids_check_hostname:1;
unsigned device_ids_refresh_trigger:1;
unsigned device_ids_invalid:1;
/*
* Devices and filtering.
*/
struct dev_filter *filter;
struct dm_list hints;
struct dm_list use_devices; /* struct dev_use for each entry in devices file */
const char *md_component_checks;
const char *search_for_devnames; /* config file setting */
struct dm_list device_ids_check_serial;
const char *devicesfile; /* from --devicesfile option */
struct dm_list deviceslist; /* from --devices option, struct dm_str_list */
struct dm_list *cache_dm_devs; /* cache with UUIDs from DM_DEVICE_LIST (when available) */
/*
* Configuration.
*/
@ -255,7 +241,6 @@ struct cmd_context {
* Paths.
*/
const char *lib_dir; /* cache value global/library_dir */
const char *device_id_sysfs_dir;
char system_dir[PATH_MAX];
char dev_dir[PATH_MAX];
char proc_dir[PATH_MAX];

View File

@ -522,9 +522,7 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
if (!(dev->flags & DEV_REGULAR) || size2)
use_plain_read = 0;
/* Ensure there is extra '\0' after end of buffer since we pass
* buffer to funtions like strtoll() */
if (!(buf = zalloc(size + size2 + 1))) {
if (!(buf = zalloc(size + size2))) {
log_error("Failed to allocate circular buffer.");
return 0;
}
@ -741,13 +739,13 @@ static struct dm_config_value *_get_def_array_values(struct cmd_context *cmd,
}
/* Proper value always starts with '#'. */
if (token[0] != '#')
goto_bad;
goto bad;
while (token) {
/* Move to type identifier. Error on no char. */
token++;
if (!token[0])
goto_bad;
goto bad;
/* Move to the actual value and decode any "##" into "#". */
p = token + 1;
@ -1169,7 +1167,7 @@ int config_def_check(struct cft_check_handle *handle)
*vp = 0;
*rp = 0;
if (!handle->cmd->cft_def_hash) {
if (!(handle->cmd->cft_def_hash = dm_hash_create(500))) {
if (!(handle->cmd->cft_def_hash = dm_hash_create(60))) {
log_error("Failed to create configuration definition hash.");
r = 0; goto out;
}
@ -1300,9 +1298,8 @@ const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile
if (item->type != CFG_TYPE_STRING)
log_error(INTERNAL_ERROR "%s cfg tree element not declared as string.", path);
str = cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile);
if (!_config_disabled(cmd, item, path))
str = dm_config_tree_find_str(cmd->cft, path, str);
str = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile)
: dm_config_tree_find_str(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile));
if (profile_applied && profile)
remove_config_tree_by_source(cmd, profile->source);
@ -1325,9 +1322,8 @@ const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, st
if (!(item->flags & CFG_ALLOW_EMPTY))
log_error(INTERNAL_ERROR "%s cfg tree element not declared to allow empty values.", path);
str = cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile);
if (!_config_disabled(cmd, item, path))
str = dm_config_tree_find_str_allow_empty(cmd->cft, path, str);
str = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile)
: dm_config_tree_find_str_allow_empty(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile));
if (profile_applied && profile)
remove_config_tree_by_source(cmd, profile->source);
@ -1348,9 +1344,8 @@ int find_config_tree_int(struct cmd_context *cmd, int id, struct profile *profil
if (item->type != CFG_TYPE_INT)
log_error(INTERNAL_ERROR "%s cfg tree element not declared as integer.", path);
i = cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile);
if (!_config_disabled(cmd, item, path))
i = dm_config_tree_find_int(cmd->cft, path, i);
i = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile)
: dm_config_tree_find_int(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile));
if (profile_applied && profile)
remove_config_tree_by_source(cmd, profile->source);
@ -1371,9 +1366,8 @@ int64_t find_config_tree_int64(struct cmd_context *cmd, int id, struct profile *
if (item->type != CFG_TYPE_INT)
log_error(INTERNAL_ERROR "%s cfg tree element not declared as integer.", path);
i64 = cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile);
if (!_config_disabled(cmd, item, path))
i64 = dm_config_tree_find_int64(cmd->cft, path, i64);
i64 = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile)
: dm_config_tree_find_int64(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile));
if (profile_applied && profile)
remove_config_tree_by_source(cmd, profile->source);
@ -1394,9 +1388,8 @@ float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *pr
if (item->type != CFG_TYPE_FLOAT)
log_error(INTERNAL_ERROR "%s cfg tree element not declared as float.", path);
f = cfg_def_get_default_value(cmd, item, CFG_TYPE_FLOAT, profile);
if (!_config_disabled(cmd, item, path))
f = dm_config_tree_find_float(cmd->cft, path, f);
f = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_FLOAT, profile)
: dm_config_tree_find_float(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_FLOAT, profile));
if (profile_applied && profile)
remove_config_tree_by_source(cmd, profile->source);
@ -1415,9 +1408,8 @@ int find_config_bool(struct cmd_context *cmd, struct dm_config_tree *cft, int id
if (item->type != CFG_TYPE_BOOL)
log_error(INTERNAL_ERROR "%s cfg tree element not declared as boolean.", path);
b = cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, NULL);
if (!_config_disabled(cmd, item, path))
b = dm_config_tree_find_bool(cft, path, b);
b = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, NULL)
: dm_config_tree_find_bool(cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, NULL));
return b;
}
@ -1435,9 +1427,8 @@ int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profi
if (item->type != CFG_TYPE_BOOL)
log_error(INTERNAL_ERROR "%s cfg tree element not declared as boolean.", path);
b = cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, profile);
if (!_config_disabled(cmd, item, path))
b = dm_config_tree_find_bool(cmd->cft, path, b);
b = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, profile)
: dm_config_tree_find_bool(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, profile));
if (profile_applied && profile)
remove_config_tree_by_source(cmd, profile->source);
@ -1837,9 +1828,8 @@ static int _out_line_fn(const struct dm_config_node *cn, const char *line, void
char summary[MAX_COMMENT_LINE+1];
char version[9];
int pos = 0;
int space_prefix_len = 0;
const char *p;
size_t len;
char *space_prefix;
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
@ -1873,36 +1863,16 @@ static int _out_line_fn(const struct dm_config_node *cn, const char *line, void
/* Usual tree view with nodes and their values. */
if (out->tree_spec->valuesonly && !(cfg_def->type & CFG_TYPE_SECTION)) {
if ((space_prefix_len = strspn(line, "\t "))) {
len = strlen(line);
p = line + space_prefix_len;
/* copy space_prefix, skip key and '=', copy value */
if (!dm_pool_begin_object(out->mem, len))
return_0;
if (!dm_pool_grow_object(out->mem, line, space_prefix_len) ||
!dm_pool_grow_object(out->mem, p + strcspn(p, "=") + 1, len + 1)) {
dm_pool_abandon_object(out->mem);
return_0;
}
line = dm_pool_end_object(out->mem);
} else
line = strchr(line, '=') + 1;
}
if ((out->tree_spec->type != CFG_DEF_TREE_CURRENT) &&
(out->tree_spec->type != CFG_DEF_TREE_DIFF) &&
(out->tree_spec->type != CFG_DEF_TREE_FULL) &&
!out->tree_spec->valuesonly &&
(cfg_def->flags & (CFG_DEFAULT_UNDEFINED | CFG_DEFAULT_COMMENTED))) {
/* print with # at the front to comment out the line */
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn)) {
space_prefix_len = strspn(line, "\t ");
fprintf(out->fp, "%.*s%s%s\n", space_prefix_len, line, "# ",
line + space_prefix_len);
space_prefix = ((len = strspn(line, "\t "))) ? dm_pool_strndup(out->mem, line, len) : NULL;
fprintf(out->fp, "%s%s%s\n", space_prefix ? : "", "# ", line + len);
if (space_prefix)
dm_pool_free(out->mem, space_prefix);
}
return 1;
}
@ -1911,9 +1881,6 @@ static int _out_line_fn(const struct dm_config_node *cn, const char *line, void
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn))
fprintf(out->fp, "%s\n", line);
if (out->tree_spec->valuesonly && !(cfg_def->type & CFG_TYPE_SECTION) && space_prefix_len)
dm_pool_free(out->mem, (char *) line);
return 1;
}

View File

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

View File

@ -118,7 +118,6 @@
* the previous default value was set (uncommented) in lvm.conf.
*/
#include "lib/config/defaults.h"
#include "device_mapper/vdo/vdo_limits.h"
cfg_section(root_CFG_SECTION, "(root)", root_CFG_SECTION, 0, vsn(0, 0, 0), 0, NULL, NULL)
@ -174,7 +173,7 @@ cfg_section(activation_CFG_SECTION, "activation", root_CFG_SECTION, CFG_PROFILAB
cfg_section(metadata_CFG_SECTION, "metadata", root_CFG_SECTION, CFG_DEFAULT_COMMENTED, vsn(1, 0, 0), 0, NULL, NULL)
cfg_section(report_CFG_SECTION, "report", root_CFG_SECTION, CFG_PROFILABLE, vsn(1, 0, 0), 0, NULL,
cfg_section(report_CFG_SECTION, "report", root_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, vsn(1, 0, 0), 0, NULL,
"LVM report command output formatting.\n")
cfg_section(dmeventd_CFG_SECTION, "dmeventd", root_CFG_SECTION, 0, vsn(1, 2, 3), 0, NULL,
@ -224,9 +223,6 @@ cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADV
"Directory in which to create volume group device nodes.\n"
"Commands also accept this as a prefix on volume group names.\n")
cfg(devices_device_id_sysfs_dir_CFG, "device_id_sysfs_dir", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_UNSUPPORTED, CFG_TYPE_STRING, DEFAULT_DEVICE_ID_SYSFS_DIR, vsn(2, 3, 17), NULL, 0, NULL,
"Location of sysfs for finding device ids (for testing.)\n")
cfg_array(devices_scan_CFG, "scan", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADVANCED, CFG_TYPE_STRING, "#S/dev", vsn(1, 0, 0), NULL, 0, NULL,
"Directories containing device nodes to use with LVM.\n")
@ -280,7 +276,7 @@ cfg_array(devices_preferred_names_CFG, "preferred_names", devices_CFG_SECTION, C
"preferred_names = [ \"^/dev/mpath/\", \"^/dev/mapper/mpath\", \"^/dev/[hs]d\" ]\n"
"#\n")
cfg(devices_use_devicesfile_CFG, "use_devicesfile", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_DEVICES_FILE, vsn(2, 3, 12), "@DEFAULT_USE_DEVICES_FILE@", 0, NULL,
cfg(devices_use_devicesfile_CFG, "use_devicesfile", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_DEVICES_FILE, vsn(2, 3, 12), NULL, 0, NULL,
"Enable or disable the use of a devices file.\n"
"When enabled, lvm will only use devices that\n"
"are lised in the devices file. A devices file will\n"
@ -306,22 +302,6 @@ cfg(devices_search_for_devnames_CFG, "search_for_devnames", devices_CFG_SECTION,
"at other devices, but only those that are likely to have the PV.\n"
"If \"all\", lvm will look at all devices on the system.\n")
cfg(devices_device_ids_refresh_CFG, "device_ids_refresh", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 3, 23), NULL, 0, NULL,
"Find PVs on new devices and update the device IDs in the devices file.\n"
"If PVs are restored or moved to a new system with new devices, but\n"
"an old system.devices remains with old device IDs, then search for\n"
"the PVIDs on new devices and update the device IDs in system.devices.\n"
"The original device IDs must also not be found on the new system.\n"
"See device_ids_refresh_check for conditions that trigger the refresh.\n")
cfg_array(devices_device_ids_refresh_checks_CFG, "device_ids_refresh_checks", devices_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "#Sproduct_uuid#Shostname", vsn(2, 3, 23), NULL, 0, NULL,
"Conditions that trigger device_ids_refresh to locate PVIDs on new devices.\n"
"product_uuid: refresh if /sys/devices/virtual/dmi/id/product_uuid does not\n"
"match the value saved in system.devices.\n"
"hostname: refresh if hostname does not match the value saved in system.devices.\n"
"(hostname is used if product_uuid is not available.)\n"
"Remove values from this list to prevent lvm from using them.\n")
cfg_array(devices_filter_CFG, "filter", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "#Sa|.*|", vsn(1, 0, 0), NULL, 0, NULL,
"Limit the block devices that are used by LVM commands.\n"
"This is a list of regular expressions used to accept or reject block\n"
@ -728,11 +708,12 @@ cfg(allocation_vdo_use_deduplication_CFG, "vdo_use_deduplication", allocation_CF
cfg(allocation_vdo_use_metadata_hints_CFG, "vdo_use_metadata_hints", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_USE_METADATA_HINTS, VDO_1ST_VSN, NULL, 0, NULL,
"Enables or disables whether VDO volume should tag its latency-critical\n"
"writes with the REQ_SYNC flag. Some device mapper targets such as dm-raid5\n"
"process writes with this flag at a higher priority.\n")
"process writes with this flag at a higher priority.\n"
"Default is enabled.\n")
cfg(allocation_vdo_minimum_io_size_CFG, "vdo_minimum_io_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_MINIMUM_IO_SIZE, VDO_1ST_VSN, NULL, 0, NULL,
"The minimum IO size for VDO volume to accept, in bytes.\n"
"Valid values are 512 or 4096. The recommended value is 4096.\n")
"Valid values are 512 or 4096. The recommended and default value is 4096.\n")
cfg(allocation_vdo_block_map_cache_size_mb_CFG, "vdo_block_map_cache_size_mb", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_BLOCK_MAP_CACHE_SIZE_MB, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the amount of memory in MiB allocated for caching block map\n"
@ -745,11 +726,10 @@ cfg(allocation_vdo_block_map_era_length_CFG, "vdo_block_map_period", allocation_
"The speed with which the block map cache writes out modified block map pages.\n"
"A smaller era length is likely to reduce the amount time spent rebuilding,\n"
"at the cost of increased block map writes during normal operation.\n"
"The maximum and recommended value is " DM_TO_STRING(DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM)
"; the minimum value is " DM_TO_STRING(DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM) ".\n")
"The maximum and recommended value is 16380; the minimum value is 1.\n")
cfg(allocation_vdo_check_point_frequency_CFG, "vdo_check_point_frequency", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_CHECK_POINT_FREQUENCY, VDO_1ST_VSN, NULL, vsn(2, 3, 22), NULL,
"Deprecated option to set default check point frequency for VDO volume.\n")
cfg(allocation_vdo_check_point_frequency_CFG, "vdo_check_point_frequency", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_CHECK_POINT_FREQUENCY, VDO_1ST_VSN, NULL, 0, NULL,
"The default check point frequency for VDO volume.\n")
// vdo format
cfg(allocation_vdo_use_sparse_index_CFG, "vdo_use_sparse_index", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_USE_SPARSE_INDEX, VDO_1ST_VSN, NULL, 0, NULL,
@ -768,34 +748,27 @@ cfg(allocation_vdo_slab_size_mb_CFG, "vdo_slab_size_mb", allocation_CFG_SECTION,
cfg(allocation_vdo_ack_threads_CFG, "vdo_ack_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_ACK_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the number of threads to use for acknowledging\n"
"completion of requested VDO I/O operations.\n"
"The value must be at in range [" DM_TO_STRING(DM_VDO_ACK_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_ACK_THREADS_MAXIMUM) "].\n")
"The value must be at in range [0..100].\n")
cfg(allocation_vdo_bio_threads_CFG, "vdo_bio_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_BIO_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the number of threads to use for submitting I/O\n"
"operations to the storage device of VDO volume.\n"
"The value must be in range [" DM_TO_STRING(DM_VDO_BIO_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_BIO_THREADS_MAXIMUM) "].\n"
"The value must be in range [1..100]\n"
"Each additional thread after the first will use an additional 18MiB of RAM,\n"
"plus 1.12 MiB of RAM per megabyte of configured read cache size.\n")
cfg(allocation_vdo_bio_rotation_CFG, "vdo_bio_rotation", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_BIO_ROTATION, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the number of I/O operations to enqueue for each bio-submission\n"
"thread before directing work to the next. The value must be in range ["
DM_TO_STRING(DM_VDO_BIO_ROTATION_MINIMUM) ".."
DM_TO_STRING(DM_VDO_BIO_ROTATION_MAXIMUM) "].\n")
"thread before directing work to the next. The value must be in range [1..1024].\n")
cfg(allocation_vdo_cpu_threads_CFG, "vdo_cpu_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_CPU_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the number of threads to use for CPU-intensive work such as\n"
"hashing or compression for VDO volume. The value must be in range ["
DM_TO_STRING(DM_VDO_CPU_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_CPU_THREADS_MAXIMUM) "].\n")
"hashing or compression for VDO volume. The value must be in range [1..100]\n")
cfg(allocation_vdo_hash_zone_threads_CFG, "vdo_hash_zone_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_HASH_ZONE_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the number of threads across which to subdivide parts of the VDO\n"
"processing based on the hash value computed from the block data.\n"
"The value must be at in range [" DM_TO_STRING(DM_VDO_HASH_ZONE_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_HASH_ZONE_THREADS_MAXIMUM) "].\n"
"The value must be at in range [0..100].\n"
"vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be\n"
"either all zero or all non-zero.\n")
@ -804,8 +777,7 @@ cfg(allocation_vdo_logical_threads_CFG, "vdo_logical_threads", allocation_CFG_SE
"processing based on the hash value computed from the block data.\n"
"A logical thread count of 9 or more will require explicitly specifying\n"
"a sufficiently large block map cache size, as well.\n"
"The value must be in range [" DM_TO_STRING(DM_VDO_LOGICAL_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_LOGICAL_THREADS_MAXIMUM) "].\n"
"The value must be in range [0..100].\n"
"vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be\n"
"either all zero or all non-zero.\n")
@ -813,8 +785,7 @@ cfg(allocation_vdo_physical_threads_CFG, "vdo_physical_threads", allocation_CFG_
"Specifies the number of threads across which to subdivide parts of the VDO\n"
"processing based on physical block addresses.\n"
"Each additional thread after the first will use an additional 10MiB of RAM.\n"
"The value must be in range [" DM_TO_STRING(DM_VDO_PHYSICAL_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_PHYSICAL_THREADS_MAXIMUM) "].\n"
"The value must be in range [0..16].\n"
"vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be\n"
"either all zero or all non-zero.\n")
@ -840,7 +811,7 @@ cfg(allocation_vdo_max_discard_CFG, "vdo_max_discard", allocation_CFG_SECTION, C
"The default and minimum is 1. The maximum is UINT_MAX / 4096.\n")
cfg(allocation_vdo_pool_header_size_CFG, "vdo_pool_header_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_POOL_HEADER_SIZE_KB, vsn(2, 3, 12), NULL, 0, NULL,
"Specified the empty header size in KiB at the front and end of vdo pool device.\n")
"Specified the emptry header size in KiB at the front and end of vdo pool device.\n")
cfg(log_report_command_log_CFG, "report_command_log", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_BOOL, DEFAULT_COMMAND_LOG_REPORT, vsn(2, 2, 158), NULL, 0, NULL,
"Enable or disable LVM log reporting.\n"
@ -963,7 +934,7 @@ cfg(backup_archive_CFG, "archive", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CF
"Think very hard before turning this off.\n")
cfg_runtime(backup_archive_dir_CFG, "archive_dir", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, vsn(1, 0, 0), 0, NULL,
"Location of the metadata archive files.\n"
"Location of the metdata archive files.\n"
"Remember to back up this directory regularly!\n")
cfg(backup_retain_min_CFG, "retain_min", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_ARCHIVE_NUMBER, vsn(1, 0, 0), NULL, 0, NULL,
@ -1148,11 +1119,28 @@ cfg(global_lvdisplay_shows_full_device_path_CFG, "lvdisplay_shows_full_device_pa
"was never a valid path in the /dev filesystem.\n")
cfg(global_event_activation_CFG, "event_activation", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 3, 1), 0, 0, NULL,
"Disable event based autoactivation commands.\n"
"WARNING: setting this to zero may cause machine startup to fail.\n"
"Previously, setting this to zero would enable static autoactivation\n"
"services (via the lvm2-activation-generator), but the autoactivation\n"
"services and generator have been removed.\n")
"Activate LVs based on system-generated device events.\n"
"When a PV appears on the system, a system-generated uevent triggers\n"
"the lvm2-pvscan service which runs the pvscan --cache -aay command.\n"
"If the new PV completes a VG, pvscan autoactivates LVs in the VG.\n"
"When event_activation is disabled, the lvm2-activation services are\n"
"generated and run at fixed points during system startup. These\n"
"services run vgchange -aay to autoactivate LVs in VGs that happen\n"
"to be present at that point in time.\n"
"See the --setautoactivation option or the auto_activation_volume_list\n"
"setting to configure autoactivation for specific VGs or LVs.\n")
cfg_array(global_event_activation_options_CFG, "event_activation_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_EVENT_ACTIVATION_OPTIONS, vsn(2, 3, 14), NULL, 0, NULL,
"Set event activation options.\n"
"service_to_event: begin with fixed activation services,\n"
"then switch to event based activation.\n"
"event_only: only use event based activation.\n"
"service_only: only use fixed activation services.\n"
"(This is equivalent to event_activation=0.)\n"
"Autoactivation commands should set --eventactivation service|event\n"
"to indicate if they are performing service or event activation.\n"
"An autoactivation command may then be skipped according to the\n"
"value of this setting.\n")
cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 2, 93), 0, vsn(2, 3, 0), NULL,
NULL)
@ -1193,7 +1181,7 @@ cfg(global_lvmlockctl_kill_command_CFG, "lvmlockctl_kill_command", global_CFG_SE
cfg(global_thin_check_executable_CFG, "thin_check_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, THIN_CHECK_CMD, vsn(2, 2, 94), "@THIN_CHECK_CMD@", 0, NULL,
"The full path to the thin_check command.\n"
"LVM uses this command to check that a thin pool metadata device is in a\n"
"LVM uses this command to check that a thin metadata device is in a\n"
"usable state. When a thin pool is activated and after it is\n"
"deactivated, this command is run. Activation will only proceed if\n"
"the command has an exit status of 0. Set to \"\" to skip this check.\n"
@ -1211,12 +1199,6 @@ cfg(global_thin_repair_executable_CFG, "thin_repair_executable", global_CFG_SECT
"an unusable state. Also see thin_repair_options.\n"
"(See package device-mapper-persistent-data or thin-provisioning-tools)\n")
cfg(global_thin_restore_executable_CFG, "thin_restore_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, THIN_RESTORE_CMD, vsn(2, 3, 22), "@THIN_RESTORE_CMD@", 0, NULL,
"The full path to the thin_restore command.\n"
"LVM uses this command to restore generated data for a thin pool metadata device.\n"
"Also see thin_restore_options.\n"
"(See package device-mapper-persistent-data or thin-provisioning-tools)\n")
cfg_array(global_thin_check_options_CFG, "thin_check_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_THIN_CHECK_OPTIONS_CONFIG, vsn(2, 2, 96), NULL, 0, NULL,
"List of options passed to the thin_check command.\n"
"With thin_check version 2.1 or newer you can add the option\n"
@ -1227,9 +1209,6 @@ cfg_array(global_thin_check_options_CFG, "thin_check_options", global_CFG_SECTIO
cfg_array(global_thin_repair_options_CFG, "thin_repair_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_THIN_REPAIR_OPTIONS_CONFIG, vsn(2, 2, 100), NULL, 0, NULL,
"List of options passed to the thin_repair command.\n")
cfg_array(global_thin_restore_options_CFG, "thin_restore_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_THIN_RESTORE_OPTIONS_CONFIG, vsn(2, 3, 22), NULL, 0, NULL,
"List of options passed to the thin_restore command.\n")
cfg_array(global_thin_disabled_features_CFG, "thin_disabled_features", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 99), NULL, 0, NULL,
"Features to not use in the thin driver.\n"
"This can be helpful for testing, or to avoid using a feature that is\n"
@ -1270,12 +1249,6 @@ cfg(global_cache_repair_executable_CFG, "cache_repair_executable", global_CFG_SE
"an unusable state. Also see cache_repair_options.\n"
"(See package device-mapper-persistent-data or thin-provisioning-tools)\n")
cfg(global_cache_restore_executable_CFG, "cache_restore_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, CACHE_RESTORE_CMD, vsn(2, 3, 22), "@CACHE_RESTORE_CMD@", 0, NULL,
"The full path to the cache_restore command.\n"
"LVM uses this command to restore generated data for a cache metadata device.\n"
"Also see cache_restore_options.\n"
"(See package device-mapper-persistent-data or thin-provisioning-tools)\n")
cfg_array(global_cache_check_options_CFG, "cache_check_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_CHECK_OPTIONS_CONFIG, vsn(2, 2, 108), NULL, 0, NULL,
"List of options passed to the cache_check command.\n"
"With cache_check version 5.0 or newer you should include the option\n"
@ -1284,9 +1257,6 @@ cfg_array(global_cache_check_options_CFG, "cache_check_options", global_CFG_SECT
cfg_array(global_cache_repair_options_CFG, "cache_repair_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG, vsn(2, 2, 108), NULL, 0, NULL,
"List of options passed to the cache_repair command.\n")
cfg_array(global_cache_restore_options_CFG, "cache_restore_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_RESTORE_OPTIONS_CONFIG, vsn(2, 3, 22), NULL, 0, NULL,
"List of options passed to the cache_restore command.\n")
cfg(global_vdo_format_executable_CFG, "vdo_format_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, VDO_FORMAT_CMD, VDO_1ST_VSN, "@VDO_FORMAT_CMD@", 0, NULL,
"The full path to the vdoformat command.\n"
"LVM uses this command to initial data volume for VDO type logical volume\n")
@ -1297,10 +1267,10 @@ cfg_array(global_vdo_format_options_CFG, "vdo_format_options", global_CFG_SECTIO
cfg_array(global_vdo_disabled_features_CFG, "vdo_disabled_features", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 3, 11), NULL, 0, NULL,
"Features to not use in the vdo driver.\n"
"This can be helpful for testing, or to avoid using a feature that is\n"
"causing problems. Features include: online_rename, version4\n"
"causing problems. Features include: online_rename\n"
"#\n"
"Example\n"
"vdo_disabled_features = [ \"online_rename\", \"version4\" ]\n"
"vdo_disabled_features = [ \"online_rename\" ]\n"
"#\n")
cfg(global_fsadm_executable_CFG, "fsadm_executable", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_FSADM_PATH, vsn(2, 2, 170), "@FSADM_PATH@", 0, NULL,
@ -1416,11 +1386,11 @@ cfg(activation_use_linear_target_CFG, "use_linear_target", activation_CFG_SECTIO
cfg(activation_reserved_stack_CFG, "reserved_stack", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_RESERVED_STACK, vsn(1, 0, 0), NULL, 0, NULL,
"Stack size in KiB to reserve for use while devices are suspended.\n"
"Insufficient reserve risks I/O deadlock during device suspension.\n")
"Insufficent reserve risks I/O deadlock during device suspension.\n")
cfg(activation_reserved_memory_CFG, "reserved_memory", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_RESERVED_MEMORY, vsn(1, 0, 0), NULL, 0, NULL,
"Memory size in KiB to reserve for use while devices are suspended.\n"
"Insufficient reserve risks I/O deadlock during device suspension.\n")
"Insufficent reserve risks I/O deadlock during device suspension.\n")
cfg(activation_process_priority_CFG, "process_priority", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_PROCESS_PRIORITY, vsn(1, 0, 0), NULL, 0, NULL,
"Nice value used while devices are suspended.\n"
@ -1546,7 +1516,7 @@ cfg(activation_raid_fault_policy_CFG, "raid_fault_policy", activation_CFG_SECTIO
"This includes LVs that have the following segment types:\n"
"raid1, raid4, raid5*, and raid6*.\n"
"If a device in the LV fails, the policy determines the steps\n"
"performed by dmeventd automatically, and the steps performed by the\n"
"performed by dmeventd automatically, and the steps perfomed by the\n"
"manual command lvconvert --repair --use-policies.\n"
"Automatic handling requires dmeventd to be monitoring the LV.\n"
"#\n"
@ -1568,7 +1538,7 @@ cfg_runtime(activation_mirror_image_fault_policy_CFG, "mirror_image_fault_policy
"(copies) and a mirror log. A disk log ensures that a mirror LV does\n"
"not need to be re-synced (all copies made the same) every time a\n"
"machine reboots or crashes. If a device in the LV fails, this policy\n"
"determines the steps performed by dmeventd automatically, and the steps\n"
"determines the steps perfomed by dmeventd automatically, and the steps\n"
"performed by the manual command lvconvert --repair --use-policies.\n"
"Automatic handling requires dmeventd to be monitoring the LV.\n"
"#\n"
@ -1712,7 +1682,7 @@ cfg(activation_monitoring_CFG, "monitoring", activation_CFG_SECTION, CFG_DEFAULT
cfg(activation_polling_interval_CFG, "polling_interval", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_INTERVAL, vsn(2, 2, 63), NULL, 0, NULL,
"Check pvmove or lvconvert progress at this interval (seconds).\n"
"When pvmove or lvconvert must wait for the kernel to finish\n"
"synchronizing or merging data, they check and report progress at\n"
"synchronising or merging data, they check and report progress at\n"
"intervals of this number of seconds. If this is set to 0 and there\n"
"is only one thing to wait for, there are no progress reports, but\n"
"the process is awoken immediately once the operation is complete.\n")
@ -1843,14 +1813,7 @@ cfg(report_output_format_CFG, "output_format", report_CFG_SECTION, CFG_PROFILABL
" one report per command, each report is prefixed with report's\n"
" name for identification.\n"
" json\n"
" JSON format.\n"
" json_std\n"
" JSON format that is more compliant with JSON standard.\n"
" Compared to original \"json\" format:\n"
" - it does not use double quotes around numeric values,\n"
" - it uses 'null' for undefined numeric values,\n"
" - it prints string list as proper JSON array of strings instead of a single string."
"\n")
" JSON format.\n")
cfg(report_compact_output_CFG, "compact_output", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_COMPACT_OUTPUT, vsn(2, 2, 115), NULL, 0, NULL,
"Do not print empty values for all report fields.\n"
@ -1879,12 +1842,8 @@ cfg(report_buffered_CFG, "buffered", report_CFG_SECTION, CFG_PROFILABLE | CFG_DE
"execution. Otherwise, if buffering is not used, each object is\n"
"reported as soon as its processing is finished.\n")
cfg(report_headings_CFG, "headings", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_REP_HEADINGS, vsn(1, 0, 0), NULL, 0, NULL,
"Format of LVM command's report output headings.\n"
"Accepted values:\n"
" 0 no headings,\n"
" 1 headings with column abbreviations,\n"
" 2 headings with full column names.\n")
cfg(report_headings_CFG, "headings", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_HEADINGS, vsn(1, 0, 0), NULL, 0, NULL,
"Show headings for columns on report.\n")
cfg(report_separator_CFG, "separator", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_REP_SEPARATOR, vsn(1, 0, 0), NULL, 0, NULL,
"A separator to use on report after each field.\n")

View File

@ -105,8 +105,6 @@
# define DEFAULT_DMEVENTD_PATH DMEVENTD_PATH
#endif
#define DEFAULT_MAX_EXEC_ARGS 15 /* Max number of accepted options args */
#ifdef THIN_CHECK_NEEDS_CHECK
# define DEFAULT_THIN_CHECK_OPTION1 "-q"
# define DEFAULT_THIN_CHECK_OPTION2 "--clear-needs-check-flag"
@ -119,8 +117,6 @@
#define DEFAULT_THIN_REPAIR_OPTION1 ""
#define DEFAULT_THIN_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_THIN_REPAIR_OPTION1
#define DEFAULT_THIN_RESTORE_OPTION1 ""
#define DEFAULT_THIN_RESTORE_OPTIONS_CONFIG "#S" DEFAULT_THIN_RESTORE_OPTION1
#define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
#define DEFAULT_THIN_POOL_CROP_METADATA 0
#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE_V1_KB (UINT64_C(255) * ((1 << 14) - 64) * 4) /* KB */ /* 0x3f8040 blocks */
@ -149,8 +145,6 @@
#define DEFAULT_CACHE_REPAIR_OPTION1 ""
#define DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_CACHE_REPAIR_OPTION1
#define DEFAULT_CACHE_RESTORE_OPTION1 ""
#define DEFAULT_CACHE_RESTORE_OPTIONS_CONFIG "#S" DEFAULT_CACHE_RESTORE_OPTION1
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
#define DEFAULT_CACHE_POOL_MAX_CHUNKS 1000000
@ -330,14 +324,15 @@
#define DEFAULT_DEVICES_FILE "system.devices"
#define DEFAULT_SEARCH_FOR_DEVNAMES "all"
#define DEFAULT_SEARCH_FOR_DEVNAMES "auto"
#define DEFAULT_WWIDS_FILE "/etc/multipath/wwids"
#define DEFAULT_EVENT_ACTIVATION_OPTION1 "service_to_event"
#define DEFAULT_EVENT_ACTIVATION_OPTIONS "#S" DEFAULT_EVENT_ACTIVATION_OPTION1
#define PVS_ONLINE_DIR DEFAULT_RUN_DIR "/pvs_online"
#define VGS_ONLINE_DIR DEFAULT_RUN_DIR "/vgs_online"
#define PVS_LOOKUP_DIR DEFAULT_RUN_DIR "/pvs_lookup"
#define DEFAULT_DEVICE_ID_SYSFS_DIR "/sys/" /* trailing / to match dm_sysfs_dir() */
#endif /* _LVM_DEFAULTS_H */

View File

@ -58,7 +58,6 @@ bool bcache_read_bytes(struct bcache *cache, int di, uint64_t start, size_t len,
block_address bb, be;
uint64_t block_size = bcache_block_sectors(cache) << SECTOR_SHIFT;
uint64_t block_offset = start % block_size;
size_t blen;
bcache_prefetch_bytes(cache, di, start, len);
@ -68,7 +67,7 @@ bool bcache_read_bytes(struct bcache *cache, int di, uint64_t start, size_t len,
if (!bcache_get(cache, di, bb, 0, &b))
return false;
blen = _min(block_size - block_offset, len);
size_t blen = _min(block_size - block_offset, len);
memcpy(data, ((unsigned char *) b->data) + block_offset, blen);
bcache_put(b);

View File

@ -53,7 +53,6 @@ static struct {
const char *dev_dir;
int has_scanned;
dev_t st_dev;
struct dm_list dirs;
struct dm_list files;
@ -80,7 +79,6 @@ static void _dev_init(struct device *dev)
dm_list_init(&dev->aliases);
dm_list_init(&dev->ids);
dm_list_init(&dev->wwids);
}
void dev_destroy_file(struct device *dev)
@ -352,14 +350,16 @@ static int _add_alias(struct device *dev, const char *path, enum add_hash hash)
goto out;
}
if (!(path = _strdup(path)) ||
if (!(path = dm_pool_strdup(_cache.mem, path)) ||
!(sl = _zalloc(sizeof(*sl)))) {
log_error("Failed to add allias to dev cache.");
return 0;
}
if (!strncmp(path, "/dev/nvme", 9))
if (!strncmp(path, "/dev/nvme", 9)) {
log_debug("Found nvme device %s", dev_name(dev));
dev->flags |= DEV_IS_NVME;
}
sl->str = path;
@ -382,25 +382,6 @@ out:
return 1;
}
int get_sysfs_binary(const char *path, char *buf, size_t buf_size, int *retlen)
{
int ret;
int fd;
fd = open(path, O_RDONLY);
if (fd < 0)
return 0;
ret = read(fd, buf, buf_size);
if (close(fd))
log_sys_debug("close", path);
if (ret <= 0)
return 0;
*retlen = ret;
return 1;
}
int get_sysfs_value(const char *path, char *buf, size_t buf_size, int error_if_no_value)
{
FILE *fp;
@ -1083,18 +1064,11 @@ static void _insert_dirs(struct dm_list *dirs)
struct dir_list *dl;
struct udev *udev = NULL;
int with_udev;
struct stat tinfo;
with_udev = obtain_device_list_from_udev() &&
(udev = udev_get_library_context());
dm_list_iterate_items(dl, &_cache.dirs) {
if (stat(dl->dir, &tinfo) < 0) {
log_warn("WARNING: Cannot use dir %s, %s.",
dl->dir, strerror(errno));
continue;
}
_cache.st_dev = tinfo.st_dev;
if (with_udev) {
if (!_insert_udev_dir(udev, dl->dir))
log_debug_devs("%s: Failed to insert devices from "
@ -1117,17 +1091,9 @@ static int _device_in_udev_db(const dev_t d)
static void _insert_dirs(struct dm_list *dirs)
{
struct dir_list *dl;
struct stat tinfo;
dm_list_iterate_items(dl, &_cache.dirs) {
if (stat(dl->dir, &tinfo) < 0) {
log_warn("WARNING: Cannot use dir %s, %s.",
dl->dir, strerror(errno));
continue;
}
_cache.st_dev = tinfo.st_dev;
dm_list_iterate_items(dl, &_cache.dirs)
_insert_dir(dl->dir);
}
}
#endif /* UDEV_SYNC_SUPPORT */
@ -1162,11 +1128,6 @@ static int _insert(const char *path, const struct stat *info,
return 1;
}
if (info->st_dev != _cache.st_dev) {
log_debug_devs("%s: Different filesystem in directory", path);
return 1;
}
if (rec && !_insert_dir(path))
return 0;
} else { /* add a device */
@ -1180,17 +1141,6 @@ static int _insert(const char *path, const struct stat *info,
return 1;
}
static void _drop_all_aliases(struct device *dev)
{
struct dm_str_list *strl, *strl2;
dm_list_iterate_items_safe(strl, strl2, &dev->aliases) {
log_debug("Drop alias for %d:%d %s.", (int)MAJOR(dev->dev), (int)MINOR(dev->dev), strl->str);
dm_hash_remove(_cache.names, strl->str);
dm_list_del(&strl->list);
}
}
void dev_cache_scan(struct cmd_context *cmd)
{
log_debug_devs("Creating list of system devices.");
@ -1275,7 +1225,7 @@ int dev_cache_init(struct cmd_context *cmd)
if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
return_0;
if (!(_cache.names = dm_hash_create(1020)) ||
if (!(_cache.names = dm_hash_create(120)) ||
!(_cache.vgid_index = dm_hash_create(30)) ||
!(_cache.lvid_index = dm_hash_create(29))) {
dm_pool_destroy(_cache.mem);
@ -1354,7 +1304,6 @@ int dev_cache_exit(void)
dm_hash_iterate(n, _cache.names) {
dev = (struct device *) dm_hash_get_data(_cache.names, n);
free_dids(&dev->ids);
free_wwids(&dev->wwids);
}
}
@ -1401,6 +1350,59 @@ int dev_cache_add_dir(const char *path)
return 1;
}
/* Check cached device name is still valid before returning it */
/* This should be a rare occurrence */
/* set quiet if the cache is expected to be out-of-date */
/* FIXME Make rest of code pass/cache struct device instead of dev_name */
const char *dev_name_confirmed(struct device *dev, int quiet)
{
struct stat buf;
const char *name;
int r;
if ((dev->flags & DEV_REGULAR))
return dev_name(dev);
while ((r = stat(name = dm_list_item(dev->aliases.n,
struct dm_str_list)->str, &buf)) ||
(buf.st_rdev != dev->dev)) {
if (r < 0) {
if (quiet)
log_sys_debug("stat", name);
else
log_sys_error("stat", name);
}
if (quiet)
log_debug_devs("Path %s no longer valid for device(%d,%d)",
name, (int) MAJOR(dev->dev),
(int) MINOR(dev->dev));
else
log_warn("Path %s no longer valid for device(%d,%d)",
name, (int) MAJOR(dev->dev),
(int) MINOR(dev->dev));
/* Remove the incorrect hash entry */
dm_hash_remove(_cache.names, name);
/* Leave list alone if there isn't an alternative name */
/* so dev_name will always find something to return. */
/* Otherwise add the name to the correct device. */
if (dm_list_size(&dev->aliases) > 1) {
dm_list_del(dev->aliases.n);
if (!r)
_insert(name, &buf, 0, obtain_device_list_from_udev());
continue;
}
/* Scanning issues this inappropriately sometimes. */
log_debug_devs("Aborting - please provide new pathname for what "
"used to be %s", name);
return NULL;
}
return dev_name(dev);
}
struct device *dev_hash_get(const char *name)
{
return (struct device *) dm_hash_lookup(_cache.names, name);
@ -1429,23 +1431,26 @@ static void _remove_alias(struct device *dev, const char *name)
* deactivated LV. Those old paths are all invalid and are dropped here.
*/
void dev_cache_verify_aliases(struct device *dev)
static void _verify_aliases(struct device *dev, const char *newname)
{
struct dm_str_list *strl, *strl2;
struct stat st;
dm_list_iterate_items_safe(strl, strl2, &dev->aliases) {
/* newname was just stat'd and added by caller */
if (newname && !strcmp(strl->str, newname))
continue;
if (stat(strl->str, &st) || (st.st_rdev != dev->dev)) {
log_debug("Drop alias for %d:%d invalid path %s %d:%d.",
(int)MAJOR(dev->dev), (int)MINOR(dev->dev), strl->str,
(int)MAJOR(st.st_rdev), (int)MINOR(st.st_rdev));
log_debug("Drop invalid path %s for %d:%d (new path %s).",
strl->str, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), newname ?: "");
dm_hash_remove(_cache.names, strl->str);
dm_list_del(&strl->list);
}
}
}
static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f, int existing)
struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f)
{
struct device *dev = (struct device *) dm_hash_lookup(_cache.names, name);
struct stat st;
@ -1459,18 +1464,13 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
if (dev && (dev->flags & DEV_REGULAR))
return dev;
if (dev && dm_list_empty(&dev->aliases)) {
/* shouldn't happen */
log_warn("Ignoring dev with no valid paths for %s.", name);
return NULL;
}
/*
* The requested path is invalid, remove any dev-cache info for it.
* The requested path is invalid, remove any dev-cache
* info for it.
*/
if (stat(name, &st)) {
if (dev) {
log_debug("Device path %s is invalid for %d:%d %s.",
log_print("Device path %s is invalid for %d:%d %s.",
name, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev));
dm_hash_remove(_cache.names, name);
@ -1478,17 +1478,11 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
_remove_alias(dev, name);
/* Remove any other names in dev->aliases that are incorrect. */
dev_cache_verify_aliases(dev);
_verify_aliases(dev, NULL);
}
return NULL;
}
if (dev && dm_list_empty(&dev->aliases)) {
/* shouldn't happen */
log_warn("Ignoring dev with no valid paths for %s.", name);
return NULL;
}
if (!S_ISBLK(st.st_mode)) {
log_debug("Not a block device %s.", name);
return NULL;
@ -1499,110 +1493,26 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
* Remove incorrect info and then add new dev-cache entry.
*/
if (dev && (st.st_rdev != dev->dev)) {
struct device *dev_by_devt = (struct device *) btree_lookup(_cache.devices, (uint32_t) st.st_rdev);
log_debug("Device path %s does not match %d:%d %s.",
name, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev));
/*
* lvm commands create this condition when they
* activate/deactivate LVs combined with creating new LVs.
* The command does not purge dev structs when deactivating
* an LV (which it probably should do), but the better
* approach would be not using dev-cache at all for LVs.
*/
dm_hash_remove(_cache.names, name);
log_debug("Dropping aliases for device entry %d:%d %s for new device %d:%d %s.",
(int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev),
(int)MAJOR(st.st_rdev), (int)MINOR(st.st_rdev), name);
_remove_alias(dev, name);
_drop_all_aliases(dev);
/* Remove any other names in dev->aliases that are incorrect. */
_verify_aliases(dev, NULL);
if (dev_by_devt) {
log_debug("Dropping aliases for device entry %d:%d %s for new device %d:%d %s.",
(int)MAJOR(dev_by_devt->dev), (int)MINOR(dev_by_devt->dev), dev_name(dev_by_devt),
(int)MAJOR(st.st_rdev), (int)MINOR(st.st_rdev), name);
_drop_all_aliases(dev_by_devt);
}
#if 0
/*
* I think only lvm's own dm devs should be added here, so use
* a warning to look for any other unknown cases.
*/
if (MAJOR(st.st_rdev) != cmd->dev_types->device_mapper_major) {
log_warn("WARNING: new device appeared %d:%d %s",
(int)MAJOR(st.st_rdev), (int)(MINOR(st.st_rdev)), name);
}
#endif
if (!_insert_dev(name, st.st_rdev))
return_NULL;
/* Get the struct dev that was just added. */
dev = (struct device *) dm_hash_lookup(_cache.names, name);
if (!dev) {
log_error("Failed to get device %s", name);
return NULL;
}
goto out;
/* Add new dev-cache entry next. */
dev = NULL;
}
if (dev && dm_list_empty(&dev->aliases)) {
/* shouldn't happen */
log_warn("Ignoring dev with no valid paths for %s.", name);
return NULL;
}
if (!dev && existing)
return_NULL;
/*
* This case should never be hit for a PV. It should only
* happen when the command is opening a new LV it has created.
* Add an arg to all callers indicating when the arg should be
* new (for an LV) and not existing.
* FIXME: fix this further by not using dev-cache struct devs
* at all for new dm devs (LVs) that lvm uses. Make the
* dev-cache contain only devs for PVs.
* Places to fix that use a dev for LVs include:
* . lv_resize opening lv to discard
* . wipe_lv opening lv to zero it
* . _extend_sanlock_lv opening lv to extend it
* . _write_log_header opening lv to write header
* Also, io to LVs should not go through bcache.
* bcache should contain only labels and metadata
* scanned from PVs.
* Either add a new struct dev for st_rdev and name,
* or add name as a new alias for an existing struct dev
* for st_rdev.
*/
if (!dev) {
/*
* This case should only be used for new devices created by this
* command (opening LVs it's created), so if a dev exists for the
* dev_t referenced by the name, then drop all aliases for before
* _insert_dev adds the new name. lvm commands actually hit this
* fairly often when it uses some LV, deactivates the LV, then
* creates some new LV which ends up with the same major:minor.
* Without dropping the aliases, it's plausible that lvm commands
* could end up using the wrong dm device.
*/
struct device *dev_by_devt = (struct device *) btree_lookup(_cache.devices, (uint32_t) st.st_rdev);
if (dev_by_devt) {
log_debug("Dropping aliases for %d:%d before adding new path %s.",
(int)MAJOR(st.st_rdev), (int)(MINOR(st.st_rdev)), name);
_drop_all_aliases(dev_by_devt);
}
#if 0
/*
* I think only lvm's own dm devs should be added here, so use
* a warning to look for any other unknown cases.
*/
if (MAJOR(st.st_rdev) != cmd->dev_types->device_mapper_major) {
log_warn("WARNING: new device appeared %d:%d %s",
(int)MAJOR(st.st_rdev), (int)(MINOR(st.st_rdev)), name);
}
#endif
if (!_insert_dev(name, st.st_rdev))
return_NULL;
@ -1613,9 +1523,10 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
log_error("Failed to get device %s", name);
return NULL;
}
_verify_aliases(dev, name);
}
out:
/*
* The caller passed a filter if they only want the dev if it
* passes filters.
@ -1625,6 +1536,18 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
return dev;
ret = f->passes_filter(cmd, f, dev, NULL);
/*
* This might happen if this function is called before
* filters can do i/o. I don't think this will happen
* any longer and this EAGAIN case can be removed.
*/
if (ret == -EAGAIN) {
log_debug_devs("dev_cache_get filter deferred %s", dev_name(dev));
dev->flags |= DEV_FILTER_AFTER_SCAN;
ret = 1;
}
if (!ret) {
log_debug_devs("dev_cache_get filter excludes %s", dev_name(dev));
return NULL;
@ -1633,40 +1556,63 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
return dev;
}
struct device *dev_cache_get_existing(struct cmd_context *cmd, const char *name, struct dev_filter *f)
struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t dev, struct dev_filter *f, int *filtered)
{
return _dev_cache_get(cmd, name, f, 1);
}
char path[PATH_MAX];
const char *sysfs_dir;
struct stat info;
struct device *d = (struct device *) btree_lookup(_cache.devices, (uint32_t) dev);
int ret;
struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f)
{
return _dev_cache_get(cmd, name, f, 0);
}
if (filtered)
*filtered = 0;
struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t devt)
{
struct device *dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) devt);
if (!d) {
sysfs_dir = dm_sysfs_dir();
if (sysfs_dir && *sysfs_dir) {
/* First check if dev is sysfs to avoid useless scan */
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d",
sysfs_dir, (int)MAJOR(dev), (int)MINOR(dev)) < 0) {
log_error("dm_snprintf partition failed.");
return NULL;
}
if (dev)
return dev;
log_debug_devs("No devno %d:%d in dev cache.", (int)MAJOR(devt), (int)MINOR(devt));
return NULL;
}
if (lstat(path, &info)) {
log_debug("No sysfs entry for %d:%d errno %d at %s.",
(int)MAJOR(dev), (int)MINOR(dev), errno, path);
return NULL;
}
}
struct device *dev_cache_get_by_pvid(struct cmd_context *cmd, const char *pvid)
{
struct btree_iter *iter = btree_first(_cache.devices);
struct device *dev;
log_debug_devs("Device num not found in dev_cache repeat dev_cache_scan for %d:%d",
(int)MAJOR(dev), (int)MINOR(dev));
dev_cache_scan(cmd);
d = (struct device *) btree_lookup(_cache.devices, (uint32_t) dev);
while (iter) {
dev = btree_get_data(iter);
if (!memcmp(dev->pvid, pvid, ID_LEN))
return dev;
iter = btree_next(iter);
if (!d)
return NULL;
}
if (d->flags & DEV_REGULAR)
return d;
if (!f)
return d;
ret = f->passes_filter(cmd, f, d, NULL);
if (ret == -EAGAIN) {
log_debug_devs("get device by number defer filter %s", dev_name(d));
d->flags |= DEV_FILTER_AFTER_SCAN;
ret = 1;
}
if (ret)
return d;
if (filtered)
*filtered = 1;
return NULL;
}
@ -1712,9 +1658,16 @@ struct device *dev_iter_get(struct cmd_context *cmd, struct dev_iter *iter)
f = iter->filter;
if (f && !(d->flags & DEV_REGULAR))
if (f && !(d->flags & DEV_REGULAR)) {
ret = f->passes_filter(cmd, f, d, NULL);
if (ret == -EAGAIN) {
log_debug_devs("get device by iter defer filter %s", dev_name(d));
d->flags |= DEV_FILTER_AFTER_SCAN;
ret = 1;
}
}
if (!f || (d->flags & DEV_REGULAR) || ret)
return d;
}
@ -1729,10 +1682,8 @@ int dev_fd(struct device *dev)
const char *dev_name(const struct device *dev)
{
if (dev && dev->aliases.n && !dm_list_empty(&dev->aliases))
return dm_list_item(dev->aliases.n, struct dm_str_list)->str;
else
return unknown_device_name();
return (dev && dev->aliases.n) ? dm_list_item(dev->aliases.n, struct dm_str_list)->str :
unknown_device_name();
}
bool dev_cache_has_md_with_end_superblock(struct dev_types *dt)
@ -1775,38 +1726,39 @@ static int _setup_devices_list(struct cmd_context *cmd)
return 1;
}
/*
* LVs that use dmeventd need to be accessible using system.devices.
*
* dmeventd will use dmeventd.devices if it exists, otherwise will use
* system.devices. If a VG is covered by dmeventd.devices it should also
* be covered by system.devices. The automated vgchange --monitor and
* vgchange -aay commands do not currently consider dmeventd.devices.
* dmeventd.devices can be useful to prevent commands run by dmeventd
* from reading VGs that do not need the service.
*
* dmeventd gets events for any applicable dm device in the kernel,
* and will attempt to run lvm commands for it. These commands
* will only use dmeventd.devices or system.devices, so if an LV
* that dmeventd is watching is not covered by either of these
* devices files, the dmeventd-generated command will fail when
* it doesn't find the VG.
*/
static int _setup_devices_file_dmeventd(struct cmd_context *cmd)
{
char path[PATH_MAX];
struct stat st;
/*
* When command is run by dmeventd there is no --devicesfile
* option that can enable/disable the use of a devices file.
*/
if (!find_config_tree_bool(cmd, devices_use_devicesfile_CFG, NULL)) {
cmd->enable_devices_file = 0;
return 1;
}
if (dm_snprintf(path, sizeof(path), "%s/devices/dmeventd.devices", cmd->system_dir) < 0)
return_0;
if (stat(path, &st))
return 0;
/*
* If /etc/lvm/devices/dmeventd.devices exists, then use that.
* The optional dmeventd.devices allows the user to control
* which devices dmeventd will look at and use.
* Otherwise, disable the devices file because dmeventd should
* be able to manage LVs in any VG (i.e. LVs in a non-system
* devices file.)
*/
if (dm_snprintf(path, sizeof(path), "%s/devices/dmeventd.devices", cmd->system_dir) < 0) {
log_warn("Failed to copy devices path");
cmd->enable_devices_file = 0;
return 1;
}
if (stat(path, &st)) {
/* No dmeventd.devices, so do not use a devices file. */
cmd->enable_devices_file = 0;
return 1;
}
cmd->enable_devices_file = 1;
(void) dm_strncpy(cmd->devices_file_path, path, sizeof(cmd->devices_file_path));
@ -1820,9 +1772,8 @@ int setup_devices_file(struct cmd_context *cmd)
struct stat st;
int rv;
/* Use dmeventd.devices if it exists. */
if (cmd->run_by_dmeventd && _setup_devices_file_dmeventd(cmd))
return 1;
if (cmd->run_by_dmeventd)
return _setup_devices_file_dmeventd(cmd);
if (cmd->devicesfile) {
/* --devicesfile <filename> or "" has been set which overrides
@ -1899,15 +1850,6 @@ int setup_devices(struct cmd_context *cmd)
file_exists = devices_file_exists(cmd);
/*
* Fail if user specifies a file name that doesn't exist and
* the command is not creating a new devices file.
*/
if (!file_exists && !cmd->create_edit_devices_file && cmd->devicesfile && strlen(cmd->devicesfile)) {
log_error("Devices file not found: %s", cmd->devices_file_path);
return 0;
}
/*
* Removing the devices file is another way of disabling the use of
* a devices file, unless the command creates the devices file.
@ -1955,9 +1897,10 @@ int setup_devices(struct cmd_context *cmd)
if (!file_exists) {
/*
* pvcreate/vgcreate create a new devices file here if it
* doesn't exist. They have create_edit_devices_file=1.
* First create/lock-ex the devices file lockfile.
* pvcreate/vgcreate/vgimportdevices/lvmdevices-add create
* a new devices file here if it doesn't exist.
* They have the create_edit_devices_file flag set.
* First they create/lock-ex the devices file lockfile.
* Other commands will not use a devices file if none exists.
*/
lock_mode = LOCK_EX;
@ -2092,12 +2035,12 @@ int setup_device(struct cmd_context *cmd, const char *devname)
}
/*
* autoactivation is specialized/optimized to look only at command args,
* pvscan --cache is specialized/optimized to look only at command args,
* so this just sets up the devices file, then individual devices are
* added to dev-cache and matched with device_ids.
* added to dev-cache and matched with device_ids later in pvscan.
*/
int setup_devices_for_online_autoactivation(struct cmd_context *cmd)
int setup_devices_for_pvscan_cache(struct cmd_context *cmd)
{
if (cmd->enable_devices_list) {
if (!_setup_devices_list(cmd))
@ -2137,23 +2080,19 @@ int setup_devices_for_online_autoactivation(struct cmd_context *cmd)
static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
{
static const char _partitions[] = "/proc/partitions";
char path[PATH_MAX];
char devname[PATH_MAX] = { 0 };
char devname[PATH_MAX];
char namebuf[NAME_LEN];
char line[1024];
unsigned major = MAJOR(devno);
unsigned minor = MINOR(devno);
unsigned line_major;
unsigned line_minor;
int major = MAJOR(devno);
int minor = MINOR(devno);
int line_major;
int line_minor;
uint64_t line_blocks;
DIR *dir;
struct dirent *dirent;
FILE *fp;
if (!devno)
return NULL;
/*
* $ ls /sys/dev/block/8:0/device/block/
* sda
@ -2165,7 +2104,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
}
if (!(dir = opendir(path)))
goto try_partition;
return NULL;
while ((dirent = readdir(dir))) {
if (dirent->d_name[0] == '.')
@ -2176,8 +2115,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
}
break;
}
if (closedir(dir))
log_sys_debug("closedir", path);
closedir(dir);
if (devname[0]) {
log_debug("Found %s for %d:%d from sys", devname, major, minor);
@ -2205,7 +2143,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
}
if (devname[0]) {
log_debug("Found %s for %d:%d from sys dm", devname, major, minor);
log_debug("Found %s for %d:%d from sys", devname, major, minor);
return _strdup(devname);
}
return NULL;
@ -2216,8 +2154,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
* major minor #blocks name
*/
try_partition:
if (!(fp = fopen(_partitions, "r")))
if (!(fp = fopen("/proc/partitions", "r")))
return NULL;
while (fgets(line, sizeof(line), fp)) {
@ -2234,12 +2171,10 @@ try_partition:
}
break;
}
if (fclose(fp))
log_sys_debug("fclose", _partitions);
fclose(fp);
if (devname[0]) {
log_debug("Found %s for %d:%d from %s", devname, major, minor, _partitions);
log_debug("Found %s for %d:%d from proc", devname, major, minor);
return _strdup(devname);
}
@ -2253,6 +2188,7 @@ try_partition:
int setup_devname_in_dev_cache(struct cmd_context *cmd, const char *devname)
{
struct stat buf;
struct device *dev;
if (stat(devname, &buf) < 0) {
log_error("Cannot access device %s.", devname);
@ -2267,7 +2203,7 @@ int setup_devname_in_dev_cache(struct cmd_context *cmd, const char *devname)
if (!_insert_dev(devname, buf.st_rdev))
return_0;
if (!dm_hash_lookup(_cache.names, devname))
if (!(dev = (struct device *) dm_hash_lookup(_cache.names, devname)))
return_0;
return 1;
@ -2283,55 +2219,3 @@ int setup_devno_in_dev_cache(struct cmd_context *cmd, dev_t devno)
return setup_devname_in_dev_cache(cmd, devname);
}
struct device *setup_dev_in_dev_cache(struct cmd_context *cmd, dev_t devno, const char *devname)
{
struct device *dev;
struct stat buf;
int major = (int)MAJOR(devno);
int minor = (int)MINOR(devno);
if (devname) {
if (stat(devname, &buf) < 0) {
log_error("Cannot access device %s for %d:%d.", devname, major, minor);
if (!devno)
return_NULL;
if (!(devname = _get_devname_from_devno(cmd, devno))) {
log_error("No device name found from %d:%d.", major, minor);
return_NULL;
}
if (stat(devname, &buf) < 0) {
log_error("Cannot access device %s from %d:%d.", devname, major, minor);
return_NULL;
}
}
} else {
if (!(devname = _get_devname_from_devno(cmd, devno))) {
log_error("No device name found from %d:%d.", major, minor);
return_NULL;
}
if (stat(devname, &buf) < 0) {
log_error("Cannot access device %s from %d:%d.", devname, major, minor);
return_NULL;
}
}
if (!S_ISBLK(buf.st_mode)) {
log_error("Invaild device type %s.", devname);
return_NULL;
}
if (devno && (buf.st_rdev != devno)) {
log_warn("Found %s devno %d:%d expected %d:%d.", devname,
(int)MAJOR(buf.st_rdev), (int)MINOR(buf.st_rdev), major, minor);
}
if (!_insert_dev(devname, buf.st_rdev))
return_NULL;
if (!(dev = (struct device *) dm_hash_lookup(_cache.names, devname))) {
log_error("Device lookup failed for %d:%d %s", major, minor, devname);
return_NULL;
}
return dev;
}

View File

@ -53,10 +53,8 @@ int dev_cache_has_scanned(void);
int dev_cache_add_dir(const char *path);
struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f);
struct device *dev_cache_get_existing(struct cmd_context *cmd, const char *name, struct dev_filter *f);
struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t devt);
struct device *dev_cache_get_by_pvid(struct cmd_context *cmd, const char *pvid);
void dev_cache_verify_aliases(struct device *dev);
struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t device, struct dev_filter *f, int *filtered);
struct device *dev_hash_get(const char *name);
@ -75,16 +73,15 @@ void dev_cache_failed_path(struct device *dev, const char *path);
bool dev_cache_has_md_with_end_superblock(struct dev_types *dt);
int get_sysfs_value(const char *path, char *buf, size_t buf_size, int error_if_no_value);
int get_sysfs_binary(const char *path, char *buf, size_t buf_size, int *retlen);
int get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor);
int setup_devices_file(struct cmd_context *cmd);
int setup_devices(struct cmd_context *cmd);
int setup_device(struct cmd_context *cmd, const char *devname);
int setup_devices_for_online_autoactivation(struct cmd_context *cmd);
/* Normal device setup functions are split up for pvscan optimization. */
int setup_devices_for_pvscan_cache(struct cmd_context *cmd);
int setup_devname_in_dev_cache(struct cmd_context *cmd, const char *devname);
int setup_devno_in_dev_cache(struct cmd_context *cmd, dev_t devno);
struct device *setup_dev_in_dev_cache(struct cmd_context *cmd, dev_t devno, const char *devname);
#endif

View File

@ -58,9 +58,6 @@ static int _dev_get_size_file(struct device *dev, uint64_t *size)
const char *name = dev_name(dev);
struct stat info;
if (dm_list_empty(&dev->aliases))
return_0;
if (dev->size_seqno == _dev_size_seqno) {
log_very_verbose("%s: using cached size %" PRIu64 " sectors",
name, dev->size);
@ -90,7 +87,7 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
int do_close = 0;
if (dm_list_empty(&dev->aliases))
return_0;
return 0;
if (dev->size_seqno == _dev_size_seqno) {
log_very_verbose("%s: using cached size %" PRIu64 " sectors",
@ -308,13 +305,6 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
if ((flags & O_EXCL))
need_excl = 1;
if (dm_list_empty(&dev->aliases)) {
/* shouldn't happen */
log_print_unless_silent("Cannot open device %d:%d with no valid paths.", (int)MAJOR(dev->dev), (int)MINOR(dev->dev));
return 0;
}
name = dev_name(dev);
if (dev->fd >= 0) {
if (((dev->flags & DEV_OPENED_RW) || !need_rw) &&
((dev->flags & DEV_OPENED_EXCL) || !need_excl)) {
@ -324,7 +314,7 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
if (dev->open_count && !need_excl)
log_debug_devs("%s: Already opened read-only. Upgrading "
"to read-write.", name);
"to read-write.", dev_name(dev));
/* dev_close_immediate will decrement this */
dev->open_count++;
@ -337,7 +327,11 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
if (critical_section())
/* FIXME Make this log_error */
log_verbose("dev_open(%s) called while suspended", name);
log_verbose("dev_open(%s) called while suspended",
dev_name(dev));
if (!(name = dev_name_confirmed(dev, quiet)))
return_0;
#ifdef O_DIRECT_SUPPORT
if (direct) {
@ -378,9 +372,9 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
}
#endif
if (quiet)
log_debug("Failed to open device path %s (%d).", name, errno);
log_sys_debug("open", name);
else
log_error("Failed to open device path %s (%d).", name, errno);
log_sys_error("open", name);
dev->flags |= DEV_OPEN_FAILURE;
return 0;
@ -421,12 +415,10 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
if ((flags & O_CREAT) && !(flags & O_TRUNC))
dev->end = lseek(dev->fd, (off_t) 0, SEEK_END);
if (!quiet) {
log_debug_devs("Opened %s %s%s%s", name,
dev->flags & DEV_OPENED_RW ? "RW" : "RO",
dev->flags & DEV_OPENED_EXCL ? " O_EXCL" : "",
dev->flags & DEV_O_DIRECT ? " O_DIRECT" : "");
}
log_debug_devs("Opened %s %s%s%s", dev_name(dev),
dev->flags & DEV_OPENED_RW ? "RW" : "RO",
dev->flags & DEV_OPENED_EXCL ? " O_EXCL" : "",
dev->flags & DEV_O_DIRECT ? " O_DIRECT" : "");
dev->flags &= ~DEV_OPEN_FAILURE;
return 1;

View File

@ -23,6 +23,9 @@ int dev_is_luks(struct cmd_context *cmd, struct device *dev, uint64_t *offset_fo
char buf[LUKS_SIGNATURE_SIZE];
int ret = -1;
if (!scan_bcache)
return -EAGAIN;
if (offset_found)
*offset_found = 0;

View File

@ -178,6 +178,12 @@ static int _dev_is_md_component_native(struct device *dev, uint64_t *offset_foun
uint64_t size, sb_offset = 0;
int ret;
/* i/o layer has not been set up */
if (!scan_bcache) {
log_error(INTERNAL_ERROR "dev_is_md_component_native requires io layer.");
return -1;
}
if (!dev_get_size(dev, &size)) {
stack;
return -1;

View File

@ -17,14 +17,12 @@
#include "lib/activate/activate.h"
#include "lib/commands/toolcontext.h"
#include "lib/device/device_id.h"
#include "lib/datastruct/str_list.h"
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h>
#include "lib/device/dev-ext-udev-constants.h"
#endif
#include <dirent.h>
#include <ctype.h>
#define MPATH_PREFIX "mpath-"
@ -37,181 +35,25 @@
* If dm-3 is not an mpath device, then the constant "1" is stored in
* the hash table with the key of the dm minor number.
*/
static struct dm_pool *_wwid_mem;
static struct dm_pool *_hash_mem;
static struct dm_hash_table *_minor_hash_tab;
static struct dm_hash_table *_wwid_hash_tab;
static struct dm_list _ignored;
static struct dm_list _ignored_exceptions;
#define MAX_WWID_LINE 512
static void _read_blacklist_file(const char *path)
{
FILE *fp;
char line[MAX_WWID_LINE];
char wwid[MAX_WWID_LINE];
char *word;
int section_black = 0;
int section_exceptions = 0;
int found_quote;
int found_type;
int i, j;
/*
* do we need to check the multipath.conf blacklist?
*/
if (!(fp = fopen(path, "r")))
return;
while (fgets(line, sizeof(line), fp)) {
word = NULL;
/* skip initial white space on the line */
for (i = 0; i < MAX_WWID_LINE; i++) {
if ((line[i] == '\n') || (line[i] == '\0'))
break;
if (isspace(line[i]))
continue;
word = &line[i];
break;
}
if (!word || word[0] == '#')
continue;
/* identify the start of the section we want to read */
if (strchr(word, '{')) {
if (!strncmp(word, "blacklist_exceptions", 20))
section_exceptions = 1;
else if (!strncmp(word, "blacklist", 9))
section_black = 1;
continue;
}
/* identify the end of the section we've been reading */
if (strchr(word, '}')) {
section_exceptions = 0;
section_black = 0;
continue;
}
/* skip lines that are not in a section we want */
if (!section_black && !section_exceptions)
continue;
/*
* read a wwid from the blacklist{_exceptions} section.
* does not recognize other non-wwid entries in the
* section, and skips those (should the entire mp
* config filtering be disabled if non-wwids are seen?
*/
if (!strstr(word, "wwid"))
continue;
i += 4; /* skip "wwid" */
/*
* copy wwid value from the line.
* the wwids copied here need to match the
* wwids read from /etc/multipath/wwids,
* which are matched to wwids from sysfs.
*/
memset(wwid, 0, sizeof(wwid));
found_quote = 0;
found_type = 0;
j = 0;
for (; i < MAX_WWID_LINE; i++) {
if ((line[i] == '\n') || (line[i] == '\0'))
break;
if (!j && isspace(line[i]))
continue;
if (isspace(line[i]))
break;
/* quotes around wwid are optional */
if ((line[i] == '"') && !found_quote) {
found_quote = 1;
continue;
}
/* second quote is end of wwid */
if ((line[i] == '"') && found_quote)
break;
/* exclude initial 3/2/1 for naa/eui/t10 */
if (!j && !found_type &&
((line[i] == '3') || (line[i] == '2') || (line[i] == '1'))) {
found_type = 1;
continue;
}
wwid[j] = line[i];
j++;
}
if (j < 8)
continue;
log_debug("multipath wwid %s in %s %s",
wwid, section_exceptions ? "blacklist_exceptions" : "blacklist", path);
if (section_exceptions) {
if (!str_list_add(_wwid_mem, &_ignored_exceptions, dm_pool_strdup(_wwid_mem, wwid)))
stack;
} else {
if (!str_list_add(_wwid_mem, &_ignored, dm_pool_strdup(_wwid_mem, wwid)))
stack;
}
}
if (fclose(fp))
stack;
}
static void _read_wwid_exclusions(void)
{
static const char _mpath_conf[] = "/etc/multipath/conf.d";
char path[PATH_MAX] = { 0 };
DIR *dir;
struct dirent *de;
struct dm_str_list *sl, *sl2;
int rem_count = 0;
_read_blacklist_file("/etc/multipath.conf");
if ((dir = opendir(_mpath_conf))) {
while ((de = readdir(dir))) {
if (de->d_name[0] == '.')
continue;
snprintf(path, sizeof(path), "%s/%s", _mpath_conf, de->d_name);
_read_blacklist_file(path);
}
if (closedir(dir))
log_sys_debug("closedir", _mpath_conf);
}
/* for each wwid in ignored_exceptions, remove it from ignored */
dm_list_iterate_items_safe(sl, sl2, &_ignored) {
if (str_list_match_item(&_ignored_exceptions, sl->str))
str_list_del(&_ignored, sl->str);
}
/* for each wwid in ignored, remove it from wwid_hash */
dm_list_iterate_items(sl, &_ignored) {
dm_hash_remove_binary(_wwid_hash_tab, sl->str, strlen(sl->str));
rem_count++;
}
if (rem_count)
log_debug("multipath config ignored %d wwids", rem_count);
}
static void _read_wwid_file(const char *config_wwids_file, int *entries)
static void _read_wwid_file(const char *config_wwids_file)
{
FILE *fp;
char line[MAX_WWID_LINE];
char *wwid, *p;
char typestr[2] = { 0 };
int count = 0;
if (config_wwids_file[0] != '/') {
log_print_unless_silent("Ignoring unknown multipath_wwids_file.");
log_print("Ignoring unknown multipath_wwids_file.");
return;
}
@ -229,17 +71,8 @@ static void _read_wwid_file(const char *config_wwids_file, int *entries)
if (line[0] == '/')
wwid++;
/*
* the initial character is the id type,
* 1 is t10, 2 is eui, 3 is naa, 8 is scsi name.
* wwids are stored in the hash table without the type charater.
* It seems that sometimes multipath does not include
* the type charater (seen with t10 scsi_debug devs).
*/
typestr[0] = *wwid;
if (typestr[0] == '1' || typestr[0] == '2' || typestr[0] == '3')
wwid++;
/* skip the initial '3' */
wwid++;
if ((p = strchr(wwid, '/')))
*p = '\0';
@ -252,7 +85,6 @@ static void _read_wwid_file(const char *config_wwids_file, int *entries)
stack;
log_debug("multipath wwids read %d from %s", count, config_wwids_file);
*entries = count;
}
int dev_mpath_init(const char *config_wwids_file)
@ -260,10 +92,6 @@ int dev_mpath_init(const char *config_wwids_file)
struct dm_pool *mem;
struct dm_hash_table *minor_tab;
struct dm_hash_table *wwid_tab;
int entries = 0;
dm_list_init(&_ignored);
dm_list_init(&_ignored_exceptions);
if (!(mem = dm_pool_create("mpath", 256))) {
log_error("mpath pool creation failed.");
@ -276,7 +104,7 @@ int dev_mpath_init(const char *config_wwids_file)
return 0;
}
_wwid_mem = mem;
_hash_mem = mem;
_minor_hash_tab = minor_tab;
/* multipath_wwids_file="" disables the use of the file */
@ -288,24 +116,16 @@ int dev_mpath_init(const char *config_wwids_file)
if (!(wwid_tab = dm_hash_create(110))) {
log_error("mpath hash table creation failed.");
dm_hash_destroy(_minor_hash_tab);
dm_pool_destroy(_wwid_mem);
dm_pool_destroy(_hash_mem);
_minor_hash_tab = NULL;
_wwid_mem = NULL;
_hash_mem = NULL;
return 0;
}
_wwid_hash_tab = wwid_tab;
if (config_wwids_file) {
_read_wwid_file(config_wwids_file, &entries);
_read_wwid_exclusions();
}
if (!entries) {
/* reading dev wwids is skipped with null wwid_hash_tab */
dm_hash_destroy(_wwid_hash_tab);
_wwid_hash_tab = NULL;
}
if (config_wwids_file)
_read_wwid_file(config_wwids_file);
return 1;
}
@ -316,12 +136,12 @@ void dev_mpath_exit(void)
dm_hash_destroy(_minor_hash_tab);
if (_wwid_hash_tab)
dm_hash_destroy(_wwid_hash_tab);
if (_wwid_mem)
dm_pool_destroy(_wwid_mem);
if (_hash_mem)
dm_pool_destroy(_hash_mem);
_minor_hash_tab = NULL;
_wwid_hash_tab = NULL;
_wwid_mem = NULL;
_hash_mem = NULL;
}
@ -452,12 +272,10 @@ static int _dev_is_mpath_component_udev(struct device *dev)
}
#endif
/* mpath_devno is major:minor of the dm multipath device currently using the component dev. */
static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device *dev,
int primary_result, dev_t primary_dev, dev_t *mpath_devno)
static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device *dev)
{
struct dev_types *dt = cmd->dev_types;
const char *part_name;
const char *name; /* e.g. "sda" for "/dev/sda" */
char link_path[PATH_MAX]; /* some obscure, unpredictable sysfs path */
char holders_path[PATH_MAX]; /* e.g. "/sys/block/sda/holders/" */
@ -468,18 +286,28 @@ static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device
struct dirent *de;
int dev_major = MAJOR(dev->dev);
int dev_minor = MINOR(dev->dev);
unsigned dm_dev_major;
unsigned dm_dev_minor;
int dm_dev_major;
int dm_dev_minor;
struct stat info;
dev_t primary_dev;
int is_mpath_component = 0;
switch (primary_result) {
/* multipathing is only known to exist for SCSI or NVME devices */
if (!major_is_scsi_device(dt, dev_major) && !dev_is_nvme(dt, dev))
return 0;
switch (dev_get_primary_dev(dt, dev, &primary_dev)) {
case 2: /* The dev is partition. */
part_name = dev_name(dev); /* name of original dev for log_debug msg */
/* gets "foo" for "/dev/foo" where "/dev/foo" comes from major:minor */
if (!(name = _get_sysfs_name_by_devt(sysfs_dir, primary_dev, link_path, sizeof(link_path))))
return_0;
log_debug_devs("%s: Device is a partition, using primary "
"device %s for mpath component detection",
part_name, name);
break;
case 1: /* The dev is already a primary dev. Just continue with the dev. */
@ -541,8 +369,8 @@ static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device
dev_name(dev), dm_dev_path, errno);
continue;
}
dm_dev_major = MAJOR(info.st_rdev);
dm_dev_minor = MINOR(info.st_rdev);
dm_dev_major = (int)MAJOR(info.st_rdev);
dm_dev_minor = (int)MINOR(info.st_rdev);
if (dm_dev_major != dt->device_mapper_major) {
log_debug_devs("dev_is_mpath_component %s holder %s %d:%d does not have dm major",
@ -596,107 +424,52 @@ static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device
out:
if (closedir(dr))
log_sys_debug("closedir", holders_path);
stack;
if (is_mpath_component)
*mpath_devno = MKDEV(dm_dev_major, dm_dev_minor);
return is_mpath_component;
}
static int _dev_in_wwid_file(struct cmd_context *cmd, struct device *dev,
int primary_result, dev_t primary_dev)
static int _dev_in_wwid_file(struct cmd_context *cmd, struct device *dev)
{
char idbuf[DEV_WWID_SIZE] = { 0 };
struct dev_wwid *dw;
char *wwid, *full_wwid;
char sysbuf[PATH_MAX] = { 0 };
char *wwid;
long look;
if (!_wwid_hash_tab)
return 0;
/*
* Check the primary device, not the partition.
*/
if (primary_result == 2) {
if (!(dev = dev_cache_get_by_devt(cmd, primary_dev))) {
log_debug("dev_is_mpath_component %s no primary dev", dev_name(dev));
return 0;
}
}
if (!read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
return 0;
/*
* sysfs wwid uses format: naa.<value>, eui.<value>, t10.<value>.
* multipath wwids file uses format: 3<value>, 2<value>, 1<value>.
*
* We omit the type prefix before looking up. The multipath/wwids
* values in the wwid_hash_tab have the initial character removed.
*
* There's no type prefix for "scsi name string" type 8 ids.
*
* First try looking up any wwids that have already been read.
*/
lookup:
dm_list_iterate_items(dw, &dev->wwids) {
if (dw->type == 1 || dw->type == 2 || dw->type == 3)
wwid = &dw->id[4];
else
wwid = dw->id;
if (dm_hash_lookup_binary(_wwid_hash_tab, wwid, strlen(wwid))) {
full_wwid = dw->id;
goto found;
}
}
/*
* The id from sysfs wwid may not be the id used by multipath,
* or a device may not have a vpd_pg83 file (e.g. nvme).
*/
if (!(dev->flags & DEV_ADDED_VPD_WWIDS) && dev_read_vpd_wwids(cmd, dev))
goto lookup;
if (!(dev->flags & DEV_ADDED_SYS_WWID) && dev_read_sys_wwid(cmd, dev, idbuf, sizeof(idbuf), &dw)) {
if (dw->type == 1 || dw->type == 2 || dw->type == 3)
wwid = &dw->id[4];
else
wwid = dw->id;
if (dm_hash_lookup_binary(_wwid_hash_tab, wwid, strlen(wwid))) {
full_wwid = dw->id;
goto found;
}
}
return 0;
found:
log_debug_devs("dev_is_mpath_component %s %s in wwids file", dev_name(dev), full_wwid);
return 1;
}
int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev, dev_t *holder_devno)
{
struct dev_types *dt = cmd->dev_types;
int primary_result;
dev_t primary_dev;
/*
* multipath only uses SCSI or NVME devices
*/
if (!major_is_scsi_device(dt, MAJOR(dev->dev)) && !dev_is_nvme(dt, dev))
if (!sysbuf[0])
return 0;
/*
* primary_result 2: dev is a partition, primary_dev is the whole device
* primary_result 1: dev is a whole device
* sysfs prints wwid as <typestr>.<value>
* multipath wwid uses '3'<value>
* does "<typestr>." always correspond to "3"?
*/
if (!(primary_result = dev_get_primary_dev(dt, dev, &primary_dev)))
return_0;
if (!(wwid = strchr(sysbuf, '.')))
return 0;
if (_dev_is_mpath_component_sysfs(cmd, dev, primary_result, primary_dev, holder_devno) == 1)
/* skip the type and dot, just as '3' was skipped from wwids entry */
wwid++;
look = (long) dm_hash_lookup_binary(_wwid_hash_tab, wwid, strlen(wwid));
if (look) {
log_debug_devs("dev_is_mpath_component %s multipath wwid %s", dev_name(dev), wwid);
return 1;
}
return 0;
}
int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev)
{
if (_dev_is_mpath_component_sysfs(cmd, dev) == 1)
goto found;
if (_dev_in_wwid_file(cmd, dev, primary_result, primary_dev))
if (_dev_in_wwid_file(cmd, dev))
goto found;
if (external_device_info_source() == DEV_EXT_UDEV) {
@ -704,85 +477,8 @@ int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev, dev_t *h
goto found;
}
/*
* TODO: save the result of this function in dev->flags and use those
* flags on repeated calls to avoid repeating the work multiple times
* for the same device when there are partitions on the device.
*/
return 0;
found:
return 1;
}
const char *dev_mpath_component_wwid(struct cmd_context *cmd, struct device *dev)
{
char slaves_path[PATH_MAX];
char wwid_path[PATH_MAX];
char sysbuf[PATH_MAX] = { 0 };
char *slave_name;
const char *wwid = NULL;
struct stat info;
DIR *dr;
struct dirent *de;
/* /sys/dev/block/253:7/slaves/sda/device/wwid */
if (dm_snprintf(slaves_path, sizeof(slaves_path), "%sdev/block/%d:%d/slaves",
dm_sysfs_dir(), (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
log_warn("Sysfs path to check mpath components is too long.");
return NULL;
}
if (stat(slaves_path, &info))
return NULL;
if (!S_ISDIR(info.st_mode)) {
log_warn("Path %s is not a directory.", slaves_path);
return NULL;
}
/* Get wwid from first component */
if (!(dr = opendir(slaves_path))) {
log_debug("Device %s has no slaves dir", dev_name(dev));
return NULL;
}
while ((de = readdir(dr))) {
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
/* slave_name "sda" */
slave_name = de->d_name;
/* read /sys/block/sda/device/wwid */
if (dm_snprintf(wwid_path, sizeof(wwid_path), "%sblock/%s/device/wwid",
dm_sysfs_dir(), slave_name) < 0) {
log_warn("Failed to create sysfs wwid path for %s", slave_name);
continue;
}
get_sysfs_value(wwid_path, sysbuf, sizeof(sysbuf), 0);
if (!sysbuf[0])
continue;
if (strstr(sysbuf, "scsi_debug")) {
unsigned i;
for (i = 0; i < strlen(sysbuf); i++) {
if (sysbuf[i] == ' ')
sysbuf[i] = '_';
}
}
if ((wwid = dm_pool_strdup(cmd->mem, sysbuf)))
break;
}
if (closedir(dr))
log_sys_debug("closedir", slaves_path);
return wwid;
}

View File

@ -42,6 +42,9 @@ int dev_is_swap(struct cmd_context *cmd, struct device *dev, uint64_t *offset_fo
unsigned page;
int ret = 0;
if (!scan_bcache)
return -EAGAIN;
if (!dev_get_size(dev, &size)) {
stack;
return -1;

View File

@ -25,7 +25,7 @@
#include "device_mapper/misc/dm-ioctl.h"
#ifdef BLKID_WIPING_SUPPORT
#include <blkid/blkid.h>
#include <blkid.h>
#endif
#ifdef UDEV_SYNC_SUPPORT
@ -89,7 +89,7 @@ int dev_is_used_by_active_lv(struct cmd_context *cmd, struct device *dev, int *u
DIR *d;
struct dirent *dirent;
char *holder_name;
unsigned dm_dev_major, dm_dev_minor;
int dm_dev_major, dm_dev_minor;
size_t lvm_prefix_len = sizeof(UUID_PREFIX) - 1;
size_t lvm_uuid_len = sizeof(UUID_PREFIX) - 1 + 2 * ID_LEN;
size_t uuid_len;
@ -548,7 +548,7 @@ static int _has_sys_partition(struct device *dev)
int minor = (int) MINOR(dev->dev);
/* check if dev is a partition */
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/partition",
if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d/partition",
dm_sysfs_dir(), major, minor) < 0) {
log_warn("WARNING: %s: partition path is too long.", dev_name(dev));
return 0;
@ -674,6 +674,11 @@ static int _dev_is_partitioned_native(struct dev_types *dt, struct device *dev)
{
int r;
if (!scan_bcache) {
log_error(INTERNAL_ERROR "dev_is_partitioned_native requires i/o.");
return -1;
}
/* Unpartitioned DASD devices are not supported. */
if ((MAJOR(dev->dev) == dt->dasd_major) && dasd_is_cdl_formatted(dev))
return 1;
@ -775,7 +780,7 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
* - basename ../../block/md0/md0 = md0
* Parent's 'dev' sysfs attribute = /sys/block/md0/dev
*/
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d",
if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d",
dm_sysfs_dir(), major, minor) < 0) {
log_warn("WARNING: %s: major:minor sysfs path is too long.", dev_name(dev));
return 0;
@ -787,7 +792,7 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
temp_path[size] = '\0';
if (dm_snprintf(path, sizeof(path), "%sblock/%s/dev",
if (dm_snprintf(path, sizeof(path), "%s/block/%s/dev",
dm_sysfs_dir(), basename(dirname(temp_path))) < 0) {
log_warn("WARNING: sysfs path for %s is too long.",
basename(dirname(temp_path)));
@ -823,143 +828,26 @@ out:
}
#ifdef BLKID_WIPING_SUPPORT
int fs_block_size_and_type(const char *pathname, uint32_t *fs_block_size_bytes, char *fstype, int *nofs)
int get_fs_block_size(const char *pathname, uint32_t *fs_block_size)
{
blkid_probe probe = NULL;
const char *type_str = NULL, *size_str = NULL;
size_t len = 0;
int ret = 1;
int rc;
char *block_size_str = NULL;
if (!(probe = blkid_new_probe_from_filename(pathname))) {
log_error("Failed libblkid probe setup for %s", pathname);
return 0;
}
blkid_probe_enable_superblocks(probe, 1);
blkid_probe_set_superblocks_flags(probe,
BLKID_SUBLKS_LABEL | BLKID_SUBLKS_LABELRAW |
BLKID_SUBLKS_UUID | BLKID_SUBLKS_UUIDRAW |
BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION |
#ifdef BLKID_SUBLKS_FSINFO
BLKID_SUBLKS_FSINFO |
#endif
BLKID_SUBLKS_MAGIC);
rc = blkid_do_safeprobe(probe);
if (rc < 0) {
log_debug("Failed libblkid probe for %s", pathname);
ret = 0;
goto out;
} else if (rc == 1) {
/* no file system on the device */
log_debug("No file system found on %s.", pathname);
if (nofs)
*nofs = 1;
goto out;
}
if (!blkid_probe_lookup_value(probe, "TYPE", &type_str, &len) && len && type_str) {
if (fstype)
strncpy(fstype, type_str, FSTYPE_MAX);
if ((block_size_str = blkid_get_tag_value(NULL, "BLOCK_SIZE", pathname))) {
*fs_block_size = (uint32_t)atoi(block_size_str);
free(block_size_str);
log_debug("Found blkid BLOCK_SIZE %u for fs on %s", *fs_block_size, pathname);
return 1;
} else {
/* any difference from blkid_do_safeprobe rc=1? */
log_debug("No file system type on %s.", pathname);
if (nofs)
*nofs = 1;
goto out;
}
if (fs_block_size_bytes) {
if (!blkid_probe_lookup_value(probe, "BLOCK_SIZE", &size_str, &len) && len && size_str)
*fs_block_size_bytes = atoi(size_str);
else
*fs_block_size_bytes = 0;
}
log_debug("Found blkid fstype %s fsblocksize %s on %s",
type_str ?: "none", size_str ?: "unused", pathname);
out:
blkid_free_probe(probe);
return ret;
}
int fs_get_blkid(const char *pathname, struct fs_info *fsi)
{
blkid_probe probe = NULL;
const char *str = "";
size_t len = 0;
uint64_t fslastblock = 0;
unsigned int fsblocksize = 0;
int rc;
if (!(probe = blkid_new_probe_from_filename(pathname))) {
log_error("Failed libblkid probe setup for %s", pathname);
log_debug("No blkid BLOCK_SIZE for fs on %s", pathname);
*fs_block_size = 0;
return 0;
}
blkid_probe_enable_superblocks(probe, 1);
blkid_probe_set_superblocks_flags(probe,
BLKID_SUBLKS_LABEL | BLKID_SUBLKS_LABELRAW |
BLKID_SUBLKS_UUID | BLKID_SUBLKS_UUIDRAW |
BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION |
#ifdef BLKID_SUBLKS_FSINFO
BLKID_SUBLKS_FSINFO |
#endif
BLKID_SUBLKS_MAGIC);
rc = blkid_do_safeprobe(probe);
if (rc < 0) {
log_error("Failed libblkid probe for %s", pathname);
blkid_free_probe(probe);
return 0;
} else if (rc == 1) {
/* no file system on the device */
log_print_unless_silent("No file system found on %s.", pathname);
fsi->nofs = 1;
blkid_free_probe(probe);
return 1;
}
if (!blkid_probe_lookup_value(probe, "TYPE", &str, &len) && len)
strncpy(fsi->fstype, str, sizeof(fsi->fstype)-1);
else {
/* any difference from blkid_do_safeprobe rc=1? */
log_print_unless_silent("No file system type on %s.", pathname);
fsi->nofs = 1;
blkid_free_probe(probe);
return 1;
}
if (!blkid_probe_lookup_value(probe, "BLOCK_SIZE", &str, &len) && len)
fsi->fs_block_size_bytes = atoi(str);
if (!blkid_probe_lookup_value(probe, "FSLASTBLOCK", &str, &len) && len)
fslastblock = strtoull(str, NULL, 0);
if (!blkid_probe_lookup_value(probe, "FSBLOCKSIZE", &str, &len) && len)
fsblocksize = (unsigned int)atoi(str);
blkid_free_probe(probe);
if (fslastblock && fsblocksize)
fsi->fs_last_byte = fslastblock * fsblocksize;
log_debug("libblkid TYPE %s BLOCK_SIZE %d FSLASTBLOCK %llu FSBLOCKSIZE %u fs_last_byte %llu",
fsi->fstype, fsi->fs_block_size_bytes, (unsigned long long)fslastblock, fsblocksize,
(unsigned long long)fsi->fs_last_byte);
return 1;
}
#else
int fs_block_size_and_type(const char *pathname, uint32_t *fs_block_size_bytes, char *fstype, int *nofs)
int get_fs_block_size(const char *pathname, uint32_t *fs_block_size)
{
log_debug("Disabled blkid BLOCK_SIZE for fs.");
return 0;
}
int fs_get_blkid(const char *pathname, struct fs_info *fsi)
{
log_debug("Disabled blkid for fs info.");
*fs_block_size = 0;
return 0;
}
#endif
@ -1078,9 +966,6 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam
/* TODO: Should we check for valid dev - _dev_is_valid(dev)? */
if (dm_list_empty(&dev->aliases))
goto_out;
if (!(probe = blkid_new_probe_from_filename(dev_name(dev)))) {
log_error("Failed to create a new blkid probe for device %s.", dev_name(dev));
goto out;
@ -1212,7 +1097,7 @@ int wipe_known_signatures(struct cmd_context *cmd, struct device *dev,
static int _snprintf_attr(char *buf, size_t buf_size, const char *sysfs_dir,
const char *attribute, dev_t dev)
{
if (dm_snprintf(buf, buf_size, "%sdev/block/%d:%d/%s", sysfs_dir,
if (dm_snprintf(buf, buf_size, "%s/dev/block/%d:%d/%s", sysfs_dir,
(int)MAJOR(dev), (int)MINOR(dev),
attribute) < 0) {
log_warn("WARNING: sysfs path for %s attribute is too long.", attribute);

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