1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-19 07:33:14 +03:00

Compare commits

..

45 Commits

Author SHA1 Message Date
David Teigland
74e404ce11 hints: new pvs_online type
Use a new form of hints to reduce device scanning in
vgchange -aay run by the udev rule for event based
autoactivation.

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

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

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

This new form of hints is mainly useful in the context of
event based autoactivation, during which standard hints are
not useful.  Once the system is in a steady state after startup
(devices are not regularly appearing), the standard hints are
most useful.  The pvs_online hint method could be used on a
running system, but would be no better than standard hints,
and may be inferior because pvs_online files are not rigidly
updated after system startup.
2021-07-19 13:29:54 -05:00
Vojtech Trefny
d13dce20df lvmdbusd: Use ID_FS_TYPE UDev property in udevwatch
'.ID_FS_TYPE_NEW' is a custom property added by an LVM UDev rule
which is now being removed and 'ID_FS_TYPE' has the same value.

Signed-off-by: Vojtech Trefny <vtrefny@redhat.com>
2021-07-14 12:52:22 -05:00
David Teigland
c229e321da add dracut files
pvscan-udev-initrd.sh is shell wrapper around the
pvscan command for use in the initrd lvm udev rule.
It finds the intersection of complete VG/LVs reported
by pvscan, and the VG/LVs specified on boot cmdline.
The resulting VG or LVs are printed as env-vars that
the udev rule can IMPORT, and pass to vgchange/lvchange.

64-lvm.rules calls pvscan-udev-initrd.sh/pvscan to scan
the PV to check if any VG or LVs are complete given the
new device.  The pvscan will only ever read the single
device triggering the uevent.  If any VG or LVs are
complete, the udev rule uses systemd-run to run a
vgchange or lvchange command to activate the complete
VG or LVs.  (Running vgchange or lvchange directly may
take longer than udev likes, so systemd-run --no-block
is used.)
2021-07-14 12:52:22 -05:00
Marian Csontos
8a0da7b4f5 configure: update 2021-07-14 12:52:22 -05:00
David Teigland
57c0698ec4 new udev autoactivation
new udev rule 69-dm-lvm.rules replaces
69-dm-lvm-meta.rules and lvm2-pvscan.service

udev rule calls pvscan directly on the added device

pvscan output indicates if a complete VG can be activated

udev env var LVM_VG_NAME_COMPLETE is used to pass complete
VG name from pvscan to the udev rule

udev rule uses systemd-run to run vgchange -aay <vgname>
2021-07-14 12:52:22 -05:00
David Teigland
f39fbebb04 logging: to the systemd journal
Configure via lvm.conf log/journal or command line --journal.

Possible values:
"command" records command information.
"output" records default command output.
"debug" records full command debugging.

Multiple values can be set in lvm.conf as an array.
One value can be set in --journal which is added to
values set in lvm.conf
2021-07-14 12:52:22 -05:00
David Teigland
7578a30534 pvscan: add options listlvs listvg checkcomplete
pvscan --cache <dev>
    . read only dev
    . create online file for dev

pvscan --listvg <dev>
    . read only dev
    . list VG using dev

pvscan --listlvs <dev>
    . read only dev
    . list VG using dev
    . list LVs using dev

pvscan --cache --listvg [--checkcomplete] <dev>
    . read only dev
    . create online file for dev
    . list VG using dev
    . [check online files and report if VG is complete]

pvscan --cache --listlvs [--checkcomplete] <dev>
    . read only dev
    . create online file for dev
    . list VG using dev
    . list LVs using dev
    . [check online files and report if VG is complete]
    . [check online files and report if LVs are complete]

[--vgonline]
can be used with --checkcomplete, to enable use of a vg online
file.  This results in only the first pvscan command to see
the complete VG to report 'VG complete', and others will report
'VG finished'.  This allows the caller to easily run a single
activation of the VG.

[--udevoutput]
can be used with --cache --listvg --checkcomplete, to enable
an output mode that prints LVM_VG_NAME_COMPLETE='vgname' that
a udev rule can import, and prevents other output from the
command (other output causes udev to ignore the command.)

The list of complete LVs is meant to be passed to lvchange -aay,
or the complete VG used with vgchange -aay.

When --checkcomplete is used, lvm assumes that that the output
will be used to trigger event-based autoactivation, so the pvscan
does nothing if event_activation=0 and --checkcomplete is used.

Example of listlvs
------------------

$ lvs -a vg -olvname,devices
  LV     Devices
  lv_a   /dev/loop0(0)
  lv_ab  /dev/loop0(1),/dev/loop1(1)
  lv_abc /dev/loop0(3),/dev/loop1(3),/dev/loop2(1)
  lv_b   /dev/loop1(0)
  lv_c   /dev/loop2(0)

$ pvscan --cache --listlvs --checkcomplete /dev/loop0
  pvscan[35680] PV /dev/loop0 online, VG vg incomplete (need 2).
  VG vg incomplete
  LV vg/lv_a complete
  LV vg/lv_ab incomplete
  LV vg/lv_abc incomplete

$ pvscan --cache --listlvs --checkcomplete /dev/loop1
  pvscan[35681] PV /dev/loop1 online, VG vg incomplete (need 1).
  VG vg incomplete
  LV vg/lv_b complete
  LV vg/lv_ab complete
  LV vg/lv_abc incomplete

$ pvscan --cache --listlvs --checkcomplete /dev/loop2
  pvscan[35682] PV /dev/loop2 online, VG vg is complete.
  VG vg complete
  LV vg/lv_c complete
  LV vg/lv_abc complete

Example of listvg
-----------------

$ pvscan --cache --listvg --checkcomplete /dev/loop0
  pvscan[35684] PV /dev/loop0 online, VG vg incomplete (need 2).
  VG vg incomplete

$ pvscan --cache --listvg --checkcomplete /dev/loop1
  pvscan[35685] PV /dev/loop1 online, VG vg incomplete (need 1).
  VG vg incomplete

$ pvscan --cache --listvg --checkcomplete /dev/loop2
  pvscan[35686] PV /dev/loop2 online, VG vg is complete.
  VG vg complete
2021-07-14 12:51:59 -05:00
David Teigland
fc726b60bc system_id: new appmachineid option
The new system_id_source="appmachineid" will cause
lvm to use an lvm-specific derivation of the machine-id,
instead of the machine-id directly.  This is now
recommended in place of using machineid.
2021-07-14 11:28:11 -05:00
David Teigland
8f2789a37d config: change default use_devicesfile to 1 2021-07-14 11:28:11 -05:00
David Teigland
f8357f5b98 config: comment all default settings 2021-07-14 11:28:11 -05:00
Zdenek Kabelac
d38fdb25e4 thin: fix component detection of external origin
When check active componet of thinLV with external origin,
we need to check if the external origin isn't already active.
For this however we need to use layered check for -real device.
2021-07-14 12:56:08 +02:00
David Teigland
e33c2e032c pvscan: narrow the previous commit slightly
to avoid change to pvscan-autoactivate.sh
2021-07-13 16:38:04 -05:00
David Teigland
25f0f5daac pvscan: do nothing for device removal and event_activation=0
The lvm2-pvscan service runs pvscan --cache -aay <dev> for
device addition, and pvscan --cache <dev> on device removal.
For event_activation=0, the addition does nothing.  Fix
device removal to also do nothing for event_activation=0.
Device removal was previously doing some work to process
the removal which slowed down stopping lvm2-pvscan services.
2021-07-13 16:09:54 -05:00
David Teigland
f8b52f2763 fix multipath component detection for multiple holders
sysfs-based multipath component detection quit if a
device had multiple holders, and in this case would
fail to detect a device was an mpath component.
2021-07-13 11:11:23 -05:00
David Teigland
deaf43d6f0 filter-usable: remove udev dev size check
For the pv_min_size check, always use dev_get_size()
which is commonly used elsewhere, and don't bother
asking libudev for the device size when
external_device_info_source=udev.
2021-07-13 11:11:23 -05:00
David Teigland
9048565093 devices: rework libudev usage
related to config settings:
  obtain_device_info_from_udev (controls if lvm gets
    a list of devices from readdir /dev or from libudev)
  external_device_info_source (controls if lvm asks
    libudev for device information)

. Make the obtain_device_list_from_udev setting
  affect only the choice of readdir /dev vs libudev.
  The setting no longer controls if udev is used for
  device type checks.

. Change obtain_device_list_from_udev default to 0.
  This helps avoid boot timeouts due to slow libudev
  queries, avoids reported failures from
  udev_enumerate_scan_devices, and avoids delays from
  "device not initialized in udev database" errors.
  Even without errors, for a system booting with 1024 PVs,
  lvm2-pvscan times improve from about 100 sec to 15 sec,
  and the pvscan command from about 64 sec to about 4 sec.

. For external_device_info_source="none", remove all
  libudev device info queries, and use only lvm
  native device info.

. For external_device_info_source="udev", first check
  lvm native device info, then check libudev info.

. Remove sleep/retry loop when attempting libudev
  queries for device info.  udev info will simply
  be skipped if it's not immediately available.

. Only set up a libdev connection if it will be used by
  obtain_device_list_from_udev/external_device_info_source.

. For native multipath component detection, use
  /etc/multipath/wwids.  If a device has a wwid
  matching an entry in the wwids file, then it's
  considered a multipath component.  This is
  necessary to natively detect multipath
  components when the mpath device is not set up.
2021-07-13 11:11:23 -05:00
Heming Zhao
db22a389cf toolcontext: fix double free (core dumped) issue
How to trigger:

```
~ # export LVM_SYSTEM_DIR=_
~ # pvscan
  No matching physical volumes found
double free or corruption (!prev)
Aborted (core dumped)
```

when LVM_SYSTEM_DIR is empty, _load_config_file() won't be called.

when LVM_SYSTEM_DIR is not empty, cfl->cft links into cmd->config_files
by _load_config_file()@lib/commands/toolcontext.c

core dumped code: _destroy_config()@lib/commands/toolcontext.c

```
    /* CONFIG_FILE/CONFIG_MERGED_FILES */
    if ((cft = remove_config_tree_by_source(cmd, CONFIG_MERGED_FILES)))
        config_destroy(cft);
    else if ((cft = remove_config_tree_by_source(cmd, CONFIG_FILE)))
        config_destroy(cft); <=== first free the cft

    dm_list_iterate_items(cfl, &cmd->config_files)
        config_destroy(cfl->cft); <=== double free the cft
```

Fixes: c43f2f8ae0

Signed-off-by: Heming Zhao <heming.zhao@suse.com>
2021-07-12 14:10:21 -05:00
David Teigland
66daedc6d2 skip indexing devices used by LVs in more commands
expands commit d5a06f9a7d
  "pvscan: skip indexing devices used by LVs"

The dev cache index is expensive and slow, so limit it
to commands that are used to observe the state of lvm.
The index is only used to print warnings about incorrect
device use by active LVs, e.g. if an LV is using a
multipath component device instead of the multipath
device.  Commands that continue to use the index and
print the warnings:

  fullreport, lvmdiskscan, vgs, lvs, pvs,
  vgdisplay, lvdisplay, pvdisplay,
  vgscan, lvscan, pvscan (excluding --cache)

A couple other commands were borrowing the DEV_USED_FOR_LV
flag to just check if a device was actively in use by LVs.
These are converted to the new dev_is_used_by_active_lv().
2021-07-09 13:59:31 -05:00
Zdenek Kabelac
70c32d1e74 man: vdoimport page 2021-07-09 20:50:40 +02:00
Zdenek Kabelac
ed48cb26a3 vdo: add vdoimport support
Add tool 'vdoimport' to support easy conversion of an existing VDO manager managed
VDO volumes into lvm2 managed VDO LV.

When physical converted volume is already a logical volume, conversion
happens with the VG itself, just with validation for extent_size, so
the virtually sized logical VDO volume size can be expressed in extents.

Example of basic simple usage:

vdoimport --name vg/vdolv  /dev/mapper/vdophysicalvolume
2021-07-09 14:57:59 +02:00
Zdenek Kabelac
3a92d633a5 configure: updates 2021-07-09 14:57:59 +02:00
David Teigland
d5a06f9a7d pvscan: skip indexing devices used by LVs
dev_cache_index_devs() is taking a large amount of time
when there are many PVs.  The index keeps track of
devices that are currently in use by active LVs.  This
info is used to print warnings for users in some limited
cases.

The checks/warnings that are enabled by the index are not
needed by pvscan --cache, so disable it in this case.

This may be expanded to other cases in future commits.
dev_cache_index_devs should also be improved in another
commit to avoid the extreme delays with many devices.
2021-07-06 10:18:07 -05:00
David Teigland
b876dbfc24 scan: move metadata vgname check
There have been two separate checks for metadata
validity: first that the metadata text begins with
a valid VG name, and second the checksum of the
metadata text.  These happen in different places,
which means there have been two separate error paths
for invalid metadata.  This also causes large metadata
to be read in multiple parts, the first part is read
just to check the vgname, and then remaining parts are
read later when the full metadata is needed.

This patch moves the vg name verification so it's
done just before the checksum verification, which
results in a single error path for invalid metadata,
and causes the entire metadata to be read together
rather that in parts from different parts of the code.
2021-07-06 10:10:23 -05:00
David Teigland
e035e32350 scan: retry reading metadata on error
If label_scan encounters bad vg metadata, invalidate
bcache data for the device and reread the mda_header
and metadata text back to back.  With concurrent commands
modifying large metadata, it's possible that the entire
metadata area can be rewritten in the time between a
command reading the mda_header and reading the metadata
text that the header points to.  Since the label_scan
is just assembling an initial overview of devices, it
doesn't use locking to serialize with other commands
that may be modifying the vg metadata at the same time.
2021-07-06 10:10:23 -05:00
David Teigland
d89942d157 scan: don't hold bcache block during scan
This allows data from the bcache block to be
invalidated and reread if needed.
2021-07-06 10:10:23 -05:00
David Teigland
a47e20a092 tests: skip tests that require blkid BLOCK_SIZE
Recent commit 84bd394cf9
  "writecache: use block size 4096 when no fs is found"

changed the default writecache block size from 512 to 4096
when no file system is detected.  The fs block size detection
requires the libblkid BLOCK_SIZE feature, so skip tests on
systems without this.  Otherwise, 4096 writecache added to
512 xfs leads fs io or mount failures.
2021-06-30 11:56:42 -05:00
Zdenek Kabelac
39f497b9d8 WHATS_NEW: update 2021-06-28 20:41:07 +02:00
Zdenek Kabelac
580e64e93b make: generate 2021-06-28 20:41:07 +02:00
Zdenek Kabelac
2c6a2b6e86 vdo: support vdo_pool_header_size
Add profilable configurable setting for vdo pool header size, that is
used as 'extra' empty space at the front and end of vdo-pool device
to avoid having a disk in the system the may have same data is real
vdo LV.

For some conversion cases however we may need to allow using '0' header size.

TODO: in this case we may eventually avoid adding 'linear' mapping layer
in future - but this requires further modification over lvm code base.
2021-06-28 20:41:07 +02:00
Zdenek Kabelac
5fcbc3bd7d vdo: rename variable vdo_pool_zero
Match rest of code.
2021-06-28 20:41:07 +02:00
Zdenek Kabelac
6e773bb196 lvconvert: fix vdo virtual size when specified
Correctly use virtual size specified by:
lvconvert --type vdo-pool --virtualsize
2021-06-28 20:41:07 +02:00
Zdenek Kabelac
d9cb1d3983 config_settings: typo fix 2021-06-28 18:11:14 +02:00
David Teigland
73a05c8f02 device_id: handle qemu wwid
Ignore made-up wwid values reported for qemu devices
that contain the string "QEMU HARDDISK".  The devname
will be used as the device id.
2021-06-24 11:30:46 -05:00
David Teigland
84bd394cf9 writecache: use block size 4096 when no fs is found
When there is no block size constraint from a file system
or from a user setting, use 4096 rather than 512 because of
better performance.
2021-06-23 12:38:57 -05:00
David Teigland
1139a05939 device_id: handle scsi_debug wwid
Ignore the wwid value reported by scsi_debug devices
that begin "t10.Linux   scsi_debug".  The devname
will be used as the device id.
2021-06-22 13:36:10 -05:00
David Teigland
c35f7722d5 lvconvert: allow writecache with other thinpool command syntax
"lvconvert --thinpool LV" should allow LV to have a writecache,
but there was an extra type check preventing it.
2021-06-17 16:15:18 -05:00
Tony Asleson
f773040625 lvmdbusd: Wrap json.load in try/except
In testing where we inject large amounts of additional output in stderr
we can occassionally get truncated stdout from lvm.  Catching and dumping
the json for debug before we re-raise the exception.  As this doesn't
happen without the error injecting wrapper around lvm, the error seems to
be with the wrapper.

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2021-06-17 09:14:29 -05:00
Tony Asleson
c474f174cc lvmdbusd: Handle arbitrary amounts stdout & stderr
When exec'ing lvm, it's possible to get large amounts of both stdout
and stderr depending on the state of lvm and the size of the lvm
configuration.  If we allow any of the buffers to fill we can end
up deadlocking the process.  Ensure we are handling stdout & stderr
during lvm execution.

Ref. https://bugzilla.redhat.com/show_bug.cgi?id=1966636

Signed-off-by: Tony Asleson <tasleson@redhat.com>
2021-06-17 09:14:29 -05:00
David Teigland
71cb54d92f coverity cleanups 2021-06-16 13:42:51 -05:00
Tony Asleson
f70d97b916 lvmdbusd: Defer dbus object removal
When we are walking the new lvm state comparing it to the old state we can
run into an issue where we remove a VG that is no longer present from the
object manager, but is still needed by LVs that are left to be processed.
When we try to process existing LVs to see if their state needs to be
updated, or if they need to be removed, we need to be able to reference the
VG that was associated with it.  However, if it's been removed from the
object manager we fail to find it which results in:

Traceback (most recent call last):
File "/usr/lib/python3.6/site-packages/lvmdbusd/utils.py", line 666, in _run
  self.rc = self.f(*self.args)
File "/usr/lib/python3.6/site-packages/lvmdbusd/fetch.py", line 36, in _main_thread_load
  cache_refresh=False)[1]
File "/usr/lib/python3.6/site-packages/lvmdbusd/lv.py", line 146, in load_lvs
  lv_name, object_path, refresh, emit_signal, cache_refresh)
File "/usr/lib/python3.6/site-packages/lvmdbusd/loader.py", line 68, in common
  num_changes += dbus_object.refresh(object_state=o)
File "/usr/lib/python3.6/site-packages/lvmdbusd/automatedproperties.py", line 160, in refresh
  search = self.lvm_id
File "/usr/lib/python3.6/site-packages/lvmdbusd/lv.py", line 483, in lvm_id
  return self.state.lvm_id
File "/usr/lib/python3.6/site-packages/lvmdbusd/lv.py", line 173, in lvm_id
  return "%s/%s" % (self.vg_name_lookup(), self.Name)
File "/usr/lib/python3.6/site-packages/lvmdbusd/lv.py", line 169, in vg_name_lookup
  return cfg.om.get_object_by_path(self.Vg).Name

Instead of removing objects from the object manager immediately, we will
keep them in a list and remove them once we have processed all of the state.

Ref:
https://bugzilla.redhat.com/show_bug.cgi?id=1968752
2021-06-16 12:19:02 -05:00
Tony Asleson
e8f3a63000 lvmdbusd: Don't setup search key unless needed
self.lvm_id is a property which actually executes some code which doesn't
need to be executed everytime.
2021-06-16 12:19:02 -05:00
Leo Yan
27abb03a0d tests: Fix building for IDM program
When execute IDM testing, the command reports error:

  /usr/bin/install: cannot stat ‘lib/idm_inject_failure’: No such file
  or directory

Since there have a stale program in my local environment, thus Makefile
always uses the stale program and doesn't report any issue.  In the
brand new repository, it doesn't contain an idm_inject_failure program,
and Makefile doesn't build it without specifying the dependency, thus
the test command complaints the file 'idm_inject_failure' is not found.

This patch adds the dependency 'lib/idm_inject_failure' for IDM testing,
so it can firstly build the injection program and dismiss the error.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
2021-06-16 10:35:12 -05:00
Leo Yan
f25df0386e tests: stress: Change to use $SHARED for vgcreate
Use the variable $SHARED to replace "--shared" for vgcreate commands.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
2021-06-16 10:35:12 -05:00
David Teigland
e5740e9646 tests: fix skip in stress_single_thread.sh 2021-06-16 09:37:04 -05:00
David Teigland
f8742b6df2 tests: add some LVM_TEST_LOCK_TYPE_IDM 2021-06-15 14:02:45 -05:00
95 changed files with 3696 additions and 1507 deletions

View File

@@ -1,5 +1,9 @@
Version 2.03.13 -
===============================
Fix detection of active components of external origin volume.
Add vdoimport tool to support conversion of VDO volumes.
Support configurable allocation/vdo_pool_header_size.
Fix handling of lvconvert --type vdo-pool --virtualsize.
Simplified handling of archive() and backup() internal calls.
Fix load of kvdo target when it is not present in memory (2.03.12).

View File

@@ -723,7 +723,7 @@ allocation {
# vdo_write_policy = "auto"
# Configuration option allocation/vdo_max_discard.
# Specified te maximum size of discard bio accepted, in 4096 byte blocks.
# Specified the maximum size of discard bio accepted, in 4096 byte blocks.
# I/O requests to a VDO volume are normally split into 4096-byte blocks,
# and processed up to 2048 at a time. However, discard requests to a VDO volume
# can be automatically split to a larger size, up to <max discard> 4096-byte blocks
@@ -733,6 +733,11 @@ allocation {
# The default and minimum is 1. The maximum is UINT_MAX / 4096.
# This configuration option has an automatic default value.
# vdo_max_discard = 1
# Configuration option allocation/vdo_pool_header_size.
# Specified the emptry header size in KiB at the front and end of vdo pool device.
# This configuration option has an automatic default value.
# vdo_pool_header_size = 512
}
# Configuration section log.

149
configure vendored
View File

@@ -643,6 +643,8 @@ WRITE_INSTALL
WRITECACHE
VDO_LIB
VDO_INCLUDE
VDOIMPORT_PATH
VDOIMPORT
VDO
VALGRIND_POOL
USRSBINDIR
@@ -747,7 +749,6 @@ BUILD_DMFILEMAPD
BUILD_LOCKDDLM_CONTROL
BUILD_LOCKDDLM
BUILD_LOCKDSANLOCK
BUILD_LOCKDIDM
BUILD_LVMLOCKD
BUILD_LVMPOLLD
BUILD_LVMDBUSD
@@ -775,16 +776,20 @@ SYSTEMD_LIBS
SYSTEMD_CFLAGS
BLKID_LIBS
BLKID_CFLAGS
APP_MACHINEID_LIBS
APP_MACHINEID_CFLAGS
NOTIFY_DBUS_LIBS
NOTIFY_DBUS_CFLAGS
BLKID_LIBS
BLKID_CFLAGS
LOCKD_IDM_LIBS
LOCKD_IDM_CFLAGS
LOCKD_DLM_CONTROL_LIBS
LOCKD_DLM_CONTROL_CFLAGS
LOCKD_DLM_LIBS
LOCKD_DLM_CFLAGS
LOCKD_SANLOCK_LIBS
LOCKD_SANLOCK_CFLAGS
LOCKD_IDM_LIBS
LOCKD_IDM_CFLAGS
VALGRIND_LIBS
VALGRIND_CFLAGS
GENPNG
@@ -956,6 +961,7 @@ enable_use_lvmpolld
with_lvmpolld_pidfile
enable_dmfilemapd
enable_notify_dbus
enable_app_machineid
enable_blkid_wiping
enable_udev_systemd_background_jobs
enable_udev_sync
@@ -970,6 +976,7 @@ enable_dbus_service
enable_pkgconfig
enable_write_install
enable_fsadm
enable_vdoimport
enable_blkdeactivate
enable_dmeventd
enable_selinux
@@ -1027,8 +1034,12 @@ LOCKD_IDM_CFLAGS
LOCKD_IDM_LIBS
NOTIFY_DBUS_CFLAGS
NOTIFY_DBUS_LIBS
APP_MACHINEID_CFLAGS
APP_MACHINEID_LIBS
BLKID_CFLAGS
BLKID_LIBS
NOTIFY_DBUS_CFLAGS
NOTIFY_DBUS_LIBS
SYSTEMD_CFLAGS
SYSTEMD_LIBS
UDEV_CFLAGS
@@ -1689,6 +1700,7 @@ Optional Features:
--disable-use-lvmpolld disable usage of LVM Poll Daemon
--enable-dmfilemapd enable the dmstats filemap daemon
--enable-notify-dbus enable LVM notification using dbus
--enable-app-machineid enable LVM system ID using app-specific machine-id
--disable-blkid_wiping disable libblkid detection of signatures when wiping
and use native code instead
--disable-udev-systemd-background-jobs
@@ -1708,6 +1720,7 @@ Optional Features:
--enable-pkgconfig install pkgconfig support
--enable-write_install install user writable files
--disable-fsadm disable fsadm
--disable-vdoimport disable vdoimport
--disable-blkdeactivate disable blkdeactivate
--enable-dmeventd enable the device-mapper event daemon
--disable-selinux disable selinux support
@@ -1843,10 +1856,17 @@ Some influential environment variables:
C compiler flags for LOCKD_IDM, overriding pkg-config
LOCKD_IDM_LIBS
linker flags for LOCKD_IDM, overriding pkg-config
BLKID_CFLAGS
C compiler flags for BLKID, overriding pkg-config
BLKID_LIBS linker flags for BLKID, overriding pkg-config
NOTIFY_DBUS_CFLAGS
C compiler flags for NOTIFY_DBUS, overriding pkg-config
NOTIFY_DBUS_LIBS
linker flags for NOTIFY_DBUS, overriding pkg-config
APP_MACHINEID_CFLAGS
C compiler flags for APP_MACHINEID, overriding pkg-config
APP_MACHINEID_LIBS
linker flags for APP_MACHINEID, overriding pkg-config
BLKID_CFLAGS
C compiler flags for BLKID, overriding pkg-config
BLKID_LIBS linker flags for BLKID, overriding pkg-config
@@ -3140,6 +3160,7 @@ case "$host_os" in
DM_IOCTLS=yes
SELINUX=yes
FSADM=yes
VDOIMPORT=yes
BLKDEACTIVATE=yes
;;
darwin*)
@@ -3153,6 +3174,7 @@ case "$host_os" in
DM_IOCTLS=no
SELINUX=no
FSADM=no
VDOIMPORT=no
BLKDEACTIVATE=no
;;
*)
@@ -11260,7 +11282,7 @@ fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -11278,7 +11300,7 @@ fi
$bailout
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
$bailout
else
@@ -11286,6 +11308,7 @@ else
LOCKD_IDM_LIBS=$pkg_cv_LOCKD_IDM_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
HAVE_LOCKD_IDM=yes
fi
pkg_failed=no
@@ -11582,6 +11605,101 @@ $as_echo "yes" >&6; }
fi
fi
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build appmachineid" >&5
$as_echo_n "checking whether to build appmachineid... " >&6; }
# Check whether --enable-app-machineid was given.
if test "${enable_app_machineid+set}" = set; then :
enableval=$enable_app_machineid; APP_MACHINEID_SUPPORT=$enableval
else
APP_MACHINEID_SUPPORT=no
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $APP_MACHINEID_SUPPORT" >&5
$as_echo "$APP_MACHINEID_SUPPORT" >&6; }
if test "$APP_MACHINEID_SUPPORT" = yes; then
$as_echo "#define APP_MACHINEID_SUPPORT 1" >>confdefs.h
SYSTEMD_LIBS="-lsystemd"
fi
################################################################################
if test "$APP_MACHINEID_SUPPORT" = yes; then
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for APP_MACHINEID" >&5
$as_echo_n "checking for APP_MACHINEID... " >&6; }
if test -n "$APP_MACHINEID_CFLAGS"; then
pkg_cv_APP_MACHINEID_CFLAGS="$APP_MACHINEID_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd >= 234\""; } >&5
($PKG_CONFIG --exists --print-errors "systemd >= 234") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_APP_MACHINEID_CFLAGS=`$PKG_CONFIG --cflags "systemd >= 234" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test -n "$APP_MACHINEID_LIBS"; then
pkg_cv_APP_MACHINEID_LIBS="$APP_MACHINEID_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd >= 234\""; } >&5
($PKG_CONFIG --exists --print-errors "systemd >= 234") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_APP_MACHINEID_LIBS=`$PKG_CONFIG --libs "systemd >= 234" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
APP_MACHINEID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "systemd >= 234" 2>&1`
else
APP_MACHINEID_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "systemd >= 234" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$APP_MACHINEID_PKG_ERRORS" >&5
$bailout
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
$bailout
else
APP_MACHINEID_CFLAGS=$pkg_cv_APP_MACHINEID_CFLAGS
APP_MACHINEID_LIBS=$pkg_cv_APP_MACHINEID_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
HAVE_APP_MACHINEID=yes
fi
fi
################################################################################
# Check whether --enable-blkid_wiping was given.
@@ -12544,6 +12662,18 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $FSADM" >&5
$as_echo "$FSADM" >&6; }
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install vdoimport" >&5
$as_echo_n "checking whether to install vdoimport... " >&6; }
# Check whether --enable-vdoimport was given.
if test "${enable_vdoimport+set}" = set; then :
enableval=$enable_vdoimport; VDOIMPORT=$enableval
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $VDOIMPORT" >&5
$as_echo "$VDOIMPORT" >&6; }
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install blkdeactivate" >&5
$as_echo_n "checking whether to install blkdeactivate... " >&6; }
@@ -14030,6 +14160,13 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
VDOIMPORT_PATH="$SBINDIR/vdoimport"
cat >>confdefs.h <<_ACEOF
#define VDOIMPORT_PATH "$VDOIMPORT_PATH"
_ACEOF
################################################################################
if test "$BUILD_DMEVENTD" = yes; then
@@ -14350,6 +14487,8 @@ _ACEOF

View File

@@ -46,6 +46,7 @@ case "$host_os" in
DM_IOCTLS=yes
SELINUX=yes
FSADM=yes
VDOIMPORT=yes
BLKDEACTIVATE=yes
;;
darwin*)
@@ -59,6 +60,7 @@ case "$host_os" in
DM_IOCTLS=no
SELINUX=no
FSADM=no
VDOIMPORT=no
BLKDEACTIVATE=no
;;
*)
@@ -1102,6 +1104,26 @@ if test "$NOTIFYDBUS_SUPPORT" = yes; then
PKG_CHECK_MODULES(NOTIFY_DBUS, systemd >= 221, [HAVE_NOTIFY_DBUS=yes], $bailout)
fi
################################################################################
dnl -- Build appmachineid
AC_MSG_CHECKING(whether to build appmachineid)
AC_ARG_ENABLE(app-machineid,
AC_HELP_STRING([--enable-app-machineid],
[enable LVM system ID using app-specific machine-id]),
APP_MACHINEID_SUPPORT=$enableval, APP_MACHINEID_SUPPORT=no)
AC_MSG_RESULT($APP_MACHINEID_SUPPORT)
if test "$APP_MACHINEID_SUPPORT" = yes; then
AC_DEFINE([APP_MACHINEID_SUPPORT], 1, [Define to 1 to include code that uses libsystemd machine-id apis.])
SYSTEMD_LIBS="-lsystemd"
fi
################################################################################
dnl -- Look for libsystemd libraries
if test "$APP_MACHINEID_SUPPORT" = yes; then
PKG_CHECK_MODULES(APP_MACHINEID, systemd >= 234, [HAVE_APP_MACHINEID=yes], $bailout)
fi
################################################################################
dnl -- Enable blkid wiping functionality
@@ -1311,6 +1333,14 @@ AC_ARG_ENABLE(fsadm, AC_HELP_STRING([--disable-fsadm], [disable fsadm]),
FSADM=$enableval)
AC_MSG_RESULT($FSADM)
################################################################################
dnl -- Enable vdoimport
AC_MSG_CHECKING(whether to install vdoimport)
AC_ARG_ENABLE(vdoimport, AC_HELP_STRING([--disable-vdoimport], [disable vdoimport]),
VDOIMPORT=$enableval)
AC_MSG_RESULT($VDOIMPORT)
################################################################################
dnl -- Enable blkdeactivate
AC_MSG_CHECKING(whether to install blkdeactivate)
@@ -1666,6 +1696,9 @@ USRSBINDIR="$(eval echo $(eval echo $usrsbindir))"
FSADM_PATH="$SBINDIR/fsadm"
AC_DEFINE_UNQUOTED(FSADM_PATH, ["$FSADM_PATH"], [Path to fsadm binary.])
VDOIMPORT_PATH="$SBINDIR/vdoimport"
AC_DEFINE_UNQUOTED(VDOIMPORT_PATH, ["$VDOIMPORT_PATH"], [Path to vdoimport binary.])
################################################################################
dnl -- dmeventd pidfile and executable path
if test "$BUILD_DMEVENTD" = yes; then
@@ -1902,6 +1935,8 @@ AC_SUBST(SILENT_RULES)
AC_SUBST(USRSBINDIR)
AC_SUBST(VALGRIND_POOL)
AC_SUBST(VDO)
AC_SUBST(VDOIMPORT)
AC_SUBST(VDOIMPORT_PATH)
AC_SUBST(VDO_FORMAT_CMD)
AC_SUBST(VDO_INCLUDE)
AC_SUBST(VDO_LIB)

View File

@@ -157,14 +157,15 @@ class AutomatedProperties(dbus.service.Object):
if not self._ap_search_method:
return 0
search = self.lvm_id
if search_key:
search = search_key
# Either we have the new object state or we need to go fetch it
if object_state:
new_state = object_state
else:
if search_key:
search = search_key
else:
search = self.lvm_id
new_state = self._ap_search_method([search])[0]
assert isinstance(new_state, State)

View File

@@ -9,13 +9,14 @@
import subprocess
from . import cfg
from .cmdhandler import options_to_cli_args, LvmExecutionMeta
from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm
import dbus
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
add_no_notify
import os
mt_async_call
from .request import RequestEntry
import threading
import time
import traceback
def pv_move_lv_cmd(move_options, lv_full_name,
@@ -39,58 +40,50 @@ def lv_merge_cmd(merge_options, lv_full_name):
return cmd
def _load_wrapper(ignored):
cfg.load()
def _move_callback(job_state, line_str):
try:
if line_str.count(':') == 2:
(device, ignore, percentage) = line_str.split(':')
job_state.Percent = int(round(
float(percentage.strip()[:-1]), 1))
# While the move is in progress we need to periodically update
# the state to reflect where everything is at. we will do this
# by scheduling the load to occur in the main work queue.
r = RequestEntry(
-1, _load_wrapper, ("_move_callback: load",), None, None, False)
cfg.worker_q.put(r)
except ValueError:
log_error("Trying to parse percentage which failed for %s" % line_str)
def _move_merge(interface_name, command, job_state):
# We need to execute these command stand alone by forking & exec'ing
# the command always as we will be getting periodic output from them on
# the status of the long running operation.
command.insert(0, cfg.LVM_CMD)
# Instruct lvm to not register an event with us
command = add_no_notify(command)
#(self, start, ended, cmd, ec, stdout_txt, stderr_txt)
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
cfg.blackbox.add(meta)
process = subprocess.Popen(command, stdout=subprocess.PIPE,
env=os.environ,
stderr=subprocess.PIPE, close_fds=True)
log_debug("Background process for %s is %d" %
(str(command), process.pid))
lines_iterator = iter(process.stdout.readline, b"")
for line in lines_iterator:
line_str = line.decode("utf-8")
# Check to see if the line has the correct number of separators
try:
if line_str.count(':') == 2:
(device, ignore, percentage) = line_str.split(':')
job_state.Percent = round(
float(percentage.strip()[:-1]), 1)
# While the move is in progress we need to periodically update
# the state to reflect where everything is at.
cfg.load()
except ValueError:
log_error("Trying to parse percentage which failed for %s" %
line_str)
out = process.communicate()
ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
cb_data=job_state)
with meta.lock:
meta.ended = time.time()
meta.ec = process.returncode
meta.stderr_txt = out[1]
meta.ec = ec
meta.stderr_txt = stderr
if process.returncode == 0:
if ec == 0:
job_state.Percent = 100
else:
raise dbus.exceptions.DBusException(
interface_name,
'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
'Exit code %s, stderr = %s' % (str(ec), stderr))
cfg.load()
return '/'

View File

@@ -8,6 +8,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from subprocess import Popen, PIPE
import select
import time
import threading
from itertools import chain
@@ -16,7 +17,8 @@ import traceback
import os
from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
make_non_block, read_decoded
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
try:
@@ -82,16 +84,23 @@ def _debug_c(cmd, exit_code, out):
log_error(("STDERR=\n %s\n" % out[1]))
def call_lvm(command, debug=False):
def call_lvm(command, debug=False, line_cb=None,
cb_data=None):
"""
Call an executable and return a tuple of exitcode, stdout, stderr
:param command: Command to execute
:param debug: Dump debug to stdout
"""
# print 'STACK:'
# for line in traceback.format_stack():
# print line.strip()
:param command: Command to execute
:param debug: Dump debug to stdout
:param line_cb: Call the supplied function for each line read from
stdin, CALL MUST EXECUTE QUICKLY and not *block*
otherwise call_lvm function will fail to read
stdin/stdout. Return value of call back is ignored
:param cb_data: Supplied to callback to allow caller access to
its own data
# Callback signature
def my_callback(my_context, line_read_stdin)
pass
"""
# Prepend the full lvm executable so that we can run different versions
# in different locations on the same box
command.insert(0, cfg.LVM_CMD)
@@ -99,10 +108,44 @@ def call_lvm(command, debug=False):
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
env=os.environ)
out = process.communicate()
stdout_text = bytes(out[0]).decode("utf-8")
stderr_text = bytes(out[1]).decode("utf-8")
stdout_text = ""
stderr_text = ""
stdout_index = 0
make_non_block(process.stdout)
make_non_block(process.stderr)
while True:
try:
rd_fd = [process.stdout.fileno(), process.stderr.fileno()]
ready = select.select(rd_fd, [], [], 2)
for r in ready[0]:
if r == process.stdout.fileno():
stdout_text += read_decoded(process.stdout)
elif r == process.stderr.fileno():
stderr_text += read_decoded(process.stderr)
if line_cb is not None:
# Process the callback for each line read!
while True:
i = stdout_text.find("\n", stdout_index)
if i != -1:
try:
line_cb(cb_data, stdout_text[stdout_index:i])
except:
st = traceback.format_exc()
log_error("call_lvm: line_cb exception: \n %s" % st)
stdout_index = i + 1
else:
break
# Check to see if process has terminated, None when running
if process.poll() is not None:
break
except IOError as ioe:
log_debug("call_lvm:" + str(ioe))
pass
if debug or process.returncode != 0:
_debug_c(command, process.returncode, (stdout_text, stderr_text))
@@ -584,7 +627,13 @@ def lvm_full_report_json():
assert(type(out) == dict)
return out
else:
return json.loads(out)
try:
return json.loads(out)
except json.decoder.JSONDecodeError as joe:
log_error("JSONDecodeError %s, \n JSON=\n%s\n" %
(str(joe), out))
raise joe
return None

View File

@@ -20,22 +20,30 @@ import traceback
def _main_thread_load(refresh=True, emit_signal=True):
num_total_changes = 0
to_remove = []
num_total_changes += load_pvs(
(changes, remove) = load_pvs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_vgs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
cache_refresh=False)[1:]
num_total_changes += changes
to_remove.extend(remove)
lv_changes = load_lvs(
(changes, remove) = load_vgs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
cache_refresh=False)[1:]
num_total_changes += changes
to_remove.extend(remove)
(lv_changes, remove) = load_lvs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1:]
num_total_changes += lv_changes
to_remove.extend(remove)
# When the LVs change it can cause another change in the VGs which is
# missed if we don't scan through the VGs again. We could achieve this
@@ -44,10 +52,23 @@ def _main_thread_load(refresh=True, emit_signal=True):
# changes causing the dbus object representing it to be removed and
# recreated.
if refresh and lv_changes > 0:
num_total_changes += load_vgs(
(changes, remove) = load_vgs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
cache_refresh=False)[1:]
num_total_changes += changes
to_remove.extend(remove)
# Remove any objects that are no longer needed. We do this after we process
# all the objects to ensure that references still exist for objects that
# are processed after them.
to_remove.reverse()
for i in to_remove:
dbus_obj = cfg.om.get_object_by_path(i)
if dbus_obj:
cfg.om.remove_object(dbus_obj, True)
num_total_changes += 1
return num_total_changes

View File

@@ -75,11 +75,10 @@ def common(retrieve, o_type, search_keys,
object_path = None
to_remove = []
if refresh:
for k in list(existing_paths.keys()):
cfg.om.remove_object(cfg.om.get_object_by_path(k), True)
num_changes += 1
to_remove = list(existing_paths.keys())
num_changes += len(rc)
return rc, num_changes
return rc, num_changes, to_remove

View File

@@ -13,7 +13,6 @@
import subprocess
import shlex
from fcntl import fcntl, F_GETFL, F_SETFL
import os
import traceback
import sys
@@ -29,7 +28,8 @@ except ImportError:
from lvmdbusd.cfg import LVM_CMD
from lvmdbusd.utils import log_debug, log_error, add_no_notify
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
read_decoded
SHELL_PROMPT = "lvm> "
@@ -43,13 +43,6 @@ def _quote_arg(arg):
class LVMShellProxy(object):
@staticmethod
def _read(stream):
tmp = stream.read()
if tmp:
return tmp.decode("utf-8")
return ''
# Read until we get prompt back and a result
# @param: no_output Caller expects no output to report FD
# Returns stdout, report, stderr (report is JSON!)
@@ -75,11 +68,11 @@ class LVMShellProxy(object):
for r in ready[0]:
if r == self.lvm_shell.stdout.fileno():
stdout += LVMShellProxy._read(self.lvm_shell.stdout)
stdout += read_decoded(self.lvm_shell.stdout)
elif r == self.report_stream.fileno():
report += LVMShellProxy._read(self.report_stream)
report += read_decoded(self.report_stream)
elif r == self.lvm_shell.stderr.fileno():
stderr += LVMShellProxy._read(self.lvm_shell.stderr)
stderr += read_decoded(self.lvm_shell.stderr)
# Check to see if the lvm process died on us
if self.lvm_shell.poll():
@@ -124,11 +117,6 @@ class LVMShellProxy(object):
assert (num_written == len(cmd_bytes))
self.lvm_shell.stdin.flush()
@staticmethod
def _make_non_block(stream):
flags = fcntl(stream, F_GETFL)
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
def __init__(self):
# Create a temp directory
@@ -162,8 +150,8 @@ class LVMShellProxy(object):
stderr=subprocess.PIPE, close_fds=True, shell=True)
try:
LVMShellProxy._make_non_block(self.lvm_shell.stdout)
LVMShellProxy._make_non_block(self.lvm_shell.stderr)
make_non_block(self.lvm_shell.stdout)
make_non_block(self.lvm_shell.stderr)
# wait for the first prompt
errors = self._read_until_prompt(no_output=True)[2]

View File

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

View File

@@ -14,6 +14,7 @@ import ctypes
import os
import string
import datetime
from fcntl import fcntl, F_GETFL, F_SETFL
import dbus
from lvmdbusd import cfg
@@ -681,3 +682,16 @@ def _remove_objects(dbus_objects_rm):
# Remove dbus objects from main thread
def mt_remove_dbus_objects(objs):
MThreadRunner(_remove_objects, objs).done()
# Make stream non-blocking
def make_non_block(stream):
flags = fcntl(stream, F_GETFL)
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
def read_decoded(stream):
tmp = stream.read()
if tmp:
return tmp.decode("utf-8")
return ''

44
dracut/64-lvm.rules Normal file
View File

@@ -0,0 +1,44 @@
# Copyright 2008,2021 Red Hat, Inc.
#
# Jeremy Katz <katzj@redhat.com>
SUBSYSTEM!="block", GOTO="lvm_end"
ACTION!="add|change", GOTO="lvm_end"
# Also don't process disks that are slated to be a multipath device
ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="lvm_end"
KERNEL=="dm-[0-9]*", ACTION=="add", GOTO="lvm_end"
ENV{ID_FS_TYPE}!="LVM2_member", GOTO="lvm_end"
PROGRAM=="/bin/sh -c 'for i in $sys/$devpath/holders/dm-[0-9]*; do [ -e $$i ] && exit 0; done; exit 1;' ", \
GOTO="lvm_end"
# pvscan-udev-initrd.sh is a wrapper that calls pvscan and prints
# LVM_VG_NAME_COMPLETE='...'
# LVM_LV_NAMES_COMPLETE='...'
# if the given device completes a VG or LVs listed in
# rd.lvm.vg or rd.lvm.lv
#
# If a VG or LVs are completed by the device, but are not
# listed in rd.lvm.vg/lv, then they are not printed
# (we don't want to activate VGs/LVs that are not specified.)
#
# If no VG or LVs are completed by the device, then
# nothing is printed.
#
# LVs may be complete and activated before the VG is complete,
# i.e. the entire VG is not necessary to activate LVs in it.
#
# If multiple LV names are completed from one device,
# e.g. LVM_LV_NAMES_COMPLETE='vg/lv1 vg/lv2 vg/lv3'
# they will be activated by one lvchange command.
IMPORT{program}="pvscan-udev-initrd.sh $env{DEVNAME}"
# systemd services are used to run vgchange/lvchange
# because the lvm activation commands can run for longer
# than udev will tolerate.
ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run --no-block --property DefaultDependencies=no /sbin/lvm vgchange -ay --yes --ignoremonitoring --poll n --sysinit $env{LVM_VG_NAME_COMPLETE}"
ENV{LVM_LV_NAMES_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run --no-block --property DefaultDependencies=no /sbin/lvm lvchange -ay --yes -K --ignoremonitoring --poll n --sysinit $env{LVM_LV_NAMES_COMPLETE}"
LABEL="lvm_end"

112
dracut/module-setup.sh Executable file
View File

@@ -0,0 +1,112 @@
#!/bin/bash
# called by dracut
check() {
# No point trying to support lvm if the binaries are missing
require_binaries lvm || return 1
[[ $hostonly ]] || [[ $mount_needs ]] && {
for fs in "${host_fs_types[@]}"; do
[[ $fs = LVM*_member ]] && return 0
done
return 255
}
return 0
}
# called by dracut
depends() {
# We depend on dm_mod being loaded
echo rootfs-block dm
return 0
}
# called by dracut
cmdline() {
local _activated
declare -A _activated
for dev in "${!host_fs_types[@]}"; do
[ -e /sys/block/${dev#/dev/}/dm/name ] || continue
[ -e /sys/block/${dev#/dev/}/dm/uuid ] || continue
uuid=$(</sys/block/${dev#/dev/}/dm/uuid)
[[ "${uuid#LVM-}" == "$uuid" ]] && continue
dev=$(</sys/block/${dev#/dev/}/dm/name)
eval $(dmsetup splitname --nameprefixes --noheadings --rows "$dev" 2>/dev/null)
[[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || return 1
if ! [[ ${_activated[${DM_VG_NAME}/${DM_LV_NAME}]} ]]; then
printf " rd.lvm.lv=%s " "${DM_VG_NAME}/${DM_LV_NAME} "
_activated["${DM_VG_NAME}/${DM_LV_NAME}"]=1
fi
done
}
installkernel() {
hostonly='' instmods dm-snapshot
}
# called by dracut
install() {
local _i
inst lvm
if [[ $hostonly_cmdline == "yes" ]]; then
local _lvmconf=$(cmdline)
[[ $_lvmconf ]] && printf "%s\n" "$_lvmconf" >> "${initdir}/etc/cmdline.d/90lvm.conf"
fi
inst_rules "$moddir/64-lvm.rules"
if [[ $hostonly ]] || [[ $lvmconf = "yes" ]]; then
if [ -f $dracutsysrootdir/etc/lvm/lvm.conf ]; then
inst_simple -H /etc/lvm/lvm.conf
fi
export LVM_SUPPRESS_FD_WARNINGS=1
# Also install any files needed for LVM system id support.
if [ -f $dracutsysrootdir/etc/lvm/lvmlocal.conf ]; then
inst_simple -H /etc/lvm/lvmlocal.conf
fi
eval $(lvm dumpconfig global/system_id_source &>/dev/null)
if [ "$system_id_source" == "file" ]; then
eval $(lvm dumpconfig global/system_id_file)
if [ -f "$system_id_file" ]; then
inst_simple -H $system_id_file
fi
fi
unset LVM_SUPPRESS_FD_WARNINGS
fi
inst_rules 11-dm-lvm.rules
inst_script "$moddir/pvscan-udev-initrd.sh" /usr/lib/udev/pvscan-udev-initrd.sh
inst_hook cmdline 30 "$moddir/parse-lvm.sh"
inst_libdir_file "libdevmapper-event-lvm*.so"
if [[ $hostonly ]] && type -P lvs &>/dev/null; then
for dev in "${!host_fs_types[@]}"; do
[ -e /sys/block/${dev#/dev/}/dm/name ] || continue
dev=$(</sys/block/${dev#/dev/}/dm/name)
eval $(dmsetup splitname --nameprefixes --noheadings --rows "$dev" 2>/dev/null)
[[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || continue
case "$(lvs --noheadings -o segtype ${DM_VG_NAME} 2>/dev/null)" in
*thin*|*cache*|*era*)
inst_multiple -o thin_dump thin_restore thin_check thin_repair \
cache_dump cache_restore cache_check cache_repair \
era_check era_dump era_invalidate era_restore
break;;
esac
done
fi
if ! [[ $hostonly ]]; then
inst_multiple -o thin_dump thin_restore thin_check thin_repair \
cache_dump cache_restore cache_check cache_repair \
era_check era_dump era_invalidate era_restore
fi
dracut_need_initqueue
}

18
dracut/parse-lvm.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
if [ -e /etc/lvm/lvm.conf ] && ! getargbool 1 rd.lvm.conf -d -n rd_NO_LVMCONF; then
rm -f -- /etc/lvm/lvm.conf
fi
LV_DEVS="$(getargs rd.lvm.vg -d rd_LVM_VG=) $(getargs rd.lvm.lv -d rd_LVM_LV=)"
if ! getargbool 1 rd.lvm -d -n rd_NO_LVM \
|| ( [ -z "$LV_DEVS" ] && ! getargbool 0 rd.auto ); then
info "rd.lvm=0: removing LVM activation"
rm -f -- /etc/udev/rules.d/64-lvm*.rules
else
for dev in $LV_DEVS; do
wait_for_dev -n "/dev/$dev"
done
fi

57
dracut/pvscan-udev-initrd.sh Executable file
View File

@@ -0,0 +1,57 @@
#!/bin/sh
# pvscan wrapper called by initrd lvm udev rule to find the
# intersection of complete VGs/LVs found by pvscan and the
# requested VGs/LVs from the cmdline.
#
# Used in 64-lvm.rules as:
# IMPORT{program}="pvscan-udev-initrd.sh $env{DEVNAME}"
#
# See /usr/lib/dracut/modules.d/90lvm/64-lvm.rules
dev=$1
type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
VGS=$(getargs rd.lvm.vg -d rd_LVM_VG=)
LVS=$(getargs rd.lvm.lv -d rd_LVM_LV=)
IFS=' '
# pvscan will produce a single VG line, and one or more LV lines.
# VG <name> complete
# VG <name> incomplete
# LV <name> complete
# LV <name> incomplete
#
# LV names are printed as vgname/lvname.
# We only care about the complete items.
# Each pvscan will produce a single VG line,
# and may produce zero, one or more LV lines.
PVSCAN=$(/sbin/lvm pvscan --cache --listlvs --checkcomplete --journal output --config 'global/event_activation=1' $dev)
read -r -a VGSARRAY <<< "$VGS"
for VG in "${VGSARRAY[@]}"
do
if strstr "$PVSCAN" "VG $VG complete" ; then
echo LVM_VG_NAME_COMPLETE=\'"$VG"\'
fi
done
# Combine all matching LVs into a single print containing them all,
# e.g. LVM_LV_NAMES_COMPLETE='vg/lv1 vg/lv2'
read -r -a LVSARRAY <<< "$LVS"
echo -n LVM_LV_NAMES_COMPLETE=\'
for LV in "${LVSARRAY[@]}"
do
if strstr "$PVSCAN" "LV $LV complete" ; then
echo -n "$LV "
fi
done
echo \'

View File

@@ -1,5 +1,8 @@
/* include/configure.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 to include code that uses libsystemd machine-id apis. */
#undef APP_MACHINEID_SUPPORT
/* Define to 1 to use libblkid detection of signatures when wiping. */
#undef BLKID_WIPING_SUPPORT
@@ -558,12 +561,12 @@
/* Define to 1 to include code that uses lvmlockd dlm option. */
#undef LOCKDDLM_SUPPORT
/* Define to 1 to include code that uses lvmlockd sanlock option. */
#undef LOCKDSANLOCK_SUPPORT
/* Define to 1 to include code that uses lvmlockd IDM option. */
#undef LOCKDIDM_SUPPORT
/* Define to 1 to include code that uses lvmlockd sanlock option. */
#undef LOCKDSANLOCK_SUPPORT
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
@@ -687,6 +690,9 @@
/* Enable a valgrind aware build of pool */
#undef VALGRIND_POOL
/* Path to vdoimport binary. */
#undef VDOIMPORT_PATH
/* The path to 'vdoformat', if available. */
#undef VDO_FORMAT_CMD

View File

@@ -34,6 +34,7 @@ SOURCES =\
device/dev-ext.c \
device/dev-io.c \
device/dev-md.c \
device/dev-mpath.c \
device/dev-swap.c \
device/dev-type.c \
device/dev-luks.c \

View File

@@ -2740,7 +2740,10 @@ static int _component_cb(struct logical_volume *lv, void *data)
(lv_is_thin_pool(lv) && pool_is_active(lv)))
return -1;
if (lv_is_active(lv)) {
/* External origin is activated through thinLV and uses -real suffix.
* Note: for old clustered logic we would need to check for all thins */
if ((lv_is_external_origin(lv) && lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0)) ||
lv_is_active(lv)) {
if (!lv_is_component(lv) || lv_is_visible(lv))
return -1; /* skip whole subtree */

130
lib/cache/lvmcache.c vendored
View File

@@ -88,9 +88,6 @@ static int _vgs_locked = 0;
static int _found_duplicate_vgnames = 0;
static int _outdated_warning = 0;
static const char *_scan_lock_global_file = DEFAULT_RUN_DIR "/scan_lock_global";
static int _scan_lock_global_file_exists = 0;
int lvmcache_init(struct cmd_context *cmd)
{
/*
@@ -695,7 +692,7 @@ next:
*/
info = lvmcache_info_from_pvid(pvid, NULL, 0);
if (info && dev_is_md_component(info->dev, NULL, 1)) {
if (info && dev_is_md_component(cmd, info->dev, NULL, 1)) {
/* does not go in del_cache_devs which become unused_duplicates */
log_debug_cache("PV %s drop MD component from scan selection %s", pvid, dev_name(info->dev));
lvmcache_del(info);
@@ -703,7 +700,7 @@ next:
}
dm_list_iterate_items_safe(devl, devl_safe, &altdevs) {
if (dev_is_md_component(devl->dev, NULL, 1)) {
if (dev_is_md_component(cmd, devl->dev, NULL, 1)) {
log_debug_cache("PV %s drop MD component from scan duplicates %s", pvid, dev_name(devl->dev));
dm_list_del(&devl->list);
}
@@ -802,8 +799,8 @@ next:
same_id2 = !strcmp(idname2, device_id);
}
has_lv1 = (dev1->flags & DEV_USED_FOR_LV) ? 1 : 0;
has_lv2 = (dev2->flags & DEV_USED_FOR_LV) ? 1 : 0;
has_lv1 = dev_is_used_by_active_lv(cmd, dev1, NULL, NULL, NULL, NULL);
has_lv2 = dev_is_used_by_active_lv(cmd, dev2, NULL, NULL, NULL, NULL);
in_subsys1 = dev_subsystem_part_major(dt, dev1);
in_subsys2 = dev_subsystem_part_major(dt, dev2);
@@ -857,6 +854,11 @@ next:
dev_name(dev1), has_lv1 ? "is used for" : "is not used for",
dev_name(dev2), has_lv2 ? "is used for" : "is not used for");
free((void *)idname1);
free((void *)idname2);
idname1 = NULL;
idname2 = NULL;
change = 0;
if (prev_unchosen1 && !prev_unchosen2) {
@@ -1202,7 +1204,7 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd)
(unsigned long long)pvsize, (unsigned long long)devsize,
device_hint ?: "none", dev_name(dev));
if (dev_is_md_component(dev, NULL, 1)) {
if (dev_is_md_component(cmd, dev, NULL, 1)) {
log_debug("dropping PV from md component %s", dev_name(dev));
dev->flags &= ~DEV_SCAN_FOUND_LABEL;
/* lvmcache_del will also delete vginfo if info was last one */
@@ -2745,115 +2747,19 @@ bool lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const c
return true;
}
/*
* max_size_bytes and max_size_percent may come from different areas and
* different vgs because of different area sizes.
*/
static uint64_t _max_metadata_size_bytes;
static dm_percent_t _max_metadata_size_percent = DM_PERCENT_INVALID;
static uint64_t _max_metadata_size;
void lvmcache_save_metadata_size_bytes(uint64_t val)
void lvmcache_save_metadata_size(uint64_t val)
{
if (!_max_metadata_size_bytes)
_max_metadata_size_bytes = val;
else if (_max_metadata_size_bytes < val)
_max_metadata_size_bytes = val;
if (!_max_metadata_size)
_max_metadata_size = val;
else if (_max_metadata_size < val)
_max_metadata_size = val;
}
uint64_t lvmcache_max_metadata_size_bytes(void)
uint64_t lvmcache_max_metadata_size(void)
{
return _max_metadata_size_bytes;
}
/*
* TODO: enable/disable scan_lock_global with config setting:
* y: always use it
* n: never use it
* auto (default): use based on /run/lvm/scan_lock_global
*/
void lvmcache_save_metadata_size_percent(uint64_t meta_size, uint64_t mdah_size)
{
dm_percent_t pc = dm_make_percent(meta_size, mdah_size);
if (pc == DM_PERCENT_INVALID || pc == DM_PERCENT_FAILED ||
pc == DM_PERCENT_0 || pc == DM_PERCENT_1)
return;
if (_max_metadata_size_percent == DM_PERCENT_INVALID) {
_max_metadata_size_percent = pc;
return;
}
if (_max_metadata_size_percent < pc)
_max_metadata_size_percent = pc;
}
/*
* TODO: make the percent at which scan_lock_global is used
* configurable?
*/
#define SCAN_LOCK_GLOBAL_METADATA_PERCENT (DM_PERCENT_1 * 25)
void set_scan_lock_global(struct cmd_context *cmd)
{
FILE *fp;
if (_max_metadata_size_percent == DM_PERCENT_INVALID)
return;
if (_max_metadata_size_percent >= SCAN_LOCK_GLOBAL_METADATA_PERCENT) {
if (_scan_lock_global_file_exists)
return;
log_debug("Creating %s.", _scan_lock_global_file);
if (!(fp = fopen(_scan_lock_global_file, "w")))
return;
if (fclose(fp))
stack;
} else {
if (_scan_lock_global_file_exists) {
log_debug("Unlinking %s.", _scan_lock_global_file);
if (unlink(_scan_lock_global_file))
stack;
}
}
}
int do_scan_lock_global(struct cmd_context *cmd, int *gl_ex)
{
struct stat buf;
if (cmd->nolocking)
return 0;
/* global lock is already held */
if (cmd->lockf_global_ex)
return 0;
if (!stat(_scan_lock_global_file, &buf)) {
_scan_lock_global_file_exists = 1;
/*
* Tell the caller to use sh or ex. A command that may write
* vg metadata should use ex, otherwise sh.
*
* lockd_vg_default_sh/LOCKD_VG_SH is set for commands that
* do not modify vg metadata.
*
* FIXME: this variable/flag was previously used only for
* lvmlockd locking logic, but is now more general, so
* it should be renamed.
*/
if (cmd->lockd_vg_default_sh)
*gl_ex = 0;
else
*gl_ex = 1;
return 1;
}
return 0;
return _max_metadata_size;
}
int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, char *pvid)

View File

@@ -183,9 +183,8 @@ bool lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const c
int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, char *pvid);
uint64_t lvmcache_max_metadata_size_bytes(void);
void lvmcache_save_metadata_size_bytes(uint64_t val);
void lvmcache_save_metadata_size_percent(uint64_t meta_size, uint64_t mdah_size);
uint64_t lvmcache_max_metadata_size(void);
void lvmcache_save_metadata_size(uint64_t val);
int dev_in_device_list(struct device *dev, struct dm_list *head);
@@ -227,8 +226,4 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd);
unsigned int lvmcache_vg_info_count(void);
void set_scan_lock_global(struct cmd_context *cmd);
int do_scan_lock_global(struct cmd_context *cmd, int *gl_ex);
#endif

View File

@@ -41,6 +41,10 @@
#include <syslog.h>
#include <time.h>
#ifdef APP_MACHINEID_SUPPORT
#include <systemd/sd-id128.h>
#endif
#ifdef __linux__
# include <malloc.h>
#endif
@@ -129,9 +133,12 @@ static const char *_read_system_id_from_file(struct cmd_context *cmd, const char
return system_id;
}
/* systemd-id128 new produced: f64406832c2140e8ac5422d1089aae03 */
#define LVM_APPLICATION_ID SD_ID128_MAKE(f6,44,06,83,2c,21,40,e8,ac,54,22,d1,08,9a,ae,03)
static const char *_system_id_from_source(struct cmd_context *cmd, const char *source)
{
char filebuf[PATH_MAX];
char buf[PATH_MAX];
const char *file;
const char *etc_str;
const char *str;
@@ -150,10 +157,23 @@ static const char *_system_id_from_source(struct cmd_context *cmd, const char *s
goto out;
}
#ifdef APP_MACHINEID_SUPPORT
if (!strcasecmp(source, "appmachineid")) {
sd_id128_t id;
sd_id128_get_machine_app_specific(LVM_APPLICATION_ID, &id);
if (dm_snprintf(buf, PATH_MAX, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)) < 0)
stack;
system_id = system_id_from_string(cmd, buf);
goto out;
}
#endif
if (!strcasecmp(source, "machineid") || !strcasecmp(source, "machine-id")) {
etc_str = find_config_tree_str(cmd, global_etc_CFG, NULL);
if (dm_snprintf(filebuf, sizeof(filebuf), "%s/machine-id", etc_str) != -1)
system_id = _read_system_id_from_file(cmd, filebuf);
if (dm_snprintf(buf, sizeof(buf), "%s/machine-id", etc_str) != -1)
system_id = _read_system_id_from_file(cmd, buf);
goto out;
}
@@ -320,6 +340,33 @@ static int _parse_debug_classes(struct cmd_context *cmd)
return debug_classes;
}
static uint32_t _parse_log_journal(struct cmd_context *cmd, int cfg, const char *cfgname)
{
const struct dm_config_node *cn;
const struct dm_config_value *cv;
uint32_t fields = 0;
uint32_t val;
if (!(cn = find_config_tree_array(cmd, cfg, NULL))) {
log_debug("Unable to find configuration for log/%s.", cfgname);
return 0;
}
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
log_verbose("log/%s contains a value which is not a string. Ignoring.", cfgname);
continue;
}
if ((val = log_journal_str_to_val(cv->v.str)))
fields |= val;
else
log_verbose("Unrecognised value for log/%s: %s", cfgname, cv->v.str);
}
return fields;
}
static void _init_logging(struct cmd_context *cmd)
{
int append = 1;
@@ -388,6 +435,9 @@ static void _init_logging(struct cmd_context *cmd)
init_debug_file_fields(_parse_debug_fields(cmd, log_debug_file_fields_CFG, "debug_file_fields"));
init_debug_output_fields(_parse_debug_fields(cmd, log_debug_output_fields_CFG, "debug_output_fields"));
cmd->default_settings.journal = _parse_log_journal(cmd, log_journal_CFG, "journal");
init_log_journal(cmd->default_settings.journal);
t = time(NULL);
ctime_r(&t, &timebuf[0]);
timebuf[24] = '\0';
@@ -402,15 +452,12 @@ static void _init_logging(struct cmd_context *cmd)
reset_lvm_errno(1);
}
static int _check_disable_udev(const char *msg) {
static int _check_disable_udev(const char *msg)
{
if (getenv("DM_DISABLE_UDEV")) {
log_very_verbose("DM_DISABLE_UDEV environment variable set. "
"Overriding configuration to use "
"udev_rules=0, udev_sync=0, verify_udev_operations=1.");
if (udev_is_running())
log_warn("Udev is running and DM_DISABLE_UDEV environment variable is set. "
"Bypassing udev, LVM will %s.", msg);
log_very_verbose("DM_DISABLE_UDEV environment variable set.");
log_very_verbose("Overriding configuration to use udev_rules=0, udev_sync=0, verify_udev_operations=1.");
log_very_verbose("LVM will %s.", msg);
return 1;
}
@@ -563,7 +610,7 @@ static int _init_system_id(struct cmd_context *cmd)
static int _process_config(struct cmd_context *cmd)
{
mode_t old_umask;
const char *dev_ext_info_src;
const char *dev_ext_info_src = NULL;
const char *read_ahead;
struct stat st;
const struct dm_config_node *cn;
@@ -597,15 +644,26 @@ static int _process_config(struct cmd_context *cmd)
#endif
dev_ext_info_src = find_config_tree_str(cmd, devices_external_device_info_source_CFG, NULL);
if (dev_ext_info_src && !strcmp(dev_ext_info_src, "none"))
init_external_device_info_source(DEV_EXT_NONE);
else if (dev_ext_info_src && !strcmp(dev_ext_info_src, "udev"))
init_external_device_info_source(DEV_EXT_UDEV);
else {
log_error("Invalid external device info source specification.");
return 0;
if (dev_ext_info_src &&
strcmp(dev_ext_info_src, "none") &&
strcmp(dev_ext_info_src, "udev")) {
log_warn("WARNING: unknown external device info source, using none.");
dev_ext_info_src = NULL;
}
if (dev_ext_info_src && !strcmp(dev_ext_info_src, "udev")) {
if (udev_init_library_context()) {
init_external_device_info_source(DEV_EXT_UDEV);
} else {
log_warn("WARNING: failed to init udev for external device info, using none.");
dev_ext_info_src = NULL;
}
}
if (!dev_ext_info_src || !strcmp(dev_ext_info_src, "none"))
init_external_device_info_source(DEV_EXT_NONE);
/* proc dir */
if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
find_config_tree_str(cmd, global_proc_CFG, NULL)) < 0) {
@@ -966,8 +1024,13 @@ static void _destroy_config(struct cmd_context *cmd)
/* CONFIG_FILE/CONFIG_MERGED_FILES */
if ((cft = remove_config_tree_by_source(cmd, CONFIG_MERGED_FILES)))
config_destroy(cft);
else if ((cft = remove_config_tree_by_source(cmd, CONFIG_FILE)))
else if ((cft = remove_config_tree_by_source(cmd, CONFIG_FILE))) {
dm_list_iterate_items(cfl, &cmd->config_files) {
if (cfl->cft == cft)
dm_list_del(&cfl->list);
}
config_destroy(cft);
}
dm_list_iterate_items(cfl, &cmd->config_files)
config_destroy(cfl->cft);
@@ -1013,16 +1076,10 @@ static int _init_dev_cache(struct cmd_context *cmd)
if (!dev_cache_init(cmd))
return_0;
/*
* Override existing config and hardcode device_list_from_udev = 0 if:
* - udev is not running
* - udev is disabled using DM_DISABLE_UDEV environment variable
*/
if (_check_disable_udev("obtain device list by scanning device directory"))
device_list_from_udev = 0;
else
device_list_from_udev = udev_is_running() ?
find_config_tree_bool(cmd, devices_obtain_device_list_from_udev_CFG, NULL) : 0;
if ((device_list_from_udev = find_config_tree_bool(cmd, devices_obtain_device_list_from_udev_CFG, NULL))) {
if (!udev_init_library_context())
device_list_from_udev = 0;
}
init_obtain_device_list_from_udev(device_list_from_udev);
@@ -1177,7 +1234,7 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
nr_filt++;
}
if (!(composite = composite_filter_create(nr_filt, 1, filters)))
if (!(composite = composite_filter_create(nr_filt, filters)))
goto_bad;
return composite;
@@ -1608,6 +1665,7 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
cmd->handles_missing_pvs = 0;
cmd->handles_unknown_segments = 0;
cmd->hosttags = 0;
cmd->check_devs_used = 1;
dm_list_init(&cmd->arg_value_groups);
dm_list_init(&cmd->formats);
dm_list_init(&cmd->segtypes);

View File

@@ -29,6 +29,7 @@ struct config_info {
int debug_classes;
int verbose;
int silent;
int suppress;
int test;
int syslog;
int activation;
@@ -40,6 +41,7 @@ struct config_info {
int udev_sync;
int udev_fallback;
int issue_discards;
uint32_t journal;
const char *msg_prefix;
const char *fmt_name;
const char *dmeventd_executable;
@@ -180,6 +182,7 @@ struct cmd_context {
unsigned enable_hints:1; /* hints are enabled for cmds in general */
unsigned use_hints:1; /* if hints are enabled this cmd can use them */
unsigned pvscan_recreate_hints:1; /* enable special case hint handling for pvscan --cache */
unsigned hints_pvs_online:1; /* hints="pvs_online" */
unsigned scan_lvs:1;
unsigned wipe_outdated_pvs:1;
unsigned enable_devices_list:1; /* command is using --devices option */
@@ -192,6 +195,7 @@ struct cmd_context {
unsigned filter_nodata_only:1; /* only use filters that do not require data from the dev */
unsigned run_by_dmeventd:1; /* command is being run by dmeventd */
unsigned sysinit:1; /* --sysinit is used */
unsigned check_devs_used:1; /* check devs used by LVs */
/*
* Devices and filtering.
@@ -256,7 +260,6 @@ struct cmd_context {
unsigned rand_seed;
struct dm_list pending_delete; /* list of LVs for removal */
struct dm_pool *pending_delete_mem; /* memory pool for pending deletes */
int early_lock_vg_mode;
};
/*

View File

@@ -501,6 +501,9 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
checksum_fn_t checksum_fn, uint32_t checksum,
int checksum_only, int no_dup_node_check)
{
char namebuf[NAME_LEN + 1] __attribute__((aligned(8)));
int namelen = 0;
int bad_name = 0;
char *fb, *fe;
int r = 0;
int sz, use_plain_read = 1;
@@ -548,6 +551,23 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
fb = buf;
if (!(dev->flags & DEV_REGULAR)) {
memcpy(namebuf, buf, NAME_LEN);
while (namebuf[namelen] && !isspace(namebuf[namelen]) && namebuf[namelen] != '{' && namelen < (NAME_LEN - 1))
namelen++;
namebuf[namelen] = '\0';
/*
* Check that the text metadata begins with a valid name.
*/
if (!validate_name(namebuf)) {
log_warn("WARNING: Metadata location on %s at offset %llu begins with invalid name.",
dev_name(dev), (unsigned long long)offset);
bad_name = 1;
}
}
/*
* The checksum passed in is the checksum from the mda_header
* preceding this metadata. They should always match.
@@ -557,10 +577,13 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
if (checksum_fn && checksum !=
(checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)fb, size),
(const uint8_t *)(fb + size), size2))) {
log_error("%s: Checksum error at offset %" PRIu64, dev_name(dev), (uint64_t) offset);
log_warn("WARNING: Checksum error on %s at offset %llu.", dev_name(dev), (unsigned long long)offset);
goto out;
}
if (bad_name)
goto out;
if (!checksum_only) {
fe = fb + size + size2;
if (no_dup_node_check) {

View File

@@ -205,7 +205,7 @@ cfg_section(local_CFG_SECTION, "local", root_CFG_SECTION, 0, vsn(2, 2, 117), 0,
"# Please take care that each setting only appears once if uncommenting\n" \
"# example settings in this file and never copy this file between hosts.\n\n"
cfg(config_checks_CFG, "checks", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 99), NULL, 0, NULL,
cfg(config_checks_CFG, "checks", config_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 2, 99), NULL, 0, NULL,
"If enabled, any LVM configuration mismatch is reported.\n"
"This implies checking that the configuration key is understood by\n"
"LVM and that the value of the key is the proper type. If disabled,\n"
@@ -213,22 +213,22 @@ cfg(config_checks_CFG, "checks", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2,
"without any warning (a message about the configuration key not being\n"
"found is issued in verbose mode only).\n")
cfg(config_abort_on_errors_CFG, "abort_on_errors", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2,2,99), NULL, 0, NULL,
cfg(config_abort_on_errors_CFG, "abort_on_errors", config_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2,2,99), NULL, 0, NULL,
"Abort the LVM process if a configuration mismatch is found.\n")
cfg_runtime(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, vsn(2, 2, 99), 0, NULL,
cfg_runtime(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, vsn(2, 2, 99), 0, NULL,
"Directory where LVM looks for configuration profiles.\n")
cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_DEV_DIR, vsn(1, 0, 0), NULL, 0, NULL,
cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_DEV_DIR, vsn(1, 0, 0), NULL, 0, NULL,
"Directory in which to create volume group device nodes.\n"
"Commands also accept this as a prefix on volume group names.\n")
cfg_array(devices_scan_CFG, "scan", devices_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, "#S/dev", vsn(1, 0, 0), NULL, 0, NULL,
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")
cfg_array(devices_loopfiles_CFG, "loopfiles", devices_CFG_SECTION, CFG_DEFAULT_UNDEFINED | CFG_UNSUPPORTED, CFG_TYPE_STRING, NULL, vsn(1, 2, 0), NULL, vsn(2, 3, 0), NULL, NULL)
cfg(devices_obtain_device_list_from_udev_CFG, "obtain_device_list_from_udev", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV, vsn(2, 2, 85), NULL, 0, NULL,
cfg(devices_obtain_device_list_from_udev_CFG, "obtain_device_list_from_udev", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV, vsn(2, 2, 85), NULL, 0, NULL,
"Obtain the list of available devices from udev.\n"
"This avoids opening or using any inapplicable non-block devices or\n"
"subdirectories found in the udev directory. Any device node or\n"
@@ -237,23 +237,11 @@ cfg(devices_obtain_device_list_from_udev_CFG, "obtain_device_list_from_udev", de
"directories will be scanned fully. LVM needs to be compiled with\n"
"udev support for this setting to apply.\n")
cfg(devices_external_device_info_source_CFG, "external_device_info_source", devices_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE, vsn(2, 2, 116), NULL, 0, NULL,
"Select an external device information source.\n"
"Some information may already be available in the system and LVM can\n"
"use this information to determine the exact type or use of devices it\n"
"processes. Using an existing external device information source can\n"
"speed up device processing as LVM does not need to run its own native\n"
"routines to acquire this information. For example, this information\n"
"is used to drive LVM filtering like MD component detection, multipath\n"
"component detection, partition detection and others.\n"
"#\n"
"Accepted values:\n"
" none\n"
" No external device information source is used.\n"
" udev\n"
" Reuse existing udev database records. Applicable only if LVM is\n"
" compiled with udev support.\n"
"#\n")
cfg(devices_external_device_info_source_CFG, "external_device_info_source", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE, vsn(2, 2, 116), NULL, 0, NULL,
"Enable device information from udev.\n"
"If set to \"udev\", lvm will supplement its own native device information\n"
"with information from libudev. This can potentially improve the detection\n"
"of MD component devices and multipath component devices.\n")
cfg(devices_hints_CFG, "hints", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_HINTS, vsn(2, 3, 2), NULL, 0, NULL,
"Use a local file to remember which devices have PVs on them.\n"
@@ -372,12 +360,12 @@ cfg_array(devices_types_CFG, "types", devices_CFG_SECTION, CFG_DEFAULT_UNDEFINED
"types = [ \"fd\", 16 ]\n"
"#\n")
cfg(devices_sysfs_scan_CFG, "sysfs_scan", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SYSFS_SCAN, vsn(1, 0, 8), NULL, 0, NULL,
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")
cfg(devices_scan_lvs_CFG, "scan_lvs", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SCAN_LVS, vsn(2, 2, 182), NULL, 0, NULL,
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,
"Scan LVM LVs for layered PVs, allowing LVs to be used as PVs.\n"
"When 1, LVM will detect PVs layered on LVs, and caution must be\n"
"taken to avoid a host accessing a layered VG that may not belong\n"
@@ -390,10 +378,14 @@ cfg(devices_scan_lvs_CFG, "scan_lvs", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEF
"an LV. The LVs are ignored using a built in device filter that\n"
"identifies and excludes LVs.\n")
cfg(devices_multipath_component_detection_CFG, "multipath_component_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MULTIPATH_COMPONENT_DETECTION, vsn(2, 2, 89), NULL, 0, NULL,
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")
cfg(devices_md_component_detection_CFG, "md_component_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MD_COMPONENT_DETECTION, vsn(1, 0, 18), NULL, 0, NULL,
cfg(devices_multipath_wwids_file_CFG, "multipath_wwids_file", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ALLOW_EMPTY, CFG_TYPE_STRING, DEFAULT_WWIDS_FILE, vsn(2, 3, 13), NULL, 0, NULL,
"The path to the multipath wwids file used for multipath component detection.\n"
"Set this to an empty string to disable the use of the multipath wwids file.\n")
cfg(devices_md_component_detection_CFG, "md_component_detection", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_MD_COMPONENT_DETECTION, vsn(1, 0, 18), NULL, 0, NULL,
"Enable detection and exclusion of MD component devices.\n"
"An MD component device is a block device that MD uses as part\n"
"of a software RAID virtual device. When an LVM PV is created\n"
@@ -419,12 +411,12 @@ cfg(devices_md_component_checks_CFG, "md_component_checks", devices_CFG_SECTION,
" This requires an extra read at the end of devices.\n"
"#\n")
cfg(devices_fw_raid_component_detection_CFG, "fw_raid_component_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_FW_RAID_COMPONENT_DETECTION, vsn(2, 2, 112), NULL, 0, NULL,
cfg(devices_fw_raid_component_detection_CFG, "fw_raid_component_detection", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FW_RAID_COMPONENT_DETECTION, vsn(2, 2, 112), NULL, 0, NULL,
"Ignore devices that are components of firmware RAID devices.\n"
"LVM must use an external_device_info_source other than none for this\n"
"detection to execute.\n")
cfg(devices_md_chunk_alignment_CFG, "md_chunk_alignment", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MD_CHUNK_ALIGNMENT, vsn(2, 2, 48), NULL, 0, NULL,
cfg(devices_md_chunk_alignment_CFG, "md_chunk_alignment", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_MD_CHUNK_ALIGNMENT, vsn(2, 2, 48), NULL, 0, NULL,
"Align the start of a PV data area with md device's stripe-width.\n"
"This applies if a PV is placed directly on an md device.\n"
"default_data_alignment will be overridden if it is not aligned\n"
@@ -438,7 +430,7 @@ cfg(devices_default_data_alignment_CFG, "default_data_alignment", devices_CFG_SE
"This setting is overridden by data_alignment and the --dataalignment\n"
"option.\n")
cfg(devices_data_alignment_detection_CFG, "data_alignment_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_DATA_ALIGNMENT_DETECTION, vsn(2, 2, 51), NULL, 0, NULL,
cfg(devices_data_alignment_detection_CFG, "data_alignment_detection", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_DATA_ALIGNMENT_DETECTION, vsn(2, 2, 51), NULL, 0, NULL,
"Align the start of a PV data area with sysfs io properties.\n"
"The start of a PV data area will be a multiple of minimum_io_size or\n"
"optimal_io_size exposed in sysfs. minimum_io_size is the smallest\n"
@@ -452,14 +444,14 @@ cfg(devices_data_alignment_detection_CFG, "data_alignment_detection", devices_CF
"This setting is overridden by data_alignment and the --dataalignment\n"
"option.\n")
cfg(devices_data_alignment_CFG, "data_alignment", devices_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(2, 2, 45), NULL, 0, NULL,
cfg(devices_data_alignment_CFG, "data_alignment", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(2, 2, 45), NULL, 0, NULL,
"Align the start of a PV data area with this number of KiB.\n"
"When non-zero, this setting overrides default_data_alignment.\n"
"Set to 0 to disable, in which case default_data_alignment\n"
"is used to align the first PE in units of MiB.\n"
"This setting is overridden by the --dataalignment option.\n")
cfg(devices_data_alignment_offset_detection_CFG, "data_alignment_offset_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_DATA_ALIGNMENT_OFFSET_DETECTION, vsn(2, 2, 50), NULL, 0, NULL,
cfg(devices_data_alignment_offset_detection_CFG, "data_alignment_offset_detection", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_DATA_ALIGNMENT_OFFSET_DETECTION, vsn(2, 2, 50), NULL, 0, NULL,
"Shift the start of an aligned PV data area based on sysfs information.\n"
"After a PV data area is aligned, it will be shifted by the\n"
"alignment_offset exposed in sysfs. This offset is often 0, but may\n"
@@ -469,12 +461,12 @@ cfg(devices_data_alignment_offset_detection_CFG, "data_alignment_offset_detectio
"LBA -1, and consequently sector 63 is aligned on a 4KiB boundary).\n"
"This setting is overridden by the --dataalignmentoffset option.\n")
cfg(devices_ignore_suspended_devices_CFG, "ignore_suspended_devices", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_IGNORE_SUSPENDED_DEVICES, vsn(1, 2, 19), NULL, 0, NULL,
cfg(devices_ignore_suspended_devices_CFG, "ignore_suspended_devices", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_IGNORE_SUSPENDED_DEVICES, vsn(1, 2, 19), NULL, 0, NULL,
"Ignore DM devices that have I/O suspended while scanning devices.\n"
"Otherwise, LVM waits for a suspended device to become accessible.\n"
"This should only be needed in recovery situations.\n")
cfg(devices_ignore_lvm_mirrors_CFG, "ignore_lvm_mirrors", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_IGNORE_LVM_MIRRORS, vsn(2, 2, 104), NULL, 0, NULL,
cfg(devices_ignore_lvm_mirrors_CFG, "ignore_lvm_mirrors", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_IGNORE_LVM_MIRRORS, vsn(2, 2, 104), NULL, 0, NULL,
"Do not scan 'mirror' LVs to avoid possible deadlocks.\n"
"This avoids possible deadlocks when using the 'mirror' segment type.\n"
"This setting determines whether LVs using the 'mirror' segment type\n"
@@ -492,19 +484,19 @@ cfg(devices_ignore_lvm_mirrors_CFG, "ignore_lvm_mirrors", devices_CFG_SECTION, 0
"apply to LVM RAID types like 'raid1' which handle failures in a\n"
"different way, making them a better choice for VG stacking.\n")
cfg(devices_disable_after_error_count_CFG, "disable_after_error_count", devices_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(2, 2, 75), NULL, vsn(2, 3, 0), NULL,
cfg(devices_disable_after_error_count_CFG, "disable_after_error_count", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(2, 2, 75), NULL, vsn(2, 3, 0), NULL,
NULL)
cfg(devices_require_restorefile_with_uuid_CFG, "require_restorefile_with_uuid", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_REQUIRE_RESTOREFILE_WITH_UUID, vsn(2, 2, 73), NULL, 0, NULL,
cfg(devices_require_restorefile_with_uuid_CFG, "require_restorefile_with_uuid", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REQUIRE_RESTOREFILE_WITH_UUID, vsn(2, 2, 73), NULL, 0, NULL,
"Allow use of pvcreate --uuid without requiring --restorefile.\n")
cfg(devices_pv_min_size_CFG, "pv_min_size", devices_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_PV_MIN_SIZE_KB, vsn(2, 2, 85), NULL, 0, NULL,
cfg(devices_pv_min_size_CFG, "pv_min_size", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_PV_MIN_SIZE_KB, vsn(2, 2, 85), NULL, 0, NULL,
"Minimum size in KiB of block devices which can be used as PVs.\n"
"In a clustered environment all nodes must use the same value.\n"
"Any value smaller than 512KiB is ignored. The previous built-in\n"
"value was 512.\n")
cfg(devices_issue_discards_CFG, "issue_discards", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ISSUE_DISCARDS, vsn(2, 2, 85), NULL, 0, NULL,
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 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"
@@ -516,7 +508,7 @@ cfg(devices_issue_discards_CFG, "issue_discards", devices_CFG_SECTION, 0, CFG_TY
"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, 0, CFG_TYPE_BOOL, DEFAULT_ALLOW_CHANGES_WITH_DUPLICATE_PVS, vsn(2, 2, 153), NULL, 0, NULL,
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"
"When a PV appears on multiple devices, LVM attempts to choose the\n"
"best device to use for the PV. If the devices represent the same\n"
@@ -528,7 +520,7 @@ cfg(devices_allow_changes_with_duplicate_pvs_CFG, "allow_changes_with_duplicate_
"Enabling this setting allows the VG to be used as usual even with\n"
"uncertain devices.\n")
cfg(devices_allow_mixed_block_sizes_CFG, "allow_mixed_block_sizes", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 3, 6), NULL, 0, NULL,
cfg(devices_allow_mixed_block_sizes_CFG, "allow_mixed_block_sizes", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 3, 6), NULL, 0, NULL,
"Allow PVs in the same VG with different logical block sizes.\n"
"When allowed, the user is responsible to ensure that an LV is\n"
"using PVs with matching block sizes when necessary.\n")
@@ -551,14 +543,14 @@ cfg_array(allocation_cling_tag_list_CFG, "cling_tag_list", allocation_CFG_SECTIO
"cling_tag_list = [ \"@site1\", \"@site2\" ]\n"
"#\n")
cfg(allocation_maximise_cling_CFG, "maximise_cling", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MAXIMISE_CLING, vsn(2, 2, 85), NULL, 0, NULL,
cfg(allocation_maximise_cling_CFG, "maximise_cling", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_MAXIMISE_CLING, vsn(2, 2, 85), NULL, 0, NULL,
"Use a previous allocation algorithm.\n"
"Changes made in version 2.02.85 extended the reach of the 'cling'\n"
"policies to detect more situations where data can be grouped onto\n"
"the same disks. This setting can be used to disable the changes\n"
"and revert to the previous algorithm.\n")
cfg(allocation_use_blkid_wiping_CFG, "use_blkid_wiping", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_BLKID_WIPING, vsn(2, 2, 105), "@DEFAULT_USE_BLKID_WIPING@", 0, NULL,
cfg(allocation_use_blkid_wiping_CFG, "use_blkid_wiping", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_BLKID_WIPING, vsn(2, 2, 105), "@DEFAULT_USE_BLKID_WIPING@", 0, NULL,
"Use blkid to detect and erase existing signatures on new PVs and LVs.\n"
"The blkid library can detect more signatures than the native LVM\n"
"detection code, but may take longer. LVM needs to be compiled with\n"
@@ -567,7 +559,7 @@ cfg(allocation_use_blkid_wiping_CFG, "use_blkid_wiping", allocation_CFG_SECTION,
"swap signature, and LUKS signatures. To see the list of signatures\n"
"recognized by blkid, check the output of the 'blkid -k' command.\n")
cfg(allocation_wipe_signatures_when_zeroing_new_lvs_CFG, "wipe_signatures_when_zeroing_new_lvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 105), NULL, 0, NULL,
cfg(allocation_wipe_signatures_when_zeroing_new_lvs_CFG, "wipe_signatures_when_zeroing_new_lvs", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 2, 105), NULL, 0, NULL,
"Look for and erase any signatures while zeroing a new LV.\n"
"The --wipesignatures option overrides this setting.\n"
"Zeroing is controlled by the -Z/--zero option, and if not specified,\n"
@@ -583,7 +575,7 @@ cfg(allocation_wipe_signatures_when_zeroing_new_lvs_CFG, "wipe_signatures_when_z
"When this setting is disabled, signatures on new LVs are not detected\n"
"or erased unless the --wipesignatures option is used directly.\n")
cfg(allocation_mirror_logs_require_separate_pvs_CFG, "mirror_logs_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MIRROR_LOGS_REQUIRE_SEPARATE_PVS, vsn(2, 2, 85), NULL, 0, NULL,
cfg(allocation_mirror_logs_require_separate_pvs_CFG, "mirror_logs_require_separate_pvs", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_MIRROR_LOGS_REQUIRE_SEPARATE_PVS, vsn(2, 2, 85), NULL, 0, NULL,
"Mirror logs and images will always use different PVs.\n"
"The default setting changed in version 2.02.85.\n")
@@ -807,7 +799,7 @@ cfg(allocation_vdo_write_policy_CFG, "vdo_write_policy", allocation_CFG_SECTION,
" Data which has not been flushed is not guaranteed to persist in this mode.\n")
cfg(allocation_vdo_max_discard_CFG, "vdo_max_discard", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_MAX_DISCARD, VDO_1ST_VSN, NULL, 0, NULL,
"Specified te maximum size of discard bio accepted, in 4096 byte blocks.\n"
"Specified the maximum size of discard bio accepted, in 4096 byte blocks.\n"
"I/O requests to a VDO volume are normally split into 4096-byte blocks,\n"
"and processed up to 2048 at a time. However, discard requests to a VDO volume\n"
"can be automatically split to a larger size, up to <max discard> 4096-byte blocks\n"
@@ -816,6 +808,9 @@ cfg(allocation_vdo_max_discard_CFG, "vdo_max_discard", allocation_CFG_SECTION, C
"increased latency for the individual discard requests.\n"
"The default and minimum is 1. The maximum is UINT_MAX / 4096.\n")
cfg(allocation_vdo_pool_header_size_CFG, "vdo_pool_header_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_POOL_HEADER_SIZE_KB, vsn(2, 3, 12), NULL, 0, NULL,
"Specified the emptry header size in KiB at the front and end of vdo pool device.\n")
cfg(log_report_command_log_CFG, "report_command_log", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_BOOL, DEFAULT_COMMAND_LOG_REPORT, vsn(2, 2, 158), NULL, 0, NULL,
"Enable or disable LVM log reporting.\n"
"If enabled, LVM will collect a log of operations, messages,\n"
@@ -857,10 +852,10 @@ cfg(log_command_log_selection_CFG, "command_log_selection", log_CFG_SECTION, CFG
"For more information about selection criteria in general, see\n"
"lvm(8) man page.\n")
cfg(log_verbose_CFG, "verbose", log_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_VERBOSE, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_verbose_CFG, "verbose", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VERBOSE, vsn(1, 0, 0), NULL, 0, NULL,
"Controls the messages sent to stdout or stderr.\n")
cfg(log_silent_CFG, "silent", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SILENT, vsn(2, 2, 98), NULL, 0, NULL,
cfg(log_silent_CFG, "silent", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_SILENT, vsn(2, 2, 98), NULL, 0, NULL,
"Suppress all non-essential messages from stdout.\n"
"This has the same effect as -qq. When enabled, the following commands\n"
"still produce output: dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck,\n"
@@ -870,16 +865,22 @@ cfg(log_silent_CFG, "silent", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SILENT,
"Any 'yes' or 'no' questions not overridden by other arguments are\n"
"suppressed and default to 'no'.\n")
cfg(log_syslog_CFG, "syslog", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SYSLOG, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_syslog_CFG, "syslog", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_SYSLOG, vsn(1, 0, 0), NULL, 0, NULL,
"Send log messages through syslog.\n")
cfg(log_file_CFG, "file", log_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
"Write error and debug log messages to a file specified here.\n")
cfg(log_overwrite_CFG, "overwrite", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_OVERWRITE, vsn(1, 0, 0), NULL, 0, NULL,
cfg_array(log_journal_CFG, "journal", log_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(2, 3, 12), NULL, 0, NULL,
"Record lvm information in the systemd journal.\n"
"command: record commands that are run.\n"
"output: record default output from commands.\n"
"debug: record debug messages from commands.\n")
cfg(log_overwrite_CFG, "overwrite", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_OVERWRITE, vsn(1, 0, 0), NULL, 0, NULL,
"Overwrite the log file each time the program is run.\n")
cfg(log_level_CFG, "level", log_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_LOGLEVEL, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_level_CFG, "level", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_LOGLEVEL, vsn(1, 0, 0), NULL, 0, NULL,
"The level of log messages that are sent to the log file or syslog.\n"
"There are 6 syslog-like log levels currently in use: 2 to 7 inclusive.\n"
"7 is the most verbose (LOG_DEBUG).\n")
@@ -887,23 +888,23 @@ cfg(log_level_CFG, "level", log_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_LOGLEVEL,
cfg(log_indent_CFG, "indent", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_INDENT, vsn(1, 0, 0), NULL, 0, NULL,
"Indent messages according to their severity.\n")
cfg(log_command_names_CFG, "command_names", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_CMD_NAME, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_command_names_CFG, "command_names", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_CMD_NAME, vsn(1, 0, 0), NULL, 0, NULL,
"Display the command name on each line of output.\n")
cfg(log_prefix_CFG, "prefix", log_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, DEFAULT_MSG_PREFIX, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_prefix_CFG, "prefix", log_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ALLOW_EMPTY, CFG_TYPE_STRING, DEFAULT_MSG_PREFIX, vsn(1, 0, 0), NULL, 0, NULL,
"A prefix to use before the log message text.\n"
"(After the command name, if selected).\n"
"Two spaces allows you to see/grep the severity of each message.\n"
"To make the messages look similar to the original LVM tools use:\n"
"indent = 0, command_names = 1, prefix = \" -- \"\n")
cfg(log_activation_CFG, "activation", log_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(1, 0, 0), NULL, 0, NULL,
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"
"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)
cfg_array(log_debug_classes_CFG, "debug_classes", log_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, "#Smemory#Sdevices#Sio#Sactivation#Sallocation#Smetadata#Scache#Slocking#Slvmpolld#Sdbus", vsn(2, 2, 99), NULL, 0, NULL,
cfg_array(log_debug_classes_CFG, "debug_classes", log_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ALLOW_EMPTY, CFG_TYPE_STRING, "#Smemory#Sdevices#Sio#Sactivation#Sallocation#Smetadata#Scache#Slocking#Slvmpolld#Sdbus", vsn(2, 2, 99), NULL, 0, NULL,
"Select log messages by class.\n"
"Some debugging messages are assigned to a class and only appear in\n"
"debug output if the class is listed here. Classes currently\n"
@@ -918,55 +919,55 @@ cfg_array(log_debug_output_fields_CFG, "debug_output_fields", log_CFG_SECTION, C
"The fields included in debug output written to stderr.\n"
"Use \"all\" to include everything (the default).\n")
cfg(backup_backup_CFG, "backup", backup_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_BACKUP_ENABLED, vsn(1, 0, 0), NULL, 0, NULL,
cfg(backup_backup_CFG, "backup", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_BACKUP_ENABLED, vsn(1, 0, 0), NULL, 0, NULL,
"Maintain a backup of the current metadata configuration.\n"
"Think very hard before turning this off!\n")
cfg_runtime(backup_backup_dir_CFG, "backup_dir", backup_CFG_SECTION, 0, CFG_TYPE_STRING, vsn(1, 0, 0), 0, NULL,
cfg_runtime(backup_backup_dir_CFG, "backup_dir", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, vsn(1, 0, 0), 0, NULL,
"Location of the metadata backup files.\n"
"Remember to back up this directory regularly!\n")
cfg(backup_archive_CFG, "archive", backup_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ARCHIVE_ENABLED, vsn(1, 0, 0), NULL, 0, NULL,
cfg(backup_archive_CFG, "archive", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ARCHIVE_ENABLED, vsn(1, 0, 0), NULL, 0, NULL,
"Maintain an archive of old metadata configurations.\n"
"Think very hard before turning this off.\n")
cfg_runtime(backup_archive_dir_CFG, "archive_dir", backup_CFG_SECTION, 0, CFG_TYPE_STRING, vsn(1, 0, 0), 0, NULL,
cfg_runtime(backup_archive_dir_CFG, "archive_dir", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, vsn(1, 0, 0), 0, NULL,
"Location of the metdata archive files.\n"
"Remember to back up this directory regularly!\n")
cfg(backup_retain_min_CFG, "retain_min", backup_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_ARCHIVE_NUMBER, vsn(1, 0, 0), NULL, 0, NULL,
cfg(backup_retain_min_CFG, "retain_min", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_ARCHIVE_NUMBER, vsn(1, 0, 0), NULL, 0, NULL,
"Minimum number of archives to keep.\n")
cfg(backup_retain_days_CFG, "retain_days", backup_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_ARCHIVE_DAYS, vsn(1, 0, 0), NULL, 0, NULL,
cfg(backup_retain_days_CFG, "retain_days", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_ARCHIVE_DAYS, vsn(1, 0, 0), NULL, 0, NULL,
"Minimum number of days to keep archive files.\n")
cfg(shell_history_size_CFG, "history_size", shell_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_MAX_HISTORY, vsn(1, 0, 0), NULL, 0, NULL,
cfg(shell_history_size_CFG, "history_size", shell_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_MAX_HISTORY, vsn(1, 0, 0), NULL, 0, NULL,
"Number of lines of history to store in ~/.lvm_history.\n")
cfg(global_umask_CFG, "umask", global_CFG_SECTION, CFG_FORMAT_INT_OCTAL, CFG_TYPE_INT, DEFAULT_UMASK, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_umask_CFG, "umask", global_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_FORMAT_INT_OCTAL, CFG_TYPE_INT, DEFAULT_UMASK, vsn(1, 0, 0), NULL, 0, NULL,
"The file creation mask for any files and directories created.\n"
"Interpreted as octal if the first digit is zero.\n")
cfg(global_test_CFG, "test", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_test_CFG, "test", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(1, 0, 0), NULL, 0, NULL,
"No on-disk metadata changes will be made in test mode.\n"
"Equivalent to having the -t option on every command.\n")
cfg(global_units_CFG, "units", global_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_STRING, DEFAULT_UNITS, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_units_CFG, "units", global_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_PROFILABLE, CFG_TYPE_STRING, DEFAULT_UNITS, vsn(1, 0, 0), NULL, 0, NULL,
"Default value for --units argument.\n")
cfg(global_si_unit_consistency_CFG, "si_unit_consistency", global_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_SI_UNIT_CONSISTENCY, vsn(2, 2, 54), NULL, 0, NULL,
cfg(global_si_unit_consistency_CFG, "si_unit_consistency", global_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_SI_UNIT_CONSISTENCY, vsn(2, 2, 54), NULL, 0, NULL,
"Distinguish between powers of 1024 and 1000 bytes.\n"
"The LVM commands distinguish between powers of 1024 bytes,\n"
"e.g. KiB, MiB, GiB, and powers of 1000 bytes, e.g. KB, MB, GB.\n"
"If scripts depend on the old behaviour, disable this setting\n"
"temporarily until they are updated.\n")
cfg(global_suffix_CFG, "suffix", global_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_SUFFIX, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_suffix_CFG, "suffix", global_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_SUFFIX, vsn(1, 0, 0), NULL, 0, NULL,
"Display unit suffix for sizes.\n"
"This setting has no effect if the units are in human-readable form\n"
"(global/units = \"h\") in which case the suffix is always displayed.\n")
cfg(global_activation_CFG, "activation", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ACTIVATION, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_activation_CFG, "activation", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ACTIVATION, vsn(1, 0, 0), NULL, 0, NULL,
"Enable/disable communication with the kernel device-mapper.\n"
"Disable to use the tools to manipulate LVM metadata without\n"
"activating any logical volumes. If the device-mapper driver\n"
@@ -984,30 +985,30 @@ cfg_array(global_format_libraries_CFG, "format_libraries", global_CFG_SECTION, C
cfg_array(global_segment_libraries_CFG, "segment_libraries", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL, vsn(2, 3, 3), NULL, NULL)
cfg(global_proc_CFG, "proc", global_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_PROC_DIR, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_proc_CFG, "proc", global_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_PROC_DIR, vsn(1, 0, 0), NULL, 0, NULL,
"Location of proc filesystem.\n")
cfg(global_etc_CFG, "etc", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_ETC_DIR, vsn(2, 2, 117), "@CONFDIR@", 0, NULL,
cfg(global_etc_CFG, "etc", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_ETC_DIR, vsn(2, 2, 117), "@CONFDIR@", 0, NULL,
"Location of /etc system configuration directory.\n")
cfg(global_locking_type_CFG, "locking_type", global_CFG_SECTION, 0, CFG_TYPE_INT, 1, vsn(1, 0, 0), NULL, vsn(2, 3, 0), NULL,
cfg(global_locking_type_CFG, "locking_type", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 1, vsn(1, 0, 0), NULL, vsn(2, 3, 0), NULL,
NULL)
cfg(global_wait_for_locks_CFG, "wait_for_locks", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_WAIT_FOR_LOCKS, vsn(2, 2, 50), NULL, 0, NULL,
cfg(global_wait_for_locks_CFG, "wait_for_locks", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_WAIT_FOR_LOCKS, vsn(2, 2, 50), NULL, 0, NULL,
"When disabled, fail if a lock request would block.\n")
cfg(global_fallback_to_clustered_locking_CFG, "fallback_to_clustered_locking", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING, vsn(2, 2, 42), NULL, vsn(2, 3, 0), NULL,
cfg(global_fallback_to_clustered_locking_CFG, "fallback_to_clustered_locking", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING, vsn(2, 2, 42), NULL, vsn(2, 3, 0), NULL,
NULL)
cfg(global_fallback_to_local_locking_CFG, "fallback_to_local_locking", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_LOCAL_LOCKING, vsn(2, 2, 42), NULL, vsn(2, 3, 0), NULL,
cfg(global_fallback_to_local_locking_CFG, "fallback_to_local_locking", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_LOCAL_LOCKING, vsn(2, 2, 42), NULL, vsn(2, 3, 0), NULL,
NULL)
cfg(global_locking_dir_CFG, "locking_dir", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_LOCK_DIR, vsn(1, 0, 0), "@DEFAULT_LOCK_DIR@", 0, NULL,
cfg(global_locking_dir_CFG, "locking_dir", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_LOCK_DIR, vsn(1, 0, 0), "@DEFAULT_LOCK_DIR@", 0, NULL,
"Directory to use for LVM command file locks.\n"
"Local non-LV directory that holds file-based locks while commands are\n"
"in progress. A directory like /tmp that may get wiped on reboot is OK.\n")
cfg(global_prioritise_write_locks_CFG, "prioritise_write_locks", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_PRIORITISE_WRITE_LOCKS, vsn(2, 2, 52), NULL, 0, NULL,
cfg(global_prioritise_write_locks_CFG, "prioritise_write_locks", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_PRIORITISE_WRITE_LOCKS, vsn(2, 2, 52), NULL, 0, NULL,
"Allow quicker VG write access during high volume read access.\n"
"When there are competing read-only and read-write access requests for\n"
"a volume group's metadata, instead of always granting the read-only\n"
@@ -1021,22 +1022,22 @@ cfg(global_library_dir_CFG, "library_dir", global_CFG_SECTION, CFG_DEFAULT_UNDEF
cfg(global_locking_library_CFG, "locking_library", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_LOCKING_LIB, vsn(1, 0, 0), NULL, vsn(2, 3, 0), NULL,
NULL)
cfg(global_abort_on_internal_errors_CFG, "abort_on_internal_errors", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ABORT_ON_INTERNAL_ERRORS, vsn(2, 2, 57), NULL, 0, NULL,
cfg(global_abort_on_internal_errors_CFG, "abort_on_internal_errors", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ABORT_ON_INTERNAL_ERRORS, vsn(2, 2, 57), NULL, 0, NULL,
"Abort a command that encounters an internal error.\n"
"Treat any internal errors as fatal errors, aborting the process that\n"
"encountered the internal error. Please only enable for debugging.\n")
cfg(global_detect_internal_vg_cache_corruption_CFG, "detect_internal_vg_cache_corruption", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 96), NULL, vsn(2, 2, 174), NULL,
cfg(global_detect_internal_vg_cache_corruption_CFG, "detect_internal_vg_cache_corruption", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 2, 96), NULL, vsn(2, 2, 174), NULL,
NULL)
cfg(global_metadata_read_only_CFG, "metadata_read_only", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_METADATA_READ_ONLY, vsn(2, 2, 75), NULL, 0, NULL,
cfg(global_metadata_read_only_CFG, "metadata_read_only", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_METADATA_READ_ONLY, vsn(2, 2, 75), NULL, 0, NULL,
"No operations that change on-disk metadata are permitted.\n"
"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 mess up your system, so seek advice first!\n")
cfg(global_mirror_segtype_default_CFG, "mirror_segtype_default", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_MIRROR_SEGTYPE, vsn(2, 2, 87), "@DEFAULT_MIRROR_SEGTYPE@", 0, NULL,
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"
"The --type mirror|raid1 option overrides this setting.\n"
"#\n"
@@ -1071,7 +1072,7 @@ cfg(global_support_mirrored_mirror_log_CFG, "support_mirrored_mirror_log", globa
"Not supported for regular operation!\n"
"\n")
cfg(global_raid10_segtype_default_CFG, "raid10_segtype_default", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_RAID10_SEGTYPE, vsn(2, 2, 99), "@DEFAULT_RAID10_SEGTYPE@", 0, NULL,
cfg(global_raid10_segtype_default_CFG, "raid10_segtype_default", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_RAID10_SEGTYPE, vsn(2, 2, 99), "@DEFAULT_RAID10_SEGTYPE@", 0, NULL,
"The segment type used by the -i -m combination.\n"
"The --type raid10|mirror option overrides this setting.\n"
"The --stripes/-i and --mirrors/-m options can both be specified\n"
@@ -1089,7 +1090,7 @@ cfg(global_raid10_segtype_default_CFG, "raid10_segtype_default", global_CFG_SECT
" in terms of providing redundancy and performance.\n"
"#\n")
cfg(global_sparse_segtype_default_CFG, "sparse_segtype_default", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_SPARSE_SEGTYPE, vsn(2, 2, 112), "@DEFAULT_SPARSE_SEGTYPE@", 0, NULL,
cfg(global_sparse_segtype_default_CFG, "sparse_segtype_default", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_SPARSE_SEGTYPE, vsn(2, 2, 112), "@DEFAULT_SPARSE_SEGTYPE@", 0, NULL,
"The segment type used by the -V -L combination.\n"
"The --type snapshot|thin option overrides this setting.\n"
"The combination of -V and -L options creates a sparse LV. There are\n"
@@ -1127,7 +1128,7 @@ cfg(global_event_activation_CFG, "event_activation", global_CFG_SECTION, CFG_DEF
"See the --setautoactivation option or the auto_activation_volume_list\n"
"setting to configure autoactivation for specific VGs or LVs.\n")
cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 93), 0, vsn(2, 3, 0), NULL,
cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 2, 93), 0, vsn(2, 3, 0), NULL,
NULL)
cfg(global_lvmetad_update_wait_time_CFG, "lvmetad_update_wait_time", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(2, 2, 151), NULL, vsn(2, 3, 0), NULL,
@@ -1136,7 +1137,7 @@ cfg(global_lvmetad_update_wait_time_CFG, "lvmetad_update_wait_time", global_CFG_
cfg(global_use_aio_CFG, "use_aio", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_AIO, vsn(2, 2, 183), NULL, 0, NULL,
"Use async I/O when reading and writing devices.\n")
cfg(global_use_lvmlockd_CFG, "use_lvmlockd", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 124), NULL, 0, NULL,
cfg(global_use_lvmlockd_CFG, "use_lvmlockd", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 2, 124), NULL, 0, NULL,
"Use lvmlockd for locking among hosts using LVM on shared storage.\n"
"Applicable only if LVM is compiled with lockd support in which\n"
"case there is also lvmlockd(8) man page available for more\n"
@@ -1262,7 +1263,7 @@ 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_system_id_source_CFG, "system_id_source", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_SYSTEM_ID_SOURCE, vsn(2, 2, 117), NULL, 0, NULL,
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"
@@ -1278,10 +1279,12 @@ cfg(global_system_id_source_CFG, "system_id_source", global_CFG_SECTION, 0, CFG_
" uname\n"
" Set the system ID from the hostname (uname) of the system.\n"
" System IDs beginning localhost are not permitted.\n"
" appmachineid\n"
" Use an LVM-specific derivation of the local machine-id as the\n"
" system ID. See 'man machine-id'.\n"
" machineid\n"
" Use the contents of the machine-id file to set the system ID.\n"
" Some systems create this file at installation time.\n"
" See 'man machine-id' and global/etc.\n"
" Use the contents of the machine-id file to set the system ID\n"
" (appmachineid is recommended.)\n"
" file\n"
" Use the contents of another file (system_id_file) to set the\n"
" system ID.\n"
@@ -1292,13 +1295,13 @@ cfg(global_system_id_file_CFG, "system_id_file", global_CFG_SECTION, CFG_DEFAULT
"This is used when system_id_source is set to 'file'.\n"
"Comments starting with the character # are ignored.\n")
cfg(activation_checks_CFG, "checks", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ACTIVATION_CHECKS, vsn(2, 2, 86), NULL, 0, NULL,
cfg(activation_checks_CFG, "checks", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ACTIVATION_CHECKS, vsn(2, 2, 86), NULL, 0, NULL,
"Perform internal checks of libdevmapper operations.\n"
"Useful for debugging problems with activation. Some of the checks may\n"
"be expensive, so it's best to use this only when there seems to be a\n"
"problem.\n")
cfg(global_use_lvmpolld_CFG, "use_lvmpolld", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_LVMPOLLD, vsn(2, 2, 120), "@DEFAULT_USE_LVMPOLLD@", 0, NULL,
cfg(global_use_lvmpolld_CFG, "use_lvmpolld", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_LVMPOLLD, vsn(2, 2, 120), "@DEFAULT_USE_LVMPOLLD@", 0, NULL,
"Use lvmpolld to supervise long running LVM commands.\n"
"When enabled, control of long running LVM commands is transferred\n"
"from the original LVM command to the lvmpolld daemon. This allows\n"
@@ -1311,7 +1314,7 @@ cfg(global_use_lvmpolld_CFG, "use_lvmpolld", global_CFG_SECTION, 0, CFG_TYPE_BOO
"commands will supervise long running operations by forking themselves.\n"
"Applicable only if LVM is compiled with lvmpolld support.\n")
cfg(global_notify_dbus_CFG, "notify_dbus", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_NOTIFY_DBUS, vsn(2, 2, 145), NULL, 0, NULL,
cfg(global_notify_dbus_CFG, "notify_dbus", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_NOTIFY_DBUS, vsn(2, 2, 145), NULL, 0, NULL,
"Enable D-Bus notification from LVM commands.\n"
"When enabled, an LVM command that changes PVs, changes VG metadata,\n"
"or changes the activation state of an LV will send a notification.\n")
@@ -1324,7 +1327,7 @@ cfg(global_io_memory_size_CFG, "io_memory_size", global_CFG_SECTION, CFG_DEFAULT
"This value should usually not be decreased from the default; setting\n"
"it too low can result in lvm failing to read VGs.\n")
cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_UDEV_SYNC, vsn(2, 2, 51), NULL, 0, NULL,
cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_UDEV_SYNC, vsn(2, 2, 51), NULL, 0, NULL,
"Use udev notifications to synchronize udev and LVM.\n"
"The --noudevsync option overrides this setting.\n"
"When disabled, LVM commands will not wait for notifications from\n"
@@ -1334,7 +1337,7 @@ cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, 0, CFG_TYPE_B
"running, and LVM processes are waiting for udev, run the command\n"
"'dmsetup udevcomplete_all' to wake them up.\n")
cfg(activation_udev_rules_CFG, "udev_rules", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_UDEV_RULES, vsn(2, 2, 57), NULL, 0, NULL,
cfg(activation_udev_rules_CFG, "udev_rules", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_UDEV_RULES, vsn(2, 2, 57), NULL, 0, NULL,
"Use udev rules to manage LV device nodes and symlinks.\n"
"When disabled, LVM will manage the device nodes and symlinks for\n"
"active LVs itself. Manual intervention may be required if this\n"
@@ -1346,13 +1349,13 @@ cfg(activation_verify_udev_operations_CFG, "verify_udev_operations", activation_
"in the device directory after udev has completed processing its\n"
"events. Useful for diagnosing problems with LVM/udev interactions.\n")
cfg(activation_retry_deactivation_CFG, "retry_deactivation", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_RETRY_DEACTIVATION, vsn(2, 2, 89), NULL, 0, NULL,
cfg(activation_retry_deactivation_CFG, "retry_deactivation", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_RETRY_DEACTIVATION, vsn(2, 2, 89), NULL, 0, NULL,
"Retry failed LV deactivation.\n"
"If LV deactivation fails, LVM will retry for a few seconds before\n"
"failing. This may happen because a process run from a quick udev rule\n"
"temporarily opened the device.\n")
cfg(activation_missing_stripe_filler_CFG, "missing_stripe_filler", activation_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_STRIPE_FILLER, vsn(1, 0, 0), NULL, 0, NULL,
cfg(activation_missing_stripe_filler_CFG, "missing_stripe_filler", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_STRIPE_FILLER, vsn(1, 0, 0), NULL, 0, NULL,
"Method to fill missing stripes when activating an incomplete LV.\n"
"Using 'error' will make inaccessible parts of the device return I/O\n"
"errors on access. Using 'zero' will return success (and zero) on I/O\n"
@@ -1465,11 +1468,11 @@ cfg_array(activation_read_only_volume_list_CFG, "read_only_volume_list", activat
"read_only_volume_list = [ \"vg1\", \"vg2/lvol1\", \"@tag1\", \"@*\" ]\n"
"#\n")
cfg(activation_mirror_region_size_CFG, "mirror_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(1, 0, 0), NULL, vsn(2, 2, 99),
cfg(activation_mirror_region_size_CFG, "mirror_region_size", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(1, 0, 0), NULL, vsn(2, 2, 99),
"This has been replaced by the activation/raid_region_size setting.\n",
"Size in KiB of each raid or mirror synchronization region.\n")
cfg(activation_raid_region_size_CFG, "raid_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(2, 2, 99), NULL, 0, NULL,
cfg(activation_raid_region_size_CFG, "raid_region_size", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(2, 2, 99), NULL, 0, NULL,
"Size in KiB of each raid or mirror synchronization region.\n"
"The clean/dirty state of data is tracked for each region.\n"
"The value is rounded down to a power of two if necessary, and\n"
@@ -1494,7 +1497,7 @@ cfg(activation_readahead_CFG, "readahead", activation_CFG_SECTION, CFG_DEFAULT_C
" Use default value chosen by kernel.\n"
"#\n")
cfg(activation_raid_fault_policy_CFG, "raid_fault_policy", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_RAID_FAULT_POLICY, vsn(2, 2, 89), NULL, 0, NULL,
cfg(activation_raid_fault_policy_CFG, "raid_fault_policy", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_RAID_FAULT_POLICY, vsn(2, 2, 89), NULL, 0, NULL,
"Defines how a device failure in a RAID LV is handled.\n"
"This includes LVs that have the following segment types:\n"
"raid1, raid4, raid5*, and raid6*.\n"
@@ -1515,7 +1518,7 @@ cfg(activation_raid_fault_policy_CFG, "raid_fault_policy", activation_CFG_SECTIO
" replace faulty devices.\n"
"#\n")
cfg_runtime(activation_mirror_image_fault_policy_CFG, "mirror_image_fault_policy", activation_CFG_SECTION, 0, CFG_TYPE_STRING, vsn(2, 2, 57), 0, NULL,
cfg_runtime(activation_mirror_image_fault_policy_CFG, "mirror_image_fault_policy", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, vsn(2, 2, 57), 0, NULL,
"Defines how a device failure in a 'mirror' LV is handled.\n"
"An LV with the 'mirror' segment type is composed of mirror images\n"
"(copies) and a mirror log. A disk log ensures that a mirror LV does\n"
@@ -1551,16 +1554,16 @@ cfg_runtime(activation_mirror_image_fault_policy_CFG, "mirror_image_fault_policy
" replacement.\n"
"#\n")
cfg(activation_mirror_log_fault_policy_CFG, "mirror_log_fault_policy", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_MIRROR_LOG_FAULT_POLICY, vsn(1, 2, 18), NULL, 0, NULL,
cfg(activation_mirror_log_fault_policy_CFG, "mirror_log_fault_policy", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_MIRROR_LOG_FAULT_POLICY, vsn(1, 2, 18), NULL, 0, NULL,
"Defines how a device failure in a 'mirror' log LV is handled.\n"
"The mirror_image_fault_policy description for mirrored LVs also\n"
"applies to mirrored log LVs.\n")
cfg(activation_mirror_device_fault_policy_CFG, "mirror_device_fault_policy", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_MIRROR_DEVICE_FAULT_POLICY, vsn(1, 2, 10), NULL, vsn(2, 2, 57),
cfg(activation_mirror_device_fault_policy_CFG, "mirror_device_fault_policy", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_MIRROR_DEVICE_FAULT_POLICY, vsn(1, 2, 10), NULL, vsn(2, 2, 57),
"This has been replaced by the activation/mirror_image_fault_policy setting.\n",
"Define how a device failure affecting a mirror is handled.\n")
cfg(activation_snapshot_autoextend_threshold_CFG, "snapshot_autoextend_threshold", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD, vsn(2, 2, 75), NULL, 0, NULL,
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"
@@ -1574,7 +1577,7 @@ cfg(activation_snapshot_autoextend_threshold_CFG, "snapshot_autoextend_threshold
"snapshot_autoextend_threshold = 70\n"
"#\n")
cfg(activation_snapshot_autoextend_percent_CFG, "snapshot_autoextend_percent", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT, vsn(2, 2, 75), NULL, 0, NULL,
cfg(activation_snapshot_autoextend_percent_CFG, "snapshot_autoextend_percent", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT, vsn(2, 2, 75), NULL, 0, NULL,
"Auto-extending a snapshot adds this percent extra space.\n"
"The amount of additional space added to a snapshot is this\n"
"percent of its current size.\n"
@@ -1586,7 +1589,7 @@ cfg(activation_snapshot_autoextend_percent_CFG, "snapshot_autoextend_percent", a
"snapshot_autoextend_percent = 20\n"
"#\n")
cfg(activation_thin_pool_autoextend_threshold_CFG, "thin_pool_autoextend_threshold", activation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_INT, DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD, vsn(2, 2, 89), NULL, 0, NULL,
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"
@@ -1600,7 +1603,7 @@ cfg(activation_thin_pool_autoextend_threshold_CFG, "thin_pool_autoextend_thresho
"thin_pool_autoextend_threshold = 70\n"
"#\n")
cfg(activation_thin_pool_autoextend_percent_CFG, "thin_pool_autoextend_percent", activation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_INT, DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT, vsn(2, 2, 89), NULL, 0, NULL,
cfg(activation_thin_pool_autoextend_percent_CFG, "thin_pool_autoextend_percent", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_INT, DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT, vsn(2, 2, 89), NULL, 0, NULL,
"Auto-extending a thin pool adds this percent extra space.\n"
"The amount of additional space added to a thin pool is this\n"
"percent of its current size.\n"
@@ -1657,7 +1660,7 @@ cfg(activation_use_mlockall_CFG, "use_mlockall", activation_CFG_SECTION, CFG_DEF
"Prior to version 2.02.62, LVM used mlockall() to pin the whole\n"
"process's memory while activating devices.\n")
cfg(activation_monitoring_CFG, "monitoring", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_DMEVENTD_MONITOR, vsn(2, 2, 63), NULL, 0, NULL,
cfg(activation_monitoring_CFG, "monitoring", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_DMEVENTD_MONITOR, vsn(2, 2, 63), NULL, 0, NULL,
"Monitor LVs that are activated.\n"
"The --ignoremonitoring option overrides this setting.\n"
"When enabled, LVM will ask dmeventd to monitor activated LVs.\n")
@@ -1679,7 +1682,7 @@ cfg(activation_auto_set_activation_skip_CFG, "auto_set_activation_skip", activat
"flag set. When this setting is enabled, the activation skip flag is\n"
"set on new thin snapshot LVs.\n")
cfg(activation_mode_CFG, "activation_mode", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_ACTIVATION_MODE, vsn(2,2,108), NULL, 0, NULL,
cfg(activation_mode_CFG, "activation_mode", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_ACTIVATION_MODE, vsn(2,2,108), NULL, 0, NULL,
"How LVs with missing devices are activated.\n"
"The --activationmode option overrides this setting.\n"
"#\n"
@@ -2202,4 +2205,4 @@ cfg(local_host_id_CFG, "host_id", local_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_
"This must be unique among all hosts, and must be between 1 and 2000.\n"
"Applicable only if LVM is compiled with lockd support\n")
cfg(CFG_COUNT, NULL, root_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(0, 0, 0), NULL, 0, NULL, NULL)
cfg(CFG_COUNT, NULL, root_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(0, 0, 0), NULL, 0, NULL, NULL)

View File

@@ -42,7 +42,7 @@
#define DEFAULT_DEV_DIR "/dev"
#define DEFAULT_PROC_DIR "/proc"
#define DEFAULT_SYSTEM_ID_SOURCE "none"
#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 1
#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 0
#define DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE "none"
#define DEFAULT_SYSFS_SCAN 1
#define DEFAULT_MD_COMPONENT_DETECTION 1
@@ -181,8 +181,7 @@
* VDO pool will reverve some sectors in the front and the back of pool device to avoid
* seeing same device twice in the system.
*/
#define DEFAULT_VDO_POOL_HEADER_SIZE (1024) // 512KiB
#define DEFAULT_VDO_POOL_HEADER_SIZE_KB (512)
#define DEFAULT_FSADM_PATH FSADM_PATH
@@ -323,9 +322,15 @@
#define DEFAULT_MD_COMPONENT_CHECKS "auto"
#define DEFAULT_USE_DEVICES_FILE 0
#define DEFAULT_USE_DEVICES_FILE 1
#define DEFAULT_DEVICES_FILE "system.devices"
#define DEFAULT_SEARCH_FOR_DEVNAMES "auto"
#define DEFAULT_WWIDS_FILE "/etc/multipath/wwids"
#define PVS_ONLINE_DIR DEFAULT_RUN_DIR "/pvs_online"
#define VGS_ONLINE_DIR DEFAULT_RUN_DIR "/vgs_online"
#define PVS_LOOKUP_DIR DEFAULT_RUN_DIR "/pvs_lookup"
#endif /* _LVM_DEFAULTS_H */

View File

@@ -412,7 +412,7 @@ out:
return r;
}
static int _get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor)
int get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor)
{
char path[PATH_MAX];
@@ -533,7 +533,7 @@ static int _get_vgid_and_lvid_for_dev(struct device *dev)
char uuid[DM_UUID_LEN];
size_t uuid_len;
if (!_get_dm_uuid_from_sysfs(uuid, sizeof(uuid), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)))
if (!get_dm_uuid_from_sysfs(uuid, sizeof(uuid), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)))
return_0;
uuid_len = strlen(uuid);
@@ -1139,7 +1139,7 @@ static int _insert(const char *path, const struct stat *info,
return 1;
}
void dev_cache_scan(void)
void dev_cache_scan(struct cmd_context *cmd)
{
log_debug_devs("Creating list of system devices.");
@@ -1147,7 +1147,8 @@ void dev_cache_scan(void)
_insert_dirs(&_cache.dirs);
(void) dev_cache_index_devs();
if (cmd->check_devs_used)
(void) dev_cache_index_devs();
}
int dev_cache_has_scanned(void)
@@ -1583,7 +1584,7 @@ struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t dev, struct
log_debug_devs("Device num not found in dev_cache repeat dev_cache_scan for %d:%d",
(int)MAJOR(dev), (int)MINOR(dev));
dev_cache_scan();
dev_cache_scan(cmd);
d = (struct device *) btree_lookup(_cache.devices, (uint32_t) dev);
if (!d)
@@ -1953,7 +1954,7 @@ int setup_devices(struct cmd_context *cmd)
* This will not open or read any devices, but may look at sysfs properties.
* This list of devs comes from looking /dev entries, or from asking libudev.
*/
dev_cache_scan();
dev_cache_scan(cmd);
/*
* Match entries from cmd->use_devices with device structs in dev-cache.

View File

@@ -48,7 +48,7 @@ int dev_cache_exit(void);
*/
int dev_cache_check_for_open_devices(void);
void dev_cache_scan(void);
void dev_cache_scan(struct cmd_context *cmd);
int dev_cache_has_scanned(void);
int dev_cache_add_dir(const char *path);
@@ -68,13 +68,12 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int unused);
void dev_iter_destroy(struct dev_iter *iter);
struct device *dev_iter_get(struct cmd_context *cmd, struct dev_iter *iter);
void dev_reset_error_count(struct cmd_context *cmd);
void dev_cache_failed_path(struct device *dev, const char *path);
bool dev_cache_has_md_with_end_superblock(struct dev_types *dt);
int get_sysfs_value(const char *path, char *buf, size_t buf_size, int error_if_no_value);
int get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor);
int setup_devices_file(struct cmd_context *cmd);
int setup_devices(struct cmd_context *cmd);

View File

@@ -18,7 +18,7 @@
#define LUKS_SIGNATURE "LUKS\xba\xbe"
#define LUKS_SIGNATURE_SIZE 6
int dev_is_luks(struct device *dev, uint64_t *offset_found, int full)
int dev_is_luks(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full)
{
char buf[LUKS_SIGNATURE_SIZE];
int ret = -1;

View File

@@ -17,6 +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"
@@ -144,25 +145,16 @@ static int _dev_has_ddf_magic(struct device *dev, uint64_t devsize_sectors, uint
return 0;
}
/*
* _udev_dev_is_md_component() only works if
* external_device_info_source="udev"
*
* but
*
* udev_dev_is_md_component() in dev-type.c only works if
* obtain_device_list_from_udev=1
*
* and neither of those config setting matches very well
* with what we're doing here.
*/
#ifdef UDEV_SYNC_SUPPORT
static int _udev_dev_is_md_component(struct device *dev)
static int _dev_is_md_component_udev(struct device *dev)
{
const char *value;
struct dev_ext *ext;
/*
* external_device_info_source="udev" enables these udev checks.
* external_device_info_source="none" disables them.
*/
if (!(ext = dev_ext_get(dev)))
return_0;
@@ -172,7 +164,7 @@ static int _udev_dev_is_md_component(struct device *dev)
return !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_SW_RAID);
}
#else
static int _udev_dev_is_md_component(struct device *dev)
static int _dev_is_md_component_udev(struct device *dev)
{
return 0;
}
@@ -181,13 +173,16 @@ static int _udev_dev_is_md_component(struct device *dev)
/*
* Returns -1 on error
*/
static int _native_dev_is_md_component(struct device *dev, uint64_t *offset_found, int full)
static int _dev_is_md_component_native(struct device *dev, uint64_t *offset_found, int full)
{
uint64_t size, sb_offset = 0;
int ret;
if (!scan_bcache)
return -EAGAIN;
/* i/o layer has not been set up */
if (!scan_bcache) {
log_error(INTERNAL_ERROR "dev_is_md_component_native requires io layer.");
return -1;
}
if (!dev_get_size(dev, &size)) {
stack;
@@ -295,41 +290,20 @@ out:
return ret;
}
int dev_is_md_component(struct device *dev, uint64_t *offset_found, int full)
int dev_is_md_component(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full)
{
int ret;
if (_dev_is_md_component_native(dev, offset_found, full) == 1)
goto found;
/*
* If non-native device status source is selected, use it
* only if offset_found is not requested as this
* information is not in udev db.
*/
if ((dev->ext.src == DEV_EXT_NONE) || offset_found) {
ret = _native_dev_is_md_component(dev, offset_found, full);
if (!full) {
if (!ret || (ret == -EAGAIN)) {
if (udev_dev_is_md_component(dev))
ret = 1;
}
}
if (ret && (ret != -EAGAIN))
dev->flags |= DEV_IS_MD_COMPONENT;
return ret;
if (external_device_info_source() == DEV_EXT_UDEV) {
if (_dev_is_md_component_udev(dev) == 1)
goto found;
}
return 0;
if (dev->ext.src == DEV_EXT_UDEV) {
ret = _udev_dev_is_md_component(dev);
if (ret && (ret != -EAGAIN))
dev->flags |= DEV_IS_MD_COMPONENT;
return ret;
}
log_error(INTERNAL_ERROR "Missing hook for MD device recognition "
"using external device info source %s", dev_ext_name(dev));
return -1;
found:
dev->flags |= DEV_IS_MD_COMPONENT;
return 1;
}
static int _md_sysfs_attribute_snprintf(char *path, size_t size,
@@ -552,7 +526,8 @@ int dev_is_md_with_end_superblock(struct dev_types *dt, struct device *dev)
#else
int dev_is_md_component(struct device *dev __attribute__((unused)),
int dev_is_md_component(struct cmd_context *cmd __attribute__((unused)),
struct device *dev __attribute__((unused)),
uint64_t *sb __attribute__((unused)))
{
return 0;

483
lib/device/dev-mpath.c Normal file
View File

@@ -0,0 +1,483 @@
/*
* Copyright (C) 2011 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 "base/memory/zalloc.h"
#include "lib/misc/lib.h"
#include "lib/activate/activate.h"
#include "lib/commands/toolcontext.h"
#include "lib/device/device_id.h"
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h>
#include "lib/device/dev-ext-udev-constants.h"
#endif
#include <dirent.h>
#define MPATH_PREFIX "mpath-"
/*
* This hash table keeps track of whether a given dm device
* is a mpath device or not.
*
* If dm-3 is an mpath device, then the constant "2" is stored in
* the hash table with the key of the dm minor number ("3" for dm-3).
* If dm-3 is not an mpath device, then the constant "1" is stored in
* the hash table with the key of the dm minor number.
*/
static struct dm_pool *_hash_mem;
static struct dm_hash_table *_minor_hash_tab;
static struct dm_hash_table *_wwid_hash_tab;
#define MAX_WWID_LINE 512
/*
* do we need to check the multipath.conf blacklist?
*/
static void _read_wwid_file(const char *config_wwids_file)
{
FILE *fp;
char line[MAX_WWID_LINE];
char *wwid, *p;
int count = 0;
if (config_wwids_file[0] != '/') {
log_print("Ignoring unknown multipath_wwids_file.");
return;
}
if (!(fp = fopen(config_wwids_file, "r"))) {
log_debug("multipath wwids file not found");
return;
}
while (fgets(line, sizeof(line), fp)) {
if (line[0] == '#')
continue;
wwid = line;
if (line[0] == '/')
wwid++;
/* skip the initial '3' */
wwid++;
if ((p = strchr(wwid, '/')))
*p = '\0';
(void) dm_hash_insert_binary(_wwid_hash_tab, wwid, strlen(wwid), (void*)1);
count++;
}
if (fclose(fp))
stack;
log_debug("multipath wwids read %d from %s", count, config_wwids_file);
}
int dev_mpath_init(const char *config_wwids_file)
{
struct dm_pool *mem;
struct dm_hash_table *minor_tab;
struct dm_hash_table *wwid_tab;
if (!(mem = dm_pool_create("mpath", 256))) {
log_error("mpath pool creation failed.");
return 0;
}
if (!(minor_tab = dm_hash_create(110))) {
log_error("mpath hash table creation failed.");
dm_pool_destroy(mem);
return 0;
}
_hash_mem = mem;
_minor_hash_tab = minor_tab;
/* multipath_wwids_file="" disables the use of the file */
if (config_wwids_file && !strlen(config_wwids_file)) {
log_debug("multipath wwids file disabled.");
return 1;
}
if (!(wwid_tab = dm_hash_create(110))) {
log_error("mpath hash table creation failed.");
dm_hash_destroy(_minor_hash_tab);
dm_pool_destroy(_hash_mem);
_minor_hash_tab = NULL;
_hash_mem = NULL;
return 0;
}
_wwid_hash_tab = wwid_tab;
_read_wwid_file(config_wwids_file);
return 1;
}
void dev_mpath_exit(void)
{
if (_minor_hash_tab)
dm_hash_destroy(_minor_hash_tab);
if (_wwid_hash_tab)
dm_hash_destroy(_wwid_hash_tab);
if (_hash_mem)
dm_pool_destroy(_hash_mem);
_minor_hash_tab = NULL;
_wwid_hash_tab = NULL;
_hash_mem = NULL;
}
/*
* given "/dev/foo" return "foo"
*/
static const char *_get_sysfs_name(struct device *dev)
{
const char *name;
if (!(name = strrchr(dev_name(dev), '/'))) {
log_error("Cannot find '/' in device name.");
return NULL;
}
name++;
if (!*name) {
log_error("Device name is not valid.");
return NULL;
}
return name;
}
/*
* given major:minor
* readlink translates /sys/dev/block/major:minor to /sys/.../foo
* from /sys/.../foo return "foo"
*/
static const char *_get_sysfs_name_by_devt(const char *sysfs_dir, dev_t devno,
char *buf, size_t buf_size)
{
const char *name;
char path[PATH_MAX];
int size;
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d", sysfs_dir,
(int) MAJOR(devno), (int) MINOR(devno)) < 0) {
log_error("Sysfs path string is too long.");
return NULL;
}
if ((size = readlink(path, buf, buf_size - 1)) < 0) {
log_sys_error("readlink", path);
return NULL;
}
buf[size] = '\0';
if (!(name = strrchr(buf, '/'))) {
log_error("Cannot find device name in sysfs path.");
return NULL;
}
name++;
return name;
}
static int _get_sysfs_string(const char *path, char *buffer, int max_size)
{
FILE *fp;
int r = 0;
if (!(fp = fopen(path, "r"))) {
log_sys_error("fopen", path);
return 0;
}
if (!fgets(buffer, max_size, fp))
log_sys_error("fgets", path);
else
r = 1;
if (fclose(fp))
log_sys_error("fclose", path);
return r;
}
static int _get_sysfs_dm_mpath(struct dev_types *dt, const char *sysfs_dir, const char *holder_name)
{
char path[PATH_MAX];
char buffer[128];
if (dm_snprintf(path, sizeof(path), "%sblock/%s/dm/uuid", sysfs_dir, holder_name) < 0) {
log_error("Sysfs path string is too long.");
return 0;
}
buffer[0] = '\0';
if (!_get_sysfs_string(path, buffer, sizeof(buffer)))
return_0;
if (!strncmp(buffer, MPATH_PREFIX, 6))
return 1;
return 0;
}
#ifdef UDEV_SYNC_SUPPORT
static int _dev_is_mpath_component_udev(struct device *dev)
{
const char *value;
struct dev_ext *ext;
/*
* external_device_info_source="udev" enables these udev checks.
* external_device_info_source="none" disables them.
*/
if (!(ext = dev_ext_get(dev)))
return_0;
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_TYPE);
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH))
return 1;
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
if (value && !strcmp(value, "1"))
return 1;
return 0;
}
#else
static int _dev_is_mpath_component_udev(struct device *dev)
{
return 0;
}
#endif
static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device *dev)
{
struct dev_types *dt = cmd->dev_types;
const char *part_name;
const char *name; /* e.g. "sda" for "/dev/sda" */
char link_path[PATH_MAX]; /* some obscure, unpredictable sysfs path */
char holders_path[PATH_MAX]; /* e.g. "/sys/block/sda/holders/" */
char dm_dev_path[PATH_MAX]; /* e.g. "/dev/dm-1" */
char *holder_name; /* e.g. "dm-1" */
const char *sysfs_dir = dm_sysfs_dir();
DIR *dr;
struct dirent *de;
int dev_major = MAJOR(dev->dev);
int dev_minor = MINOR(dev->dev);
int dm_dev_major;
int dm_dev_minor;
struct stat info;
dev_t primary_dev;
int is_mpath_component = 0;
/* multipathing is only known to exist for SCSI or NVME devices */
if (!major_is_scsi_device(dt, dev_major) && !dev_is_nvme(dt, dev))
return 0;
switch (dev_get_primary_dev(dt, dev, &primary_dev)) {
case 2: /* The dev is partition. */
part_name = dev_name(dev); /* name of original dev for log_debug msg */
/* gets "foo" for "/dev/foo" where "/dev/foo" comes from major:minor */
if (!(name = _get_sysfs_name_by_devt(sysfs_dir, primary_dev, link_path, sizeof(link_path))))
return_0;
log_debug_devs("%s: Device is a partition, using primary "
"device %s for mpath component detection",
part_name, name);
break;
case 1: /* The dev is already a primary dev. Just continue with the dev. */
/* gets "foo" for "/dev/foo" */
if (!(name = _get_sysfs_name(dev)))
return_0;
break;
default: /* 0, error. */
log_warn("Failed to get primary device for %d:%d.", dev_major, dev_minor);
return 0;
}
if (dm_snprintf(holders_path, sizeof(holders_path), "%sblock/%s/holders", sysfs_dir, name) < 0) {
log_warn("Sysfs path to check mpath is too long.");
return 0;
}
/* also will filter out partitions */
if (stat(holders_path, &info))
return 0;
if (!S_ISDIR(info.st_mode)) {
log_warn("Path %s is not a directory.", holders_path);
return 0;
}
/*
* If any holder is a dm mpath device, then return 1;
*/
if (!(dr = opendir(holders_path))) {
log_debug("Device %s has no holders dir", dev_name(dev));
return 0;
}
while ((de = readdir(dr))) {
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
/*
* holder_name is e.g. "dm-1"
* dm_dev_path is then e.g. "/dev/dm-1"
*/
holder_name = de->d_name;
if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0) {
log_warn("dm device path to check mpath is too long.");
continue;
}
/*
* stat "/dev/dm-1" which is the holder of the dev we're checking
* dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
*/
if (stat(dm_dev_path, &info)) {
log_debug_devs("dev_is_mpath_component %s holder %s stat result %d",
dev_name(dev), dm_dev_path, errno);
continue;
}
dm_dev_major = (int)MAJOR(info.st_rdev);
dm_dev_minor = (int)MINOR(info.st_rdev);
if (dm_dev_major != dt->device_mapper_major) {
log_debug_devs("dev_is_mpath_component %s holder %s %d:%d does not have dm major",
dev_name(dev), dm_dev_path, dm_dev_major, dm_dev_minor);
continue;
}
/*
* A previous call may have checked if dm_dev_minor is mpath and saved
* the result in the hash table. If there's a saved result just use that.
*
* The minor number of "/dev/dm-1" is added to the hash table with
* const value 2 meaning that dm minor 1 (for /dev/dm-1) is a multipath dev
* and const value 1 meaning that dm minor 1 is not a multipath dev.
*/
if (_minor_hash_tab) {
long look = (long) dm_hash_lookup_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor));
if (look > 0) {
log_debug_devs("dev_is_mpath_component %s holder %s %u:%u already checked as %sbeing mpath.",
dev_name(dev), holder_name, dm_dev_major, dm_dev_minor, (look > 1) ? "" : "not ");
is_mpath_component = (look == 2);
goto out;
}
/* no saved result for dm_dev_minor, so check the uuid for it */
}
/*
* Returns 1 if /sys/block/<holder_name>/dm/uuid indicates that
* <holder_name> is a dm device with dm uuid prefix mpath-.
* When true, <holder_name> will be something like "dm-1".
*/
if (_get_sysfs_dm_mpath(dt, sysfs_dir, holder_name)) {
log_debug_devs("dev_is_mpath_component %s holder %s %u:%u ignore mpath component",
dev_name(dev), holder_name, dm_dev_major, dm_dev_minor);
/* For future checks, save that the dm minor refers to mpath ("2" == is mpath) */
if (_minor_hash_tab)
(void) dm_hash_insert_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor), (void*)2);
is_mpath_component = 1;
goto out;
}
/* For future checks, save that the dm minor does not refer to mpath ("1" == is not mpath) */
if (_minor_hash_tab)
(void) dm_hash_insert_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor), (void*)1);
}
out:
if (closedir(dr))
stack;
return is_mpath_component;
}
static int _dev_in_wwid_file(struct cmd_context *cmd, struct device *dev)
{
char sysbuf[PATH_MAX] = { 0 };
char *wwid;
long look;
if (!_wwid_hash_tab)
return 0;
if (!read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
return 0;
if (!sysbuf[0])
return 0;
/*
* sysfs prints wwid as <typestr>.<value>
* multipath wwid uses '3'<value>
* does "<typestr>." always correspond to "3"?
*/
if (!(wwid = strchr(sysbuf, '.')))
return 0;
/* skip the type and dot, just as '3' was skipped from wwids entry */
wwid++;
look = (long) dm_hash_lookup_binary(_wwid_hash_tab, wwid, strlen(wwid));
if (look) {
log_debug_devs("dev_is_mpath_component %s multipath wwid %s", dev_name(dev), wwid);
return 1;
}
return 0;
}
int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev)
{
if (_dev_is_mpath_component_sysfs(cmd, dev) == 1)
goto found;
if (_dev_in_wwid_file(cmd, dev))
goto found;
if (external_device_info_source() == DEV_EXT_UDEV) {
if (_dev_is_mpath_component_udev(dev) == 1)
goto found;
}
return 0;
found:
return 1;
}

View File

@@ -35,7 +35,7 @@ static int _swap_detect_signature(const char *buf)
return 0;
}
int dev_is_swap(struct device *dev, uint64_t *offset_found, int full)
int dev_is_swap(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full)
{
char buf[10];
uint64_t size;

View File

@@ -22,6 +22,7 @@
#include "lib/device/bcache.h"
#include "lib/label/label.h"
#include "lib/commands/toolcontext.h"
#include "device_mapper/misc/dm-ioctl.h"
#ifdef BLKID_WIPING_SUPPORT
#include <blkid.h>
@@ -34,6 +35,7 @@
#include <libgen.h>
#include <ctype.h>
#include <dirent.h>
/*
* An nvme device has major number 259 (BLKEXT), minor number <minor>,
@@ -77,6 +79,121 @@ int dev_is_lv(struct device *dev)
return ret;
}
int dev_is_used_by_active_lv(struct cmd_context *cmd, struct device *dev, int *used_by_lv_count,
char **used_by_dm_name, char **used_by_vg_uuid, char **used_by_lv_uuid)
{
char holders_path[PATH_MAX];
char dm_dev_path[PATH_MAX];
char dm_uuid[DM_UUID_LEN];
struct stat info;
DIR *d;
struct dirent *dirent;
char *holder_name;
int dm_dev_major, dm_dev_minor;
size_t lvm_prefix_len = sizeof(UUID_PREFIX) - 1;
size_t lvm_uuid_len = sizeof(UUID_PREFIX) - 1 + 2 * ID_LEN;
size_t uuid_len;
int used_count = 0;
char *used_name = NULL;
char *used_vgid = NULL;
char *used_lvid = NULL;
/*
* An LV using this device will be listed as a "holder" in the device's
* sysfs "holders" dir.
*/
if (dm_snprintf(holders_path, sizeof(holders_path), "%sdev/block/%d:%d/holders/", dm_sysfs_dir(), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)) < 0) {
log_error("%s: dm_snprintf failed for path to holders directory.", dev_name(dev));
return 0;
}
if (!(d = opendir(holders_path)))
return 0;
while ((dirent = readdir(d))) {
if (!strcmp(".", dirent->d_name) || !strcmp("..", dirent->d_name))
continue;
holder_name = dirent->d_name;
/*
* dirent->d_name is the dev name of the holder, e.g. "dm-1"
* from this name, create path "/dev/dm-1" to run stat on.
*/
if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0)
continue;
/*
* stat "/dev/dm-1" which is the holder of the dev we're checking
* dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
*/
if (stat(dm_dev_path, &info))
continue;
dm_dev_major = (int)MAJOR(info.st_rdev);
dm_dev_minor = (int)MINOR(info.st_rdev);
if (dm_dev_major != cmd->dev_types->device_mapper_major)
continue;
/*
* if "dm-1" is a dm device, then check if it's an LVM LV
* by reading /sys/block/<holder_name>/dm/uuid and seeing
* if the uuid begins with LVM-
* UUID_PREFIX is "LVM-"
*/
dm_uuid[0] = '\0';
if (!get_dm_uuid_from_sysfs(dm_uuid, sizeof(dm_uuid), dm_dev_major, dm_dev_minor))
continue;
if (!strncmp(dm_uuid, UUID_PREFIX, 4))
used_count++;
if (used_by_dm_name && !used_name)
used_name = dm_pool_strdup(cmd->mem, holder_name);
if (!used_by_vg_uuid && !used_by_lv_uuid)
continue;
/*
* UUID for LV is either "LVM-<vg_uuid><lv_uuid>" or
* "LVM-<vg_uuid><lv_uuid>-<suffix>", where vg_uuid and lv_uuid
* has length of ID_LEN and suffix len is not restricted (only
* restricted by whole DM UUID max len).
*/
uuid_len = strlen(dm_uuid);
if (((uuid_len == lvm_uuid_len) ||
((uuid_len > lvm_uuid_len) && (dm_uuid[lvm_uuid_len] == '-'))) &&
!strncmp(dm_uuid, UUID_PREFIX, lvm_prefix_len)) {
if (used_by_vg_uuid && !used_vgid)
used_vgid = dm_pool_strndup(cmd->mem, dm_uuid + lvm_prefix_len, ID_LEN);
if (used_by_lv_uuid && !used_lvid)
used_lvid = dm_pool_strndup(cmd->mem, dm_uuid + lvm_prefix_len + ID_LEN, ID_LEN);
}
}
if (used_by_lv_count)
*used_by_lv_count = used_count;
if (used_by_dm_name)
*used_by_dm_name = used_name;
if (used_by_vg_uuid)
*used_by_vg_uuid = used_vgid;
if (used_by_lv_uuid)
*used_by_lv_uuid = used_lvid;
if (used_count)
return 1;
return 0;
}
struct dev_types *create_dev_types(const char *proc_dir,
const struct dm_config_node *cn)
{
@@ -504,12 +621,16 @@ static int _has_partition_table(struct device *dev)
}
#ifdef UDEV_SYNC_SUPPORT
static int _udev_dev_is_partitioned(struct dev_types *dt, struct device *dev)
static int _dev_is_partitioned_udev(struct dev_types *dt, struct device *dev)
{
struct dev_ext *ext;
struct udev_device *device;
const char *value;
/*
* external_device_info_source="udev" enables these udev checks.
* external_device_info_source="none" disables them.
*/
if (!(ext = dev_ext_get(dev)))
return_0;
@@ -540,21 +661,20 @@ static int _udev_dev_is_partitioned(struct dev_types *dt, struct device *dev)
return !strcmp(value, DEV_EXT_UDEV_DEVTYPE_DISK);
}
#else
static int _udev_dev_is_partitioned(struct dev_types *dt, struct device *dev)
static int _dev_is_partitioned_udev(struct dev_types *dt, struct device *dev)
{
return 0;
}
#endif
static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
static int _dev_is_partitioned_native(struct dev_types *dt, struct device *dev)
{
int r;
if (!scan_bcache)
return -EAGAIN;
if (!_is_partitionable(dt, dev))
return 0;
if (!scan_bcache) {
log_error(INTERNAL_ERROR "dev_is_partitioned_native requires i/o.");
return -1;
}
/* Unpartitioned DASD devices are not supported. */
if ((MAJOR(dev->dev) == dt->dasd_major) && dasd_is_cdl_formatted(dev))
@@ -565,16 +685,20 @@ static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
return r;
}
int dev_is_partitioned(struct dev_types *dt, struct device *dev)
int dev_is_partitioned(struct cmd_context *cmd, struct device *dev)
{
if (dev->ext.src == DEV_EXT_NONE)
return _native_dev_is_partitioned(dt, dev);
struct dev_types *dt = cmd->dev_types;
if (dev->ext.src == DEV_EXT_UDEV)
return _udev_dev_is_partitioned(dt, dev);
if (!_is_partitionable(dt, dev))
return 0;
log_error(INTERNAL_ERROR "Missing hook for partition table recognition "
"using external device info source %s", dev_ext_name(dev));
if (_dev_is_partitioned_native(dt, dev) == 1)
return 1;
if (external_device_info_source() == DEV_EXT_UDEV) {
if (_dev_is_partitioned_udev(dt, dev) == 1)
return 1;
}
return 0;
}
@@ -886,14 +1010,14 @@ out:
#endif /* BLKID_WIPING_SUPPORT */
static int _wipe_signature(struct device *dev, const char *type, const char *name,
static int _wipe_signature(struct cmd_context *cmd, struct device *dev, const char *type, const char *name,
int wipe_len, int yes, force_t force, int *wiped,
int (*signature_detection_fn)(struct device *dev, uint64_t *offset_found, int full))
int (*signature_detection_fn)(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full))
{
int wipe;
uint64_t offset_found = 0;
wipe = signature_detection_fn(dev, &offset_found, 1);
wipe = signature_detection_fn(cmd, dev, &offset_found, 1);
if (wipe == -1) {
log_error("Fatal error while trying to detect %s on %s.",
type, name);
@@ -921,7 +1045,7 @@ static int _wipe_signature(struct device *dev, const char *type, const char *nam
return 1;
}
static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name,
static int _wipe_known_signatures_with_lvm(struct cmd_context *cmd, struct device *dev, const char *name,
uint32_t types_to_exclude __attribute__((unused)),
uint32_t types_no_prompt __attribute__((unused)),
int yes, force_t force, int *wiped)
@@ -932,9 +1056,9 @@ static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name,
wiped = &wiped_tmp;
*wiped = 0;
if (!_wipe_signature(dev, "software RAID md superblock", name, 4, yes, force, wiped, dev_is_md_component) ||
!_wipe_signature(dev, "swap signature", name, 10, yes, force, wiped, dev_is_swap) ||
!_wipe_signature(dev, "LUKS signature", name, 8, yes, force, wiped, dev_is_luks))
if (!_wipe_signature(cmd, dev, "software RAID md superblock", name, 4, yes, force, wiped, dev_is_md_component) ||
!_wipe_signature(cmd, dev, "swap signature", name, 10, yes, force, wiped, dev_is_swap) ||
!_wipe_signature(cmd, dev, "LUKS signature", name, 8, yes, force, wiped, dev_is_luks))
return 0;
return 1;
@@ -959,7 +1083,7 @@ int wipe_known_signatures(struct cmd_context *cmd, struct device *dev,
"while LVM is not compiled with blkid wiping support.");
log_warn("WARNING: Falling back to native LVM signature detection.");
}
return _wipe_known_signatures_with_lvm(dev, name,
return _wipe_known_signatures_with_lvm(cmd, dev, name,
types_to_exclude,
types_no_prompt,
yes, force, wiped);
@@ -1149,147 +1273,3 @@ int dev_is_pmem(struct dev_types *dt, struct device *dev)
}
#endif
#ifdef UDEV_SYNC_SUPPORT
/*
* Udev daemon usually has 30s timeout to process each event by default.
* But still, that value can be changed in udev configuration and we
* don't have libudev API to read the actual timeout value used.
*/
/* FIXME: Is this long enough to wait for udev db to get initialized?
*
* Take also into consideration that this check is done for each
* device that is scanned so we don't want to wait for a long time
* if there's something wrong with udev, e.g. timeouts! With current
* libudev API, we can't recognize whether the event processing has
* not finished yet and it's still being processed or whether it has
* failed already due to timeout in udev - in both cases the
* udev_device_get_is_initialized returns 0.
*/
#define UDEV_DEV_IS_COMPONENT_ITERATION_COUNT 100
#define UDEV_DEV_IS_COMPONENT_USLEEP 100000
static struct udev_device *_udev_get_dev(struct device *dev)
{
struct udev *udev_context = udev_get_library_context();
struct udev_device *udev_device = NULL;
int initialized = 0;
unsigned i = 0;
if (!udev_context) {
log_warn("WARNING: No udev context available to check if device %s is multipath component.", dev_name(dev));
return NULL;
}
while (1) {
if (i >= UDEV_DEV_IS_COMPONENT_ITERATION_COUNT)
break;
if (udev_device)
udev_device_unref(udev_device);
if (!(udev_device = udev_device_new_from_devnum(udev_context, 'b', dev->dev))) {
log_warn("WARNING: Failed to get udev device handler for device %s.", dev_name(dev));
return NULL;
}
#ifdef HAVE_LIBUDEV_UDEV_DEVICE_GET_IS_INITIALIZED
if ((initialized = udev_device_get_is_initialized(udev_device)))
break;
#else
if ((initialized = (udev_device_get_property_value(udev_device, DEV_EXT_UDEV_DEVLINKS) != NULL)))
break;
#endif
log_debug("Device %s not initialized in udev database (%u/%u, %u microseconds).", dev_name(dev),
i + 1, UDEV_DEV_IS_COMPONENT_ITERATION_COUNT,
i * UDEV_DEV_IS_COMPONENT_USLEEP);
if (!udev_sleeping())
break;
usleep(UDEV_DEV_IS_COMPONENT_USLEEP);
i++;
}
if (!initialized) {
log_warn("WARNING: Device %s not initialized in udev database even after waiting %u microseconds.",
dev_name(dev), i * UDEV_DEV_IS_COMPONENT_USLEEP);
goto out;
}
out:
return udev_device;
}
int udev_dev_is_mpath_component(struct device *dev)
{
struct udev_device *udev_device;
const char *value;
int ret = 0;
if (!obtain_device_list_from_udev())
return 0;
if (!(udev_device = _udev_get_dev(dev)))
return 0;
value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_BLKID_TYPE);
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH)) {
log_debug("Device %s is multipath component based on blkid variable in udev db (%s=\"%s\").",
dev_name(dev), DEV_EXT_UDEV_BLKID_TYPE, value);
ret = 1;
goto out;
}
value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
if (value && !strcmp(value, "1")) {
log_debug("Device %s is multipath component based on multipath variable in udev db (%s=\"%s\").",
dev_name(dev), DEV_EXT_UDEV_MPATH_DEVICE_PATH, value);
ret = 1;
goto out;
}
out:
udev_device_unref(udev_device);
return ret;
}
int udev_dev_is_md_component(struct device *dev)
{
struct udev_device *udev_device;
const char *value;
int ret = 0;
if (!obtain_device_list_from_udev())
return 0;
if (!(udev_device = _udev_get_dev(dev)))
return 0;
value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_BLKID_TYPE);
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_SW_RAID)) {
log_debug("Device %s is md raid component based on blkid variable in udev db (%s=\"%s\").",
dev_name(dev), DEV_EXT_UDEV_BLKID_TYPE, value);
dev->flags |= DEV_IS_MD_COMPONENT;
ret = 1;
goto out;
}
out:
udev_device_unref(udev_device);
return ret;
}
#else
int udev_dev_is_mpath_component(struct device *dev)
{
return 0;
}
int udev_dev_is_md_component(struct device *dev)
{
return 0;
}
#endif

View File

@@ -57,12 +57,11 @@ const char *dev_subsystem_name(struct dev_types *dt, struct device *dev);
int major_is_scsi_device(struct dev_types *dt, int major);
/* Signature/superblock recognition with position returned where found. */
int dev_is_md_component(struct device *dev, uint64_t *sb, int full);
int dev_is_swap(struct device *dev, uint64_t *signature, int full);
int dev_is_luks(struct device *dev, uint64_t *signature, int full);
int dev_is_md_component(struct cmd_context *cmd, struct device *dev, uint64_t *sb, int full);
int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev);
int dev_is_swap(struct cmd_context *cmd, struct device *dev, uint64_t *signature, int full);
int dev_is_luks(struct cmd_context *cmd, struct device *dev, uint64_t *signature, int full);
int dasd_is_cdl_formatted(struct device *dev);
int udev_dev_is_mpath_component(struct device *dev);
int udev_dev_is_md_component(struct device *dev);
int dev_is_lvm1(struct device *dev, char *buf, int buflen);
int dev_is_pool(struct device *dev, char *buf, int buflen);
@@ -81,7 +80,7 @@ int dev_is_md_with_end_superblock(struct dev_types *dt, struct device *dev);
/* Partitioning */
int major_max_partitions(struct dev_types *dt, int major);
int dev_is_partitioned(struct dev_types *dt, struct device *dev);
int dev_is_partitioned(struct cmd_context *cmd, struct device *dev);
int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result);
int dev_get_partition_number(struct device *dev, int *num);
@@ -102,4 +101,7 @@ int dev_is_lv(struct device *dev);
int get_fs_block_size(const char *pathname, uint32_t *fs_block_size);
int dev_is_used_by_active_lv(struct cmd_context *cmd, struct device *dev, int *used_by_lv_count,
char **used_by_dm_name, char **used_by_vg_uuid, char **used_by_lv_uuid);
#endif

View File

@@ -205,4 +205,7 @@ void dev_destroy_file(struct device *dev);
/* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev, int quiet);
int dev_mpath_init(const char *config_wwids_file);
void dev_mpath_exit(void);
#endif

View File

@@ -180,7 +180,7 @@ void free_dids(struct dm_list *ids)
}
}
static int _read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suffix, char *sysbuf, int sysbufsize)
int read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suffix, char *sysbuf, int sysbufsize)
{
char path[PATH_MAX];
dev_t devt = dev->dev;
@@ -246,7 +246,7 @@ static int _dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, cons
char sysbuf[PATH_MAX] = { 0 };
const char *idname;
if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
return 0;
if (!_dm_uuid_has_prefix(sysbuf, "mpath-"))
@@ -265,7 +265,7 @@ static int _dev_has_crypt_uuid(struct cmd_context *cmd, struct device *dev, cons
char sysbuf[PATH_MAX] = { 0 };
const char *idname;
if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
return 0;
if (!_dm_uuid_has_prefix(sysbuf, "CRYPT-"))
@@ -284,7 +284,7 @@ static int _dev_has_lvmlv_uuid(struct cmd_context *cmd, struct device *dev, cons
char sysbuf[PATH_MAX] = { 0 };
const char *idname;
if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
return 0;
if (!_dm_uuid_has_prefix(sysbuf, "LVM-"))
@@ -304,29 +304,37 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
const char *idname = NULL;
if (idtype == DEV_ID_TYPE_SYS_WWID) {
_read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf));
read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf));
if (!sysbuf[0])
_read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf));
read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf));
/* scsi_debug wwid begins "t10.Linux scsi_debug ..." */
if (strstr(sysbuf, "scsi_debug"))
sysbuf[0] = '\0';
/* qemu wwid begins "t10.ATA QEMU HARDDISK ..." */
if (strstr(sysbuf, "QEMU HARDDISK"))
sysbuf[0] = '\0';
}
else if (idtype == DEV_ID_TYPE_SYS_SERIAL)
_read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf));
read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf));
else if (idtype == DEV_ID_TYPE_MPATH_UUID)
_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
else if (idtype == DEV_ID_TYPE_CRYPT_UUID)
_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
else if (idtype == DEV_ID_TYPE_LVMLV_UUID)
_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
else if (idtype == DEV_ID_TYPE_MD_UUID)
_read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf));
read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf));
else if (idtype == DEV_ID_TYPE_LOOP_FILE) {
_read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf));
read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf));
/* if backing file is deleted, fall back to devname */
if (strstr(sysbuf, "(deleted)"))
sysbuf[0] = '\0';
@@ -364,17 +372,17 @@ static int _dev_has_stable_id(struct cmd_context *cmd, struct device *dev)
return 1;
}
if (_read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
if (read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
return 1;
if (_read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf)))
if (read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf)))
return 1;
if (_read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf)))
if (read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf)))
return 1;
if ((MAJOR(dev->dev) == cmd->dev_types->device_mapper_major)) {
if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
goto_out;
if (_dm_uuid_has_prefix(sysbuf, "mpath-"))
@@ -386,11 +394,11 @@ static int _dev_has_stable_id(struct cmd_context *cmd, struct device *dev)
}
if ((MAJOR(dev->dev) == cmd->dev_types->md_major) &&
_read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf)))
read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf)))
return 1;
if ((MAJOR(dev->dev) == cmd->dev_types->loop_major) &&
_read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf)))
read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf)))
return 1;
out:
/* DEV_ID_TYPE_DEVNAME would be used for this dev. */
@@ -1132,6 +1140,7 @@ id_done:
if (yes_no_prompt("Add device with duplicate PV to devices file?") == 'n') {
log_print("Device not added.");
free((void *)check_idname);
return 1;
}
}
@@ -1181,7 +1190,7 @@ id_done:
if (!label_scan_open(du_devid->dev))
log_warn("Cannot open %s", dev_name(du_devid->dev));
if (dev_is_partitioned(cmd->dev_types, du_devid->dev)) {
if (dev_is_partitioned(cmd, du_devid->dev)) {
/* Check if existing entry is whole device and new entry is a partition of it. */
ret1 = dev_get_primary_dev(cmd->dev_types, dev, &devt1);
if ((ret1 == 2) && (devt1 == du_devid->dev->dev))

View File

@@ -52,4 +52,6 @@ void devices_file_exit(struct cmd_context *cmd);
void unlink_searched_devnames(struct cmd_context *cmd);
int read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suffix, char *sysbuf, int sysbufsize);
#endif

View File

@@ -21,29 +21,24 @@
static int _and_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
struct dev_filter **filters;
int ret;
int ret = 1;
dev_ext_enable(dev, external_device_info_source());
for (filters = (struct dev_filter **) f->private; *filters; ++filters) {
if (use_filter_name && strcmp((*filters)->name, use_filter_name))
continue;
ret = (*filters)->passes_filter(cmd, *filters, dev, use_filter_name);
if (!ret)
return 0; /* No 'stack': a filter, not an error. */
if (!ret) {
ret = 0; /* No 'stack': a filter, not an error. */
break;
}
}
return 1;
}
static int _and_p_with_dev_ext_info(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
int r;
dev_ext_enable(dev, external_device_info_source());
r = _and_p(cmd, f, dev, use_filter_name);
dev_ext_disable(dev);
return r;
return ret;
}
static void _composite_destroy(struct dev_filter *f)
@@ -72,7 +67,7 @@ static void _wipe(struct cmd_context *cmd, struct dev_filter *f, struct device *
}
}
struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters)
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
{
struct dev_filter **filters_copy, *cft;
@@ -93,7 +88,7 @@ struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct d
return NULL;
}
cft->passes_filter = use_dev_ext_info ? _and_p_with_dev_ext_info : _and_p;
cft->passes_filter = _and_p;
cft->destroy = _composite_destroy;
cft->wipe = _wipe;
cft->use_count = 0;

View File

@@ -98,7 +98,7 @@ static int _passes_md_filter(struct cmd_context *cmd, struct dev_filter *f __att
if (!md_filtering())
return 1;
ret = dev_is_md_component(dev, NULL, cmd->use_full_md_check);
ret = dev_is_md_component(cmd, dev, NULL, cmd->use_full_md_check);
if (ret == -EAGAIN) {
/* let pass, call again after scan */

View File

@@ -17,333 +17,17 @@
#include "lib/filters/filter.h"
#include "lib/activate/activate.h"
#include "lib/commands/toolcontext.h"
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h>
#include "lib/device/dev-ext-udev-constants.h"
#endif
#ifdef __linux__
#include <dirent.h>
#define MPATH_PREFIX "mpath-"
struct mpath_priv {
struct dm_pool *mem;
struct dev_filter f;
struct dev_types *dt;
struct dm_hash_table *hash;
};
/*
* given "/dev/foo" return "foo"
*/
static const char *_get_sysfs_name(struct device *dev)
{
const char *name;
if (!(name = strrchr(dev_name(dev), '/'))) {
log_error("Cannot find '/' in device name.");
return NULL;
}
name++;
if (!*name) {
log_error("Device name is not valid.");
return NULL;
}
return name;
}
/*
* given major:minor
* readlink translates /sys/dev/block/major:minor to /sys/.../foo
* from /sys/.../foo return "foo"
*/
static const char *_get_sysfs_name_by_devt(const char *sysfs_dir, dev_t devno,
char *buf, size_t buf_size)
{
const char *name;
char path[PATH_MAX];
int size;
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d", sysfs_dir,
(int) MAJOR(devno), (int) MINOR(devno)) < 0) {
log_error("Sysfs path string is too long.");
return NULL;
}
if ((size = readlink(path, buf, buf_size - 1)) < 0) {
log_sys_error("readlink", path);
return NULL;
}
buf[size] = '\0';
if (!(name = strrchr(buf, '/'))) {
log_error("Cannot find device name in sysfs path.");
return NULL;
}
name++;
return name;
}
static int _get_sysfs_string(const char *path, char *buffer, int max_size)
{
FILE *fp;
int r = 0;
if (!(fp = fopen(path, "r"))) {
log_sys_error("fopen", path);
return 0;
}
if (!fgets(buffer, max_size, fp))
log_sys_error("fgets", path);
else
r = 1;
if (fclose(fp))
log_sys_error("fclose", path);
return r;
}
static int _get_sysfs_dm_mpath(struct dev_types *dt, const char *sysfs_dir, const char *holder_name)
{
char path[PATH_MAX];
char buffer[128];
if (dm_snprintf(path, sizeof(path), "%sblock/%s/dm/uuid", sysfs_dir, holder_name) < 0) {
log_error("Sysfs path string is too long.");
return 0;
}
buffer[0] = '\0';
if (!_get_sysfs_string(path, buffer, sizeof(buffer)))
return_0;
if (!strncmp(buffer, MPATH_PREFIX, 6))
return 1;
return 0;
}
static int _get_holder_name(const char *dir, char *name, int max_size)
{
struct dirent *d;
DIR *dr;
int r = 0;
if (!(dr = opendir(dir))) {
log_sys_error("opendir", dir);
return 0;
}
*name = '\0';
while ((d = readdir(dr))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
/* There should be only one holder if it is multipath */
if (*name) {
r = 0;
break;
}
strncpy(name, d->d_name, max_size);
r = 1;
}
if (closedir(dr))
log_sys_debug("closedir", dir);
return r;
}
#ifdef UDEV_SYNC_SUPPORT
static int _udev_dev_is_mpath_component(struct device *dev)
{
const char *value;
struct dev_ext *ext;
if (!(ext = dev_ext_get(dev)))
return_0;
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_TYPE);
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH))
return 1;
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
if (value && !strcmp(value, "1"))
return 1;
return 0;
}
#else
static int _udev_dev_is_mpath_component(struct device *dev)
{
return 0;
}
#endif
static int _native_dev_is_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
{
struct mpath_priv *mp = (struct mpath_priv *) f->private;
struct dev_types *dt = mp->dt;
const char *part_name;
const char *name; /* e.g. "sda" for "/dev/sda" */
char link_path[PATH_MAX]; /* some obscure, unpredictable sysfs path */
char holders_path[PATH_MAX]; /* e.g. "/sys/block/sda/holders/" */
char dm_dev_path[PATH_MAX]; /* e.g. "/dev/dm-1" */
char holder_name[256]; /* e.g. "dm-1" */
const char *sysfs_dir = dm_sysfs_dir();
int dev_major = MAJOR(dev->dev);
int dev_minor = MINOR(dev->dev);
int dm_dev_major;
int dm_dev_minor;
struct stat info;
dev_t primary_dev;
long look;
/* Limit this filter to SCSI or NVME devices */
if (!major_is_scsi_device(dt, dev_major) && !dev_is_nvme(dt, dev))
return 0;
switch (dev_get_primary_dev(dt, dev, &primary_dev)) {
case 2: /* The dev is partition. */
part_name = dev_name(dev); /* name of original dev for log_debug msg */
/* gets "foo" for "/dev/foo" where "/dev/foo" comes from major:minor */
if (!(name = _get_sysfs_name_by_devt(sysfs_dir, primary_dev, link_path, sizeof(link_path))))
return_0;
log_debug_devs("%s: Device is a partition, using primary "
"device %s for mpath component detection",
part_name, name);
break;
case 1: /* The dev is already a primary dev. Just continue with the dev. */
/* gets "foo" for "/dev/foo" */
if (!(name = _get_sysfs_name(dev)))
return_0;
break;
default: /* 0, error. */
log_warn("Failed to get primary device for %d:%d.", dev_major, dev_minor);
return 0;
}
if (dm_snprintf(holders_path, sizeof(holders_path), "%sblock/%s/holders", sysfs_dir, name) < 0) {
log_warn("Sysfs path to check mpath is too long.");
return 0;
}
/* also will filter out partitions */
if (stat(holders_path, &info))
return 0;
if (!S_ISDIR(info.st_mode)) {
log_warn("Path %s is not a directory.", holders_path);
return 0;
}
/*
* If holders dir contains an entry such as "dm-1", then this sets
* holder_name to "dm-1".
*
* If holders dir is empty, return 0 (this is generally where
* devs that are not mpath components return.)
*/
if (!_get_holder_name(holders_path, holder_name, sizeof(holder_name)))
return 0;
if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0) {
log_warn("dm device path to check mpath is too long.");
return 0;
}
/*
* stat "/dev/dm-1" which is the holder of the dev we're checking
* dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
*/
if (stat(dm_dev_path, &info)) {
log_debug("filter-mpath %s holder %s stat result %d",
dev_name(dev), dm_dev_path, errno);
return 0;
}
dm_dev_major = (int)MAJOR(info.st_rdev);
dm_dev_minor = (int)MINOR(info.st_rdev);
if (dm_dev_major != dt->device_mapper_major) {
log_debug_devs("filter-mpath %s holder %s %d:%d does not have dm major",
dev_name(dev), dm_dev_path, dm_dev_major, dm_dev_minor);
return 0;
}
/*
* Save the result of checking that "/dev/dm-1" is an mpath device
* to avoid repeating it for each path component.
* The minor number of "/dev/dm-1" is added to the hash table with
* const value 2 meaning that dm minor 1 (for /dev/dm-1) is a multipath dev
* and const value 1 meaning that dm minor 1 is not a multipath dev.
*/
look = (long) dm_hash_lookup_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor));
if (look > 0) {
log_debug_devs("filter-mpath %s holder %s %u:%u already checked as %sbeing mpath.",
dev_name(dev), holder_name, dm_dev_major, dm_dev_minor, (look > 1) ? "" : "not ");
return (look > 1) ? 1 : 0;
}
/*
* Returns 1 if /sys/block/<holder_name>/dm/uuid indicates that
* <holder_name> is a dm device with dm uuid prefix mpath-.
* When true, <holder_name> will be something like "dm-1".
*
* (Is a hash table worth it to avoid reading one sysfs file?)
*/
if (_get_sysfs_dm_mpath(dt, sysfs_dir, holder_name)) {
log_debug_devs("filter-mpath %s holder %s %u:%u ignore mpath component",
dev_name(dev), holder_name, dm_dev_major, dm_dev_minor);
(void) dm_hash_insert_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor), (void*)2);
return 1;
}
(void) dm_hash_insert_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor), (void*)1);
return 0;
}
static int _dev_is_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
{
if (dev->ext.src == DEV_EXT_NONE)
return _native_dev_is_mpath_component(cmd, f, dev);
if (dev->ext.src == DEV_EXT_UDEV)
return _udev_dev_is_mpath_component(dev);
log_error(INTERNAL_ERROR "Missing hook for mpath recognition "
"using external device info source %s", dev_ext_name(dev));
return 0;
}
#define MSG_SKIPPING "%s: Skipping mpath component device"
static int _ignore_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
dev->filtered_flags &= ~DEV_FILTERED_MPATH_COMPONENT;
if (_dev_is_mpath_component(cmd, f, dev) == 1) {
if (dev->ext.src == DEV_EXT_NONE)
log_debug_devs(MSG_SKIPPING, dev_name(dev));
else
log_debug_devs(MSG_SKIPPING " [%s:%p]", dev_name(dev),
dev_ext_name(dev), dev->ext.handle);
if (dev_is_mpath_component(cmd, dev)) {
log_debug_devs("%s: Skipping mpath component device", dev_name(dev));
dev->filtered_flags |= DEV_FILTERED_MPATH_COMPONENT;
return 0;
}
@@ -353,59 +37,33 @@ static int _ignore_mpath_component(struct cmd_context *cmd, struct dev_filter *f
static void _destroy(struct dev_filter *f)
{
struct mpath_priv *mp = (struct mpath_priv*) f->private;
if (f->use_count)
log_error(INTERNAL_ERROR "Destroying mpath filter while in use %u times.", f->use_count);
dm_hash_destroy(mp->hash);
dm_pool_destroy(mp->mem);
}
struct dev_filter *mpath_filter_create(struct dev_types *dt)
{
struct dev_filter *f;
const char *sysfs_dir = dm_sysfs_dir();
struct mpath_priv *mp;
struct dm_pool *mem;
struct dm_hash_table *hash;
if (!*sysfs_dir) {
log_verbose("No proc filesystem found: skipping multipath filter");
return NULL;
}
if (!(hash = dm_hash_create(110))) {
log_error("mpath hash table creation failed.");
if (!(f = zalloc(sizeof(*f)))) {
log_error("mpath filter allocation failed");
return NULL;
}
if (!(mem = dm_pool_create("mpath", 256))) {
log_error("mpath pool creation failed.");
dm_hash_destroy(hash);
return NULL;
}
if (!(mp = dm_pool_zalloc(mem, sizeof(*mp)))) {
log_error("mpath filter allocation failed.");
goto bad;
}
mp->f.passes_filter = _ignore_mpath_component;
mp->f.destroy = _destroy;
mp->f.use_count = 0;
mp->f.private = mp;
mp->f.name = "mpath";
mp->dt = dt;
mp->mem = mem;
mp->hash = hash;
f->passes_filter = _ignore_mpath_component;
f->destroy = _destroy;
f->use_count = 0;
f->name = "mpath";
log_debug_devs("mpath filter initialised.");
return &mp->f;
bad:
dm_pool_destroy(mem);
dm_hash_destroy(hash);
return NULL;
return f;
}
#else

View File

@@ -22,7 +22,6 @@
static int _passes_partitioned_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
struct dev_types *dt = (struct dev_types *) f->private;
int ret;
if (cmd->filter_nodata_only)
@@ -30,7 +29,7 @@ static int _passes_partitioned_filter(struct cmd_context *cmd, struct dev_filter
dev->filtered_flags &= ~DEV_FILTERED_PARTITIONED;
ret = dev_is_partitioned(dt, dev);
ret = dev_is_partitioned(cmd, dev);
if (ret == -EAGAIN) {
/* let pass, call again after scan */
@@ -72,7 +71,6 @@ struct dev_filter *partitioned_filter_create(struct dev_types *dt)
f->passes_filter = _passes_partitioned_filter;
f->destroy = _partitioned_filter_destroy;
f->use_count = 0;
f->private = dt;
f->name = "partitioned";
log_debug_devs("Partitioned filter initialised.");

View File

@@ -16,10 +16,6 @@
#include "lib/misc/lib.h"
#include "lib/filters/filter.h"
#include "lib/activate/activate.h"
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h>
#include "lib/device/dev-ext-udev-constants.h"
#endif
struct filter_data {
filter_mode_t mode;
@@ -28,7 +24,7 @@ struct filter_data {
static const char *_too_small_to_hold_pv_msg = "Too small to hold a PV";
static int _native_check_pv_min_size(struct device *dev)
static int _check_pv_min_size(struct device *dev)
{
uint64_t size;
int ret = 0;
@@ -50,61 +46,6 @@ out:
return ret;
}
#ifdef UDEV_SYNC_SUPPORT
static int _udev_check_pv_min_size(struct device *dev)
{
struct dev_ext *ext;
const char *size_str;
char *endp;
uint64_t size;
if (!(ext = dev_ext_get(dev)))
return_0;
if (!(size_str = udev_device_get_sysattr_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_SYSFS_ATTR_SIZE))) {
log_debug_devs("%s: Skipping: failed to get size from sysfs [%s:%p]",
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
return 0;
}
errno = 0;
size = strtoull(size_str, &endp, 10);
if (errno || !endp || *endp) {
log_debug_devs("%s: Skipping: failed to parse size from sysfs [%s:%p]",
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
return 0;
}
if (size < pv_min_size()) {
log_debug_devs("%s: Skipping: %s [%s:%p]", dev_name(dev),
_too_small_to_hold_pv_msg,
dev_ext_name(dev), dev->ext.handle);
return 0;
}
return 1;
}
#else
static int _udev_check_pv_min_size(struct device *dev)
{
return 1;
}
#endif
static int _check_pv_min_size(struct device *dev)
{
if (dev->ext.src == DEV_EXT_NONE)
return _native_check_pv_min_size(dev);
if (dev->ext.src == DEV_EXT_UDEV)
return _udev_check_pv_min_size(dev);
log_error(INTERNAL_ERROR "Missing hook for PV min size check "
"using external device info source %s", dev_ext_name(dev));
return 0;
}
static int _passes_usable_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
struct filter_data *data = f->private;
@@ -156,19 +97,9 @@ static int _passes_usable_filter(struct cmd_context *cmd, struct dev_filter *f,
}
if (r) {
/* check if the device is not too small to hold a PV */
switch (mode) {
case FILTER_MODE_NO_LVMETAD:
/* fall through */
case FILTER_MODE_PRE_LVMETAD:
r = _check_pv_min_size(dev);
if (!r)
dev->filtered_flags |= DEV_FILTERED_MINSIZE;
break;
case FILTER_MODE_POST_LVMETAD:
/* nothing to do here */
break;
}
r = _check_pv_min_size(dev);
if (!r)
dev->filtered_flags |= DEV_FILTERED_MINSIZE;
}
return r;

View File

@@ -20,7 +20,7 @@
#include "lib/device/dev-cache.h"
#include "lib/device/dev-type.h"
struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters);
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters);
struct dev_filter *lvm_type_filter_create(struct dev_types *dt);
struct dev_filter *md_filter_create(struct cmd_context *cmd, struct dev_types *dt);

View File

@@ -296,24 +296,11 @@ static struct raw_locn *_read_metadata_location_vg(struct cmd_context *cmd,
const char *vgname,
int *precommitted)
{
size_t len;
char vgnamebuf[NAME_LEN + 2] __attribute__((aligned(8)));
struct raw_locn *rlocn, *rlocn_precommitted;
struct lvmcache_info *info;
struct lvmcache_vgsummary vgsummary_orphan = {
.vgname = FMT_TEXT_ORPHAN_VG_NAME,
};
int rlocn_was_ignored;
dm_list_init(&vgsummary_orphan.pvsummaries);
memcpy(&vgsummary_orphan.vgid, FMT_TEXT_ORPHAN_VG_NAME, sizeof(FMT_TEXT_ORPHAN_VG_NAME));
rlocn = mdah->raw_locns; /* Slot 0 */
rlocn_precommitted = rlocn + 1; /* Slot 1 */
rlocn_was_ignored = rlocn_is_ignored(rlocn);
/* Should we use precommitted metadata? */
if (*precommitted && rlocn_precommitted->size &&
(rlocn_precommitted->offset != rlocn->offset)) {
@@ -338,42 +325,7 @@ static struct raw_locn *_read_metadata_location_vg(struct cmd_context *cmd,
if (!rlocn->offset && !rlocn->size)
return NULL;
/*
* Don't try to check existing metadata
* if given vgname is an empty string.
*/
if (!vgname || !*vgname)
return rlocn;
/*
* If live rlocn has ignored flag, data will be out-of-date so skip further checks.
*/
if (rlocn_was_ignored)
return rlocn;
/*
* Verify that the VG metadata pointed to by the rlocn
* begins with a valid vgname.
*/
memset(vgnamebuf, 0, sizeof(vgnamebuf));
if (!dev_read_bytes(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, vgnamebuf))
goto fail;
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{'))
return rlocn;
fail:
log_error("Metadata on %s at %llu has wrong VG name \"%s\" expected %s.",
dev_name(dev_area->dev),
(unsigned long long)(dev_area->start + rlocn->offset),
vgnamebuf, vgname);
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, dev_area->dev, 0)) &&
!lvmcache_update_vgname_and_id(cmd, info, &vgsummary_orphan))
stack;
return NULL;
return rlocn;
}
/*
@@ -487,9 +439,13 @@ static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd,
rlocn->checksum,
&when, &desc);
if (!vg) {
/* FIXME: detect and handle errors, and distinguish from the optimization
that skips parsing the metadata which also returns NULL. */
if (!vg && !*use_previous_vg) {
log_warn("WARNING: failed to read metadata text on %s at %llu size %llu for VG %s.",
dev_name(area->dev),
(unsigned long long)(area->start + rlocn->offset),
(unsigned long long)rlocn->size,
vgname);
return NULL;
}
log_debug_metadata("Found metadata on %s at %llu size %llu for VG %s",
@@ -498,7 +454,7 @@ static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd,
(unsigned long long)rlocn->size,
vgname);
if (vg && precommitted)
if (precommitted)
vg->status |= PRECOMMITTED;
out:
@@ -1533,8 +1489,6 @@ int read_metadata_location_summary(const struct format_type *fmt,
{
struct raw_locn *rlocn;
uint32_t wrap = 0;
unsigned int len = 0;
char namebuf[NAME_LEN + 1] __attribute__((aligned(8)));
uint64_t max_size;
if (!mdah) {
@@ -1563,28 +1517,6 @@ int read_metadata_location_summary(const struct format_type *fmt,
return 0;
}
memset(namebuf, 0, sizeof(namebuf));
if (!dev_read_bytes(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, namebuf))
stack;
while (namebuf[len] && !isspace(namebuf[len]) && namebuf[len] != '{' &&
len < (NAME_LEN - 1))
len++;
namebuf[len] = '\0';
/*
* Check that the text metadata in the circular buffer begins with a
* valid vg name.
*/
if (!validate_name(namebuf)) {
log_warn("WARNING: Metadata location on %s at %llu begins with invalid VG name.",
dev_name(dev_area->dev),
(unsigned long long)(dev_area->start + rlocn->offset));
return 0;
}
/*
* This function is used to read the vg summary during label scan.
* Save the text start location and checksum during scan. After the VG
@@ -1646,9 +1578,7 @@ int read_metadata_location_summary(const struct format_type *fmt,
vgsummary->mda_size = rlocn->size;
/* Keep track of largest metadata size we find. */
lvmcache_save_metadata_size_bytes(rlocn->size);
/* Keep track of the most full metadata area. */
lvmcache_save_metadata_size_percent(rlocn->size, mdah->size);
lvmcache_save_metadata_size(rlocn->size);
lvmcache_lookup_mda(vgsummary);

View File

@@ -327,6 +327,9 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct mda_header *mdah;
int retries = 0;
retry:
if (!(mdah = raw_read_mda_header(fmt, &mdac->area, (mda->mda_num == 1), 0, bad_fields))) {
log_warn("WARNING: bad metadata header on %s at %llu.",
@@ -354,6 +357,38 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
if (vgsummary->zero_offset)
return 1;
/*
* This code is used by label_scan to get a summary of the
* VG metadata that will be properly read later by vg_read.
* The initial read of this device during label_scan
* populates bcache with the first 128K of data from the
* device. That block of data contains the mda_header
* (at 4k) but will often not include the metadata text,
* which is often located further into the metadata area
* (beyond the 128K block saved in bcache.)
* So read_metadata_location_summary will usually get the
* mda_header from bcache which was read initially, and
* then it will often need to do a new disk read to get
* the actual metadata text that the mda_header points to.
* Since there is no locking around label_scan, it's
* possible (but very rare) that the entire metadata area
* can be rewritten by other commands between the time that
* this command read the mda_header and the time that it
* reads the metadata text. This means the expected metadata
* text isn't found, and an error is returned here.
* To handle this, invalidate all data in bcache for this
* device and reread the mda_header and metadata text back to
* back, so inconsistency is less likely (without locking
* there's no guarantee, e.g. if the command is blocked
* somehow between the two reads.)
*/
if (!retries) {
log_print("Retrying metadata scan.");
retries++;
dev_invalidate(mdac->area.dev);
goto retry;
}
log_warn("WARNING: bad metadata text on %s in mda%d",
dev_name(mdac->area.dev), mda->mda_num);
*bad_fields |= BAD_MDA_TEXT;

View File

@@ -150,11 +150,14 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/sysmacros.h>
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
static const char *_hints_file = DEFAULT_RUN_DIR "/hints";
static const char *_nohints_file = DEFAULT_RUN_DIR "/nohints";
static const char *_newhints_file = DEFAULT_RUN_DIR "/newhints";
@@ -1279,6 +1282,109 @@ check:
free(name);
}
static int _get_hints_from_pvs_online(struct cmd_context *cmd, struct dm_list *hints_out,
struct dm_list *devs_in, struct dm_list *devs_out)
{
char path[PATH_MAX];
char file_vgname[NAME_LEN];
struct dm_list hints_list;
struct hint file_hint;
struct hint *alloc_hint;
struct hint *hint, *hint2;
struct device_list *devl, *devl2;
int file_major, file_minor;
int found = 0;
DIR *dir;
struct dirent *de;
char *vgname = NULL;
char *pvid;
dm_list_init(&hints_list);
if (!(dir = opendir(PVS_ONLINE_DIR)))
return 0;
while ((de = readdir(dir))) {
if (de->d_name[0] == '.')
continue;
pvid = de->d_name;
if (strlen(pvid) != ID_LEN) /* 32 */
continue;
memset(path, 0, sizeof(path));
snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid);
memset(&file_hint, 0, sizeof(file_hint));
memset(file_vgname, 0, sizeof(file_vgname));
file_major = 0;
file_minor = 0;
if (!online_pvid_file_read(path, &file_major, &file_minor, file_vgname))
continue;
if (!dm_strncpy(file_hint.pvid, pvid, sizeof(file_hint.pvid)))
continue;
file_hint.devt = makedev(file_major, file_minor);
if (file_vgname[0] && validate_name(file_vgname)) {
if (!dm_strncpy(file_hint.vgname, file_vgname, sizeof(file_hint.vgname)))
continue;
}
if (!(alloc_hint = malloc(sizeof(struct hint))))
continue;
memcpy(alloc_hint, &file_hint, sizeof(struct hint));
log_debug("add hint %s %d:%d %s from pvs_online", file_hint.pvid, file_major, file_minor, file_vgname);
dm_list_add(&hints_list, &alloc_hint->list);
found++;
}
if (closedir(dir))
stack;
log_debug("accept hints found %d from pvs_online", found);
_get_single_vgname_cmd_arg(cmd, &hints_list, &vgname);
/*
* apply_hints equivalent, move devs from devs_in to devs_out if
* their devno matches the devno of a hint (and if the hint matches
* the vgname when a vgname is present.)
*/
dm_list_iterate_items_safe(devl, devl2, devs_in) {
dm_list_iterate_items_safe(hint, hint2, &hints_list) {
if ((MAJOR(devl->dev->dev) == MAJOR(hint->devt)) &&
(MINOR(devl->dev->dev) == MINOR(hint->devt))) {
if (vgname && hint->vgname[0] && strcmp(vgname, hint->vgname))
goto next_dev;
snprintf(hint->name, sizeof(hint->name), "%s", dev_name(devl->dev));
hint->chosen = 1;
dm_list_del(&devl->list);
dm_list_add(devs_out, &devl->list);
}
}
next_dev:
;
}
log_debug("applied hints using %d other %d vgname %s from pvs_online",
dm_list_size(devs_out), dm_list_size(devs_in), vgname ?: "");
dm_list_splice(hints_out, &hints_list);
free(vgname);
return 1;
}
/*
* Returns 0: no hints are used.
* . newhints is set if this command should create new hints after scan
@@ -1288,14 +1394,12 @@ check:
*/
int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
struct dm_list *devs_in, struct dm_list *devs_out, char **vgname_out)
struct dm_list *devs_in, struct dm_list *devs_out)
{
struct dm_list hints_list;
int needs_refresh = 0;
char *vgname = NULL;
*vgname_out = NULL;
dm_list_init(&hints_list);
/* Decide below if the caller should create new hints. */
@@ -1322,6 +1426,15 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
if (!cmd->use_hints)
return 0;
/* hints = "pvs_online" */
if (cmd->hints_pvs_online) {
if (!_get_hints_from_pvs_online(cmd, &hints_list, devs_in, devs_out)) {
log_debug("get_hints: pvs_online failed");
return 0;
}
return 1;
}
/*
* Check if another command created the nohints file to prevent us from
* using hints.
@@ -1435,7 +1548,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
dm_list_splice(hints_out, &hints_list);
*vgname_out = vgname;
free(vgname);
return 1;
}

View File

@@ -33,7 +33,7 @@ void clear_hint_file(struct cmd_context *cmd);
void invalidate_hints(struct cmd_context *cmd);
int get_hints(struct cmd_context *cmd, struct dm_list *hints, int *newhints,
struct dm_list *devs_in, struct dm_list *devs_out, char **vgname_out);
struct dm_list *devs_in, struct dm_list *devs_out);
int validate_hints(struct cmd_context *cmd, struct dm_list *hints);

View File

@@ -264,9 +264,8 @@ static bool _in_bcache(struct device *dev)
}
static struct labeller *_find_lvm_header(struct device *dev,
char *scan_buf,
uint32_t scan_buf_sectors,
char *label_buf,
char *headers_buf,
int headers_buf_size,
uint64_t *label_sector,
uint64_t block_sector,
uint64_t start_sector)
@@ -277,24 +276,13 @@ static struct labeller *_find_lvm_header(struct device *dev,
uint64_t sector;
int found = 0;
/*
* Find which sector in scan_buf starts with a valid label,
* and copy it into label_buf.
*/
for (sector = start_sector; sector < start_sector + LABEL_SCAN_SECTORS;
sector += LABEL_SIZE >> SECTOR_SHIFT) {
/*
* The scan_buf passed in is a bcache block, which is
* BCACHE_BLOCK_SIZE_IN_SECTORS large. So if start_sector is
* one of the last couple sectors in that buffer, we need to
* break early.
*/
if (sector >= scan_buf_sectors)
if ((sector * 512) >= headers_buf_size)
break;
lh = (struct label_header *) (scan_buf + (sector << SECTOR_SHIFT));
lh = (struct label_header *) (headers_buf + (sector << SECTOR_SHIFT));
if (!memcmp(lh->id, LABEL_ID, sizeof(lh->id))) {
if (found) {
@@ -332,7 +320,6 @@ static struct labeller *_find_lvm_header(struct device *dev,
labeller_ret = li->l;
found = 1;
memcpy(label_buf, lh, LABEL_SIZE);
if (label_sector)
*label_sector = block_sector + sector;
break;
@@ -354,13 +341,13 @@ static struct labeller *_find_lvm_header(struct device *dev,
* are performed in the processing functions to get that data.
*/
static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
struct device *dev, struct block *bb,
struct device *dev, char *headers_buf, int headers_buf_size,
uint64_t block_sector, uint64_t start_sector,
int *is_lvm_device)
{
char label_buf[LABEL_SIZE] __attribute__((aligned(8)));
char *label_buf;
struct labeller *labeller;
uint64_t sector = 0;
uint64_t label_sector = 0;
int is_duplicate = 0;
int ret = 0;
@@ -396,13 +383,9 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
}
/*
* Finds the data sector containing the label and copies into label_buf.
* label_buf: struct label_header + struct pv_header + struct pv_header_extension
*
* FIXME: we don't need to copy one sector from bb->data into label_buf,
* we can just point label_buf at one sector in ld->buf.
* Finds the data sector containing the label.
*/
if (!(labeller = _find_lvm_header(dev, bb->data, BCACHE_BLOCK_SIZE_IN_SECTORS, label_buf, &sector, block_sector, start_sector))) {
if (!(labeller = _find_lvm_header(dev, headers_buf, headers_buf_size, &label_sector, block_sector, start_sector))) {
/*
* Non-PVs exit here
@@ -427,6 +410,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
dev->flags |= DEV_SCAN_FOUND_LABEL;
*is_lvm_device = 1;
label_buf = headers_buf + (label_sector * 512);
/*
* This is the point where the scanning code dives into the rest of
@@ -436,7 +420,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
* info/vginfo structs. That lvmcache info is used later when the
* command wants to read the VG to do something to it.
*/
ret = labeller->ops->read(cmd, labeller, dev, label_buf, sector, &is_duplicate);
ret = labeller->ops->read(cmd, labeller, dev, label_buf, label_sector, &is_duplicate);
if (!ret) {
if (is_duplicate) {
@@ -670,9 +654,12 @@ static void _invalidate_di(struct bcache *cache, int di)
* its info is removed from lvmcache.
*/
#define HEADERS_BUF_SIZE 4096
static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
struct dm_list *devs, int want_other_devs, int *failed)
{
char headers_buf[HEADERS_BUF_SIZE];
struct dm_list wait_devs;
struct dm_list done_devs;
struct dm_list reopen_devs;
@@ -738,14 +725,35 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
scan_read_errors++;
scan_failed_count++;
lvmcache_del_dev(devl->dev);
if (bb)
bcache_put(bb);
} else {
log_debug_devs("Processing data from device %s %d:%d di %d block %p",
/* copy the first 4k from bb that will contain label_header */
memcpy(headers_buf, bb->data, HEADERS_BUF_SIZE);
/*
* "put" the bcache block before process_block because
* processing metadata may need to invalidate and reread
* metadata that's covered by bb. invalidate/reread is
* not allowed while bb is held. The functions for
* filtering and scanning metadata for this device use
* dev_read_bytes(), which will generally grab the
* bcache block/data that we're putting here. Since
* we're doing put, it's possible but not likely that
* bcache could drop the block before dev_read_bytes()
* uses it again, in which case bcache will reread it
* from disk for dev_read_bytes().
*/
bcache_put(bb);
log_debug_devs("Processing data from device %s %d:%d di %d",
dev_name(devl->dev),
(int)MAJOR(devl->dev->dev),
(int)MINOR(devl->dev->dev),
devl->dev->bcache_di, (void *)bb);
devl->dev->bcache_di);
ret = _process_block(cmd, f, devl->dev, bb, 0, 0, &is_lvm_device);
ret = _process_block(cmd, f, devl->dev, headers_buf, sizeof(headers_buf), 0, 0, &is_lvm_device);
if (!ret && is_lvm_device) {
log_debug_devs("Scan failed to process %s", dev_name(devl->dev));
@@ -754,9 +762,6 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
}
}
if (bb)
bcache_put(bb);
/*
* Keep the bcache block of lvm devices we have processed so
* that the vg_read phase can reuse it. If bcache failed to
@@ -1032,7 +1037,6 @@ int label_scan(struct cmd_context *cmd)
struct dev_iter *iter;
struct device_list *devl, *devl2;
struct device *dev;
char *vgname_hint = NULL;
uint64_t max_metadata_size_bytes;
int device_ids_invalid = 0;
int using_hints;
@@ -1138,54 +1142,21 @@ int label_scan(struct cmd_context *cmd)
* by using hints which tell us which devices are PVs, which
* are the only devices we actually need to scan. Without
* hints we need to scan all devs to find which are PVs.
*/
if (!get_hints(cmd, &hints_list, &create_hints, &all_devs, &scan_devs, &vgname_hint)) {
dm_list_splice(&scan_devs, &all_devs);
dm_list_init(&hints_list);
using_hints = 0;
} else
using_hints = 1;
/*
* If the command is using hints and a single vgname
*
* TODO: if the command is using hints and a single vgname
* arg, we can also take the vg lock here, prior to scanning.
* This means we would not need to rescan the PVs in the VG
* in vg_read (skip lvmcache_label_rescan_vg) after the
* vg lock is usually taken. (Some commands are already
* able to avoid rescan in vg_read, but locking early would
* apply to more cases.)
*
* TODO: we don't know exactly which vg lock mode (read or write)
* the command will use in vg_read() for the normal lock_vol(),
* but we could make a fairly accurate guess of READ/WRITE based
* on looking at the command name. If we guess wrong we can
* just unlock_vg and lock_vol again with the correct mode in
* vg_read().
*/
if (vgname_hint) {
uint32_t lck_type = LCK_VG_WRITE;
log_debug("Early lock vg");
/* FIXME: borrowing this lockd flag which should be
quite close to what we want, based on the command name.
Need to do proper mode selection here, and then check
in case the later lock_vol in vg_read wants different. */
if (cmd->lockd_vg_default_sh)
lck_type = LCK_VG_READ;
if (!lock_vol(cmd, vgname_hint, lck_type, NULL)) {
log_warn("Could not pre-lock VG %s.", vgname_hint);
/* not an error since this is just an optimization */
} else {
/* Save some state indicating that the vg lock
is already held so that the normal lock_vol()
will know. */
cmd->early_lock_vg_mode = lck_type;
}
free(vgname_hint);
}
if (!get_hints(cmd, &hints_list, &create_hints, &all_devs, &scan_devs)) {
dm_list_splice(&scan_devs, &all_devs);
dm_list_init(&hints_list);
using_hints = 0;
} else
using_hints = 1;
/*
* If the total number of devices exceeds the soft open file
@@ -1221,7 +1192,7 @@ int label_scan(struct cmd_context *cmd)
* If the largest metadata is within 1MB of the bcache size, then start
* warning.
*/
max_metadata_size_bytes = lvmcache_max_metadata_size_bytes();
max_metadata_size_bytes = lvmcache_max_metadata_size();
if (max_metadata_size_bytes + (1024 * 1024) > _current_bcache_size_bytes) {
/* we want bcache to be 1MB larger than the max metadata seen */
@@ -1236,14 +1207,6 @@ int label_scan(struct cmd_context *cmd)
(unsigned long long)want_size_kb);
}
/*
* If vg metadata is using a large percentage of a metadata area, then
* create /run/lvm/scan_lock_global to tell future lvm commands to
* begin doing lock_global() prior to scanning to avoid problems due to
* metadata wrapping between label_scan and vg_read.
*/
set_scan_lock_global(cmd);
dm_list_init(&cmd->hints);
/*
@@ -1741,6 +1704,11 @@ bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len)
return bcache_invalidate_bytes(scan_bcache, dev->bcache_di, start, len);
}
void dev_invalidate(struct device *dev)
{
bcache_invalidate_di(scan_bcache, dev->bcache_di);
}
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len)
{
return dev_set_bytes(dev, start, len, 0);

View File

@@ -130,6 +130,7 @@ bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data)
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len);
bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val);
bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len);
void dev_invalidate(struct device *dev);
void dev_set_last_byte(struct device *dev, uint64_t offset);
void dev_unset_last_byte(struct device *dev);

View File

@@ -203,11 +203,6 @@ int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags, const str
if (is_orphan_vg(vol))
return 1;
if (!is_global && cmd->early_lock_vg_mode && (lck_type != LCK_UNLOCK)) {
log_debug("VG was locked early.");
return 1;
}
if (!_blocking_supported)
flags |= LCK_NONBLOCK;
@@ -359,8 +354,10 @@ static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert,
if (!strcmp(mode, "ex")) {
flags |= LCK_WRITE;
if (cmd->lockf_global_ex)
if (cmd->lockf_global_ex) {
log_warn("global flock already held ex");
return 1;
}
ret = lock_vol(cmd, VG_GLOBAL, flags, NULL);
if (ret)

View File

@@ -25,6 +25,7 @@
#include <syslog.h>
#include <ctype.h>
#include <time.h>
#include <systemd/sd-journal.h>
static FILE *_log_file;
static char _log_file_path[PATH_MAX];
@@ -40,6 +41,7 @@ static char _msg_prefix[30] = " ";
static int _abort_on_internal_errors_config = 0;
static uint32_t _debug_file_fields;
static uint32_t _debug_output_fields;
static uint32_t _log_journal = 0;
static lvm2_log_fn_t _lvm2_log_fn = NULL;
@@ -455,6 +457,11 @@ void init_debug_output_fields(uint32_t debug_fields)
_debug_output_fields = debug_fields;
}
void init_log_journal(uint32_t fields)
{
_log_journal = fields;
}
static void _set_time_prefix(char *prefix, int buflen)
{
@@ -609,6 +616,33 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
}
log_it:
if (_log_journal) {
int to_journal = 0;
/* By default the visible command output is _LOG_WARN or less. */
if (_log_journal & LOG_JOURNAL_DEBUG)
to_journal = 1;
if ((_log_journal & LOG_JOURNAL_OUTPUT) && (log_level(level) <= _LOG_WARN))
to_journal = 1;
if (to_journal) {
int prio;
switch (log_level(level)) {
case _LOG_ERR: prio = LOG_ERR; break;
case _LOG_WARN: prio = LOG_WARNING; break;
case _LOG_INFO: prio = LOG_INFO; break;
case _LOG_NOTICE: prio = LOG_NOTICE; break;
case _LOG_DEBUG: prio = LOG_DEBUG; break;
default: prio = LOG_INFO;
}
va_copy(ap, orig_ap);
sd_journal_printv(prio, trformat, ap);
va_end(ap);
}
}
if (!logged_via_report && ((verbose_level() >= level) && !_log_suppress)) {
if (verbose_level() > _LOG_DEBUG) {
memset(buf, 0, sizeof(buf));
@@ -792,3 +826,60 @@ void log_set_report_object_name_and_id(const char *name, const char *id)
_log_report.object_name = name;
_log_report.object_id = id;
}
/*
* TODO: log/journal=["daemon_command"]
* daemon_command: record commands that are run by an lvm daemon.
* (i.e. not commands run directly by a user.)
* For this we need to be able to clearly identify when a command is
* being run by dmeventd/lvmpolld/lvmdbusd.
*
* TODO: log/journal_commmand_names=["lvcreate","lvconvert"]
* This would restrict log/journal=["command"] to the listed command names.
* Also allow "!command" to exclude a command, e.g. ["!pvs"]
*
* TODO: log/journal_daemon_command_names=["lvcreate","lvconvert"]
* This would restrict log/journal=["dameon_command"] to the listed command names.
*
* TODO: log/journal_daemon_names=["dmeventd"]
* This would restrict log/journal=["daemon_command"] to commands run by
* the named daemon.
*
* TODO: log/command_to_file=<path> would write this info to the file.
*
* TODO: log/debug_to_file=<path> would write full debugging to the file.
* (the same effect as log/file=<path> log/level=7)
*/
void log_command(const char *cmd_line, const char *cmd_name, const char *cmd_id)
{
if (_log_journal & LOG_JOURNAL_COMMAND) {
/*
* TODO: DAEMON=dmeventd|lvmpolld|lvmdbusd,
* Could we include caller info such as libblkid, udev rule, etc?
* Does systemd already record the caller for us?
*/
/* The command line, pid, and other things are automatically included. */
sd_journal_send("MESSAGE=lvm command %s", cmd_name,
"MESSAGE_ID=3ca432788c374e4ba684b834188eca36",
"LVM_CMD_NAME=%s", cmd_name,
"LVM_CMD_ID=%s", cmd_id,
"PRIORITY=%i", LOG_INFO,
NULL);
}
}
uint32_t log_journal_str_to_val(const char *str)
{
if (!strcasecmp(str, "command"))
return LOG_JOURNAL_COMMAND;
if (!strcasecmp(str, "output"))
return LOG_JOURNAL_OUTPUT;
if (!strcasecmp(str, "debug"))
return LOG_JOURNAL_DEBUG;
return 0;
}

View File

@@ -63,6 +63,10 @@
#define LOG_DEBUG_FIELD_FILELINE 0x0004
#define LOG_DEBUG_FIELD_MESSAGE 0x0008
#define LOG_JOURNAL_COMMAND 0x0001
#define LOG_JOURNAL_OUTPUT 0x0002
#define LOG_JOURNAL_DEBUG 0x0004
/*
* Classes available for debug log messages.

View File

@@ -62,6 +62,12 @@ void reset_log_duplicated(void);
void init_syslog(int facility);
void fin_syslog(void);
void init_log_journal(uint32_t fields);
uint32_t log_journal_str_to_val(const char *str);
void log_command(const char *cmd_line, const char *cmd_name, const char *cmd_id);
int error_message_produced(void);
void reset_lvm_errno(int store_errmsg);
int stored_errno(void);

View File

@@ -8739,7 +8739,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
if (seg_is_vdo_pool(lp)) {
if (!convert_vdo_pool_lv(lv, &lp->vdo_params, &lp->virtual_extents, 1)) {
if (!convert_vdo_pool_lv(lv, &lp->vdo_params, &lp->virtual_extents,
1, lp->vdo_pool_header_size)) {
stack;
goto deactivate_and_revert_new_lv;
}

View File

@@ -1034,6 +1034,7 @@ struct lvcreate_params {
int approx_alloc; /* all */
alloc_policy_t alloc; /* all */
struct dm_vdo_target_params vdo_params; /* vdo */
uint64_t vdo_pool_header_size; /* VDO */
int raidintegrity;
const char *raidintegritymode;
@@ -1368,10 +1369,12 @@ int parse_vdo_pool_status(struct dm_pool *mem, const struct logical_volume *vdo_
struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
const struct dm_vdo_target_params *vtp,
uint32_t *virtual_extents,
int format);
int format,
uint64_t vdo_pool_header_size);
int set_vdo_write_policy(enum dm_vdo_write_policy *vwp, const char *policy);
int fill_vdo_target_params(struct cmd_context *cmd,
struct dm_vdo_target_params *vtp,
uint64_t *vdo_pool_header_size,
struct profile *profile);
/* -- metadata/vdo_manip.c */

View File

@@ -5132,7 +5132,8 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
if (!check_pv_dev_sizes(vg))
log_warn("WARNING: One or more devices used as PVs in VG %s have changed sizes.", vg->name);
_check_devs_used_correspond_with_vg(vg);
if (cmd->check_devs_used)
_check_devs_used_correspond_with_vg(vg);
if (!_access_vg_lock_type(cmd, vg, lockd_state, &failure)) {
/* Either FAILED_LOCK_TYPE or FAILED_LOCK_MODE were set. */
@@ -5278,3 +5279,36 @@ struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_
return vg;
}
int get_visible_lvs_using_pv(struct cmd_context *cmd, struct volume_group *vg, struct device *dev,
struct dm_list *lvs_list)
{
struct pv_list *pvl;
struct lv_list *lvl, *lvl2;
struct physical_volume *pv = NULL;
dm_list_iterate_items(pvl, &vg->pvs) {
if (pvl->pv->dev == dev) {
pv = pvl->pv;
break;
}
}
if (!pv)
return_0;
dm_list_iterate_items(lvl, &vg->lvs) {
if (!lv_is_visible(lvl->lv))
continue;
if (!lv_is_on_pv(lvl->lv, pv))
continue;
if (!(lvl2 = dm_pool_zalloc(cmd->mem, sizeof(*lvl2))))
return_0;
lvl2->lv = lvl->lv;
dm_list_add(lvs_list, &lvl2->list);
}
return 1;
}

View File

@@ -538,4 +538,8 @@ char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tagsl);
void set_pv_devices(struct format_instance *fid, struct volume_group *vg);
int get_visible_lvs_using_pv(struct cmd_context *cmd, struct volume_group *vg, struct device *dev,
struct dm_list *lvs_list);
#endif

View File

@@ -356,9 +356,9 @@ static int _format_vdo_pool_data_lv(struct logical_volume *data_lv,
struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
const struct dm_vdo_target_params *vtp,
uint32_t *virtual_extents,
int format)
int format,
uint64_t vdo_pool_header_size)
{
const uint64_t header_size = DEFAULT_VDO_POOL_HEADER_SIZE;
const uint32_t extent_size = data_lv->vg->extent_size;
struct cmd_context *cmd = data_lv->vg->cmd;
struct logical_volume *vdo_pool_lv = data_lv;
@@ -379,7 +379,7 @@ struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
if (*virtual_extents)
vdo_logical_size =
_get_virtual_size(*virtual_extents, extent_size, header_size);
_get_virtual_size(*virtual_extents, extent_size, vdo_pool_header_size);
if (!dm_vdo_validate_target_params(vtp, vdo_logical_size))
return_0;
@@ -393,7 +393,8 @@ struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
} else {
log_verbose("Skiping VDO formating %s.", display_lvname(data_lv));
/* TODO: parse existing VDO data and retrieve vdo_logical_size */
vdo_logical_size = data_lv->size;
if (!*virtual_extents)
vdo_logical_size = data_lv->size;
}
if (!deactivate_lv(data_lv->vg->cmd, data_lv)) {
@@ -402,7 +403,7 @@ struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
return NULL;
}
vdo_logical_size -= 2 * header_size;
vdo_logical_size -= 2 * vdo_pool_header_size;
if (vdo_logical_size < extent_size) {
if (!*virtual_extents)
@@ -425,7 +426,7 @@ struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
vdo_pool_seg = first_seg(vdo_pool_lv);
vdo_pool_seg->segtype = vdo_pool_segtype;
vdo_pool_seg->vdo_params = *vtp;
vdo_pool_seg->vdo_pool_header_size = DEFAULT_VDO_POOL_HEADER_SIZE;
vdo_pool_seg->vdo_pool_header_size = vdo_pool_header_size;
vdo_pool_seg->vdo_pool_virtual_extents = *virtual_extents;
vdo_pool_lv->status |= LV_VDO_POOL;
@@ -452,6 +453,7 @@ int set_vdo_write_policy(enum dm_vdo_write_policy *vwp, const char *policy)
int fill_vdo_target_params(struct cmd_context *cmd,
struct dm_vdo_target_params *vtp,
uint64_t *vdo_pool_header_size,
struct profile *profile)
{
const char *policy;
@@ -500,5 +502,7 @@ int fill_vdo_target_params(struct cmd_context *cmd,
if (!set_vdo_write_policy(&vtp->write_policy, policy))
return_0;
*vdo_pool_header_size = 2 * find_config_tree_int64(cmd, allocation_vdo_pool_header_size_CFG, profile);
return 1;
}

View File

@@ -25,19 +25,29 @@ struct udev *_udev;
int udev_init_library_context(void)
{
if (_udev)
udev_unref(_udev);
return 1;
if (getenv("DM_DISABLE_UDEV"))
return 0;
if (!(_udev = udev_new())) {
log_error("Failed to create udev library context.");
return 0;
}
if (!udev_is_running()) {
udev_unref(_udev);
_udev = NULL;
return 0;
}
return 1;
}
void udev_fin_library_context(void)
{
udev_unref(_udev);
if (_udev)
udev_unref(_udev);
_udev = NULL;
}

View File

@@ -23,6 +23,7 @@ else
endif
FSADMMAN = fsadm.8
VDOIMPORTMAN = vdoimport.8
BLKDEACTIVATEMAN = blkdeactivate.8
DMEVENTDMAN = dmeventd.8
DMFILEMAPDMAN = dmfilemapd.8
@@ -50,7 +51,7 @@ MAN8SYSTEMD_GENERATORS=lvm2-activation-generator.8
ifeq (,$(findstring $(MAKECMDGOALS), distclean all_man install_all_man))
MAN7 += lvmcache.7 lvmthin.7 lvmvdo.7
MAN8+=$(FSADMMAN) $(LVMPOLLDMAN) $(LVMLOCKDMAN) $(LVMDBUSDMAN)
MAN8+=$(FSADMMAN) $(LVMPOLLDMAN) $(LVMLOCKDMAN) $(LVMDBUSDMAN) $(VDOIMPORTMAN)
MAN8DM+=$(BLKDEACTIVATEMAN) $(DMEVENTDMAN) $(DMFILEMAPDMAN)
MAN8CLUSTER+=$(CMIRRORDMAN)
else
@@ -58,6 +59,10 @@ else
MAN8+=$(FSADMMAN)
endif
ifeq ("@VDOIMPORT@", "yes")
MAN8+=$(VDOIMPORTMAN)
endif
ifeq ("@BUILD_LVMDBUSD@", "yes")
MAN8+=$(LVMDBUSDMAN)
endif

View File

@@ -670,7 +670,7 @@ Convert LV to type thin-pool.
.RE
.P
.RS 4
LV1 types: linear striped cache raid error zero
LV1 types: linear striped cache raid error zero writecache
.RE
.P
\(em

View File

@@ -27,6 +27,8 @@ lvmdevices \(em Manage the devices file
\fB--deldev\fP \fIPV\fP
.br
\fB--delpvid\fP \fIString\fP
.br
\fB--deviceidtype\fP \fIString\fP
.br
\fB--devices\fP \fIPV\fP
.br
@@ -70,18 +72,18 @@ remove it from the devices file with lvmdevices --deldev. The
vgimportdevices(8) command adds all PVs from a VG to the devices file,
and updates the VG metadata to include device IDs of the PVs.
.P
Commands adding new devices to the devices file necessarily look outside
the existing devices file to find the devices to add. pvcreate, vgcreate,
and vgextend also look outside the devices file to create new PVs and add
them to the devices file.
Commands that add new devices to the devices file necessarily look outside
the existing devices file to find the devices being added. pvcreate,
vgcreate, and vgextend also look outside the devices file to create new
PVs and add those PVs to the devices file.
.P
LVM records devices in the devices file using hardware-specific IDs, such
as the WWID, and attempts to use subsystem-specific IDs for virtual device
types (which also aim to be as unique and stable as possible.)
These device IDs are also written in the VG metadata. When no hardware or
types (which also aim to be as unique and stable as possible.) These
device IDs are also written in the VG metadata. When no hardware or
virtual ID is available, lvm falls back using the unstable device name as
the device ID. When devnames are used, lvm performs extra scanning to
find devices if their devname changes, e.g. after reboot.
the device ID. When devnames are used as IDs, lvm performs extra scanning
to find devices if their devname changes, e.g. after reboot.
.P
When proper device IDs are used, an lvm command will not look at devices
outside the devices file, but when devnames are used as a fallback, lvm
@@ -95,12 +97,13 @@ overriding the devices file. The listed devices act as a sort of devices
file in terms of limiting which devices lvm will see and use. Devices
that are not listed will appear to be missing to the lvm command.
.P
Multiple devices files can be kept in \fI#DEFAULT_SYS_DIR#/devices\fP, which allows lvm
to be used with different sets of devices, e.g. system devices do not need
to be exposed to a specific application, and the application can use lvm on
its own devices that are not exposed to the system. The option
--devicesfile <filename> is used to select the devices file to use with the
command. Without the option set, the default system devices file is used.
Multiple devices files can be kept \fI#DEFAULT_SYS_DIR#/devices\fP, which
allows lvm to be used with different sets of devices. For example, system
devices do not need to be exposed to a specific application, and the
application can use lvm on its own devices that are not exposed to the
system. The option --devicesfile <filename> is used to select the devices
file to use with the command. Without the option set, the default system
devices file is used.
.P
Setting --devicesfile "" causes lvm to not use a devices file.
.P
@@ -120,6 +123,45 @@ if it does not yet exist.
.P
It is recommended to use lvm commands to make changes to the devices file to
ensure proper updates.
.P
The device ID and device ID type are included in the VG metadata and can
be reported with pvs -o deviceid,deviceidtype. (Note that the lvmdevices
command does not update VG metadata, but subsequent lvm commands modifying
the metadata will include the device ID.)
.P
Possible device ID types are:
.br
.IP \[bu] 2
.B sys_wwid
uses the wwid reported by sysfs. This is the first choice for non-virtual
devices.
.IP \[bu] 2
.B sys_serial
uses the serial number reported by sysfs. This is the second choice for
non-virtual devices.
.IP \[bu] 2
.B mpath_uuid
is used for dm multipath devices, reported by sysfs.
.IP \[bu] 2
.B crypt_uuid
is used for dm crypt devices, reported by sysfs.
.IP \[bu] 2
.B md_uuid
is used for md devices, reported by sysfs.
.B lvmlv_uuid
is used if a PV is placed on top of an lvm LV, reported by sysfs.
.IP \[bu] 2
.B loop_file
is used for loop devices, the backing file name repored by sysfs.
.IP \[bu] 2
.B devname
the device name is used if no other type applies.
.P
The default choice for device ID type can be overriden using lvmdevices
--addev --deviceidtype <type>. If the specified type is available for the
device it will be used, otherwise the device will be added using the type
that would otherwise be chosen.
.
.SH USAGE
.
@@ -169,6 +211,8 @@ Add a device to the devices file.
.br
.RS 4
.ad l
[ \fB--deviceidtype\fP \fIString\fP ]
.br
[ COMMON_OPTIONS ]
.ad b
.RE
@@ -214,13 +258,6 @@ Remove the devices file entry for the given PVID.
.P
\(em
.P
Common options for command:
.
.RS 4
.ad l
.ad b
.RE
.P
Common options for lvm:
.
.RS 4
@@ -308,6 +345,13 @@ Remove a device from the devices file.
Remove a device with the PVID from the devices file.
.
.HP
\fB--deviceidtype\fP \fIString\fP
.br
The type of device ID to use for the device.
If the specified type is available for the device,
then it will override the default type that lvm would use.
.
.HP
\fB--devices\fP \fIPV\fP
.br
Devices that the command can use. This option can be repeated

View File

@@ -172,6 +172,22 @@ global {
}
.fi
.
.TP
.B appmachineid
.br
An LVM-specific derivation of /etc/machine-id is used as the system ID.
See
.BR machine-id (5)
to check if machine-id is available on the host.
.I lvm.conf
.nf
global {
system_id_source = "appmachineid"
}
.fi
.TP
.B machineid
.br
@@ -181,6 +197,7 @@ See
and
.BR systemd-machine-id-setup (1)
to check if machine-id is available on the host.
(appmachineid is recommended in place of machineid.)
.sp
.I lvm.conf
.nf

92
man/vdoimport.8_main Normal file
View File

@@ -0,0 +1,92 @@
.TH "FSADM" "8" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\""
.
.SH "NAME"
.
vdoimport \(em utility to import VDO volumes into a new volume group.
.
.SH SYNOPSIS
.
.PD 0
.ad l
.TP 10
.B vdoimport
.RI [ options ]
.IR device
.
.PD
.
.SH DESCRIPTION
.
vdoimport utility imports VDO volumes created and managed by
.BR vdo (8)
manager into
.BR lvm2 (8)
managed VDO LV. This is realized by moving VDO superblock by 2MiB
and creating lvm2 metadata at the front of this device. The operation is not reversible,
thus after conversion to lvm2 the access to VDO data is only possible with
.BR lvm2 (8)
commands,
.BR vdo (8)
manager no longer control such volume.
.
.SH OPTIONS
.
.TP
.BR -f | --force
Bypass some sanity checks.
.
.TP
.BR -h | --help
Display the help text.
.
.TP
.BR -n | --name
Specifies the name of converted VDO LV. When the name is not specified,
some automatic name is selected. In case the converted VDO volume is
already using LV a backend device, the name of this LV is used for VDO LV.
In this case also the of volume group must stay same.
.
.TP
.BR -v | --verbose
Be more verbose.
.
.TP
.BR -y | --yes
Answer "yes" at any prompts.
.
.TP
.BR --dry-run
Print commands without running them.
.
.
.SH DIAGNOSTICS
.
On successful completion, the status code is 0.
A status code of 1 is used for failure.
.
.SH EXAMPLES
.
Convert VDO volume created by vdo manager into logical volume LV1 with within volume group VG1.
.P
#
.B vdoimport --name VG1/LV1 /dev/mapper/vdo-volume
.
.SH ENVIRONMENT VARIABLES
.
.TP
.B TMPDIR
The temporary directory name for mount points. Defaults to "\fI/tmp\fP".
.TP
.B DM_DEV_DIR
The device directory name.
Defaults to "\fI/dev\fP" and must be an absolute path.
.
.SH SEE ALSO
.
.nh
.ad l
.BR lvm (8),
.BR lvm.conf (5),
.P
.BR vdo (8),
.BR vdo2lvm (8),

View File

@@ -393,13 +393,6 @@ Change the lock type for a shared VG.
.P
\(em
.P
Common options for command:
.
.RS 4
.ad l
.ad b
.RE
.P
Common options for lvm:
.
.RS 4

View File

@@ -46,13 +46,6 @@ Rewrite VG metadata to correct problems.
.ad b
.RE
.P
Common options for command:
.
.RS 4
.ad l
.ad b
.RE
.P
Common options for lvm:
.
.RS 4

View File

@@ -31,6 +31,10 @@ ifeq ("@FSADM@", "yes")
LVM_SCRIPTS += fsadm.sh
endif
ifeq ("@VDOIMPORT@", "yes")
LVM_SCRIPTS += vdoimport.sh
endif
ifeq ("@BLKDEACTIVATE@", "yes")
DM_SCRIPTS += blkdeactivate.sh
endif
@@ -88,7 +92,6 @@ install_systemd_generators:
install_systemd_units: install_dbus_service
@echo " [INSTALL] systemd_units"
$(Q) $(INSTALL_DIR) $(systemd_unit_dir)
$(Q) $(INSTALL_DATA) lvm2-pvscan.service $(systemd_unit_dir)/lvm2-pvscan@.service
ifeq ("@BUILD_DMEVENTD@", "yes")
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.socket $(systemd_unit_dir)/dm-event.socket
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.service $(systemd_unit_dir)/dm-event.service

376
scripts/vdoimport.sh Executable file
View File

@@ -0,0 +1,376 @@
#!/bin/bash
#
# Copyright (C) 2021 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 General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Author: Zdenek Kabelac <zkabelac at redhat.com>
#
# Script for converting VDO volumes to lvm2 VDO LVs
#
# Needed utilities:
# lvm, dmsetup,
# vdo, vdo2lvm,
# grep, awk, sed, blockdev, readlink, mkdir
#
# Conversion is using 'vdo convert' support from VDO manager to move
# existing VDO header by 2M which makes space to place in PV header
# and VG metadata area, and then create VDOPOOL LV and VDO LV in such VG.
#
set -euE -o pipefail
TOOL=vdoimport
_SAVEPATH=$PATH
PATH="/sbin:/usr/sbin:/bin:/usr/sbin:$PATH"
# user may override lvm location by setting LVM_BINARY
LVM=${LVM_BINARY:-lvm}
VDO=${VDO_BINARY:-vdo}
VDOCONF=${VDOCONF:-}
BLOCKDEV="blockdev"
READLINK="readlink"
READLINK_E="-e"
MKDIR="mkdir"
TEMPDIR="${TMPDIR:-/tmp}/${TOOL}_${RANDOM}$$"
DM_DEV_DIR="${DM_DEV_DIR:-/dev}"
DRY=0
VERB=""
FORCE=""
YES=""
# default name for converted VG and its VDO LV
NAME="vdovg/vdolvol"
# help message
tool_usage() {
echo "${TOOL}: Utility to convert VDO volume to VDO LV."
echo
echo " ${TOOL} [options] <vdo_device_path>"
echo
echo " Options:"
echo " -f | --force Bypass sanity checks"
echo " -h | --help Show this help message"
echo " -n | --name Specifies VG/LV name for converted VDO volume"
echo " -v | --verbose Be verbose"
echo " -y | --yes Answer \"yes\" at any prompts"
echo " --dry-run Print commands without running them"
exit
}
verbose() {
test -z "$VERB" || echo "$TOOL:" "$@"
}
# Support multi-line error messages
error() {
for i in "$@" ; do
echo "$TOOL: $i" >&2
done
cleanup 1
}
dry() {
if [ "$DRY" -ne 0 ]; then
verbose "Dry execution" "$@"
return 0
fi
verbose "Executing" "$@"
"$@"
}
cleanup() {
trap '' 2
rm -rf "$TEMPDIR"
# error exit status for break
exit "${1:-1}"
}
get_enabled_value_() {
case "$1" in
enabled) echo "1" ;;
*) echo "0" ;;
esac
}
get_kb_size_with_unit_() {
case "$1" in
*[kK]) echo $(( ${1%[kK]} )) ;;
*[mM]) echo $(( ${1%[mM]} * 1024 )) ;;
*[gG]) echo $(( ${1%[gG]} * 1024 * 1024 )) ;;
*[tT]) echo $(( ${1%[tT]} * 1024 * 1024 * 1024 )) ;;
*[pP]) echo $(( ${1%[pP]} * 1024 * 1024 * 1024 * 1024 )) ;;
esac
}
get_mb_size_with_unit_() {
case "$1" in
*[mM]) echo $(( ${1%[mM]} )) ;;
*[gG]) echo $(( ${1%[gG]} * 1024 )) ;;
*[tT]) echo $(( ${1%[tT]} * 1024 * 1024 )) ;;
*[pP]) echo $(( ${1%[pP]} * 1024 * 1024 * 1024 )) ;;
esac
}
# Figure out largest possible extent size usable for VG
# $1 physical size
# $2 logical size
get_largest_extent_size_() {
local max=4
local i
local d
for i in 8 16 32 64 128 256 512 1024 2048 4096 ; do
d=$(( $1 / i ))
test $(( d * i )) -eq "$1" || break
d=$(( $2 / i ))
test $(( d * i )) -eq "$2" || break
max=$i
done
echo "$max"
}
# detect LV on the given device
# dereference device name if it is symbolic link
detect_lv_() {
local DEVICE=$1
local MAJOR
local MINOR
local SYSVOLUME
local MAJORMINOR
DEVICE=${1/#"${DM_DEV_DIR}/"/}
DEVICE=$("$READLINK" $READLINK_E "$DM_DEV_DIR/$DEVICE")
test -n "$DEVICE" || error "Cannot get readlink \"$1\"."
RDEVICE=$DEVICE
case "$RDEVICE" in
# hardcoded /dev since udev does not create these entries elsewhere
/dev/dm-[0-9]*)
read -r <"/sys/block/${RDEVICE#/dev/}/dm/name" SYSVOLUME 2>&1 && DEVICE="$DM_DEV_DIR/mapper/$SYSVOLUME"
read -r <"/sys/block/${RDEVICE#/dev/}/dev" MAJORMINOR 2>&1 || error "Cannot get major:minor for \"$DEVICE\"."
MAJOR=${MAJORMINOR%%:*}
MINOR=${MAJORMINOR##*:}
;;
*)
STAT=$(stat --format "MAJOR=\$((0x%t)) MINOR=\$((0x%T))" "$RDEVICE")
test -n "$STAT" || error "Cannot get major:minor for \"$DEVICE\"."
eval "$STAT"
;;
esac
eval "$(dmsetup info -c -j "$MAJOR" -m "$MINOR" -o uuid,name --noheadings --nameprefixes --separator ' ')"
}
# parse yaml config files into 'prefix_yaml_part_names=("value")' strings
parse_yaml_() {
local yaml_file=$1
local prefix=$2
local s
local w
local fs
s='[[:space:]]*'
w='[a-zA-Z0-9_.-]*'
fs="$(echo @|tr @ '\034')"
(
sed -ne '/^--/s|--||g; s|\"|\\\"|g; s/[[:space:]]*$//g;' \
-e 's/\$/\\\$/g' \
-e "/#.*[\"\']/!s| #.*||g; /^#/s|#.*||g;" \
-e "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
-e "s|^\($s\)\($w\)${s}[:-]$s\(.*\)$s\$|\1$fs\2$fs\3|p" |
awk -F"$fs" '{
indent = length($1)/2;
if (length($2) == 0) { conj[indent]="+";} else {conj[indent]="";}
vname[indent] = $2;
for (i in vname) {if (i > indent) {delete vname[i]}}
if (length($3) > 0) {
vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
printf("%s%s%s%s=(\"%s\")\n", "'"$prefix"'",vn, $2, conj[indent-1], $3);
}
}' |
sed -e 's/_=/+=/g' |
awk 'BEGIN {
FS="=";
OFS="="
}
/(-|\.).*=/ {
gsub("-|\\.", "_", $1)
}
{ print }'
) < "$yaml_file"
}
# convert existing VDO volume into lvm2 volume
convert2lvm_() {
local DEVICE=$1
local VGNAME=${NAME%/*}
local LVNAME=${NAME#*/}
local VDONAME
local TRVDONAME
local EXTENTSZ
local IS_LV=1
DM_UUID=""
detect_lv_ "$DEVICE"
case "$DM_UUID" in
LVM-*) eval "$(dmsetup splitname --nameprefixes --noheadings --separator ' ' "$DM_NAME")"
if [ -z "$VGNAME" ] || [ "$VGNAME" = "$LVNAME" ] ; then
VGNAME=$DM_VG_NAME
elif test "$VGNAME" != "$DM_VG_NAME" ; then
error "Volume group name \"$VGNAME\" does not match name \"$DM_VG_NAME\" for device \"$DEVICE\"."
fi
;;
*) IS_LV=0
# Check $VGNANE does not already exists
"$LVM" vgs "$VGNAME" && error "Cannot use already existing volume group name \"$VGNAME\"."
;;
esac
verbose "Checked whether device $1 is already LV ($IS_LV)."
"$MKDIR" -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR."
verbose "Getting YAML VDO configuration."
"$VDO" printConfigFile $VDOCONF >"$TEMPDIR/vdoconf.yml"
VDONAME=$(awk -v DNAME="$DEVICE" '/.*VDOService$/ {VNAME=substr($1, 0, length($1) - 1)} /[[:space:]]*device:/ { if ($2 ~ DNAME) {print VNAME}}' "$TEMPDIR/vdoconf.yml")
TRVDONAME=$(echo "$VDONAME" | tr '-' '_')
# When VDO volume is 'active', check it's not mounted/being used
eval "$(dmsetup info -c -o open "$VDONAME" --noheadings --nameprefixes || true)"
test "${DM_OPEN:-0}" -eq 0 || error "Cannot converted VDO volume \"$VDONAME\" which is in use!"
#parse_yaml_ "$TEMPDIR/vdoconf.yml" _
eval "$(parse_yaml_ "$TEMPDIR/vdoconf.yml" _ | grep "$TRVDONAME" | sed -e "s/_config_vdos_$TRVDONAME/vdo/g")"
vdo_logicalSize=$(get_kb_size_with_unit_ "$vdo_logicalSize")
vdo_physicalSize=$(get_kb_size_with_unit_ "$vdo_physicalSize")
verbose "Going to convert physical sized VDO device $vdo_physicalSize KiB."
verbose "With logical volume of size $vdo_logicalSize KiB."
PARAMS=$(cat <<EOF
allocation {
vdo_use_compression = $(get_enabled_value_ "$vdo_compression")
vdo_use_deduplication = $(get_enabled_value_ "$vdo_deduplication")
vdo_use_metadata_hints=1
vdo_minimum_io_size = $vdo_logicalBlockSize
vdo_block_map_cache_size_mb = $(get_mb_size_with_unit_ "$vdo_blockMapCacheSize")
vdo_block_map_period = $vdo_blockMapPeriod
vdo_check_point_frequency = $vdo_indexCfreq
vdo_use_sparse_index = $(get_enabled_value_ "$vdo_indexSparse")
vdo_index_memory_size_mb = $(awk "BEGIN {print $vdo_indexMemory * 1024}")
vdo_slab_size_mb = $(get_mb_size_with_unit_ "$vdo_blockMapCacheSize")
vdo_ack_threads = $vdo_ackThreads
vdo_bio_threads = $vdo_bioThreads
vdo_bio_rotation = $vdo_bioRotationInterval
vdo_cpu_threads = $vdo_cpuThreads
vdo_hash_zone_threads = $vdo_hashZoneThreads
vdo_logical_threads = $vdo_logicalThreads
vdo_physical_threads = $vdo_physicalThreads
vdo_write_policy = $vdo_writePolicy
vdo_max_discard = $(( $(get_kb_size_with_unit_ "$vdo_maxDiscardSize") * 1024 ))
vdo_pool_header_size = 0
}
EOF
)
verbose "VDO conversion paramaters: $PARAMS"
verbose "Stopping VDO volume."
dry "$VDO" stop $VDOCONF --name "$VDONAME"
if [ "$IS_LV" = "0" ]; then
verbose "Moving VDO header by 2MiB."
dry "$VDO" convert $VDOCONF --force --name "$VDONAME"
dry "$LVM" pvcreate $YES --dataalignment 2M "$DEVICE" || {
error "Creation of PV on \"$DEVICE\" failed, while VDO header has been already moved!"
}
# Obtain free space in this new PV
# after 'vdo convert/vdo2lvm' call there is +2M free space at the front of the device
case "$DRY" in
0) pvfree=$("$LVM" pvs -o devsize --units b --nosuffix --noheadings "$DEVICE") ;;
*) pvfree=$("$BLOCKDEV" --getsize64 "$DEVICE") ;;
esac
pvfree=$(( pvfree / 1024 - 2048 )) # to KiB
else
pvfree=$("$LVM" lvs -o size --units b --nosuffix --noheadings "$VGNAME/$LVNAME")
pvfree=$(( pvfree / 1024 )) # to KiB
fi
# select largest possible extent size that can exactly express both sizes
EXTENTSZ=$(get_largest_extent_size_ "$pvfree" "$vdo_logicalSize")
if [ "$IS_LV" = "0" ]; then
verbose "Creating VG \"${NAME%/*}\" with extent size $EXTENTSZ KiB."
dry "$LVM" vgcreate $YES $VERB -s "${EXTENTSZ}k" "$VGNAME" "$DEVICE" || {
error "Creation of VG \"$VGNAME\" failed, while VDO header has been already moved!"
}
verbose "Creating VDO pool data LV from all extents in volume group $VGNAME."
dry "$LVM" lvcreate -Zn -Wn $YES $VERB -l100%VG -n "${LVNAME}_vpool" "$VGNAME"
else
# validate existing VG extent_size can express virtual VDO size
vg_extent_size=$("$LVM" vgs -o vg_extent_size --units b --nosuffix --noheadings "$VGNAME" || true)
vg_extent_size=$(( vg_extent_size / 1024 ))
test "$vg_extent_size" -le "$EXTENTSZ" || {
error "Please vgchange extent_size to at most $EXTENTSZ KiB or extend and align virtual size on $vg_extent_size KiB."
}
verbose "Renaming existing LV to be used as _vdata volume for VDO pool LV."
dry "$LVM" lvrename $YES $VERB "$VGNAME/$LVNAME" "$VGNAME/${LVNAME}_vpool" || {
error "Rename of LV \"$VGNAME/$LVNAME\" failed, while VDO header has been already moved!"
}
fi
verbose "Converting to VDO pool."
dry "$LVM" lvconvert $YES $VERB $FORCE --config "$PARAMS" -Zn -V "${vdo_logicalSize}k" -n "$LVNAME" --type vdo-pool "$VGNAME/${LVNAME}_vpool"
rm -fr "$TEMPDIR"
}
#############################
# start point of this script
# - parsing parameters
#############################
trap "cleanup 2" 2
test "$#" -eq 0 && tool_usage
while [ "$#" -ne 0 ]
do
case "$1" in
"") ;;
"-f"|"--force" ) FORCE="-f" ;;
"-h"|"--help" ) tool_usage ;;
"-n"|"--name" ) shift; NAME=$1 ;;
"-v"|"--verbose") VERB="-v" ;;
"-y"|"--yes" ) YES="-y" ;;
"--dry-run" ) DRY="1" ;;
"-*") error "Wrong argument \"$1\". (see: $TOOL --help)" ;;
*) DEVICENAME=$1 ;; # device name does not start with '-'
esac
shift
done
# do conversion
convert2lvm_ "$DEVICENAME"

View File

@@ -70,6 +70,7 @@ fi
%{_sbindir}/vgdisplay
%{_sbindir}/vgexport
%{_sbindir}/vgextend
%{_sbindir}/vdoimport
%{_sbindir}/vgimport
%{_sbindir}/vgimportclone
%{_sbindir}/vgimportdevices
@@ -157,7 +158,7 @@ fi
%endif
%if %{enable_udev}
%{_udevdir}/11-dm-lvm.rules
%{_udevdir}/69-dm-lvm-metad.rules
%{_udevdir}/69-dm-lvm.rules
%endif
%dir %{_sysconfdir}/lvm
%ghost %{_sysconfdir}/lvm/cache/.cache
@@ -183,7 +184,6 @@ fi
%{_tmpfilesdir}/%{name}.conf
%{_unitdir}/blk-availability.service
%{_unitdir}/lvm2-monitor.service
%{_unitdir}/lvm2-pvscan@.service
%attr(555, -, -) %{_prefix}/lib/systemd/system-generators/lvm2-activation-generator
%if %{have_service lvmpolld}
%{_unitdir}/lvm2-lvmpolld.service

View File

@@ -171,7 +171,7 @@ check_lvmlockd_dlm: .tests-stamp
endif
ifeq ("@BUILD_LVMLOCKD@", "yes")
check_lvmlockd_idm: .tests-stamp
check_lvmlockd_idm: .tests-stamp lib/idm_inject_failure
$(INSTALL_PROGRAM) lib/idm_inject_failure $(EXECDIR)
VERBOSE=$(VERBOSE) ./lib/runner \
--testdir . --outdir $(LVM_TEST_RESULTS) \
@@ -368,6 +368,7 @@ LIB = $(addprefix lib/, $(LIB_SECURETEST) $(LIB_DMSECURETEST) $(LIB_SHARED) $(LI
$(Q) $(LN_S) -f $(abs_top_srcdir)/conf/lvmdbusd.profile lib/
$(Q) $(LN_S) -f $(abs_top_srcdir)/conf/thin-performance.profile lib/
$(Q) $(LN_S) -f $(abs_top_srcdir)/scripts/fsadm.sh lib/fsadm
$(Q) $(LN_S) -f $(abs_top_srcdir)/scripts/vdoimport.sh lib/vdoimport
@test "$(srcdir)" = . || \
for i in $(LIB_LVMLOCKD_CONF) $(LIB_MKE2FS_CONF); do \
test -n "$(Q)" || echo "$(LN_S) -f $(abs_top_srcdir)/test/lib/$$i lib/"; \

View File

@@ -67,4 +67,26 @@ fail lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv
# Thin-pool CAN use cached data LV
lvconvert --yes --thinpool $vg/$lv
lvremove -f $vg
# Check we can active snapshot of cached external origin (BZ: 1967744)
lvcreate -T -L10M $vg/pool "$dev1"
lvcreate -L10M -n origin $vg "$dev1"
lvcreate -H -L4M -n CPOOL $vg/origin "$dev2"
# Use cached origin as external origin
lvconvert -y -T --thinpool $vg/pool --originname extorig origin
# Check we can easily create snapshot of such LV
lvcreate -y -kn -n snap -s $vg/origin
# Deactivate everything and do a component activation of _cmeta volume
lvchange -an $vg
lvchange -ay -y $vg/CPOOL_cpool_cmeta
# Now this must fail since component volume is active
not lvcreate -y -kn -n snap2 -s $vg/origin |& tee err
grep "cmeta is active" err
vgremove -f $vg

View File

@@ -118,6 +118,14 @@ mkdir -p "$mount_dir"
aux prepare_devs 6 70 # want 64M of usable space from each dev
# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
vgcreate $vg "$dev1"
lvcreate -n $lv1 -L50 $vg
mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
blkid -c /dev/null "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
lvchange -an $vg
vgremove -ff $vg
# generate random data
dd if=/dev/urandom of=pattern bs=512K count=1

View File

@@ -15,13 +15,15 @@ SKIP_WITH_LVMPOLLD=1
. lib/inittest
[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip;
aux prepare_devs 6
get_devs
pvcreate -M2 "${DEVICES[@]}"
vgcreate --shared -M2 "$vg1" "$dev1" "$dev2" "$dev3"
vgcreate --shared -M2 "$vg2" "$dev4" "$dev5" "$dev6"
vgcreate $SHARED -M2 "$vg1" "$dev1" "$dev2" "$dev3"
vgcreate $SHARED -M2 "$vg2" "$dev4" "$dev5" "$dev6"
test_vg_thread1()
{

View File

@@ -15,6 +15,8 @@ SKIP_WITH_LVMPOLLD=1
. lib/inittest
[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip;
aux prepare_devs 8
get_devs
@@ -24,14 +26,14 @@ test_vg_thread1()
{
for i in {1..1000}
do
vgcreate --shared -M2 "$vg1" "$dev1" "$dev2" "$dev3"
vgcreate $SHARED -M2 "$vg1" "$dev1" "$dev2" "$dev3"
vgremove -ff $vg1
done
}
test_vg_thread2()
{
vgcreate --shared -M2 "$vg2" "$dev4" "$dev5" "$dev6"
vgcreate $SHARED -M2 "$vg2" "$dev4" "$dev5" "$dev6"
for i in {1..1000}
do

View File

@@ -15,6 +15,8 @@ SKIP_WITH_LVMPOLLD=1
. lib/inittest
[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip;
aux prepare_vg 3
for i in {1..1000}

View File

@@ -50,6 +50,17 @@ check vg_field $vg1 systemid "$SID"
vgremove $vg1
fi
## appmachineid
lvm version > lvmver
if grep app-machineid lvmver; then
aux lvmconf "global/system_id_source = appmachineid"
lvm systemid | awk '{ print $3 }' > sid_lvm
vgcreate $vg1 "$dev1"
vgs -o systemid --noheadings $vg1 | awk '{print $1}' > sid_vg
diff sid_lvm sid_vg
vgremove $vg1
fi
## uname
SID1=$(uname -n)

View File

@@ -0,0 +1,403 @@
#!/usr/bin/env bash
# Copyright (C) 2021 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
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description='udev rule and systemd unit run vgchange'
SKIP_WITH_LVMPOLLD=1
SKIP_WITH_LVMLOCKD=1
. lib/inittest
#
# $ cat /tmp/devs
# /dev/sdb
# /dev/sdc
# /dev/sdd
#
# Specify this file as LVM_TEST_DEVICE_LIST=/tmp/devs
# when running the test.
#
# This test will wipe these devices.
#
if [ -z ${LVM_TEST_DEVICE_LIST+x} ]; then echo "LVM_TEST_DEVICE_LIST is unset" && skip; else echo "LVM_TEST_DEVICE_LIST is set to '$LVM_TEST_DEVICE_LIST'"; fi
test -e "$LVM_TEST_DEVICE_LIST" || skip
num_devs=$(cat $LVM_TEST_DEVICE_LIST | wc -l)
RUNDIR="/run"
test -d "$RUNDIR" || RUNDIR="/var/run"
PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
_clear_online_files() {
# wait till udev is finished
aux udev_wait
rm -f "$PVS_ONLINE_DIR"/*
rm -f "$VGS_ONLINE_DIR"/*
rm -f "$PVS_LOOKUP_DIR"/*
}
test -d "$PVS_ONLINE_DIR" || mkdir -p "$PVS_ONLINE_DIR"
test -d "$VGS_ONLINE_DIR" || mkdir -p "$VGS_ONLINE_DIR"
test -d "$PVS_LOOKUP_DIR" || mkdir -p "$PVS_LOOKUP_DIR"
_clear_online_files
aux prepare_real_devs
aux lvmconf 'devices/dir = "/dev"'
aux lvmconf 'devices/use_devicesfile = 1'
DFDIR="$LVM_SYSTEM_DIR/devices"
DF="$DFDIR/system.devices"
mkdir $DFDIR || true
not ls $DF
get_real_devs
wipe_all() {
for dev in "${REAL_DEVICES[@]}"; do
wipefs -a $dev
done
}
# udevadm trigger runs udev rule which runs systemd-run --no-wait vgchange -aay
# Because of --no-wait, we need to wait for the transient systemd
# service to be gone before checking the effects of the vgchange.
wait_lvm_activate() {
local vgw=$1
local wait=0
while systemctl status lvm-activate-$vgw > /dev/null && test "$wait" -le 30; do
sleep .2
wait=$(( wait + 1 ))
done
}
# Test requires 3 devs
test $num_devs -gt 2 || skip
BDEV1=$(basename "$dev1")
BDEV2=$(basename "$dev2")
BDEV3=$(basename "$dev3")
wipe_all
touch $DF
for dev in "${REAL_DEVICES[@]}"; do
pvcreate $dev
done
# 1 dev, 1 vg, 1 lv
vgcreate $vg1 "$dev1"
lvcreate -l1 -an -n $lv1 $vg1 "$dev1"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger --settle -c add /sys/block/$BDEV1
wait_lvm_activate $vg1
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/vgs_online/$vg1"
journalctl -u lvm-activate-$vg1 | tee out || true
grep "now active" out
check lv_field $vg1/$lv1 lv_active "active"
vgchange -an $vg1
vgremove -y $vg1
# 2 devs, 1 vg, 2 lvs
vgcreate $vg2 "$dev1" "$dev2"
lvcreate -l1 -an -n $lv1 $vg2 "$dev1"
lvcreate -l1 -an -n $lv2 $vg2 "$dev2"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger --settle -c add /sys/block/$BDEV1
ls "$RUNDIR/lvm/pvs_online/$PVID1"
not ls "$RUNDIR/lvm/vgs_online/$vg2"
journalctl -u lvm-activate-$vg2 | tee out || true
not grep "now active" out
check lv_field $vg2/$lv1 lv_active ""
check lv_field $vg2/$lv2 lv_active ""
udevadm trigger --settle -c add /sys/block/$BDEV2
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/vgs_online/$vg2"
wait_lvm_activate $vg2
journalctl -u lvm-activate-$vg2 | tee out || true
grep "now active" out
check lv_field $vg2/$lv1 lv_active "active"
check lv_field $vg2/$lv2 lv_active "active"
vgchange -an $vg2
vgremove -y $vg2
# 3 devs, 1 vg, 4 lvs, concurrent pvscans
# (attempting to have the pvscans run concurrently and race
# to activate the VG)
vgcreate $vg3 "$dev1" "$dev2" "$dev3"
lvcreate -l1 -an -n $lv1 $vg3 "$dev1"
lvcreate -l1 -an -n $lv2 $vg3 "$dev2"
lvcreate -l1 -an -n $lv3 $vg3 "$dev3"
lvcreate -l8 -an -n $lv4 -i 2 $vg3 "$dev1" "$dev2"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg3
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/pvs_online/$PVID3"
ls "$RUNDIR/lvm/vgs_online/$vg3"
journalctl -u lvm-activate-$vg3 | tee out || true
grep "now active" out
check lv_field $vg3/$lv1 lv_active "active"
check lv_field $vg3/$lv2 lv_active "active"
check lv_field $vg3/$lv3 lv_active "active"
check lv_field $vg3/$lv4 lv_active "active"
vgchange -an $vg3
vgremove -y $vg3
# 3 devs, 1 vg, 4 lvs, concurrent pvscans, metadata on only 1 PV
wipe_all
rm $DF
touch $DF
pvcreate --metadatacopies 0 "$dev1"
pvcreate --metadatacopies 0 "$dev2"
pvcreate "$dev3"
vgcreate $vg4 "$dev1" "$dev2" "$dev3"
lvcreate -l1 -an -n $lv1 $vg4 "$dev1"
lvcreate -l1 -an -n $lv2 $vg4 "$dev2"
lvcreate -l1 -an -n $lv3 $vg4 "$dev3"
lvcreate -l8 -an -n $lv4 -i 2 $vg4 "$dev1" "$dev2"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg4
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/pvs_online/$PVID3"
ls "$RUNDIR/lvm/vgs_online/$vg4"
journalctl -u lvm-activate-$vg4 | tee out || true
grep "now active" out
check lv_field $vg4/$lv1 lv_active "active"
check lv_field $vg4/$lv2 lv_active "active"
check lv_field $vg4/$lv3 lv_active "active"
check lv_field $vg4/$lv4 lv_active "active"
vgchange -an $vg4
vgremove -y $vg4
# 3 devs, 3 vgs, 2 lvs in each vg, concurrent pvscans
wipe_all
rm $DF
touch $DF
vgcreate $vg5 "$dev1"
vgcreate $vg6 "$dev2"
vgcreate $vg7 "$dev3"
lvcreate -l1 -an -n $lv1 $vg5
lvcreate -l1 -an -n $lv2 $vg5
lvcreate -l1 -an -n $lv1 $vg6
lvcreate -l1 -an -n $lv2 $vg6
lvcreate -l1 -an -n $lv1 $vg7
lvcreate -l1 -an -n $lv2 $vg7
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg5
wait_lvm_activate $vg6
wait_lvm_activate $vg7
ls "$RUNDIR/lvm/vgs_online/$vg5"
ls "$RUNDIR/lvm/vgs_online/$vg6"
ls "$RUNDIR/lvm/vgs_online/$vg7"
journalctl -u lvm-activate-$vg5 | tee out || true
grep "now active" out
journalctl -u lvm-activate-$vg6 | tee out || true
grep "now active" out
journalctl -u lvm-activate-$vg7 | tee out || true
grep "now active" out
check lv_field $vg5/$lv1 lv_active "active"
check lv_field $vg5/$lv2 lv_active "active"
check lv_field $vg6/$lv1 lv_active "active"
check lv_field $vg6/$lv2 lv_active "active"
check lv_field $vg7/$lv1 lv_active "active"
check lv_field $vg7/$lv2 lv_active "active"
vgchange -an $vg5
vgremove -y $vg5
vgchange -an $vg6
vgremove -y $vg6
vgchange -an $vg7
vgremove -y $vg7
# 3 devs, 1 vg, 1000 LVs
wipe_all
rm $DF
touch $DF
pvcreate --metadatacopies 0 "$dev1"
pvcreate "$dev2"
pvcreate "$dev3"
vgcreate -s 128K $vg8 "$dev1" "$dev2" "$dev3"
# Number of LVs to create
TEST_DEVS=1000
# On low-memory boxes let's not stress too much
test "$(aux total_mem)" -gt 524288 || TEST_DEVS=256
vgcfgbackup -f data $vg8
# Generate a lot of devices (size of 1 extent)
awk -v TEST_DEVS=$TEST_DEVS '/^\t\}/ {
printf("\t}\n\tlogical_volumes {\n");
cnt=0;
for (i = 0; i < TEST_DEVS; i++) {
printf("\t\tlvol%06d {\n", i);
printf("\t\t\tid = \"%06d-1111-2222-3333-2222-1111-%06d\"\n", i, i);
print "\t\t\tstatus = [\"READ\", \"WRITE\", \"VISIBLE\"]";
print "\t\t\tsegment_count = 1";
print "\t\t\tsegment1 {";
print "\t\t\t\tstart_extent = 0";
print "\t\t\t\textent_count = 1";
print "\t\t\t\ttype = \"striped\"";
print "\t\t\t\tstripe_count = 1";
print "\t\t\t\tstripes = [";
print "\t\t\t\t\t\"pv0\", " cnt++;
printf("\t\t\t\t]\n\t\t\t}\n\t\t}\n");
}
}
{print}
' data >data_new
vgcfgrestore -f data_new $vg8
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg8
ls "$RUNDIR/lvm/vgs_online/$vg8"
journalctl -u lvm-activate-$vg8 | tee out || true
grep "now active" out
num_active=$(lvs $vg8 --noheading -o active | grep active | wc -l)
test $num_active -eq $TEST_DEVS
vgchange -an $vg8
vgremove -y $vg8
# 1 pv on an md dev, 1 vg
wait_md_create() {
local md=$1
while :; do
if ! grep "$(basename $md)" /proc/mdstat; then
echo "$md not ready"
cat /proc/mdstat
sleep 2
else
break
fi
done
echo "$md" > WAIT_MD_DEV
}
test -f /proc/mdstat && grep -q raid1 /proc/mdstat || \
modprobe raid1 || skip
mddev="/dev/md33"
not grep $mddev /proc/mdstat || skip
wipe_all
rm $DF
touch $DF
mdadm --create --metadata=1.0 "$mddev" --level 1 --chunk=64 --raid-devices=2 "$dev1" "$dev2"
wait_md_create "$mddev"
vgcreate $vg9 "$mddev"
PVIDMD=`pvs $mddev --noheading -o uuid | tr -d - | awk '{print $1}'`
BDEVMD=$(basename "$mddev")
lvcreate -l1 -an -n $lv1 $vg9
lvcreate -l1 -an -n $lv2 $vg9
_clear_online_files
udevadm trigger --settle -c add /sys/block/$BDEVMD
wait_lvm_activate $vg9
ls "$RUNDIR/lvm/vgs_online/$vg9"
journalctl -u lvm-activate-$vg9 | tee out || true
grep "now active" out
check lv_field $vg9/$lv1 lv_active "active"
check lv_field $vg9/$lv2 lv_active "active"
vgchange -an $vg9
vgremove -y $vg9
mdadm --stop "$mddev"
aux udev_wait
wipe_all

110
test/shell/vdo-convert.sh Normal file
View File

@@ -0,0 +1,110 @@
#!/usr/bin/env bash
# Copyright (C) 2021 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
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Test conversion of VDO volumes made by vdo manager into VDO LV.
SKIP_WITH_LVMPOLLD=1
. lib/inittest
# Use local for this test vdo configuratoin
VDOCONF="-f vdotestconf.yml"
#VDOCONF=""
export VDOCONF
VDONAME="${PREFIX}-TESTVDO"
# VDO automatically starts dmeventd
aux prepare_dmeventd
#
# Main
#
which vdo || skip
which mkfs.ext4 || skip
export MKE2FS_CONFIG="$TESTDIR/lib/mke2fs.conf"
aux have_vdo 6 2 0 || skip
aux prepare_devs 2 10000
aux extend_filter_LVMTEST
#
# Check conversion of VDO volume made on some LV
#
# In this case we do not need to move any VDO headers.
#
vgcreate $vg "$dev1"
lvcreate -L5G -n $lv1 $vg
vdo create $VDOCONF --name "$VDONAME" --device="$DM_DEV_DIR/$vg/$lv1" --vdoLogicalSize=10G
mkfs -E nodiscard "$DM_DEV_DIR/mapper/$VDONAME"
# Different VG name fails
not vdoimport -y -v --name $vg1/$lv1 "$DM_DEV_DIR/$vg/$lv1"
# Try just dry run and observe logging
vdoimport --dry-run -y -v --name $lv1 "$DM_DEV_DIR/$vg/$lv1"
vdoimport -y --name $lv1 "$DM_DEV_DIR/$vg/$lv1"
# ATM needed - since we do not call 'vdo convert' in this case
vdo remove $VDOCONF --force --name "$VDONAME" || true
vgremove -f $vg
aux wipefs_a "$dev1"
# prepare 'unused' $vg2
vgcreate $vg2 "$dev2"
#
# Check conversion of VDO volume on non-LV device
#
vdo create $VDOCONF --name "$VDONAME" --device="$dev1" --vdoLogicalSize=31G
mkfs -E nodiscard "$DM_DEV_DIR/mapper/$VDONAME"
# Fail with an already existing volume group $vg2
not vdoimport --dry-run -y -v --name $vg2/$lv1 "$dev1" |& tee err
grep "already existing volume group" err
# User can also convert already stopped VDO volume
vdo stop $VDOCONF --name "$VDONAME"
vdoimport -y -v --name $vg/$lv1 "$dev1"
fsck -n "$DM_DEV_DIR/$vg/$lv1"
vgremove -f $vg
#
# Try once again with different vgname/lvname and sizes
#
aux teardown_devs
aux prepare_devs 1 23456
vdo create $VDOCONF --name "$VDONAME" --device="$dev1" --vdoLogicalSize=23G
mkfs -E nodiscard "$DM_DEV_DIR/mapper/$VDONAME"
vdoimport -y -v --name $vg1/$lv2 "$dev1"
fsck -n "$DM_DEV_DIR/$vg1/$lv2"
vgremove -f $vg1

View File

@@ -159,6 +159,14 @@ _run_test() {
aux prepare_scsi_debug_dev 256 sector_size=512 physblk_exp=3
aux prepare_devs 2 64
# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
vgcreate $vg "$dev1"
lvcreate -n $lv1 -L50 $vg
mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
blkid -c /dev/null "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
lvchange -an $vg
vgremove -ff $vg
# loopa/loopb have LBS 512 PBS 512
which fallocate || skip
fallocate -l 64M loopa

View File

@@ -25,6 +25,14 @@ check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "512"
aux prepare_devs 2 64
# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
vgcreate $vg "$dev1"
lvcreate -n $lv1 -L50 $vg
mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
blkid -c /dev/null "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
lvchange -an $vg
vgremove -ff $vg
# scsi_debug devices with 512 LBS and 4K PBS
#aux prepare_scsi_debug_dev 256 sector_size=512 physblk_exp=3
#check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"

View File

@@ -323,12 +323,33 @@ arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0,
arg(importdevices_ARG, '\0', "importdevices", 0, 0, 0,
"Add devices to the devices file.\n")
arg(journal_ARG, '\0', "journal", string_VAL, 0, 0,
"Record information in the systemd journal.\n"
"This information is in addition to information\n"
"enabled by the lvm.conf log/journal setting.\n"
"command: record information about the command.\n"
"output: record the default command output.\n"
"debug: record full command debugging.\n")
arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0,
"By default the PV is labelled with an LVM2 identifier in its second\n"
"sector (sector 1). This lets you use a different sector near the\n"
"start of the disk (between 0 and 3 inclusive - see LABEL_SCAN_SECTORS\n"
"in the source). Use with care.\n")
arg(listlvs_ARG, '\0', "listlvs", 0, 0, 0,
"Print a list of LVs that use the device.\n")
arg(listvg_ARG, '\0', "listvg", 0, 0, 0,
"Print the VG that uses the device.\n")
arg(checkcomplete_ARG, '\0', "checkcomplete", 0, 0, 0,
"Check if all the devices used by a VG or LV are present,\n"
"and print \"complete\" or \"incomplete\" for each listed\n"
"VG or LV. This option is used as a part of event-based\n"
"autoactivation, so pvscan will do nothing if this option\n"
"is set and event_activation=0 in the config settings.\n")
arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0,
"Used to pass options for special cases to lvmlockd.\n"
"See \\fBlvmlockd\\fP(8) for more information.\n")
@@ -811,6 +832,9 @@ arg(type_ARG, '\0', "type", segtype_VAL, 0, 0,
"(e.g. --stripes, --mirrors, --snapshot, --virtualsize, --thin, --cache, --vdo).\n"
"Use inferred types with care because it can lead to unexpected results.\n")
arg(udevoutput_ARG, '\0', "udevoutput", 0, 0, 0,
"Command output is modified to be imported from a udev rule.\n")
arg(unbuffered_ARG, '\0', "unbuffered", 0, 0, 0,
"Produce output immediately without sorting or aligning the columns properly.\n")
@@ -887,6 +911,10 @@ arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", vgmetadatacopies_VAL, 0, 0,
"\\fBall\\fP causes LVM to first clear the metadataignore flags on\n"
"all PVs, and then to become unmanaged.\n")
arg(vgonline_ARG, '\0', "vgonline", 0, 0, 0,
"The first command to see a complete VG will report it uniquely.\n"
"Other commands to see the complete VG will report it differently.\n")
arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0,
"Display a one line comment for each configuration node.\n")

View File

@@ -204,7 +204,7 @@
#
OO_ALL: --commandprofile String, --config String, --debug,
--driverloaded Bool, --help, --nolocking, --lockopt String, --longhelp, --profile String, --quiet,
--verbose, --version, --yes, --test, --devicesfile String, --devices PV
--verbose, --version, --yes, --test, --devicesfile String, --devices PV, --journal String
#
# options for pvs, lvs, vgs, fullreport
@@ -1633,11 +1633,37 @@ DESC: Display PV information.
pvscan --cache_long
OO: --ignorelockingfailure, --reportformat ReportFmt,
--activate ay, --major Number, --minor Number, --noudevsync
--major Number, --minor Number, --noudevsync
OP: PV|String ...
IO: --background
ID: pvscan_cache
DESC: Autoactivate a VG when all PVs are online.
DESC: Record that a PV is online or offline.
pvscan --cache_long --activate ay
OO: --ignorelockingfailure, --reportformat ReportFmt,
--major Number, --minor Number, --noudevsync
OP: PV|String ...
IO: --background
ID: pvscan_cache
DESC: Record that a PV is online and autoactivate the VG if complete.
pvscan --cache_long --listvg PV
OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput
ID: pvscan_cache
DESC: Record that a PV is online and list the VG using the PV.
pvscan --cache_long --listlvs PV
OO: --ignorelockingfailure, --checkcomplete, --vgonline
ID: pvscan_cache
DESC: Record that a PV is online and list LVs using the PV.
pvscan --listlvs PV
ID: pvscan_cache
DESC: List LVs using the PV.
pvscan --listvg PV
ID: pvscan_cache
DESC: List the VG using the PV.
---

View File

@@ -141,7 +141,7 @@ static inline int dumptype_arg(struct cmd_context *cmd __attribute__((unused)),
#define CAN_USE_ONE_SCAN 0x00002000
#define ALLOW_HINTS 0x00004000
#define ALLOW_EXPORTED 0x00008000
#define CHECK_DEVS_USED 0x00010000
/* create foo_CMD enums for command def ID's in command-lines.in */

View File

@@ -31,7 +31,7 @@ xx(formats,
xx(fullreport,
"Display full report",
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_HINTS | ALLOW_EXPORTED)
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(help,
"Display help for commands",
@@ -55,7 +55,7 @@ xx(lvcreate,
xx(lvdisplay,
"Display information about a logical volume",
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | CHECK_DEVS_USED)
xx(lvextend,
"Add space to a logical volume",
@@ -75,7 +75,7 @@ xx(lvmdevices,
xx(lvmdiskscan,
"List devices that may be used as physical volumes",
PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ALLOW_EXPORTED)
PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(lvmsadc,
"Collect activity data",
@@ -107,11 +107,11 @@ xx(lvresize,
xx(lvs,
"Display information about logical volumes",
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | CHECK_DEVS_USED)
xx(lvscan,
"List all logical volumes in all volume groups",
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH)
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CHECK_DEVS_USED)
xx(pvchange,
"Change attributes of physical volume(s)",
@@ -131,7 +131,7 @@ xx(pvdata,
xx(pvdisplay,
"Display various attributes of physical volume(s)",
PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
/* ALL_VGS_IS_DEFAULT is for polldaemon to find pvmoves in-progress using process_each_vg. */
@@ -149,11 +149,11 @@ xx(pvresize,
xx(pvs,
"Display information about physical volumes",
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(pvscan,
"List all physical volumes",
PERMITTED_READ_ONLY | LOCKD_VG_SH | ALLOW_EXPORTED)
PERMITTED_READ_ONLY | LOCKD_VG_SH | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(segtypes,
"List available segment types",
@@ -197,7 +197,7 @@ xx(vgcreate,
xx(vgdisplay,
"Display volume group information",
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(vgexport,
"Unregister volume group(s) from the system",
@@ -241,11 +241,11 @@ xx(vgrename,
xx(vgs,
"Display information about volume groups",
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(vgscan,
"Search for all volume groups",
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_EXPORTED)
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(vgsplit,
"Move physical volumes into a new or existing volume group",

View File

@@ -4769,7 +4769,7 @@ static int _lvconvert_to_pool_or_swap_metadata_single(struct cmd_context *cmd,
switch (cmd->command->command_enum) {
case lvconvert_to_thinpool_or_swap_metadata_CMD:
if (lv_is_cache(lv))
if (lv_is_cache(lv) || lv_is_writecache(lv))
/* For cached LV check the cache origin LV type */
lvt_enum = get_lvt_enum(seg_lv(first_seg(lv), 0));
to_thinpool = 1;
@@ -5404,7 +5404,8 @@ static int _lvconvert_to_vdopool_single(struct cmd_context *cmd,
struct processing_handle *handle)
{
const char *vg_name = NULL;
unsigned int zero_vdopool;
unsigned int vdo_pool_zero;
uint64_t vdo_pool_header_size;
struct volume_group *vg = lv->vg;
struct logical_volume *vdo_lv;
struct dm_vdo_target_params vdo_params; /* vdo */
@@ -5447,7 +5448,7 @@ static int _lvconvert_to_vdopool_single(struct cmd_context *cmd,
goto out;
}
if (!fill_vdo_target_params(cmd, &vdo_params, vg->profile))
if (!fill_vdo_target_params(cmd, &vdo_params, &vdo_pool_header_size, vg->profile))
goto_out;
if (arg_is_set(cmd, compression_ARG))
@@ -5463,12 +5464,12 @@ static int _lvconvert_to_vdopool_single(struct cmd_context *cmd,
goto out;
}
zero_vdopool = arg_int_value(cmd, zero_ARG, 1);
vdo_pool_zero = arg_int_value(cmd, zero_ARG, 1);
log_warn("WARNING: Converting logical volume %s to VDO pool volume %s formating.",
display_lvname(lv), zero_vdopool ? "with" : "WITHOUT");
display_lvname(lv), vdo_pool_zero ? "with" : "WITHOUT");
if (zero_vdopool)
if (vdo_pool_zero)
log_warn("THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)");
else
log_warn("WARNING: Using invalid VDO pool data MAY DESTROY YOUR DATA!");
@@ -5480,7 +5481,7 @@ static int _lvconvert_to_vdopool_single(struct cmd_context *cmd,
goto out;
}
if (zero_vdopool) {
if (vdo_pool_zero) {
if (!wipe_lv(lv, (struct wipe_params) { .do_zero = 1, .do_wipe_signatures = 1,
.yes = arg_count(cmd, yes_ARG),
.force = arg_count(cmd, force_ARG)})) {
@@ -5489,7 +5490,8 @@ static int _lvconvert_to_vdopool_single(struct cmd_context *cmd,
}
}
if (!convert_vdo_pool_lv(lv, &vdo_params, &lvc.virtual_extents, zero_vdopool))
if (!convert_vdo_pool_lv(lv, &vdo_params, &lvc.virtual_extents,
vdo_pool_zero, vdo_pool_header_size))
goto_out;
dm_list_init(&lvc.tags);
@@ -5992,24 +5994,13 @@ static int _set_writecache_block_size(struct cmd_context *cmd,
rv = get_fs_block_size(pathname, &fs_block_size);
skip_fs:
if (!rv || !fs_block_size) {
if (lbs_4k && pbs_4k && !pbs_512) {
block_size = 4096;
} else if (lbs_512 && pbs_512 && !pbs_4k) {
block_size = 512;
} else if (lbs_512 && pbs_4k) {
if (block_size_setting == 4096)
block_size = 4096;
else
block_size = 512;
} else {
block_size = 512;
}
if (block_size_setting && (block_size_setting != block_size)) {
log_warn("WARNING: writecache block size %u does not match device block sizes, logical %u physical %u",
block_size_setting, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
if (block_size_setting)
block_size = block_size_setting;
}
else
block_size = 4096;
log_print("Using writecache block size %u for unknown file system block size, logical block size %u, physical block size %u.",
block_size, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
if (block_size != 512) {
log_warn("WARNING: unable to detect a file system block size on %s", display_lvname(lv));
@@ -6021,8 +6012,6 @@ skip_fs:
}
}
log_print("Using writecache block size %u for unknown file system block size, logical block size %u, physical block size %u.",
block_size, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
goto out;
}

View File

@@ -1097,7 +1097,7 @@ static int _lvcreate_params(struct cmd_context *cmd,
// FIXME: prefiling here - this is wrong place
// but will work for this moment
if (!fill_vdo_target_params(cmd, &lp->vdo_params, NULL))
if (!fill_vdo_target_params(cmd, &lp->vdo_params, &lp->vdo_pool_header_size, NULL))
return_0;
if (arg_is_set(cmd, compression_ARG))

View File

@@ -2016,6 +2016,8 @@ out:
log_debug("Recognised command %s (id %d / enum %d).",
commands[best_i].command_id, best_i, commands[best_i].command_enum);
log_command(cmd->cmd_line, commands[best_i].name, commands[best_i].command_id);
return &commands[best_i];
}
@@ -2390,6 +2392,9 @@ static void _reset_current_settings_to_default(struct cmd_context *cmd)
static void _get_current_output_settings_from_args(struct cmd_context *cmd)
{
if (arg_is_set(cmd, udevoutput_ARG))
cmd->current_settings.suppress = 1;
if (arg_is_set(cmd, debug_ARG))
cmd->current_settings.debug = _LOG_FATAL + (arg_count(cmd, debug_ARG) - 1);
@@ -2401,14 +2406,25 @@ static void _get_current_output_settings_from_args(struct cmd_context *cmd)
cmd->current_settings.verbose = 0;
cmd->current_settings.silent = (arg_count(cmd, quiet_ARG) > 1) ? 1 : 0;
}
/*
* default_settings.journal is already set from config and has already been
* applied using init_log_journal().
* current_settings have been set to default_settings.
* now --journal value adds to current_settings.
*/
if (arg_is_set(cmd, journal_ARG))
cmd->current_settings.journal |= log_journal_str_to_val(arg_str_value(cmd, journal_ARG, ""));
}
static void _apply_current_output_settings(struct cmd_context *cmd)
{
log_suppress(cmd->current_settings.suppress);
init_debug(cmd->current_settings.debug);
init_debug_classes_logged(cmd->default_settings.debug_classes);
init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL);
init_silent(cmd->current_settings.silent);
init_log_journal(cmd->current_settings.journal);
}
static int _read_devices_list(struct cmd_context *cmd)
@@ -2473,6 +2489,8 @@ static int _get_current_settings(struct cmd_context *cmd)
cmd->allow_mixed_block_sizes = find_config_tree_bool(cmd, devices_allow_mixed_block_sizes_CFG, NULL);
cmd->check_devs_used = (cmd->cname->flags & CHECK_DEVS_USED) ? 1 : 0;
/*
* enable_hints is set to 1 if any commands are using hints.
* use_hints is set to 1 if this command should use the hints.
@@ -2509,6 +2527,8 @@ static int _get_current_settings(struct cmd_context *cmd)
if (!strcmp(hint_mode, "none")) {
cmd->enable_hints = 0;
cmd->use_hints = 0;
} else if (!strcmp(hint_mode, "pvs_online")) {
cmd->hints_pvs_online = 1;
}
}
@@ -3226,6 +3246,11 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
_init_md_checks(cmd);
if (!dev_mpath_init(find_config_tree_str_allow_empty(cmd, devices_multipath_wwids_file_CFG, NULL))) {
ret = ECMD_FAILED;
goto_out;
}
if (!_cmd_no_meta_proc(cmd) && !_init_lvmlockd(cmd)) {
ret = ECMD_FAILED;
goto_out;
@@ -3246,6 +3271,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
out:
dev_mpath_exit();
hints_exit(cmd);
lvmcache_destroy(cmd, 1, 1);
label_scan_destroy(cmd);
@@ -3539,9 +3565,6 @@ struct cmd_context *init_lvm(unsigned set_connections,
{
struct cmd_context *cmd;
if (!udev_init_library_context())
stack;
/*
* It's not necessary to use name mangling for LVM:
* - the character set used for LV names is subset of udev character set
@@ -3549,9 +3572,7 @@ struct cmd_context *init_lvm(unsigned set_connections,
*/
dm_set_name_mangling_mode(DM_STRING_MANGLING_NONE);
if (!(cmd = create_toolcontext(0, NULL, 1, threaded,
set_connections, set_filters))) {
udev_fin_library_context();
if (!(cmd = create_toolcontext(0, NULL, 1, threaded, set_connections, set_filters))) {
return_NULL;
}
@@ -3559,7 +3580,6 @@ struct cmd_context *init_lvm(unsigned set_connections,
if (stored_errno()) {
destroy_toolcontext(cmd);
udev_fin_library_context();
return_NULL;
}

View File

@@ -15,6 +15,7 @@
#include "tools.h"
#include "lib/cache/lvmcache.h"
#include "lib/device/device_id.h"
#include "lib/device/dev-type.h"
static void _search_devs_for_pvids(struct cmd_context *cmd, struct dm_list *search_pvids, struct dm_list *found_devs)
{
@@ -171,7 +172,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
log_error("Failed to read the devices file.");
return ECMD_FAILED;
}
dev_cache_scan();
dev_cache_scan(cmd);
device_ids_match(cmd);
if (arg_is_set(cmd, check_ARG) || arg_is_set(cmd, update_ARG)) {
@@ -389,7 +390,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
* dev_cache_scan uses sysfs to check if an LV is using each dev
* and sets this flag is so.
*/
if (dev->flags & DEV_USED_FOR_LV) {
if (dev_is_used_by_active_lv(cmd, dev, NULL, NULL, NULL, NULL)) {
if (!arg_count(cmd, yes_ARG) &&
yes_no_prompt("Device %s is used by an active LV, continue to remove? ", devname) == 'n') {
log_error("Device not removed.");
@@ -435,7 +436,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
if (du->devname && (du->devname[0] != '.')) {
if ((dev = dev_cache_get(cmd, du->devname, NULL)) &&
(dev->flags & DEV_USED_FOR_LV)) {
dev_is_used_by_active_lv(cmd, dev, NULL, NULL, NULL, NULL)) {
if (!arg_count(cmd, yes_ARG) &&
yes_no_prompt("Device %s is used by an active LV, continue to remove? ", du->devname) == 'n') {
log_error("Device not removed.");

View File

@@ -3053,7 +3053,7 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
}
}
if (arg_is_set(cmd, dump_ARG)) {
if ((dump = arg_str_value(cmd, dump_ARG, NULL))) {
struct stat sb;
pv_name = argv[0];
@@ -3121,7 +3121,7 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
}
}
if ((dump = arg_str_value(cmd, dump_ARG, NULL))) {
if (dump) {
cmd->use_hints = 0;
if (!strcmp(dump, "metadata"))
@@ -3145,6 +3145,7 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
} else
log_error("Unknown dump value.");
free(def);
if (!ret)
return ECMD_FAILED;
return ECMD_PROCESSED;

View File

@@ -21,6 +21,8 @@
#include <dirent.h>
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
struct pvscan_params {
int new_pvs_found;
int pvs_found;
@@ -179,6 +181,27 @@ out:
return ret;
}
/*
* Avoid a duplicate pvscan[%d] prefix when logging to the journal.
* FIXME: this should probably replace if (udevoutput) with
* if (log_journal & LOG_JOURNAL_OUTPUT)
*/
#define log_print_pvscan(cmd, fmt, args...) \
do \
if (arg_is_set(cmd, udevoutput_ARG)) \
log_print(fmt, ##args); \
else \
log_print("pvscan[%d] " fmt, getpid(), ##args); \
while (0)
#define log_error_pvscan(cmd, fmt, args...) \
do \
if (arg_is_set(cmd, udevoutput_ARG)) \
log_error(fmt, ##args); \
else \
log_error("pvscan[%d] " fmt, getpid(), ##args); \
while (0)
static char *_vgname_in_pvid_file_buf(char *buf)
{
char *p, *n;
@@ -204,7 +227,7 @@ static char *_vgname_in_pvid_file_buf(char *buf)
#define MAX_PVID_FILE_SIZE 512
static int _online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
{
char buf[MAX_PVID_FILE_SIZE] = { 0 };
char *name;
@@ -259,7 +282,7 @@ static void _lookup_file_remove(char *vgname)
* that the vg will be activated again when it becomes complete.
*/
static void _online_vg_file_remove(const char *vgname)
void online_vg_file_remove(const char *vgname)
{
char path[PATH_MAX];
@@ -306,7 +329,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
file_minor = 0;
memset(file_vgname, 0, sizeof(file_vgname));
_online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
if ((file_major == major) && (file_minor == minor)) {
log_debug("Unlink pv online %s", path);
@@ -314,7 +337,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
log_sys_debug("unlink", path);
if (file_vgname[0]) {
_online_vg_file_remove(file_vgname);
online_vg_file_remove(file_vgname);
_lookup_file_remove(file_vgname);
}
}
@@ -345,7 +368,7 @@ static void _online_files_remove(const char *dirpath)
log_sys_debug("closedir", dirpath);
}
static int _online_pvid_file_create(struct device *dev, const char *vgname)
static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname)
{
char path[PATH_MAX];
char buf[MAX_PVID_FILE_SIZE] = { 0 };
@@ -362,18 +385,18 @@ static int _online_pvid_file_create(struct device *dev, const char *vgname)
minor = (int)MINOR(dev->dev);
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, dev->pvid) < 0) {
log_error("Path %s/%s is too long.", _pvs_online_dir, dev->pvid);
log_error_pvscan(cmd, "Path %s/%s is too long.", _pvs_online_dir, dev->pvid);
return 0;
}
if ((len1 = dm_snprintf(buf, sizeof(buf), "%d:%d\n", major, minor)) < 0) {
log_error("Cannot create online file path for %s %d:%d.", dev_name(dev), major, minor);
log_error_pvscan(cmd, "Cannot create online file path for %s %d:%d.", dev_name(dev), major, minor);
return 0;
}
if (vgname) {
if ((len2 = dm_snprintf(buf + len1, sizeof(buf) - len1, "vg:%s\n", vgname)) < 0) {
log_warn("Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname);
log_print_pvscan(cmd, "Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname);
/* can still continue without vgname */
len2 = 0;
}
@@ -387,7 +410,7 @@ static int _online_pvid_file_create(struct device *dev, const char *vgname)
if (fd < 0) {
if (errno == EEXIST)
goto check_duplicate;
log_error("Failed to create online file for %s path %s error %d", dev_name(dev), path, errno);
log_error_pvscan(cmd, "Failed to create online file for %s path %s error %d", dev_name(dev), path, errno);
return 0;
}
@@ -425,7 +448,7 @@ check_duplicate:
memset(file_vgname, 0, sizeof(file_vgname));
_online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
if ((file_major == major) && (file_minor == minor)) {
log_debug("Existing online file for %d:%d", major, minor);
@@ -435,12 +458,12 @@ check_duplicate:
/* Don't know how vgname might not match, but it's not good so fail. */
if ((file_major != major) || (file_minor != minor))
log_error("pvscan[%d] PV %s is duplicate for PVID %s on %d:%d and %d:%d.",
getpid(), dev_name(dev), dev->pvid, major, minor, file_major, file_minor);
log_error_pvscan(cmd, "PV %s is duplicate for PVID %s on %d:%d and %d:%d.",
dev_name(dev), dev->pvid, major, minor, file_major, file_minor);
if (file_vgname[0] && vgname && strcmp(file_vgname, vgname))
log_error("pvscan[%d] PV %s has unexpected VG %s vs %s.",
getpid(), dev_name(dev), vgname, file_vgname);
log_error_pvscan(cmd, "PV %s has unexpected VG %s vs %s.",
dev_name(dev), vgname, file_vgname);
return 0;
}
@@ -475,7 +498,7 @@ static int _write_lookup_file(struct cmd_context *cmd, struct volume_group *vg)
int fd;
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, vg->name) < 0) {
log_error("Path %s/%s is too long.", _pvs_lookup_dir, vg->name);
log_error_pvscan(cmd, "Path %s/%s is too long.", _pvs_lookup_dir, vg->name);
return 0;
}
@@ -638,7 +661,7 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
return (vgname) ? 1 : 0;
}
static void _online_dir_setup(void)
static void _online_dir_setup(struct cmd_context *cmd)
{
struct stat st;
int rv;
@@ -652,7 +675,7 @@ static void _online_dir_setup(void)
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(DEFAULT_RUN_DIR, &st))
log_error("Failed to create %s %d", DEFAULT_RUN_DIR, errno);
log_error_pvscan(cmd, "Failed to create %s %d", DEFAULT_RUN_DIR, errno);
do_pvs:
if (!stat(_pvs_online_dir, &st))
@@ -664,7 +687,7 @@ do_pvs:
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(_pvs_online_dir, &st))
log_error("Failed to create %s %d", _pvs_online_dir, errno);
log_error_pvscan(cmd, "Failed to create %s %d", _pvs_online_dir, errno);
do_vgs:
if (!stat(_vgs_online_dir, &st))
@@ -676,7 +699,7 @@ do_vgs:
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(_vgs_online_dir, &st))
log_error("Failed to create %s %d", _vgs_online_dir, errno);
log_error_pvscan(cmd, "Failed to create %s %d", _vgs_online_dir, errno);
do_lookup:
if (!stat(_pvs_lookup_dir, &st))
@@ -688,7 +711,7 @@ do_lookup:
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(_pvs_lookup_dir, &st))
log_error("Failed to create %s %d", _pvs_lookup_dir, errno);
log_error_pvscan(cmd, "Failed to create %s %d", _pvs_lookup_dir, errno);
}
@@ -725,7 +748,7 @@ static int _pvscan_aa_single(struct cmd_context *cmd, const char *vg_name,
log_debug("pvscan autoactivating VG %s.", vg_name);
if (!vgchange_activate(cmd, vg, CHANGE_AAY)) {
log_error("%s: autoactivation failed.", vg->name);
log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name);
pp->activate_errors++;
}
@@ -738,7 +761,7 @@ static int _online_vg_file_create(struct cmd_context *cmd, const char *vgname)
int fd;
if (dm_snprintf(path, sizeof(path), "%s/%s", _vgs_online_dir, vgname) < 0) {
log_error("Path %s/%s is too long.", _vgs_online_dir, vgname);
log_error_pvscan(cmd, "Path %s/%s is too long.", _vgs_online_dir, vgname);
return 0;
}
@@ -823,18 +846,18 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname,
file_minor = 0;
memset(file_vgname, 0, sizeof(file_vgname));
_online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
if (file_vgname[0] && strcmp(vgname, file_vgname)) {
log_error("Wrong VG found for %d:%d PVID %s: %s vs %s",
file_major, file_minor, pvid, vgname, file_vgname);
log_error_pvscan(cmd, "Wrong VG found for %d:%d PVID %s: %s vs %s",
file_major, file_minor, pvid, vgname, file_vgname);
goto bad;
}
devno = MKDEV(file_major, file_minor);
if (!(dev = dev_cache_get_by_devt(cmd, devno, NULL, NULL))) {
log_error("No device found for %d:%d PVID %s", file_major, file_minor, pvid);
log_error_pvscan(cmd, "No device found for %d:%d PVID %s", file_major, file_minor, pvid);
goto bad;
}
@@ -844,7 +867,7 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname,
if (strcmp(name1, name2)) {
if (!id_write_format((const struct id *)pvid, uuidstr, sizeof(uuidstr)))
uuidstr[0] = '\0';
log_print("PVID %s read from %s last written to %s.", uuidstr, name1, name2);
log_print_pvscan(cmd, "PVID %s read from %s last written to %s.", uuidstr, name1, name2);
goto bad;
}
@@ -921,7 +944,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
* The dev_cache gives us struct devices from the devnums.
*/
if (!_get_devs_from_saved_vg(cmd, vgname, &devs)) {
log_print("pvscan[%d] VG %s not using quick activation.", getpid(), vgname);
log_print_pvscan(cmd, "VG %s not using quick activation.", vgname);
*no_quick = 1;
return ECMD_FAILED;
}
@@ -932,7 +955,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
* label rescan are then disabled in vg_read.)
*/
if (!lock_vol(cmd, vgname, LCK_VG_WRITE, NULL)) {
log_error("pvscan activation for VG %s failed to lock VG.", vgname);
log_error_pvscan(cmd, "activation for VG %s failed to lock VG.", vgname);
return ECMD_FAILED;
}
@@ -945,7 +968,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
label_scan_devs(cmd, NULL, &devs);
if (!(vgid = lvmcache_vgid_from_vgname(cmd, vgname))) {
log_error("pvscan activation for VG %s failed to find vgid.", vgname);
log_error_pvscan(cmd, "activation for VG %s failed to find vgid.", vgname);
return ECMD_FAILED;
}
@@ -965,7 +988,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
* original device arg scan. There will be very few and unusual
* cases that would be caught here.
*/
log_error("pvscan activation for VG %s cannot read (%x).", vgname, error_flags);
log_error_pvscan(cmd, "activation for VG %s cannot read (%x).", vgname, error_flags);
return ECMD_FAILED;
}
@@ -987,7 +1010,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
dm_list_iterate_items(pvl, &vg->pvs) {
if (dev_in_device_list(pvl->pv->dev, &devs))
continue;
log_error("pvscan activation for VG %s found different devices.", vgname);
log_error_pvscan(cmd, "activation for VG %s found different devices.", vgname);
ret = ECMD_FAILED;
goto out;
}
@@ -995,7 +1018,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
log_debug("pvscan autoactivating VG %s.", vgname);
if (!vgchange_activate(cmd, vg, CHANGE_AAY)) {
log_error("%s: autoactivation failed.", vg->name);
log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name);
pp->activate_errors++;
}
@@ -1014,7 +1037,7 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
int ret = ECMD_FAILED;
if (!(handle = init_processing_handle(cmd, NULL))) {
log_error("Failed to initialize processing handle.");
log_error_pvscan(cmd, "Failed to initialize processing handle.");
goto out;
}
@@ -1029,11 +1052,11 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
*/
dm_list_iterate_items_safe(sl, sl2, vgnames) {
if (!_online_vg_file_create(cmd, sl->str)) {
log_print("pvscan[%d] VG %s skip autoactivation.", getpid(), sl->str);
log_print_pvscan(cmd, "VG %s skip autoactivation.", sl->str);
str_list_del(vgnames, sl->str);
continue;
}
log_print("pvscan[%d] VG %s run autoactivation.", getpid(), sl->str);
log_print_pvscan(cmd, "VG %s run autoactivation.", sl->str);
}
if (dm_list_empty(vgnames)) {
@@ -1165,6 +1188,64 @@ static int _get_args_devs(struct cmd_context *cmd, struct dm_list *pvscan_args,
return 1;
}
static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group *vg)
{
char path[PATH_MAX];
char file_vgname[NAME_LEN];
char pvid[ID_LEN+1] = { 0 };
struct pv_list *pvl;
struct device *dev;
int major, minor;
dev_t devno;
dm_list_iterate_items(pvl, &vg->pvs) {
memcpy(&pvid, &pvl->pv->id.uuid, ID_LEN);
if (pvl->pv->status & MISSING_PV) {
log_debug("set_pv_devices_online vg %s pv %s missing flag already set",
vg->name, pvid);
continue;
}
if (!_online_pvid_file_exists(pvid)) {
log_debug("set_pv_devices_online vg %s pv %s no online file",
vg->name, pvid);
pvl->pv->status |= MISSING_PV;
continue;
}
memset(path, 0, sizeof(path));
snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid);
major = 0;
minor = 0;
file_vgname[0] = '\0';
online_pvid_file_read(path, &major, &minor, file_vgname);
if (file_vgname[0] && strcmp(vg->name, file_vgname)) {
log_warn("WARNING: VG %s PV %s wrong vgname in online file %s",
vg->name, pvid, file_vgname);
pvl->pv->status |= MISSING_PV;
continue;
}
devno = MKDEV(major, minor);
if (!(dev = dev_cache_get_by_devt(cmd, devno, NULL, NULL))) {
log_print_pvscan(cmd, "VG %s PV %s no device found for %d:%d",
vg->name, pvid, major, minor);
pvl->pv->status |= MISSING_PV;
continue;
}
log_debug("set_pv_devices_online vg %s pv %s is online %s",
vg->name, pvid, dev_name(dev));
pvl->pv->dev = dev;
}
}
static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvscan_devs,
int *pv_count, struct dm_list *complete_vgnames)
{
@@ -1177,15 +1258,20 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
struct metadata_area *mda1, *mda2;
struct volume_group *vg;
struct physical_volume *pv;
const char *vgname;
uint32_t ext_version, ext_flags;
const char *vgname = NULL;
uint64_t devsize;
uint32_t ext_version, ext_flags;
int do_cache = arg_is_set(cmd, cache_long_ARG);
int do_activate = arg_is_set(cmd, activate_ARG);
int do_full_check;
int do_list_lvs = arg_is_set(cmd, listlvs_ARG);
int do_list_vg = arg_is_set(cmd, listvg_ARG);
int do_check_complete = arg_is_set(cmd, checkcomplete_ARG);
int do_vgonline = arg_is_set(cmd, vgonline_ARG);
int pvs_online;
int pvs_offline;
int pvs_unknown;
int vg_complete;
int do_full_check;
int ret = 1;
dm_list_iterate_items_safe(devl, devl2, pvscan_devs) {
@@ -1193,26 +1279,16 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
log_debug("online_devs %s %s", dev_name(dev), dev->pvid);
/*
* This should already have been done by the filter, but make
* another check directly with udev in case the filter was not
* using udev and the native version didn't catch it.
*/
if (udev_dev_is_mpath_component(dev)) {
log_print("pvscan[%d] ignore multipath component %s.", getpid(), dev_name(dev));
continue;
}
if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
if (!do_all)
log_print("pvscan[%d] ignore %s with no lvm info.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "ignore %s with no lvm info.", dev_name(dev));
continue;
}
ext_version = lvmcache_ext_version(info);
ext_flags = lvmcache_ext_flags(info);
if ((ext_version >= 2) && !(ext_flags & PV_EXT_USED)) {
log_print("pvscan[%d] PV %s not used.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "PV %s not used.", dev_name(dev));
(*pv_count)++;
continue;
}
@@ -1231,7 +1307,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
vg = mda2->ops->vg_read(cmd, fid, "", mda2, NULL, NULL);
if (!vg) {
log_print("pvscan[%d] PV %s has no VG metadata.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "PV %s has no VG metadata.", dev_name(dev));
if (fid)
fmt->ops->destroy_instance(fid);
goto online;
@@ -1240,7 +1316,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
set_pv_devices(fid, vg);
if (!(pv = find_pv(vg, dev))) {
log_print("pvscan[%d] PV %s not found in VG %s.", getpid(), dev_name(dev), vg->name);
log_print_pvscan(cmd, "PV %s not found in VG %s.", dev_name(dev), vg->name);
release_vg(vg);
continue;
}
@@ -1257,14 +1333,15 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
if (pv->device_hint && !strncmp(pv->device_hint, "/dev/md", 7))
do_full_check = 1;
}
if (do_full_check && dev_is_md_component(dev, NULL, 1)) {
log_print("pvscan[%d] ignore md component %s.", getpid(), dev_name(dev));
if (do_full_check && dev_is_md_component(cmd, dev, NULL, 1)) {
log_print_pvscan(cmd, "ignore md component %s.", dev_name(dev));
release_vg(vg);
continue;
}
if (vg_is_shared(vg)) {
log_print("pvscan[%d] PV %s ignore shared VG.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "PV %s ignore shared VG.", dev_name(dev));
release_vg(vg);
continue;
}
@@ -1274,7 +1351,13 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
vg_is_foreign(vg)) {
log_verbose("Ignore PV %s with VG system id %s with our system id %s",
dev_name(dev), vg->system_id, cmd->system_id);
log_print("pvscan[%d] PV %s ignore foreign VG.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "PV %s ignore foreign VG.", dev_name(dev));
release_vg(vg);
continue;
}
if (vg_is_exported(vg)) {
log_print_pvscan(cmd, "PV %s ignore exported VG.", dev_name(dev));
release_vg(vg);
continue;
}
@@ -1293,19 +1376,20 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
/*
* Create file named for pvid to record this PV is online.
* The command creates/checks online files only when --cache is used.
*/
if (!_online_pvid_file_create(dev, vg ? vg->name : NULL)) {
log_error("pvscan[%d] PV %s failed to create online file.", getpid(), dev_name(dev));
if (do_cache && !_online_pvid_file_create(cmd, dev, vg ? vg->name : NULL)) {
log_error_pvscan(cmd, "PV %s failed to create online file.", dev_name(dev));
release_vg(vg);
ret = 0;
continue;
}
/*
* When not activating we don't need to know about vg completeness.
* A plain pvscan --cache <dev> just creates the online file.
*/
if (!do_activate) {
log_print("pvscan[%d] PV %s online.", getpid(), dev_name(dev));
if (!do_activate && !do_list_lvs && !do_list_vg) {
log_print_pvscan(cmd, "PV %s online.", dev_name(dev));
release_vg(vg);
continue;
}
@@ -1313,58 +1397,159 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
/*
* Check if all the PVs for this VG are online. If the arrival
* of this dev completes the VG, then save the vgname in
* complete_vgnames so it will be activated.
* complete_vgnames (activation phase will want to know which
* VGs to activate.)
*/
pvs_online = 0;
pvs_offline = 0;
pvs_unknown = 0;
vg_complete = 0;
if (do_activate || do_check_complete) {
pvs_online = 0;
pvs_offline = 0;
pvs_unknown = 0;
vg_complete = 0;
if (vg) {
/*
* Use the VG metadata from this PV for a list of all
* PVIDs. Write a lookup file of PVIDs in case another
* pvscan needs it. After writing lookup file, recheck
* pvid files to resolve a possible race with another
* pvscan reading the lookup file that missed it.
*/
log_debug("checking all pvid files from vg %s", vg->name);
_count_pvid_files(vg, &pvs_online, &pvs_offline);
if (pvs_offline && _write_lookup_file(cmd, vg)) {
log_debug("rechecking all pvid files from vg %s", vg->name);
if (vg) {
/*
* Use the VG metadata from this PV for a list of all
* PVIDs. Write a lookup file of PVIDs in case another
* pvscan needs it. After writing lookup file, recheck
* pvid files to resolve a possible race with another
* pvscan reading the lookup file that missed it.
*/
log_debug("checking all pvid files from vg %s", vg->name);
_count_pvid_files(vg, &pvs_online, &pvs_offline);
if (!pvs_offline)
log_print("pvscan[%d] VG %s complete after recheck.", getpid(), vg->name);
if (pvs_offline && _write_lookup_file(cmd, vg)) {
log_debug("rechecking all pvid files from vg %s", vg->name);
_count_pvid_files(vg, &pvs_online, &pvs_offline);
if (!pvs_offline)
log_print_pvscan(cmd, "VG %s complete after recheck.", vg->name);
}
vgname = vg->name;
} else {
/*
* No VG metadata on this PV, so try to use a lookup
* file written by a prior pvscan for a list of all
* PVIDs. A lookup file may not exist for this PV if
* it's the first to appear from the VG.
*/
log_debug("checking all pvid files from lookup file");
if (!_count_pvid_files_from_lookup_file(cmd, dev, &pvs_online, &pvs_offline, &vgname))
pvs_unknown = 1;
}
if (pvs_unknown) {
log_print_pvscan(cmd, "PV %s online, VG unknown.", dev_name(dev));
vg_complete = 0;
} else if (pvs_offline) {
log_print_pvscan(cmd, "PV %s online, VG %s incomplete (need %d).",
dev_name(dev), vgname, pvs_offline);
vg_complete = 0;
} else {
log_print_pvscan(cmd, "PV %s online, VG %s is complete.", dev_name(dev), vgname);
if (!str_list_add(cmd->mem, complete_vgnames, dm_pool_strdup(cmd->mem, vgname)))
stack;
vg_complete = 1;
}
}
if (!vgname && vg)
vgname = vg->name;
if (do_list_vg || do_list_lvs) {
if (!vgname) {
log_print("VG unknown");
} else if (!do_check_complete) {
log_print("VG %s", vgname);
} else if (vg_complete) {
if (do_vgonline && !_online_vg_file_create(cmd, vgname)) {
log_print("VG %s finished", vgname);
} else {
/*
* A udev rule imports KEY=val from a program's stdout.
* Other output causes udev to ignore everything.
* Run pvscan from udev rule using --udevoutput to
* enable this printf, and suppress all log output
*/
if (arg_is_set(cmd, udevoutput_ARG))
printf("LVM_VG_NAME_COMPLETE='%s'\n", vgname);
else
log_print("VG %s complete", vgname);
}
} else {
if (arg_is_set(cmd, udevoutput_ARG))
printf("LVM_VG_NAME_INCOMPLETE='%s'\n", vgname);
else
log_print("VG %s incomplete", vgname);
}
vgname = vg->name;
} else {
/*
* No VG metadata on this PV, so try to use a lookup
* file written by a prior pvscan for a list of all
* PVIDs. A lookup file may not exist for this PV if
* it's the first to appear from the VG.
* When the VG is complete|finished, we could print
* a list of devices in the VG, by reading the pvid files
* that were counted, which provides major:minor of each
* device and using that to get the struct dev and dev_name.
* The user could pass this list of devices to --devices
* to optimize a subsequent command (activation) on the VG.
* Just call set_pv_devices_online (if not done othewise)
* since that finds the devs.
*/
log_debug("checking all pvid files from lookup file");
if (!_count_pvid_files_from_lookup_file(cmd, dev, &pvs_online, &pvs_offline, &vgname))
pvs_unknown = 1;
}
if (pvs_unknown) {
log_print("pvscan[%d] PV %s online, VG unknown.",
getpid(), dev_name(dev));
} else if (pvs_offline) {
log_print("pvscan[%d] PV %s online, VG %s incomplete (need %d).",
getpid(), dev_name(dev), vgname, pvs_offline);
} else {
log_print("pvscan[%d] PV %s online, VG %s is complete.", getpid(), dev_name(dev), vgname);
if (!str_list_add(cmd->mem, complete_vgnames, dm_pool_strdup(cmd->mem, vgname)))
stack;
vg_complete = 1;
if (do_list_lvs && !vg) {
/* require all PVs used for booting have metadata */
log_print_pvscan(cmd, "Cannot list LVs from device without metadata.");
}
if (!saved_vg && vg && vg_complete && !do_all && (dm_list_size(pvscan_devs) == 1))
if (do_list_lvs && vg) {
struct dm_list lvs_list;
struct lv_list *lvl;
dm_list_init(&lvs_list);
/*
* For each vg->pvs entry, get the dev based on the online file
* for the pvid and set pv->dev or pv->status MISSING_PV.
*/
_set_pv_devices_online(cmd, vg);
/*
* lvs_list are LVs that use dev.
*/
if (!get_visible_lvs_using_pv(cmd, vg, dev, &lvs_list))
log_print_pvscan(cmd, "Failed to find LVs using %s.", dev_name(dev));
if (!do_check_complete) {
dm_list_iterate_items(lvl, &lvs_list)
log_print("LV %s", display_lvname(lvl->lv));
} else if (vg_complete) {
/*
* A shortcut; the vg complete implies all lvs are complete.
*/
dm_list_iterate_items(lvl, &lvs_list)
log_print("LV %s complete", display_lvname(lvl->lv));
} else {
/*
* For each LV in VG, check if all devs are present.
* Sets the PARTIAL flag on LVs that are not complete.
*/
if (!vg_mark_partial_lvs(vg, 1))
log_print_pvscan(cmd, "Failed to check partial lvs.");
dm_list_iterate_items(lvl, &lvs_list) {
if (!lv_is_partial(lvl->lv))
log_print("LV %s complete", display_lvname(lvl->lv));
else
log_print("LV %s incomplete", display_lvname(lvl->lv));
}
}
}
/*
* When "pvscan --cache -aay <dev>" completes the vg, save the
* struct vg to use for quick activation function.
*/
if (do_activate && !saved_vg && vg && vg_complete && !do_all && (dm_list_size(pvscan_devs) == 1))
saved_vg = vg;
else
release_vg(vg);
@@ -1453,7 +1638,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
cmd->pvscan_cache_single = 1;
if (!setup_devices(cmd)) {
log_error("Failed to set up devices.");
log_error_pvscan(cmd, "Failed to set up devices.");
return 0;
}
@@ -1519,8 +1704,8 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
dm_list_iterate_items_safe(devl, devl2, &pvscan_devs) {
if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) {
log_print("pvscan[%d] %s excluded by filters: %s.", getpid(),
dev_name(devl->dev), dev_filtered_reason(devl->dev));
log_print_pvscan(cmd, "%s excluded by filters: %s.",
dev_name(devl->dev), dev_filtered_reason(devl->dev));
dm_list_del(&devl->list);
}
}
@@ -1556,7 +1741,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
if (!has_pvid) {
/* Not an lvm device */
log_print("pvscan[%d] %s not an lvm device.", getpid(), dev_name(devl->dev));
log_print_pvscan(cmd, "%s not an lvm device.", dev_name(devl->dev));
dm_list_del(&devl->list);
continue;
}
@@ -1567,8 +1752,8 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
*/
if (relax_deviceid_filter) {
if (!get_du_for_pvid(cmd, devl->dev->pvid)) {
log_print("pvscan[%d] %s excluded by devices file (checking PVID).",
getpid(), dev_name(devl->dev));
log_print_pvscan(cmd, "%s excluded by devices file (checking PVID).",
dev_name(devl->dev));
dm_list_del(&devl->list);
continue;
}
@@ -1576,8 +1761,8 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
/* Applies all filters, including those that need data from dev. */
if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) {
log_print("pvscan[%d] %s excluded by filters: %s.", getpid(),
dev_name(devl->dev), dev_filtered_reason(devl->dev));
log_print_pvscan(cmd, "%s excluded by filters: %s.",
dev_name(devl->dev), dev_filtered_reason(devl->dev));
dm_list_del(&devl->list);
}
}
@@ -1621,18 +1806,53 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
struct pvscan_aa_params pp = { 0 };
struct dm_list complete_vgnames;
int do_activate = arg_is_set(cmd, activate_ARG);
int event_activation;
int devno_args = 0;
int do_all;
int ret;
dm_list_init(&complete_vgnames);
if (do_activate &&
!find_config_tree_bool(cmd, global_event_activation_CFG, NULL)) {
cmd->check_devs_used = 0;
event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL);
if (do_activate && !event_activation) {
log_verbose("Ignoring pvscan --cache -aay because event_activation is disabled.");
return ECMD_PROCESSED;
}
/*
* lvm udev rules call:
* pvscan --cache --listvg|--listlvs --checkcomplete PV
* when PVs appear, even if event_activation=0 in lvm.conf.
*
* The udev rules will do autoactivation if they see complete
* VGs/LVs reported from the pvscan.
*
* When event_activation=0 we do not want to do autoactivation
* from udev events, so we need the pvscan to not report any
* complete VGs/LVs when event_activation=0 so that the udev
* rules do not attempt to autoactivate.
*/
if (arg_is_set(cmd, checkcomplete_ARG) && !event_activation) {
if (arg_is_set(cmd, udevoutput_ARG))
printf("LVM_EVENT_ACTIVATION=0\n");
else
log_print_pvscan(cmd, "Ignoring pvscan with --checkcomplete because event_activation is disabled.");
return ECMD_PROCESSED;
}
/*
* If obtain_device_list_from_udev was set to 1, force it to 0.
* Don't ask udev for info since pvscan is running from udev.
* If a pvscan attempts to get dev info from udev, udev can
* repeatedly return errors about the dev not being initialized
* which will stall the pvscan.
*/
init_obtain_device_list_from_udev(0);
if (arg_is_set(cmd, major_ARG) + arg_is_set(cmd, minor_ARG))
devno_args = 1;
@@ -1643,12 +1863,17 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
do_all = !argc && !devno_args;
_online_dir_setup();
_online_dir_setup(cmd);
if (do_all) {
if (!_pvscan_cache_all(cmd, argc, argv, &complete_vgnames))
return ECMD_FAILED;
} else {
if (!arg_is_set(cmd, checkcomplete_ARG) && !event_activation) {
/* Avoid doing anything for device removal: pvscan --cache <devno> */
log_verbose("Ignoring pvscan --cache because event_activation is disabled.");
return ECMD_PROCESSED;
}
if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames))
return ECMD_FAILED;
}

View File

@@ -811,6 +811,24 @@ int lv_change_activate(struct cmd_context *cmd, struct logical_volume *lv,
lv_clear_integrity_recalculate_metadata(lv);
}
/*
* When LVs are deactivated, then autoactivation of the VG is
* "re-armed" by removing the vg online file. So, after deactivation
* of LVs, if PVs are disconnected and reconnected again, event
* activation will trigger autoactivation again. This secondary
* autoactivation is somewhat different from, and not as important as
* the initial autoactivation during system startup. The secondary
* autoactivation will happen to a VG on a running system and may be
* mixing with user commands, so the end result is unpredictable.
*
* It's possible that we might want a config setting for usersto
* disable secondary autoactivations. Once a system is up, the
* user may want to take charge of activation changes to the VG
* and not have the system autoactivation interfere.
*/
if (!is_change_activating(activate) && find_config_tree_bool(cmd, global_event_activation_CFG, NULL))
online_vg_file_remove(lv->vg->name);
set_lv_notify(lv->vg->cmd);
return r;
@@ -2140,7 +2158,6 @@ int process_each_vg(struct cmd_context *cmd,
struct dm_list vgnameids_to_process; /* vgnameid_list */
int enable_all_vgs = (cmd->cname->flags & ALL_VGS_IS_DEFAULT);
int process_all_vgs_on_system = 0;
int gl_ex = 0;
int ret_max = ECMD_PROCESSED;
int ret;
@@ -2174,25 +2191,11 @@ int process_each_vg(struct cmd_context *cmd,
process_all_vgs_on_system = 1;
/*
* The global lock will be taken prior to scanning if the
* /run/lvm/scan_lock_global file has been created by a prior command,
* indicating that vg metadata sizes are large enough to possibly wrap
* around the metadata area during label_scan or between label_scan and
* vg_read, which can invalidate the scan results (normally unlocked)
* and prevent a valid vg_read (which uses metadata locations saved by
* label_scan).
* Needed for a current listing of the global VG namespace.
*/
if (do_scan_lock_global(cmd, &gl_ex)) {
if (!lock_global(cmd, gl_ex ? "ex" : "sh")) {
ret_max = ECMD_FAILED;
goto_out;
}
} else if (process_all_vgs_on_system) {
/* Needed for a current listing of the global VG namespace. */
if (!lock_global(cmd, "sh")) {
ret_max = ECMD_FAILED;
goto_out;
}
if (process_all_vgs_on_system && !lock_global(cmd, "sh")) {
ret_max = ECMD_FAILED;
goto_out;
}
/*
@@ -3683,7 +3686,6 @@ int process_each_lv(struct cmd_context *cmd,
struct dm_list vgnameids_to_process; /* vgnameid_list */
int enable_all_vgs = (cmd->cname->flags & ALL_VGS_IS_DEFAULT);
int process_all_vgs_on_system = 0;
int gl_ex = 0;
int ret_max = ECMD_PROCESSED;
int ret;
@@ -3738,17 +3740,12 @@ int process_each_lv(struct cmd_context *cmd,
else if (dm_list_empty(&arg_vgnames) && handle->internal_report_for_select)
process_all_vgs_on_system = 1;
if (do_scan_lock_global(cmd, &gl_ex)) {
if (!lock_global(cmd, gl_ex ? "ex" : "sh")) {
ret_max = ECMD_FAILED;
goto_out;
}
} else if (process_all_vgs_on_system) {
/* Needed for a current listing of the global VG namespace. */
if (!lock_global(cmd, "sh")) {
ret_max = ECMD_FAILED;
goto_out;
}
/*
* Needed for a current listing of the global VG namespace.
*/
if (process_all_vgs_on_system && !lock_global(cmd, "sh")) {
ret_max = ECMD_FAILED;
goto_out;
}
/*
@@ -4405,7 +4402,6 @@ int process_each_pv(struct cmd_context *cmd,
struct device_id_list *dil;
int process_all_pvs;
int process_all_devices;
int gl_ex = 0;
int ret_max = ECMD_PROCESSED;
int ret;
@@ -4456,17 +4452,10 @@ int process_each_pv(struct cmd_context *cmd,
process_all_devices = process_all_pvs && (cmd->cname->flags & ENABLE_ALL_DEVS) && all_is_set;
if (do_scan_lock_global(cmd, &gl_ex)) {
if (!lock_global(cmd, gl_ex ? "ex" : "sh")) {
ret_max = ECMD_FAILED;
goto_out;
}
} else if (!only_this_vgname) {
/* Needed for a current listing of the global VG namespace. */
if (!lock_global(cmd, "sh")) {
ret_max = ECMD_FAILED;
goto_out;
}
/* Needed for a current listing of the global VG namespace. */
if (!only_this_vgname && !lock_global(cmd, "sh")) {
ret_max = ECMD_FAILED;
goto_out;
}
if (!(read_flags & PROCESS_SKIP_SCAN))

View File

@@ -139,6 +139,8 @@ struct arg_value_group_list {
#define ALLOW_HINTS 0x00004000
/* Command can access exported vg. */
#define ALLOW_EXPORTED 0x00008000
/* Command checks and reports warning if devs used by LV are incorrect. */
#define CHECK_DEVS_USED 0x00010000
void usage(const char *name);
@@ -291,4 +293,6 @@ int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle);
void online_vg_file_remove(const char *vgname);
#endif

View File

@@ -61,14 +61,14 @@ static int _update_vg(struct cmd_context *cmd, struct volume_group *vg,
/*
* N.B. lvs_in_vg_activated() is not smart enough to distinguish
* between LVs that are active in the original VG vs the cloned VG
* that's being imported, so check DEV_USED_FOR_LV.
* that's being imported, so check dev_is_used_by_active_lv.
*/
dm_list_iterate_items(pvl, &vg->pvs) {
if (is_missing_pv(pvl->pv) || !pvl->pv->dev) {
log_error("VG is missing a device.");
goto bad;
}
if (pvl->pv->dev->flags & DEV_USED_FOR_LV) {
if (dev_is_used_by_active_lv(cmd, pvl->pv->dev, NULL, NULL, NULL, NULL)) {
log_error("Device %s has active LVs, deactivate first.", dev_name(pvl->pv->dev));
devs_used_for_lv++;
}

87
udev/69-dm-lvm.rules.in Normal file
View File

@@ -0,0 +1,87 @@
# Copyright (C) 2012,2021 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM.
#
# This rule requires blkid to be called on block devices before so only devices
# used as LVM PVs are processed (ID_FS_TYPE="LVM2_member").
SUBSYSTEM!="block", GOTO="lvm_end"
(LVM_EXEC_RULE)
ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="lvm_end"
# Only process devices already marked as a PV - this requires blkid to be called before.
ENV{ID_FS_TYPE}!="LVM2_member", GOTO="lvm_end"
ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="lvm_end"
ACTION=="remove", GOTO="lvm_end"
# Create /dev/disk/by-id/lvm-pv-uuid-<PV_UUID> symlink for each PV
ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-id/lvm-pv-uuid-$env{ID_FS_UUID_ENC}"
# If the PV is a special device listed below, scan only if the device is
# properly activated. These devices are not usable after an ADD event,
# but they require an extra setup and they are ready after a CHANGE event.
# Also support coldplugging with ADD event but only if the device is already
# properly activated.
# This logic should be eventually moved to rules where those particular
# devices are processed primarily (MD and loop).
# DM device:
KERNEL!="dm-[0-9]*", GOTO="next"
ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}=="1", ENV{DM_ACTIVATION}=="1", GOTO="lvm_scan"
GOTO="lvm_end"
# MD device:
LABEL="next"
KERNEL!="md[0-9]*", GOTO="next"
IMPORT{db}="LVM_MD_PV_ACTIVATED"
ACTION=="add", ENV{LVM_MD_PV_ACTIVATED}=="1", GOTO="lvm_scan"
ACTION=="change", ENV{LVM_MD_PV_ACTIVATED}!="1", TEST=="md/array_state", ENV{LVM_MD_PV_ACTIVATED}="1", GOTO="lvm_scan"
ACTION=="add", KERNEL=="md[0-9]*p[0-9]*", GOTO="lvm_scan"
ENV{LVM_MD_PV_ACTIVATED}!="1", ENV{SYSTEMD_READY}="0"
GOTO="lvm_end"
# Loop device:
LABEL="next"
KERNEL!="loop[0-9]*", GOTO="next"
ACTION=="add", ENV{LVM_LOOP_PV_ACTIVATED}=="1", GOTO="lvm_scan"
ACTION=="change", ENV{LVM_LOOP_PV_ACTIVATED}!="1", TEST=="loop/backing_file", ENV{LVM_LOOP_PV_ACTIVATED}="1", GOTO="lvm_scan"
ENV{LVM_LOOP_PV_ACTIVATED}!="1", ENV{SYSTEMD_READY}="0"
GOTO="lvm_end"
LABEL="next"
ACTION!="add", GOTO="lvm_end"
LABEL="lvm_scan"
ENV{SYSTEMD_READY}="1"
# pvscan will check if this device completes a VG,
# i.e. all PVs in the VG are now present with the
# arrival of this PV. If so, it prints to stdout:
# LVM_VG_NAME_COMPLETE='foo'
#
# When the VG is complete it can be activated, so
# vgchange -aay <vgname> is run. It is run via
# systemd since it can take longer to run than
# udev wants to block when processing rules.
# (if there are hundreds of LVs to activate,
# the vgchange can take many seconds.)
#
# pvscan only reads the single device specified,
# and uses temp files under /run/lvm to check if
# other PVs in the VG are present.
#
# If event_activation=0 in lvm.conf, this pvscan
# (using checkcomplete) will do nothing, so that
# no event-based autoactivation will be happen.
#
# TODO: adjust the output of vgchange -aay so that
# it's better suited to appearing in the journal.
IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --udevoutput --journal=output $env{DEVNAME}"
ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run -r --no-block --property DefaultDependencies=no --unit lvm-activate-$env{LVM_VG_NAME_COMPLETE} lvm vgchange -aay --config devices/hints=pvs_online $env{LVM_VG_NAME_COMPLETE}"
GOTO="lvm_end"
LABEL="lvm_end"

View File

@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
include $(top_builddir)/make.tmpl
DM_RULES=10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
LVM_RULES=11-dm-lvm.rules 69-dm-lvm-metad.rules
LVM_RULES=11-dm-lvm.rules 69-dm-lvm.rules
DM_DIR=$(shell $(GREP) "\#define DM_DIR" $(top_srcdir)/libdm/misc/dm-ioctl.h | $(AWK) '{print $$3}')