1
0
mirror of git://sourceware.org/git/lvm2.git synced 2026-01-01 16:32:54 +03:00

Compare commits

..

2 Commits

Author SHA1 Message Date
David Teigland
76da788251 uncache and splitcache should restore inactive state
If an inactive LV is being cached in writeback mode, then
removing the cache does a temporary activation to flush
the cache back to the main LV.  However, it forgot to
deactivate the LV again, so the temporary activation
was left in place.
2025-02-18 17:22:52 -06:00
David Teigland
6285738dee lvmlockd: add debug line 2025-02-18 17:04:44 -06:00
778 changed files with 24373 additions and 48777 deletions

1
.gitignore vendored
View File

@@ -156,7 +156,6 @@ test/lib/lvmlockd
test/lib/lvmpolld
test/lib/lvm_import_vdo
test/lib/lvm_vdo_wrapper
test/lib/lvresize_fs_helper
test/lib/not
test/lib/paths
test/lib/paths-common

View File

@@ -1,7 +1,6 @@
stages:
- approve
- test
- post
approve1:
stage: approve
@@ -46,7 +45,6 @@ test-job:
matrix:
- TAG: rhel8
CONFIGURE: >
--with-default-use-devices-file=0
--with-cluster=internal
--enable-cmirrord
- TAG: rhel9
@@ -59,7 +57,6 @@ test-job:
paths:
- test/results/
expire_in: 1 week
when: always
tags:
- ${TAG}
timeout: 2h
@@ -81,7 +78,9 @@ test-job:
--enable-lvmlockd-sanlock
--enable-dbus-service --enable-notify-dbus
--enable-dmfilemapd
--with-vdo-format=/usr/bin/vdoformat
--with-writecache=internal
--with-vdo=internal --with-vdo-format=/usr/bin/vdoformat
--with-integrity=internal
--disable-silent-rules
- make
- rm -rf test/results
@@ -93,10 +92,9 @@ test-job:
- 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|'))
- find test/results -type f -empty -delete
- 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\|lvconvert-raid-reshape-size\|lvconvert-raid-reshape-stripes-load-fail\)\.sh' | sort; then false; else true; fi
- 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
@@ -104,25 +102,3 @@ test-job:
when: manual
- when: on_success
# reboot must be configured to let runner finish cleanly while not accepting new jobs
# NOTE: If this causes warnings, gitlab-runner needs to be configured to be stopped using SIGQUIT
# See: https://docs.gitlab.com/runner/commands/#gitlab-runner-stop-doesnt-shut-down-gracefully
# NOTE: It should be possible to use after_script in test job, which runs
# before artifacts collection, but reboot may be too eager to stop the job
# while collecting artifacts
# NOTE: What would happen when there are multiple jobs in the queue for each
# tag? Could the tests run first and reboot only after them? I think so!
reboot:
stage: post
parallel:
matrix:
- TAG: rhel8
- TAG: rhel9
tags:
- ${TAG}
timeout: 1m
script:
- reboot
allow_failure: true
when: always

17
INSTALL
View File

@@ -5,15 +5,11 @@ Installation
Run the 'configure' script from the top directory.
On system with udevd use: --enable-udev_sync
If you don't want to include the LVM1 backwards-compatibility code use:
./configure --with-lvm1=none
To build with dmeventd: --enable-cmdlib --enable-dmeventd
For DBus support: --enable-dbus-service --enable-notify-dbus
For lvmpolld usage: --enable-lvmpolld
For lvmlockd support: --enable-lvmlockd-sanlock --enable-lvmlockd-dlm --enable-lvmlockd-dlmcontrol
To separate the LVM1 support into a shared library loaded by lvm.conf use:
./configure --with-lvm1=shared
Use ./configure --help to see other options.
@@ -28,7 +24,8 @@ Installation
3) If using LVM2, create a configuration file.
The tools will work fine without a configuration file being
present, but you ought to review the example file in conf/example.conf.
present, but you ought to review the example file in doc/example.conf.
Please also refer to the WHATS_NEW file and the manual pages for the
Please also refer to the WHATS_NEW file and the manual pages for the
individual commands.

View File

@@ -116,7 +116,6 @@ rpm: dist
-e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \
-e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $$GIT_VER," \
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
LC_ALL=C date '+* %a %b %d %Y LVM Development Team <linux-lvm@lists.linux.dev>' >$(rpmbuilddir)/SOURCES/changelog.inc
V=$(V) rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
generate: conf.generate man.generate
@@ -135,7 +134,6 @@ install_system_dirs:
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_LOCK_DIR)
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR)
$(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache
$(INSTALL_ROOT_DIR) $(DESTDIR)/var/lib/lvm
install_initscripts:
$(MAKE) -C scripts install_initscripts
@@ -174,7 +172,7 @@ 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 " print-VARIABLE Resolve make variable."
@echo " rpm Build rpm."
@echo " run-unit-test Run unit tests."
@echo " tags Generate c/etags."
@@ -196,7 +194,6 @@ ifneq ("$(GENHTML)", "")
lcov:
$(RM) -rf $(LCOV_REPORTS_DIR)
$(MKDIR_P) $(LCOV_REPORTS_DIR)
-find . -name '*.gc[dn][ao]' ! -newer make.tmpl -delete
-$(LCOV) --capture --directory $(top_builddir) --ignore-errors source,negative,gcov \
--output-file $(LCOV_REPORTS_DIR)/out.info
-test ! -s $(LCOV_REPORTS_DIR)/out.info || \

2
README
View File

@@ -6,8 +6,8 @@ Installation instructions are in INSTALL.
There is no warranty - see COPYING and COPYING.LIB.
Tarballs are available from:
https://sourceware.org/pub/lvm2/releases/
ftp://sourceware.org/pub/lvm2/
https://github.com/lvmteam/lvm2/releases
The source code is stored in git:
https://gitlab.com/lvmteam/lvm2

View File

@@ -1 +1 @@
2.03.39(2)-git (2025-12-15)
2.03.31(2)-git (2025-01-14)

View File

@@ -1 +1 @@
1.02.213-git (2025-12-15)
1.02.205-git (2025-01-14)

110
WHATS_NEW
View File

@@ -1,118 +1,10 @@
Version 2.03.39 -
Version 2.03.31 -
==================
Version 2.03.38 - 15th December 2025
====================================
Synchronize with udev after creating pool metadata spare volume.
Conversion to thin-pool removes activation skipping from converted LVs.
Configure now checks for xfs/xfs.h.
Workaround for libblkid returning old FSLASTBLOCK immediately after resize.
Enhance pvmove activation and deactivation.
LV locks whole device tree using such locked LV.
Version 2.03.37 - 21st November 2025
====================================
Remove unsupported --blockdevice option from lvscan.
Support output in list mode for all lvmconfig --typeconfig types with --list.
Enhance shutdown performance of daemons using libdaemon.
Update lvmdevices(8).
Add --force option for lvmdevices --update.
Add --listids, --delid, --addid options for manipulation by device_id to lvmdevices.
Add missing synchronization for vdopool.
Fix deadlock in lvmdbusd on SIGINT in lvm shell mode.
Add VG attr character and pr field for persistent reservation status to vgs.
Fix persistent reservations setting handling in vgmerge, vgsplit and vgimportclone.
Add missing synchronization while converting cachevols.
Warn on classic snapshot on raid creation and error on activation if missing.
Translate udev device paths in lvmdbusd for test environments.
Use source='udev' in lvmdbusd to monitor processed udev events.
Symlink to /dev nodes when using alternative dev dir to trigger udev.
Avoid passing uninitialized buffer in dmeventd to fix valgrind report.
Improve lvmdbusd matching of udevd reported device paths.
Version 2.03.36 - 24th October 2025
===================================
Fix uninitialized chunk_size_calc_policy in pool parameter functions.
Fix approximate allocation for Raid with insufficient extents.
Fix race in dmeventd remonitoring optimization (2.03.35).
Use -real suffix for pvmove UUID.
Add support pvmove segmentation allocation/pvmove_max_segmentation_size_mb.
Allow creating _imeta with multiple segments.
Fix driver_version() accepts NULL version buffer pointer.
Fix invalid free() call in error path of _add_metadata_area_to_pv().
Avoid destroying aio context in forked process.
Add lvs -o cache_promotions,cache_promotions fields.
Update pvmove logic when moving i.e. raid legs.
Display integrity info in lvdisplay.
Increase storage size for internal filter chain.
Add helper function display_mb_size().
Enhance code for adding and removing integrity to RAID volumes.
Add code for basic validation of integrity segment.
Use -real private suffix for integrity origin and meta volumes.
Use -real private suffix for mirror and raid legs.
Detect and use existing XFS quota mount options for lvresize --fs resize.
Version 2.03.35 - 09th September 2025
=====================================
Fix unlocking devices file only after all PVs are processed.
Avoid creating system.devices when deleting entries.
Fix existing issues with persistent reservations.
Fix possible report output format inconsistencies while processing PVs.
Allow report options for pv/vg/lvdisplay only if used with -C|--columns.
Fix vgsplit failing to split a VG with RAID+integrity or cache with cachevol.
Fix --lockopt handling in lvmlockd when --nolocking is used.
Optimize dmeventd when remonitoring active devices.
Version 2.03.34 - 30th July 2025
================================
Support dmeventd restart when there are no monitored devices.
Dmeventd no longer calls 'action commands' on removed devices.
Fix reader of VDO metadata on 32bit architecture.
Fix lvmdevices --deldev/--delpvid to error out if devices file not writeable.
Fix lvresize corruption in LV->crypt->FS stack if near crypt min size limit.
Enhanced lvresize -r support for btrfs.
Use glibc standard functions htoX, Xtoh functions for endian conversion.
Fix structure copying within sanlock's release_rename().
Fix autoactivation on top of loop dev PVs to trigger once for change uevents.
Add lvmlockd --lockopt repair to reinitialize corrupted sanlock leases.
Fix support for lvcreate -T --setautoactivation.
Add lvm.conf global/lvresize_fs_helper_executable.
Enable lvm to use persistent reservations on a VG.
Version 2.03.33 - 27th June 2025
================================
Various spelling, grammar, formatting, test, and build script improvements.
Override LC_NUMERIC locale if unsuitable for json_std report format.
Repair raid arrays with transiently lost devices.
Version 2.03.32 - 05th May 2025
===============================
Lvconvert vdopool conversion properly validates acceptable LVs.
Accept thin pool data LV as cacheable LV.
Allow using zram block devices (likely for testing).
Fix lvresize when resizing COW snapshots already covering origin.
Fix lvmdbusd read of executed lvm commands output.
Fix construction of DM UUID for cachevol _cdata and _cmeta devices.
Ignore PV claims from old metadata when then PV belongs to a new VG.
Fix integrity metadata rounding.
Accept --autobackup option in pvresize.
Version 2.03.31 - 27th February 2025
====================================
Reduce 'mandoc -T lint' reported issues for man pages.
Restore support for LVM_SUPPRESS_FD_WARNINGS (2.03.24).
Fix uncache and split cache restoring original state of volume.
Extend use of lockopt skip to more scenarios.
Enhance error path resolving in polling code.
Disallow shared activation of LV with CoW snapshot.
Fix lvmlockd use in lvremove of CoW snapshot, VDO pool, and uncache.
Improve mirror split with opened temporary volumes.
Improve pvmove finish with opened temporary volumes.
Fix backup limit for devices file, handle over 10,000 files.
Ignore reported optimal_io_size not divisible by 4096.
Fix busy-loop in config reading when read returned 0.
Fix DM cache preserving logic (2.03.28).
Improve use of lvmlockd for usecases involving thin volumes and pools.
Version 2.03.30 - 14th January 2025
===================================

View File

@@ -1,39 +1,6 @@
Version 1.02.213 -
Version 1.02.205 -
===================
Version 1.02.212 - 15th December 2025
=====================================
Version 1.02.211 - 21st November 2025
=====================================
Dmeventd starts to use mutex per thread.
Consolidate dmsetup stats display functions using helper macros.
Refactor dmsetup _process_tree_options to use bsearch.
Version 1.02.210 - 24th October 2025
====================================
Version 1.02.209 - 09th September 2025
======================================
Version 1.02.208 - 30th July 2025
=================================
Version 1.02.207 - 27th June 2025
=================================
Escape the escape character itself on JSON report format output.
Fail dm_report_group_create if radix char from locale unsuitable for JSON_STD.
Version 1.02.206 - 05th May 2025
================================
Add support for using regex in selection criteria for string lists.
Fix string list selection when using [<item> || <item> ...].
Version 1.02.205 - 27th February 2025
=====================================
Restore missing symbol dm_tree_node_size_changed@Base (1.02.175).
Restore missing symbol dm_bitset_parse_list@@DM_1_02_138 (1.02.175).
Version 1.02.204 - 14th January 2025
====================================
Create /dev/disk/by-diskseq/<DISKSEQ> symlink for public DM devices.
@@ -306,7 +273,7 @@ Version 1.02.136 - 5th November 2016
Still produce output when dmsetup dependency tree building finds dev missing.
Check and report pthread_sigmask() failure in dmeventd.
Check mem alloc fail in _canonicalize_field_ids().
Use unsigned math when checking more than 31 legs of raid.
Use unsigned math when checking more then 31 legs of raid.
Fix 'dmstats delete' with dmsetup older than v1.02.129
Fix stats walk segfault with dmsetup older than v1.02.129

8
aclocal.m4 vendored
View File

@@ -1,6 +1,6 @@
# generated automatically by aclocal 1.18.1 -*- Autoconf -*-
# generated automatically by aclocal 1.17 -*- Autoconf -*-
# Copyright (C) 1996-2025 Free Software Foundation, Inc.
# Copyright (C) 1996-2024 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -422,7 +422,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-2025 Free Software Foundation, Inc.
# Copyright (C) 1999-2024 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -792,7 +792,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-2025 Free Software Foundation, Inc.
# Copyright (C) 2001-2024 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,

View File

@@ -191,8 +191,8 @@ static bool _insert_unset(struct radix_tree *rt, struct value *v, const uint8_t
v->value = rv;
rt->nr_entries++;
} else {
// prefix -> value (all fields explicitly initialized)
struct prefix_chain *pc = malloc(sizeof(*pc) + len);
// prefix -> value
struct prefix_chain *pc = zalloc(sizeof(*pc) + len);
if (!pc)
return false;
@@ -267,8 +267,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
if (kb[i] != pc->prefix[i])
break;
// All fields of pc2 are explicitly initialized
if (!(pc2 = malloc(sizeof(*pc2) + pc->len - i)))
if (!(pc2 = zalloc(sizeof(*pc2) + pc->len - i)))
return false;
pc2->len = pc->len - i;
memmove(pc2->prefix, pc->prefix + i, pc2->len);
@@ -445,8 +444,7 @@ static bool _insert(struct radix_tree *rt, struct value *v, const uint8_t *kb, c
v->value = rv;
} else {
// All fields explicitly initialized
struct value_chain *vc = malloc(sizeof(*vc));
struct value_chain *vc = zalloc(sizeof(*vc));
if (!vc)
return false;
@@ -574,6 +572,22 @@ int radix_tree_uniq_insert(struct radix_tree *rt, const void *key, size_t keylen
((entries != rt->nr_entries) ? 1 : -1) : 0;
}
// Note the degrade functions also free the original node.
static void _degrade_to_n4(struct node16 *n16, struct value *result)
{
struct node4 *n4 = zalloc(sizeof(*n4));
assert(n4 != NULL);
n4->nr_entries = n16->nr_entries;
memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys));
memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values));
free(n16);
result->type = NODE4;
result->value.ptr = n4;
}
static void _degrade_to_n16(struct node48 *n48, struct value *result)
{
unsigned i, count = 0;
@@ -654,10 +668,9 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
return true;
} else if (root->type == VALUE_CHAIN) {
// Free value_chain after copying child out
vc = root->value.ptr;
_dtr(rt, vc->value);
*root = vc->child;
memcpy(root, &vc->child, sizeof(*root));
free(vc);
return true;
@@ -731,9 +744,8 @@ static bool _remove(struct radix_tree *rt, struct value *root, const uint8_t *kb
}
n16->nr_entries--;
if (!n16->nr_entries) {
free(n16);
root->type = UNSET;
if (n16->nr_entries <= 4) {
_degrade_to_n4(n16, root);
}
}
return r;
@@ -888,10 +900,8 @@ static bool _remove_subtree(struct radix_tree *rt, struct value *root, const uin
}
n16->nr_entries--;
if (!n16->nr_entries) {
free(n16);
root->type = UNSET;
}
if (n16->nr_entries <= 4)
_degrade_to_n4(n16, root);
}
return r;
}

View File

@@ -37,7 +37,7 @@ config {
# checks = 1
# Configuration option config/validate_metadata.
# Allows selecting the level of validation after metadata transformation.
# Allows to select the level of validation after metadata transformation.
# Validation takes extra CPU time to verify internal consistency.
# Accepted values:
# full
@@ -179,16 +179,10 @@ devices {
# 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.
# Set to 1 to enable a single automatic refresh attempt when a trigger
# condition is detected. Set to 0 to disable automatic refresh.
# Set to a value between 10 and 600 (in seconds) to enable an extended
# refresh period during which missing PVs will be located using the PVID,
# and the system.devices device ID updated if the PV is found on a new device.
# An extended refresh period may be useful if devices require refresh,
# but are attached to the system some time the initial refresh.
# This configuration option has an automatic default value.
# device_ids_refresh = 10
# device_ids_refresh = 1
# Configuration option devices/device_ids_refresh_checks.
# Conditions that trigger device_ids_refresh to locate PVIDs on new devices.
@@ -213,7 +207,7 @@ devices {
# device is rejected. Unmatching path names do not affect the accept
# or reject decision. If no path names for a device match a pattern,
# then the device is accepted. Be careful mixing 'a' and 'r' patterns,
# as the combination might produce unexpected results (test changes).
# as the combination might produce unexpected results (test changes.)
# Run vgscan after changing the filter to regenerate the cache.
#
# Example
@@ -255,7 +249,7 @@ devices {
# Configuration option devices/sysfs_scan.
# Restrict device scanning to block devices appearing in sysfs.
# This is a quick way of filtering out block devices that are not
# present on the system. sysfs must be part of the kernel and mounted.
# present on the system. sysfs must be part of the kernel and mounted.)
# This configuration option has an automatic default value.
# sysfs_scan = 1
@@ -265,7 +259,7 @@ devices {
# avoid using PVs that belong to guest images stored on LVs.
# When enabled, the LVs scanned should be restricted using the
# devices file or the filter. This option does not enable autoactivation
# of layered VGs, which requires editing LVM udev rules (see LVM_PVSCAN_ON_LVS).
# of layered VGs, which requires editing LVM udev rules (see LVM_PVSCAN_ON_LVS.)
# This configuration option has an automatic default value.
# scan_lvs = 0
@@ -343,7 +337,7 @@ devices {
# penalty, e.g. MD chunk size. optimal_io_size is the device's
# preferred unit of receiving I/O, e.g. MD stripe width.
# minimum_io_size is used if optimal_io_size is undefined (0).
# If md_chunk_alignment is enabled, it will detect the optimal_io_size.
# If md_chunk_alignment is enabled, that detects the optimal_io_size.
# default_data_alignment and md_chunk_alignment will be overridden
# if they are not aligned with the value detected for this setting.
# This setting is overridden by data_alignment and the --dataalignment
@@ -413,16 +407,16 @@ devices {
# pv_min_size = 2048
# Configuration option devices/issue_discards.
# Issue discard commands to physical volumes when freeing space.
# When an LV frees space on a PV (e.g., lvremove, lvreduce), LVM can
# send discard commands to notify the storage device that those blocks
# are no longer in use. NVMe/SSDs use this information for TRIM operations
# to improve performance and longevity. Thinly provisioned storage uses
# UNMAP to reclaim the freed space. Discards are issued using the
# protocol supported by the device (TRIM, UNMAP, or WRITE SAME with
# UNMAP bit set) and only when both the storage and kernel support it.
# Warning: vgcfgrestore restores only VG metadata, not LV data. Any
# data in discarded regions will be lost.
# Issue discards to PVs that are no longer used by an LV.
# Discards are sent to an LV's underlying physical volumes when the LV
# is no longer using the physical volumes' space, e.g. lvremove,
# lvreduce. Discards inform the storage that a region is no longer
# used. Storage that supports discards advertise the protocol-specific
# way discards should be issued by the kernel (TRIM, UNMAP, or
# WRITE SAME with UNMAP bit set). Not all storage will support or
# benefit from discards, but SSDs and thinly provisioned LUNs
# generally do. If enabled, discards will only be issued if both the
# storage and kernel provide support.
# This configuration option has an automatic default value.
# issue_discards = 0
@@ -503,7 +497,7 @@ allocation {
# is not claimed incorrectly by other tools because of old signatures
# from previous use. The number of signatures that LVM can detect
# depends on the detection code that is selected (see
# use_blkid_wiping). Wiping each detected signature must be confirmed.
# use_blkid_wiping.) Wiping each detected signature must be confirmed.
# When this setting is disabled, signatures on new LVs are not detected
# or erased unless the --wipesignatures option is used directly.
# This configuration option has an automatic default value.
@@ -535,7 +529,7 @@ allocation {
# Accepted values:
# 0 Automatically detected best available format
# 1 Original format
# 2 Improved second-generation format
# 2 Improved 2nd. generation format
#
# This configuration option has an automatic default value.
# cache_metadata_format = 0
@@ -585,26 +579,15 @@ allocation {
# Using cache pool with more chunks may degrade cache performance.
# This configuration option does not have a default value defined.
# Configuration option allocation/pvmove_max_segment_size_mb.
# Maximum size in MiB of segments to mirror at once during pvmove.
# When pvmove needs to move large segments, it will split them into
# smaller chunks of this size, mirror each chunk, and update metadata
# between chunks. This prevents mirroring excessively large amounts
# of data at once. A value of 0 (default) means no limit - the entire
# segment will be mirrored at once. Setting this to e.g. 10240 will
# limit each mirroring operation to 10GiB chunks.
# This configuration option has an automatic default value.
# pvmove_max_segment_size_mb = 0
# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
# Thin pool metadata and data will always use different PVs.
# This configuration option has an automatic default value.
# thin_pool_metadata_require_separate_pvs = 0
# Configuration option allocation/thin_pool_crop_metadata.
# Older versions of lvm2 cropped pool's metadata size to 15.81 GiB.
# This is slightly less than the actual maximum 15.88 GiB.
# For compatibility with older versions and to use the cropped size, set to 1.
# Older version of lvm2 cropped pool's metadata size to 15.81 GiB.
# This is slightly less then the actual maximum 15.88 GiB.
# For compatibility with older version and use of cropped size set to 1.
# This configuration option has an automatic default value.
# thin_pool_crop_metadata = 0
@@ -916,7 +899,7 @@ log {
# Configuration option log/activation.
# Log messages during activation.
# Do not use this in low memory situations (can deadlock).
# Don't use this in low memory situations (can deadlock).
# This configuration option has an automatic default value.
# activation = 0
@@ -1091,7 +1074,7 @@ global {
# Additionally, read-only commands that encounter metadata in need of
# repair will still be allowed to proceed exactly as if the repair had
# been performed (except for the unchanged vg_seqno). Inappropriate
# use could corrupt your system, so seek advice first!
# use could mess up your system, so seek advice first!
# This configuration option has an automatic default value.
# metadata_read_only = 0
@@ -1125,7 +1108,7 @@ global {
# Configuration option global/support_mirrored_mirror_log.
# Enable mirrored 'mirror' log type for testing.
#
# This type is deprecated for creation or conversion but can
# This type is deprecated to create or convert to but can
# be enabled to test that activation of existing mirrored
# logs and conversion to disk/core works.
#
@@ -1225,7 +1208,7 @@ global {
# Configuration option global/sanlock_align_size.
# The sanlock lease size in MiB to use on disks with a 4K sector size.
# Possible values are 1,2,4,8. The default is 8, which supports up to
# 2000 hosts (and max host_id 2000). Smaller values support smaller
# 2000 hosts (and max host_id 2000.) Smaller values support smaller
# numbers of max hosts (and max host_ids): 250, 500, 1000, 2000 for
# lease sizes 1,2,4,8. Disks with 512 byte sectors always use 1MiB
# leases and support 2000 hosts, and are not affected by this setting.
@@ -1235,7 +1218,7 @@ global {
# Configuration option global/lvmlockctl_kill_command.
# The command that lvmlockctl --kill should use to force LVs offline.
# The lvmlockctl --kill command is run when a shared VG has lost
# access to locks (e.g. when sanlock has lost access to storage).
# access to locks (e.g. when sanlock has lost access to storage.)
# An empty string means that there will be no automatic attempt by
# lvmlockctl --kill to forcibly shut down LVs in the VG, and the user
# can manually intervene as described in lvmlockd(8).
@@ -1396,16 +1379,10 @@ global {
# This configuration option has an automatic default value.
# fsadm_executable = "@FSADM_PATH@"
# Configuration option global/lvresize_fs_helper_executable.
# The full path to the lvresize_fs_helper command.
# LVM uses this command to help with filesystem operations during lvresize.
# This configuration option has an automatic default value.
# lvresize_fs_helper_executable = "@LVRESIZE_FS_HELPER_PATH@"
# Configuration option global/system_id_source.
# The method LVM uses to set the local system ID.
# Volume Groups can also be given a system ID (by vgcreate, vgchange,
# or vgimport). A VG on shared storage devices is accessible only to
# or vgimport.) A VG on shared storage devices is accessible only to
# the host with a matching system ID. See 'man lvmsystemid' for
# information on limitations and correct usage.
#
@@ -1749,7 +1726,7 @@ activation {
# Configuration option activation/snapshot_autoextend_threshold.
# Auto-extend a snapshot when its usage exceeds this percent.
# Setting this to 100 disables automatic extension.
# The minimum value is 50 (a smaller value is treated as 50).
# The minimum value is 50 (a smaller value is treated as 50.)
# Also see snapshot_autoextend_percent.
# Automatic extension requires dmeventd to be monitoring the LV.
#
@@ -1779,7 +1756,7 @@ activation {
# Configuration option activation/thin_pool_autoextend_threshold.
# Auto-extend a thin pool when its usage exceeds this percent.
# Setting this to 100 disables automatic extension.
# The minimum value is 50 (a smaller value is treated as 50).
# The minimum value is 50 (a smaller value is treated as 50.)
# Also see thin_pool_autoextend_percent.
# Automatic extension requires dmeventd to be monitoring the LV.
#
@@ -1809,7 +1786,7 @@ activation {
# Configuration option activation/vdo_pool_autoextend_threshold.
# Auto-extend a VDO pool when its usage exceeds this percent.
# Setting this to 100 disables automatic extension.
# The minimum value is 50 (a smaller value is treated as 50).
# The minimum value is 50 (a smaller value is treated as 50.)
# Also see vdo_pool_autoextend_percent.
# Automatic extension requires dmeventd to be monitoring the LV.
#
@@ -2041,7 +2018,7 @@ report {
# Configuration option report/compact_output.
# Do not print empty values for all report fields.
# If enabled, all fields that do not have a value set for any of the
# If enabled, all fields that don't have a value set for any of the
# rows reported are skipped and not printed. Compact output is
# applicable only if report/buffered is enabled. If you need to
# compact only specified fields, use compact_output=0 and define
@@ -2051,7 +2028,7 @@ report {
# Configuration option report/compact_output_cols.
# Do not print empty values for specified report fields.
# If defined, specified fields that do not have a value set for any
# If defined, specified fields that don't have a value set for any
# of the rows reported are skipped and not printed. Compact output
# is applicable only if report/buffered is enabled. If you need to
# compact all fields, use compact_output=1 instead in which case

View File

@@ -38,14 +38,6 @@ local {
# This configuration option has an automatic default value.
# system_id = ""
# Configuration option local/pr_key.
# The local persistent reservation key in hexadecimal.
# The value must be unique among all hosts using the same VG.
# The max length is 16 hex characters (8 bytes), plus an optional
# 0x prefix. If pr_key is not set, host_id will be used to create a key.
# This configuration option has an automatic default value.
# pr_key = ""
# Configuration option local/extra_system_ids.
# A list of extra VG system IDs the local host can access.
# VGs with the system IDs listed here (in addition to the host's own
@@ -60,9 +52,7 @@ local {
# The sanlock host_id used by lvmlockd. This must be unique among all the hosts
# using shared VGs with sanlock. Accepted values are 1-2000, except when sanlock_align_size
# is configured to 1, 2 or 4, which correspond to max host_id values of 250, 500, or 1000.
# When using persistent reservations, lvm will generate a PR key from the host_id
# if pr_key is not defined. All hosts using a sanlock shared VG with PR must use
# the same approach for configuring their PR key (pr_key or host_id.)
# Applicable only if LVM is compiled with support for lvmlockd+sanlock.
# This configuration option has an automatic default value.
# host_id = 0
}

56
configure vendored
View File

@@ -6921,20 +6921,6 @@ then :
fi
for ac_header in xfs/xfs.h
do :
ac_fn_c_check_header_compile "$LINENO" "xfs/xfs.h" "ac_cv_header_xfs_xfs_h" "#define _GNU_SOURCE 1
"
if test "x$ac_cv_header_xfs_xfs_h" = xyes
then :
printf "%s\n" "#define HAVE_XFS_XFS_H 1" >>confdefs.h
LVM_NO_XFS_WARN=
else case e in #(
e) LVM_NO_XFS_WARN=y ;;
esac
fi
done
for ac_header in libaio.h
do :
ac_fn_c_check_header_compile "$LINENO" "libaio.h" "ac_cv_header_libaio_h" "$ac_includes_default"
@@ -12188,31 +12174,6 @@ printf "%s\n" "$BUILD_LOCKDSANLOCK" >&6; }
if test "$BUILD_LOCKDSANLOCK" = "yes"
then :
LOCKDSANLOCK_SUPPORT=370
if test -n "$PKG_CONFIG" && \
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsanlock_client >= 4.0.0\""; } >&5
($PKG_CONFIG --exists --print-errors "libsanlock_client >= 4.0.0") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
LOCKDSANLOCK_SUPPORT=400
fi
if test -n "$PKG_CONFIG" && \
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsanlock_client >= 4.1.0\""; } >&5
($PKG_CONFIG --exists --print-errors "libsanlock_client >= 4.1.0") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
LOCKDSANLOCK_SUPPORT=410
fi
if test -n "$PKG_CONFIG" && \
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsanlock_client >= 4.2.0\""; } >&5
($PKG_CONFIG --exists --print-errors "libsanlock_client >= 4.2.0") 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
LOCKDSANLOCK_SUPPORT=420
fi
pkg_failed=no
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libsanlock_client >= 3.7.0" >&5
@@ -12305,7 +12266,7 @@ printf "%s\n" "yes" >&6; }
BUILD_LVMLOCKD="yes"
fi
printf "%s\n" "#define LOCKDSANLOCK_SUPPORT $LOCKDSANLOCK_SUPPORT" >>confdefs.h
printf "%s\n" "#define LOCKDSANLOCK_SUPPORT 1" >>confdefs.h
fi
@@ -13733,7 +13694,7 @@ if test "$NOTIFYDBUS_SUPPORT" = "yes"
then :
printf "%s\n" "#define NOTIFYDBUS_SUPPORT 1" >>confdefs.h
]
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build notifydbus" >&5
@@ -14594,7 +14555,7 @@ printf %s "checking whether to compile liblvm2cmd.so... " >&6; }
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CMDLIB" >&5
printf "%s\n" "$CMDLIB" >&6; }
if test "$CMDLIB" = "yes" && test "$SHARED_LINK" = "no"
if test "$CMDLIB" == "yes" && test "$SHARED_LINK" = "no"
then :
as_fn_error $? "--enable-cmdlib requires dynamic linking." "$LINENO" 5
fi
@@ -16525,11 +16486,6 @@ LVRESIZE_FS_HELPER_PATH="$LIBEXECDIR/lvresize_fs_helper"
printf "%s\n" "#define LVRESIZE_FS_HELPER_PATH \"$LVRESIZE_FS_HELPER_PATH\"" >>confdefs.h
LVMPERSIST_PATH="$SBINDIR/lvmpersist"
printf "%s\n" "#define LVMPERSIST_PATH \"$LVMPERSIST_PATH\"" >>confdefs.h
################################################################################
# Check whether --with-dmeventd-pidfile was given.
@@ -18259,12 +18215,6 @@ then :
printf "%s\n" "$as_me: WARNING: Only libdm part can be build without libaio: make [install_]device-mapper" >&2;}
fi
if test -n "$LVM_NO_XFS_WARN"
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'lvextend --resizefs' is less capable without xfs/xfs.h (see package: xfsprogs devel)" >&5
printf "%s\n" "$as_me: WARNING: 'lvextend --resizefs' is less capable without xfs/xfs.h (see package: xfsprogs devel)" >&2;}
fi
if test "$ODIRECT" != "yes"
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: O_DIRECT disabled: low-memory pvmove may lock up" >&5

View File

@@ -1,3 +1,4 @@
###############################################################################
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
## Copyright (C) 2004-2023 Red Hat, Inc. All rights reserved.
##
@@ -101,7 +102,6 @@ AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
unistd.h], , [AC_MSG_ERROR(bailing out)])
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h sys/vfs.h linux/magic.h linux/fiemap.h)
AC_CHECK_HEADERS(xfs/xfs.h, LVM_NO_XFS_WARN=, LVM_NO_XFS_WARN=y, [#define _GNU_SOURCE 1])
AC_CHECK_HEADERS(libaio.h,LVM_NEEDS_LIBAIO_WARN=,LVM_NEEDS_LIBAIO_WARN=y)
AS_CASE(["$host_os"],
[linux*], [AC_CHECK_HEADERS([asm/byteorder.h linux/fs.h malloc.h], [], [AC_MSG_ERROR(bailing out)])],
@@ -935,12 +935,8 @@ AC_MSG_RESULT([$BUILD_LOCKDSANLOCK])
dnl -- Look for sanlock libraries
AS_IF([test "$BUILD_LOCKDSANLOCK" = "yes"], [
LOCKDSANLOCK_SUPPORT=370
PKG_CHECK_EXISTS(libsanlock_client >= 4.0.0, [LOCKDSANLOCK_SUPPORT=400])
PKG_CHECK_EXISTS(libsanlock_client >= 4.1.0, [LOCKDSANLOCK_SUPPORT=410])
PKG_CHECK_EXISTS(libsanlock_client >= 4.2.0, [LOCKDSANLOCK_SUPPORT=420])
PKG_CHECK_MODULES(LIBSANLOCKCLIENT, libsanlock_client >= 3.7.0, [BUILD_LVMLOCKD="yes"])
AC_DEFINE_UNQUOTED([LOCKDSANLOCK_SUPPORT], [$LOCKDSANLOCK_SUPPORT], [Define version of sanlock.])
AC_DEFINE([LOCKDSANLOCK_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd sanlock option.])
])
################################################################################
@@ -1296,7 +1292,7 @@ AS_IF([test "$NOTIFYDBUS_SUPPORT" = "maybe"],
[NOTIFYDBUS_SUPPORT="yes"], [NOTIFYDBUS_SUPPORT="no"])])
AS_IF([test "$NOTIFYDBUS_SUPPORT" = "yes"],
[AC_DEFINE([NOTIFYDBUS_SUPPORT], 1, [Define to 1 to include code that uses dbus notification.])])
AC_DEFINE([NOTIFYDBUS_SUPPORT], 1, [Define to 1 to include code that uses dbus notification.])])
AC_MSG_CHECKING([whether to build notifydbus])
AC_MSG_RESULT([$NOTIFYDBUS_SUPPORT])
@@ -1398,7 +1394,7 @@ AS_IF([test "$CMDLIB" != "yes"], [CMDLIB="no" LVM2CMD_LIB=], [LVM2CMD_LIB="-llvm
AC_MSG_CHECKING([whether to compile liblvm2cmd.so])
AC_MSG_RESULT([$CMDLIB])
AS_IF([test "$CMDLIB" = "yes" && test "$SHARED_LINK" = "no"],
AS_IF([test "$CMDLIB" == "yes" && test "$SHARED_LINK" = "no"],
[AC_MSG_ERROR([--enable-cmdlib requires dynamic linking.])])
@@ -1774,9 +1770,6 @@ LIBEXECDIR="$(eval echo $(eval echo $libexecdir))"
LVRESIZE_FS_HELPER_PATH="$LIBEXECDIR/lvresize_fs_helper"
AC_DEFINE_UNQUOTED(LVRESIZE_FS_HELPER_PATH, ["$LVRESIZE_FS_HELPER_PATH"], [Path to lvresize_fs_helper script.])
LVMPERSIST_PATH="$SBINDIR/lvmpersist"
AC_DEFINE_UNQUOTED(LVMPERSIST_PATH, ["$LVMPERSIST_PATH"], [Path to lvmpersist script.])
################################################################################
dnl -- dmeventd pidfile and executable path
AC_ARG_WITH(dmeventd-pidfile,
@@ -2131,9 +2124,6 @@ AS_IF([test -n "$VDO_CONFIGURE_WARN"],
AS_IF([test -n "$LVM_NEEDS_LIBAIO_WARN"],
[AC_MSG_WARN([Only libdm part can be build without libaio: make [[install_]]device-mapper])])
AS_IF([test -n "$LVM_NO_XFS_WARN"],
[AC_MSG_WARN(['lvextend --resizefs' is less capable without xfs/xfs.h (see package: xfsprogs devel)])])
AS_IF([test "$ODIRECT" != "yes"],
[AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])])

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -28,412 +28,128 @@
* cov-format-errors --dir cov --html-output html
*/
/* Define NULL for Coverity modeling */
#define NULL ((void *)0)
/* Forward declarations */
struct lv_segment;
struct logical_volume;
struct cmd_context;
struct profile;
struct dm_pool;
struct dm_list;
struct lvinfo;
struct dminfo;
struct lv_seg_status;
/* Partial definition of segment_type - only fields we need for modeling */
struct segment_type {
const char *name;
const char *dso;
/* other fields omitted */
};
/*
* These functions never return NULL for valid LVs with segments
*/
struct lv_segment *first_seg(const struct logical_volume *lv)
{
struct lv_segment *seg;
/* Model: assume lv is valid and has at least one segment */
if (lv) {
__coverity_read_pointee__(lv);
return seg;
}
__coverity_panic__(); /* Should never happen in valid code */
return ((struct lv_segment **)lv)[0];
}
struct lv_segment *last_seg(const struct logical_volume *lv)
{
struct lv_segment *seg;
if (lv) {
__coverity_read_pointee__(lv);
return seg;
}
__coverity_panic__();
return ((struct lv_segment **)lv)[0];
}
const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile)
{
char *str;
__coverity_read_pointee__(cmd);
if (str)
return str;
__coverity_panic__();
return "STRING";
}
const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, struct profile *profile)
/*
struct logical_volume *origin_from_cow(const struct logical_volume *lv)
{
char *str;
__coverity_read_pointee__(cmd);
if (str)
return str;
__coverity_panic__();
}
struct segment_type *init_unknown_segtype(struct cmd_context *cmd, const char *name)
{
struct segment_type *seg_type;
__coverity_read_pointee__(cmd);
__coverity_read_pointee__(name);
if (seg_type)
return seg_type;
if (lv)
return lv;
__coverity_panic__();
}
*/
/* simple_memccpy() from glibc */
void *memccpy(void *dest, const void *src, int c, unsigned long n)
{
int success;
const char *s = src;
char *d = dest;
__coverity_negative_sink__(n);
__coverity_negative_sink__(c);
__coverity_tainted_data_transitive__(dest, src);
__coverity_write_buffer_bytes__(dest, n);
while (n-- > 0)
if ((*d++ = *s++) == (char) c)
return d;
if (!success)
return NULL;
return dest;
}
/* dm_pool_alloc - can return NULL on allocation failure */
void *dm_pool_alloc(struct dm_pool *p, unsigned long s)
{
void *ptr;
int success;
if (!p) {
__coverity_panic__();
}
__coverity_negative_sink__(s); /* Catch negative sizes */
if (!success)
return NULL;
ptr = __coverity_alloc__(s);
/* Mark as escaped - pool memory doesn't need individual free */
__coverity_escape__(ptr);
return ptr;
}
/* dm_pool_zalloc - allocates and zeros */
void *dm_pool_zalloc(struct dm_pool *p, unsigned long s)
{
void *ptr;
int success;
if (!p) {
__coverity_panic__();
}
__coverity_negative_sink__(s); /* Catch negative sizes */
if (!success)
return NULL;
ptr = __coverity_alloc__(s);
__coverity_writeall0__(ptr); /* Memory is zeroed */
/* Mark as escaped - pool memory doesn't need individual free */
__coverity_escape__(ptr);
return ptr;
}
/* dm_pool_strdup - duplicates string in pool */
char *dm_pool_strdup(struct dm_pool *p, const char *str)
{
char *ptr;
unsigned long size;
int success;
if (!p || !str) {
__coverity_panic__();
}
__coverity_string_null_sink__(str); /* str must be null-terminated */
__coverity_string_size_sink__(str); /* Coverity tracks the size */
if (!success)
return NULL;
/* Allocate symbolic size - Coverity will track this appropriately */
ptr = __coverity_alloc__(size);
__coverity_tainted_data_transitive__(ptr, str);
/* Mark as escaped - pool memory doesn't need individual free */
__coverity_escape__(ptr);
return ptr;
}
/* dm_pool_strndup - duplicates up to n characters */
char *dm_pool_strndup(struct dm_pool *p, const char *str, unsigned long n)
{
char *ptr;
int success;
if (!p) {
__coverity_panic__();
}
__coverity_string_size_source__(str);
__coverity_negative_sink__(n);
if (!success)
return NULL;
ptr = __coverity_alloc__(n + 1);
__coverity_tainted_data_transitive__(ptr, str);
__coverity_string_null_copy__(ptr, str, n);
/* Mark as escaped - pool memory doesn't need individual free */
__coverity_escape__(ptr);
return ptr;
}
/* dm_pool_free - frees memory back to the pool */
void dm_pool_free(struct dm_pool *p, void *ptr)
{
if (!p || !ptr) {
__coverity_panic__();
}
}
void dm_pool_empty(struct dm_pool *p)
{
if (!p) {
__coverity_panic__();
}
}
/* dm_malloc - standard malloc wrapper */
void *dm_malloc_wrapper(unsigned long s, const char *file, int line)
{
void *ptr;
int success;
__coverity_negative_sink__(s);
if (!success)
return NULL;
ptr = __coverity_alloc__(s);
__coverity_mark_as_afm_allocated__(ptr, AFM_free);
return ptr;
}
/* dm_zalloc - standard calloc wrapper */
void *dm_zalloc_wrapper(unsigned long s, const char *file, int line)
{
void *ptr;
int success;
__coverity_negative_sink__(s);
if (!success)
return NULL;
ptr = __coverity_alloc__(s);
__coverity_mark_as_afm_allocated__(ptr, AFM_free);
__coverity_writeall0__(ptr);
return ptr;
}
/* dm_free - standard free wrapper */
void dm_free_wrapper(void *ptr, const char *file, int line)
{
if (ptr) {
__coverity_free__(ptr);
}
}
/* dm_list_init - initializes a list head */
void dm_list_init(struct dm_list *head)
{
if (head) {
__coverity_writeall__(head);
}
}
/* dm_list_empty - checks if list is empty (never fails) */
int dm_list_empty(const struct dm_list *head)
{
int is_empty;
if (head)
return is_empty;
__coverity_panic__();
}
/* dm_list_add - adds to list (never fails) */
void dm_list_add(struct dm_list *head, struct dm_list *elem)
{
if (!head || !elem) {
__coverity_panic__();
}
/* Modification happens, but no failure */
__coverity_writeall__(head);
__coverity_writeall__(elem);
__coverity_escape__(elem);
}
struct segtype_library;
/* lvm_register_segtype - registers a segment type
* Returns 1 on success, 0 on failure
* On failure, it calls segtype->ops->destroy(segtype) which frees the resource
* On success, the segtype is added to the list and ownership is transferred
*/
int lvm_register_segtype(struct segtype_library *seglib,
struct segment_type *segtype)
{
int success;
char *dso;
if (!seglib || !segtype) {
__coverity_panic__();
}
__coverity_read_pointee__(seglib);
__coverity_read_pointee__(segtype);
if (!success) {
/* On failure, the function calls segtype->ops->destroy(segtype)
* which frees both segtype->dso and segtype itself */
/* Read dso field and mark it as freed if it exists */
dso = segtype->dso;
if (dso)
__coverity_free__(dso);
/* Then free the segtype structure itself */
__coverity_free__(segtype);
return 0;
}
/* On success, segtype is added to the list and ownership transfers */
__coverity_escape__(segtype);
return 1;
return 0;
}
/*
* lv_info - get logical volume information
* Returns 1 if info structure has been populated, else 0 on failure.
* When lvinfo* is NULL, it returns 1 if the device is locally active, 0 otherwise.
* 2 lines below needs to be placed in coverity/config/user_nodefs.h
* Not sure about any other way.
* Without them, coverity shows warning since x86 system header files
* are using inline assembly to reset fdset
*/
int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer,
struct lvinfo *info, int with_open_count, int with_read_ahead)
//#nodef FD_ZERO model_FD_ZERO
//void model_FD_ZERO(void *fdset);
void model_FD_ZERO(void *fdset)
{
int success;
unsigned i;
if (!cmd || !lv) {
__coverity_panic__();
}
__coverity_read_pointee__(cmd);
__coverity_read_pointee__(lv);
if (!success) {
/* On failure, info may not be initialized */
return 0;
}
/* On success, info structure is fully populated (if info is not NULL) */
if (info) {
__coverity_writeall__(info);
}
return 1;
for (i = 0; i < 1024 / 8 / sizeof(long); ++i)
((long*)fdset)[i] = 0;
}
/* Resent Coverity reports quite weird errors... */
int *__errno_location(void)
{
static int _i = 0;
return &_i;
}
const unsigned short **__ctype_b_loc (void)
{
static const unsigned short *_a[1] = { 0 };
return _a;
}
/*
* lv_info - get logical volume information
* Returns 1 if info structure has been populated, else 0 on failure.
* When lvinfo* is NULL, it returns 1 if the device is locally active, 0 otherwise.
* Added extra pointer check to not need these models,
* for now just keep then in file
*/
int _info(struct cmd_context *cmd,
const char *name, const char *dlid,
int with_open_count, int with_read_ahead, int with_name_check,
struct dm_info *dminfo, unsigned *read_ahead,
struct lv_seg_status *seg_status)
/*
struct cmd_context;
struct profile;
const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile)
{
int success;
if (!cmd || (!name && !dlid)) {
__coverity_panic__();
}
__coverity_read_pointee__(cmd);
if (name)
__coverity_read_pointee__(name);
if (dlid)
__coverity_read_pointee__(dlid);
if (!success) {
/* On failure, dminfo may not be initialized */
return 0;
}
/* On success, info structure is fully populated (if info is not NULL) */
if (dminfo) {
__coverity_writeall__(dminfo);
}
if (seg_status) {
__coverity_writeall__(seg_status);
}
if (read_ahead) {
__coverity_writeall__(read_ahead);
}
return 1;
return "text";
}
const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, struct profile *profile)
{
return "text";
}
*/
/*
* Until fixed coverity case# 00531860:
* A FORWARD_NULL false positive on a recursive function call
*
* model also these functions:
*/
/*
const struct dm_config_node;
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile)
{
const struct dm_config_node *cn;
return cn;
}
const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, int id, struct profile *profile)
{
const struct dm_config_node *cn;
return cn;
}
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile)
{
int b;
return b;
}
*/

View File

@@ -228,15 +228,16 @@ static void daemonize(void)
umask(0);
if (((devnull != STDIN_FILENO) && (dup2(devnull, STDIN_FILENO) == -1)) ||
((devnull != STDOUT_FILENO) && (dup2(devnull, STDOUT_FILENO) == -1)) ||
((devnull != STDERR_FILENO) && (dup2(devnull, STDERR_FILENO) == -1))) {
if (devnull > STDERR_FILENO)
(void) close(devnull);
/* coverity[leaked_handle] devnull is stdin/stdout/stderr */
if (close(0) || close(1) || close(2)) {
LOG_ERROR("Failed to close terminal FDs");
exit(EXIT_FAILURE);
}
if ((dup2(devnull, 0) < 0) || /* reopen stdin */
(dup2(devnull, 1) < 0) || /* reopen stdout */
(dup2(devnull, 2) < 0)) /* reopen stderr */
exit(EXIT_FAILURE);
if ((devnull > STDERR_FILENO) && close(devnull)) {
LOG_ERROR("Failed to close descriptor %d: %s",
devnull, strerror(errno));
@@ -244,7 +245,7 @@ static void daemonize(void)
}
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
/* coverity[leaked_handle] devnull is stdin/stdout/stderr */
/* coverity[leaked_handle] devnull cannot leak here */
}
/*

View File

@@ -197,7 +197,7 @@ int cluster_send(struct clog_request *rq)
iov.iov_base = rq;
iov.iov_len = sizeof(struct clog_request) + rq->u_rq.data_size;
rq->u.version[0] = htole64(CLOG_TFR_VERSION);
rq->u.version[0] = xlate64(CLOG_TFR_VERSION);
rq->u.version[1] = CLOG_TFR_VERSION;
r = clog_request_to_network(rq);

View File

@@ -52,19 +52,19 @@ static void v5_data_endian_switch(struct clog_request *rq, int to_network __attr
case DM_ULOG_GET_REGION_SIZE:
case DM_ULOG_GET_SYNC_COUNT:
pu64 = (uint64_t *)rq->u_rq.data;
*pu64 = htole64(*pu64);
*pu64 = xlate64(*pu64);
break;
case DM_ULOG_IS_CLEAN:
case DM_ULOG_IN_SYNC:
pi64 = (int64_t *)rq->u_rq.data;
*pi64 = htole64(*pi64);
*pi64 = xlate64(*pi64);
break;
case DM_ULOG_GET_RESYNC_WORK:
case DM_ULOG_IS_REMOTE_RECOVERING:
pi64 = (int64_t *)rq->u_rq.data;
pu64 = ((uint64_t *)rq->u_rq.data) + 1;
*pi64 = htole64(*pi64);
*pu64 = htole64(*pu64);
*pi64 = xlate64(*pi64);
*pu64 = xlate64(*pu64);
break;
default:
LOG_ERROR("Unknown request type, %u", rq_type);
@@ -94,7 +94,7 @@ static void v5_data_endian_switch(struct clog_request *rq, int to_network __attr
case DM_ULOG_IN_SYNC:
case DM_ULOG_IS_REMOTE_RECOVERING:
pu64 = (uint64_t *)rq->u_rq.data;
*pu64 = htole64(*pu64);
*pu64 = xlate64(*pu64);
break;
case DM_ULOG_MARK_REGION:
case DM_ULOG_CLEAR_REGION:
@@ -102,13 +102,13 @@ static void v5_data_endian_switch(struct clog_request *rq, int to_network __attr
pu64 = (uint64_t *)rq->u_rq.data;
for (i = 0; i < end; i++)
pu64[i] = htole64(pu64[i]);
pu64[i] = xlate64(pu64[i]);
break;
case DM_ULOG_SET_REGION_SYNC:
pu64 = (uint64_t *)rq->u_rq.data;
pi64 = ((int64_t *)rq->u_rq.data) + 1;
*pu64 = htole64(*pu64);
*pi64 = htole64(*pi64);
*pu64 = xlate64(*pu64);
*pi64 = xlate64(*pi64);
break;
default:
LOG_ERROR("Unknown request type, %u", rq_type);
@@ -124,15 +124,15 @@ static int v5_endian_to_network(struct clog_request *rq)
size = sizeof(*rq) + u_rq->data_size;
u_rq->error = htole32(u_rq->error);
u_rq->seq = htole32(u_rq->seq);
u_rq->error = xlate32(u_rq->error);
u_rq->seq = xlate32(u_rq->seq);
rq->originator = htole32(rq->originator);
rq->originator = xlate32(rq->originator);
v5_data_endian_switch(rq, 1);
u_rq->request_type = htole32(u_rq->request_type);
u_rq->data_size = htole32(u_rq->data_size);
u_rq->request_type = xlate32(u_rq->request_type);
u_rq->data_size = xlate32(u_rq->data_size);
return size;
}
@@ -142,7 +142,7 @@ int clog_request_to_network(struct clog_request *rq)
int r;
/* FIXME: Remove this safety check */
if (rq->u.version[0] != htole64(rq->u.version[1])) {
if (rq->u.version[0] != xlate64(rq->u.version[1])) {
LOG_ERROR("Programmer error: version[0] must be LE");
exit(EXIT_FAILURE);
}
@@ -165,12 +165,12 @@ static int v5_endian_from_network(struct clog_request *rq)
int size;
struct dm_ulog_request *u_rq = &rq->u_rq;
u_rq->error = htole32(u_rq->error);
u_rq->seq = htole32(u_rq->seq);
u_rq->request_type = htole32(u_rq->request_type);
u_rq->data_size = htole32(u_rq->data_size);
u_rq->error = xlate32(u_rq->error);
u_rq->seq = xlate32(u_rq->seq);
u_rq->request_type = xlate32(u_rq->request_type);
u_rq->data_size = xlate32(u_rq->data_size);
rq->originator = htole32(rq->originator);
rq->originator = xlate32(rq->originator);
size = sizeof(*rq) + u_rq->data_size;
@@ -182,7 +182,7 @@ static int v5_endian_from_network(struct clog_request *rq)
int clog_request_from_network(void *data, size_t data_len)
{
uint64_t *vp = data;
uint64_t version = htole64(vp[0]);
uint64_t version = xlate64(vp[0]);
struct clog_request *rq = data;
switch (version) {

View File

@@ -380,8 +380,8 @@ static int _clog_ctr(char *uuid, uint64_t luid,
int disk_log;
char disk_path[PATH_MAX] = { 0 };
int unlink_path = 0;
long ps;
size_t pages, page_size;
long page_size;
int pages;
/* If core log request, then argv[0] will be region_size */
if (!strtoll(argv[0], &p, 0) || *p) {
@@ -488,15 +488,14 @@ static int _clog_ctr(char *uuid, uint64_t luid,
lc->sync_count = (log_sync == NOSYNC) ? region_count : 0;
if (disk_log) {
if (((ps = sysconf(_SC_PAGESIZE)) <= 0) ||
(ps > (1 << 24))) {
if ((page_size = sysconf(_SC_PAGESIZE)) < 0) {
LOG_ERROR("Unable to read pagesize: %s",
strerror(errno));
r = errno;
goto fail;
}
page_size = (size_t)ps;
pages = (*(lc->clean_bits) + page_size - 1) / page_size;
pages = *(lc->clean_bits) / page_size;
pages += *(lc->clean_bits) % page_size ? 1 : 0;
pages += 1; /* for header */
r = open(disk_path, O_RDWR | O_DIRECT);

View File

@@ -326,11 +326,10 @@ static int do_local_work(void *data __attribute__((unused)))
*
* Returns: 0 on success, -EXXX on failure
*/
int kernel_send(void *data)
int kernel_send(struct dm_ulog_request *u_rq)
{
int r;
uint16_t size;
struct dm_ulog_request *u_rq = data;
if (!u_rq)
return -EINVAL;
@@ -354,7 +353,7 @@ int kernel_send(void *data)
size = sizeof(struct dm_ulog_request);
}
r = kernel_send_helper(data, size);
r = kernel_send_helper(u_rq, size);
if (r)
LOG_ERROR("Failed to send msg to kernel.");

View File

@@ -17,6 +17,6 @@ struct dm_ulog_request;
int init_local(void);
void cleanup_local(void);
int kernel_send(void *data);
int kernel_send(struct dm_ulog_request *rq);
#endif /* _LVM_CLOG_LOCAL_H */

File diff suppressed because it is too large Load Diff

View File

@@ -829,7 +829,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
}
dm_event_handler_set_dso(dmevh, reply_dso);
dm_event_handler_set_event_mask(dmevh, (enum dm_event_mask) reply_mask);
dm_event_handler_set_event_mask(dmevh, reply_mask);
free(reply_dso);
reply_dso = NULL;
@@ -956,13 +956,12 @@ void dm_event_log(const char *subsys, int level, const char *file,
prio = LOG_CRIT;
}
/* Serialize to keep lines readable */
pthread_mutex_lock(&_log_mutex);
if (_use_syslog) {
/* vsyslog() is thread-safe per POSIX, no mutex needed */
vsyslog(prio, format, ap);
} else {
/* Serialize to keep lines readable */
pthread_mutex_lock(&_log_mutex);
if (_debug_level) {
#define _NSEC_PER_SEC (1000000000LL)
#ifdef HAVE_REALTIME
@@ -989,10 +988,10 @@ void dm_event_log(const char *subsys, int level, const char *file,
fprintf(stream, "%28s:%4d %s", file, line, indent);
vfprintf(stream, _(format), ap);
fputc('\n', stream);
(void) fflush(stream);
pthread_mutex_unlock(&_log_mutex);
fflush(stream);
}
pthread_mutex_unlock(&_log_mutex);
if (_abort_on_internal_errors < 0)
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */

View File

@@ -15,7 +15,6 @@
#include "lib/misc/lib.h"
#include "dmeventd_lvm.h"
#include "daemons/dmeventd/libdevmapper-event.h"
#include "lib/metadata/metadata-exported.h" /* MIRROR_SYNC_LAYER */
#include "tools/lvm2cmd.h"
#include <pthread.h>
@@ -144,7 +143,7 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
}
/* strip off the mirror component designations */
if ((layer = strstr(lv, MIRROR_SYNC_LAYER)) ||
if ((layer = strstr(lv, "_mimagetmp")) ||
(layer = strstr(lv, "_mlog")))
*layer = '\0';

View File

@@ -84,7 +84,7 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
*/
if (!state->warned && status->insync_regions < status->total_regions) {
state->warned = 1;
log_warn("WARNING: Waiting for resynchronization to finish "
log_warn("WARNING: waiting for resynchronization to finish "
"before initiating repair on RAID device %s.", device);
/* Fall through to allow lvconvert to run. */
}

View File

@@ -45,10 +45,10 @@
struct dso_state {
struct dm_pool *mem;
dm_percent_t metadata_percent_check;
dm_percent_t metadata_percent;
dm_percent_t data_percent_check;
dm_percent_t data_percent;
int metadata_percent_check;
int metadata_percent;
int data_percent_check;
int data_percent;
uint64_t known_metadata_size;
uint64_t known_data_size;
unsigned fails;
@@ -56,7 +56,7 @@ struct dso_state {
int restore_sigset;
sigset_t old_sigset;
pid_t pid;
const char *argv[3];
char *argv[3];
char *cmd_str;
};
@@ -95,7 +95,7 @@ static int _run_command(struct dso_state *state)
/* child */
(void) close(0);
for (i = 3; i < 255; ++i) (void) close(i);
execvp(state->argv[0], (char **) state->argv);
execvp(state->argv[0], state->argv);
_exit(errno);
} else if (state->pid == -1) {
log_error("Can't fork command %s.", state->cmd_str);
@@ -223,12 +223,10 @@ void process_event(struct dm_task *dmt,
}
#if THIN_DEBUG
log_debug("Thin pool status " FMTu64 "/" FMTu64 " (" FMTu64 ") "
FMTu64 "/" FMTu64 " (" FMTu64").",
tps->used_data_blocks, tps->total_data_blocks,
state->known_data_size,
log_debug("Thin pool status " FMTu64 "/" FMTu64 " "
FMTu64 "/" FMTu64 ".",
tps->used_metadata_blocks, tps->total_metadata_blocks,
state->known_metadata_size);
tps->used_data_blocks, tps->total_data_blocks);
#endif
/* Thin pool size had changed. Clear the threshold. */
@@ -384,10 +382,11 @@ int register_device(const char *device,
} else /* Unsupported command format */
goto inval;
state->max_fails = 1;
state->pid = -1;
*user = state;
log_info("Monitoring thin pool %s.", device);
return 1;
inval:
log_error("Invalid command for monitoring: %s.", cmd_str);
@@ -431,6 +430,7 @@ int unregister_device(const char *device,
_restore_thread_signals(state);
dmeventd_lvm2_exit_with_pool(state);
log_info("No longer monitoring thin pool %s.", device);
return 1;
}

View File

@@ -49,7 +49,7 @@ struct dso_state {
int restore_sigset;
sigset_t old_sigset;
pid_t pid;
const char *argv[3];
char *argv[3];
const char *cmd_str;
const char *name;
};
@@ -86,7 +86,7 @@ static int _run_command(struct dso_state *state)
/* child */
(void) close(0);
for (i = 3; i < 255; ++i) (void) close(i);
execvp(state->argv[0], (char **)state->argv);
execvp(state->argv[0], state->argv);
_exit(errno);
} else if (state->pid == -1) {
log_error("Can't fork command %s.", state->cmd_str);
@@ -314,7 +314,7 @@ int register_device(const char *device,
{
struct dso_state *state;
const char *cmd;
const char *str;
char *str;
char cmd_str[PATH_MAX + 128 + 2]; /* cmd ' ' vg/lv \0 */
const char *name = "pool";

View File

@@ -160,8 +160,6 @@ def call_lvm(command, debug=False, line_cb=None,
# Check to see if process has terminated, None when running
if process.poll() is not None:
stdout_text += read_decoded(process.stdout)
stderr_text += read_decoded(process.stderr)
break
except IOError as ioe:
log_debug("call_lvm:" + str(ioe))

View File

@@ -272,7 +272,7 @@ class ObjectManager(AutomatedProperties):
For a given lvm asset return the dbus object path registered for it.
This method first looks up by uuid and then by lvm_id. You
can search by just one by setting uuid == lvm_id (uuid or lvm_id).
If the object is not found and path_create is not None, the
If the object is not found and path_create is a not None, the
path_create function will be called to create a new object path and
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
@@ -295,7 +295,7 @@ class ObjectManager(AutomatedProperties):
if uuid == lvm_id:
path = self._id_lookup(lvm_id)
else:
# We have a uuid and an lvm_id we can do sanity checks to ensure
# We have an 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

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
@@ -9,7 +9,6 @@
import pyudev
import threading
import os
from . import cfg
from .request import RequestEntry
from . import utils
@@ -53,47 +52,10 @@ def filter_event(action, device):
# when appropriate.
refresh = False
# Debug: Uncomment to log all udev events
#devlinks_str = device.get('DEVLINKS', '')
#utils.log_debug("Udev event: action='%s', DEVNAME='%s', ID_FS_TYPE='%s', subsystem='%s', DEVLINKS='%s'" %
# (action, device.get('DEVNAME', 'N/A'), device.get('ID_FS_TYPE', 'N/A'),
# device.get('SUBSYSTEM', 'N/A'), devlinks_str[:100] if devlinks_str else 'N/A'))
# Ignore everything but change
if action != 'change':
return
# Helper to lookup device with automatic path translation for test environments
dm_dev_dir = os.environ.get('DM_DEV_DIR', '/dev')
def lookup_with_translation(device):
"""Lookup device by name, with fallback to translated path if needed.
Try direct lookup first (fast path for production).
If not found and using test environment (DM_DEV_DIR != /dev):
- Extract dm-name from DEVLINKS (/dev/disk/by-id/dm-name-XXX)
- Construct path: $DM_DEV_DIR/mapper/XXX
- Try lookup again
Returns the found object or None.
"""
devname = device.get('DEVNAME', '')
obj = cfg.om.get_object_by_lvm_id(devname)
if not obj and dm_dev_dir != '/dev' and devname.startswith('/dev/dm-'):
devlinks = device.get('DEVLINKS', '')
if devlinks:
# Parse DEVLINKS to find dm-name-XXX
for link in devlinks.split():
if 'dm-name-' in link:
# Extract device-mapper name from /dev/disk/by-id/dm-name-XXX
dm_name = link.split('dm-name-', 1)[1]
# Construct path in DM_DEV_DIR and try lookup
mapped_path = os.path.join(dm_dev_dir, 'mapper', dm_name)
#utils.log_debug("Translating %s to %s (via dm-name)" % (devname, mapped_path))
obj = cfg.om.get_object_by_lvm_id(mapped_path)
break
return obj
if 'ID_FS_TYPE' in device:
fs_type_new = device['ID_FS_TYPE']
if 'LVM' in fs_type_new:
@@ -102,29 +64,17 @@ def filter_event(action, device):
# 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 lookup_with_translation(device):
if not cfg.om.get_object_by_lvm_id(device['DEVNAME']):
refresh = True
elif fs_type_new == '':
# Check to see if the device was one we knew about
if 'DEVNAME' in device:
if lookup_with_translation(device):
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
refresh = True
else:
# This handles the wipefs -a path
if not refresh and 'DEVNAME' in device:
found_obj = lookup_with_translation(device)
# Also check device symlinks - udev might report /dev/dm-X but
# the PV is tracked under a different name
if not found_obj:
devlinks = device.get('DEVLINKS', '')
if devlinks:
for link in devlinks.split():
found_obj = cfg.om.get_object_by_lvm_id(link)
if found_obj:
break
if found_obj:
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
refresh = True
if refresh:
@@ -135,8 +85,7 @@ def add():
with observer_lock:
global observer
context = pyudev.Context()
# Use source='udev' to get processed udev events, not raw kernel events
monitor = pyudev.Monitor.from_netlink(context, source='udev')
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by('block')
observer = pyudev.MonitorObserver(monitor, filter_event)
observer.start()

View File

@@ -406,12 +406,10 @@ def handler(signum):
cfg.ignore_sigterm = False
return True
# Set shutdown flag first so worker threads can detect shutdown
# even if exit_shell() blocks on shell_lock
cfg.run.value = 0
# 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)
if cfg.loop is not None:
cfg.loop.quit()

View File

@@ -15,7 +15,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SOURCES = lvmlockd-core.c lvmlockd-helper.c
SOURCES = lvmlockd-core.c
SOURCES2 = lvmlockctl.c
TARGETS = lvmlockd lvmlockctl

View File

@@ -67,160 +67,6 @@ do { \
syslog(LOG_WARNING, fmt, ##args); \
} while (0)
/*
* Like sscanf, but requires buffer size to be specified
* for storing scanned strings, e.g.
*
* szscanf("%s", sizeof(buf), buf);
*
* Up to size-1 input bytes will be copied into buf.
* A null byte will be written to buf following the
* last copied byte. When nothing is copied to buf,
* no terminating null byte is written.
*
* If an input string matching %s is too long for the
* specified buffer size, the characters that would have
* been copied are ignored.
*
* Only recognizes: %d, %u, %s.
*/
static int szscanf(const char *input, const char *format, ...)
{
va_list args;
const char *fm;
const char *in;
int matched = 0;
int n;
va_start(args, format);
fm = format;
in = input;
while (*fm != '\0') {
/*
* format is a string containing:
* 1. %d matching int from input
* %u matching unsigned int from input
* %s matching non-whitespace characters from input
* 2. whitespace chars matching zero or more whitespace
* characters from input
* 3. non-whitespace chars matching the same input chars
*/
if (*fm == '%') {
/*
* case 1: %u, %d, or %s
*/
/* advance past '%' character, to look for 'u', 'd' or 's' */
fm++;
if (*fm == 'd') {
/*
* read an int (%d)
*/
int *dest = va_arg(args, int *);
if (sscanf(in, "%d%n", dest, &n) == 1) {
in += n;
matched++;
} else {
/* matching failure: no input int */
break;
}
} else if (*fm == 'u') {
/*
* read an unsigned int (%u)
*/
unsigned int *dest = va_arg(args, unsigned int *);
if (sscanf(in, "%u%n", dest, &n) == 1) {
in += n;
matched++;
} else {
/* matching failure: no input unsigned int */
break;
}
} else if (*fm == 's') {
/*
* read a string (%s) into dest buffer with dest_size
* copy up to dest_size-1 characters into dest buffer
* write null byte into dest buffer following the last
* character copied. When dest_size-1 bytes are copied,
* the null byte is written into the final byte of the
* dest buffer. input bytes that would have been copied
* but did not fit in the dest buffer are skipped.
*/
size_t dest_size = va_arg(args, size_t);
char *dest = va_arg(args, char *);
char *out = dest;
/* don't copy leading input whitespace to dest */
while (isspace((unsigned char)*in))
in++;
/* copy non-whitespace characters from input to dest */
n = 0;
while (*in != '\0' && !isspace((unsigned char)*in) && (n < (int)dest_size-1)) {
*out = *in;
out++;
in++;
n++;
}
if (n) {
dest[n] = '\0';
matched++;
} else {
/* matching failure: no input string chars */
break;
}
/* ignore input bytes that would have been copied but didn't fit */
while (*in != '\0' && !isspace((unsigned char)*in))
in++;
} else {
/* unsupported format specifier */
matched = -1;
break;
}
/* advance past 'd', 'u', or 's' character */
fm++;
} else if (isspace((unsigned char)*fm)) {
/*
* case 2: format whitespace skips zero or more input
* whitespace characters
*/
while (isspace((unsigned char)*in))
in++;
/* advance past whitespace character */
fm++;
} else if (*fm == *in) {
/*
* case 3: literal character match between format and input
*/
fm++;
in++;
} else {
/*
* matching failure: format and input don't match
*/
break;
}
}
va_end(args);
return matched;
}
#define MAX_LINE 512
/* copied from lvmlockd-internal.h */
@@ -251,11 +97,9 @@ static void save_client_info(char *line)
uint32_t client_id = 0;
char name[MAX_NAME+1] = { 0 };
/* info=client pid=%u fd=%d pi=%d id=%u name=%s */
if (szscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
&pid, &fd, &pi, &client_id, sizeof(name), name) < 0)
return;
(void) sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%"
DM_TO_STRING(MAX_NAME) "s",
&pid, &fd, &pi, &client_id, name);
clients[num_clients].client_id = client_id;
clients[num_clients].pid = pid;
@@ -283,26 +127,22 @@ static void format_info_ls(char *line)
char ls_name[MAX_NAME+1] = { 0 };
char vg_name[MAX_NAME+1] = { 0 };
char vg_uuid[MAX_NAME+1] = { 0 };
char vg_args[MAX_ARGS+1] = { 0 };
char lm_type[MAX_NAME+1] = { 0 };
char lock_args[MAX_ARGS+1] = { 0 };
char lock_type[MAX_NAME+1] = { 0 };
/* info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_args=%s lm_type=%s */
if (szscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_args=%s lm_type=%s",
sizeof(ls_name), ls_name,
sizeof(vg_name), vg_name,
sizeof(vg_uuid), vg_uuid,
sizeof(vg_args), vg_args,
sizeof(lm_type), lm_type) < 0)
return;
(void) sscanf(line, "info=ls ls_name=%" DM_TO_STRING(MAX_NAME) "s vg_name=%"
DM_TO_STRING(MAX_NAME) "s vg_uuid=%" DM_TO_STRING(MAX_NAME)
"s vg_args=%" DM_TO_STRING(MAX_NAME) "s lm_type=%"
DM_TO_STRING(MAX_NAME) "s",
ls_name, vg_name, vg_uuid, lock_args, lock_type);
if (!first_ls)
printf("\n");
first_ls = 0;
printf("VG %s lock_type=%s %s\n", vg_name, lm_type, vg_uuid);
printf("VG %s lock_type=%s %s\n", vg_name, lock_type, vg_uuid);
printf("LS %s %s\n", lm_type, ls_name);
printf("LS %s %s\n", lock_type, ls_name);
}
static void format_info_ls_action(char *line)
@@ -314,67 +154,29 @@ static void format_info_ls_action(char *line)
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
/* info=ls_action client_id=%u flags=%s version=%u op=%s rt=%s mode=%s lm_type=%s result=%d lm_rv=%d owner_host_id=%u owner_generation=%u */
if (szscanf(line, "info=ls_action client_id=%u flags=%s version=%s op=%s",
&client_id,
sizeof(flags), flags,
sizeof(version), version,
sizeof(op), op) < 0)
return;
(void) sscanf(line, "info=ls_action client_id=%u %"
DM_TO_STRING(MAX_NAME) "s %"
DM_TO_STRING(MAX_NAME) "s op=%"
DM_TO_STRING(MAX_NAME) "s",
&client_id, flags, version, op);
find_client_info(client_id, &pid, cl_name);
printf("OP %s pid %u (%s)\n", op, pid, cl_name);
}
static void format_info_ls_fence_history(char *line)
{
char op[MAX_NAME+1] = { 0 };
int result = 0;
uint32_t msg_id = 0;
uint32_t owner_host_id = 0;
uint32_t owner_generation = 0;
char ourkey_str[MAX_NAME+1] = { 0 };
char remkey_str[MAX_NAME+1] = { 0 };
/* info=ls_fence_history op=%s result=%d msg_id=%u owner_host_id=%u owner_generation=%u ourkey=0x%llx remkey=0x%llx */
if (szscanf(line, "info=ls_fence_history op=%s result=%d msg_id=%u owner_host_id=%u owner_generation=%u ourkey=%s remkey=%s",
sizeof(op), op,
&result,
&msg_id,
&owner_host_id,
&owner_generation,
sizeof(ourkey_str), ourkey_str,
sizeof(remkey_str), remkey_str) < 0)
return;
if (!strcmp(op, "fence_result"))
printf("PR host_id %u generation %u key %s %s\n",
owner_host_id, owner_generation, remkey_str, result == 0 ? "removed" : "failed");
else if (!strcmp(op, "fence"))
printf("PR host_id %u generation %u key %s waiting\n",
owner_host_id, owner_generation, remkey_str);
}
static void format_info_r(char *line, char *r_name_out, char *r_type_out)
{
char r_name[MAX_NAME+1] = { 0 };
char r_type[4] = { 0 };
char mode[4] = { 0 };
int sh_count = 0;
unsigned int ver = 0;
char sh_count[MAX_NAME+1] = { 0 };
uint32_t ver = 0;
/* info=r name=%s type=%s mode=%s sh_count=%d version=%s */
if (szscanf(line, "info=r name=%s type=%s mode=%s sh_count=%d version=%u",
sizeof(r_name), r_name,
sizeof(r_type), r_type,
sizeof(mode), mode,
&sh_count,
&ver) < 0)
return;
(void) sscanf(line, "info=r name=%" DM_TO_STRING(MAX_NAME)
"s type=%3s mode=%3s %"
DM_TO_STRING(MAX_NAME) "s version=%u",
r_name, r_type, mode, sh_count, &ver);
strcpy(r_name_out, r_name);
strcpy(r_type_out, r_type);
@@ -399,8 +201,8 @@ static void format_info_r(char *line, char *r_name_out, char *r_type_out)
static void format_info_lk(char *line, char *r_name, char *r_type)
{
char mode[4] = { 0 };
char flags[MAX_NAME+1] = { 0 };
uint32_t ver = 0;
char flags[MAX_NAME+1] = { 0 };
uint32_t client_id = 0;
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
@@ -411,14 +213,9 @@ static void format_info_lk(char *line, char *r_name, char *r_type)
return;
}
/* info=lk mode=%s version=%s flags=%s client_id=%u */
if (szscanf(line, "info=lk mode=%s version=%u flags=%s client_id=%u",
sizeof(mode), mode,
&ver,
sizeof(flags), flags,
&client_id) < 0)
return;
(void) sscanf(line, "info=lk mode=%3s version=%u %"
DM_TO_STRING(MAX_NAME) "s client_id=%u",
mode, &ver, flags, &client_id);
find_client_info(client_id, &pid, cl_name);
@@ -441,9 +238,9 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
char op[MAX_NAME+1] = { 0 };
char rt[4] = { 0 };
char mode[4] = { 0 };
char lm_type[MAX_NAME+1] = { 0 };
int result = 0;
int lm_rv = 0;
char lm[MAX_NAME+1] = { 0 };
char result[MAX_NAME+1] = { 0 };
char lm_rv[MAX_NAME+1] = { 0 };
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
@@ -453,19 +250,11 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
return;
}
/* info=r_action client_id=%u flags=%s version=%s op=%s rt=%s mode=%s lm_type=%s result=%d lm_rv=%d owner_host_id=%u owner_generation=%u */
if (szscanf(line, "info=r_action client_id=%u flags=%s version=%s op=%s rt=%s mode=%s lm_type=%s result=%d lm_rv=%d",
&client_id,
sizeof(flags), flags,
sizeof(version), version,
sizeof(op), op,
sizeof(rt), rt,
sizeof(mode), mode,
sizeof(lm_type), lm_type,
&result,
&lm_rv) < 0)
return;
(void) sscanf(line, "info=r_action client_id=%u %" DM_TO_STRING(MAX_NAME)
"s %" DM_TO_STRING(MAX_NAME) "s op=%" DM_TO_STRING(MAX_NAME)
"s rt=%3s mode=%3s %" DM_TO_STRING(MAX_NAME) "s %"
DM_TO_STRING(MAX_NAME) "s %" DM_TO_STRING(MAX_NAME) "s",
&client_id, flags, version, op, rt, mode, lm, result, lm_rv);
find_client_info(client_id, &pid, cl_name);
@@ -485,62 +274,6 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
}
}
static void format_info_r_fence_wait_action(char *line, char *r_name, char *r_type)
{
uint32_t client_id = 0;
char flags[MAX_NAME+1] = { 0 };
char version[MAX_NAME+1] = { 0 };
char op[MAX_NAME+1] = { 0 };
char rt[4] = { 0 };
char mode[4] = { 0 };
char lm_type[MAX_NAME+1] = { 0 };
int result = 0;
int lm_rv = 0;
uint32_t owner_host_id = 0;
uint32_t owner_generation = 0;
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
if (!r_name[0] || !r_type[0]) {
printf("format_info_r_fence_wait_action error r_name %s r_type %s\n", r_name, r_type);
printf("%s\n", line);
return;
}
/* info=r_fence_wait_action client_id=%u flags=%s version=%s op=%s rt=%s mode=%s lm_type=%s result=%d lm_rv=%d owner_host_id=%u owner_generation=%u */
if (szscanf(line, "info=r_fence_wait_action client_id=%u flags=%s version=%s op=%s rt=%s mode=%s lm_type=%s result=%d lm_rv=%d owner_host_id=%u owner_generation=%u",
&client_id,
sizeof(flags), flags,
sizeof(version), version,
sizeof(op), op,
sizeof(rt), rt,
sizeof(mode), mode,
sizeof(lm_type), lm_type,
&result,
&lm_rv,
&owner_host_id,
&owner_generation) < 0)
return;
find_client_info(client_id, &pid, cl_name);
if (strcmp(op, "lock")) {
printf("OP %s pid %u (%s)\n", op, pid, cl_name);
return;
}
if (!strcmp(r_type, "gl")) {
printf("LW GL %s ver %u pid %u (%s) fence_owner %u.%u\n", mode, 0, pid, cl_name, owner_host_id, owner_generation);
} else if (!strcmp(r_type, "vg")) {
printf("LW VG %s ver %u pid %u (%s) fence_owner %u.%u\n", mode, 0, pid, cl_name, owner_host_id, owner_generation);
} else if (!strcmp(r_type, "lv")) {
printf("LW LV %s %s fence_owner %u.%u\n", mode, r_name, owner_host_id, owner_generation);
}
}
static void format_info_line(char *line, char *r_name, char *r_type)
{
if (!strncmp(line, "info=structs ", sizeof("info=structs ") - 1)) {
@@ -555,9 +288,6 @@ static void format_info_line(char *line, char *r_name, char *r_type)
} else if (!strncmp(line, "info=ls_action ", sizeof("info=ls_action ") - 1)) {
format_info_ls_action(line);
} else if (!strncmp(line, "info=ls_fence_history ", sizeof("info=ls_fence_history ") - 1)) {
format_info_ls_fence_history(line);
} else if (!strncmp(line, "info=r ", sizeof("info=r ") - 1)) {
/*
* r_name/r_type are reset when a new resource is found.
@@ -575,11 +305,6 @@ static void format_info_line(char *line, char *r_name, char *r_type)
} else if (!strncmp(line, "info=r_action ", sizeof("info=r_action ") - 1)) {
/* will use info from previous r */
format_info_r_action(line, r_name, r_type);
} else if (!strncmp(line, "info=r_fence_wait_action ", sizeof("info=r_fence_wait_action ") - 1)) {
/* will use info from previous r */
format_info_r_fence_wait_action(line, r_name, r_type);
} else {
printf("UN %s\n", line);
}

View File

@@ -57,14 +57,5 @@ static inline void lvmlockd_close(daemon_handle h)
#define EORPHAN 222
#define EADOPT_NONE 223
#define EADOPT_RETRY 224
#define EIOTIMEOUT 225
#define ELOCKREPAIR 226
#define LOCKARGS_VERSION 0x00000001 /* meta only */
#define LOCKARGS_LVMLOCK 0x00000002 /* meta only */
#define LOCKARGS_TIMEOUT 0x00000004 /* user only */
#define LOCKARGS_NOTIMEOUT 0x00000008 /* meta or user */
#define LOCKARGS_PERSIST 0x00000010 /* meta or user */
#define LOCKARGS_NOPERSIST 0x00000020 /* user only */
#endif /* _LVM_LVMLOCKD_CLIENT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,7 @@
#include <errno.h>
#include <endian.h>
#include <fcntl.h>
#include <byteswap.h>
#include <syslog.h>
#include <dirent.h>
@@ -76,7 +77,7 @@ static int check_args_version(char *vg_args)
unsigned int major = 0;
int rv;
rv = lockd_lockargs_get_version(vg_args, &major, NULL, NULL);
rv = version_from_args(vg_args, &major, NULL, NULL);
if (rv < 0) {
log_error("check_args_version %s error %d", vg_args, rv);
return rv;
@@ -583,9 +584,9 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
if (daemon_test) {
if (rdd->vb) {
vb_out->version = le16toh(rdd->vb->version);
vb_out->flags = le16toh(rdd->vb->flags);
vb_out->r_version = le32toh(rdd->vb->r_version);
vb_out->version = le16_to_cpu(rdd->vb->version);
vb_out->flags = le16_to_cpu(rdd->vb->flags);
vb_out->r_version = le32_to_cpu(rdd->vb->r_version);
}
return 0;
}
@@ -637,9 +638,9 @@ lockrv:
memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk));
memcpy(rdd->vb, &vb, sizeof(vb));
vb_out->version = le16toh(vb.version);
vb_out->flags = le16toh(vb.flags);
vb_out->r_version = le32toh(vb.r_version);
vb_out->version = le16_to_cpu(vb.version);
vb_out->flags = le16_to_cpu(vb.flags);
vb_out->r_version = le32_to_cpu(vb.r_version);
}
out:
return 0;
@@ -664,9 +665,9 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
if (!rdd->vb->version) {
/* first time vb has been written */
rdd->vb->version = htole16(VAL_BLK_VERSION);
rdd->vb->version = cpu_to_le16(VAL_BLK_VERSION);
}
rdd->vb->r_version = htole32(r_version);
rdd->vb->r_version = cpu_to_le32(r_version);
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
log_debug("%s:%s convert_dlm set r_version %u",
@@ -723,17 +724,17 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
memcpy(&vb_next, rdd->vb, sizeof(struct val_blk));
if (!vb_prev.version) {
vb_next.version = htole16(VAL_BLK_VERSION);
vb_next.version = cpu_to_le16(VAL_BLK_VERSION);
new_vb = 1;
}
if ((lmu_flags & LMUF_FREE_VG) && (r->type == LD_RT_VG)) {
vb_next.flags = htole16(VBF_REMOVED);
vb_next.flags = cpu_to_le16(VBF_REMOVED);
new_vb = 1;
}
if (r_version) {
vb_next.r_version = htole32(r_version);
vb_next.r_version = cpu_to_le32(r_version);
new_vb = 1;
}
@@ -743,12 +744,12 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
log_debug("%s:%s unlock_dlm vb old %x %x %u new %x %x %u",
ls->name, r->name,
le16toh(vb_prev.version),
le16toh(vb_prev.flags),
le32toh(vb_prev.r_version),
le16toh(vb_next.version),
le16toh(vb_next.flags),
le32toh(vb_next.r_version));
le16_to_cpu(vb_prev.version),
le16_to_cpu(vb_prev.flags),
le32_to_cpu(vb_prev.r_version),
le16_to_cpu(vb_next.version),
le16_to_cpu(vb_next.flags),
le32_to_cpu(vb_next.r_version));
} else {
log_debug("%s:%s unlock_dlm vb unchanged", ls->name, r->name);
}
@@ -798,14 +799,6 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
* the stale lockspaces on the others eventually.)
*/
/*
* On error, returns < 0
*
* On success:
* If other hosts are found, returns the number.
* If no other hosts are found (only ourself), returns 0.
*/
int lm_hosts_dlm(struct lockspace *ls, int notify)
{
char ls_nodes_path[PATH_MAX];

View File

@@ -1,264 +0,0 @@
/*
* Copyright 2025 Red Hat, Inc.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v2 or (at your option) any later version.
*/
#include <inttypes.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <poll.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#include <stdarg.h>
#include <signal.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <grp.h>
#include <syslog.h>
#include "lvmlockd-internal.h"
struct list_head commands; /* helper_msg_list entries */
static int _log_stderr;
#define log_helper(fmt, args...) \
do { \
if (_log_stderr) \
fprintf(stderr, fmt "\n", ##args); \
} while (0)
static void _save_command(struct helper_msg *msg)
{
struct helper_msg_list *ml;
ml = malloc(sizeof(struct helper_msg_list));
if (!ml)
return;
memcpy(&ml->msg, msg, sizeof(struct helper_msg));
list_add_tail(&ml->list, &commands);
}
static struct helper_msg_list *_get_command(int pid)
{
struct helper_msg_list *ml;
list_for_each_entry(ml, &commands, list) {
if (ml->msg.pid == pid)
return ml;
}
return NULL;
}
static int read_msg(int fd, struct helper_msg *msg)
{
int rv;
retry:
rv = read(fd, msg, sizeof(struct helper_msg));
if (rv == -1 && errno == EINTR)
goto retry;
if (rv != sizeof(struct helper_msg))
return -1;
return 0;
}
static void exec_command(char *cmd_str)
{
char arg[ONE_ARG_LEN];
char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */
int av_count = 0;
int i, arg_len, cmd_len;
for (i = 0; i < MAX_AV_COUNT + 1; i++)
av[i] = NULL;
if (!cmd_str[0])
return;
/* this should already be done, but make sure */
cmd_str[RUN_COMMAND_LEN - 1] = '\0';
memset(&arg, 0, sizeof(arg));
arg_len = 0;
cmd_len = strlen(cmd_str);
for (i = 0; i < cmd_len; i++) {
if (!cmd_str[i])
break;
if (av_count == MAX_AV_COUNT)
break;
if (cmd_str[i] == '\\') {
if (i == (cmd_len - 1))
break;
i++;
if (cmd_str[i] == '\\') {
arg[arg_len++] = cmd_str[i];
continue;
}
if (isspace(cmd_str[i])) {
arg[arg_len++] = cmd_str[i];
continue;
} else {
break;
}
}
if (isalnum(cmd_str[i]) || ispunct(cmd_str[i])) {
arg[arg_len++] = cmd_str[i];
} else if (isspace(cmd_str[i])) {
if (arg_len)
av[av_count++] = strdup(arg);
memset(arg, 0, sizeof(arg));
arg_len = 0;
} else {
break;
}
}
if ((av_count < MAX_AV_COUNT) && arg_len) {
av[av_count++] = strdup(arg);
}
execvp(av[0], av);
}
static int send_result(struct helper_msg *msg, int fd)
{
int rv;
rv = write(fd, msg, sizeof(struct helper_msg));
if (rv == sizeof(struct helper_msg))
return 0;
return -1;
}
#define IDLE_TIMEOUT_MS (30 * 1000)
#define ACTIVE_TIMEOUT_MS 500
__attribute__((noreturn)) void helper_main(int in_fd, int out_fd, int log_stderr)
{
struct pollfd pollfd;
struct helper_msg msg;
struct helper_msg_list *ml;
siginfo_t info;
unsigned int fork_count = 0;
unsigned int done_count = 0;
int timeout = IDLE_TIMEOUT_MS;
int rv, pid;
INIT_LIST_HEAD(&commands);
_log_stderr = log_stderr;
rv = setgroups(0, NULL);
if (rv < 0)
log_helper("error clearing helper groups errno %i", errno);
memset(&pollfd, 0, sizeof(pollfd));
pollfd.fd = in_fd;
pollfd.events = POLLIN;
openlog("lvmlockd-helper", LOG_CONS | LOG_PID, LOG_LOCAL4);
while (1) {
rv = poll(&pollfd, 1, timeout);
if (rv == -1 && errno == EINTR)
continue;
if (rv < 0)
exit(0);
if (pollfd.revents & POLLIN) {
memset(&msg, 0, sizeof(msg));
rv = read_msg(in_fd, &msg);
if (rv)
continue;
if (msg.type == HELPER_COMMAND) {
pid = fork();
if (!pid) {
exec_command(msg.command);
exit(1);
}
msg.pid = pid;
_save_command(&msg);
fork_count++;
}
}
if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL))
exit(0);
/* collect child exits until no more children exist (ECHILD)
or none are ready (WNOHANG) */
while (1) {
memset(&info, 0, sizeof(info));
rv = waitid(P_ALL, 0, &info, WEXITED | WNOHANG);
if ((rv < 0) && (errno == ECHILD)) {
/*
log_helper("helper no children exist fork_count %d done_count %d", fork_count, done_count);
*/
timeout = IDLE_TIMEOUT_MS;
}
else if (!rv && !info.si_pid) {
log_helper("helper no children ready fork_count %d done_count %d", fork_count, done_count);
timeout = ACTIVE_TIMEOUT_MS;
}
else if (!rv && info.si_pid) {
done_count++;
if (!(ml = _get_command(info.si_pid))) {
log_helper("command for pid %d result %d not found",
info.si_pid, info.si_status);
continue;
}
log_helper("command for pid %d result %d done", info.si_pid, info.si_status);
ml->msg.type = HELPER_COMMAND_RESULT;
ml->msg.result = info.si_status;
send_result(&ml->msg, out_fd);
list_del(&ml->list);
free(ml);
continue;
}
else {
log_helper("helper waitid rv %d errno %d fork_count %d done_count %d",
rv, errno, fork_count, done_count);
}
break;
}
}
}

View File

@@ -556,9 +556,9 @@ int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
if (daemon_test) {
if (rdi->vb) {
vb_out->version = le16toh(rdi->vb->version);
vb_out->flags = le16toh(rdi->vb->flags);
vb_out->r_version = le32toh(rdi->vb->r_version);
vb_out->version = le16_to_cpu(rdi->vb->version);
vb_out->flags = le16_to_cpu(rdi->vb->flags);
vb_out->r_version = le32_to_cpu(rdi->vb->r_version);
}
return 0;
}

View File

@@ -62,11 +62,6 @@ enum {
LD_OP_BUSY,
LD_OP_QUERY_LOCK,
LD_OP_REFRESH_LV,
LD_OP_VG_STATUS,
LD_OP_FENCE,
LD_OP_FENCE_RESULT,
LD_OP_SETLOCKARGS_BEFORE,
LD_OP_SETLOCKARGS_FINAL,
};
/* resource types */
@@ -122,9 +117,6 @@ struct client {
#define LD_AF_SH_EXISTS 0x00100000
#define LD_AF_ADOPT_ONLY 0x00200000 /* adopt orphan or fail */
#define LD_AF_NODELAY 0x00400000
#define LD_AF_REPAIR 0x00800000
#define LD_AF_NO_TIMEOUT 0x01000000
#define LD_AF_HOSTS_UNKNOWN 0x02000000
/*
* Number of times to repeat a lock request after
@@ -138,54 +130,13 @@ struct pvs {
int num;
};
#define RUN_COMMAND_LEN 1024
#define MAX_AV_COUNT 32
#define ONE_ARG_LEN 256
/* helper_msg types */
#define HELPER_COMMAND 0x1
#define HELPER_COMMAND_RESULT 0x2
struct helper_msg {
uint8_t type;
uint8_t act;
uint16_t unused1;
uint32_t msg_id;
int pid;
int result;
char ls_name[MAX_NAME+1];
uint8_t unused2;
uint16_t unused3;
char command[RUN_COMMAND_LEN];
};
struct helper_msg_list {
struct helper_msg msg;
struct list_head list;
};
#define OWNER_NAME_SIZE 64
#define OWNER_STATE_SIZE 32
struct owner {
uint32_t host_id;
uint32_t generation;
uint32_t timestamp;
char state[OWNER_STATE_SIZE];
char name[OWNER_NAME_SIZE];
};
struct action {
struct list_head list;
uint32_t client_id;
uint32_t flags; /* LD_AF_ */
uint32_t msg_id;
uint32_t version;
uint32_t host_id;
uint64_t ourkey;
uint64_t remkey;
uint64_t host_id;
uint64_t lv_size_bytes;
uint64_t ls_generation;
int8_t op; /* operation type LD_OP_ */
int8_t rt; /* resource type LD_RT_ */
int8_t mode; /* lock mode LD_LK_ */
@@ -202,8 +153,7 @@ struct action {
char lv_uuid[MAX_NAME+1];
char vg_args[MAX_ARGS+1];
char lv_args[MAX_ARGS+1];
char other_args[MAX_ARGS+1];
struct owner owner;
char prev_lv_args[MAX_ARGS+1];
struct pvs pvs; /* PV list for idm */
};
@@ -223,7 +173,6 @@ struct resource {
unsigned int use_vb : 1;
struct list_head locks;
struct list_head actions;
struct list_head fence_wait_actions;
char lv_args[MAX_ARGS+1];
char lm_data[]; /* lock manager specific data */
};
@@ -246,9 +195,7 @@ struct lockspace {
char vg_args[MAX_ARGS+1]; /* lock manager specific args */
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
void *lm_data;
uint32_t lock_args_flags;
uint32_t host_id;
uint64_t generation;
uint64_t host_id;
uint64_t free_lock_offset; /* for sanlock, start search for free lock here */
struct pvs pvs; /* for idm: PV list */
@@ -263,14 +210,13 @@ struct lockspace {
unsigned int thread_done : 1;
unsigned int sanlock_gl_enabled: 1;
unsigned int sanlock_gl_dup: 1;
unsigned int free_vg: 1;
unsigned int kill_vg: 1;
unsigned int fence_pr: 1;
unsigned int no_timeout: 1;
unsigned int drop_vg: 1;
struct list_head actions; /* new client actions */
struct list_head resources; /* resource/lock state for gl/vg/lv */
struct list_head dispose; /* resources to free */
struct list_head fence_history; /* internally created actions for fencing */
};
/* val_blk version */
@@ -429,9 +375,7 @@ void log_level(int level, const char *fmt, ...) __attribute__((format(printf, 2
struct lockspace *alloc_lockspace(void);
int lockspaces_empty(void);
int last_string_from_args(char *args_in, char *last);
void helper_main(int in_fd, int out_fd, int log_stderr);
int lockd_lockargs_get_user_flags(const char *str, uint32_t *flags);
int lockd_lockargs_get_version(char *str, unsigned int *major, unsigned int *minor, unsigned int *patch);
int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsigned int *patch);
static inline const char *mode_str(int x)
{
@@ -600,34 +544,30 @@ static inline int lm_refresh_lv_check_dlm(struct action *act)
#ifdef LOCKDSANLOCK_SUPPORT
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb, char *other_args);
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb);
int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args);
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation, int repair);
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok, int nodelay);
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r);
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int *retry, struct owner *owner,
int adopt_only, int adopt_ok, int repair);
struct val_blk *vb_out, int *retry,
int adopt_only, int adopt_ok);
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version);
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
uint32_t r_version, uint32_t lmu_flags);
int lm_able_gl_sanlock(struct lockspace *ls, int enable);
int lm_ex_disable_gl_sanlock(struct lockspace *ls);
int lm_hosts_sanlock(struct lockspace *ls, int notify, int *hosts_unknown);
int lm_hosts_sanlock(struct lockspace *ls, int notify);
int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r);
int lm_gl_is_enabled(struct lockspace *ls);
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
int lm_data_size_sanlock(void);
int lm_is_running_sanlock(void);
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes);
int lm_vg_status_sanlock(struct lockspace *ls, struct action *act);
void lm_set_host_dead_sanlock(struct lockspace *ls, struct owner *owner);
int lm_setlockargs_supported_sanlock(struct lockspace *ls, struct action *act);
int lm_setlockargs_vg_sanlock(char *ls_name, char *vg_name, struct action *act);
static inline int lm_support_sanlock(void)
{
@@ -636,7 +576,7 @@ static inline int lm_support_sanlock(void)
#else
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb, char *other_args)
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb)
{
return -1;
}
@@ -656,7 +596,7 @@ static inline int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t fl
return -1;
}
static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation, int repair)
static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls)
{
return -1;
}
@@ -677,8 +617,8 @@ static inline int lm_add_resource_sanlock(struct lockspace *ls, struct resource
}
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int *retry, struct owner *owner,
int adopt_only, int adopt_ok, int repair)
struct val_blk *vb_out, int *retry,
int adopt_only, int adopt_ok)
{
return -1;
}
@@ -705,7 +645,7 @@ static inline int lm_ex_disable_gl_sanlock(struct lockspace *ls)
return -1;
}
static inline int lm_hosts_sanlock(struct lockspace *ls, int notify, int *hosts_unknown)
static inline int lm_hosts_sanlock(struct lockspace *ls, int notify)
{
return -1;
}
@@ -740,30 +680,11 @@ static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_si
return -1;
}
static inline int lm_vg_status_sanlock(struct lockspace *ls, struct action *act)
{
return -1;
}
static inline int lm_support_sanlock(void)
{
return 0;
}
static inline void lm_set_host_dead_sanlock(struct lockspace *ls, struct owner *owner)
{
}
static inline int lm_setlockargs_supported_sanlock(struct lockspace *ls, struct action *act)
{
return 0;
}
static inline int lm_setlockargs_vg_sanlock(char *ls_name, char *vg_name, struct action *act)
{
return -1;
}
#endif /* sanlock support */
#ifdef LOCKDIDM_SUPPORT

File diff suppressed because it is too large Load Diff

View File

@@ -46,7 +46,7 @@ static char *_construct_lvm_system_dir_env(const char *sysdir)
* - or -
* just single char to store NULL byte
*/
size_t l = sysdir ? strlen(sysdir) + sizeof(LVM_SYSTEM_DIR): 1;
size_t l = sysdir ? strlen(sysdir) + 16 : 1;
char *env = (char *) malloc(l * sizeof(char));
if (!env)
@@ -89,17 +89,6 @@ char *construct_id(const char *sysdir, const char *uuid)
return id;
}
static void _free_lvmpolld_lv(struct lvmpolld_lv *p)
{
free((void *)p->devicesfile);
free((void *)p->lvm_system_dir_env);
free((void *)p->lvmpolld_id);
free((void *)p->lvname);
free((void *)p->sinterval);
free((void *)p->cmdargv);
free((void *)p->cmdenvp);
}
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
const char *vgname, const char *lvname,
const char *sysdir, enum poll_type type,
@@ -107,26 +96,30 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
struct lvmpolld_store *pdst,
const char *devicesfile)
{
char *lvmpolld_id = strdup(id), /* copy */
*full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
*lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
char *devicesfile_dup = devicesfile ? strdup(devicesfile) : NULL;
struct lvmpolld_lv tmp = {
.ls = ls,
.type = type,
.lvmpolld_id = strdup(id),
.lvname = _construct_full_lvname(vgname, lvname),
.devicesfile = devicesfile ? strdup(devicesfile) : NULL,
.lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir),
.sinterval = strdup(sinterval),
.lvmpolld_id = lvmpolld_id,
.lvid = _get_lvid(lvmpolld_id, sysdir),
.lvname = full_lvname,
.devicesfile = devicesfile_dup,
.lvm_system_dir_env = lvm_system_dir_env,
.sinterval = strdup(sinterval), /* copy */
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
.cmd_state = { .retcode = -1, .signal = 0 },
.pdst = pdst,
.init_rq_count = 1
}, *pdlv = (struct lvmpolld_lv *) malloc(sizeof(struct lvmpolld_lv));
if (!pdlv || !tmp.lvmpolld_id || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
if (!pdlv || !tmp.lvid || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
goto err;
tmp.lvid = _get_lvid(tmp.lvmpolld_id, sysdir),
*pdlv = tmp;
memcpy(pdlv, &tmp, sizeof(*pdlv));
if (pthread_mutex_init(&pdlv->lock, NULL))
goto err;
@@ -134,20 +127,29 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
return pdlv;
err:
_free_lvmpolld_lv(&tmp);
free(pdlv);
free((void *)devicesfile_dup);
free((void *)full_lvname);
free((void *)lvmpolld_id);
free((void *)lvm_system_dir_env);
free((void *)tmp.sinterval);
free((void *)pdlv);
return NULL;
}
void pdlv_destroy(struct lvmpolld_lv *pdlv)
{
_free_lvmpolld_lv(pdlv);
free((void *)pdlv->lvmpolld_id);
free((void *)pdlv->devicesfile);
free((void *)pdlv->lvname);
free((void *)pdlv->sinterval);
free((void *)pdlv->lvm_system_dir_env);
free((void *)pdlv->cmdargv);
free((void *)pdlv->cmdenvp);
pthread_mutex_destroy(&pdlv->lock);
free(pdlv);
free((void *)pdlv);
}
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)
@@ -307,16 +309,10 @@ void pdst_locked_send_cancel(const struct lvmpolld_store *pdst)
struct lvmpolld_lv *pdlv;
struct dm_hash_node *n;
/* Signal child processes and cancel monitoring threads */
dm_hash_iterate(n, pdst->store) {
pdlv = dm_hash_get_data(pdst->store, n);
if (!pdlv_locked_polling_finished(pdlv)) {
/* Signal child lvpoll process to terminate */
if (pdlv->cmd_pid > 0)
kill(pdlv->cmd_pid, SIGTERM);
/* Cancel monitoring thread (which will reap the child) */
if (!pdlv_locked_polling_finished(pdlv))
pthread_cancel(pdlv->tid);
}
}
}

View File

@@ -25,7 +25,6 @@ DEVICE_MAPPER_SOURCE=\
device_mapper/libdm-targets.c \
device_mapper/libdm-timestamp.c \
device_mapper/mm/pool.c \
device_mapper/raid/raid_parser.c \
device_mapper/regex/matcher.c \
device_mapper/regex/parse_rx.c \
device_mapper/regex/ttree.c \

View File

@@ -19,7 +19,6 @@
#include "base/data-struct/list.h"
#include "base/data-struct/hash.h"
#include "raid/target.h"
#include "vdo/target.h"
#include <inttypes.h>

View File

@@ -770,7 +770,7 @@ static size_t _align_val(size_t val)
}
static void *_align_ptr(void *ptr)
{
return (void *)(uintptr_t)_align_val((size_t)ptr);
return (void *)_align_val((size_t)ptr);
}
static int _check_has_event_nr(void) {

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
@@ -668,7 +668,7 @@ static int _dm_task_set_name_from_path(struct dm_task *dmt, const char *path,
int dm_task_set_name(struct dm_task *dmt, const char *name)
{
const char *pos;
char *pos;
/* Path supplied for existing device? */
if ((pos = strrchr(name, '/')))
@@ -1044,19 +1044,12 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
{
char path[PATH_MAX];
struct stat info;
struct stat linfo;
dev_t dev = MKDEV(major, minor);
mode_t old_mask;
if (!_build_dev_path(path, sizeof(path), dev_name))
return_0;
/*
* Check if the device node already exists.
* Note: stat() follows symlinks, so this checks the target device,
* not the symlink itself. This works correctly for both real nodes
* and symlinks pointing to the right device.
*/
if (stat(path, &info) >= 0) {
if (!S_ISBLK(info.st_mode)) {
log_error("A non-block device file at '%s' "
@@ -1065,71 +1058,16 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
}
/* If right inode already exists we don't touch uid etc. */
if (info.st_rdev == dev) {
/*
* Correct device exists (either as real node or symlink).
* Use lstat() to distinguish between them for logging.
*/
if (lstat(path, &linfo) >= 0 && S_ISLNK(linfo.st_mode))
log_debug_activation("Symlink %s to correct device already exists", path);
if (info.st_rdev == dev)
return 1;
}
if (unlink(path) && (errno != ENOENT)) {
log_sys_error("unlink", path);
return 0;
}
} else {
/*
* stat() failed. Check for dangling symlinks (where lstat succeeds
* but stat fails with ENOENT because the symlink target doesn't exist).
* Remove the dangling symlink before attempting to create a new node.
*/
if (errno == ENOENT && lstat(path, &linfo) >= 0 && S_ISLNK(linfo.st_mode)) {
log_debug_activation("Removing dangling symlink %s", path);
if (unlink(path) && (errno != ENOENT)) {
log_sys_error("unlink", path);
return 0;
}
}
if (_warn_if_op_needed(warn_if_udev_failed))
log_warn("%s not set up by udev: Falling back to direct "
"node creation.", path);
}
/*
* Test environment optimization: If using alternative dev dir (e.g., /tmp/LVMTEST/dev)
* and the real /dev node already exists, create a symlink instead of a duplicate node.
* This ensures operations trigger udev events which only monitors /dev.
*/
if (strcmp(_dm_dir, DEV_DIR) != 0) {
char real_path[PATH_MAX];
struct stat real_stat;
/* Build path to real /dev node (kernel always creates /dev/dm-N) */
if (dm_snprintf(real_path, sizeof(real_path), DEV_DIR "dm-%u", minor) >= 0) {
/* Check if real node exists with matching dev */
if (stat(real_path, &real_stat) >= 0 &&
S_ISBLK(real_stat.st_mode) &&
real_stat.st_rdev == dev) {
/*
* Real /dev/dm-N exists. Create symlink from alternative location.
* This allows operations to work through the symlink and trigger
* udev events on the real device.
*/
log_debug_activation("Creating symlink %s -> %s", path, real_path);
(void) dm_prepare_selinux_context(path, S_IFLNK);
if (symlink(real_path, path) < 0) {
log_sys_error("symlink", path);
(void) dm_prepare_selinux_context(NULL, 0);
return 0;
}
(void) dm_prepare_selinux_context(NULL, 0);
log_debug_activation("Created symlink %s -> %s", path, real_path);
return 1;
}
}
}
} else if (_warn_if_op_needed(warn_if_udev_failed))
log_warn("%s not set up by udev: Falling back to direct "
"node creation.", path);
(void) dm_prepare_selinux_context(path, S_IFBLK);
old_mask = umask(0);
@@ -1813,7 +1751,7 @@ static int _mountinfo_parse_line(const char *line, unsigned *maj, unsigned *min,
{
char root[PATH_MAX + 1]; /* sscanf needs extra '\0' */
char target[PATH_MAX + 1];
const char *devmapper;
char *devmapper;
struct dm_task *dmt;
struct dm_info info;
unsigned i;
@@ -1894,27 +1832,32 @@ int dm_mountinfo_read(dm_mountinfo_line_callback_fn read_fn, void *cb_data)
static int _sysfs_get_dm_name(uint32_t major, uint32_t minor, char *buf, size_t buf_size)
{
char sysfs_path[PATH_MAX], temp_buf[2 * DM_NAME_LEN];
char *sysfs_path, *temp_buf = NULL;
FILE *fp = NULL;
int r = 0;
size_t len;
if (dm_snprintf(sysfs_path, sizeof(sysfs_path),
"%sdev/block/%" PRIu32 ":%" PRIu32
if (!(sysfs_path = malloc(PATH_MAX)) ||
!(temp_buf = malloc(PATH_MAX))) {
log_error("_sysfs_get_dm_name: failed to allocate temporary buffers");
goto bad;
}
if (dm_snprintf(sysfs_path, PATH_MAX, "%sdev/block/%" PRIu32 ":%" PRIu32
"/dm/name", _sysfs_dir, major, minor) < 0) {
log_error("_sysfs_get_dm_name: dm_snprintf failed.");
log_error("_sysfs_get_dm_name: dm_snprintf failed");
goto bad;
}
if (!(fp = fopen(sysfs_path, "r"))) {
if (errno == ENOENT)
log_sys_debug("fopen", sysfs_path);
else
if (errno != ENOENT)
log_sys_error("fopen", sysfs_path);
else
log_sys_debug("fopen", sysfs_path);
goto bad;
}
if (!fgets(temp_buf, sizeof(temp_buf), fp)) {
if (!fgets(temp_buf, PATH_MAX, fp)) {
log_sys_error("fgets", sysfs_path);
goto bad;
}
@@ -1922,21 +1865,20 @@ static int _sysfs_get_dm_name(uint32_t major, uint32_t minor, char *buf, size_t
len = strlen(temp_buf);
if (len > buf_size) {
log_error("_sysfs_get_dm_name: supplied buffer too small.");
log_error("_sysfs_get_dm_name: supplied buffer too small");
goto bad;
}
if (len)
--len; /* strip \n */
memcpy(buf, temp_buf, len);
buf[len] = '\0';
temp_buf[len ? len - 1 : 0] = '\0'; /* \n */
strcpy(buf, temp_buf);
r = 1;
bad:
if (fp && fclose(fp))
log_sys_error("fclose", sysfs_path);
free(temp_buf);
free(sysfs_path);
return r;
}

View File

@@ -1069,6 +1069,9 @@ static const char *_find_config_str(const void *start, node_lookup_fn find_fn,
log_warn("WARNING: Ignoring unsupported value for %s.", path);
}
if (fail)
log_very_verbose("%s not found in config: defaulting to \"%s\"",
path, fail);
return fail;
}
@@ -1094,6 +1097,8 @@ static int64_t _find_config_int64(const void *start, node_lookup_fn find,
return n->v->v.i;
}
log_very_verbose("%s not found in config: defaulting to %" PRId64,
path, fail);
return fail;
}
@@ -1107,6 +1112,9 @@ static float _find_config_float(const void *start, node_lookup_fn find,
return n->v->v.f;
}
log_very_verbose("%s not found in config: defaulting to %f",
path, fail);
return fail;
}
@@ -1161,6 +1169,9 @@ static int _find_config_bool(const void *start, node_lookup_fn find,
}
}
log_very_verbose("%s not found in config: defaulting to %d",
path, fail);
return fail;
}

View File

@@ -19,6 +19,7 @@
#include "misc/dm-ioctl.h"
#include "vdo/target.h"
#include <stdarg.h>
#include <string.h>
#include <sys/utsname.h>
@@ -3362,26 +3363,9 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
/* Preload children first */
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
/* When a parent node (other than root) is inactive, we cannot delay
* the resume of a new device.
* For example, preloading a RAID table with a pvmoved leg requires the
* leg LV to be active before loading the RAID LV, so the pvmove device must
* be resumed immediately.
* This scenario only occurs when neither the RAID nor pvmove device has
* been instantiated yet. In this case, starting the pvmove device does
* not leak access to the PV device without going through the mirror target.
* However, if the RAID is already active and running, we can only preload
* the new pvmove device, and a full suspend must occur before resuming
* the new table with the running pvmove. So until the resume point
* any IO is going through the existing table line and not via pvmove target.
*/
if ((child->props.delay_resume_if_new > 1) &&
!dnode->info.exists &&
(dnode != &dnode->dtree->root)) { /* Ignore when parent is root node */
log_debug("%s with inactive parent cancels delay_resume_if_new.",
_node_name(child));
child->props.delay_resume_if_new = 0;
}
/* Propagate delay of resume from parent node */
if (dnode->props.delay_resume_if_new > 1)
child->props.delay_resume_if_new = dnode->props.delay_resume_if_new;
/* Skip existing non-device-mapper devices */
if (!child->info.exists && child->info.major)

View File

@@ -17,7 +17,6 @@
#include "base/memory/zalloc.h"
#include <ctype.h>
#include <langinfo.h>
#include <math.h> /* fabs() */
#include <float.h> /* DBL_EPSILON */
#include <time.h>
@@ -32,7 +31,6 @@
struct selection {
struct dm_pool *mem;
struct dm_pool *regex_mem;
struct selection_node *selection_root;
int add_new_fields;
};
@@ -206,9 +204,7 @@ static const struct op_def _op_log[] = {
struct selection_str_list {
struct dm_str_list str_list;
struct dm_regex *regex;
size_t regex_num_patterns;
unsigned type; /* either SEL_LIST_LS or SEL_LIST_SUBSET_LS with either SEL_AND or SEL_OR */
unsigned type; /* either SEL_AND or SEL_OR */
};
struct field_selection_value {
@@ -1416,11 +1412,8 @@ struct dm_report *dm_report_init(uint32_t *report_types,
void dm_report_free(struct dm_report *rh)
{
if (rh->selection) {
if (rh->selection)
dm_pool_destroy(rh->selection->mem);
if (rh->selection->regex_mem)
dm_pool_destroy(rh->selection->regex_mem);
}
if (rh->value_cache)
dm_hash_destroy(rh->value_cache);
dm_pool_destroy(rh->mem);
@@ -1759,74 +1752,8 @@ static int _cmp_field_time(struct dm_report *rh,
return 0;
}
static int _str_list_item_match_regex(const struct str_list_sort_value *val, unsigned int i, struct dm_regex *regex)
{
struct pos_len *item = val->items + i;
char *s = (char *) (val->value + item->pos);
char c = s[item->len];
int r;
/*
* The val->items contains the whole string list in the form of a single string,
* where each item is delimited by a delimiter.
*
* The item->pos + item->len pair then points to the exact item within the val->items.
*
* The dm_regex_match accepts a string, not the pos + len pair, so we need to adapt here:
* replace the delimiter with '\0' temporarily so the item is a proper string.
*/
s[item->len] = '\0';
r = dm_regex_match(regex, s);
s[item->len] = c;
return r;
}
static size_t _bitset_count_set(dm_bitset_t bs)
{
size_t i, size = bs[0]/DM_BITS_PER_INT + 1;
size_t count = 0;
for (i = 1; i <= size; i++)
count += hweight32(bs[i]);
return count;
}
/* Matches if all items from selection string list match list value strictly 1:1. */
static int _cmp_field_string_list_strict_regex_all(const struct dm_report *rh,
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
unsigned int i;
dm_bitset_t bs;
int r;
if (!val->items)
return (sel->regex_num_patterns == 1) && dm_regex_match(sel->regex, "") >= 0;
if (!(bs = dm_bitset_create(rh->selection->mem, sel->regex_num_patterns))) {
log_error("Failed to create bitset for regex match counter.");
return 0;
}
for (i = 1; i <= val->items[0].pos; i++) {
if ((r = _str_list_item_match_regex(val, i, sel->regex)) < 0) {
r = 0;
goto out;
}
dm_bit_set(bs, r);
}
r = _bitset_count_set(bs) == sel->regex_num_patterns;
out:
dm_pool_free(rh->selection->mem, bs);
return r;
}
/* Matches if all items from selection string list match list value strictly 1:1. */
static int _cmp_field_string_list_strict_all(const struct dm_report *rh,
const struct str_list_sort_value *val,
static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
unsigned int sel_list_size = dm_list_size(&sel->str_list.list);
@@ -1858,36 +1785,7 @@ static int _cmp_field_string_list_strict_all(const struct dm_report *rh,
}
/* Matches if all items from selection string list match a subset of list value. */
static int _cmp_field_string_list_subset_regex_all(const struct dm_report *rh,
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
dm_bitset_t bs;
unsigned int i;
int r;
if (!val->items)
return (sel->regex_num_patterns == 1) && dm_regex_match(sel->regex, "") >= 0;
if (!(bs = dm_bitset_create(rh->selection->mem, sel->regex_num_patterns))) {
log_error("Failed to create bitset for regex match counter.");
return 0;
}
for (i = 1; i <= val->items[0].pos; i++) {
if ((r = _str_list_item_match_regex(val, i, sel->regex)) < 0)
continue;
dm_bit_set(bs, r);
}
r = _bitset_count_set(bs) == sel->regex_num_patterns;
dm_pool_free(rh->selection->mem, bs);
return r;
}
/* Matches if all items from selection string list match a subset of list value. */
static int _cmp_field_string_list_subset_all(const struct dm_report *rh __attribute__((unused)),
const struct str_list_sort_value *val,
static int _cmp_field_string_list_subset_all(const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
unsigned int sel_list_size = dm_list_size(&sel->str_list.list);
@@ -1922,26 +1820,8 @@ static int _cmp_field_string_list_subset_all(const struct dm_report *rh __attrib
}
/* Matches if any item from selection string list matches list value. */
static int _cmp_field_string_list_subset_regex_any(const struct dm_report *rh __attribute__((unused)),
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
unsigned int i;
if (!val->items)
return dm_regex_match(sel->regex, "") >= 0;
for (i = 1; i <= val->items[0].pos; i++) {
if (_str_list_item_match_regex(val, i, sel->regex) >= 0)
return 1;
}
return 0;
}
/* Matches if any item from selection string list matches list value. */
static int _cmp_field_string_list_subset_any(const struct dm_report *rh __attribute__((unused)),
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
struct dm_str_list *sel_item;
unsigned int i;
@@ -1970,59 +1850,7 @@ static int _cmp_field_string_list_subset_any(const struct dm_report *rh __attrib
return 0;
}
/* Matches if all items from list value can be matched by any item from selection list. */
static int _cmp_field_string_list_strict_regex_any(const struct dm_report *rh __attribute__((unused)),
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
unsigned int i;
if (!val->items)
return dm_regex_match(sel->regex, "") >= 0;
for (i = 1; i <= val->items[0].pos; i++) {
if (_str_list_item_match_regex(val, i, sel->regex) < 0)
return 0;
}
return 1;
}
/* Matches if all items from list value can be matched by any item from selection list. */
static int _cmp_field_string_list_strict_any(const struct dm_report *rh __attribute__((unused)),
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
struct dm_str_list *sel_item;
unsigned int i;
int match;
/* match blank string list with selection that contains blank string */
if (!val->items) {
dm_list_iterate_items(sel_item, &sel->str_list.list) {
if (!strcmp(sel_item->str, ""))
return 1;
}
return 0;
}
for (i = 1; i <= val->items[0].pos; i++) {
match = 0;
dm_list_iterate_items(sel_item, &sel->str_list.list) {
if ((strlen(sel_item->str) == val->items[i].len) &&
!strncmp(sel_item->str, val->value + val->items[i].pos, val->items[i].len)) {
match = 1;
break;
}
}
if (!match)
return 0;
}
return 1;
}
static int _cmp_field_string_list(struct dm_report *rh,
static int _cmp_field_string_list(struct dm_report *rh __attribute__((unused)),
uint32_t field_num, const char *field_id,
const struct str_list_sort_value *val,
struct field_selection *fs)
@@ -2044,16 +1872,11 @@ static int _cmp_field_string_list(struct dm_report *rh,
switch (sel->type & SEL_MASK) {
case SEL_AND:
r = subset ? sel->regex ? _cmp_field_string_list_subset_regex_all(rh, val, sel)
: _cmp_field_string_list_subset_all(rh, val, sel)
: sel->regex ? _cmp_field_string_list_strict_regex_all(rh, val, sel)
: _cmp_field_string_list_strict_all(rh, val, sel);
r = subset ? _cmp_field_string_list_subset_all(val, sel)
: _cmp_field_string_list_strict_all(val, sel);
break;
case SEL_OR:
r = subset ? sel->regex ? _cmp_field_string_list_subset_regex_any(rh, val, sel)
: _cmp_field_string_list_subset_any(rh, val, sel)
: sel->regex ? _cmp_field_string_list_strict_regex_any(rh, val, sel)
: _cmp_field_string_list_strict_any(rh, val, sel);
r = _cmp_field_string_list_any(val, sel);
break;
default:
log_error(INTERNAL_ERROR "_cmp_field_string_list: unsupported string "
@@ -2087,17 +1910,7 @@ static int _compare_selection_field(struct dm_report *rh,
}
if (fs->flags & FLD_CMP_REGEX)
switch (f->props->flags & DM_REPORT_FIELD_TYPE_MASK) {
case DM_REPORT_FIELD_TYPE_STRING:
r = _cmp_field_regex((const char *) f->sort_value, fs);
break;
case DM_REPORT_FIELD_TYPE_STRING_LIST:
r = _cmp_field_string_list(rh, f->props->field_num, field_id, (const struct str_list_sort_value *) f->sort_value, fs);
break;
default:
log_error(INTERNAL_ERROR "_compare_selection_field: regex: incorrect type %" PRIu32 " for field %s",
f->props->flags & DM_REPORT_FIELD_TYPE_MASK, field_id);
}
r = _cmp_field_regex((const char *) f->sort_value, fs);
else {
switch(f->props->flags & DM_REPORT_FIELD_TYPE_MASK) {
case DM_REPORT_FIELD_TYPE_PERCENT:
@@ -2124,8 +1937,7 @@ static int _compare_selection_field(struct dm_report *rh,
r = _cmp_field_time(rh, f->props->field_num, field_id, *(const time_t *) f->sort_value, fs);
break;
default:
log_error(INTERNAL_ERROR "_compare_selection_field: incorrect type %" PRIu32 " for field %s",
f->props->flags & DM_REPORT_FIELD_TYPE_MASK, field_id);
log_error(INTERNAL_ERROR "_compare_selection_field: unknown field type for field %s", field_id);
}
}
@@ -2817,9 +2629,11 @@ static int _check_reserved_values_supported(const struct dm_report_field_type fi
static const char *_tok_value_regex(struct dm_report *rh,
const struct dm_report_field_type *ft,
const char *s, const char **begin,
const char **end, uint32_t *flags)
const char **end, uint32_t *flags,
struct reserved_value_wrapper *rvw)
{
char c;
rvw->reserved = NULL;
s = _skip_space(s);
@@ -2882,8 +2696,7 @@ static int _add_item_to_string_list(struct dm_pool *mem, const char *begin,
static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
struct dm_pool *mem, const char *s,
const char **begin, const char **end,
struct selection_str_list **sel_str_list,
uint32_t *flags)
struct selection_str_list **sel_str_list)
{
static const char _str_list_item_parsing_failed[] = "Failed to parse string list value "
"for selection field %s.";
@@ -2897,11 +2710,12 @@ static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
int list_end = 0;
char c;
if (!(ssl = dm_pool_zalloc(mem, sizeof(*ssl)))) {
log_error("_tok_value_string_list: memory allocation failed for selection list.");
if (!(ssl = dm_pool_alloc(mem, sizeof(*ssl)))) {
log_error("_tok_value_string_list: memory allocation failed for selection list");
goto bad;
}
dm_list_init(&ssl->str_list.list);
ssl->type = 0;
*begin = s;
if (!(op_flags = _tok_op_log(s, &tmp, SEL_LIST_LS | SEL_LIST_SUBSET_LS))) {
@@ -2913,7 +2727,7 @@ static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
}
if (!_add_item_to_string_list(mem, begin_item, end_item, &ssl->str_list.list))
goto_bad;
ssl->type = SEL_OR | SEL_LIST_SUBSET_LS;
ssl->type = SEL_OR | SEL_LIST_LS;
goto out;
}
@@ -2988,17 +2802,12 @@ static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
else
ssl->type |= SEL_LIST_SUBSET_LS;
/* Sort the list. */
if (!(list_size = dm_list_size(&ssl->str_list.list))) {
log_error(INTERNAL_ERROR "_tok_value_string_list: list has no items");
goto bad;
} else if (list_size == 1)
goto out;
if (*flags & FLD_CMP_REGEX)
/* No need to sort the list for regex. */
goto out;
/* Sort the list. */
if (!(arr = malloc(sizeof(item) * list_size))) {
log_error("_tok_value_string_list: memory allocation failed for sort array");
goto bad;
@@ -3327,9 +3136,7 @@ static int _local_tz_offset(time_t t_local)
time_t t_gmt;
gmtime_r(&t_local, &tm_gmt);
if ((t_gmt = mktime(&tm_gmt)) < 0)
return 0;
t_gmt = mktime(&tm_gmt);
/*
* gmtime returns time that is adjusted
@@ -3340,7 +3147,7 @@ static int _local_tz_offset(time_t t_local)
if (tm_gmt.tm_isdst)
t_gmt -= 3600;
return (int)(t_local - t_gmt);
return t_local - t_gmt;
}
static void _get_final_time(time_range_t range, struct tm *tm,
@@ -3516,10 +3323,7 @@ static const char *_tok_value(struct dm_report *rh,
s = _skip_space(s);
/* recognize possible reserved value (but not in a regex) */
if (!(*flags & FLD_CMP_REGEX))
s = _get_reserved(rh, expected_type, field_num, implicit, s, begin, end, rvw);
s = _get_reserved(rh, expected_type, field_num, implicit, s, begin, end, rvw);
if (rvw->reserved) {
/*
* FLD_CMP_NUMBER shares operators with FLD_CMP_TIME,
@@ -3530,24 +3334,17 @@ static const char *_tok_value(struct dm_report *rh,
else if (expected_type == DM_REPORT_FIELD_TYPE_NUMBER)
*flags &= ~FLD_CMP_TIME;
*flags |= expected_type;
/* if we matched a reserved value, skip further processing of this token */
return s;
}
switch (expected_type) {
case DM_REPORT_FIELD_TYPE_STRING:
if (*flags & FLD_CMP_REGEX) {
if (!(s = _tok_value_regex(rh, ft, s, begin, end, flags)))
return NULL;
} else {
c = _get_and_skip_quote_char(&s);
if (!(s = _tok_value_string(s, begin, end, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL))) {
log_error("Failed to parse string value "
"for selection field %s.", ft->id);
return NULL;
}
c = _get_and_skip_quote_char(&s);
if (!(s = _tok_value_string(s, begin, end, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL))) {
log_error("Failed to parse string value "
"for selection field %s.", ft->id);
return NULL;
}
*flags |= DM_REPORT_FIELD_TYPE_STRING;
break;
@@ -3556,7 +3353,7 @@ static const char *_tok_value(struct dm_report *rh,
if (!(str_list = (struct selection_str_list **) custom))
goto_bad;
s = _tok_value_string_list(ft, mem, s, begin, end, str_list, flags);
s = _tok_value_string_list(ft, mem, s, begin, end, str_list);
if (!(*str_list)) {
log_error("Failed to parse string list value "
"for selection field %s.", ft->id);
@@ -3640,7 +3437,7 @@ static const char *_tok_value(struct dm_report *rh,
return s;
bad:
log_error(INTERNAL_ERROR "_tok_value: Forbidden NULL custom parameter detected.");
log_error(INTERNAL_ERROR "Forbidden NULL custom detected.");
return NULL;
}
@@ -3711,19 +3508,6 @@ static int _get_reserved_value(struct dm_report *rh, uint32_t field_num,
return 1;
}
static struct dm_regex *_selection_regex_create(struct selection *selection, const char * const *patterns,
unsigned num_patterns)
{
if (!selection->regex_mem) {
if (!(selection->regex_mem = dm_pool_create("report selection regex", 32 * 1024))) {
log_error("Failed to create report selection regex memory pool.");
return NULL;
}
}
return dm_regex_create(selection->regex_mem, patterns, num_patterns);
}
static struct field_selection *_create_field_selection(struct dm_report *rh,
uint32_t field_num,
int implicit,
@@ -3741,11 +3525,7 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
struct time_value *tval;
uint64_t factor;
char *s;
const char *s_arr_single[2] = { 0 };
const char **s_arr;
size_t s_arr_size;
struct dm_str_list *sl;
size_t i;
const char *s_array[2] = { 0 };
dm_list_iterate_items(fp, &rh->field_props) {
if ((fp->implicit == implicit) && (fp->field_num == field_num)) {
@@ -3810,55 +3590,21 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
/* store comparison operand */
if (flags & FLD_CMP_REGEX) {
/* REGEX */
switch (flags & DM_REPORT_FIELD_TYPE_MASK) {
case DM_REPORT_FIELD_TYPE_STRING:
if (!(s = malloc(len + 1))) {
log_error("dm_report: malloc failed to store "
"regex value for selection field %s", field_id);
goto error;
}
memcpy(s, v, len);
s[len] = '\0';
s_arr_single[0] = s;
if (!(s = malloc(len + 1))) {
log_error("dm_report: malloc failed to store "
"regex value for selection field %s", field_id);
goto error;
}
memcpy(s, v, len);
s[len] = '\0';
s_array[0] = s;
fs->value->v.r = _selection_regex_create(rh->selection, s_arr_single, 1);
free(s);
if (!fs->value->v.r) {
log_error("dm_report: failed to create regex "
"matcher for selection field %s", field_id);
goto error;
}
break;
case DM_REPORT_FIELD_TYPE_STRING_LIST:
if (!custom)
goto bad;
fs->value->v.l = *((struct selection_str_list **) custom);
if (!(s_arr_size = dm_list_size(&fs->value->v.l->str_list.list)))
break;
if (!(s_arr = calloc(s_arr_size, sizeof(char *)))) {
log_error("dm_report: malloc failed for regex array "
"for selection field %s", field_id);
goto error;
}
i = 0;
dm_list_iterate_items(sl, &fs->value->v.l->str_list.list)
s_arr[i++] = sl->str;
fs->value->v.l->regex = _selection_regex_create(rh->selection, s_arr, s_arr_size);
fs->value->v.l->regex_num_patterns = s_arr_size;
free(s_arr);
if (!fs->value->v.l->regex) {
log_error("dm_report: failed to create regex "
"matcher for selection field %s", field_id);
goto error;
}
break;
default:
log_error(INTERNAL_ERROR "_create_field_selection: regex: incorrect type %" PRIu32 " for field %s",
flags & DM_REPORT_FIELD_TYPE_MASK, field_id);
goto error;
fs->value->v.r = dm_regex_create(rh->selection->mem, s_array, 1);
free(s);
if (!fs->value->v.r) {
log_error("dm_report: failed to create regex "
"matcher for selection field %s", field_id);
goto error;
}
} else {
/* STRING, NUMBER, SIZE, PERCENT, STRING_LIST, TIME */
@@ -3972,8 +3718,8 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
}
break;
default:
log_error(INTERNAL_ERROR "_create_field_selection: incorrect type %" PRIu32 " for field %s",
flags & DM_REPORT_FIELD_TYPE_MASK, field_id);
log_error(INTERNAL_ERROR "_create_field_selection: "
"unknown type of selection field %s", field_id);
goto error;
}
}
@@ -3984,7 +3730,7 @@ error_field_id:
field_id);
goto error;
bad:
log_error(INTERNAL_ERROR "_create_field_selection: Forbidden NULL custom detected.");
log_error(INTERNAL_ERROR "Forbidden NULL custom detected.");
error:
dm_pool_free(rh->selection->mem, fs);
@@ -4078,11 +3824,8 @@ out_reserved_values:
log_warn(" ");
}
static void _parse_syntax_error(const char *s)
{
log_error("Selection syntax error at '%s'.", s);
log_error("Use \'help\' for selection to get more help.");
}
static const char _sel_syntax_error_at_msg[] = "Selection syntax error at '%s'.";
static const char _sel_help_ref_msg[] = "Use \'help\' for selection to get more help.";
/*
* Selection parser
@@ -4123,7 +3866,7 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
char *tmp;
char c;
/* get field name */
/* field name */
if (!(last = _tok_field_name(s, &ws, &we))) {
log_error("Expecting field name");
goto bad;
@@ -4156,7 +3899,7 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
} else
ft = &rh->fields[field_num];
/* get comparison operator */
/* comparison operator */
if (!(flags = _tok_op_cmp(we, &last))) {
_display_selection_help(rh);
log_error("Unrecognised comparison operator: %s", we);
@@ -4168,49 +3911,50 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
goto bad;
}
/* check we can use the operator with the field */
/* comparison value */
if (flags & FLD_CMP_REGEX) {
if (!(ft->flags & (DM_REPORT_FIELD_TYPE_STRING |
DM_REPORT_FIELD_TYPE_STRING_LIST))) {
_display_selection_help(rh);
log_error("Operator can be used only with string or string list fields: %s", ws);
goto bad;
}
} else if (flags & FLD_CMP_NUMBER) {
if (!(ft->flags & (DM_REPORT_FIELD_TYPE_NUMBER |
DM_REPORT_FIELD_TYPE_SIZE |
DM_REPORT_FIELD_TYPE_PERCENT |
DM_REPORT_FIELD_TYPE_TIME))) {
_display_selection_help(rh);
log_error("Operator can be used only with number, size, time or percent fields: %s", ws);
goto bad;
}
} else if (flags & FLD_CMP_TIME) {
if (!(ft->flags & DM_REPORT_FIELD_TYPE_TIME)) {
_display_selection_help(rh);
log_error("Operator can be used only with time fields: %s", ws);
goto bad;
/*
* REGEX value
*/
if (!(last = _tok_value_regex(rh, ft, last, &vs, &ve, &flags, &rvw)))
goto_bad;
} else {
/*
* STRING, NUMBER, SIZE, PERCENT, STRING_LIST, TIME value
*/
if (flags & FLD_CMP_NUMBER) {
if (!(ft->flags & (DM_REPORT_FIELD_TYPE_NUMBER |
DM_REPORT_FIELD_TYPE_SIZE |
DM_REPORT_FIELD_TYPE_PERCENT |
DM_REPORT_FIELD_TYPE_TIME))) {
_display_selection_help(rh);
log_error("Operator can be used only with number, size, time or percent fields: %s", ws);
goto bad;
}
} else if (flags & FLD_CMP_TIME) {
if (!(ft->flags & DM_REPORT_FIELD_TYPE_TIME)) {
_display_selection_help(rh);
log_error("Operator can be used only with time fields: %s", ws);
goto bad;
}
}
if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE ||
ft->flags == DM_REPORT_FIELD_TYPE_NUMBER ||
ft->flags == DM_REPORT_FIELD_TYPE_PERCENT)
custom = &factor;
else if (ft->flags & DM_REPORT_FIELD_TYPE_TIME)
custom = &tval;
else if (ft->flags == DM_REPORT_FIELD_TYPE_STRING_LIST)
custom = &str_list;
else
custom = NULL;
if (!(last = _tok_value(rh, ft, field_num, implicit,
last, &vs, &ve, &flags,
&rvw, rh->selection->mem, custom)))
goto_bad;
}
/* assign custom structures to hold extra information for specific value types */
if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE ||
ft->flags == DM_REPORT_FIELD_TYPE_NUMBER ||
ft->flags == DM_REPORT_FIELD_TYPE_PERCENT)
custom = &factor;
else if (ft->flags & DM_REPORT_FIELD_TYPE_TIME)
custom = &tval;
else if (ft->flags == DM_REPORT_FIELD_TYPE_STRING_LIST)
custom = &str_list;
else
custom = NULL;
/* get value to compare with */
if (!(last = _tok_value(rh, ft, field_num, implicit,
last, &vs, &ve, &flags,
&rvw, rh->selection->mem, custom)))
goto_bad;
*next = _skip_space(last);
/* create selection */
@@ -4226,7 +3970,8 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
return sn;
bad:
_parse_syntax_error(s);
log_error(_sel_syntax_error_at_msg, s);
log_error(_sel_help_ref_msg);
*next = s;
return NULL;
}
@@ -4350,7 +4095,7 @@ error:
static int _alloc_rh_selection(struct dm_report *rh)
{
if (!(rh->selection = dm_pool_zalloc(rh->mem, sizeof(struct selection))) ||
!(rh->selection->mem = dm_pool_create("report selection", 1024))) {
!(rh->selection->mem = dm_pool_create("report selection", 10 * 1024))) {
log_error("Failed to allocate report selection structure.");
if (rh->selection)
dm_pool_free(rh->mem, rh->selection);
@@ -4391,7 +4136,8 @@ static int _report_set_selection(struct dm_report *rh, const char *selection, in
next = _skip_space(fin);
if (*next) {
log_error("Expecting logical operator");
_parse_syntax_error(next);
log_error(_sel_syntax_error_at_msg, next);
log_error(_sel_help_ref_msg);
goto bad;
}
@@ -4671,12 +4417,9 @@ static int _sort_rows(struct dm_report *rh)
struct row *(*rows)[];
uint32_t count = 0;
struct row *row;
size_t cnt_rows;
if (!(cnt_rows = dm_list_size(&rh->rows)))
return 1; /* nothing to sort */
if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) * cnt_rows))) {
if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
dm_list_size(&rh->rows)))) {
log_error("dm_report: sort array allocation failed");
return 0;
}
@@ -4851,39 +4594,31 @@ bad:
static int _safe_repstr_output(struct dm_report *rh, const char *repstr, size_t len)
{
const char *repstr_next_write = repstr;
const char *repstr_current = repstr;
const char *p_repstr;
const char *repstr_end = len ? repstr + len : repstr + strlen(repstr);
/* Escape any JSON_ESCAPE_CHAR and JSON_QUOTE that may appear in reported string. */
while (repstr_current < repstr_end) {
if (repstr_current[0] == JSON_ESCAPE_CHAR[0] || repstr_current[0] == JSON_QUOTE[0]) {
// Write out all "sanitized" chars so far
if (repstr_next_write < repstr_current) {
if (!dm_pool_grow_object(rh->mem, repstr_next_write, repstr_current - repstr_next_write)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
/* Escape any JSON_QUOTE that may appear in reported string. */
while (1) {
if (!(p_repstr = memchr(repstr, JSON_QUOTE[0], repstr_end - repstr)))
break;
repstr_next_write = repstr_current;
}
// Add an escape
if (!dm_pool_grow_object(rh->mem, JSON_ESCAPE_CHAR, 1)) {
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;
}
}
++repstr_current;
}
// Write out all remaining "sanitized" chars
if (repstr_next_write < repstr_end) {
if (!dm_pool_grow_object(rh->mem, repstr_next_write, repstr_end - repstr_next_write)) {
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;
@@ -5033,11 +4768,10 @@ static int _output_as_rows(struct dm_report *rh)
dm_list_iterate_items(fp, &rh->field_props) {
if (fp->flags & FLD_HIDDEN) {
dm_list_iterate_items(row, &rh->rows) {
/* coverity[unreachable] intentional single iteration to get first item */
dm_list_iterate_items(field, &row->fields) {
dm_list_del(&field->list);
break; /* 1st. field removed */
}
if (dm_list_empty(&row->fields))
continue;
field = dm_list_item(dm_list_first(&row->fields), struct dm_report_field);
dm_list_del(&field->list);
}
continue;
}
@@ -5368,15 +5102,6 @@ struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void
struct dm_pool *mem;
struct report_group_item *item;
if (type == DM_REPORT_GROUP_JSON_STD) {
const char * radixchar = nl_langinfo(RADIXCHAR);
if (radixchar && strcmp(radixchar, ".")) {
log_error("dm_report: incompatible locale used for DM_REPORT_GROUP_JSON_STD, "
"radix character is '%s', expected '.'", radixchar);
return NULL;
}
}
if (!(mem = dm_pool_create("report_group", 1024))) {
log_error("dm_report: dm_report_init_group: failed to allocate mem pool");
return NULL;

View File

@@ -169,7 +169,7 @@ int dm_vasprintf(char **result, const char *format, va_list aq)
}
if (i > 1) {
/* Reallocating more than once? */
/* Reallocating more then once? */
if (!(*result = strdup(buf))) {
free(buf);
return -1;
@@ -591,7 +591,7 @@ const char *dm_size_to_string(struct dm_pool *mem, uint64_t size,
if ((s < NUM_UNIT_PREFIXES) &&
((unit_type == 'R') || (unit_type == 'r'))) {
/* When the rounding would cause difference, add '<' prefix
* i.e. 2043M is more than 1.9949G prints <2.00G
* i.e. 2043M is more then 1.9949G prints <2.00G
* This version is for 2 digits fixed precision */
d = 100. * (double) size / byte;
if (!_close_enough(floorl(d), nearbyintl(d)))

View File

@@ -120,7 +120,7 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
if (!(pp = _skip_fields(p, 1)))
goto_bad;
/* Raid target can actually report more than real number of legs in a case
/* Raid target can actually report more then real number of legs in a case
* raid legs have been removed during initial raid array resynchronization */
if (i > (pp - p - 1))
i = pp - p - 1;
@@ -335,19 +335,11 @@ int dm_get_status_cache(struct dm_pool *mem, const char *params,
/* Read in policy args */
pp = p;
if (!(p = _skip_fields(p, 1)))
goto_bad;
i = p - pp;
if ((i < 1) ||
!(s->policy_name = dm_pool_zalloc(mem, i)))
goto_bad;
dm_strncpy(s->policy_name, pp, i);
if (sscanf(p, "%d", &s->policy_argc) != 1)
if (!(p = _skip_fields(p, 1)) ||
!(s->policy_name = dm_pool_zalloc(mem, (p - pp))))
goto bad;
if (sscanf(pp, "%s %d", s->policy_name, &s->policy_argc) != 2)
goto bad;
if (s->policy_argc &&
(!(s->policy_argv = dm_pool_zalloc(mem, sizeof(char *) * s->policy_argc)) ||
!(p = _skip_fields(p, 1)) ||
@@ -579,7 +571,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
pos += used;
if (num_devs > DM_MIRROR_MAX_IMAGES) {
log_error(INTERNAL_ERROR "More than " DM_TO_STRING(DM_MIRROR_MAX_IMAGES)
log_error(INTERNAL_ERROR "More then " DM_TO_STRING(DM_MIRROR_MAX_IMAGES)
" reported in mirror status.");
goto out;
}

View File

@@ -1,165 +0,0 @@
/*
* Copyright (C) 2024 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
*/
/*
* Support counting number of failed device bits in dm-raid superblock bit arrays or clear them out.
*/
#include "device_mapper/misc/dmlib.h"
#include "device_mapper/all.h"
#include "device_mapper/raid/target.h"
#include "lib/mm/xlate.h"
#include <fcntl.h>
#include <unistd.h>
/* Copied/derived from kernel's drivers/md/dm-raid.c so this is prone to out-of-sync (factor out to header file?). */
#define MAX_RAID_DEVICES 253 /* md-raid kernel limit? */
#define UINT64_BITS (sizeof(uint64_t) * 8)
#define DISKS_ARRAY_ELEMS ((MAX_RAID_DEVICES + (UINT64_BITS - 1)) / UINT64_BITS)
#define DM_RAID_SB_MAGIC 0x446D5264 /* "DmRd" */
#define FEATURE_FLAG_SUPPORTS_V190 0x1 /* Supports extended superblock */
/* RAID superblock at beginning of rmeta SubLVs trimmed down to mandatory members. */
struct dm_raid_superblock {
__le32 magic; /* "DmRd" */
__le32 compat_features; /* Used to indicate compatible features (like 1.9.0 ondisk metadata extension) */
__le32 dummy[4];
__le64 failed_devices; /* Pre 1.9.0 part of bit field of devices to */
/* indicate device failures (see extension below) */
__le32 dummy1[7];
/********************************************************************
* BELOW FOLLOW V1.9.0 EXTENSIONS TO THE PRISTINE SUPERBLOCK FORMAT!!!
*
* FEATURE_FLAG_SUPPORTS_V190 in the compat_features member indicates that those exist
*/
__le32 flags; /* Flags defining array states for reshaping */
__le32 dummy2[14];
__le64 extended_failed_devices[DISKS_ARRAY_ELEMS - 1];
__le32 dummy3;
/* Always set rest up to logical block size to 0 when writing ... */
} __packed;
/* END: Copied from ... */
/* Superblock I/O buffer size to be able to Cope with 4K native devices... */
#define SB_BUFSZ 4096
static size_t _get_sb_size(const struct dm_raid_superblock *sb)
{
return (FEATURE_FLAG_SUPPORTS_V190 & le32toh(sb->compat_features)) ?
sizeof(*sb) : ((char *) &sb->flags - (char *) sb);
}
static uint32_t _hweight64(__le64 v)
{
uint32_t r = 0;
while (v) {
r += v & 1;
v >>= 1;
}
return r;
}
static uint32_t _hweight_failed(struct dm_raid_superblock *sb)
{
uint32_t r = _hweight64(sb->failed_devices);
if (_get_sb_size(sb) == sizeof(*sb)) {
int i = (int)DM_ARRAY_SIZE(sb->extended_failed_devices);
while (i--)
r = max(r, _hweight64(sb->extended_failed_devices[i]));
}
return r;
}
static void _clear_failed_devices(struct dm_raid_superblock *sb)
{
sb->failed_devices = 0;
if (_get_sb_size(sb) == sizeof(*sb))
memset(sb->extended_failed_devices, 0, sizeof(sb->extended_failed_devices));
}
static int _count_or_clear_failed_devices(const char *dev_path, bool clear, uint32_t *nr_failed)
{
struct dm_raid_superblock *sb = NULL;
size_t sz;
int fd, r = 0;
if (posix_memalign((void *) &sb, SB_BUFSZ, SB_BUFSZ)) {
log_sys_error("Failed to allocate RAID superblock buffer", dev_path);
return 0;
}
fd = open(dev_path, O_EXCL | ((clear) ? O_RDWR : O_RDONLY) | O_DIRECT);
if (fd < 0) {
log_sys_error("Failed to open RAID metadata volume", dev_path);
goto out;
}
if (read(fd, sb, SB_BUFSZ) != SB_BUFSZ) {
log_sys_error("Failed to read RAID metadata volume", dev_path);
goto out;
}
/* FIXME: big endian??? */
if (sb->magic != htobe32(DM_RAID_SB_MAGIC)) {
log_error("No RAID signature on %s.", dev_path);
goto out;
}
if (nr_failed)
*nr_failed = _hweight_failed(sb);
if (clear) {
if (lseek(fd, 0, SEEK_SET) < 0) {
log_sys_error("Failed to seek RAID metadata volume", dev_path);
goto out;
}
sz = _get_sb_size(sb);
memset((void *)((char *) sb + sz), 0, SB_BUFSZ - sz);
_clear_failed_devices(sb);
if (write(fd, sb, SB_BUFSZ) != SB_BUFSZ) {
log_sys_error("Failed to clear RAID metadata volume", dev_path);
goto out;
}
}
r = 1;
out:
if ((fd >= 0) && close(fd))
log_sys_debug("close", dev_path);
free(sb);
return r;
}
int dm_raid_count_failed_devices(const char *dev_path, uint32_t *nr_failed)
{
return _count_or_clear_failed_devices(dev_path, false, nr_failed);
}
int dm_raid_clear_failed_devices(const char *dev_path, uint32_t *nr_failed)
{
return _count_or_clear_failed_devices(dev_path, true, nr_failed);
}

View File

@@ -1,23 +0,0 @@
/*
* Copyright (C) 2024 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef DEVICE_MAPPER_RAID_TARGET_H
#define DEVICE_MAPPER_RAID_TARGET_H
#include <stdint.h>
int dm_raid_count_failed_devices(const char *dev_path, uint32_t *nr_failed);
int dm_raid_clear_failed_devices(const char *dev_path, uint32_t *nr_failed);
#endif

View File

@@ -28,6 +28,11 @@
#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>
@@ -67,7 +72,7 @@ enum {
struct vdo_header {
uint32_t id; /* The component this is a header for */
struct vdo_version_number version; /* The version of the data format */
uint64_t size; /* The size of the data following this header */
size_t size; /* The size of the data following this header */
} __packed;
struct vdo_geometry_block {
@@ -135,36 +140,36 @@ struct vdo_volume_geometry_4 {
static void _vdo_decode_version(struct vdo_version_number *v)
{
v->major_version = le32toh(v->major_version);
v->minor_version = le32toh(v->minor_version);
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 = le32toh(h->id);
h->id = le32_to_cpu(h->id);
_vdo_decode_version(&h->version);
h->size = le64toh(h->size);
h->size = le64_to_cpu(h->size);
}
static void _vdo_decode_geometry_region(struct vdo_volume_region *vr)
{
vr->id = (enum vdo_volume_region_id) le32toh(vr->id);
vr->start_block = le64toh(vr->start_block);
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 = le32toh(vg->release_version);
vg->nonce = le64toh(vg->nonce);
vg->bio_offset = le64toh(vg->bio_offset);
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 = le32toh(vg_4->release_version);
vg->nonce = le64toh(vg_4->nonce);
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]);
@@ -172,17 +177,17 @@ static void _vdo_decode_volume_geometry_4(struct vdo_volume_geometry *vg,
static void _vdo_decode_config(struct vdo_config *vc)
{
vc->logical_blocks = le64toh(vc->logical_blocks);
vc->physical_blocks = le64toh(vc->physical_blocks);
vc->slab_size = le64toh(vc->slab_size);
vc->recovery_journal_size = le64toh(vc->recovery_journal_size);
vc->slab_journal_blocks = le64toh(vc->slab_journal_blocks);
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 = le64toh(pvc->nonce);
pvc->nonce = le64_to_cpu(pvc->nonce);
}
bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)

View File

@@ -72,7 +72,6 @@ incorrectly!
Make one by running `pvcreate /dev/sdX`.
See [pvcreate(8)](https://man7.org/linux/man-pages/man8/pvcreate.8.html). This step is optional.
* Volume Group (VG) consisting of one or more PVs is used as a pool from which LVs are allocated.
List VGs using [vgs(8)](https://man7.org/linux/man-pages/man8/vgs.8.html) or
[vgdisplay(8)](https://man7.org/linux/man-pages/man8/vgdisplay.8.html).
@@ -81,34 +80,27 @@ incorrectly!
To use LVM at least one Volume Group must be present on the system.
See [vgcreate(8)](https://man7.org/linux/man-pages/man8/vgcreate.8.html), and
[vgextend(8)](https://man7.org/linux/man-pages/man8/vgextend.8.html).
* Logical Volume (LV) is the block device usually visible to user to be used for file system.
List LVs using [lvs(8)](https://man7.org/linux/man-pages/man8/lvs.8.html) or
List PVs using [lvs(8)](https://man7.org/linux/man-pages/man8/lvs.8.html) or
[lvdisplay(8)](https://man7.org/linux/man-pages/man8/lvdisplay.8.html).
Make one by running `lvcreate [-n LVNAME] -L SIZE VGNAME`, and you are done!
See [lvcreate(8)](https://man7.org/linux/man-pages/man8/lvcreate.8.html).
To change size of LV it is recommended to use [lvresize(8)](https://man7.org/linux/man-pages/man8/lvresize.8.html) with `--resizefs` option.
To change properties of LV (e.g. to activate/deactivate a volume, or change it to read only) use [lvchange(8)](https://man7.org/linux/man-pages/man8/lvchange.8.html).
To change the type of LV (e.g. change a linear volume to a RAID) use [lvconvert(8)](https://man7.org/linux/man-pages/man8/lvconvert.8.html).
See [vgcreate(8)](https://man7.org/linux/man-pages/man8/vgcreate.8.html).
## Avoiding Problems
Good start is to **avoid using `{--force|-f}` and `{--yes|-y}` options** which are
Good start is to avoid using `{--force|-f}` and `{--yes|-y}` options which are
often seen on internet discussions.
When there is a possibility of data loss, LVM tools usually ask, so read the
prompts carefully! Using `--yes` removes these measures.
Also in cases where it is too dangerous to proceed, e.g. device is used,
there is a possibility of data loss, LVM tools usually ask, so read the prompts
carefully! Using `--yes` removes these safety.
Also in some cases where it is too dangerous to proceed, e.g. device is used,
LVM refuses to do so, which can be overridden by `--force`.
Second, when **resizing** and especially when shrinking LVs it is always a good
idea to **use `--resizefs` option** which ensures the devices are resized in
Second, when resizing and especially when shrinking LVs it is always a good
idea to use `--resizefs` option which ensures the devices are resized in
correct order.
Third, if you still make a mess, **never ever run fsck on damaged LV/FS**, this is
Third, if you still make a mess, never ever run fsck on damaged LV/FS, this is
usually the final blow to your data. It is always better to ask first!

View File

@@ -23,7 +23,7 @@ The dm-zoned implementation is simple and minimizes system overhead (CPU
and memory usage as well as storage capacity loss). For a 10TB
host-managed disk with 256 MB zones, dm-zoned memory usage per disk
instance is at most 4.5 MB and as little as 5 zones will be used
internally for storing metadata and performing reclaim operations.
internally for storing metadata and performaing reclaim operations.
dm-zoned target devices are formatted and checked using the dmzadm
utility available at:

View File

@@ -224,9 +224,9 @@ lv {
The real trick is dealing with the metadata devices. Mirroring has an entry,
'mirror_log', in the top-level segment. This won't work for RAID because there
is a one-to-one mapping between the data devices and the metadata devices. The
mirror devices are laid-out in sub-device/le pairs. The 'le' parameter
is redundant since it will always be zero. So for RAID, I have simple
put the metadata and data devices in pairs without the 'le' parameter.
mirror devices are layed-out in sub-device/le pairs. The 'le' parameter is
redundant since it will always be zero. So for RAID, I have simple put the
metadata and data devices in pairs without the 'le' parameter.
RAID metadata:
lv {

208
doc/lvmetad_design.txt Normal file
View File

@@ -0,0 +1,208 @@
The design of LVMetaD
=====================
Invocation and setup
--------------------
The daemon should be started automatically by the first LVM command issued on
the system, when needed. The usage of the daemon should be configurable in
lvm.conf, probably with its own section. Say
lvmetad {
enabled = 1 # default
autostart = 1 # default
socket = "/path/to/socket" # defaults to /var/run/lvmetad or such
}
Library integration
-------------------
When a command needs to access metadata, it currently needs to perform a scan
of the physical devices available in the system. This is a possibly quite
expensive operation, especially if many devices are attached to the system. In
most cases, LVM needs a complete image of the system's PVs to operate
correctly, so all devices need to be read, to at least determine presence (and
content) of a PV label. Additional IO is done to obtain or write metadata
areas, but this is only marginally related and addressed by Dave's
metadata-balancing work.
In the existing scanning code, a cache layer exists, under
lib/cache/lvmcache.[hc]. This layer is keeping a textual copy of the metadata
for a given volume group, in a format_text form, as a character string. We can
plug the lvmetad interface at this level: in lvmcache_get_vg, which is
responsible for looking up metadata in a local cache, we can, if the metadata
is not available in the local cache, query lvmetad. Under normal circumstances,
when a VG is not cached yet, this operation fails and prompts the caller to
perform a scan. Under the lvmetad enabled scenario, this would never happen and
the fall-through would only be activated when lvmetad is disabled, which would
lead to local cache being populated as usual through a locally executed scan.
Therefore, existing stand-alone (i.e. no lvmetad) functionality of the tools
would be not compromised by adding lvmetad. With lvmetad enabled, however,
significant portions of the code would be short-circuited.
Scanning
--------
Initially (at least), the lvmetad will be not allowed to read disks: it will
rely on an external program to provide the metadata. In the ideal case, this
will be triggered by udev. The role of lvmetad is then to collect and maintain
an accurate (up to the data it has received) image of the VGs available in the
system. I imagine we could extend the pvscan command (or add a new one, say
lvmetad_client, if pvscan is found to be inappropriate):
$ pvscan --cache /dev/foo
$ pvscan --cache --remove /dev/foo
These commands would simply read the label and the MDA (if applicable) from the
given PV and feed that data to the running lvmetad, using
lvmetad_{add,remove}_pv (see lvmetad_client.h).
We however need to ensure a couple of things here:
1) only LVM commands ever touch PV labels and VG metadata
2) when a device is added or removed, udev fires a rule to notify lvmetad
While the latter is straightforward, there are issues with the first. We
*might* want to invoke the dreaded "watch" udev rule in this case, however it
ends up being implemented. Of course, we can also rely on the sysadmin to be
reasonable and not write over existing LVM metadata without first telling LVM
to let go of the respective device(s).
Even if we simply ignore the problem, metadata write should fail in these
cases, so the admin should be unable to do substantial damage to the system. If
there were active LVs on top of the vanished PV, they are in trouble no matter
what happens there.
Incremental scan
----------------
There are some new issues arising with the "udev" scan mode. Namely, the
devices of a volume group will be appearing one by one. The behaviour in this
case will be very similar to the current behaviour when devices are missing:
the volume group, until *all* its physical volumes have been discovered and
announced by udev, will be in a state with some of its devices flagged as
MISSING_PV. This means that the volume group will be, for most purposes,
read-only until it is complete and LVs residing on yet-unknown PVs won't
activate without --partial. Under usual circumstances, this is not a problem
and the current code for dealing with MISSING_PVs should be adequate.
However, the code for reading volume groups from disks will need to be adapted,
since it currently does not work incrementally. Such support will need to track
metadata-less PVs that have been encountered so far and to provide a way to
update an existing volume group. When the first PV with metadata of a given VG
is encountered, the VG is created in lvmetad (probably in the form of "struct
volume_group") and it is assigned any previously cached metadata-less PVs it is
referencing. Any PVs that were not yet encountered will be marked as MISSING_PV
in the "struct volume_group". Upon scanning a new PV, if it belongs to any
already-known volume group, this PV is checked for consistency with the already
cached metadata (in a case of mismatch, the VG needs to be recovered or
declared conflicted), and is subsequently unmarked MISSING_PV. Care need be
taken not to unmark MISSING_PV on PVs that have this flag in their persistent
metadata, though.
The most problematic aspect of the whole design may be orphan PVs. At any given
point, a metadata-less PV may appear orphaned, if a PV of its VG with metadata
has not been scanned yet. Eventually, we will have to decide that this PV is
really an orphan and enable its usage for creating or extending VGs. In
practice, the decision might be governed by a timeout or assumed immediately --
the former case is a little safer, the latter is probably more transparent. I
am not very keen on using timeouts and we can probably assume that the admin
won't blindly try to reuse devices in a way that would trip up LVM in this
respect. I would be in favour of just assuming that metadata-less VGs with no
known referencing VGs are orphans -- after all, this is the same approach as we
use today. The metadata balancing support may stress this a bit more than the
usual contemporary setups do, though.
Automatic activation
--------------------
It may also be prudent to provide a command that will block until a volume
group is complete, so that scripts can reliably activate/mount LVs and such. Of
course, some PVs may never appear, so a timeout is necessary. Again, this is
something not handled by current tools, but may become more important in
future. It probably does not need to be implemented right away though.
The other aspect of the progressive VG assembly is automatic activation. The
currently only problem with that is that we would like to avoid having
activation code in lvmetad, so we would prefer to fire up an event of some sort
and let someone else handle the activation and whatnot.
Cluster support
---------------
When working in a cluster, clvmd integration will be necessary: clvmd will need
to instruct lvmetad to re-read metadata as appropriate due to writes on remote
hosts. Overall, this is not hard, but the devil is in the details. I would
possibly disable lvmetad for clustered volume groups in the first phase and
only proceed when the local mode is robust and well tested.
With lvmlockd, lvmetad state is kept up to date by flagging either an
individual VG as "invalid", or the global state as "invalid". When either
the VG or the global state are read, this invalid flag is returned along
with the data. The client command can check for this invalid state and
decide to read the information from disk rather than use the stale cached
data. After the latest data is read from disk, the command may choose to
send it to lvmetad to update the cache. lvmlockd uses version numbers
embedded in its VG and global locks to detect when cached data becomes
invalid, and it then tells lvmetad to set the related invalid flag.
dct, 2015-06-23
Protocol & co.
--------------
I expect a simple text-based protocol executed on top of an Unix Domain Socket
to be the communication interface for lvmetad. Ideally, the requests and
replies will be well-formed "config file" style strings, so we can reuse
existing parsing infrastructure.
Since we already have two daemons, I would probably look into factoring some
common code for daemon-y things, like sockets, communication (including thread
management) and maybe logging and re-using it in all the daemons (clvmd,
dmeventd and lvmetad). This shared infrastructure should live under
daemons/common, and the existing daemons shall be gradually migrated to the
shared code.
Future extensions
-----------------
The above should basically cover the use of lvmetad as a cache-only
daemon. Writes could still be executed locally, and the new metadata version
can be provided to lvmetad through the socket the usual way. This is fairly
natural and in my opinion reasonable. The lvmetad acts like a cache that will
hold metadata, no more no less.
Above this, there is a couple of things that could be worked on later, when the
above basic design is finished and implemented.
_Metadata writing_: We may want to support writing new metadata through
lvmetad. This may or may not be a better design, but the write itself should be
more or less orthogonal to the rest of the story outlined above.
_Locking_: Other than directing metadata writes through lvmetad, one could
conceivably also track VG/LV locking through the same.
_Clustering_: A deeper integration of lvmetad with clvmd might be possible and
maybe desirable. Since clvmd communicates over the network with other clvmd
instances, this could be extended to metadata exchange between lvmetad's,
further cutting down scanning costs. This would combine well with the
write-through-lvmetad approach.
Testing
-------
Since (at least bare-bones) lvmetad has no disk interaction and is fed metadata
externally, it should be very amenable to automated testing. We need to provide
a client that can feed arbitrary, synthetic metadata to the daemon and request
the data back, providing reasonable (nearly unit-level) testing infrastructure.
Battle plan & code layout
=========================
- config_tree from lib/config needs to move to libdm/
- daemon/common *client* code can go to libdm/ as well (say
libdm/libdm-daemon.{h,c} or such)
- daemon/common *server* code stays, is built in daemon/ toplevel as a static
library, say libdaemon-common.a
- daemon/lvmetad *client* code goes to lib/lvmetad
- daemon/lvmetad *server* code stays (links in daemon/libdaemon_common.a)

View File

@@ -6,11 +6,11 @@ Version 2.03.30
Small bugfix release:
* **NEW** Create `/dev/disk/by-diskseq/<DISKSEQ>` symlink for public DM devices.
* **NEW** Create /dev/disk/by-diskseq/<DISKSEQ> symlink for public DM devices.
* Lvresize reports origin vdo volume cannot be resized.
* Support setting `reserved_memory|stack` using `--config` on cmdline.
* Support setting reserved_memory|stack using --config on cmdline.
* Fix support for disabling memory locking (2.03.27).
* Do not extend an LV if FS resize unsupported and `--fs resize` used.
* Do not extend an LV if FS resize unsupported and '--fs resize' used.
* Prevent leftover temporary device when converting in use volume to a pool.
* lvconvert detects volume in use early when converting it to a pool.
* Handle NVMe with quirk changed WWID not matching WWID in devices file.

View File

@@ -1,33 +0,0 @@
<!-- Page title -->
[[!meta title="Version 2.03.31 - Bug Fix Release"]]
Version 2.03.31
===============
Bugfix release:
* Disallow shared activation of LV with CoW snapshot.
* Ignore reported `optimal_io_size` not divisible by 4096.
* Restore support for `LVM_SUPPRESS_FD_WARNINGS` (2.03.24).
* Fix DM cache preserving logic (2.03.28).
* Restore missing symbol `dm_tree_node_size_changed@Base` (1.02.175).
* Restore missing symbol `dm_bitset_parse_list@@DM_1_02_138` (1.02.175).
* Fix uncache and split cache restoring original state of volume.
* Extend use of lockopt skip to more scenarios.
* Reduce `mandoc -T lint` reported issues for man pages.
* Enhance error path resolving in polling code.
* Fix lvmlockd use in lvremove of CoW snapshot, VDO pool, and uncache.
* Improve mirror split with opened temporary volumes.
* Improve pvmove finish with opened temporary volumes.
* Fix backup limit for devices file, handle over 10,000 files.
* Fix busy-loop in config reading when read returned 0.
* Improve use of lvmlockd for usecases involving thin volumes and pools.
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
[[!tag]]
<!--
For old releases add Release Timestamp like this, date from git show $COMMIT is fine.
[[!meta date="Thu Feb 27 16:51:29 2025 +0100"]]
-->

View File

@@ -1,26 +0,0 @@
<!-- Page title -->
[[!meta title="Version 2.03.32 - Bug Fix Release"]]
Version 2.03.32
===============
Mostly bugfix release:
* Add support for using regex in selection criteria for string lists.
* Accept thin pool data LV as cacheable LV.
* Accept `--autobackup` option in pvresize.
* Allow using zram block devices (likely for testing).
* Lvconvert vdopool conversion properly validates acceptable LVs.
* Fix lvresize when resizing COW snapshots already covering origin.
* Fix lvmdbusd read of executed lvm commands output.
* Fix construction of DM UUID for cachevol `_cdata` and `_cmeta` devices.
* Ignore PV claims from old metadata when then PV belongs to a new VG.
* Fix integrity metadata rounding.
* Fix string list selection when using `[<item> || <item> ...]`.
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
[[!tag]]
<!--
For old releases add Release Timestamp like this, date from git show $COMMIT is fine.
[[!meta date="Mon May 05 17:02:00 2025 +0200"]]
-->

View File

@@ -1,19 +0,0 @@
<!-- Page title -->
[[!meta title="Version 2.03.33 - Bug Fix Release"]]
Version 2.03.33
===============
Mostly bugfix release:
* Use `lvconvert --repair` to repair raid arrays with transiently lost devices.
* Override `LC_NUMERIC` locale if unsuitable for `json_std` report format.
* Fail `dm_report_group_create` if radix char from locale unsuitable for `json_std`.
* Escape the escape character itself on JSON report format output.
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
[[!tag]]
<!--
For old releases add Release Timestamp like this, date from git show $COMMIT is fine.
[[!meta date="Fri Jun 27 10:14:00 2025 +0200"]]
-->

View File

@@ -1,30 +0,0 @@
<!-- Page title -->
[[!meta title="Version 2.03.34 - Bug Fix Release"]]
Version 2.03.34
===============
Add *Persistent Reservations* and many mostly small fixes.
* **NEW** Add support for **persistent reservations** controlling access to shared PVs.
* See [lvmpersist(8)](https://man7.org/linux/man-pages/man8/lvmpersist.8.html) for more details.
* Add `lvmlockd --lockopt repair` to reinitialize corrupted sanlock leases.
* Add *lvm.conf* `global/lvresize_fs_helper_executable`.
* Fix lvresize corruption in LV->crypt->FS stack if near crypt min size limit.
* Support dmeventd restart when there are no monitored devices.
* Dmeventd no longer calls 'action commands' on removed devices.
* Enhanced `lvresize -r` support for btrfs.
* Fix reader of VDO metadata on 32bit architecture.
* Fix `lvmdevices --deldev/--delpvid` to error out if devices file not writeable.
* Use glibc standard functions htoX, Xtoh functions for endian conversion.
* Fix structure copying within sanlock's `release_rename()`.
* Fix autoactivation on top of loop dev PVs to trigger once for change uevents.
* Fix support for `lvcreate -T --setautoactivation`.
* Fix many issues found by coverity static analysis, gcc warnings, typos, tests, and other clean ups.
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
[[!tag]]
<!--
For old releases add Release Timestamp like this, date from git show $COMMIT is fine.
[[!meta date="Wed Jul 30 15:35:00 2025 +0200"]]
-->

View File

@@ -1,53 +0,0 @@
<!-- Page title -->
[[!meta title="Version 2.03.35 - Feature and Bug Fix Release"]]
Version 2.03.35
===============
* Optimize dmeventd when remonitoring active devices.
* Allow report options for `(pv|vg|lv)display` only if used with `-C|--columns`.
* And [[!toggle text="more"]]
[[!toggleable text="""
Features
-----------------------
### Optimize dmeventd when remonitoring active devices.
Add grace period (controlled by `-g SECONDS` option) to [dmeventd(8)](https://man7.org/linux/man-pages/man8/dmeventd.8.html) to reuse threads.
This change help to reduce overhead and unnecessary `lvextend` calls.
<!--
TODO: It would be nice if we could use a real session output, so we could test the examples
- During tests, save some outputs
-->
Changes in command line
-----------------------
* Report options (`--select STRING`, `--configreport CONFIG_REPORT`, `--logonly`)
are allowed only with `(pv|vg|lv)display -C|--columns`.
These **no longer work** without `-C|--columns` and were removed as they were not working properly anyway.
Other Changes
-------------
* Fix unlocking devices file only after all PVs are processed.
* Avoid creating system.devices when deleting entries.
* Fix existing issues with persistent reservations.
* Fix possible report output format inconsistencies while processing PVs.
* Allow report options for pv/vg/lvdisplay only if used with -C|--columns.
* Fix vgsplit failing to split a VG with RAID+integrity or cache with cachevol.
* Fix --lockopt handling in lvmlockd when --nolocking is used.
* Optimize dmeventd when remonitoring active devices.
"""]]
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
[[!tag]]
<!--
For old releases add Release Timestamp like this, date from git show $COMMIT is fine.
[[!meta date="Tue Sep 09 14:19:37 2025 +0200"]]
-->

View File

@@ -1,39 +0,0 @@
<!-- Page title -->
[[!meta title="Version 2.03.36 - Feature and Bug Fix Release"]]
Version 2.03.36
===============
* Support splitting large pvmove into segments, controlled by
`allocation/pvmove_max_segment_size_mb` configuration option.
* Add cache promotions/demotions to reports.
* Handle XFS quota when resizing.
* Allow creating `_imeta` with multiple segments.
* Fix race in dmeventd remonitoring optimization (2.03.35).
* And [[!toggle text="more"]]
[[!toggleable text="""
Other Changes
-------------
* Support `--setpersist` in vgcreate.
* Use only hostid-based PR keys for sanlock VGs.
* Update lvmlockd(8) man page.
* Consistent sorting of command options in help and man pages.
* Use `-real` UUID suffix to keep internal volumes hidden from udev. This is
implemented for RAID, mirror, integrity, and internal pvmove volumes. This
should handle corner cases where where operations were not finishing cleanly.
* Fix adding and removing integrity to RAID volumes.
* Deactivate internal lvmlock LV if lock start fails.
* Detect insufficient space for RAID with split metadata.
"""]]
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
[[!tag]]
<!--
For old releases add Release Timestamp like this, date from git show $COMMIT is fine.
[[!meta date="Fri Oct 24 18:22:00 2025 +0100"]]
-->

View File

@@ -1,45 +0,0 @@
<!-- Page title -->
[[!meta title="Version 2.03.37 - Feature and Bug Fix Release"]]
Version 2.03.37
===============
* Improvements in dmeventd thread safety, shutdown times and more.
* Many fixes and improvements for persistent reservations.
* Support output in list mode for all lvmconfig --typeconfig types with --list.
* Fix deadlock in lvmdbusd on SIGINT in lvm shell mode.
* And [[!toggle text="more"]]
[[!toggleable text="""
Other Changes
-------------
* Remove unsupported `--blockdevice` option from lvscan.
* Add missing synchronization while converting cachevols.
* Add missing synchronization for vdopool.
* Warn on classic snapshot on raid creation and error on activation if missing.
* Use `source='udev'` in lvmdbusd to monitor processed udev events.
* Improve lvmdbusd matching of udevd reported device paths.
* Add `--setlockargs` option to vgchange. See vgchange(8).
* lvmdevices:
* Add `--force` option for `lvmdevices --update`.
* Add `--listids`, `--delid`, `--addid` options for manipulation by `device_id`.
* Major update of lvmdevices(8) man page.
* Persistent Reservations(PR):
* Use PR for recovery with sanlock in lvmlockd - see lvmlockd(8) and
lvmpersist(8) man pages.
* Add VG attr character and `pr` field for PR status to vgs.
* Fix PR setting handling in vgmerge, vgsplit and vgimportclone.
* Enhance shutdown performance of daemons using libdaemon.
* Lot of cleanups, test improvements, static analysis fixes.
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
[[!tag]]
<!--
For old releases add Release Timestamp like this, date from git show $COMMIT is fine.
[[!meta date="Fri Nov 21 20:07:00 2025 +0100"]]
-->
"""]]

View File

@@ -1,26 +0,0 @@
<!-- Page title -->
[[!meta title="Version 2.03.38 - Bug Fix Release"]]
Version 2.03.38
===============
* **IMPORTANT:** Workaround for **libblkid returning old `FSLASTBLOCK`** immediately after resize.
This may cause data loss on lvextend followed by lvreduce to original size.
* Fix tree manipulation when activating LV with pvmove in progress.
* Conversion to thin-pool removes activation skipping from converted LVs.
* And [[!toggle text="more"]]
[[!toggleable text="""
* Synchronize with udev after creating pool metadata spare volume.
* Configure now checks for `xfs/xfs.h`.
* LV locks whole device tree using such locked LV.
"""]]
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
[[!tag]]
<!--
For old releases add Release Timestamp like this, date from git show $COMMIT is fine.
[[!meta date="Mon Dec 15 15:15:00 2025 +0100"]]
-->

View File

@@ -549,9 +549,6 @@
/* Define to 1 if 'vfork' works. */
#undef HAVE_WORKING_VFORK
/* Define to 1 if you have the <xfs/xfs.h> header file. */
#undef HAVE_XFS_XFS_H
/* Define to 1 if the system has the type '_Bool'. */
#undef HAVE__BOOL
@@ -582,7 +579,7 @@
/* Define to 1 to include code that uses lvmlockd IDM option. */
#undef LOCKDIDM_SUPPORT
/* Define version of sanlock. */
/* Define to 1 to include code that uses lvmlockd sanlock option. */
#undef LOCKDSANLOCK_SUPPORT
/* Define to 1 if 'lstat' dereferences a symlink specified with a trailing
@@ -601,9 +598,6 @@
/* Define to 1 to include code that uses lvmlockd. */
#undef LVMLOCKD_SUPPORT
/* Path to lvmpersist script. */
#undef LVMPERSIST_PATH
/* Path to lvmpolld pidfile. */
#undef LVMPOLLD_PIDFILE

View File

@@ -40,11 +40,9 @@ SOURCES =\
device/dev-luks.c \
device/dev-dasd.c \
device/dev-lvm1-pool.c \
device/filesystem_xfs.c \
device/filesystem.c \
device/online.c \
device/parse_vpd.c \
device/persist.c \
device/nvme.c \
device/dev_util.c \
display/display.c \
@@ -71,7 +69,6 @@ SOURCES =\
format_text/import_vsn1.c \
format_text/text_label.c \
freeseg/freeseg.c \
id/id.c \
label/label.c \
label/hints.c \
locking/file_locking.c \
@@ -117,6 +114,7 @@ SOURCES =\
snapshot/snapshot.c \
striped/striped.c \
thin/thin.c \
uuid/uuid.c \
zero/zero.c
ifeq ("@DEVMAPPER@", "yes")

View File

@@ -28,6 +28,7 @@
#include "lib/config/config.h"
#include "lib/metadata/segtype.h"
#include "lib/misc/sharedlib.h"
#include "lib/metadata/metadata.h"
#include "lib/misc/lvm-signal.h"
#include <limits.h>
@@ -501,9 +502,7 @@ int driver_version(char *version, size_t size)
!dm_driver_version(_vsn, sizeof(_vsn)))
return_0;
if (version &&
!_dm_strncpy(version, _vsn, size))
return_0;
dm_strncpy(version, _vsn, size);
return 1;
}
@@ -682,55 +681,6 @@ int get_dm_active_devices(const struct volume_group *vg, struct dm_list **devs,
return dev_manager_get_dm_active_devices(NULL, devs, devs_features);
}
/*
* Check for active devices with private "-real" UUID suffix
* when public device doesn't exist.
*
* This function extends _lv_info() functionality to handle edge cases
* where a visible LV has no active device with its public UUID,
* but there might be an active device using a private "-real" suffixed UUID.
* This situation typically occurs during RAID/mirror operations
* where internal LV components transition to public LVs but retain their
* private device mapper UUIDs.
*
* The function:
* - Skips LVs that already have "-real" in their UUID (likely internal components)
* - Queries device mapper for a device using the LV name with "real" layer
* - Populates dminfo structure if such device exists
*
* These 'orphan' LVs with private UUIDs need explicit activation to be
* properly managed before they can be deactivated with their correct
* public UUIDs.
*
* TODO: automate removal of orphan LVs with -real suffix
* using LV_PENDING_DELETE to reduce this workaround code.
*/
static int _lv_info_real(const struct logical_volume *lv,
struct dm_info *dminfo)
{
const char *dlid;
if (lv_is_origin(lv) ||
lv_is_external_origin(lv) ||
lv_is_integrity_origin(lv) ||
lv_is_cow(lv))
return 1;
if (!(dlid = build_dm_uuid(lv->vg->cmd->mem, lv, NULL)))
return_0;
if (strstr(dlid, "-real")) {
/* UUID has "-real" suffix (likely MIRROR_SYNC_LAYER), skip */
return 1;
}
if (!dev_manager_info(lv->vg->cmd, lv, "real", 0, 0, 0,
dminfo, NULL, NULL))
return_0;
return 1;
}
/*
* When '*info' is NULL, returns 1 only when LV is active.
* When '*info' != NULL, returns 1 when info structure is populated.
@@ -776,10 +726,6 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
seg_status))
return_0;
if (!dminfo.exists && !use_layer && lv_is_visible(lv) &&
!_lv_info_real(lv, &dminfo))
return_0;
if (!info)
return dminfo.exists;
@@ -952,7 +898,7 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
int lv_check_not_in_use(const struct logical_volume *lv, int error_if_used)
{
struct lvinfo info;
int open_count_check_retries;
unsigned int open_count_check_retries;
if (!lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) || !info.exists)
return 2;
@@ -983,8 +929,8 @@ int lv_check_not_in_use(const struct logical_volume *lv, int error_if_used)
}
open_count_check_retries = retry_deactivation() ? OPEN_COUNT_CHECK_RETRIES : 1;
while (open_count_check_retries-- > 0) {
if (!sigint_usleep(OPEN_COUNT_CHECK_USLEEP_DELAY))
while (open_count_check_retries--) {
if (interruptible_usleep(OPEN_COUNT_CHECK_USLEEP_DELAY))
break; /* interrupted */
log_debug_activation("Retrying open_count check for %s.",
@@ -1694,7 +1640,7 @@ bad:
char *get_monitor_dso_path(struct cmd_context *cmd, int id)
{
const char *libpath = find_config_tree_str(cmd, id, NULL);
char path[PATH_MAX] = { 0 };
char path[PATH_MAX];
get_shared_library_path(cmd, libpath, path, sizeof(path));
@@ -1814,8 +1760,7 @@ int target_register_events(struct cmd_context *cmd, const char *dso, const struc
return_0;
if (!(dmevh = _create_dm_event_handler(cmd, uuid, dso, timeout,
timeout ? DM_EVENT_ERROR_AND_TIMEOUT_MASK :
DM_EVENT_ALL_ERRORS)))
DM_EVENT_ALL_ERRORS | (timeout ? DM_EVENT_TIMEOUT : 0))))
return_0;
r = set ? dm_event_register_handler(dmevh) : dm_event_unregister_handler(dmevh);
@@ -2089,7 +2034,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
break;
log_very_verbose("%s %smonitoring still pending: waiting...",
display_lvname(lv), monitor ? "" : "un");
if (!sigint_usleep(10000 * i)) {
if (interruptible_usleep(10000 * i)) {
stack;
r = 0;
break;
@@ -2139,12 +2084,16 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
const struct logical_volume *lv, const struct logical_volume *lv_pre)
{
const struct logical_volume *pvmove_lv = NULL;
const struct logical_volume *lv_pre_tmp, *lv_tmp;
struct logical_volume *lv_pre_tmp, *lv_tmp;
struct seg_list *sl;
struct lv_segment *snap_seg;
struct lvinfo info;
int r = 0, lockfs = 0, flush_required = 0;
struct detached_lv_data detached;
struct dm_pool *mem = NULL;
struct dm_list suspend_lvs;
struct lv_list *lvl;
int found;
if (!activation())
return 1;
@@ -2152,7 +2101,8 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
if (test_mode()) {
_skip("Suspending %s%s.", display_lvname(lv),
laopts->origin_only ? " origin without snapshots" : "");
return 1;
r = 1;
goto out;
}
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
@@ -2179,71 +2129,40 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
laopts->origin_only = 0;
}
/* Preload devices for the LV. */
/*
* Preload devices for the LV.
* If the PVMOVE LV is being removed, it's only present in the old
* metadata and not the new, so we must explicitly add the new
* tables for all the changed LVs here, as the relationships
* are not found by walking the new metadata.
*/
if (lv_is_locked(lv) && !lv_is_locked(lv_pre) &&
(pvmove_lv = find_pvmove_lv_in_lv(lv))) {
/*
* When the PVMOVE LV is being removed, it's only present
* in the committed metadata and not in the new precommmitted.
* Preloading all changed LVs here before suspending any of it,
* as the relationships are not found by walking the
* precommitted metadata.
*
* Note:
* When there is suspended LV, lvm shall not preload tables!
*
* Suspend of PVMOVE LV does NOT trace pvmove dependencies
* thus we need to use active pvmoved LV if there is one.
*/
lv = pvmove_lv; /* Suspend PVMOVE LV if no other pvmoved LV is active */
/* Preload all the LVs above the PVMOVE LV */
dm_list_iterate_items(sl, &pvmove_lv->segs_using_this_lv) {
if (!(lv_tmp = find_active_pvmoved_lv(sl->seg->lv)))
continue;
/* Preload this LV from precommitted metadata */
if (!(lv_pre_tmp = find_lv(lv_pre->vg, lv_tmp->name))) {
log_error(INTERNAL_ERROR "LV %s is missing from precommitted metadata.",
display_lvname(lv_tmp));
if (!(lv_pre_tmp = find_lv(lv_pre->vg, sl->seg->lv->name))) {
log_error(INTERNAL_ERROR "LV %s missing from preload metadata.",
display_lvname(sl->seg->lv));
goto out;
}
log_debug_activation("Preloading pvmoved LV %s for pvmove removal.",
display_lvname(lv_tmp));
if (!_lv_preload(lv_pre_tmp, laopts, &flush_required))
goto_out;
lv = lv_tmp; /* Prefer to suspend active pvmoved LV */
}
/* Now preload the PVMOVE LV itself */
if (!(lv_pre_tmp = find_lv(lv_pre->vg, pvmove_lv->name))) {
log_error(INTERNAL_ERROR "LV %s missing from preload metadata.",
display_lvname(pvmove_lv));
goto out;
}
log_debug_activation("Preloading PVMOVE LV %s for pvmove removal.",
display_lvname(lv_pre_tmp));
if (!_lv_preload(lv_pre_tmp, laopts, &flush_required))
goto_out;
} else {
/*
* PVMOVE operation requires different activation paths:
*
* Active LVs path:
* Suspend all active participating LVs and preload them from
* precommitted metadata, which inserts pvmove segments into
* the live device-mapper tree.
*
* Inactive LVs path:
* Simply activate the pvmove LV. Participating LVs will be
* activated with pvmove segments when accessed later.
*/
/* Suspending 1st. LV above PVMOVE suspends whole tree */
dm_list_iterate_items(sl, &pvmove_lv->segs_using_this_lv) {
lv = sl->seg->lv;
break;
}
} else {
if (!_lv_preload(lv_pre, laopts, &flush_required))
/* FIXME Revert preloading */
goto_out;
@@ -2312,15 +2231,70 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
&first_seg(lv)->external_lv->lvid.id[1], ID_LEN) != 0))))
lockfs = 1;
critical_section_inc(cmd, "suspending");
if (!lv_is_locked(lv) && lv_is_locked(lv_pre) &&
(pvmove_lv = find_pvmove_lv_in_lv(lv_pre))) {
/*
* When starting PVMOVE, suspend participating LVs first
* with committed metadata by looking at precommitted pvmove list.
* In committed metadata these LVs are not connected in any way.
*
* TODO: prepare list of LVs needed to be suspended and pass them
* via 'struct laopts' directly to _lv_suspend_lv() and handle this
* with a single 'dmtree' call.
*/
if (!(mem = dm_pool_create("suspend_lvs", 128)))
goto_out;
if (!_lv_suspend_lv(lv, laopts, lockfs, flush_required)) {
critical_section_dec(cmd, "failed suspend");
goto_out;
/* Prepare list of all LVs for suspend ahead */
dm_list_init(&suspend_lvs);
dm_list_iterate_items(sl, &pvmove_lv->segs_using_this_lv) {
lv_tmp = sl->seg->lv;
if (lv_is_cow(lv_tmp))
/* Never suspend COW, always has to be origin */
lv_tmp = origin_from_cow(lv_tmp);
found = 0;
dm_list_iterate_items(lvl, &suspend_lvs)
if (strcmp(lvl->lv->name, lv_tmp->name) == 0) {
found = 1;
break;
}
if (found)
continue; /* LV is already in the list */
if (!(lvl = dm_pool_alloc(mem, sizeof(*lvl)))) {
log_error("lv_list alloc failed.");
goto out;
}
/* Look for precommitted LV name in committed VG */
if (!(lvl->lv = find_lv(lv->vg, lv_tmp->name))) {
log_error(INTERNAL_ERROR "LV %s missing from preload metadata.",
display_lvname(lv_tmp));
goto out;
}
dm_list_add(&suspend_lvs, &lvl->list);
}
critical_section_inc(cmd, "suspending");
dm_list_iterate_items(lvl, &suspend_lvs)
if (!_lv_suspend_lv(lvl->lv, laopts, lockfs, 1)) {
critical_section_dec(cmd, "failed suspend");
goto_out; /* FIXME: resume on recovery path? */
}
} else { /* Standard suspend */
critical_section_inc(cmd, "suspending");
if (!_lv_suspend_lv(lv, laopts, lockfs, flush_required)) {
critical_section_dec(cmd, "failed suspend");
goto_out;
}
}
r = 1;
out:
if (mem)
dm_pool_destroy(mem);
return r;
}

View File

@@ -197,8 +197,6 @@ int lv_raid_mismatch_count(const struct logical_volume *lv, uint64_t *cnt);
int lv_raid_sync_action(const struct logical_volume *lv, char **sync_action);
int lv_raid_message(const struct logical_volume *lv, const char *msg);
int lv_raid_status(const struct logical_volume *lv, struct lv_status_raid **status);
int lv_raid_clear_failed_devices(const struct logical_volume *lv);
int lv_raid_count_failed_devices(const struct logical_volume *lv, uint32_t *failed_cnt);
int lv_writecache_message(const struct logical_volume *lv, const char *msg);
int lv_cache_status(const struct logical_volume *cache_lv,
struct lv_status_cache **status);

View File

@@ -47,18 +47,7 @@ typedef enum {
} action_t;
/* This list must match lib/misc/lvm-string.c:build_dm_uuid(). */
static const char * const _uuid_suffix_list[] = {
"cdata",
"cmeta",
"cvol",
"imeta",
"pool",
"tdata",
"tmeta",
"vdata",
"vpool",
NULL
};
static const char * const _uuid_suffix_list[] = { "pool", "cdata", "cmeta", "cvol", "tdata", "tmeta", "vdata", "vpool", "imeta", NULL};
struct dlid_list {
struct dm_list list;
@@ -701,7 +690,7 @@ static int _ignore_frozen_raid(struct device *dev, const char *params)
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 = NULL, *lvname = NULL, *layer = NULL;
char *vgname, *lvname, *layer;
char vg_name[NAME_LEN];
if (!check_reserved && !check_lv)
@@ -1018,6 +1007,28 @@ static int _info(struct cmd_context *cmd,
return 1;
}
int dev_manager_remove_dm_major_minor(uint32_t major, uint32_t minor)
{
struct dm_task *dmt;
int r = 0;
log_verbose("Removing dm dev %u:%u", major, minor);
if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
return_0;
if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
log_error("Failed to set device number for remove %u:%u", major, minor);
goto out;
}
r = dm_task_run(dmt);
out:
dm_task_destroy(dmt);
return r;
}
static int _info_by_dev(uint32_t major, uint32_t minor, struct dm_info *info)
{
return _info_run(NULL, info, NULL, NULL, NULL, 0, 0, major, minor);
@@ -2003,7 +2014,7 @@ int dev_manager_thin_device_id(struct dev_manager *dm,
if (dm_get_next_target(dmt, NULL, &start, &length,
&target_type, &params)) {
log_error("More than one table line found for %s.",
log_error("More then one table line found for %s.",
display_lvname(lv));
goto out;
}
@@ -2056,7 +2067,7 @@ int dev_manager_vdo_pool_status(struct dev_manager *dm,
display_lvname(lv));
if (dm_get_next_target(dmt, NULL, &start, &length, &type, &params)) {
log_error("More than one table line found for %s.",
log_error("More then one table line found for %s.",
display_lvname(lv));
goto out;
}
@@ -2110,7 +2121,7 @@ int dev_manager_vdo_pool_size_config(struct dev_manager *dm,
display_lvname(lv));
if (dm_get_next_target(dmt, NULL, &start, &length, &type, &params)) {
log_error("More than one table line found for %s.",
log_error("More then one table line found for %s.",
display_lvname(lv));
goto out;
}
@@ -2325,6 +2336,123 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
const struct logical_volume *lv,
struct lv_activate_opts *laopts,
const char *layer);
/*
* Check for device holders (ATM used only for removed pvmove targets)
* and add them into dtree structures.
* When 'laopts != NULL' add them as new nodes - which also corrects READ_AHEAD.
* Note: correct table are already explicitly PRELOADED.
*/
static int _check_holder(struct dev_manager *dm, struct dm_tree *dtree,
const struct logical_volume *lv,
struct lv_activate_opts *laopts,
uint32_t major, const char *d_name)
{
const char *default_uuid_prefix = dm_uuid_prefix();
const size_t default_uuid_prefix_len = strlen(default_uuid_prefix);
const char *name;
const char *uuid;
struct dm_info info;
struct dm_task *dmt;
struct logical_volume *lv_det;
union lvid id;
int dev, r = 0;
errno = 0;
dev = strtoll(d_name + 3, NULL, 10);
if (errno) {
log_error("Failed to parse dm device minor number from %s.", d_name);
return 0;
}
if (!(dmt = _setup_task_run(DM_DEVICE_INFO, &info, NULL, NULL, NULL,
major, dev, 0, 0, 0)))
return_0;
if (info.exists) {
uuid = dm_task_get_uuid(dmt);
name = dm_task_get_name(dmt);
log_debug_activation("Checking holder of %s %s (" FMTu32 ":" FMTu32 ") %s.",
display_lvname(lv), uuid, info.major, info.minor,
name);
/* Skip common uuid prefix */
if (!strncmp(default_uuid_prefix, uuid, default_uuid_prefix_len))
uuid += default_uuid_prefix_len;
if (!memcmp(uuid, &lv->vg->id, ID_LEN) &&
!dm_tree_find_node_by_uuid(dtree, uuid)) {
/* trims any UUID suffix (i.e. -cow) */
dm_strncpy((char*)&id, uuid, 2 * sizeof(struct id) + 1);
/* If UUID is not yet in dtree, look for matching LV */
if (!(lv_det = find_lv_in_vg_by_lvid(lv->vg, &id))) {
log_error("Cannot find holder with device name %s in VG %s.",
name, lv->vg->name);
goto out;
}
if (lv_is_cow(lv_det))
lv_det = origin_from_cow(lv_det);
log_debug_activation("Found holder %s of %s.",
display_lvname(lv_det),
display_lvname(lv));
if (!laopts) {
if (!_add_lv_to_dtree(dm, dtree, lv_det, 0))
goto_out;
} else if (!_add_new_lv_to_dtree(dm, dtree, lv_det, laopts, 0))
goto_out;
}
}
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
/*
* Add exiting devices which holds given LV device open.
* This is used in case when metadata already do not contain information
* i.e. PVMOVE is being finished and final table is going to be resumed.
*/
static int _add_holders_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
const struct logical_volume *lv,
struct lv_activate_opts *laopts,
const struct dm_info *info)
{
const char *sysfs_dir = dm_sysfs_dir();
char sysfs_path[PATH_MAX];
struct dirent *dirent;
DIR *d;
int r = 0;
/* Sysfs path of holders */
if (dm_snprintf(sysfs_path, sizeof(sysfs_path), "%sblock/dm-" FMTu32
"/holders", sysfs_dir, info->minor) < 0) {
log_error("sysfs_path dm_snprintf failed.");
return 0;
}
if (!(d = opendir(sysfs_path))) {
log_sys_error("opendir", sysfs_path);
return 0;
}
while ((dirent = readdir(d)))
/* Expects minor is added to 'dm-' prefix */
if (!strncmp(dirent->d_name, "dm-", 3) &&
!_check_holder(dm, dtree, lv, laopts, info->major, dirent->d_name))
goto_out;
r = 1;
out:
if (closedir(d))
log_sys_debug("closedir", "holders");
return r;
}
static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
const struct logical_volume *lv, const char *layer)
@@ -2393,6 +2521,15 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
return_0;
}
/*
* Find holders of existing active LV where name starts with 'pvmove',
* but it's not anymore PVMOVE LV and also it's not PVMOVE _mimage
*/
if (info.exists && !lv_is_pvmove(lv) &&
!strchr(lv->name, '_') && !strncmp(lv->name, "pvmove", 6))
if (!_add_holders_to_dtree(dm, dtree, lv, NULL, &info))
return_0;
return 1;
}
@@ -2636,10 +2773,9 @@ static int _add_cvol_subdev_to_dtree(struct dev_manager *dm, struct dm_tree *dtr
const struct logical_volume *pool_lv = lvseg->pool_lv;
struct dm_info info;
char *name ,*dlid;
union lvid lvid = { .id = { lv->vg->id, _get_id_for_meta_or_data(lvseg, meta_or_data) } };
lvid.s[sizeof(lvid.id)] = 0;
union lvid lvid = { { lv->vg->id, _get_id_for_meta_or_data(lvseg, meta_or_data) } };
if (!(dlid = dm_build_dm_uuid(mem, UUID_PREFIX, lvid.s, layer)))
if (!(dlid = dm_build_dm_uuid(mem, UUID_PREFIX, (const char *)&lvid.s, layer)))
return_0;
/* Name is actually not really needed here, but aids debugging... */
@@ -2817,10 +2953,9 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
if ((dm->track_pvmove_deps == 1) && lv_is_pvmove(lv)) {
dm->track_pvmove_deps = 2; /* Mark as already seen */
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
/* Check for lock holding LV to reload its whole device tree */
plv = lv_lock_holder(sl->seg->lv);
if (!_cached_dm_tree_node(dm->mem, dtree, plv, lv_layer(plv)) &&
!_add_lv_to_dtree(dm, dtree, plv, 0))
/* If LV is snapshot COW - whole snapshot needs reload */
plv = lv_is_cow(sl->seg->lv) ? origin_from_cow(sl->seg->lv) : sl->seg->lv;
if (!_add_lv_to_dtree(dm, dtree, plv, 0))
return_0;
}
dm->track_pvmove_deps = 1;
@@ -2885,11 +3020,6 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
return 1;
}
static void _set_optional_uuid_suffixes(struct dm_tree *dtree)
{
dm_tree_set_optional_uuid_suffixes(dtree, (const char**)_uuid_suffix_list);
}
static struct dm_tree *_create_partial_dtree(struct dev_manager *dm, const struct logical_volume *lv, int origin_only)
{
struct dm_tree *dtree;
@@ -2900,7 +3030,7 @@ static struct dm_tree *_create_partial_dtree(struct dev_manager *dm, const struc
return NULL;
}
_set_optional_uuid_suffixes(dtree);
dm_tree_set_optional_uuid_suffixes(dtree, (const char**)_uuid_suffix_list);
if (!_add_lv_to_dtree(dm, dtree, lv, (lv_is_origin(lv) || lv_is_thin_volume(lv) || lv_is_thin_pool(lv)) ? origin_only : 0))
goto_bad;
@@ -3296,10 +3426,9 @@ static int _add_new_cvol_subdev_to_dtree(struct dev_manager *dm,
const struct logical_volume *pool_lv = lvseg->pool_lv;
struct dm_tree_node *dnode;
char *dlid, *dlid_pool, *name;
union lvid lvid = { .id = { lv->vg->id, _get_id_for_meta_or_data(lvseg, meta_or_data) } };
lvid.s[sizeof(lvid.id)] = 0;
union lvid lvid = { { lv->vg->id, _get_id_for_meta_or_data(lvseg, meta_or_data) } };
if (!(dlid = dm_build_dm_uuid(dm->mem, UUID_PREFIX, lvid.s, layer)))
if (!(dlid = dm_build_dm_uuid(dm->mem, UUID_PREFIX, (const char *)&lvid.s, layer)))
return_0;
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, pool_lv->name, layer)))
@@ -3431,70 +3560,6 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
return 1;
}
/*
* Check if a visible LV is active but still uses a private "-real" UUID suffix.
*
* This situation occurs during certain operations like RAID leg splits,
* where an LV transitions from being an internal component (with "-real" suffix)
* to a public LV, but the device mapper device retains the old private UUID.
*
* This function detects such inconsistencies by:
* 1. Constructing a potential "-real" suffixed UUID for the given LV
* 2. Searching for an active device with that UUID but without "-real" in its name
* 3. If found, updating UUID parameter to use the private UUID
*
* Note: Such LVs should be deactivated and reactivated to use the correct public UUID.
*/
static int _lv_adjust_real_uuid(struct dev_manager *dm, struct dm_tree *dtree,
const struct logical_volume *lv,
char **dlid)
{
struct dm_tree_node *dnode;
const struct dm_info *dinfo;
const char *s;
char *uuid;
/* Only check visible LVs that are neither origin nor snapshot */
if (!lv_is_visible(lv) ||
lv_is_origin(lv) ||
lv_is_external_origin(lv) ||
lv_is_integrity_origin(lv) ||
lv_is_cow(lv))
return 1;
/* Currently only a few LV types can be RAID/mirror orphans, for example:
* legs cannot be cached, however old mirror log can be mirrored */
if (!lv_is_linear(lv) &&
!lv_is_striped(lv) &&
!lv_is_mirrored(lv) &&
!lv_is_error(lv) &&
!lv_is_zero(lv))
return 1;
if (!(uuid = build_dm_uuid(dm->mem, lv, "real")))
return_0;
/* Temporarily disable suffix masking. Exact match is required. */
dm_tree_set_optional_uuid_suffixes(dtree, NULL);
if ((dnode = dm_tree_find_node_by_uuid(dtree, uuid)) &&
(dinfo = dm_tree_node_get_info(dnode)) && dinfo->exists) {
s = strstr(dm_tree_node_get_name(dnode), "-real");
/* Ignore devices whose names end with "-real" suffix */
if (!s || s[5]) {
log_debug("Adjusting UUID to %s for LV %s active as %s.",
uuid, display_lvname(lv),
dm_tree_node_get_name(dnode));
*dlid = uuid;
}
}
/* Restore suffix handling. */
_set_optional_uuid_suffixes(dtree);
return 1;
}
static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
const struct logical_volume *lv, struct lv_activate_opts *laopts,
const char *layer)
@@ -3511,7 +3576,6 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
uint32_t read_ahead_flags = UINT32_C(0);
int save_pending_delete = dm->track_pending_delete;
int merge_in_progress = 0;
const struct logical_volume *lock_lv;
if (!(lvlayer = dm_pool_alloc(dm->mem, sizeof(*lvlayer)))) {
log_error("_add_new_lv_to_dtree: pool alloc failed for %s %s.",
@@ -3620,9 +3684,6 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
dm_tree_node_get_context(dnode))
return 1;
/* Use UUID with -real private suffix for such active LV. */
if (!layer && !_lv_adjust_real_uuid(dm, dtree, lv, &dlid))
return_0;
/*
* Add LV to dtree.
* If we're working with precommitted metadata, clear any
@@ -3739,6 +3800,17 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
!_pool_register_callback(dm, dnode, lv))
return_0;
/*
* Update tables for ANY PVMOVE holders for active LV where the name starts with 'pvmove',
* but it's not anymore PVMOVE LV and also it's not a PVMOVE _mimage LV.
* When resume happens, tables MUST be already preloaded with correct entries!
* (since we can't preload different table while devices are suspended)
*/
if (!lv_is_pvmove(lv) && !strncmp(lv->name, "pvmove", 6) && !strchr(lv->name, '_') &&
(dinfo = _cached_dm_info(dm->mem, dtree, lv, NULL)))
if (!_add_holders_to_dtree(dm, dtree, lv, laopts, dinfo))
return_0;
if (read_ahead == DM_READ_AHEAD_AUTO) {
/* we need RA at least twice a whole stripe - see the comment in md/raid0.c */
read_ahead = max_stripe_size * 2;
@@ -3752,16 +3824,9 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
/* Add any LVs referencing a PVMOVE LV unless told not to */
if (dm->track_pvmove_deps && lv_is_pvmove(lv))
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
lock_lv = lv_lock_holder(sl->seg->lv);
if ((lock_lv != sl->seg->lv) &&
_cached_dm_tree_node(dm->mem, dtree, lock_lv, NULL)) {
if (!_add_new_lv_to_dtree(dm, dtree, lock_lv, laopts, NULL))
return_0;
} else if (_cached_dm_tree_node(dm->mem, dtree, sl->seg->lv, NULL) &&
!_add_new_lv_to_dtree(dm, dtree, sl->seg->lv, laopts, NULL))
dm_list_iterate_items(sl, &lv->segs_using_this_lv)
if (!_add_new_lv_to_dtree(dm, dtree, sl->seg->lv, laopts, NULL))
return_0;
}
dm->track_pending_delete = save_pending_delete; /* restore */
@@ -4102,7 +4167,7 @@ int dev_manager_device_uses_vg(struct device *dev,
return r;
}
_set_optional_uuid_suffixes(dtree);
dm_tree_set_optional_uuid_suffixes(dtree, (const char**)_uuid_suffix_list);
if (!dm_tree_add_dev(dtree, MAJOR(dev->dev), MINOR(dev->dev))) {
log_error("Failed to add device %s (%u:%u) to dtree.",

View File

@@ -105,6 +105,8 @@ int dev_manager_execute(struct dev_manager *dm);
int dev_manager_device_uses_vg(struct device *dev,
struct volume_group *vg);
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_dm_active_devices(const char *prefix, struct dm_list **devs,
unsigned *devs_features);

View File

@@ -490,11 +490,7 @@ void fs_unlock(void)
{
/* Do not allow syncing device name with suspended devices */
if (!dm_get_suspended_counter()) {
if (!dm_udev_get_sync_support())
log_debug_activation("Not syncing device names (--noudevsync ? %d).",
dm_udev_get_checking());
else
log_debug_activation("Syncing device names");
log_debug_activation("Syncing device names");
/* Wait for all processed udev devices */
if (!dm_udev_wait(_fs_cookie))
stack;

120
lib/cache/lvmcache.c vendored
View File

@@ -21,6 +21,7 @@
#include "lib/device/device_id.h"
#include "lib/locking/locking.h"
#include "lib/metadata/metadata.h"
#include "lib/mm/memlock.h"
#include "lib/format_text/format-text.h"
#include "lib/config/config.h"
#include "lib/filters/filter.h"
@@ -314,7 +315,7 @@ 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);
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;
@@ -1890,7 +1891,7 @@ static int _lvmcache_update_vgname(struct cmd_context *cmd,
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);
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);
@@ -1953,7 +1954,7 @@ static int _lvmcache_update_vgname(struct cmd_context *cmd,
log_warn("WARNING: VG name %s is used by VGs %s and %s.",
vgname, vgid_dashed, other_dashed);
log_warn("WARNING: Fix duplicate VG names with vgrename uuid, or vgrename --devices.");
log_warn("Fix duplicate VG names with vgrename uuid, a device filter, or system IDs.");
}
if (!vginfo_is_allowed && !other_is_allowed) {
@@ -2096,17 +2097,12 @@ int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info
vgid = vgname;
}
/*
* This happens when vgremove does pv_write to make a PV
* that was previously part of a VG into a new orphan.
* FIXME: change pv_write to not use or update lvmcache,
* which should only be updated by label_scan.
*/
if (is_orphan_vg(vgname) && info->vginfo && !is_orphan_vg(info->vginfo->vgname)) {
log_debug("lvmcache change %s to orphan from previous VG %s.",
dev_name(info->dev), info->vginfo->vgname);
/* FIXME: remove this, it shouldn't be needed */
/* If PV without mdas is already in a real VG, don't make it orphan */
if (is_orphan_vg(vgname) && info->vginfo &&
mdas_empty_or_ignored(&info->mdas) &&
!is_orphan_vg(info->vginfo->vgname) && critical_section())
return 1;
}
/*
* Creates a new vginfo struct for this vgname/vgid if none exists,
@@ -2227,7 +2223,7 @@ int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info
*/
if ((vginfo->mda_size != vgsummary->mda_size) || (vginfo->mda_checksum != vgsummary->mda_checksum)) {
log_warn("WARNING: Scan of VG %s from %s mda%d found mda_checksum %x mda_size %zu vs %x %zu.",
log_warn("WARNING: scan of VG %s from %s mda%d found mda_checksum %x mda_size %zu vs %x %zu",
vgname, dev_name(info->dev), vgsummary->mda_num,
vgsummary->mda_checksum, vgsummary->mda_size,
vginfo->mda_checksum, vginfo->mda_size);
@@ -2269,7 +2265,7 @@ int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info
* using the 'vg'.
*/
void lvmcache_update_vg_from_read(struct volume_group *vg, int *incorrect_pv_claim)
int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted)
{
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
char vgid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
@@ -2289,11 +2285,9 @@ void lvmcache_update_vg_from_read(struct volume_group *vg, int *incorrect_pv_cla
if (!(vginfo = lvmcache_vginfo_from_vgname(vg->name, vgid))) {
log_error(INTERNAL_ERROR "lvmcache_update_vg %s no vginfo", vg->name);
return;
return 0;
}
log_debug_cache("lvmcache_update_vg %s vginfo from metadata", vg->name);
/*
* The label scan doesn't know when a PV with old metadata has been
* removed from the VG. Now with the vg we can tell, so remove the
@@ -2312,7 +2306,7 @@ void lvmcache_update_vg_from_read(struct volume_group *vg, int *incorrect_pv_cla
if (found)
continue;
log_warn("WARNING: Outdated PV %s seqno %u has been removed in current VG %s seqno %u.",
log_warn("WARNING: outdated PV %s seqno %u has been removed in current VG %s seqno %u.",
dev_name(info->dev), info->summary_seqno, vg->name, vginfo->seqno);
if (!_outdated_warning++)
@@ -2332,32 +2326,8 @@ void lvmcache_update_vg_from_read(struct volume_group *vg, int *incorrect_pv_cla
continue;
}
/*
* If this PV info is already attached to a different VG, don't
* override that. The info/vginfo map a PV to a VG based on the
* metadata which appears on the PV itself. That has precedence
* over a different mapping of PV to another VG (the vg arg here)
* which is likely outdated metadata from some other device.
*/
if (info->vginfo && !is_orphan_vg(info->vginfo->vgname) &&
(strcmp(info->vginfo->vgname, vg->name) || memcmp(info->vginfo->vgid, &vg->id, ID_LEN))) {
char vgid_old[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
char vgid_new[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
memcpy(vgid_old, &vg->id, ID_LEN);
memcpy(vgid_new, info->vginfo->vgid, ID_LEN);
if (!strcmp(info->vginfo->vgname, vg->name))
log_warn("WARNING: PV %s %s belongs to VGID %s, ignoring claim from VGID %s (%s).",
dev_name(info->dev), pvid, vgid_new, vgid_old, vg->name);
else
log_warn("WARNING: PV %s %s belongs to VG %s, ignoring claim from VG %s.",
dev_name(info->dev), pvid, info->vginfo->vgname, vg->name);
pvl->pv->wrong_vg = 1;
*incorrect_pv_claim = 1;
continue;
}
log_debug_cache("lvmcache_update_vg %s for %s", vg->name, dev_name(info->dev));
log_debug_cache("lvmcache_update_vg %s for info %s",
vg->name, dev_name(info->dev));
/*
* FIXME: use a different function that just attaches info's that
@@ -2379,7 +2349,7 @@ void lvmcache_update_vg_from_read(struct volume_group *vg, int *incorrect_pv_cla
* (since label_scan didn't know this without metadata.)
*/
dm_list_iterate_items(mda, &info->mdas) {
if (!_mda_is_ignored(mda))
if (!mda_is_ignored(mda))
continue;
log_debug("lvmcache_update_vg %s copy ignored mdas for %s", vg->name, dev_name(info->dev));
if (!lvmcache_fid_add_mdas_pv(info, vg->fid)) {
@@ -2389,6 +2359,8 @@ void lvmcache_update_vg_from_read(struct volume_group *vg, int *incorrect_pv_cla
break;
}
}
return 1;
}
/*
@@ -3145,16 +3117,6 @@ bool lvmcache_has_old_metadata(struct cmd_context *cmd, const char *vgname, cons
if (info->summary_seqno_mismatch)
return true;
/* shouldn't happen? */
if (!info->vginfo)
return false;
/* PV moved to a different VG between label_scan and this vg_write */
if (memcmp(info->vginfo->vgid, vgid, ID_LEN)) {
log_debug("lvmcache_has_old_metadata: PV in new VG %s", dev_name(dev));
return false;
}
/* one or both mdas on this dev has older metadata than another dev */
if (vginfo->seqno > info->summary_seqno)
return true;
@@ -3241,52 +3203,6 @@ bool lvmcache_is_outdated_dev(struct cmd_context *cmd,
return false;
}
/*
* Metadata is being processed which shows 'vg' containing 'pv'.
* Verify that this is consistent with the headers/metadata that
* were scanned from PV. The headers/metadata scanned from the
* actual PV could be different from what 'vg' metadata claims,
* if the 'vg' metadata is old/outdated.
*/
int lvmcache_verify_info_in_vg(struct volume_group *vg, struct lvmcache_info *info)
{
char vgid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
memcpy(vgid, &vg->id, ID_LEN);
if (!info->dev) {
log_error(INTERNAL_ERROR "Verify PV info in %s: skip, no dev", vg->name);
return 1;
}
if (!info->dev->pvid[0]) {
log_debug("Verify PV %s in %s: uncertain, no pvid",
dev_name(info->dev), vg->name);
return 1;
}
if (!info->vginfo) {
log_debug("Verify PV %s %s in %s: uncertain, no vginfo",
info->dev->pvid, dev_name(info->dev), vg->name);
return 1;
}
if (strcmp(vg->name, info->vginfo->vgname)) {
log_debug("Verify PV %s %s in %s: fail, other VG %s",
info->dev->pvid, dev_name(info->dev), vg->name, info->vginfo->vgname);
return 0;
}
if (memcmp(vgid, info->vginfo->vgid, ID_LEN)) {
log_debug("Verify PV %s %s in %s: fail, other vgid %s",
info->dev->pvid, dev_name(info->dev), vg->name, info->vginfo->vgid);
return 0;
}
return 1;
}
const char *dev_filtered_reason(struct device *dev)
{
if (dev->filtered_flags & DEV_FILTERED_REGEX)

View File

@@ -18,7 +18,7 @@
#include "lib/device/dev-cache.h"
#include "lib/device/dev-type.h"
#include "lib/id/id.h"
#include "lib/uuid/uuid.h"
#include "lib/label/label.h"
#include "lib/locking/locking.h"
@@ -83,7 +83,7 @@ void lvmcache_del_dev(struct device *dev);
/* Update things */
int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info *info,
struct lvmcache_vgsummary *vgsummary);
void lvmcache_update_vg_from_read(struct volume_group *vg, int *incorrect_pv_claim);
int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted);
void lvmcache_lock_vgname(const char *vgname, int read_only);
void lvmcache_unlock_vgname(const char *vgname);
@@ -190,8 +190,6 @@ void lvmcache_save_metadata_size(uint64_t val);
bool lvmcache_has_old_metadata(struct cmd_context *cmd, const char *vgname, const char *vgid, struct device *dev);
int lvmcache_verify_info_in_vg(struct volume_group *vg, struct lvmcache_info *info);
void lvmcache_get_outdated_devs(struct cmd_context *cmd,
const char *vgname, const char *vgid,
struct dm_list *devs);

View File

@@ -12,7 +12,7 @@
enum {
#define cmd(a, b) a ,
#include "cmds.h"
#include "include/cmds.h"
#undef cmd
};

View File

@@ -82,7 +82,7 @@ const char *system_id_from_string(struct cmd_context *cmd, const char *str)
}
if (!strncmp(system_id, "localhost", 9)) {
log_warn("WARNING: System ID may not begin with the string \"localhost\".");
log_warn("WARNING: system ID may not begin with the string \"localhost\".");
return NULL;
}
@@ -614,7 +614,7 @@ static int _init_system_id(struct cmd_context *cmd)
return 1;
}
static int _init_device_ids_refresh(struct cmd_context *cmd)
static void _init_device_ids_refresh(struct cmd_context *cmd)
{
const struct dm_config_node *cn;
const struct dm_config_value *cv;
@@ -622,21 +622,14 @@ static int _init_device_ids_refresh(struct cmd_context *cmd)
int check_hostname = 0;
char path[PATH_MAX];
char uuid[128] = { 0 };
int val;
cmd->device_ids_check_product_uuid = 0;
cmd->device_ids_check_hostname = 0;
if (!(val = find_config_tree_int(cmd, devices_device_ids_refresh_CFG, NULL)))
return 1;
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 1;
/* 0 disables, 1 enables single refresh, 10-600 enables refresh period */
if ((val > 1 && val < 10) || (val > 600)) {
log_error("Invalid device_ids_refresh value %u", val);
return 0;
}
return;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING)
@@ -650,7 +643,7 @@ static int _init_device_ids_refresh(struct cmd_context *cmd)
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_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)
@@ -659,7 +652,6 @@ static int _init_device_ids_refresh(struct cmd_context *cmd)
if (check_hostname && cmd->hostname)
cmd->device_ids_check_hostname = 1;
return 1;
}
static int _process_config(struct cmd_context *cmd)
@@ -704,7 +696,7 @@ static int _process_config(struct cmd_context *cmd)
if (dev_ext_info_src &&
strcmp(dev_ext_info_src, "none") &&
strcmp(dev_ext_info_src, "udev")) {
log_warn("WARNING: Unknown external device info source, using none.");
log_warn("WARNING: unknown external device info source, using none.");
dev_ext_info_src = NULL;
}
@@ -712,7 +704,7 @@ static int _process_config(struct cmd_context *cmd)
if (udev_init_library_context()) {
init_external_device_info_source(DEV_EXT_UDEV);
} else {
log_warn("WARNING: Failed to init udev for external device info, using none.");
log_warn("WARNING: failed to init udev for external device info, using none.");
dev_ext_info_src = NULL;
}
}
@@ -728,7 +720,7 @@ static int _process_config(struct cmd_context *cmd)
}
if (*cmd->proc_dir && !dir_exists(cmd->proc_dir)) {
log_warn("WARNING: proc dir %s not found - some checks will be bypassed.",
log_warn("WARNING: proc dir %s not found - some checks will be bypassed",
cmd->proc_dir);
cmd->proc_dir[0] = '\0';
}
@@ -801,13 +793,13 @@ static int _process_config(struct cmd_context *cmd)
else if (strcmp(cmd->stripe_filler, "error") &&
strcmp(cmd->stripe_filler, "zero")) {
if (stat(cmd->stripe_filler, &st)) {
log_warn("WARNING: activation/missing_stripe_filler = \"%s\"."
log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
"is invalid,", cmd->stripe_filler);
log_warn(" stat failed: %s", strerror(errno));
log_warn("Falling back to \"error\" missing_stripe_filler.");
cmd->stripe_filler = "error";
} else if (!S_ISBLK(st.st_mode)) {
log_warn("WARNING: activation/missing_stripe_filler = \"%s\"."
log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
"is not a block device.", cmd->stripe_filler);
log_warn("Falling back to \"error\" missing_stripe_filler.");
cmd->stripe_filler = "error";
@@ -842,8 +834,7 @@ static int _process_config(struct cmd_context *cmd)
if (!_init_system_id(cmd))
return_0;
if (!_init_device_ids_refresh(cmd))
return_0;
_init_device_ids_refresh(cmd);
init_io_memory_size(find_config_tree_int(cmd, global_io_memory_size_CFG, NULL));
@@ -1195,7 +1186,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
return 1;
}
#define MAX_FILTERS 20
#define MAX_FILTERS 10
static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
{

View File

@@ -73,8 +73,7 @@ struct cmd_context_initialized_parts {
};
struct cmd_report {
unsigned log_only:1;
unsigned lc_numeric_override:1;
int log_only;
dm_report_group_type_t report_group_type;
struct dm_report_group *report_group;
struct dm_report *log_rh;
@@ -224,10 +223,8 @@ struct cmd_context {
unsigned device_ids_refresh_trigger:1;
unsigned device_ids_invalid:1;
unsigned device_ids_auto_import:1;
unsigned device_ids_read_refresh:1; /* device_ids_read found REFRESH_UNTIL */
unsigned get_vgname_from_options:1; /* used by lvconvert */
unsigned vg_write_validates_vg:1;
unsigned disable_pr_required:1;
/*
* Devices and filtering.
@@ -237,7 +234,6 @@ struct cmd_context {
const char *md_component_checks;
const char *search_for_devnames; /* config file setting */
struct dm_list device_ids_check_serial;
uint64_t device_ids_refresh_until; /* timestamp of YYYYMMDDHHMMSS */
const char *devicesfile; /* from --devicesfile option */
struct dm_list deviceslist; /* from --devices option, struct dm_str_list */

View File

@@ -522,7 +522,6 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
/* Note: also used for lvm.conf to read all settings */
for (rsize = 0; rsize < size; rsize += sz) {
do {
/* coverity[overflow_sink] - only positive 'sz' is used */
sz = read(dev_fd(dev), buf + rsize, size - rsize);
} while ((sz < 0) && ((errno == EINTR) || (errno == EAGAIN)));
@@ -1753,7 +1752,7 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
if (cn->id <= 0)
return 1;
if (out->tree_spec->listmode)
if (out->tree_spec->type == CFG_DEF_TREE_LIST)
return 1;
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
@@ -1835,55 +1834,50 @@ static int _should_print_cfg_with_undef_def_val(struct out_baton *out, const cfg
return out->tree_spec->check_status && (out->tree_spec->check_status[cn->id] & CFG_USED);
}
static int _out_line_list(const struct dm_config_node *cn, const char *line, struct out_baton *out)
static int _out_line_fn(const struct dm_config_node *cn, const char *line, void *baton)
{
struct out_baton *out = baton;
const struct cfg_def_item *cfg_def;
char config_path[CFG_PATH_MAX_LEN];
char summary[MAX_COMMENT_LINE+1];
char version[9];
const struct cfg_def_item *cfg_def;
int pos = 0;
const char *val = NULL;
cfg_def = cfg_def_get_item_p(cn->id);
if (cfg_def->type & CFG_TYPE_SECTION)
return 1;
if (!_cfg_def_make_path(config_path, CFG_PATH_MAX_LEN, cfg_def->id, cfg_def, 1))
return_0;
if (out->tree_spec->withversions && !_get_config_node_version(cfg_def->since_version, version))
return_0;
summary[0] = '\0';
if (out->tree_spec->withsummary && cfg_def->comment)
_copy_one_line(cfg_def->comment, summary, &pos, strlen(cfg_def->comment));
if (out->tree_spec->type != CFG_DEF_TREE_LIST) {
if (!(val = strrchr(line, '=')))
return 0;
}
fprintf(out->fp, "%s%s%s%s%s%s%s%s\n", config_path, val ? val : "",
*summary || out->tree_spec->withversions ? " - ": "",
*summary ? summary : "",
*summary ? " " : "",
out->tree_spec->withversions ? "[" : "",
out->tree_spec->withversions ? version : "",
out->tree_spec->withversions ? "]" : "");
return 1;
}
static int _out_line_tree(const struct dm_config_node *cn, const char *line, struct out_baton *out)
{
const struct cfg_def_item *cfg_def;
int space_prefix_len = 0;
const char *p;
size_t len;
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
return 1;
cfg_def = cfg_def_get_item_p(cn->id);
if (out->tree_spec->type == CFG_DEF_TREE_LIST) {
/* List view with node paths and summary. */
if (cfg_def->type & CFG_TYPE_SECTION)
return 1;
if (!_cfg_def_make_path(config_path, CFG_PATH_MAX_LEN, cfg_def->id, cfg_def, 1))
return_0;
if (out->tree_spec->withversions && !_get_config_node_version(cfg_def->since_version, version))
return_0;
summary[0] = '\0';
if (out->tree_spec->withsummary && cfg_def->comment)
_copy_one_line(cfg_def->comment, summary, &pos, strlen(cfg_def->comment));
fprintf(out->fp, "%s%s%s%s%s%s%s\n", config_path,
*summary || out->tree_spec->withversions ? " - ": "",
*summary ? summary : "",
*summary ? " " : "",
out->tree_spec->withversions ? "[" : "",
out->tree_spec->withversions ? version : "",
out->tree_spec->withversions ? "]" : "");
return 1;
}
/* 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);
@@ -1926,21 +1920,6 @@ static int _out_line_tree(const struct dm_config_node *cn, const char *line, str
dm_pool_free(out->mem, (char *) line);
return 1;
}
static int _out_line_fn(const struct dm_config_node *cn, const char *line, void *baton)
{
struct out_baton *out = baton;
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
return 1;
if (out->tree_spec->listmode)
return _out_line_list(cn, line, out);
return _out_line_tree(cn, line, out);
}
static int _out_suffix_fn(const struct dm_config_node *cn, const char *line, void *baton)
@@ -2552,10 +2531,10 @@ const char *get_default_activation_mirror_image_fault_policy_CFG(struct cmd_cont
int get_default_allocation_thin_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile)
{
uint32_t chunk_size;
unsigned chunk_size_calc_policy;
int chunk_size_calc_method;
if (!get_default_allocation_thin_pool_chunk_size(cmd, profile, &chunk_size,
&chunk_size_calc_policy)) {
&chunk_size_calc_method)) {
stack; /* Ignore this error, never happens... */
chunk_size = DEFAULT_THIN_POOL_CHUNK_SIZE * 2;
}

View File

@@ -177,7 +177,6 @@ struct config_def_tree_spec {
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 */
unsigned listmode:1; /* print in list mode instead of structured tree mode */
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
};

View File

@@ -215,7 +215,7 @@ cfg(config_checks_CFG, "checks", config_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_
"found is issued in verbose mode only).\n")
cfg(config_validate_metadata_CFG, "validate_metadata", config_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_VALIDATE_METADATA, vsn(2, 3, 28), NULL, 0, NULL,
"Allows selecting the level of validation after metadata transformation.\n"
"Allows to select the level of validation after metadata transformation.\n"
"Validation takes extra CPU time to verify internal consistency.\n"
"Accepted values:\n"
" full\n"
@@ -235,7 +235,7 @@ cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADV
"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")
"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")
@@ -324,19 +324,13 @@ 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_INT, DEFAULT_DEVICE_IDS_REFRESH, vsn(2, 3, 23), NULL, 0, NULL,
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"
"See device_ids_refresh_check for conditions that trigger the refresh.\n"
"Set to 1 to enable a single automatic refresh attempt when a trigger\n"
"condition is detected. Set to 0 to disable automatic refresh.\n"
"Set to a value between 10 and 600 (in seconds) to enable an extended\n"
"refresh period during which missing PVs will be located using the PVID,\n"
"and the system.devices device ID updated if the PV is found on a new device.\n"
"An extended refresh period may be useful if devices require refresh,\n"
"but are attached to the system some time the initial refresh.\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"
@@ -359,7 +353,7 @@ cfg_array(devices_filter_CFG, "filter", devices_CFG_SECTION, CFG_DEFAULT_COMMENT
"device is rejected. Unmatching path names do not affect the accept\n"
"or reject decision. If no path names for a device match a pattern,\n"
"then the device is accepted. Be careful mixing 'a' and 'r' patterns,\n"
"as the combination might produce unexpected results (test changes).\n"
"as the combination might produce unexpected results (test changes.)\n"
"Run vgscan after changing the filter to regenerate the cache.\n"
"#\n"
"Example\n"
@@ -407,7 +401,7 @@ cfg_array(devices_types_CFG, "types", devices_CFG_SECTION, CFG_DEFAULT_UNDEFINED
cfg(devices_sysfs_scan_CFG, "sysfs_scan", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_SYSFS_SCAN, vsn(1, 0, 8), NULL, 0, NULL,
"Restrict device scanning to block devices appearing in sysfs.\n"
"This is a quick way of filtering out block devices that are not\n"
"present on the system. sysfs must be part of the kernel and mounted.\n")
"present on the system. sysfs must be part of the kernel and mounted.)\n")
cfg(devices_scan_lvs_CFG, "scan_lvs", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_SCAN_LVS, vsn(2, 2, 182), NULL, 0, NULL,
"Allow LVM LVs to be used as PVs. When enabled, LVM commands will\n"
@@ -415,7 +409,7 @@ cfg(devices_scan_lvs_CFG, "scan_lvs", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED
"avoid using PVs that belong to guest images stored on LVs.\n"
"When enabled, the LVs scanned should be restricted using the\n"
"devices file or the filter. This option does not enable autoactivation\n"
"of layered VGs, which requires editing LVM udev rules (see LVM_PVSCAN_ON_LVS).\n")
"of layered VGs, which requires editing LVM udev rules (see LVM_PVSCAN_ON_LVS.)\n")
cfg(devices_multipath_component_detection_CFG, "multipath_component_detection", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_MULTIPATH_COMPONENT_DETECTION, vsn(2, 2, 89), NULL, 0, NULL,
"Ignore devices that are components of DM multipath devices.\n")
@@ -477,7 +471,7 @@ cfg(devices_data_alignment_detection_CFG, "data_alignment_detection", devices_CF
"penalty, e.g. MD chunk size. optimal_io_size is the device's\n"
"preferred unit of receiving I/O, e.g. MD stripe width.\n"
"minimum_io_size is used if optimal_io_size is undefined (0).\n"
"If md_chunk_alignment is enabled, it will detect the optimal_io_size.\n"
"If md_chunk_alignment is enabled, that detects the optimal_io_size.\n"
"default_data_alignment and md_chunk_alignment will be overridden\n"
"if they are not aligned with the value detected for this setting.\n"
"This setting is overridden by data_alignment and the --dataalignment\n"
@@ -536,16 +530,16 @@ cfg(devices_pv_min_size_CFG, "pv_min_size", devices_CFG_SECTION, CFG_DEFAULT_COM
"value was 512.\n")
cfg(devices_issue_discards_CFG, "issue_discards", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ISSUE_DISCARDS, vsn(2, 2, 85), NULL, 0, NULL,
"Issue discard commands to physical volumes when freeing space.\n"
"When an LV frees space on a PV (e.g., lvremove, lvreduce), LVM can\n"
"send discard commands to notify the storage device that those blocks\n"
"are no longer in use. NVMe/SSDs use this information for TRIM operations\n"
"to improve performance and longevity. Thinly provisioned storage uses\n"
"UNMAP to reclaim the freed space. Discards are issued using the\n"
"protocol supported by the device (TRIM, UNMAP, or WRITE SAME with\n"
"UNMAP bit set) and only when both the storage and kernel support it.\n"
"Warning: vgcfgrestore restores only VG metadata, not LV data. Any\n"
"data in discarded regions will be lost.\n")
"Issue discards to PVs that are no longer used by an LV.\n"
"Discards are sent to an LV's underlying physical volumes when the LV\n"
"is no longer using the physical volumes' space, e.g. lvremove,\n"
"lvreduce. Discards inform the storage that a region is no longer\n"
"used. Storage that supports discards advertise the protocol-specific\n"
"way discards should be issued by the kernel (TRIM, UNMAP, or\n"
"WRITE SAME with UNMAP bit set). Not all storage will support or\n"
"benefit from discards, but SSDs and thinly provisioned LUNs\n"
"generally do. If enabled, discards will only be issued if both the\n"
"storage and kernel provide support.\n")
cfg(devices_allow_changes_with_duplicate_pvs_CFG, "allow_changes_with_duplicate_pvs", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ALLOW_CHANGES_WITH_DUPLICATE_PVS, vsn(2, 2, 153), NULL, 0, NULL,
"Allow VG modification while a PV appears on multiple devices.\n"
@@ -610,7 +604,7 @@ cfg(allocation_wipe_signatures_when_zeroing_new_lvs_CFG, "wipe_signatures_when_z
"is not claimed incorrectly by other tools because of old signatures\n"
"from previous use. The number of signatures that LVM can detect\n"
"depends on the detection code that is selected (see\n"
"use_blkid_wiping). Wiping each detected signature must be confirmed.\n"
"use_blkid_wiping.) Wiping each detected signature must be confirmed.\n"
"When this setting is disabled, signatures on new LVs are not detected\n"
"or erased unless the --wipesignatures option is used directly.\n")
@@ -638,7 +632,7 @@ cfg(allocation_cache_metadata_format_CFG, "cache_metadata_format", allocation_CF
"Accepted values:\n"
" 0 Automatically detected best available format\n"
" 1 Original format\n"
" 2 Improved second-generation format\n"
" 2 Improved 2nd. generation format\n"
"#\n")
cfg(allocation_cache_mode_CFG, "cache_mode", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_MODE, vsn(2, 2, 128), NULL, 0, NULL,
@@ -682,22 +676,13 @@ cfg(allocation_cache_pool_max_chunks_CFG, "cache_pool_max_chunks", allocation_CF
"For cache target v1.9 the recommended maximum is 1000000 chunks.\n"
"Using cache pool with more chunks may degrade cache performance.\n")
cfg(allocation_pvmove_max_segment_size_mb_CFG, "pvmove_max_segment_size_mb", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_PVMOVE_MAX_SEGMENT_SIZE_MB, vsn(2, 3, 36), NULL, 0, NULL,
"Maximum size in MiB of segments to mirror at once during pvmove.\n"
"When pvmove needs to move large segments, it will split them into\n"
"smaller chunks of this size, mirror each chunk, and update metadata\n"
"between chunks. This prevents mirroring excessively large amounts\n"
"of data at once. A value of 0 (default) means no limit - the entire\n"
"segment will be mirrored at once. Setting this to e.g. 10240 will\n"
"limit each mirroring operation to 10GiB chunks.\n")
cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 89), NULL, 0, NULL,
"Thin pool metadata and data will always use different PVs.\n")
cfg(allocation_thin_pool_crop_metadata_CFG, "thin_pool_crop_metadata", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_CROP_METADATA, vsn(2, 3, 12), NULL, 0, NULL,
"Older versions of lvm2 cropped pool's metadata size to 15.81 GiB.\n"
"This is slightly less than the actual maximum 15.88 GiB.\n"
"For compatibility with older versions and to use the cropped size, set to 1.\n")
"Older version of lvm2 cropped pool's metadata size to 15.81 GiB.\n"
"This is slightly less then the actual maximum 15.88 GiB.\n"
"For compatibility with older version and use of cropped size set to 1.\n")
cfg(allocation_thin_pool_zero_CFG, "thin_pool_zero", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_ZERO, vsn(2, 2, 99), NULL, 0, NULL,
"Thin pool data chunks are zeroed before they are first used.\n"
@@ -963,7 +948,7 @@ cfg(log_prefix_CFG, "prefix", log_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ALLOW
cfg(log_activation_CFG, "activation", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(1, 0, 0), NULL, 0, NULL,
"Log messages during activation.\n"
"Do not use this in low memory situations (can deadlock).\n")
"Don't use this in low memory situations (can deadlock).\n")
cfg(log_activate_file_CFG, "activate_file", log_CFG_SECTION, CFG_DEFAULT_UNDEFINED | CFG_UNSUPPORTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
@@ -1098,7 +1083,7 @@ cfg(global_metadata_read_only_CFG, "metadata_read_only", global_CFG_SECTION, CFG
"Additionally, read-only commands that encounter metadata in need of\n"
"repair will still be allowed to proceed exactly as if the repair had\n"
"been performed (except for the unchanged vg_seqno). Inappropriate\n"
"use could corrupt your system, so seek advice first!\n")
"use could mess up your system, so seek advice first!\n")
cfg(global_mirror_segtype_default_CFG, "mirror_segtype_default", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_MIRROR_SEGTYPE, vsn(2, 2, 87), "@DEFAULT_MIRROR_SEGTYPE@", 0, NULL,
"The segment type used by the short mirroring option -m.\n"
@@ -1128,7 +1113,7 @@ cfg(global_mirror_segtype_default_CFG, "mirror_segtype_default", global_CFG_SECT
cfg(global_support_mirrored_mirror_log_CFG, "support_mirrored_mirror_log", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 3, 2), NULL, 0, NULL,
"Enable mirrored 'mirror' log type for testing.\n"
"#\n"
"This type is deprecated for creation or conversion but can\n"
"This type is deprecated to create or convert to but can\n"
"be enabled to test that activation of existing mirrored\n"
"logs and conversion to disk/core works.\n"
"#\n"
@@ -1217,7 +1202,7 @@ cfg(global_sanlock_lv_extend_CFG, "sanlock_lv_extend", global_CFG_SECTION, CFG_D
cfg(global_sanlock_align_size_CFG, "sanlock_align_size", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_SANLOCK_ALIGN_SIZE, vsn(2, 3, 27), NULL, 0, NULL,
"The sanlock lease size in MiB to use on disks with a 4K sector size.\n"
"Possible values are 1,2,4,8. The default is 8, which supports up to\n"
"2000 hosts (and max host_id 2000). Smaller values support smaller\n"
"2000 hosts (and max host_id 2000.) Smaller values support smaller\n"
"numbers of max hosts (and max host_ids): 250, 500, 1000, 2000 for\n"
"lease sizes 1,2,4,8. Disks with 512 byte sectors always use 1MiB\n"
"leases and support 2000 hosts, and are not affected by this setting.\n")
@@ -1225,7 +1210,7 @@ cfg(global_sanlock_align_size_CFG, "sanlock_align_size", global_CFG_SECTION, CFG
cfg(global_lvmlockctl_kill_command_CFG, "lvmlockctl_kill_command", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "", vsn(2, 3, 12), NULL, 0, NULL,
"The command that lvmlockctl --kill should use to force LVs offline.\n"
"The lvmlockctl --kill command is run when a shared VG has lost\n"
"access to locks (e.g. when sanlock has lost access to storage).\n"
"access to locks (e.g. when sanlock has lost access to storage.)\n"
"An empty string means that there will be no automatic attempt by\n"
"lvmlockctl --kill to forcibly shut down LVs in the VG, and the user\n"
"can manually intervene as described in lvmlockd(8).\n"
@@ -1347,14 +1332,10 @@ cfg(global_fsadm_executable_CFG, "fsadm_executable", global_CFG_SECTION, CFG_DEF
"The full path to the fsadm command.\n"
"LVM uses this command to help with lvresize -r operations.\n")
cfg(global_lvresize_fs_helper_executable_CFG, "lvresize_fs_helper_executable", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_LVRESIZE_FS_HELPER_PATH, vsn(2, 3, 33), "@LVRESIZE_FS_HELPER_PATH@", 0, NULL,
"The full path to the lvresize_fs_helper command.\n"
"LVM uses this command to help with filesystem operations during lvresize.\n")
cfg(global_system_id_source_CFG, "system_id_source", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_SYSTEM_ID_SOURCE, vsn(2, 2, 117), NULL, 0, NULL,
"The method LVM uses to set the local system ID.\n"
"Volume Groups can also be given a system ID (by vgcreate, vgchange,\n"
"or vgimport). A VG on shared storage devices is accessible only to\n"
"or vgimport.) A VG on shared storage devices is accessible only to\n"
"the host with a matching system ID. See 'man lvmsystemid' for\n"
"information on limitations and correct usage.\n"
"#\n"
@@ -1658,7 +1639,7 @@ cfg(activation_mirror_device_fault_policy_CFG, "mirror_device_fault_policy", act
cfg(activation_snapshot_autoextend_threshold_CFG, "snapshot_autoextend_threshold", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD, vsn(2, 2, 75), NULL, 0, NULL,
"Auto-extend a snapshot when its usage exceeds this percent.\n"
"Setting this to 100 disables automatic extension.\n"
"The minimum value is 50 (a smaller value is treated as 50).\n"
"The minimum value is 50 (a smaller value is treated as 50.)\n"
"Also see snapshot_autoextend_percent.\n"
"Automatic extension requires dmeventd to be monitoring the LV.\n"
"#\n"
@@ -1684,7 +1665,7 @@ cfg(activation_snapshot_autoextend_percent_CFG, "snapshot_autoextend_percent", a
cfg(activation_thin_pool_autoextend_threshold_CFG, "thin_pool_autoextend_threshold", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_INT, DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD, vsn(2, 2, 89), NULL, 0, NULL,
"Auto-extend a thin pool when its usage exceeds this percent.\n"
"Setting this to 100 disables automatic extension.\n"
"The minimum value is 50 (a smaller value is treated as 50).\n"
"The minimum value is 50 (a smaller value is treated as 50.)\n"
"Also see thin_pool_autoextend_percent.\n"
"Automatic extension requires dmeventd to be monitoring the LV.\n"
"#\n"
@@ -1710,7 +1691,7 @@ cfg(activation_thin_pool_autoextend_percent_CFG, "thin_pool_autoextend_percent",
cfg(activation_vdo_pool_autoextend_threshold_CFG, "vdo_pool_autoextend_threshold", activation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_POOL_AUTOEXTEND_THRESHOLD, VDO_1ST_VSN, NULL, 0, NULL,
"Auto-extend a VDO pool when its usage exceeds this percent.\n"
"Setting this to 100 disables automatic extension.\n"
"The minimum value is 50 (a smaller value is treated as 50).\n"
"The minimum value is 50 (a smaller value is treated as 50.)\n"
"Also see vdo_pool_autoextend_percent.\n"
"Automatic extension requires dmeventd to be monitoring the LV.\n"
"#\n"
@@ -1902,7 +1883,7 @@ cfg(report_output_format_CFG, "output_format", report_CFG_SECTION, CFG_PROFILABL
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"
"If enabled, all fields that do not have a value set for any of the\n"
"If enabled, all fields that don't have a value set for any of the\n"
"rows reported are skipped and not printed. Compact output is\n"
"applicable only if report/buffered is enabled. If you need to\n"
"compact only specified fields, use compact_output=0 and define\n"
@@ -1910,7 +1891,7 @@ cfg(report_compact_output_CFG, "compact_output", report_CFG_SECTION, CFG_PROFILA
cfg(report_compact_output_cols_CFG, "compact_output_cols", report_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_COMPACT_OUTPUT_COLS, vsn(2, 2, 133), NULL, 0, NULL,
"Do not print empty values for specified report fields.\n"
"If defined, specified fields that do not have a value set for any\n"
"If defined, specified fields that don't have a value set for any\n"
"of the rows reported are skipped and not printed. Compact output\n"
"is applicable only if report/buffered is enabled. If you need to\n"
"compact all fields, use compact_output=1 instead in which case\n"
@@ -2294,12 +2275,6 @@ cfg(local_system_id_CFG, "system_id", local_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_D
"system_id = \"host1\"\n"
"#\n")
cfg(local_pr_key_CFG, "pr_key", local_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, 0, vsn(2, 3, 32), NULL, 0, NULL,
"The local persistent reservation key in hexadecimal.\n"
"The value must be unique among all hosts using the same VG.\n"
"The max length is 16 hex characters (8 bytes), plus an optional\n"
"0x prefix. If pr_key is not set, host_id will be used to create a key.\n")
cfg_array(local_extra_system_ids_CFG, "extra_system_ids", local_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 117), NULL, 0, NULL,
"A list of extra VG system IDs the local host can access.\n"
"VGs with the system IDs listed here (in addition to the host's own\n"
@@ -2313,8 +2288,6 @@ cfg(local_host_id_CFG, "host_id", local_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_
"The sanlock host_id used by lvmlockd. This must be unique among all the hosts\n"
"using shared VGs with sanlock. Accepted values are 1-2000, except when sanlock_align_size\n"
"is configured to 1, 2 or 4, which correspond to max host_id values of 250, 500, or 1000.\n"
"When using persistent reservations, lvm will generate a PR key from the host_id\n"
"if pr_key is not defined. All hosts using a sanlock shared VG with PR must use\n"
"the same approach for configuring their PR key (pr_key or host_id.)\n")
"Applicable only if LVM is compiled with support for lvmlockd+sanlock.\n")
cfg(CFG_COUNT, NULL, root_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(0, 0, 0), NULL, 0, NULL, NULL)

View File

@@ -161,8 +161,6 @@
#define DEFAULT_CACHE_METADATA_FORMAT CACHE_METADATA_FORMAT_UNSELECTED /* Autodetect */
#define DEFAULT_CACHE_MODE "writethrough"
#define DEFAULT_PVMOVE_MAX_SEGMENT_SIZE_MB 0
/* VDO defaults */
#define DEFAULT_VDO_USE_COMPRESSION (true)
@@ -194,7 +192,6 @@
#define DEFAULT_FSADM_PATH FSADM_PATH
#define DEFAULT_LVRESIZE_FS_HELPER_PATH LVRESIZE_FS_HELPER_PATH
#define DEFAULT_UMASK 0077
@@ -348,6 +345,4 @@
#define DEFAULT_DEVICESFILE_BACKUP_LIMIT 50
#define DEFAULT_DEVICE_IDS_REFRESH 10
#endif /* _LVM_DEFAULTS_H */

View File

@@ -92,7 +92,7 @@ static void _cb_set_destroy(struct cb_set *cbs)
// never be in flight IO.
if (!dm_list_empty(&cbs->allocated)) {
// bail out
log_warn("WARNING: Async io still in flight.");
log_warn("WARNING: async io still in flight.");
return;
}
@@ -131,7 +131,6 @@ struct async_engine {
io_context_t aio_context;
struct cb_set *cbs;
unsigned page_mask;
pid_t aio_context_pid; /* PID that created this AIO context */
};
static struct async_engine *_to_async(struct io_engine *e)
@@ -141,24 +140,15 @@ static struct async_engine *_to_async(struct io_engine *e)
static void _async_destroy(struct io_engine *ioe)
{
int r;
struct async_engine *e = _to_async(ioe);
_cb_set_destroy(e->cbs);
/*
* Only call io_destroy() if we're in the same process that created
* the AIO context. After fork(), the child inherits the parent's
* aio_context value but must not call io_destroy() on it.
*/
if (e->aio_context) {
if (e->aio_context_pid != getpid())
log_debug_devs("Skipping AIO context destroy for different pid.");
else {
log_debug_devs("Destroy AIO context.");
if (io_destroy(e->aio_context)) // really slow (~40ms)
log_sys_warn("io_destroy");
}
}
// io_destroy is really slow
r = io_destroy(e->aio_context);
if (r)
log_sys_warn("io_destroy");
free(e);
}
@@ -386,7 +376,6 @@ struct io_engine *create_async_io_engine(void)
e->e.max_io = _async_max_io;
e->aio_context = 0;
e->aio_context_pid = getpid();
r = io_setup(MAX_IO, &e->aio_context);
if (r < 0) {
log_debug("io_setup failed %d", r);

View File

@@ -407,7 +407,7 @@ out:
/* Change bit ordering for devno to generate more compact bTree */
static inline uint32_t _shuffle_devno(dev_t d)
{
return htobe32(d);
return cpu_to_be32(d);
//return (d & 0xff) << 24 | (d & 0xff00) << 8 | (d & 0xff0000) >> 8 | (d & 0xff000000) >> 24;
//return (d & 0xff000000) >> 24 | (d & 0xffff00) | ((d & 0xff) << 24);
//return (uint32_t) d;
@@ -1715,7 +1715,7 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
* 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 %u:%u %s.",
log_warn("WARNING: new device appeared %u:%u %s",
MAJOR(st.st_rdev), (MINOR(st.st_rdev)), name);
}
#endif
@@ -1785,7 +1785,7 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
* 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 %u:%u %s.",
log_warn("WARNING: new device appeared %u:%u %s.",
MAJOR(st.st_rdev), MINOR(st.st_rdev), name);
}
#endif

View File

@@ -61,7 +61,7 @@ int dev_is_lvm1(struct device *dev, char *buf, int buflen)
uint32_t version;
int ret;
version = htole16(pvd->version);
version = xlate16(pvd->version);
if (pvd->id[0] == 'H' && pvd->id[1] == 'M' &&
(version == 1 || version == 2))
@@ -128,9 +128,9 @@ struct pool_disk {
};
#define CPIN_8(x, y, z) {memcpy((x), (y), (z));}
#define CPIN_16(x, y) {(x) = htobe16((y));}
#define CPIN_32(x, y) {(x) = htobe32((y));}
#define CPIN_64(x, y) {(x) = htobe64((y));}
#define CPIN_16(x, y) {(x) = xlate16_be((y));}
#define CPIN_32(x, y) {(x) = xlate32_be((y));}
#define CPIN_64(x, y) {(x) = xlate64_be((y));}
static void pool_label_in(struct pool_disk *pl, void *buf)
{

View File

@@ -17,7 +17,7 @@
#include "lib/device/dev-type.h"
#include "lib/mm/xlate.h"
#include "lib/misc/crc.h"
#include "lib/commands/toolcontext.h"
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h> /* for MD detection using udev db records */
#include "lib/device/dev-ext-udev-constants.h"
@@ -36,7 +36,7 @@
static int _dev_has_md_magic(struct device *dev, uint64_t sb_offset)
{
uint32_t md_magic = 0;
uint32_t md_magic;
/* Version 1 is little endian; version 0.90.0 is machine endian */
@@ -45,7 +45,7 @@ static int _dev_has_md_magic(struct device *dev, uint64_t sb_offset)
if ((md_magic == MD_SB_MAGIC) ||
/* coverity[result_independent_of_operands] */
((MD_SB_MAGIC != htole32(MD_SB_MAGIC)) && (md_magic == htole32(MD_SB_MAGIC))))
((MD_SB_MAGIC != xlate32(MD_SB_MAGIC)) && (md_magic == xlate32(MD_SB_MAGIC))))
return 1;
return 0;
@@ -103,14 +103,14 @@ static int _dev_has_ddf_magic(struct device *dev, uint64_t devsize_sectors, uint
if (!dev_read_bytes(dev, off, 512, &hdr))
return_0;
if ((hdr.magic == htobe32(DDF_MAGIC)) ||
(hdr.magic == htole32(DDF_MAGIC))) {
if ((hdr.magic == cpu_to_be32(DDF_MAGIC)) ||
(hdr.magic == cpu_to_le32(DDF_MAGIC))) {
crc = hdr.crc;
hdr.crc = 0xffffffff;
our_crc = calc_crc(0, (const uint8_t *)&hdr, 512);
if ((htobe32(our_crc) == crc) ||
(htole32(our_crc) == crc)) {
if ((cpu_to_be32(our_crc) == crc) ||
(cpu_to_le32(our_crc) == crc)) {
*sb_offset = off;
return 1;
} else {
@@ -126,14 +126,14 @@ static int _dev_has_ddf_magic(struct device *dev, uint64_t devsize_sectors, uint
if (!dev_read_bytes(dev, off, 512, &hdr))
return_0;
if ((hdr.magic == htobe32(DDF_MAGIC)) ||
(hdr.magic == htole32(DDF_MAGIC))) {
if ((hdr.magic == cpu_to_be32(DDF_MAGIC)) ||
(hdr.magic == cpu_to_le32(DDF_MAGIC))) {
crc = hdr.crc;
hdr.crc = 0xffffffff;
our_crc = calc_crc(0, (const uint8_t *)&hdr, 512);
if ((htobe32(our_crc) == crc) ||
(htole32(our_crc) == crc)) {
if ((cpu_to_be32(our_crc) == crc) ||
(cpu_to_le32(our_crc) == crc)) {
*sb_offset = off;
return 1;
} else {
@@ -353,12 +353,11 @@ static int _md_sysfs_attribute_scanf(struct dev_types *dt,
const char *attribute_fmt,
void *attribute_value)
{
char path[PATH_MAX] = { 0 };
char buffer[MD_MAX_SYSFS_SIZE] = { 0 };
char path[PATH_MAX+1], buffer[MD_MAX_SYSFS_SIZE];
FILE *fp;
int ret = 0;
if (_md_sysfs_attribute_snprintf(path, sizeof(path), dt,
if (_md_sysfs_attribute_snprintf(path, PATH_MAX, dt,
dev, attribute_name) < 0)
return ret;
@@ -380,7 +379,7 @@ static int _md_sysfs_attribute_scanf(struct dev_types *dt,
out:
if (fclose(fp))
log_sys_debug("fclose", path);
log_sys_error("fclose", path);
return ret;
}

View File

@@ -53,51 +53,13 @@ int dev_is_nvme(struct device *dev)
return (dev->flags & DEV_IS_NVME) ? 1 : 0;
}
int dev_is_scsi(struct cmd_context *cmd, struct device *dev)
{
return major_is_scsi_device(cmd->dev_types, MAJOR(dev->dev));
}
int dm_uuid_has_prefix(char *sysbuf, const char *prefix)
{
if (!strncmp(sysbuf, prefix, strlen(prefix)))
return 1;
/*
* If it's a kpartx partitioned dm device the dm uuid will
* be part%d-<prefix>... e.g. part1-mpath-abc...
* Check for the prefix after the part%-
*/
if (!strncmp(sysbuf, "part", 4)) {
const char *dash = strchr(sysbuf, '-');
if (!dash)
return 0;
if (!strncmp(dash + 1, prefix, strlen(prefix)))
return 1;
}
return 0;
}
int dev_is_mpath(struct cmd_context *cmd, struct device *dev)
{
char buffer[128];
if (dev_dm_uuid(cmd, dev, buffer, sizeof(buffer)) &&
dm_uuid_has_prefix(buffer, "mpath-"))
return 1;
return 0;
}
int dev_is_lv(struct cmd_context *cmd, struct device *dev)
{
char buffer[128];
if (dev_dm_uuid(cmd, dev, buffer, sizeof(buffer)) &&
!strncmp(buffer, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
return 1;
return 1;
return 0;
}
@@ -158,7 +120,7 @@ int dev_is_used_by_active_lv(struct cmd_context *cmd, struct device *dev, int *u
dm_dev_major = MAJOR(info.st_rdev);
dm_dev_minor = MINOR(info.st_rdev);
if (dm_dev_major != cmd->dev_types->device_mapper_major)
continue;
@@ -643,19 +605,19 @@ static int _has_gpt_partition_table(struct device *dev)
/* the gpt table is always written using LE on disk */
if (le64toh(gpt_header.magic) != PART_GPT_MAGIC)
if (le64_to_cpu(gpt_header.magic) != PART_GPT_MAGIC)
return 0;
entries_start = le64toh(gpt_header.part_entries_lba) * lbs;
nr_entries = le32toh(gpt_header.nr_part_entries);
sz_entry = le32toh(gpt_header.sz_part_entry);
entries_start = le64_to_cpu(gpt_header.part_entries_lba) * lbs;
nr_entries = le32_to_cpu(gpt_header.nr_part_entries);
sz_entry = le32_to_cpu(gpt_header.sz_part_entry);
for (i = 0; i < nr_entries; i++) {
if (!dev_read_bytes(dev, entries_start + (uint64_t)i * sz_entry,
sizeof(gpt_part_entry), &gpt_part_entry))
return_0;
/* just check if the guid is nonzero, no need to call le64toh here */
/* just check if the guid is nonzero, no need to call le64_to_cpu here */
if (gpt_part_entry.part_type_guid)
return 1;
}
@@ -690,7 +652,7 @@ static int _has_partition_table(struct device *dev)
/* FIXME Check for other types of partition table too */
/* Check for msdos partition table */
if (buf.magic == htole16(PART_MSDOS_MAGIC)) {
if (buf.magic == xlate16(PART_MSDOS_MAGIC)) {
for (p = 0; p < 4; ++p) {
/* Table is invalid if boot indicator not 0 or 0x80 */
if (buf.part[p].boot_ind & 0x7f) {
@@ -1037,9 +999,6 @@ int fs_get_blkid(const char *pathname, struct fs_info *fsi)
if (!blkid_probe_lookup_value(probe, "FSSIZE", &str, &len) && len)
fssize = strtoull(str, NULL, 0);
if (!blkid_probe_lookup_value(probe, "UUID", &str, &len) && len)
memcpy(fsi->uuid, str, UUID_LEN);
blkid_free_probe(probe);
if (fslastblock && fsblocksize)
@@ -1056,13 +1015,6 @@ int fs_get_blkid(const char *pathname, struct fs_info *fsi)
fsi->fs_last_byte += fsblocksize;
}
/*
* For a multi-devices btrfs, fslastblock * fsblocksize means the whole fs size.
* Thus here fs_last_byte can't be used as a device size boundary.
* Let btrfs handle it.
*/
if (!strcmp(fsi->fstype, "btrfs"))
fsi->fs_last_byte = 0;
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,

View File

@@ -95,15 +95,12 @@ unsigned long dev_optimal_io_size(struct dev_types *dt, struct device *dev);
unsigned long dev_discard_max_bytes(struct dev_types *dt, struct device *dev);
unsigned long dev_discard_granularity(struct dev_types *dt, struct device *dev);
int dm_uuid_has_prefix(char *sysbuf, const char *prefix);
int dev_is_rotational(struct dev_types *dt, struct device *dev);
int dev_is_pmem(struct dev_types *dt, struct device *dev);
int dev_is_nvme(struct device *dev);
int dev_is_scsi(struct cmd_context *cmd, struct device *dev);
int dev_is_mpath(struct cmd_context *cmd, struct device *dev);
int dev_is_lv(struct cmd_context *cmd, struct device *dev);
#define FSTYPE_MAX 16

View File

@@ -64,13 +64,3 @@ struct device_list *device_list_find_dev(struct dm_list *devices, struct device
return NULL;
}
int device_list_add(struct dm_pool *mem, struct dm_list *devices, struct device *dev)
{
struct device_list *devl;
if (!(devl = dm_pool_alloc(mem, sizeof(struct device_list))))
return_0;
devl->dev = dev;
dm_list_add(devices, &devl->list);
return 1;
}

View File

@@ -70,7 +70,6 @@ static const dev_known_type_t _dev_known_types[] = {
{"nvme", 64, "NVM Express"},
{"zvol", 16, "ZFS Zvols"},
{"VxDMP", 16, "Veritas Dynamic Multipathing"},
{"zram", 1, "zram block device"},
{"", 0, ""}
};

View File

@@ -17,7 +17,7 @@
#define _LVM_DEVICE_H
#include "base/data-struct/list.h"
#include "lib/id/id.h"
#include "lib/uuid/uuid.h"
#include <stdint.h>
#include <fcntl.h>
@@ -74,11 +74,10 @@ struct dev_ext {
#define DEV_ID_TYPE_WWID_NAA 9
#define DEV_ID_TYPE_WWID_EUI 10
#define DEV_ID_TYPE_WWID_T10 11
#define DEV_ID_TYPE_UNUSED 12 /* reserve 12 for "scsi name string" if we decide to add that */
/* reserve 12 for "scsi name string" if we decide to add that */
#define DEV_ID_TYPE_NVME_EUI64 13
#define DEV_ID_TYPE_NVME_NGUID 14
#define DEV_ID_TYPE_NVME_UUID 15
#define DEV_ID_TYPE_LAST 15
/* Max length of SCSI or NVME WWID */
#define DEV_WWID_SIZE 128
@@ -251,7 +250,6 @@ int parse_vpd_serial(const unsigned char *in, char *out, size_t outsize);
int device_id_list_remove(struct dm_list *devices, struct device *dev);
struct device_id_list *device_id_list_find_dev(struct dm_list *devices, struct device *dev);
int device_list_remove(struct dm_list *devices, struct device *dev);
int device_list_add(struct dm_pool *mem, struct dm_list *devices, struct device *dev);
struct device_list *device_list_find_dev(struct dm_list *devices, struct device *dev);
char *strdup_pvid(char *pvid);

View File

@@ -54,51 +54,6 @@ static const char _searched_file_dir[] = DEFAULT_RUN_DIR;
char devices_file_hostname_orig[PATH_MAX];
char devices_file_product_uuid_orig[PATH_MAX];
static uint64_t _get_refresh_timestamp(unsigned int add_seconds)
{
time_t now;
struct tm *tm;
uint64_t timestamp;
time(&now);
now += add_seconds;
if ((tm = gmtime(&now))) {
/* YYYYMMDDHHMMSS as a uint64_t */
timestamp = (uint64_t)tm->tm_year + 1900;
timestamp = timestamp * 100 + (tm->tm_mon + 1);
timestamp = timestamp * 100 + tm->tm_mday;
timestamp = timestamp * 100 + tm->tm_hour;
timestamp = timestamp * 100 + tm->tm_min;
timestamp = timestamp * 100 + tm->tm_sec;
} else
timestamp = now;
return timestamp;
}
static uint64_t _new_refresh_timestamp(struct cmd_context *cmd)
{
unsigned int val;
/*
* val:
* 0: refresh trigger disabled (this function will not be called)
* 1: single refresh enabled, no extended period (return 0)
* 10-600: refresh period enabled for the specified number of seconds
* (return a new refresh_until timestamp: the current time
* plus the configured number of seconds for the refresh period)
* other values: treated like 1 (return 0)
*/
if (!(val = find_config_tree_int(cmd, devices_device_ids_refresh_CFG, NULL)))
return_0;
if (val >= 10 && val <= 600)
return _get_refresh_timestamp(val);
return 0;
}
/*
* The input string pvid may be of any length, it's often
* read from system.devices, which can be edited.
@@ -527,6 +482,28 @@ int read_sys_block_binary(struct cmd_context *cmd, struct device *dev,
return _read_sys_block(cmd, dev, suffix, sysbuf, sysbufsize, 1, retlen);
}
static int _dm_uuid_has_prefix(char *sysbuf, const char *prefix)
{
if (!strncmp(sysbuf, prefix, strlen(prefix)))
return 1;
/*
* If it's a kpartx partitioned dm device the dm uuid will
* be part%d-<prefix>... e.g. part1-mpath-abc...
* Check for the prefix after the part%-
*/
if (!strncmp(sysbuf, "part", 4)) {
const char *dash = strchr(sysbuf, '-');
if (!dash)
return 0;
if (!strncmp(dash + 1, prefix, strlen(prefix)))
return 1;
}
return 0;
}
/* the dm uuid uses the wwid of the underlying dev */
int dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, char **idname_out)
{
@@ -537,7 +514,7 @@ int dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, char **idnam
if (!dev_dm_uuid(cmd, dev, uuid, sizeof(uuid)))
return_0;
if (!dm_uuid_has_prefix(uuid, "mpath-"))
if (!_dm_uuid_has_prefix(uuid, "mpath-"))
return 0;
if (!idname_out)
@@ -556,7 +533,7 @@ static int _dev_has_crypt_uuid(struct cmd_context *cmd, struct device *dev, char
if (!dev_dm_uuid(cmd, dev, uuid, sizeof(uuid)))
return_0;
if (!dm_uuid_has_prefix(uuid, "CRYPT-"))
if (!_dm_uuid_has_prefix(uuid, "CRYPT-"))
return 0;
if (!idname_out)
@@ -575,7 +552,7 @@ static int _dev_has_lvmlv_uuid(struct cmd_context *cmd, struct device *dev, char
if (!dev_dm_uuid(cmd, dev, uuid, sizeof(uuid)))
return_0;
if (!dm_uuid_has_prefix(uuid, UUID_PREFIX))
if (!_dm_uuid_has_prefix(uuid, UUID_PREFIX))
return 0;
if (!idname_out)
@@ -868,22 +845,9 @@ char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_
_dev_read_sys_serial(cmd, dev, sysbuf, sizeof(sysbuf));
break;
case DEV_ID_TYPE_MPATH_UUID:
if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
stack;
if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "mpath-"))
sysbuf[0] = '\0';
break;
case DEV_ID_TYPE_CRYPT_UUID:
if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
stack;
if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "CRYPT-"))
sysbuf[0] = '\0';
break;
case DEV_ID_TYPE_LVMLV_UUID:
if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
stack;
if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "LVM-"))
sysbuf[0] = '\0';
(void)dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf));
break;
case DEV_ID_TYPE_MD_UUID:
read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf));
@@ -920,8 +884,6 @@ char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_
return strdup(dw->id);
}
return NULL;
case DEV_ID_TYPE_UNUSED:
return NULL;
}
/*
@@ -1120,11 +1082,11 @@ static int _dev_has_stable_id(struct cmd_context *cmd, struct device *dev)
if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
goto_out;
if (dm_uuid_has_prefix(sysbuf, "mpath-"))
if (_dm_uuid_has_prefix(sysbuf, "mpath-"))
return 1;
if (dm_uuid_has_prefix(sysbuf, "CRYPT-"))
if (_dm_uuid_has_prefix(sysbuf, "CRYPT-"))
return 1;
if (dm_uuid_has_prefix(sysbuf, "LVM-"))
if (_dm_uuid_has_prefix(sysbuf, "LVM-"))
return 1;
}
@@ -1155,7 +1117,6 @@ static const char _dev_id_types[][16] = {
[DEV_ID_TYPE_WWID_NAA] = "wwid_naa",
[DEV_ID_TYPE_WWID_EUI] = "wwid_eui",
[DEV_ID_TYPE_WWID_T10] = "wwid_t10",
[DEV_ID_TYPE_UNUSED] = "unused",
[DEV_ID_TYPE_NVME_EUI64] = "nvme_eui64",
[DEV_ID_TYPE_NVME_NGUID] = "nvme_nguid",
[DEV_ID_TYPE_NVME_UUID] = "nvme_uuid",
@@ -1177,9 +1138,6 @@ uint16_t idtype_from_str(const char *str)
{
uint16_t i;
if (!str)
return 0;
for (i = 1; i < DM_ARRAY_SIZE(_dev_id_types); ++i)
if (!strcmp(str, _dev_id_types[i]))
return i;
@@ -1356,8 +1314,6 @@ int device_ids_read(struct cmd_context *cmd)
log_debug("Devices file hostname %s vs local %s.",
check_id[0] ? check_id : "none", cmd->hostname ?: "none");
cmd->device_ids_refresh_trigger = 1;
cmd->device_ids_refresh_until = _new_refresh_timestamp(cmd);
log_debug("Devices file refresh until %llu new", (unsigned long long)cmd->device_ids_refresh_until);
}
continue;
}
@@ -1379,31 +1335,10 @@ int device_ids_read(struct cmd_context *cmd)
log_debug("Devices file product_uuid %s vs local %s.",
check_id[0] ? check_id : "none", cmd->product_uuid ?: "none");
cmd->device_ids_refresh_trigger = 1;
cmd->device_ids_refresh_until = _new_refresh_timestamp(cmd);
log_debug("Devices file refresh until %llu new", (unsigned long long)cmd->device_ids_refresh_until);
}
continue;
}
if (!strncmp(line, "REFRESH_UNTIL", 13)) {
uint64_t refresh_until = 0;
_copy_idline_str(line, check_id, sizeof(check_id));
log_debug("read devices file refresh_until %s", check_id);
if (check_id[0] && find_config_tree_int(cmd, devices_device_ids_refresh_CFG, NULL))
refresh_until = strtoull(check_id, NULL, 0);
if (refresh_until == ULLONG_MAX)
refresh_until = 0;
/* device_ids_read_refresh=1 means system.devices contains a REFRESH_UNTIL line */
cmd->device_ids_read_refresh = 1;
cmd->device_ids_refresh_until = refresh_until;
if (refresh_until && (_get_refresh_timestamp(0) < refresh_until))
cmd->device_ids_refresh_trigger = 1;
log_debug("Devices file refresh until %llu old trigger %d",
(unsigned long long)cmd->device_ids_refresh_until, cmd->device_ids_refresh_trigger);
continue;
}
if (!strncmp(line, "VERSION", 7)) {
_copy_idline_str(line, _devices_file_version, sizeof(_devices_file_version));
log_debug("read devices file version %s", _devices_file_version);
@@ -1422,7 +1357,7 @@ int device_ids_read(struct cmd_context *cmd)
continue;
if (!(du = zalloc(sizeof(struct dev_use)))) {
log_warn("WARNING: Failed to process devices file entry.");
log_warn("WARNING: failed to process devices file entry.");
continue;
}
@@ -1467,7 +1402,7 @@ int device_ids_read(struct cmd_context *cmd)
}
if (line_error) {
log_warn("WARNING: Failed to process devices file entry.");
log_warn("WARNING: failed to process devices file entry.");
free_du(du);
continue;
}
@@ -1670,10 +1605,6 @@ static void devices_file_backup(struct cmd_context *cmd, char *fc, char *fb, tim
/* Remove the n oldest files by sorting system.devices-*. */
setlocale(LC_COLLATE, "C"); /* Avoid sorting by locales */
#ifndef HAVE_VERSIONSORT
/* fallback to alphasort when versionsort is not defined */
#define versionsort alphasort
#endif /* !HAVE_VERSIONSORT */
sort_count = scandir(dirpath, &namelist, _filter_backup_files, versionsort);
setlocale(LC_COLLATE, "");
if (sort_count < 0) {
@@ -1778,12 +1709,12 @@ int device_ids_write(struct cmd_context *cmd)
if (_devices_file_version[0]) {
if (sscanf(_devices_file_version, "%u.%u.%u", &df_major, &df_minor, &df_counter) != 3) {
/* don't update a file we can't parse */
log_warn("WARNING: Not updating devices file with unparsed version.");
log_warn("WARNING: not updating devices file with unparsed version.");
return 0;
}
if (df_major > DEVICES_FILE_MAJOR) {
/* don't update a file with a newer major version */
log_warn("WARNING: Not updating devices file with larger major version.");
log_warn("WARNING: not updating devices file with larger major version.");
return 0;
}
}
@@ -1799,12 +1730,12 @@ int device_ids_write(struct cmd_context *cmd)
log_sys_debug("unlink", tmppath);
if (!(fp = fopen(tmppath, "w+"))) {
log_warn("WARNING: %s: cannot open for writing: %s.", tmppath, strerror(errno));
log_warn("Cannot open to write %s.", tmppath);
goto out;
}
if ((dir_fd = open(dirpath, O_RDONLY)) < 0) {
log_warn("WARNING: %s: cannot open directory: %s.", dirpath, strerror(errno));
log_sys_debug("open", dirpath);
goto out;
}
@@ -1817,7 +1748,7 @@ int device_ids_write(struct cmd_context *cmd)
fb_size = names_len + 256 + (128 * dm_list_size(&cmd->use_devices));
if (!(fb = malloc(fb_size))) {
log_warn("Failed to allocate buffer size %d for devices file.", fb_size);
log_error("Failed to allocate buffer size %d for devices file.", fb_size);
goto out;
}
@@ -1831,7 +1762,7 @@ int device_ids_write(struct cmd_context *cmd)
num = snprintf(fb + pos, len - pos, "HOSTNAME=%s\n", cmd->hostname);
if (num >= len - pos) {
log_warn("Failed to write buffer for devices file content.");
log_error("Failed to write buffer for devices file content.");
goto out;
}
pos += num;
@@ -1839,18 +1770,9 @@ int device_ids_write(struct cmd_context *cmd)
if (dm_snprintf(version_buf, VERSION_LINE_MAX, "VERSION=%u.%u.%u", DEVICES_FILE_MAJOR, DEVICES_FILE_MINOR, df_counter+1) < 0)
goto_out;
if (cmd->device_ids_refresh_until && cmd->device_ids_refresh_trigger) {
num = snprintf(fb + pos, len - pos, "REFRESH_UNTIL=%llu\n", (unsigned long long)cmd->device_ids_refresh_until);
if (num >= len - pos) {
log_warn("Failed to write buffer for devices file content.");
goto out;
}
pos += num;
}
num = snprintf(fb + pos, len - pos, "%s\n", version_buf);
if (num >= len - pos) {
log_warn("Failed to write buffer for devices file content.");
log_error("Failed to write buffer for devices file content.");
goto out;
}
pos += num;
@@ -1879,7 +1801,7 @@ int device_ids_write(struct cmd_context *cmd)
du->idname ?: ".", devname, pvid);
}
if (num >= len - pos) {
log_warn("Failed to write buffer for devices file content.");
log_error("Failed to write buffer for devices file content.");
goto out;
}
pos += num;
@@ -1898,17 +1820,17 @@ int device_ids_write(struct cmd_context *cmd)
"# HASH=%u\n",
cmd->name, cmd->device_ids_auto_import ? " (auto)" : "",
getpid(), ctime(&t), hash)) < 0) {
log_warn("Failed to write buffer for devices file content.");
log_error("Failed to write buffer for devices file content.");
goto out;
}
fc[fc_bytes] = '\0';
if (fputs(fc, fp) < 0) {
log_warn("Failed to write devices file header.");
log_error("Failed to write devices file header.");
goto out;
}
if (fputs(fb, fp) < 0) {
log_warn("Failed to write devices file.");
log_error("Failed to write devices file.");
goto out;
}
if (fflush(fp) < 0)
@@ -1923,7 +1845,7 @@ int device_ids_write(struct cmd_context *cmd)
fp = NULL;
if (rename(tmppath, cmd->devices_file_path) < 0) {
log_warn("WARNING: %s: failed to replace devices file: %s", cmd->devices_file_path, strerror(errno));
log_error("Failed to replace devices file.");
goto out;
}
@@ -1991,7 +1913,7 @@ int device_ids_version_unchanged(struct cmd_context *cmd)
FILE *fp;
if (!(fp = fopen(cmd->devices_file_path, "r"))) {
log_warn("WARNING: Cannot open devices file to read.");
log_warn("WARNING: cannot open devices file to read.");
return 0;
}
@@ -2164,12 +2086,12 @@ int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid_
log_error("The specified --deviceidtype %s is unknown.", idtype_arg);
return 0;
}
log_warn("WARNING: Ignoring unknown device_id type %s.", idtype_arg);
log_warn("WARNING: ignoring unknown device_id type %s.", idtype_arg);
} else {
if (id_arg) {
if ((idname = strdup(id_arg)))
goto id_done;
log_warn("WARNING: Ignoring device_id name %s.", id_arg);
log_warn("WARNING: ignoring device_id name %s.", id_arg);
}
if ((idname = device_id_system_read(cmd, dev, idtype)))
@@ -2180,7 +2102,7 @@ int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid_
return 0;
}
log_warn("WARNING: Ignoring deviceidtype %s which is not available for device.", idtype_arg);
log_warn("WARNING: ignoring deviceidtype %s which is not available for device.", idtype_arg);
idtype = 0;
}
}
@@ -2269,13 +2191,13 @@ id_done:
du_devname->devname);
if (du_pvid && (du_pvid->dev != dev))
log_warn("WARNING: Adding device %s with PVID %s which is already used for %s device_id %s.",
log_warn("WARNING: adding device %s with PVID %s which is already used for %s device_id %s.",
dev_name(dev), pvid, du_pvid->dev ? dev_name(du_pvid->dev) : "missing device",
du_pvid->idname ?: "none");
if (du_devid && (du_devid->dev != dev)) {
if (!du_devid->dev) {
log_warn("WARNING: Adding device %s with idname %s which is already used for missing device.",
log_warn("WARNING: adding device %s with idname %s which is already used for missing device.",
dev_name(dev), id->idname);
} else {
int ret1, ret2;
@@ -2287,7 +2209,7 @@ id_done:
log_debug("Using separate entries for partitions of same device %s part %d %s part %d.",
dev_name(dev), part, dev_name(du_devid->dev), du_devid->part);
} else {
log_warn("WARNING: Adding device %s with idname %s which is already used for %s.",
log_warn("WARNING: adding device %s with idname %s which is already used for %s.",
dev_name(dev), id->idname, dev_name(du_devid->dev));
}
}
@@ -2401,7 +2323,7 @@ void device_id_pvremove(struct cmd_context *cmd, struct device *dev)
return;
if (!(du = get_du_for_dev(cmd, dev))) {
log_warn("WARNING: Devices to use does not include %s.", dev_name(dev));
log_warn("WARNING: devices to use does not include %s", dev_name(dev));
return;
}
@@ -2599,33 +2521,6 @@ static int _match_dm_names(struct cmd_context *cmd, char *idname, struct device
return 0;
}
static void _replace_incorrect_dm_idtype(struct dev_use *du)
{
/* Previous bug let one of these types be swapped for another
because they all read their value from sysfs file dm/uuid. */
if (du->idtype != DEV_ID_TYPE_MPATH_UUID &&
du->idtype != DEV_ID_TYPE_CRYPT_UUID &&
du->idtype != DEV_ID_TYPE_LVMLV_UUID)
return;
/* Use the IDNAME value to determine the correct IDTYPE. */
if (dm_uuid_has_prefix(du->idname, "mpath-") && (du->idtype != DEV_ID_TYPE_MPATH_UUID)) {
log_debug("replace incorrect mpath device id type for %u %s", du->idtype, du->idname);
du->idtype = DEV_ID_TYPE_MPATH_UUID;
return;
}
if (dm_uuid_has_prefix(du->idname, "CRYPT-") && (du->idtype != DEV_ID_TYPE_CRYPT_UUID)) {
log_debug("replace incorrect crypt device id type for %u %s", du->idtype, du->idname);
du->idtype = DEV_ID_TYPE_CRYPT_UUID;
return;
}
if (dm_uuid_has_prefix(du->idname, "LVM-") && (du->idtype != DEV_ID_TYPE_LVMLV_UUID)) {
log_debug("replace incorrect lvmlv device id type for %u %s", du->idtype, du->idname);
du->idtype = DEV_ID_TYPE_LVMLV_UUID;
return;
}
}
/*
* du is a devices file entry. dev is any device on the system.
* check if du is for dev by comparing the device's ids to du->idname.
@@ -2736,18 +2631,6 @@ static int _match_du_to_dev(struct cmd_context *cmd, struct dev_use *du, struct
_reduce_repeating_underscores(du_idname, sizeof(du_idname));
}
/*
* A past bug allowed mpath, crypt, or lvm devices to be added to
* system.devices using any of the dm id types, and they could be
* used normally. Accept an old system.devices with that mistake
* by updating du->idtype to have the correct idtype based on the
* idname dm prefix.
*/
if (((du->idtype == DEV_ID_TYPE_MPATH_UUID) && !dm_uuid_has_prefix(du->idname, "mpath-")) ||
((du->idtype == DEV_ID_TYPE_CRYPT_UUID) && !dm_uuid_has_prefix(du->idname, "CRYPT-")) ||
((du->idtype == DEV_ID_TYPE_LVMLV_UUID) && !dm_uuid_has_prefix(du->idname, "LVM")))
_replace_incorrect_dm_idtype(du);
/*
* Try to match du with ids that have already been read for the dev
* (and saved on dev->ids to avoid rereading.)
@@ -2898,7 +2781,7 @@ int device_ids_match_dev(struct cmd_context *cmd, struct device *dev)
* a device, is allowed to read a device to evaluate filters that need to see
* data from the dev.
*
* When a device id of a particular type is obtained for a dev, an id for that
* When a device id of a particular type is obtained for a dev, a id for that
* type is saved in dev->ids in case it needs to be checked again.
*
* When a device in dev-cache is matched to an entry in the devices file
@@ -3170,80 +3053,6 @@ static void _get_devs_with_serial_numbers(struct cmd_context *cmd, struct dm_lis
dev_iter_destroy(iter);
}
struct device *device_id_system_find(struct cmd_context *cmd, const char *find_idname, uint16_t find_idtype)
{
struct dev_iter *iter;
struct device *dev;
struct device *dev_found = NULL;
struct dev_id *id;
const char *idname;
if (!(iter = dev_iter_create(NULL, 0)))
return NULL;
while ((dev = dev_iter_get(cmd, iter))) {
dm_list_iterate_items(id, &dev->ids) {
if (id->idtype == find_idtype) {
if (!id->idname)
goto next_dev;
if (!strcmp(id->idname, find_idname)) {
dev_found = dev;
goto out;
}
}
}
/* just copying the no-data filters in similar device_ids_search */
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "sysfs"))
continue;
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "type"))
continue;
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "usable"))
continue;
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "mpath"))
continue;
if ((idname = device_id_system_read(cmd, dev, find_idtype))) {
if (!strcmp(idname, find_idname)) {
free((char *)idname);
dev_found = dev;
goto out;
}
free((char *)idname);
}
next_dev:
continue;
}
out:
dev_iter_destroy(iter);
return dev_found;
}
int device_id_system_list(struct cmd_context *cmd, struct device *dev, uint16_t check_idtype)
{
char *idname;
uint16_t idtype;
int found = 0;
for (idtype = 1; idtype <= DEV_ID_TYPE_LAST; idtype++) {
if (check_idtype && (check_idtype != idtype))
continue;
if ((idname = device_id_system_read(cmd, dev, idtype))) {
if (check_idtype)
log_print("%s", idname);
else
log_print("%-16s %s", idtype_to_str(idtype), idname);
free(idname);
found++;
}
}
if (check_idtype && !found) {
log_error("deviceidtype %s not found for %s", idtype_to_str(check_idtype), dev_name(dev));
return 0;
}
return 1;
}
/*
* This is called after devices are scanned to compare what was found on disks
* vs what's in the devices file. The devices file could be outdated and need
@@ -3450,7 +3259,7 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
/* This shouldn't happen since idname was used to match du and dev */
if (!du->idname || strcmp(devname, du->idname)) {
log_warn("WARNING: Fixing devices file IDNAME %s for PVID %s device %s.",
log_warn("WARNING: fixing devices file IDNAME %s for PVID %s device %s",
du->idname ?: ".", du->pvid, dev_name(dev));
if (!(tmpdup = strdup(devname)))
continue;
@@ -3688,20 +3497,6 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
}
}
/*
* If device_ids_search() will be called (device_ids_invalid is set,
* or device_ids_refresh_trigger is set), then let that function
* decide about updating the devices file refresh_until.
*
* If search will not be called, refresh_until is set in the file,
* but refresh_until is not active, then remove it from the file.
*/
if (!cmd->device_ids_invalid && !cmd->device_ids_refresh_trigger && cmd->device_ids_read_refresh) {
log_debug("Validate device ids: update to remove refresh_until");
cmd->device_ids_refresh_until = 0;
update_file = 1;
}
/*
* When info in the devices file has become incorrect,
* try another search for PVIDs on renamed devices.
@@ -4288,10 +4083,10 @@ void device_ids_search(struct cmd_context *cmd, struct dm_list *new_devs,
dm_list_iterate_items_safe(dil, dil2, &search_pvids) {
if (!memcmp(dil->pvid, dev->pvid, ID_LEN)) {
if (dil->dev) {
log_warn("WARNING: Found PVID %s on multiple devices %s %s.",
log_warn("WARNING: found PVID %s on multiple devices %s %s.",
dil->pvid, dev_name(dil->dev), dev_name(dev));
log_warn("WARNING: Duplicate PVIDs should be changed to be unique.");
log_warn("WARNING: Use lvmdevices to select a device for PVID %s.", dil->pvid);
log_warn("WARNING: duplicate PVIDs should be changed to be unique.");
log_warn("WARNING: use lvmdevices to select a device for PVID %s.", dil->pvid);
dm_list_del(&dil->list);
} else {
log_debug("Search for PVID %s found on %s.", dil->pvid, dev_name(dev));
@@ -4389,7 +4184,7 @@ void device_ids_search(struct cmd_context *cmd, struct dm_list *new_devs,
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, NULL)) {
/* I don't think this would happen */
log_warn("WARNING: New device %s for PVID %s is excluded: %s.",
log_warn("WARNING: new device %s for PVID %s is excluded: %s.",
dev_name(dev), dil->pvid, dev_filtered_reason(dev));
if (du) /* Should not happen 'du' is NULL */
du->dev = NULL;
@@ -4398,30 +4193,6 @@ void device_ids_search(struct cmd_context *cmd, struct dm_list *new_devs,
}
out:
/*
* Remove REFRESH_UNTIL if it was set in the file,
* and all devices have been found.
* Add REFRESH_UNTIL if it was not set in the file,
* and all devices have not been found, and the
* refresh_until interval is active.
*/
if (cmd->device_ids_read_refresh && !not_found) {
log_debug("Search for PVIDs remove refresh_until");
cmd->device_ids_refresh_until = 0;
update_file = 1;
}
if (!cmd->device_ids_read_refresh && not_found && cmd->device_ids_refresh_until) {
log_debug("Search for PVIDs add refresh_until not_found %d", not_found);
update_file = 1;
}
/*
* If the devices file is already being updated, don't include
* REFRESH_UNTIL if all devices are found.
*/
if (!not_found)
cmd->device_ids_refresh_until = 0;
/*
* try lock and device_ids_write(), the update is not required and will
* be done by a subsequent command if it's not done here.
@@ -4475,8 +4246,8 @@ void device_ids_search(struct cmd_context *cmd, struct dm_list *new_devs,
* It does not suppress searches for missing PVIDs when done for
* refresh, where PVIDs of any idtype are searched for.
*/
if (!cmd->device_ids_refresh_trigger && !cmd->device_ids_refresh_until &&
!all_ids && not_found && !found && strcmp(cmd->name, "lvmdevices"))
if (!cmd->device_ids_refresh_trigger && !all_ids && not_found && !found &&
strcmp(cmd->name, "lvmdevices"))
_searched_devnames_create(cmd, search_pvids_count, search_pvids_hash,
search_devs_count, search_devs_hash);
}
@@ -4582,7 +4353,7 @@ static int _lock_devices_file(struct cmd_context *cmd, int mode, int nonblock, i
if (_devices_file_locked) {
/* shouldn't happen */
log_warn("WARNING: Devices file already locked %d.", mode);
log_warn("WARNING: devices file already locked %d", mode);
return 0;
}
@@ -4598,7 +4369,7 @@ static int _lock_devices_file(struct cmd_context *cmd, int mode, int nonblock, i
if (_devices_fd != -1) {
/* shouldn't happen */
log_warn("WARNING: Devices file lock file already open %d.", _devices_fd);
log_warn("WARNING: devices file lock file already open %d", _devices_fd);
return 0;
}
@@ -4648,16 +4419,16 @@ void unlock_devices_file(struct cmd_context *cmd)
if (_devices_fd == -1) {
/* shouldn't happen */
log_warn("WARNING: Devices file unlock no fd.");
log_warn("WARNING: devices file unlock no fd");
return;
}
if (!_devices_file_locked)
log_warn("WARNING: Devices file unlock not locked.");
log_warn("WARNING: devices file unlock not locked");
ret = flock(_devices_fd, LOCK_UN);
if (ret)
log_warn("WARNING: Devices file unlock errno %d.", errno);
log_warn("WARNING: devices file unlock errno %d", errno);
_devices_file_locked = 0;

View File

@@ -45,9 +45,6 @@ void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs,
void device_ids_search(struct cmd_context *cmd, struct dm_list *new_devs,
int all_ids, int noupdate, int *update_needed);
char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_t idtype);
struct device *device_id_system_find(struct cmd_context *cmd, const char *find_idname, uint16_t find_idtype);
int device_id_system_list(struct cmd_context *cmd, struct device *dev, uint16_t check_idtype);
void device_id_update_vg_uuid(struct cmd_context *cmd, struct volume_group *vg, struct id *old_vg_id);
int device_ids_version_unchanged(struct cmd_context *cmd);

View File

@@ -19,21 +19,22 @@
#include "lib/display/display.h"
#include "lib/misc/lvm-exec.h"
#include "lib/activate/dev_manager.h"
#include "lib/commands/toolcontext.h"
#include <dirent.h>
#include <mntent.h>
#include <sys/ioctl.h>
#include <linux/types.h>
static const char *_get_lvresize_fs_helper_path(struct cmd_context *cmd)
static const char *_lvresize_fs_helper_path;
static const char *_get_lvresize_fs_helper_path(void)
{
const char *path = getenv("LVRESIZE_FS_HELPER_PATH");
if (!_lvresize_fs_helper_path)
_lvresize_fs_helper_path = getenv("LVRESIZE_FS_HELPER_PATH");
if (!path)
path = find_config_tree_str(cmd, global_lvresize_fs_helper_executable_CFG, NULL);
if (!_lvresize_fs_helper_path)
_lvresize_fs_helper_path = LVRESIZE_FS_HELPER_PATH; /* from configure, usually in /usr/libexec */
return path;
return _lvresize_fs_helper_path;
}
/*
@@ -107,163 +108,18 @@ int lv_crypt_is_active(struct cmd_context *cmd, char *lv_path)
return _get_crypt_path(st_lv.st_rdev, lv_path, crypt_path);
}
static int _fs_get_mnt(struct fs_info *fsi, dev_t devt)
{
struct stat stme;
FILE *fme = NULL;
struct mntent *me;
/*
* Note: used swap devices are not considered as mount points,
* hence they're not listed in /etc/mtab, we'd need to read the
* /proc/swaps instead. We don't need it at this moment though,
* but if we do once, read the /proc/swaps here if fsi->fstype == "swap".
*/
if (!(fme = setmntent("/etc/mtab", "r")))
return_0;
while ((me = getmntent(fme))) {
if (strcmp(me->mnt_type, fsi->fstype))
continue;
if (me->mnt_dir[0] != '/')
continue;
if (me->mnt_fsname[0] != '/')
continue;
/*
* st_dev of mnt_dir in btrfs is an anonymous device number,
* use mnt_fsname instead.
*/
if (!strcmp(fsi->fstype, "btrfs")) {
if (stat(me->mnt_fsname, &stme) < 0)
log_sys_error("stat", me->mnt_fsname);
if (stme.st_rdev != devt)
continue;
} else {
if (stat(me->mnt_dir, &stme) < 0)
continue;
if (stme.st_dev != devt)
continue;
fsi->mounted = 1;
}
log_debug("fs_get_info %s is mounted \"%s\"", fsi->fs_dev_path, me->mnt_dir);
strncpy(fsi->mount_dir, me->mnt_dir, PATH_MAX-1);
}
endmntent(fme);
return 1;
}
static int _btrfs_get_mnt(struct fs_info *fsi, dev_t lv_devt)
{
char devices_path[PATH_MAX];
char rdev_path[PATH_MAX];
unsigned major, minor;
dev_t devt;
char buffer[16];
char *device_name;
DIR *dr;
struct dirent *de;
int ret = 1;
int fd = -1;
int r;
bool found = false;
/* For a mounted btrfs, there will be a sys dir like /sys/fs/btrfs/$uuid/devices */
if (!dm_snprintf(devices_path, sizeof(devices_path), "%sfs/btrfs/%s/devices",
dm_sysfs_dir(), fsi->uuid)) {
log_error("Couldn't create btrfs devices path for %s.", fsi->fs_dev_path);
return 0;
}
/* btrfs module is not available or the device is not mounted */
if (!(dr = opendir(devices_path))) {
if (errno == ENOENT) {
fsi->mounted = 0;
return 1;
}
log_sys_error("opendir", devices_path);
return 0;
}
/*
* Here iterates entries under /sys/fs/btrfs/$uuid/devices and read devt.
* There is only one mnt entry per mounted fs even it's a multi-devices fs.
* So also call _fs_get_mnt for every devices to find a matched mount point.
*/
while ((de = readdir(dr))) {
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
device_name = de->d_name;
if (!dm_snprintf(rdev_path, sizeof(devices_path), "%s/%s/dev",
devices_path, device_name)) {
log_error("Couldn't create rdev path for %s.", fsi->fs_dev_path);
ret = 0;
break;
}
if ((fd = open(rdev_path, O_RDONLY)) < 0) {
log_sys_debug("open", rdev_path);
ret = 0;
break;
}
r = read(fd, buffer, sizeof(buffer));
if (close(fd))
log_sys_debug("close", rdev_path);
fd = -1;
if (r <= 0) {
ret = 0;
log_sys_debug("read", rdev_path);
break;
}
buffer[r - 1] = 0;
if (sscanf(buffer, "%u:%u", &major, &minor) != 2) {
ret = 0;
log_sys_debug("sscanf", rdev_path);
break;
}
devt = MKDEV(major, minor);
if (devt == lv_devt)
found = true;
if (fsi->mount_dir[0] == 0)
_fs_get_mnt(fsi, devt);
if (fsi->mounted && fsi->mount_dir[0])
break;
}
if (closedir(dr))
log_sys_debug("closedir", devices_path);
fsi->mounted = !!found;
if (fsi->mounted && fsi->mount_dir[0] == 0) {
log_error("Couldn't get mount point for %s.", fsi->fs_dev_path);
ret = 0;
}
return ret;
}
int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi)
int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv,
struct fs_info *fsi, int include_mount)
{
char lv_path[PATH_MAX];
char crypt_path[PATH_MAX] = { 0 };
struct stat st_lv;
struct stat st_crypt;
struct stat st_top;
struct stat stme;
struct fs_info info;
FILE *fme = NULL;
struct mntent *me;
int fd;
int ret;
@@ -342,16 +198,38 @@ int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, struct fs_in
st_top = st_lv;
}
if (!strcmp(fsi->fstype, "btrfs"))
ret = _btrfs_get_mnt(fsi, st_lv.st_rdev);
else
ret = _fs_get_mnt(fsi, st_top.st_rdev);
if (!include_mount)
return 1;
/* blkid FSLASTBLOCK may be incorrect for mounted xfs */
if (fsi->mounted && !strcmp(fsi->fstype, "xfs")) {
if (!(ret = fs_xfs_update_size_mounted(cmd, lv, lv_path, fsi)))
stack;
/*
* Note: used swap devices are not considered as mount points,
* hence they're not listed in /etc/mtab, we'd need to read the
* /proc/swaps instead. We don't need it at this moment though,
* but if we do once, read the /proc/swaps here if fsi->fstype == "swap".
*/
if (!(fme = setmntent("/etc/mtab", "r")))
return_0;
ret = 1;
while ((me = getmntent(fme))) {
if (strcmp(me->mnt_type, fsi->fstype))
continue;
if (me->mnt_dir[0] != '/')
continue;
if (me->mnt_fsname[0] != '/')
continue;
if (stat(me->mnt_dir, &stme) < 0)
continue;
if (stme.st_dev != st_top.st_rdev)
continue;
log_debug("fs_get_info %s is mounted \"%s\"", fsi->fs_dev_path, me->mnt_dir);
fsi->mounted = 1;
strncpy(fsi->mount_dir, me->mnt_dir, PATH_MAX-1);
}
endmntent(fme);
fsi->unmounted = !fsi->mounted;
return ret;
@@ -366,8 +244,6 @@ int fs_mount_state_is_misnamed(struct cmd_context *cmd, struct logical_volume *l
char proc_mntpath[PATH_MAX + 1];
char mtab_mntpath[PATH_MAX] = { 0 };
char dm_devpath[PATH_MAX];
char dm_devpath_resolved[PATH_MAX];
char proc_devpath_resolved[PATH_MAX];
char tmp_path[PATH_MAX];
char *dm_name;
struct stat st_lv;
@@ -467,19 +343,9 @@ int fs_mount_state_is_misnamed(struct cmd_context *cmd, struct logical_volume *l
* it appears in /proc/mounts once as
* /dev/mapper/vg-lvol0 on /foo type xfs ...
*/
dir_match = !strcmp(mtab_mntpath, proc_mntpath);
/*
* Resolve symlinks before comparing device paths. In test environments,
* dm_devpath may be a symlink (e.g., /dev/shm/LVMTEST/dev/mapper/vg-lv
* -> /dev/mapper/vg-lv), while proc_devpath is the resolved real path.
* Compare resolved paths to avoid false positives for rename detection.
*/
if (realpath(dm_devpath, dm_devpath_resolved) &&
realpath(proc_devpath, proc_devpath_resolved))
dev_match = !strcmp(dm_devpath_resolved, proc_devpath_resolved);
else
dev_match = !strcmp(dm_devpath, proc_devpath);
dir_match = !strcmp(mtab_mntpath, proc_mntpath);
dev_match = !strcmp(dm_devpath, proc_devpath);
if (!dir_match && !dev_match)
continue;
@@ -523,7 +389,7 @@ int crypt_resize_script(struct cmd_context *cmd, struct logical_volume *lv, stru
if (dm_snprintf(crypt_path, sizeof(crypt_path), "/dev/dm-%u", MINOR(fsi->crypt_devt)) < 0)
return_0;
argv[0] = _get_lvresize_fs_helper_path(cmd);
argv[0] = _get_lvresize_fs_helper_path();
argv[++args] = "--cryptresize";
argv[++args] = "--cryptpath";
argv[++args] = crypt_path;
@@ -573,7 +439,7 @@ int fs_reduce_script(struct cmd_context *cmd, struct logical_volume *lv, struct
if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", lv->vg->cmd->dev_dir, lv->vg->name, lv->name) < 0)
return_0;
argv[0] = _get_lvresize_fs_helper_path(cmd);
argv[0] = _get_lvresize_fs_helper_path();
argv[++args] = "--fsreduce";
argv[++args] = "--fstype";
argv[++args] = fsi->fstype;
@@ -654,29 +520,21 @@ int fs_extend_script(struct cmd_context *cmd, struct logical_volume *lv, struct
{
char lv_path[PATH_MAX];
char crypt_path[PATH_MAX];
char newsize_str[16] = { 0 };
const char *argv[FS_CMD_MAX_ARGS + 4];
char *devpath;
int args = 0;
int status;
if (dm_snprintf(newsize_str, sizeof(newsize_str), "%llu", (unsigned long long)fsi->new_size_bytes) < 0)
return_0;
if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", lv->vg->cmd->dev_dir, lv->vg->name, lv->name) < 0)
return_0;
argv[0] = _get_lvresize_fs_helper_path(cmd);
argv[0] = _get_lvresize_fs_helper_path();
argv[++args] = "--fsextend";
argv[++args] = "--fstype";
argv[++args] = fsi->fstype;
argv[++args] = "--lvpath";
argv[++args] = lv_path;
if (fsi->new_size_bytes) {
argv[++args] = "--newsizebytes";
argv[++args] = newsize_str;
}
if (fsi->mounted) {
argv[++args] = "--mountdir";
argv[++args] = fsi->mount_dir;

View File

@@ -15,20 +15,14 @@
#ifndef _FILESYSTEM_H
#define _FILESYSTEM_H
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
#include <linux/limits.h> /* PATH_MAX */
struct cmd_context;
struct logical_volume;
#define FSTYPE_MAX 16
#define UUID_LEN 37
struct fs_info {
char fstype[FSTYPE_MAX];
char mount_dir[PATH_MAX];
char uuid[UUID_LEN];
char fs_dev_path[PATH_MAX]; /* usually lv dev, can be crypt dev */
unsigned int fs_block_size_bytes; /* 512 or 4k */
uint64_t fs_last_byte; /* last byte on the device used by the fs */
@@ -49,7 +43,8 @@ struct fs_info {
unsigned needs_crypt:1;
};
int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi);
int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv,
struct fs_info *fsi, int include_mount);
int fs_extend_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, char *fsmode);
int fs_reduce_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, char *fsmode);
@@ -58,8 +53,4 @@ int crypt_resize_script(struct cmd_context *cmd, struct logical_volume *lv, stru
int fs_mount_state_is_misnamed(struct cmd_context *cmd, struct logical_volume *lv, char *lv_path, char *fstype);
int lv_crypt_is_active(struct cmd_context *cmd, char *lv_path);
/* filesystem_xfs.c */
int fs_xfs_update_size_mounted(struct cmd_context *cmd, struct logical_volume *lv,
char *lv_path, struct fs_info *fsi);
#endif

View File

@@ -1,75 +0,0 @@
/*
* Copyright (C) 2025 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "filesystem.h"
#include "lib/log/lvm-logging.h"
#ifdef HAVE_XFS_XFS_H
#include <xfs/xfs.h>
#else /* !HAVE_XFS_XFS_H */
#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
/* #IOCTL to obtain geometry info */
#define XFS_IOC_FSGEOMETRY 0x8100587e
/* Copy of some basic and hopefully unchangeable XFS header dat>a variables */
struct xfs_fsop_geom {
uint32_t blocksize; /* filesystem (data) block size */
uint32_t rtextsize;
uint32_t agblocks;
uint32_t agcount;
uint32_t logblocks;
uint32_t sectsize;
uint32_t inodesize;
uint32_t imaxpct;
uint64_t datablocks; /* fsblocks in data subvolume */
uint32_t reserved[128]; /* whatever size whole structure may have */
};
#endif
int fs_xfs_update_size_mounted(struct cmd_context *cmd, struct logical_volume *lv,
char *lv_path, struct fs_info *fsi)
{
struct xfs_fsop_geom geo = { 0 };
int ret = 0;
int fd;
if ((fd = open(fsi->mount_dir, O_RDONLY)) < 0) {
log_sys_error("XFS geometry open", fsi->mount_dir);
return 0;
}
if (ioctl(fd, XFS_IOC_FSGEOMETRY, &geo)) {
log_sys_error("XFS geometry ioctl", fsi->mount_dir);
goto out;
}
/* replace the potentially wrong value from blkid_probe_lookup_value FSLASTBLOCK */
fsi->fs_last_byte = geo.blocksize * geo.datablocks;
ret = 1;
log_debug("XFS geometry blocksize %llu datablocks %llu fs_last_byte %llu from %s %s.",
(unsigned long long)geo.blocksize, (unsigned long long)geo.datablocks,
(unsigned long long)fsi->fs_last_byte, lv_path, fsi->mount_dir);
out:
(void)close(fd);
return ret;
}

View File

@@ -17,7 +17,6 @@
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
#include "lib/device/device_id.h"
#include "lib/device/persist.h"
#include "lib/mm/xlate.h"
#include <stdio.h>
@@ -36,8 +35,6 @@
#include <stdbool.h>
#include <assert.h>
#define NVME_PR_BUF_SIZE 8192 /* space for 127 keys */
#ifdef NVME_SUPPORT
#include <libnvme.h>
@@ -185,7 +182,7 @@ void dev_read_nvme_wwids(struct device *dev)
}
if (nvme_get_nsid(fd, &nsid)) {
log_debug("dev_read_nvme_wwids nvme_get_nsid error %d %s", errno, devpath);
log_print("dev_read_nvme_wwids nvme_get_nsid error %d %s", errno, devpath);
goto out;
}
@@ -210,7 +207,7 @@ void dev_read_nvme_wwids(struct device *dev)
/* Avoid using nvme_identify_ns_descs before ver 1.3. */
if (!nvme_identify_ctrl(fd, ctrl_id)) {
if (le32toh(ctrl_id->ver) < 0x10300)
if (le32_to_cpu(ctrl_id->ver) < 0x10300)
goto_out;
}
@@ -222,7 +219,7 @@ void dev_read_nvme_wwids(struct device *dev)
goto out;
}
for (i = 0; i < (int)NVME_IDENTIFY_DATA_SIZE; i += len) {
for (i = 0; i < NVME_IDENTIFY_DATA_SIZE; i += len) {
struct nvme_ns_id_desc *cur = (struct nvme_ns_id_desc *)(data + i);
if (cur->nidl == 0)
@@ -270,252 +267,8 @@ out:
if (close(fd))
log_sys_debug("close", devpath);
}
static int prtype_from_nvme(uint8_t nvme_type)
{
switch (nvme_type) {
case 0:
return 0;
case 1:
return PR_TYPE_WE;
case 2:
return PR_TYPE_EA;
case 3:
return PR_TYPE_WERO;
case 4:
return PR_TYPE_EARO;
case 5:
return PR_TYPE_WEAR;
case 6:
return PR_TYPE_EAAR;
default:
return -1;
};
}
int dev_read_reservation_nvme(struct cmd_context *cmd, struct device *dev, uint64_t *holder_ret, int *prtype_ret)
{
const char *devname;
struct nvme_resv_report_args args = { 0 };
struct nvme_resv_status *status = NULL;
uint64_t rkey;
uint32_t nsid = 0;
int status_size = NVME_PR_BUF_SIZE;
int status_entries;
int regctl;
int err;
int fd;
int i;
int ret = 0;
devname = dev_name(dev);
if ((fd = open(devname, O_RDONLY)) < 0) {
log_error("dev_read_reservation %s open error %d", devname, errno);
return 0;
}
if (nvme_get_nsid(fd, &nsid)) {
log_error("dev_read_reservation %s nvme_get_nsid error %d", devname, errno);
goto out;
}
if (!(status = malloc(status_size)))
goto out;
args.args_size = sizeof(args);
args.fd = fd;
args.nsid = nsid;
args.eds = 1;
args.len = status_size;
args.report = status;
args.timeout = 0;
args.result = NULL;
if ((err = nvme_resv_report(&args))) {
log_error("dev_read_reservation %s error %d", devname, err);
goto out;
}
*prtype_ret = prtype_from_nvme(status->rtype);
ret = 1;
if (!holder_ret)
goto out;
*holder_ret = 0;
/* all are holders for these types so don't bother checking */
if (*prtype_ret == PR_TYPE_WEAR || *prtype_ret == PR_TYPE_EAAR)
goto out;
regctl = status->regctl[0] | (status->regctl[1] << 8);
status_entries = (status_size - 64) / 64;
if (status_entries < regctl) {
log_warn("dev_read_reservation %s too many entries %d limit %d", devname, regctl, status_entries);
regctl = status_entries;
}
for (i = 0; i < regctl; i++) {
if (status->regctl_eds[i].rcsts) {
rkey = le64toh(status->regctl_eds[i].rkey);
*holder_ret = rkey;
break;
}
}
out:
free(status);
if (close(fd))
log_sys_debug("close", devname);
return ret;
}
int dev_find_key_nvme(struct cmd_context *cmd, struct device *dev, int may_fail,
uint64_t find_key, int *found_key,
int find_host_id, uint64_t *found_host_id_key,
int find_all, int *found_count, uint64_t **found_all)
{
const char *devname;
struct nvme_resv_report_args args = { 0 };
struct nvme_resv_status *status = NULL;
uint64_t *all_keys = NULL;
uint64_t key;
uint32_t nsid = 0;
int status_size = NVME_PR_BUF_SIZE;
int status_entries;
int regctl;
int num_keys;
int err;
int fd;
int i;
int ret = 0;
devname = dev_name(dev);
if ((fd = open(devname, O_RDONLY)) < 0) {
log_error("dev_find_key_nvme %s open error %d", devname, errno);
return 0;
}
if (nvme_get_nsid(fd, &nsid)) {
if (may_fail)
log_debug("dev_find_key_nvme %s nvme_get_nsid error %d", devname, errno);
else
log_error("dev_find_key_nvme %s nvme_get_nsid error %d", devname, errno);
goto out;
}
if (!(status = malloc(status_size)))
goto out;
args.args_size = sizeof(args);
args.fd = fd;
args.nsid = nsid;
args.eds = 1;
args.len = status_size;
args.report = status;
args.timeout = 0;
args.result = NULL;
if ((err = nvme_resv_report(&args))) {
if (may_fail)
log_debug("dev_find_key_nvme %s error %d", devname, err);
else
log_error("dev_find_key_nvme %s error %d", devname, err);
goto out;
}
regctl = status->regctl[0] | (status->regctl[1] << 8);
status_entries = (status_size - 64) / 64;
if (status_entries < regctl) {
log_warn("dev_find_key_nvme %s too many entries %d limit %d", devname, regctl, status_entries);
regctl = status_entries;
}
num_keys = regctl;
log_debug("dev_find_key_nvme %s num %d", devname, num_keys);
/* caller wants just a count of all keys */
if (find_all && found_count && !found_all) {
*found_count = num_keys;
ret = 1;
goto out;
}
/* caller wants a count and array of all keys */
if (find_all && found_count && found_all) {
*found_count = num_keys;
*found_all = NULL;
if (!num_keys) {
ret = 1;
goto out;
}
if (!(all_keys = dm_pool_zalloc(cmd->mem, num_keys * sizeof(uint64_t)))) {
ret = 0;
goto out;
}
*found_all = all_keys;
}
if (!num_keys) {
ret = 1;
goto out;
}
for (i = 0; i < num_keys; i++) {
key = le64toh(status->regctl_eds[i].rkey);
log_debug("dev_find_key_nvme %s 0x%llx", devname, (unsigned long long)key);
if (find_all && found_count && found_all)
all_keys[i] = key;
if (find_key && (find_key == key)) {
if (found_key)
*found_key = 1;
if (!find_all)
break;
}
if (find_host_id && (find_host_id == (int)(key & 0xFFFF))) {
if (found_host_id_key)
*found_host_id_key = key;
if (!find_all)
break;
}
}
ret = 1;
out:
free(status);
if (close(fd))
log_sys_debug("close", devname);
return ret;
}
#else
void dev_read_nvme_wwids(struct device *dev)
{
}
int dev_read_reservation_nvme(struct cmd_context *cmd, struct device *dev, uint64_t *holder_ret, int *prtype_ret)
{
return 0;
}
int dev_find_key_nvme(struct cmd_context *cmd, struct device *dev, int may_fail,
uint64_t find_key, int *found_key,
int find_host_id, uint64_t *found_host_id_key,
int find_all, int *found_count, uint64_t **found_all)
{
return 0;
}
#endif

View File

@@ -137,8 +137,6 @@ void free_po_list(struct dm_list *list)
dm_list_del(&po->list);
free(po);
}
dm_list_init(list); /* Coverity will see empty initialized list */
}
int get_pvs_online(struct dm_list *pvs_online, const char *vgname)
@@ -206,7 +204,7 @@ int get_pvs_online(struct dm_list *pvs_online, const char *vgname)
void online_vg_file_remove(const char *vgname)
{
char path[PATH_MAX] = { 0 };
char path[PATH_MAX];
if (dm_snprintf(path, sizeof(path), "%s/%s", VGS_ONLINE_DIR, vgname) < 0) {
log_debug("Path %s/%s is too long.", VGS_ONLINE_DIR, vgname);
@@ -468,7 +466,7 @@ void online_dir_setup(struct cmd_context *cmd)
void online_lookup_file_remove(const char *vgname)
{
char path[PATH_MAX] = { 0 };
char path[PATH_MAX];
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, vgname) < 0) {
log_debug("Path %s/%s is too long.", PVS_LOOKUP_DIR, vgname);
@@ -483,7 +481,7 @@ void online_lookup_file_remove(const char *vgname)
static int _online_pvid_file_remove(char *pvid)
{
char path[PATH_MAX] = { 0 };
char path[PATH_MAX];
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid) < 0)
return_0;

File diff suppressed because it is too large Load Diff

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