1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-04-06 10:50:41 +03:00

Compare commits

...

209 Commits

Author SHA1 Message Date
Zdenek Kabelac
11b64b0c0c lvmcmdline: still support use of profile
Couple commands (lvcreate,lvconvert,vgcreate,lvchange,vgchange)
has the 'specific' property that within them the option --profile
behaves like --metadataprofile, while for all other commands this
option should be simply an alias for --commandprofile.

We may eventually drop this rather confusing behavior in the future
version and there will be only one use as --[command]profile

It should be noted this --commandprofile can be often used
instead of --config option for preconfiguring setting
for some group of commands - we should possibly more propagate
this usage.
2025-04-04 14:48:57 +02:00
Zdenek Kabelac
6838881956 libdm: fix missed init of regex pointer
Recent patch set for select enhancement missed to initialize
ssl struct element regex to NULL and this code might have
crashed on this code path evaluation.
2025-04-04 14:48:57 +02:00
Zdenek Kabelac
5d16beee57 WHATS_NEW: update 2025-04-01 15:37:36 +02:00
Zdenek Kabelac
26e86f9da9 make: generate 2025-04-01 15:37:36 +02:00
Zdenek Kabelac
b8b0fcfa10 cov: remove unused header 2025-04-01 15:37:36 +02:00
Zdenek Kabelac
6679438437 tests: check resize of snapshot with mounted origin 2025-04-01 15:37:36 +02:00
Zdenek Kabelac
1bf3961bbe tests: resize of mounted fs missed workaround
For older kernel, we need to suspend/resume.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
dcf37af2ca tests: preserve signess 2025-04-01 15:37:36 +02:00
Zdenek Kabelac
ebbdaccd9c tests: check unsupported vdo conversions
Validate unsupported vdo conversions are rejected.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
fafc0f76c5 tests: remove testing of old mirror with vdo
Actually mirror were never supposed to be usable with any newer
target as they are very problematic with any stacked usage.
So now it's going to be properly checked and prohibited.

Users are always supposed to use 'raid1' --type instead.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
491c6652ae command: use loop for short_opts pass
Slight refactoring of the code to take less size
as the code is used rather occasionally.

Correct some minor typographical issue.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
ea73594f07 man-generator: print LV1 also for options
We can print list of supported LV types for
options like --cachepool,--thinpool,--vdopool when
they are specifying particular LV.

TODO: while we nicely document them, the parser engine ATM
is not capable to validate and enforce these properties,
so the code needs to match them on its own.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
9ed7528d1f man-generator: add check for option overlap
Report --check error, when the option is required and optional
for the command.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
7becd29494 lvconvert: fix _lvconvert_visible_check ret code
_lvconvert_visible_check() used to validate visibility
of converted LV for changing mirrorlog, regionsize
and merging images.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
3687f7fee3 lvconvert: validate converted LV to vdopool
Although our command-line description file describes
supported types for conversion with some rules,
these are technically not yet fully implemented in
the code, thus we need explicit functionality to
validate passed LVs for conversion.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
74c178f7bf lvconvert: fix move is positional args
Properly shift args by 1 - hopefully 'argv[]' has the right size
to fit this single shift (as some option must have been there...)
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
82789f6134 lvconvert: simplify passing LV for conversion
Since command is defined to not taky any'free args',
we can actully avoid playing with positional args here
and just pass argv with a single arg.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
30fdd6b9b4 args: update name of kernel module
Use  '_' for kernel module name.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
63088e1f82 command-lines.in: matching vdopool conversion
Just use options in the same order as with --type vdo-pool
conversion.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
579054452b command-lines.in update some description
Add some explicit warning for commands that are destroying content
of converted volume.

Add thinpooldata to the list of allow LVs for caching
(as the code already support this).
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
253ef42362 command-lines.in: add info about implicity type
Short description about how the default implied type
is selected for this lvcreate command.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
54831ecabd command: update parameter from description
Parameter --profile is already 'generic' parameter,
so it's been listed twice in lvchange & vgchange.

Parameter --uuid was listed 2x in pvchange.
2025-04-01 15:37:36 +02:00
Zdenek Kabelac
a4951801fa tools: add suppport to recognize thinpooldata 2025-04-01 15:37:36 +02:00
Zdenek Kabelac
d0c9bcf6d7 validation: add check for single vdo segments
Add check for VDO LV and VDOPOOL LV having just
a single segment in LV.
Also add couple missing '.'  in error messages.
2025-04-01 15:37:36 +02:00
David Disseldorp
43a755d568 device-types: support zram
See Linux source Documentation/admin-guide/blockdev/zram.rst .
zram devices offer a good performance and efficient resource utilization
through the use of compression.

Signed-off-by: David Disseldorp <ddiss@suse.de>
2025-04-01 15:37:36 +02:00
Bryn M. Reeves
12419e3b67 snapshot: fix lvresize when greater than max COW size
If lvresize is given a size > the maximum COW size for a given origin
the command will fail with an internal error and no error message:

  # lvresize --size 1.6g fedora/snaptest-snap
    Rounding size to boundary between physical extents: <1.59 GiB.
    Reached maximum COW size <1.01 GiB (258 extents).
    Command failed with status code 5.

  With -vvv:

  Found snapshot target v1.16.0.
  Getting target version for snapshot-origin
  dm versions   [ opencount flush ]   [2048] (*1)
  Found snapshot-origin target v1.9.0.
  Reached maximum COW size <1.01 GiB (258 extents). <<<
  Unlock: Memlock counters: prioritized:0 locked:0 critical:0 daemon:0 suspended:0
  Syncing device names
  Unlocking /run/lock/lvm/V_fedora
  _undo_flock /run/lock/lvm/V_fedora
  Freeing VG fedora at 0x55781b142890.
  Freeing VG fedora at 0x55781b136860.
  global/notify_dbus not found in config: defaulting to 1
  Destroy lvmcache content
  Completed: lvresize -vvv --debug --size 1706243072b fedora/snaptest-snap
  Internal error: Failed command did not use log_error

This happens because in this case _lvresize_adjust_extents() returns
early without setting lp->resize to either LV_EXTEND or LV_REDUCE after
capping lp->extents to the maximum COW size.

Fix this by just capping lp->extents and relying on the existing code in
_lvresize_adjust_extents() to fixup lp->resize in the case that
lp->extents == existing_logical_extents. This is consistent with the
no-op case where -l is given as the existing size:

root@localhost:~/src/git/lvm2# LD_LIBRARY_PATH="$PWD/tools" ./tools/lvm lvresize -L 1.6g fedora/snaptest-snap
  Rounding size to boundary between physical extents: 1.60 GiB.
  Reached maximum COW size <1.01 GiB (258 extents).
  New size (258 extents) matches existing size (258 extents).
  No size change.
2025-04-01 15:36:26 +02:00
Peter Rajnoha
0d17105292
libdm: report: select: remove fixme note from _create_field_selection
Let's keep the fail-safe check in for the case some combination (e.g.
after adding a new type) is not caught earlier in the _parse_selection.
2025-03-28 10:12:20 +01:00
Peter Rajnoha
1d94dd075d
libdm: report: select: add support for string list regex selection
The c065b407cb77a7a14d7c7c3c94e09fcca2fcff09..872e085030ae8039f18908f6e45bad7ba99250a7
was for device_mapper/libdm-report.c. Do the same for libdm/libdm-report.c
2025-03-25 12:17:27 +01:00
Peter Rajnoha
872e085030
WHATS_NEW: update 2025-03-25 10:25:08 +01:00
Peter Rajnoha
959f775985
tests: select-report: cover string list regex selection 2025-03-25 10:25:08 +01:00
Peter Rajnoha
0c970d8ec7
man: lvmreport: update parts about string list selection 2025-03-25 10:25:08 +01:00
Peter Rajnoha
8d41afbc1f
libdm: report: select: support string list selection based on a regex
Wire the field<-->selection comparison logic for regexes used for
string lists.
2025-03-25 10:25:08 +01:00
Peter Rajnoha
b4ebf69739
libdm: report: select: support parsing regex for a string list
Recognize regex in string list selection criterion, including grouping
items by using {} and [] together with && (or ",") and || (or "#")
logical operators:
  - [ <regex> && <regex> ... ]
  - [ <regex> || <regex> ... ]
  - { <regex> && <regex> ... ]
  - { <regex> || <regex> ... ]

Also recognize simple "<regex>" (without any grouping operators)
as a shortcut for "{ <regex> }".
2025-03-25 10:25:08 +01:00
Peter Rajnoha
8c696e463f
libdm: report: select: lower initial size for selection mempool
The selection doesn't use that much memory, adjust the size accordingly.
2025-03-25 10:25:08 +01:00
Peter Rajnoha
91c29c318f
libdm: report: selection: use separate regex mempool
Regex remembers the mempool it was given during dm_regex_create and
then it uses it for further allocation during dm_regex_match. This
could be dangerous in case we used the same mempool for any other
allocations/frees in between dm_regex_create and dm_regex_match calls
in the outer code. This patch adds separate regex mempool for the
report/select to avoid the possible issues.
2025-03-25 10:25:07 +01:00
Peter Rajnoha
d556d77363
libdm: report: select: default to subset if no grouping operator used
Previous patch made a proper difference between [...||...] and
[...&&...]. If the criterion for a string list does not use any [] or
{}, we need to make sure that proper matching function is called -
in this case not using {} or [] is the same as if {} was used
(matching subset).
2025-03-25 10:25:07 +01:00
Peter Rajnoha
649d17d221
tests: select-report: adjust test for matching [...||...] in string lists 2025-03-25 10:25:07 +01:00
Peter Rajnoha
b4a9897bd8
libdm: report: select: fix string list match for [...||...] selection
Matching a string list criterion which had [... || ... ] was not
correctly implemented - it was the same as [ ... && ... ]. This patch
makes a difference between the two:
  - [ ... || ... ] matches if all items from string list value are
    matched by ANY item from selection string list (that is, not
    all the selection string list items need to match)

  - [ ... && ... ] matches if all items from string list value are
    matched by an item from selection string list 1:1 (that is,
    all the selection string list items need to match)
2025-03-25 10:25:07 +01:00
Peter Rajnoha
523d796b15
libdm: report: select: remove superfluous struct reserved_value_wrapper param
Remove superfluous struct reserved_value_wrapper param for
_tok_value_regex function. The only thing that _tok_value did was
zeroing the reserve field within the struct. But this one is already
zero-initialied in outer _parse_selection function.
2025-03-25 10:25:07 +01:00
Peter Rajnoha
d9832565ec
libdm: report: select: make internal errors related to incorrect field types clearer 2025-03-25 10:25:07 +01:00
Peter Rajnoha
6565ce22b7
libdm: report: select: also log function name for internal errors 2025-03-25 10:25:07 +01:00
Peter Rajnoha
53ccbdab1b
libdm: report: select: add/edit comments for parser 2025-03-25 10:25:06 +01:00
Peter Rajnoha
c065b407cb
libdm: report: select: move regex handling under common value token parsing
This is a cleanup and a preparation for adding support for regex matching
in string lists in subsequent patches.
2025-03-24 14:39:11 +01:00
David Teigland
22b628924f tests: fix metadata-old with lvmlockd_test 2025-03-17 11:49:54 -05:00
Zdenek Kabelac
06baec439e make: generate 2025-03-17 13:52:03 +01:00
Zdenek Kabelac
92493361f3 WHATS_NEW: updates 2025-03-17 13:51:24 +01:00
Zdenek Kabelac
5efa388206 man: indent with command
Avoid spaces showing as the 1st. character on the man page line.
Also start with actual text and move .IP sequence to the line end.
2025-03-17 13:51:24 +01:00
Zdenek Kabelac
fe1cf7174f makefile: rebuild man when see_also changes
Missed rebuild dependency, when see_also file changes.
2025-03-17 13:48:58 +01:00
Zdenek Kabelac
6e5e7b3193 makefile: cleanup tab 2025-03-17 13:48:58 +01:00
Zdenek Kabelac
a6264f6a44 tests: don't restart lvmdbusd
Since lvmdbusd execution of lvm2 command was fixed
stop retrying to restart lvmdbuds and abort testig
when it fails.
2025-03-17 13:48:58 +01:00
Zdenek Kabelac
b2f8e744de lvm: option description only for man generator
There is no need to include option description text
within command binary itself.

It's only used only for man generating.
2025-03-17 13:48:58 +01:00
Zdenek Kabelac
01e4764c40 man: fixes in argument description
Describe missed --segments opt for lvdisplay (matches lvs).

Describe lvm-fullreport --all option - show text for lvs,vgs,pvs.

Missed '.' for --separator.
2025-03-17 13:48:58 +01:00
Zdenek Kabelac
c9ee8d8a06 lvmdbusd: ensure readout on exit 2025-03-17 13:48:58 +01:00
Zdenek Kabelac
154befd4b8 cache: ensure UUID ends with \0
Initialization of union is somewhat tricky as it initialize only
the first member + padding, but in our case this does not clear
the whole size of union so explicitly set \0 after 2 'struct id'
and make sure DM uuid is not using random characters from stack.

Also add explicit .id designators (c99).
2025-03-17 13:48:58 +01:00
David Teigland
951fd6358b metadata: replace pv status WRONG_VG with pv bit field
Avoid any special meaning associated with the status field.
2025-03-06 10:52:50 -06:00
David Teigland
8efbffe086 lvmcache: unpair wrong PV devs and improve duplicate name warnings
After detecting that a VG has wrongly claimed a PV, unpair
the pv->dev setting.  This will cause the usual "missing PV"
message to appear for that VG.  Make this message, and some
others, clearer by using the VGID rather than the VG name
when there are multiple VGs with the same name.
2025-03-06 10:02:29 -06:00
David Teigland
cff93e4d5c lvmcache: fix check for no pvid 2025-03-05 16:03:42 -06:00
David Teigland
227d3ca507 lvmcache: add WRONG_VG PV status flag
_vg_read() calls lvmcache_update_vg_from_read() which detects
that the VG metadata is incorrectly claiming the PV.  Flag this
condition in the PV status as WRONG_VG.  Later, vg_read() can
simply check the WRONG_VG flag rather than repeating the same
PV/VG checks that were already done in lvmcache_update_vg_from_read.
2025-03-05 14:28:42 -06:00
David Teigland
cc843151b4 lvmcache: ignore incorrect PV claim from old metadata
Outdated VG metadata that appears when an old device is attached
to the system can result in PVs appearing to belong to the
old/wrong VG, and commands are allowed to use (corrupt) the PVs.

- vgcreate old /dev/sda /dev/sdb /dev/sdc
- offline /dev/sda
- vgreduce --removemissing old
- vgremove old
- vgcreate new /dev/sdb /dev/sdc
- online /dev/sda

When sda is reattached, sdb and sdc will appear to be
in VG old again.  An attempt to correct the problem,
e.g. with vgremove old or vgreduce old, would modify
sdb and sdc, removing them from the new VG.

To fix this, check that sdb and sdc contain metadata for
VG old before allowing VG old to claim ownership of them.
With the fix, sdb and sdc are not displayed as part of
VG old, and commands to change VG old will fail as long
as it references incorrect PVs.

To fix VG old (sda), remove the incorrect PVs from VG old
while limiting the command to see only the correct PVs:
vgreduce --removemissing --devices /dev/sda old
2025-03-05 14:16:46 -06:00
David Teigland
7dd2f101c7 integrity: round meta size up to minimum one extent
If VG extents are larger than the required integrity metadata size,
use one extent as the size.
2025-03-03 11:31:40 -05:00
David Teigland
381b45b5a9 lvmlockd: add helpful error message for vgremove
Print a helpful error message when the lockspace is not started.
2025-03-03 11:05:04 -05:00
David Teigland
8273a6e2e1 pvresize: accept autobackup option 2025-02-27 10:05:27 -06:00
Marian Csontos
c59a8e2d56 doc: Update metadata on 2.03.31 release notes 2025-02-27 16:53:55 +01:00
Marian Csontos
a1e449dea2 post-release 2025-02-27 16:51:29 +01:00
Marian Csontos
3a6e221c56 pre-release 2.03.31 2025-02-27 16:51:29 +01:00
Marian Csontos
d80d346f4e doc: WHATS_NEW and release note update 2025-02-27 16:49:34 +01:00
Marian Csontos
54ade3a6bb doc: Apply markdown formatting 2025-02-27 16:12:52 +01:00
Eric Blake
1dcd9fbe08 misc: Typo fix s/loose/lose/
Signed-off-by: Eric Blake <eblake@redhat.com>
2025-02-26 10:32:19 +00:00
Eric Blake
a853649565 misc: Typo fix s/more then/more than/
Also a few instances of s/less then/less than/.

Signed-off-by: Eric Blake <eblake@redhat.com>
2025-02-26 10:32:19 +00:00
Zdenek Kabelac
a512bf3c62 WHATS_NEW: update 2025-02-26 01:35:12 +01:00
Zdenek Kabelac
9197880050 make: generate 2025-02-26 01:31:50 +01:00
Zdenek Kabelac
16bc80c389 test: check LVM_SUPPRESS_FD_WARNINGS
Add test for suppression messages about leaked descriptors.
2025-02-26 01:31:49 +01:00
Zdenek Kabelac
4fa6c76181 lvmlockd: drop return from void function 2025-02-26 01:31:49 +01:00
Zdenek Kabelac
b4c9f29eb3 man: update generator code
Generate pages more complaint with 'mandoc -T lint'
Remove some generated space on EOL.
Replace .ad l with .na  macro.
Remove some .br duplicates.
2025-02-26 01:30:31 +01:00
Zdenek Kabelac
8d855ff23a man: reformat args.h to fit in 80 lines
Compliance to mandoc -T lint to fit lines into 80 chars
in generated man pages.
2025-02-26 01:29:54 +01:00
Zdenek Kabelac
ba9c4368f4 man: updates
Updates for 'mandot -T lint'
Fit lines into 80 characters.
Use  .na .ad   instead of  .ad l  .ad b
Remove some misplaced  .P  & .br
Trim spaces for EOL.
2025-02-26 01:27:15 +01:00
Jack Wilsdon
1f728f370f libdaemon: fix suppressing stray fd warnings
Restore support for LVM_SUPPRESS_FD_WARNINGS as
this was seemingly lost with refactoring to
use daemon_close_stray_fds().
2025-02-26 01:21:19 +01:00
David Teigland
80ee9e45cb uncache and splitcache should restore inactive state
If an inactive LV is being cached in writeback mode, then
removing the cache does a temporary activation to flush
the cache back to the main LV.  However, it forgot to
deactivate the LV again, so the temporary activation
was left in place.
2025-02-25 15:48:28 -06:00
David Teigland
297808c269 lvmlockd: add debug line 2025-02-25 15:48:28 -06:00
David Teigland
dfb4ed13f6 lvmlockd: expand lockopt skip options
The lockopt options for skipping locks were not being used
in many places, making it impossible to override locking to
forcibly run some commands.
2025-02-25 12:40:36 -06:00
Zdenek Kabelac
be25429ea7 test: result is some for lvmpolld
Drop 'TEST WARNING' from this case - the code works the same
were for 'pvmove -b' polling as for lvmpolld.

Just keep there 'TODO' notice we want to eventually reduce amount
of 'worked' pvmove monitoring process - ATM there will be 1 per LV.
2025-02-25 01:10:04 +01:00
Salvatore Bonaccorso
36bdffb6a4 man: clarify --stripes number of device
The current manpage is unclear in the example of a raid10 type LV RAID
with --mirrors 1 --stripes 4. The number of devices in each raid1 mirror
is NumberStripes/(NumberMirrors+1). Thus the example should read:

e.g. mirrors 1 and stripes 4 will stripe data across two raid1
mirrors, where each mirror contains two devices.

Fixes: https://gitlab.com/lvmteam/lvm2/-/issues/26
Signed-off-by: Salvatore Bonaccorso <carnil@debian.org>
2025-02-25 01:10:04 +01:00
Dion Bosschieter
6f9e247285 man: fix grammar in lvmlockd.8_main
Remove redundant 'the' in 'When the another VG'.

Signed-off-by: Dion Bosschieter <dionbosschieter@gmail.com>
2025-02-25 01:10:04 +01:00
Tyler Clark
be0b2ea01a man: removing duplicate words in man pages.
This patch removes some sequentially duplicated words in a few man pages.
2025-02-25 01:10:04 +01:00
Zdenek Kabelac
d5ac344465 clang: match prototype 2025-02-25 01:10:04 +01:00
Zdenek Kabelac
4789abbcd2 cov: some missed arg_is_set changes 2025-02-25 01:10:04 +01:00
Zdenek Kabelac
a29d0c014a lvconvert: validate mirror image counting
Since _failed_mirrors_count() may eventually return -1,
add extra validation before using returned count.
2025-02-25 01:10:04 +01:00
Zdenek Kabelac
7d0acdbcb0 thin: fix checking monitor mode
Previous commit 874a8ab4d02a59c5 missed 'IGNORE' mode.
Fix it by adding rather 'explicit' test for this value,
so the code is better readable.

Also unlock memory earlier and drop unneeded <backtrace>
from return since we already logged error in this function.
2025-02-25 01:09:49 +01:00
David Teigland
5430eec2b9 lvmlockd: fix missing lvremove free_lv
Fix missing lockd_free_lv in commit
e3f0af8f1fd7 lvmlockd: fixes for lvremove
2025-02-24 16:36:01 -06:00
Zdenek Kabelac
d83f40d25a tests: reduce Exa test size
Since kernel patch 3d9a9e9a77c5ebecda43b514f2b9659644b904d0  (6.14)
it seem device size is no limitted to <8Exa bytes (so LLONG loff_t
works across whole device).

So reduce our tested size to 8191 Peta  ~ <8 Exa.
2025-02-24 18:59:58 +01:00
Zdenek Kabelac
c40bd459df test: wait for polling finish
Increase the used mirror size for longer processing.

Add more -vvvv traces to pvmove to better chase test error.

Add extra code to wait for finish of polling pvmove after it's
been aborted - so it doesn't break 'next' test.
2025-02-24 18:59:58 +01:00
Zdenek Kabelac
d016158ff9 WHATS_NEW: updates 2025-02-24 18:59:58 +01:00
Zdenek Kabelac
874a8ab4d0 cov: add value check 2025-02-24 18:59:58 +01:00
Zdenek Kabelac
0fe1613c9b cov: use arg_count for unchecked usage
Reserve usage of  'arg_is_set()' to tested use case and use
arg_count() for unchecked one.
2025-02-24 18:59:58 +01:00
Zdenek Kabelac
56398a2180 cov: explicitly ignore value 2025-02-24 18:59:58 +01:00
Bjarni Ingi Gislason
bb458e9528 man: remarks and editorial changes for dmstats
Use "groff -e ' $' -e '\\~$' <file>" to find obvious trailing spaces.
Use "mandoc -T lint  dmstats.8"
Use "test-groff -mandoc -t -ww -z dmstats.8"

-.-.

Lines containing '\c' (' \c' does not make sense):

503:.B \-\-units \c

-.-

Change '-' (\-) to '\(en' (en-dash) for a (numeric) range.
GNU gnulib has recently (2023-06-18) updated its
"build_aux/update-copyright" to recognize "\(en" in man pages.

dmstats.8:470:expressed as a hyphen separated range, for example: '1\-10'.

-.-.

Add a (no-break, "\ " or "\~") space between a number and a unit,
as these are not one entity.

1114:Create a 32M region 1G into device d0

-.-.

Add a "\&" after "e.g." and "i.e.", or use English words
(man-pages(7)).
Abbreviation points should be protected against being interpreted as
an end of sentence, if they are not, and that independent of the
current place on the line.

511:Can also specify custom units e.g. \fB\-\-units\ 3M\fP.

-.-.

Wrong distance between sentences in the input file.

  Separate the sentences and subordinate clauses; each begins on a new
line.  See man-pages(7) ("Conventions for source file layout") and
"info groff" ("Input Conventions").

  The best procedure is to always start a new sentence on a new line,
at least, if you are typing on a computer.

Remember coding: Only one command ("sentence") on each (logical) line.

-.-.

The name of a man page is typeset in bold and the section in roman
(see man-pages(7)).

798:extents). This currently includes \fBxfs(5)\fP and \fBext4(5)\fP.
801:group, and the group alias is set to the \fBbasename(3)\fP of the

-.-.

Use thousand markers to make large numbers easy to read

560:is equivalent to 10000000. Latency values with a precision of less than

-.-.

Remove quotes when there is a printable
but no space character between them
and the quotes are not for emphasis (markup),
for example as an argument to a macro.

1:.TH DMSTATS 8 "Jun 23 2016" "Linux" "MAINTENANCE COMMANDS"

-.-.

Output from "test-groff  -mandoc -t -K utf8 -rF0 -rHY=0 -rCHECKSTYLE=10 -ww -z ":

.-.

Additionally:

  Fix some arguments for '.TP'.  A single-font macro does not work with
'\c', so use a two-font macro.

-.-

  Use the pair ".na / .ad" to set no-adjustment (same result as '.ad l')
and '.ad' to restore previous adjustment.
[Replacing ".ad l" ... ".ad b"]

  Set singular '.ad b' to '.ad \*(AD' as the user should have the choice to
control the adjustment from the command line.

  Add an empty string to string 'AD' with '.as AD "\"' to avoid a warning
about an undefined string.

-.-

Generally:

Split (sometimes) lines after a punctuation mark; before a conjunction.

Updated-by: zkabelac@redhat.com
2025-02-24 18:59:58 +01:00
Bjarni Ingi Gislason
2fae69cc4b man: remarks and editorial changes for dmsetup
Checking for defects with a new version

Use test-[g|n]roff -mandoc -t -K utf8 -rF0 -rHY=0 -rCHECKSTYLE=10 -ww -z < "man page"
Use "groff -e ' $' -e '\\~$' <file>" to find obvious trailing spaces.
Use "mandoc -T lint  dmsetup.8":
Use "test-groff -mandoc -t -ww -z dmsetup.8":

-.-.

Add a (no-break, "\ " or "\~") space between a number and a unit,
as these are not one entity.

-.-.

Use "\e" to print the escape character instead of "\\" (which gets
interpreted in copy mode).

487:with its hex value (two digits) prefixed by \\x.

-.-.

Strings longer than 3/4 of a standard line length (80)
Use "\:" to split the string at the end of an output line, for example a
long URL (web address)

1030 <name>,<uuid>,\:<minor>,<flags>,\:<table>\:[,<table>+]\:[;<name>,<uuid>,\:<minor>,<flags>,<table>\:[,<table>+]]

-.-.

Add a "\&" after "e.g." and "i.e.", or use English words
(man-pages(7)).
Abbreviation points should be protected against being interpreted as
an end of sentence, if they are not, and that independent of the
current place on the line.

581:Note: Same cookie should be used for same type of operations i.e. creation of
767:Attempts to remove all device definitions i.e. reset the driver.  This also runs
946:e.g. striped 2 32 /dev/hda1 0 /dev/hdb1 0

-.-.

Wrong distance between sentences in the input file.

  Separate the sentences and subordinate clauses; each begins on a new
line.  See man-pages(7) ("Conventions for source file layout") and
"info groff" ("Input Conventions").

  The best procedure is to always start a new sentence on a new line,
at least, if you are typing on a computer.

Remember coding: Only one command ("sentence") on each (logical) line.

Mark a final abbreviation point as such by suffixing it with "\&".

Some sentences (etc.) do not begin on a new line.

Split (sometimes) lines after a punctuation mark; before a conjunction.

-.-.

Use \(en (en-dash) for a dash at the beginning (en) of a line,
or between space characters,
not a minus (\-) or a hyphen (-), except in the NAME section.

-.-.

Remove quotes when there is a printable
but no space character between them
and the quotes are not for emphasis (markup),
for example as an argument to a macro.

1:.TH DMSETUP 8 "Apr 06 2006" "Linux" "MAINTENANCE COMMANDS"

-.-.

Output from "test-groff  -mandoc -t -K utf8 -rF0 -rHY=0 -rCHECKSTYLE=10 -ww -z ":

Updated-by: <zkabelac@redhat.com>
2025-02-24 18:59:58 +01:00
Zdenek Kabelac
0d4418fe6c polldaemon: handle sigint from nanosleep
Handle interruption caught in sleep between polling and
abort() tool execution in such case.
(Although ATM we are not normally signalling the tool this way).
2025-02-24 18:59:58 +01:00
Zdenek Kabelac
bb66753a14 polldaemon: enhance error tracking
Improve error handling in polling functions where errors
were previously ignored. These errors result from serious
failures (e.g., allocation errors) and should lead to a full
command exit, as the tool cannot function in such a state.

FIXME:

However, there is a fundamental design issue worth considering:
when a command like pvmove --abort cancels an ongoing operation,
the existing polling command continues running and only terminates
once it detects that there is nothing left to poll.

Next issue is perment reopening of a VG when 'monitoring' progress.

And the last is big trouble with '--interval 0' which is able to
wait in DM ioctl() and hold the VG lock, and there is not good way
to about such operation (other then sending a signal to such process).
2025-02-24 18:59:58 +01:00
Zdenek Kabelac
c1bc0c9726 lvmpolld: easier alloc code
Share _free_lvmpolld_lv() function.
2025-02-24 18:59:58 +01:00
Zdenek Kabelac
685e704373 test: skip retry only for lvconvert
Mirror creation is creating log volumes and needs occasionally
retry loop for deactivation.
2025-02-24 18:59:58 +01:00
Zdenek Kabelac
4be1c7b6ca makefile: remove old lcov files
Remove any older lcov generated files ('*.gcda|gcno') then the currently
generated 'make.file' before creating a new lcov report.

Otherwise we may hit the problem of using some older generated files
possibly with different format.
2025-02-24 18:59:58 +01:00
Jianqi Zeng
36be0778f8 libdm: restore missing symbols
Restore missing symbols to the libdevmapper.so library.

These symbols:

dm_bitset_parse_list@@DM_1_02_138
and dm_tree_node_size_changed@Base

become 'lost' with commit: 40b277ae1799fc7a2e3f38b0abebd81a8e3d1995
which supposedly cleaned local 'symbols' from visibility,
however these missing symbols were impproperly exported.

Signed-off-by: Jianqi Zeng <zengjianqi@kylinos.cn>
2025-02-24 18:59:58 +01:00
David Teigland
6ad474385b lvmlockd: recognize error ELMERR 2025-02-20 10:18:28 -06:00
David Teigland
b02e6cd4a9 lvmlockd: disallow shared activation of LV with cow snapshot
The check for disallowing shared activation was missing
a check for this type.
2025-02-19 16:19:42 -06:00
Zdenek Kabelac
bb0bbc6d74 test: repeatedly restart lvmdbusd
It looks like occasionally supports_json() in cmdhandler.py
for some reason does not find  'fullreport' in err output
of lvm help...  let's see more traces...
2025-02-19 00:36:46 +01:00
Zdenek Kabelac
8417a6a578 revert "test: aux gives more time for lvmdbusd start"
This reverts commit 8425c1b468af0caf2e1e36d1eb1c1b399ee22489.

Seems we have different problem with lvmdbusd test start.
2025-02-19 00:36:46 +01:00
Zdenek Kabelac
79c022133b test: improve holding device open
Use 'exec' to open device and then just pass descriptor to sleep.
2025-02-19 00:36:46 +01:00
David Teigland
e3f0af8f1f lvmlockd: fixes for lvremove
The simple common case of locking the LV to remove with a
persistent lock would usually be fine, but there are a number
of special cases that were not addressed:
- no locking was done for removing cow snapshot
- direct locking to vdo pool
- dm-cache uncache using lvremove was not handled
2025-02-18 11:57:01 -06:00
David Teigland
5359737c29 lvmlockd: use lockd_lvcreate_lock for multiple LV types
Use the same lockd_lvcreate_lock() for all cases in which
creating a new LV first requires locking another associated
LV, e.g. locking the pool or origin for the new LV.
2025-02-18 11:50:52 -06:00
Zdenek Kabelac
b13b55884a test: add check for no such file 2025-02-17 15:51:03 +01:00
Zdenek Kabelac
da19ef49b1 cov: refactor code for warning
Refactor resizing loop, so Coverity no longer sees
the loop as 'infinite' and the code is also readable.
2025-02-17 15:51:03 +01:00
Zdenek Kabelac
03b78fa666 cov: refactor code
Refactor code, so Coverity doesn't complain about over-running
an array with char*.
(IMHO this seemed like a problem in Coverity code evaluation)
2025-02-17 15:51:03 +01:00
Zdenek Kabelac
a87cc133e2 cov: initialize arrays values 2025-02-17 15:51:03 +01:00
Zdenek Kabelac
07f23d4b81 clang: refactor code for easier alloc tracking
Refactor _get_split_name(). code to simplify detection of memory leak
in _destroy_split_name(). Now there are always just 2 pointers
instead of conditional pointer free() which is hard to follow.
2025-02-17 15:51:03 +01:00
Zdenek Kabelac
8bdc234348 clang: call alloca with non-zero size
Make sure that some non 0 size is also for (mirrors == 0).
2025-02-17 15:51:03 +01:00
Zdenek Kabelac
05f1e78f3e clang: pointer protection 2025-02-17 15:51:03 +01:00
Zdenek Kabelac
9f425a62fc clang: validate command before exec
Add extra check for command existence in argv before fork().
2025-02-17 15:51:03 +01:00
Zdenek Kabelac
1e91c16112 clang: use better readable code
Here we make sure, that we always free fopen() fp.
As theoretically we may have had opened 'stdout'.
2025-02-17 15:51:03 +01:00
Zdenek Kabelac
12efeb6d51 clang: validation 2025-02-17 15:51:03 +01:00
Zdenek Kabelac
5fd50ae192 tools: using proper header order
ARG_COUNT is generated by processing command_enums and
then it can be used by command.h.

So correct include order and later use command.h.
2025-02-17 15:51:03 +01:00
Zdenek Kabelac
5a6d318b29 cleanup: headers self compilable
In most cases header should be self-compilable, so the
do not expect other 'header' files to be used upfront
so the header would be compilable.

No functional change.
2025-02-17 15:51:03 +01:00
Zdenek Kabelac
924221765e cleanup: match function prototype with definition
Match variable name in function definition with
its prototype. Pick the name which better fits
the usage.

No functional change.
2025-02-17 15:51:03 +01:00
Zdenek Kabelac
a6b2ce6299 cleanup: project headers in front
Include project headers before system header files.
2025-02-17 15:51:03 +01:00
Zdenek Kabelac
464c30e6c3 clang: silence warning
Make the code pass through Coverity/clang.
As it didn't like theoretical access beyond
_yes[] & _no[] array elements.
2025-02-17 15:51:03 +01:00
Zdenek Kabelac
5e127fb8e9 clang: correcting imprecise prototype
These internal header were using misleading variable names
in function prototypes, but correct names were used in
function definition. Noticed with:

clang-tidy --checks=readability-inconsistent-declaration-parameter-name

No functional change.
2025-02-17 15:51:02 +01:00
Zdenek Kabelac
f66c76e5ea clang: make pointer defined 2025-02-17 15:51:02 +01:00
Zdenek Kabelac
3a700dd2f2 clang: add known mask value
Bit flags likely should never have been 'enum' but since
we have this in a public header - it might be hard to
replace this. So at least add missing 'enum' element
we use.
2025-02-17 15:51:02 +01:00
Zdenek Kabelac
bacd9f394d clang: check pointers 2025-02-17 15:51:02 +01:00
Zdenek Kabelac
cb0c43898a clang: pointer validation 2025-02-17 15:51:02 +01:00
Zdenek Kabelac
ff1f1188c3 clang: better visibility of non-null lock_type
clang can't see transient result, however
it would be still better to check for type string just once.
2025-02-17 15:51:02 +01:00
Zdenek Kabelac
9cc6b15dd9 clang: ensure defined value
Although this radix_tree_simple code is not being unused ATM...
2025-02-17 15:51:02 +01:00
Zdenek Kabelac
e737c54d8a clang: validate allocated buffer size
Validate for not using 0 size arg for allocation,
however this can never heapen for running code...
2025-02-17 15:51:02 +01:00
Zdenek Kabelac
1d13b391f8 clang: trace rewind errno
Although rewind() return void, it's API suggest
to check for 'errno' value.
2025-02-17 15:51:02 +01:00
Zdenek Kabelac
15b3cf1104 clang: reduce padding in struct cfg_def_item
Reorder struct members to minimize padding.
2025-02-17 15:51:02 +01:00
Zdenek Kabelac
4ff8c706db clang: reduce padding in struct command_name
Reorder struct members to minimize padding.
2025-02-17 15:51:02 +01:00
Zdenek Kabelac
0c3c08b95f clang: refactor code to always run inner loop
Make it more clear to analyzer the inner loop always runs.
Otherwise it may complain about *c being NULL.
2025-02-17 15:51:02 +01:00
Zdenek Kabelac
063984afde clang: valid area is required
Do not try to check references when verifying
LV segments with missing area.
2025-02-17 15:51:02 +01:00
Zdenek Kabelac
623e98e16c clang: ensure extents is usable
Although the code was exiting only for  (update == 0),
the later code actually used requires 'extents' to exist
also for  (update != 0).

TODO: The logic here is not very clear, more testing needed.
2025-02-17 15:49:54 +01:00
Zdenek Kabelac
f0a707f6b4 clang: fix double free in error path
When prefix insertion to radix_tree would fail, the error
path might try to possible double free allocated memory.
2025-02-17 15:41:53 +01:00
Zdenek Kabelac
bea43e4faa raid: set warn print level
Since there conversion messages are not causing direct
command error, switch message level to log_warn().
2025-02-17 15:41:53 +01:00
David Teigland
c326796a89 man lvm: add tag info
Restore basic info about tags that was dropped years ago
during the reworking for man page generation.
Also some other minor random updates.
2025-02-13 12:21:51 -06:00
David Teigland
fd341c818d lvcreate: accept lockopt option
The redundant lvcreate.c implementation of accepted options needs
to be removed.
2025-02-13 11:42:24 -06:00
Zdenek Kabelac
00a3664a5c test: improve for use with older systems
Improve test, so it's also working on systems without delay_dev
and test is actually more 'race' resistant.
2025-02-13 11:05:23 +01:00
Zdenek Kabelac
625a38c855 raid: remove struct overlap with possible_takeover
After reorganizing elements in `possible_takeover_reshape_type`
(in commit 5b92ce741f6bcb9b3d3c19c0fc13b972f950c560),
it became apparent that the code relied on struct overlap,
which is somewhat unsafe. This commit removes it and ensures
proper `const` qualification for the struct usage.
2025-02-13 11:04:30 +01:00
David Teigland
04cacff3b9 lvmlockd: lockd_vg return value cleanup 2025-02-12 11:16:16 -06:00
Zdenek Kabelac
852f3c20bb lcov: ignore some errors
While building lcov files - ignore errors from 'negative' counter
(perhaps we can use -fprofile-update=atomic - but it would be another
slowdown of test runs)

Also ignore unexecuted blocks warnings with 'gcov'.

Failure of lcov goal is not supposed to error whole make build.
2025-02-12 15:12:31 +01:00
Zdenek Kabelac
8a67936e7e cleanup: match prototype 2025-02-12 15:11:56 +01:00
Zdenek Kabelac
13fcb7e428 cleanup: use full source path to header 2025-02-12 15:11:56 +01:00
Zdenek Kabelac
736db4247c test: handle lvmpolling case
When test runs with lvmpolld - we cannot check
messages from pvmove - as those are visible through
output of lvmpolld - so just skip this and
only check LVs are in expected state.
2025-02-12 15:11:56 +01:00
Zdenek Kabelac
0bb06eb99b coverity: cleanup model code 2025-02-12 14:31:37 +01:00
Zdenek Kabelac
5b92ce741f gcc: better structure padding
Since we use '.option' to assign struct member - just suffle
structure element for better padding.
2025-02-12 14:31:37 +01:00
Zdenek Kabelac
c0b725d6e6 gcc: fabsf float based operation
Use 'float' version of 'fabs()' to compare floats.
2025-02-12 14:31:37 +01:00
Zdenek Kabelac
75a39003b0 clang: just use regular final else
There is no need to compare, so just keep 'if' part as the comment.
2025-02-12 14:31:37 +01:00
Zdenek Kabelac
e9640e5178 sanlock: more variable structure part to the end
Move variable part so there is no need to use 'gnu' compiler extension.
2025-02-12 13:55:29 +01:00
Zdenek Kabelac
e410715154 mirror: make sure 0 is not clz arg
Just make sure there will be never ever used '0'
as parameter for clz().
2025-02-12 13:55:29 +01:00
Zdenek Kabelac
d6934ea31d lvmcmdline: fix printed error messages
Since long_opt was changed to char[], we were only comparing pointers
that always exist, whereas the original intention of the test was
to verify the presence of a string
(i.e., checking that the first byte is not \0).
2025-02-12 13:55:22 +01:00
David Teigland
a1017024f1 raidintegrity: support removal of partial images
vgreduce --removemissing --force replaces a partial image
with an error target.  When that image includes an integrity
layer, that layer needs to first be removed.
2025-02-10 12:10:08 -06:00
Zdenek Kabelac
e7ae3fbd10 WHATS_NEW: update 2025-02-10 11:31:53 +01:00
Zdenek Kabelac
8425c1b468 test: aux gives more time for lvmdbusd start
Try 20s delay to see whether dbus service will be alive...
2025-02-10 11:31:53 +01:00
Zdenek Kabelac
7f12b5d0dc test: split mirror with opened leg 2025-02-10 11:31:53 +01:00
Zdenek Kabelac
550ce921fa test: check layout for error and zero 2025-02-10 11:31:53 +01:00
Zdenek Kabelac
d913d776d1 test: pvmove with open temporary volumes
Test pvmove logic when various pvmove mirror volumes are opened
while pvmove is finishing.
2025-02-10 11:31:53 +01:00
Zdenek Kabelac
a9fcc3ab0c gcc: compare same signedness 2025-02-10 11:31:53 +01:00
Zdenek Kabelac
a187f02ed5 vdo: correctly size string array
Fix logging of VDO configuration info message which has acutally
printed " and," using next element..
Increase the array element size so it can store >=5 bytes
for " and" + \0.
2025-02-10 11:31:53 +01:00
Zdenek Kabelac
74a2325261 mirror: splitting handles opened devices
Similar to the pvmove update, enhance error path handling
for scenarios where legs or logs remain open and cannot be
closed during the splitting of a mirror image.

Remove the now obsolete _delete_lv() function,
as it will no longer be needed.
2025-02-10 11:31:53 +01:00
Zdenek Kabelac
be1b83a76f mirror: move status bit masking
Use bit masking in replace_lv_with_error_segment().
2025-02-10 11:31:53 +01:00
Zdenek Kabelac
87a4e7bb68 debug: update message for pvmove
Add some more consistency to message printed for pvmove.
2025-02-10 11:31:53 +01:00
Zdenek Kabelac
7858c25427 debug: use more similar skipping messages 2025-02-10 11:31:53 +01:00
Zdenek Kabelac
425ae9aaf0 debug: reinitialize debug pid after fork 2025-02-10 11:31:53 +01:00
Zdenek Kabelac
2a34723511 lv_manip: print layout for error and zero 2025-02-10 11:31:53 +01:00
Zdenek Kabelac
ed9468153e mirror: enhance error path for pvmove finish
When the pvmove operation is completing, it attempts to deactivate
the temporary mirror and remove its mirror legs. However,
if an external tool holds these volumes open, the operation would
previously abort entirely, leaving the LVM2 metadata in a partially
unusable state that required manual administrative fixes.

To improve this, the code has been enhanced to handle such scenarios
more gracefully. It will now complete the pvmove operation even
if some volumes cannot be deactivated, marking them in the metadata
with an error segment. While the command will report errors,
the metadata will remain in a usable state. The administrator
can then remove the orphaned volumes when they are no longer in use.
2025-02-10 11:31:52 +01:00
David Teigland
09e508cd43 devices file: fix backup limit
Fix the code that limited the total number of backup files.
It failed, and left excess files, when the file version
number was greated than 9999, exceeding the four digit suffix.

Now, after version 9999, the suffix intentionally grows beyond
four digits as needed, and is not a fixed width, or zero padded.
2025-02-05 20:40:59 -06:00
Zdenek Kabelac
a6408163dd lvmlockd: correct prototype for sanlock-less build 2025-02-03 10:45:09 +01:00
Zdenek Kabelac
c68af364e7 lvmlockd: compilation fixes 2025-02-02 20:06:10 +01:00
Zdenek Kabelac
d5cc65f683 gcc: std=c11 for test suite as well 2025-02-02 20:00:44 +01:00
Zdenek Kabelac
082d475ea9 debug: missed stack tracing 2025-02-02 20:00:44 +01:00
Zdenek Kabelac
29bb84f17b raid: refactor code to _raid_leg_degraded
Move common code into _raid_leg_degraded().
2025-02-02 20:00:44 +01:00
David Teigland
48d7511808 lvmlockd: fix free_lv immediately after init_lv
Fix for recent commit "lvmlockd: free resource structs for LVs"

When a vg_write() fails in lvcreate, lvmlockd sees init_lv()
followed by free_lv().  The LV lock is not acquired prior to
free_lv, and no prior resource struct exists. This wasn't being
handled.
2025-01-31 18:38:39 -06:00
David Teigland
ffeee23537 lvmlockd: log correct name in error path
fix for recent "lvmlockd: free resource structs for LVs"
2025-01-30 16:38:33 -06:00
Zdenek Kabelac
46a48f1320 vg_read: correct error path for DM cache update
New code for updating DM cache traveled through couple destination
however in this place only 'return_0' is missing unlocking in
error path.
2025-01-30 20:02:25 +01:00
Zdenek Kabelac
2c63b12bd3 tests: more info from test 2025-01-30 17:26:08 +01:00
Zdenek Kabelac
36ae51c3cb dev-type: require 4k only for some topology attrs
Previous commit 5f71cebcbecc37b5291018da35b3efe9636bf6c3 was not
correct. 4k requirement cannot be put on attribute_offset - where
it is valid to have this only 512b aligned.
The rule might get more complicated to recognized invalid values.
For this moment however add more easier requirement - we
impose 4K restriction on minimal and optimal io size if they
are bigger then 1 sector (512B).
2025-01-30 17:23:45 +01:00
Zdenek Kabelac
1e21b0a6f2 WHATS_NEW: update 2025-01-30 13:38:31 +01:00
Zdenek Kabelac
12f1472972 cov: annotate 2025-01-30 13:38:31 +01:00
Zdenek Kabelac
1719f1169f cov: ensure buffer does not underflow
Add explicit check for having always positive value.
2025-01-30 13:38:31 +01:00
Zdenek Kabelac
d32ee0b7ab cov: avoid expression overflow
Keep max memory in MiB  (>> 20).
2025-01-30 13:38:31 +01:00
Zdenek Kabelac
42a43c37de cov: explicitly ignore return codes 2025-01-30 13:38:31 +01:00
Zdenek Kabelac
583e5f952e cov: add validation of FID pointer
Ensure NULL theoretical NULL FID pointer is not
dereferenced.
2025-01-30 13:38:31 +01:00
Zdenek Kabelac
fd91edfd15 cov: limit buffer size for sscanf
Limit sscanf parser buffer width for string.
2025-01-30 13:38:31 +01:00
Zdenek Kabelac
51030c57a1 cov: use bigger buffer
Since pvck's  _check_vgname_start is actually checking
up-to (NAME_LEN + 2) bytes  (130),
use at least this size for (MAX_LINE_CHECK + 3).
2025-01-30 13:38:31 +01:00
Zdenek Kabelac
1e21a93ead cov: limit log levels to 7
lvm2 is using 7 levels for logging.
(Which might be already probably too much...)
2025-01-30 13:38:31 +01:00
Zdenek Kabelac
cae445443e cov: add sscanf width specifiers for lvmlockctl 2025-01-30 13:38:31 +01:00
Zdenek Kabelac
f582c7be1d cov: add space for string 0
Sscan may automatically add 0 after field width mark,
and since it's not exactlu trivial to do a macro calculation
for PATH_MAX - 1, rather make buffer for sscanf results bigger.

Also use matching FSTYPE_MAX as field width specifier.
2025-01-30 13:38:31 +01:00
Zdenek Kabelac
09d896810b cov: add extra byte for 0
Since we use 'DM_NAME_LEN' size for sscanf - it may need to store
extra string 0, which is added automatically after 'maximum field
width' specifier.
2025-01-30 13:38:31 +01:00
Zdenek Kabelac
07b595d0f3 gcc: updates for use with std=c11
Let gcc -std=c11 pass...
Useful i.e. to get working Coverity scan ATM.
(as gcc15 and stdbool changes makes it problematic.)
2025-01-30 13:38:31 +01:00
Zdenek Kabelac
9fe73c8d95 debug: drop double '/' in created pathname
Our cmd->dev_dir already has '/dev/' so do not use '/dev//devname'.
2025-01-30 13:38:31 +01:00
Zdenek Kabelac
27f0ca79cc tests: update topology test
Check lvm2 create usable VG for optimal_io_size 16776704
(which is not divisible by 4KiB).
2025-01-30 13:38:31 +01:00
Zdenek Kabelac
5f71cebcbe dev-types: ignore non-4K divisible topology values
When topology value is bigger then 1 sector (512b)
we require 4K divisibility for them.
2025-01-30 13:38:03 +01:00
Zdenek Kabelac
e907c3cf9a config: check for 0 from read
When the read returns 0, it could mean the file
was trimmed or some other type of problem.
In this case abort the potentially endless loop.
2025-01-30 13:38:03 +01:00
Zdenek Kabelac
b32c0bb9c5 vg_read: matching missed empty cache
lvm2 is caching DM nodes with the use of DM_LIST_DEVICES ioctl().
And tried to preserve the cached structure for the same list,
however there was 1 case where cache was empty, and new LIST ioctl
returned some elements - if this DM table change has happened
in the moment of 'scanning' and locking -  lvm2 has then continued
to use 'invalid' empty cache.

Fix by capturing this missed case and update cache properly.

TODO: we could possibly use plain memcmp() with previous ioctl result.
2025-01-30 13:37:19 +01:00
Zdenek Kabelac
dd09127608 vg_read: rescanning DM cache after taking lock
Since we started to use DM cache now also for basic checks
whether the DM devices is present in DM table, this cache
now needs to be actually refreshed when the LOCK is taken.
This hiddenly happend if there was enabled 'scan_lvs' however
still not at the right place.

Move this explicit cache update call right after the moment
vg_read grabs the lock.

TODO: in the optimal case, we should mark the 'cache invalid'
and later refresh this cache, when the first reader appears,
but since this would be large patch, do this little fix step patch
first and improve performance later.
2025-01-30 13:33:37 +01:00
David Teigland
76b1776367 lvmlockd: fix thin locking case for cow snapshot
The case of lvcreate creating a cow snapshot of a thin volume was
caught by the sanity check for any missed instances of thin locking.
2025-01-29 18:10:00 -06:00
David Teigland
ebb90fd2c6 lvmlockd: free resource structs for LVs
Once created, resource structs for LVs were never being freed.
If LVs are activated, then later removed or never used again,
the unused structs waste memory and cause the resource list
to grow.
2025-01-23 15:57:46 -06:00
David Teigland
7d7b5db230 lvmlockd: thin locking improvements
There was a lot of messy and inefficient locking calls sent from
a command to lvmlockd when working with thin volumes, e.g.
- requesting a lock numerous times that was already held
- releasing a lock numerous times that was already unlocked
- repeating lock/unlock/lock/unlock rather than holding the
  lock until it was no longer needed

Mistakes in the locking could easily hide among all the noise.

The mess was largely because thin-related commands involve a
lot of internal LV manipulations, and lvmlockd calls were done
at the lower level of LV activation/deactivation.  This change
adds locking code that is more specific to the thin command
being run, so it can be more intelligent in acquiring and
releasing locks where needed.
2025-01-17 14:06:21 -06:00
David Teigland
c2cf9a4cae lvmlockd: debug log message improvements 2025-01-17 14:01:17 -06:00
David Teigland
84aa248f07 lvmlockd: reject bogus lease offset values 2025-01-17 14:00:34 -06:00
Marian Csontos
6c2debf917 doc: Release Notes for 2.03.30 2025-01-14 20:57:47 +01:00
Marian Csontos
6de7c51dce post-release 2025-01-14 20:55:33 +01:00
280 changed files with 6018 additions and 3422 deletions

View File

@ -172,7 +172,7 @@ help:
@echo " lcov-dated Generate lcov with timedate suffix."
@echo " lcov-reset Reset lcov counters"
@echo " man Build man pages."
@echo " print-VARIABLE Resolve make variable."
@echo " print-VARIABLE Resolve make variable."
@echo " rpm Build rpm."
@echo " run-unit-test Run unit tests."
@echo " tags Generate c/etags."
@ -194,7 +194,8 @@ ifneq ("$(GENHTML)", "")
lcov:
$(RM) -rf $(LCOV_REPORTS_DIR)
$(MKDIR_P) $(LCOV_REPORTS_DIR)
$(LCOV) --capture --directory $(top_builddir) --ignore-errors source \
-find . -name '*.gc[dn][ao]' ! -newer make.tmpl -delete
-$(LCOV) --capture --directory $(top_builddir) --ignore-errors source,negative,gcov \
--output-file $(LCOV_REPORTS_DIR)/out.info
-test ! -s $(LCOV_REPORTS_DIR)/out.info || \
$(GENHTML) -o $(LCOV_REPORTS_DIR) --ignore-errors source \

View File

@ -1 +1 @@
2.03.30(2) (2025-01-14)
2.03.32(2)-git (2025-02-27)

View File

@ -1 +1 @@
1.02.204 (2025-01-14)
1.02.206-git (2025-02-27)

View File

@ -1,3 +1,29 @@
Version 2.03.32 -
==================
Lvconvert vdopool conversion propperly validates acceptable LVs.
Accept thin pool data LV as cachable LV.
Allow using zram block devices (likely for testing).
Fix lvresize when resizing COW snapshots already covering origin.
Fix lvmdbusd read of executed lvm commands output.
Fix construction of DM UUID for cachevol _cdata and _cmeta devices.
Version 2.03.31 - 27th February 2025
====================================
Reduce 'mandoc -T lint' reported issues for man pages.
Restore support for LVM_SUPPRESS_FD_WARNINGS (2.03.24).
Fix uncache and split cache restoring original state of volume.
Extend use of lockopt skip to more scenarios.
Enhance error path resolving in polling code.
Disallow shared activation of LV with CoW snapshot.
Fix lvmlockd use in lvremove of CoW snapshot, VDO pool, and uncache.
Improve mirror split with opened temporary volumes.
Improve pvmove finish with opened temporary volumes.
Fix backup limit for devices file, handle over 10,000 files.
Ignore reported optimal_io_size not divisible by 4096.
Fix busy-loop in config reading when read returned 0.
Fix DM cache preserving logic (2.03.28).
Improve use of lvmlockd for usecases involving thin volumes and pools.
Version 2.03.30 - 14th January 2025
===================================
Lvresize reports origin vdo volume cannot be resized.

View File

@ -1,3 +1,13 @@
Version 1.02.206 -
===================
Add support for using regex in selection criteria for string lists.
Fix string list selection when using [<item> || <item> ...].
Version 1.02.205 - 27th February 2025
=====================================
Restore missing symbol dm_tree_node_size_changed@Base (1.02.175).
Restore missing symbol dm_bitset_parse_list@@DM_1_02_138 (1.02.175).
Version 1.02.204 - 14th January 2025
====================================
Create /dev/disk/by-diskseq/<DISKSEQ> symlink for public DM devices.
@ -270,7 +280,7 @@ Version 1.02.136 - 5th November 2016
Still produce output when dmsetup dependency tree building finds dev missing.
Check and report pthread_sigmask() failure in dmeventd.
Check mem alloc fail in _canonicalize_field_ids().
Use unsigned math when checking more then 31 legs of raid.
Use unsigned math when checking more than 31 legs of raid.
Fix 'dmstats delete' with dmsetup older than v1.02.129
Fix stats walk segfault with dmsetup older than v1.02.129

View File

@ -279,7 +279,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
pc->len = i;
if (!_insert(rt, &pc->child, kb + i, ke, rv)) {
free(pc2);
free(pc->child.value.ptr);
return false;
}
@ -293,6 +293,7 @@ static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, const u
if (pc->len == 1) {
n4->values[0] = pc->child;
free(pc);
v->value.ptr = NULL;
} else {
memmove(pc->prefix, pc->prefix + 1, pc->len - 1);
pc->len--;

View File

@ -193,12 +193,12 @@ bool radix_tree_remove(struct radix_tree *rt, const void *key, size_t keylen)
return true;
}
unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *key, size_t keylen)
unsigned radix_tree_remove_prefix(struct radix_tree *rt, const void *prefix, size_t prefix_len)
{
const uint8_t *kb = key;
const uint8_t *ke = kb + keylen;
const uint8_t *kb = prefix;
const uint8_t *ke = kb + prefix_len;
struct node **pn;
unsigned count;
unsigned count = 0;
pn = _lookup(&rt->root, kb, ke);
@ -280,7 +280,7 @@ static void _dump(FILE *out, struct node *n, unsigned indent)
fprintf(out, " ");
if (n->has_value) {
fprintf(out, "value: %llu\n", n->value.n);
fprintf(out, "value: %lu\n", (unsigned long) n->value.n);
} else {
fprintf(out, "key: '%c' [0x%02x] %u\n",
isprint(n->key) ? n->key : ' ', n->key, indent);

View File

@ -586,7 +586,7 @@ allocation {
# Configuration option allocation/thin_pool_crop_metadata.
# Older version of lvm2 cropped pool's metadata size to 15.81 GiB.
# This is slightly less then the actual maximum 15.88 GiB.
# This is slightly less than the actual maximum 15.88 GiB.
# For compatibility with older version and use of cropped size set to 1.
# This configuration option has an automatic default value.
# thin_pool_crop_metadata = 0

View File

@ -30,6 +30,8 @@
struct lv_segment;
struct logical_volume;
struct cmd_context;
struct profile;
struct lv_segment *first_seg(const struct logical_volume *lv)
{
@ -57,7 +59,7 @@ struct logical_volume *origin_from_cow(const struct logical_volume *lv)
*/
/* simple_memccpy() from glibc */
void *memccpy(void *dest, const void *src, int c, size_t n)
void *memccpy(void *dest, const void *src, int c, unsigned long n)
{
const char *s = src;
char *d = dest;
@ -90,9 +92,14 @@ void model_FD_ZERO(void *fdset)
/* Resent Coverity reports quite weird errors... */
int *__errno_location(void)
{
static int _i = 0;
return &_i;
}
const unsigned short **__ctype_b_loc (void)
{
static const unsigned short *_a[1] = { 0 };
return _a;
}

View File

@ -8,6 +8,8 @@
#ifndef _LVM_CLOG_COMPAT_H
#define _LVM_CLOG_COMPAT_H
#include <stddef.h>
/*
* The intermachine communication structure version are:
* 0: Unused
@ -19,6 +21,8 @@
*/
#define CLOG_TFR_VERSION 5
struct clog_request;
int clog_request_to_network(struct clog_request *rq);
int clog_request_from_network(void *data, size_t data_len);

View File

@ -12,6 +12,8 @@
#ifndef _LVM_CLOG_LOCAL_H
#define _LVM_CLOG_LOCAL_H
struct dm_ulog_request;
int init_local(void);
void cleanup_local(void);

View File

@ -268,7 +268,7 @@ static void _free_dso_data(struct dso_data *data)
static struct dso_data *_alloc_dso_data(struct message_data *data)
{
struct dso_data *ret = (typeof(ret)) zalloc(sizeof(*ret));
struct dso_data *ret = (__typeof__(ret)) zalloc(sizeof(*ret));
if (!ret)
return_NULL;

View File

@ -15,6 +15,8 @@
#ifndef __DMEVENTD_DOT_H__
#define __DMEVENTD_DOT_H__
#include <stdint.h>
/* FIXME This stuff must be configurable. */
#define DM_EVENT_FIFO_CLIENT DEFAULT_DM_RUN_DIR "/dmeventd-client"

View File

@ -29,20 +29,23 @@
*/
enum dm_event_mask {
DM_EVENT_SETTINGS_MASK = 0x0000FF,
DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */
DM_EVENT_MULTI = 0x000002, /* Report all of them. */
DM_EVENT_SETTINGS_MASK = 0x0000FF,
DM_EVENT_ERROR_MASK = 0x00FF00,
DM_EVENT_SECTOR_ERROR = 0x000100, /* Failure on a particular sector. */
DM_EVENT_DEVICE_ERROR = 0x000200, /* Device failure. */
DM_EVENT_PATH_ERROR = 0x000400, /* Failure on an io path. */
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */
DM_EVENT_ERROR_MASK = 0x00FF00,
DM_EVENT_STATUS_MASK = 0xFF0000,
DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
DM_EVENT_TIMEOUT = 0x020000, /* Timeout has occurred */
DM_EVENT_ERROR_AND_TIMEOUT_MASK = 0x02FF00,
DM_EVENT_STATUS_MASK = 0xFF0000,
DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */
};
@ -70,10 +73,10 @@ int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path);
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path);
/*
* Identify the device to monitor by exactly one of device_name, uuid or
* Identify the device to monitor by exactly one of dev_name, uuid or
* device number. String arguments are duplicated, see above.
*/
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *device_name);
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name);
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid);

View File

@ -25,6 +25,8 @@
#ifndef _DMEVENTD_LVMWRAP_H
#define _DMEVENTD_LVMWRAP_H
#include <stddef.h>
struct dm_pool;
int dmeventd_lvm2_init(void);

View File

@ -112,7 +112,7 @@ static int _remove_failed_devices(const char *cmd_lvconvert, const char *device)
}
void process_event(struct dm_task *dmt,
enum dm_event_mask event __attribute__((unused)),
enum dm_event_mask evmask __attribute__((unused)),
void **user)
{
struct dso_state *state = *user;

View File

@ -114,7 +114,7 @@ out:
}
void process_event(struct dm_task *dmt,
enum dm_event_mask event __attribute__((unused)),
enum dm_event_mask evmask __attribute__((unused)),
void **user)
{
struct dso_state *state = *user;

View File

@ -163,7 +163,7 @@ static void _umount(const char *device, int major, int minor)
}
void process_event(struct dm_task *dmt,
enum dm_event_mask event __attribute__((unused)),
enum dm_event_mask evmask __attribute__((unused)),
void **user)
{
struct dso_state *state = *user;

View File

@ -155,7 +155,7 @@ static int _wait_for_pid(struct dso_state *state)
}
void process_event(struct dm_task *dmt,
enum dm_event_mask event __attribute__((unused)),
enum dm_event_mask evmask,
void **user)
{
const char *device = dm_task_get_name(dmt);
@ -179,7 +179,7 @@ void process_event(struct dm_task *dmt,
return;
}
if (event & DM_EVENT_DEVICE_ERROR) {
if (evmask & DM_EVENT_DEVICE_ERROR) {
/* Error -> no need to check and do instant resize */
state->data_percent = state->metadata_percent = 0;
if (_use_policy(dmt, state))

View File

@ -146,7 +146,7 @@ static int _wait_for_pid(struct dso_state *state)
}
void process_event(struct dm_task *dmt,
enum dm_event_mask event __attribute__((unused)),
enum dm_event_mask evmask __attribute__((unused)),
void **user)
{
const char *device = dm_task_get_name(dmt);
@ -169,7 +169,7 @@ void process_event(struct dm_task *dmt,
return;
}
if (event & DM_EVENT_DEVICE_ERROR) {
if (evmask & DM_EVENT_DEVICE_ERROR) {
#if VDO_DEBUG
log_debug("VDO event error.");
#endif

View File

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

View File

@ -97,8 +97,9 @@ static void save_client_info(char *line)
uint32_t client_id = 0;
char name[MAX_NAME+1] = { 0 };
(void) sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
&pid, &fd, &pi, &client_id, name);
(void) sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%"
DM_TO_STRING(MAX_NAME) "s",
&pid, &fd, &pi, &client_id, name);
clients[num_clients].client_id = client_id;
clients[num_clients].pid = pid;
@ -129,8 +130,11 @@ static void format_info_ls(char *line)
char lock_args[MAX_ARGS+1] = { 0 };
char lock_type[MAX_NAME+1] = { 0 };
(void) sscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_args=%s lm_type=%s",
ls_name, vg_name, vg_uuid, lock_args, lock_type);
(void) sscanf(line, "info=ls ls_name=%" DM_TO_STRING(MAX_NAME) "s vg_name=%"
DM_TO_STRING(MAX_NAME) "s vg_uuid=%" DM_TO_STRING(MAX_NAME)
"s vg_args=%" DM_TO_STRING(MAX_NAME) "s lm_type=%"
DM_TO_STRING(MAX_NAME) "s",
ls_name, vg_name, vg_uuid, lock_args, lock_type);
if (!first_ls)
printf("\n");
@ -150,8 +154,11 @@ static void format_info_ls_action(char *line)
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
(void) sscanf(line, "info=ls_action client_id=%u %s %s op=%s",
&client_id, flags, version, op);
(void) sscanf(line, "info=ls_action client_id=%u %"
DM_TO_STRING(MAX_NAME) "s %"
DM_TO_STRING(MAX_NAME) "s op=%"
DM_TO_STRING(MAX_NAME) "s",
&client_id, flags, version, op);
find_client_info(client_id, &pid, cl_name);
@ -166,8 +173,10 @@ static void format_info_r(char *line, char *r_name_out, char *r_type_out)
char sh_count[MAX_NAME+1] = { 0 };
uint32_t ver = 0;
(void) sscanf(line, "info=r name=%s type=%s mode=%s %s version=%u",
r_name, r_type, mode, sh_count, &ver);
(void) sscanf(line, "info=r name=%" DM_TO_STRING(MAX_NAME)
"s type=%3s mode=%3s %"
DM_TO_STRING(MAX_NAME) "s version=%u",
r_name, r_type, mode, sh_count, &ver);
strcpy(r_name_out, r_name);
strcpy(r_type_out, r_type);
@ -204,8 +213,9 @@ static void format_info_lk(char *line, char *r_name, char *r_type)
return;
}
(void) sscanf(line, "info=lk mode=%s version=%u %s client_id=%u",
mode, &ver, flags, &client_id);
(void) sscanf(line, "info=lk mode=%3s version=%u %"
DM_TO_STRING(MAX_NAME) "s client_id=%u",
mode, &ver, flags, &client_id);
find_client_info(client_id, &pid, cl_name);
@ -240,8 +250,11 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
return;
}
(void) sscanf(line, "info=r_action client_id=%u %s %s op=%s rt=%s mode=%s %s %s %s",
&client_id, flags, version, op, rt, mode, lm, result, lm_rv);
(void) sscanf(line, "info=r_action client_id=%u %" DM_TO_STRING(MAX_NAME)
"s %" DM_TO_STRING(MAX_NAME) "s op=%" DM_TO_STRING(MAX_NAME)
"s rt=%3s mode=%3s %" DM_TO_STRING(MAX_NAME) "s %"
DM_TO_STRING(MAX_NAME) "s %" DM_TO_STRING(MAX_NAME) "s",
&client_id, flags, version, op, rt, mode, lm, result, lm_rv);
find_client_info(client_id, &pid, cl_name);

View File

@ -11,7 +11,7 @@
#include "tools/tool.h"
#include "libdaemon/client/daemon-io.h"
#include "daemon-server.h"
#include "libdaemon/server/daemon-server.h"
#include "lvm-version.h"
#include "daemons/lvmlockd/lvmlockd-client.h"
#include "device_mapper/misc/dm-ioctl.h"
@ -416,6 +416,7 @@ struct lockspace *alloc_lockspace(void)
INIT_LIST_HEAD(&ls->actions);
INIT_LIST_HEAD(&ls->resources);
INIT_LIST_HEAD(&ls->dispose);
pthread_mutex_init(&ls->mutex, NULL);
pthread_cond_init(&ls->cond, NULL);
return ls;
@ -754,7 +755,7 @@ static const char *rt_str(int x)
case LD_RT_LV:
return "lv";
default:
return ".";
return "";
};
}
@ -999,7 +1000,7 @@ static int read_adopt_file(struct list_head *vg_lockd)
memset(vg_uuid, 0, sizeof(vg_uuid));
memset(mode, 0, sizeof(mode));
if (sscanf(adopt_line, "LV: %64s %64s %s %7s %u",
if (sscanf(adopt_line, "LV: %64s %64s %64s %7s %u",
vg_uuid, r->name, r->lv_args, mode, &r->version) != 5) {
free_resource(r);
goto fail;
@ -1092,6 +1093,20 @@ static int lm_rem_lockspace(struct lockspace *ls, struct action *act, int free_v
return rv;
}
static int lm_add_resource(struct lockspace *ls, struct resource *r)
{
int rv = -1;
if (ls->lm_type == LD_LM_DLM)
rv = lm_add_resource_dlm(ls, r, 0);
else if (ls->lm_type == LD_LM_SANLOCK)
rv = lm_add_resource_sanlock(ls, r);
else if (ls->lm_type == LD_LM_IDM)
rv = lm_add_resource_idm(ls, r);
return rv;
}
static int lm_lock(struct lockspace *ls, struct resource *r, int mode, struct action *act,
struct val_blk *vb_out, int *retry, int adopt_only, int adopt_ok)
{
@ -1666,20 +1681,32 @@ static int res_unlock(struct lockspace *ls, struct resource *r,
{
struct lock *lk;
uint32_t r_version;
int found_transient = 0;
int found_persistent = 0;
int rv;
if (act->flags & LD_AF_PERSISTENT) {
lk = find_lock_persistent(r);
if (lk)
goto do_unlock;
if (find_lock_client(r, act->client_id))
found_transient = 1;
} else {
lk = find_lock_client(r, act->client_id);
if (lk)
goto do_unlock;
if (find_lock_persistent(r))
found_persistent = 1;
}
if (act->op != LD_OP_CLOSE)
log_debug("%s:%s res_unlock cl %u no locks", ls->name, r->name, act->client_id);
if (act->op != LD_OP_CLOSE) {
if (found_transient)
log_debug("%s:%s res_unlock cl %u ENOENT (found transient)", ls->name, r->name, act->client_id);
else if (found_persistent)
log_debug("%s:%s res_unlock cl %u ENOENT (found persistent)", ls->name, r->name, act->client_id);
else
log_debug("%s:%s res_unlock cl %u ENOENT (no lock)", ls->name, r->name, act->client_id);
}
return -ENOENT;
do_unlock:
@ -1876,6 +1903,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
{
struct action *act, *safe, *act_close;
struct lock *lk;
uint32_t unlock_by_client_id = 0;
int lm_retry;
int rv;
@ -1909,6 +1937,9 @@ static void res_process(struct lockspace *ls, struct resource *r,
if (rv == -ENOENT && (act->flags & LD_AF_UNLOCK_CANCEL))
rv = res_cancel(ls, r, act);
if (!rv && r->mode == LD_LK_UN)
unlock_by_client_id = act->client_id;
/*
* possible unlock results:
* 0: unlock succeeded
@ -1932,22 +1963,6 @@ static void res_process(struct lockspace *ls, struct resource *r,
res_cancel(ls, r, act_close);
}
/*
* handle freeing a lock for an lv that has been removed
*/
list_for_each_entry_safe(act, safe, &r->actions, list) {
if (act->op == LD_OP_FREE && act->rt == LD_RT_LV) {
log_debug("%s:%s free_lv", ls->name, r->name);
rv = free_lv(ls, r);
act->result = rv;
list_del(&act->list);
add_client_result(act);
goto r_free;
}
}
/*
* handle enable/disable
*/
@ -2091,6 +2106,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
* be held for reading. If the T lock was sh, it would
* be converted to P ex. If the T/P modes matched, the
* lock could just be changed from T to P.
* Update: T->P is known to happen sometimes with LV locks.
*/
list_for_each_entry_safe(act, safe, &r->actions, list) {
@ -2109,6 +2125,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
list_del(&act->list);
add_client_result(act);
} else {
log_debug("res_process %s change transient to persistent", r->name);
r->last_client_id = act->client_id;
lk->flags |= LD_LF_PERSISTENT;
lk->client_id = 0;
@ -2225,18 +2242,44 @@ static void res_process(struct lockspace *ls, struct resource *r,
}
}
/*
* In general, if the resource struct has no locks, no actions, and is
* unlocked, then it can be freed. (This is only needed for LV
* resources since LVs can be removed.) However, for lvremove (and
* vgremove, sometimes lvconvert), the command will send a free_lv op
* after unlocking. The free_lv op also needs the resource struct.
* So, rather than freeing it here, move the resource struct to the
* ls->dispose list. A free_lv op will find r on the dispose list, do
* free_lv, then free_resource. If the command closes its connection
* without doing free_lv (e.g. normal deactivation), then the structs
* that the client moved to the dispose list will all be freed when
* processing the OP_CLOSE for the client.
*/
if ((r->type == LD_RT_LV) && (r->mode == LD_LK_UN) &&
list_empty(&r->locks) && list_empty(&r->actions)) {
/* An implicit unlock of a transient lock. */
if (!unlock_by_client_id)
goto r_free;
log_debug("%s:%s will dispose for %u", ls->name, r->name, unlock_by_client_id);
list_del(&r->list);
r->dispose_client_id = unlock_by_client_id;
list_add(&r->list, &ls->dispose);
}
return;
r_free:
/* For the EUNATCH case it may be possible there are queued actions? */
list_for_each_entry_safe(act, safe, &r->actions, list) {
log_error("%s:%s res_process r_free cancel %s client %d",
log_error("%s:%s res_process r_free cancel %s client %u",
ls->name, r->name, op_str(act->op), act->client_id);
act->result = -ECANCELED;
list_del(&act->list);
add_client_result(act);
}
log_debug("%s:%s res_process free", ls->name, r->name);
log_debug("%s:%s res_process free_resource", ls->name, r->name);
lm_rem_resource(ls, r);
list_del(&r->list);
free_resource(r);
@ -2271,7 +2314,7 @@ static int for_each_lock(struct lockspace *ls, int locks_do)
return 0;
}
static int clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
static void clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
{
struct resource *r, *r_safe;
struct lock *lk, *lk_safe;
@ -2281,6 +2324,13 @@ static int clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
int lk_count = 0;
int rv;
list_for_each_entry_safe(r, r_safe, &ls->dispose, list) {
log_debug("%s:%s clear_locks dispose free_resource", ls->name, r->name);
list_del(&r->list);
lm_rem_resource(ls, r);
free_resource(r);
}
list_for_each_entry_safe(r, r_safe, &ls->resources, list) {
lk_version = 0;
@ -2296,7 +2346,7 @@ static int clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
if (lk->flags & LD_LF_PERSISTENT && !drop_vg)
log_error("%s:%s clear lock persistent", ls->name, r->name);
else
log_debug("%s:%s clear lock mode %s client %d", ls->name, r->name, mode_str(lk->mode), lk->client_id);
log_debug("%s:%s clear lock mode %s client %u", ls->name, r->name, mode_str(lk->mode), lk->client_id);
if (lk->version > lk_version)
lk_version = lk->version;
@ -2332,20 +2382,33 @@ static int clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
}
list_for_each_entry_safe(act, act_safe, &r->actions, list) {
log_error("%s:%s clear_locks cancel %s client %d",
log_error("%s:%s clear_locks cancel %s client %u",
ls->name, r->name, op_str(act->op), act->client_id);
act->result = -ECANCELED;
list_del(&act->list);
add_client_result(act);
}
r_free:
log_debug("%s:%s free", ls->name, r->name);
log_debug("%s:%s clear_locks free_resource", ls->name, r->name);
lm_rem_resource(ls, r);
list_del(&r->list);
free_resource(r);
}
}
return lk_count;
static struct resource *find_dispose_act(struct lockspace *ls, struct action *act)
{
struct resource *r;
/* Only resources for unlocked LVs should exist on the dispose list. */
list_for_each_entry(r, &ls->dispose, list) {
if (r->type == LD_RT_LV && !strcmp(r->name, act->lv_uuid)) {
list_del(&r->list);
return r;
}
}
return NULL;
}
/*
@ -2484,6 +2547,7 @@ static void *lockspace_thread_main(void *arg_in)
int adopt_ok = 0;
int wait_flag = 0;
int nodelay = 0;
int nocreate;
int retry;
int rv;
@ -2713,10 +2777,64 @@ static void *lockspace_thread_main(void *arg_in)
continue;
}
if (act->op == LD_OP_FREE && act->rt == LD_RT_LV) {
list_del(&act->list);
r = find_dispose_act(ls, act); /* removes r from dispose list */
if (r) {
log_debug("%s:%s free_lv from dispose for %u", ls->name, r->name, act->client_id);
rv = free_lv(ls, r);
lm_rem_resource(ls, r);
free_resource(r);
act->result = rv;
add_client_result(act);
} else {
/* Happens when init_lv was called, but lock was never acquired. */
log_debug("%s:%s free_lv lock_args %s not found on dispose list",
ls->name, act->lv_uuid, act->lv_args);
if (!(r = alloc_resource())) {
rv = -ENOMEM;
} else {
dm_strncpy(r->name, act->lv_uuid, sizeof(r->name));
memcpy(r->lv_args, act->lv_args, MAX_ARGS);
r->type = LD_RT_LV;
r->mode = LD_LK_UN;
lm_add_resource(ls, r);
rv = free_lv(ls, r);
lm_rem_resource(ls, r);
free_resource(r);
}
act->result = rv;
add_client_result(act);
}
continue;
}
list_del(&act->list);
/* applies to all resources */
if (act->op == LD_OP_CLOSE) {
/*
* free any resources the client moved to
* ls->dispose after unlocking. Between the
* time the client unlocked the LV, and now,
* another client could have created a new
* struct resource on ls->resources for the
* same LV. This would not be a problem.
*/
list_for_each_entry_safe(r, r2, &ls->dispose, list) {
if (r->dispose_client_id == act->client_id) {
log_debug("%s:%s free_resource from dispose for %u",
ls->name, r->name, act->client_id);
list_del(&r->list);
lm_rem_resource(ls, r);
free_resource(r);
}
}
/*
* check all resources for transient locks the client
* was holding that should be automatically unlocked
*/
list_add(&act->list, &act_close);
continue;
}
@ -2729,10 +2847,12 @@ static void *lockspace_thread_main(void *arg_in)
* (This creates a new resource if the one named in
* the act is not found.)
*/
nocreate = (act->op == LD_OP_FREE) ||
((act->op == LD_OP_LOCK) && (act->mode == LD_LK_UN));
r = find_resource_act(ls, act, (act->op == LD_OP_FREE) ? 1 : 0);
r = find_resource_act(ls, act, nocreate);
if (!r) {
act->result = (act->op == LD_OP_FREE) ? -ENOENT : -ENOMEM;
act->result = nocreate ? -ENOENT : -ENOMEM;
add_client_result(act);
continue;
}
@ -2791,7 +2911,7 @@ out_rem:
log_debug("S %s clearing locks", ls->name);
(void) clear_locks(ls, free_vg, drop_vg);
clear_locks(ls, free_vg, drop_vg);
/*
* Tell any other hosts in the lockspace to leave it
@ -4061,9 +4181,9 @@ static int client_send_result(struct client *cl, struct action *act)
if (act->lv_args[0])
lv_args = act->lv_args;
log_debug("send %s[%d] cl %u %s %s rv %d vg_args %s lv_args %s",
log_debug("send %s[%d][%u] %s%s%s result %d vg_args %s lv_args %s",
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
op_str(act->op), rt_str(act->rt),
op_str(act->op), act->rt ? "_" : "", rt_str(act->rt),
act->result, vg_args ? vg_args : "", lv_args ? lv_args : "");
res = daemon_reply_simple("OK",
@ -4077,9 +4197,9 @@ static int client_send_result(struct client *cl, struct action *act)
} else if (act->op == LD_OP_QUERY_LOCK) {
log_debug("send %s[%d] cl %u %s %s rv %d mode %d",
log_debug("send %s[%d][%u] %s%s%s result %d mode %d",
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
op_str(act->op), rt_str(act->rt),
op_str(act->op), act->rt ? "_" : "", rt_str(act->rt),
act->result, act->mode);
res = daemon_reply_simple("OK",
@ -4107,7 +4227,7 @@ static int client_send_result(struct client *cl, struct action *act)
else
act->result = -EINVAL;
log_debug("send %s[%d] cl %u dump result %d dump_len %d",
log_debug("send %s[%d][%u] dump result %d dump_len %d",
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
act->result, dump_len);
@ -4120,9 +4240,9 @@ static int client_send_result(struct client *cl, struct action *act)
* A normal reply.
*/
log_debug("send %s[%d] cl %u %s %s rv %d %s %s",
log_debug("send %s[%d][%u] %s%s%s result %d %s %s",
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
op_mode_str(act->op, act->mode), rt_str(act->rt),
op_mode_str(act->op, act->mode), act->rt ? "_" : "", rt_str(act->rt),
act->result, (act->result == -ENOLS) ? "ENOLS" : "", result_flags);
res = daemon_reply_simple("OK",
@ -5054,9 +5174,16 @@ skip_pvs_path:
dm_config_destroy(req.cft);
buffer_destroy(&req.buffer);
log_debug("recv %s[%d] cl %u %s %s \"%s\" flags %x",
log_debug("recv %s[%d][%u] %s%s%s %s%s %s%s%s%s opts=%x",
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
op_mode_str(act->op, act->mode), rt_str(act->rt), act->vg_name, opts);
op_mode_str(act->op, act->mode), act->rt ? "_" : "", rt_str(act->rt),
act->vg_name[0] ? "vg=" : "",
act->vg_name,
act->lv_name[0] || act->lv_uuid[0] ? "lv=" : "",
act->lv_name[0] ? act->lv_name : "",
act->lv_uuid[0] ? ":" : "",
act->lv_uuid[0] ? act->lv_uuid : "",
opts);
if (lm == LD_LM_DLM && !lm_support_dlm()) {
log_debug("dlm not supported");

View File

@ -13,7 +13,7 @@
#include "tools/tool.h"
#include "daemon-server.h"
#include "libdaemon/server/daemon-server.h"
#include "lib/mm/xlate.h"
#include "lvmlockd-internal.h"
@ -363,7 +363,7 @@ int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
return 0;
}
static int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl)
int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;

View File

@ -13,7 +13,7 @@
#include "tools/tool.h"
#include "daemon-server.h"
#include "libdaemon/server/daemon-server.h"
#include "lib/mm/xlate.h"
#include "lvmlockd-internal.h"
@ -490,7 +490,7 @@ out:
return rv;
}
static int lm_add_resource_idm(struct lockspace *ls, struct resource *r)
int lm_add_resource_idm(struct lockspace *ls, struct resource *r)
{
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;

View File

@ -13,6 +13,9 @@
#include "base/memory/container_of.h"
#include <stdint.h>
#include <pthread.h>
#define MAX_NAME 64
#define MAX_ARGS 64
@ -163,6 +166,7 @@ struct resource {
unsigned int sh_count; /* number of sh locks on locks list */
uint32_t version;
uint32_t last_client_id; /* last client_id to lock or unlock resource */
uint32_t dispose_client_id; /* client_id disposing of resource struct */
unsigned int lm_init : 1; /* lm_data is initialized */
unsigned int adopt : 1; /* temp flag in remove_inactive_lvs */
unsigned int version_zero_valid : 1;
@ -212,6 +216,7 @@ struct lockspace {
struct list_head actions; /* new client actions */
struct list_head resources; /* resource/lock state for gl/vg/lv */
struct list_head dispose; /* resources to free */
};
/* val_blk version */
@ -278,15 +283,15 @@ static inline int list_empty(const struct list_head *head)
list_entry((ptr)->next, type, member)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
for (pos = list_entry((head)->next, __typeof__(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
pos = list_entry(pos->member.next, __typeof__(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
for (pos = list_entry((head)->next, __typeof__(*pos), member), \
n = list_entry(pos->member.next, __typeof__(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
pos = n, n = list_entry(n->member.next, __typeof__(*n), member))
/* to improve readability */
@ -397,6 +402,7 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls);
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt_only, int adopt_ok);
int lm_purge_locks_dlm(struct lockspace *ls);
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl);
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int adopt_only, int adopt_ok);
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
@ -453,6 +459,13 @@ static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
return -1;
}
static inline int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl)
{
if (daemon_test)
return 0;
return -1;
}
static inline int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int adopt_only, int adopt_ok)
{
@ -538,6 +551,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok, int nodelay);
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r);
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int *retry,
int adopt_only, int adopt_ok);
@ -597,6 +611,11 @@ static inline int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
return -1;
}
static inline int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
{
return -1;
}
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int *retry,
int adopt_only, int adopt_ok)
@ -675,6 +694,7 @@ int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_prepare_lockspace_idm(struct lockspace *ls);
int lm_add_lockspace_idm(struct lockspace *ls, int adopt_only, int adopt_ok);
int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg);
int lm_add_resource_idm(struct lockspace *ls, struct resource *r);
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
int adopt_only, int adopt_ok);
@ -720,6 +740,11 @@ static inline int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg)
return -1;
}
static inline int lm_add_resource_idm(struct lockspace *ls, struct resource *r)
{
return -1;
}
static inline int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
int adopt_only, int adopt_ok)

View File

@ -13,7 +13,7 @@
#include "tools/tool.h"
#include "daemon-server.h"
#include "libdaemon/server/daemon-server.h"
#include "lib/mm/xlate.h"
#include "lvmlockd-internal.h"
@ -153,11 +153,11 @@ struct lm_sanlock {
};
struct rd_sanlock {
struct val_blk *vb;
union {
struct sanlk_resource rs;
char buf[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)];
};
struct val_blk *vb;
};
struct sanlk_resourced {
@ -298,8 +298,8 @@ static int read_host_id_file(void)
*sep = '\0';
memset(key_str, 0, sizeof(key_str));
memset(val_str, 0, sizeof(val_str));
(void) sscanf(key, "%s", key_str);
(void) sscanf(val, "%s", val_str);
(void) sscanf(key, "%63s", key_str);
(void) sscanf(val, "%63s", val_str);
if (!strcmp(key_str, "host_id")) {
host_id = atoi(val_str);
@ -846,6 +846,11 @@ int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char
offset = align_size * LV_LOCK_BEGIN;
}
if (offset < (align_size * LV_LOCK_BEGIN)) {
log_error("S %s init_lv_san invalid offset %llu", ls_name, (unsigned long long)offset);
return -1;
}
strcpy_name_len(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
rd.rs.num_disks = 1;
memcpy(rd.rs.disks[0].path, disk_path, SANLK_PATH_LEN-1);
@ -1094,22 +1099,35 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r)
{
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
struct sanlk_resource *rs = &rds->rs;
uint64_t offset = rds->rs.disks[0].offset;
int rv;
log_debug("%s:%s free_lv_san", ls->name, r->name);
log_debug("%s:%s free_lv_san %llu", ls->name, r->name, (unsigned long long)offset);
if (daemon_test)
return 0;
strcpy_name_len(rs->name, "#unused", SANLK_NAME_LEN);
rv = sanlock_write_resource(rs, 0, 0, 0);
if (rv < 0) {
log_error("%s:%s free_lv_san write error %d",
ls->name, r->name, rv);
if (!offset) {
lock_lv_offset_from_args(r->lv_args, &offset);
rds->rs.disks[0].offset = offset;
log_debug("%s:%s free_lv_san lock_args offset %llu", ls->name, r->name, (unsigned long long)offset);
}
if (offset < (lms->align_size * LV_LOCK_BEGIN)) {
log_error("%s:%s free_lv_san invalid offset %llu",
ls->name, r->name, (unsigned long long)offset);
return -1;
}
rv = sanlock_write_resource(rs, 0, 0, 0);
if (rv < 0)
log_error("%s:%s free_lv_san %llu write error %d",
ls->name, r->name, (unsigned long long)offset, rv);
return rv;
}
@ -1734,7 +1752,7 @@ out:
return 0;
}
static int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
{
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;

View File

@ -15,8 +15,8 @@
#include "lvmpolld-common.h"
#include "lvm-version.h"
#include "daemon-server.h"
#include "daemon-log.h"
#include "libdaemon/server/daemon-server.h"
#include "libdaemon/server/daemon-log.h"
#include <getopt.h>
#include <poll.h>
@ -390,6 +390,11 @@ static void *fork_and_poll(void *args)
goto err;
}
if (!pdlv->cmdargv || !*(pdlv->cmdargv)) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "Missing command");
goto err;
}
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd line arguments:");
debug_print(ls, pdlv->cmdargv);
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");

View File

@ -46,7 +46,7 @@ static char *_construct_lvm_system_dir_env(const char *sysdir)
* - or -
* just single char to store NULL byte
*/
size_t l = sysdir ? strlen(sysdir) + 16 : 1;
size_t l = sysdir ? strlen(sysdir) + sizeof(LVM_SYSTEM_DIR): 1;
char *env = (char *) malloc(l * sizeof(char));
if (!env)
@ -89,6 +89,17 @@ char *construct_id(const char *sysdir, const char *uuid)
return id;
}
static void _free_lvmpolld_lv(struct lvmpolld_lv *p)
{
free((void *)p->devicesfile);
free((void *)p->lvm_system_dir_env);
free((void *)p->lvmpolld_id);
free((void *)p->lvname);
free((void *)p->sinterval);
free((void *)p->cmdargv);
free((void *)p->cmdenvp);
}
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
const char *vgname, const char *lvname,
const char *sysdir, enum poll_type type,
@ -96,30 +107,26 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
struct lvmpolld_store *pdst,
const char *devicesfile)
{
char *lvmpolld_id = strdup(id), /* copy */
*full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
*lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
char *devicesfile_dup = devicesfile ? strdup(devicesfile) : NULL;
struct lvmpolld_lv tmp = {
.ls = ls,
.type = type,
.lvmpolld_id = lvmpolld_id,
.lvid = _get_lvid(lvmpolld_id, sysdir),
.lvname = full_lvname,
.devicesfile = devicesfile_dup,
.lvm_system_dir_env = lvm_system_dir_env,
.sinterval = strdup(sinterval), /* copy */
.lvmpolld_id = strdup(id),
.lvname = _construct_full_lvname(vgname, lvname),
.devicesfile = devicesfile ? strdup(devicesfile) : NULL,
.lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir),
.sinterval = strdup(sinterval),
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
.cmd_state = { .retcode = -1, .signal = 0 },
.pdst = pdst,
.init_rq_count = 1
}, *pdlv = (struct lvmpolld_lv *) malloc(sizeof(struct lvmpolld_lv));
if (!pdlv || !tmp.lvid || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
if (!pdlv || !tmp.lvmpolld_id || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
goto err;
memcpy(pdlv, &tmp, sizeof(*pdlv));
tmp.lvid = _get_lvid(tmp.lvmpolld_id, sysdir),
*pdlv = tmp;
if (pthread_mutex_init(&pdlv->lock, NULL))
goto err;
@ -127,29 +134,20 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
return pdlv;
err:
free((void *)devicesfile_dup);
free((void *)full_lvname);
free((void *)lvmpolld_id);
free((void *)lvm_system_dir_env);
free((void *)tmp.sinterval);
free((void *)pdlv);
_free_lvmpolld_lv(&tmp);
free(pdlv);
return NULL;
}
void pdlv_destroy(struct lvmpolld_lv *pdlv)
{
free((void *)pdlv->lvmpolld_id);
free((void *)pdlv->devicesfile);
free((void *)pdlv->lvname);
free((void *)pdlv->sinterval);
free((void *)pdlv->lvm_system_dir_env);
free((void *)pdlv->cmdargv);
free((void *)pdlv->cmdenvp);
_free_lvmpolld_lv(pdlv);
pthread_mutex_destroy(&pdlv->lock);
free((void *)pdlv);
free(pdlv);
}
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)

View File

@ -15,7 +15,10 @@
#ifndef _LVM_LVMPOLLD_DATA_UTILS_H
#define _LVM_LVMPOLLD_DATA_UTILS_H
#include "base/data-struct/hash.h"
#include <pthread.h>
#include <stdio.h>
struct buffer;
struct lvmpolld_state;
@ -93,7 +96,7 @@ struct lvmpolld_thread_data {
struct lvmpolld_lv *pdlv;
};
char *construct_id(const char *sysdir, const char *lvid);
char *construct_id(const char *sysdir, const char *uuid);
/* LVMPOLLD_LV_T section */

View File

@ -191,7 +191,7 @@ struct dm_versions {
int dm_get_library_version(char *version, size_t size);
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi);
int dm_task_get_info(struct dm_task *dmt, struct dm_info *info);
/*
* This function returns dm device's UUID based on the value
@ -1051,7 +1051,7 @@ int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
const char *vdo_pool_name,
const char *data_uuid,
uint64_t data_size,
const struct dm_vdo_target_params *param);
const struct dm_vdo_target_params *vtp);
/*
* FIXME Add individual cache policy pairs <key> = value, like:
@ -1178,9 +1178,9 @@ void dm_tree_node_set_presuspend_node(struct dm_tree_node *node,
struct dm_tree_node *presuspend_node);
int dm_tree_node_add_target_area(struct dm_tree_node *node,
const char *dev_name,
const char *dlid,
uint64_t offset);
const char *dev_name,
const char *uuid,
uint64_t offset);
/*
* Only for temporarily-missing raid devices where changes are tracked.
@ -1590,9 +1590,9 @@ int dm_fclose(FILE *stream);
* Pointer to the buffer is stored in *buf.
* Returns -1 on failure leaving buf undefined.
*/
int dm_asprintf(char **buf, const char *format, ...)
int dm_asprintf(char **result, const char *format, ...)
__attribute__ ((format(printf, 2, 3)));
int dm_vasprintf(char **buf, const char *format, va_list ap)
int dm_vasprintf(char **result, const char *format, va_list aq)
__attribute__ ((format(printf, 2, 0)));
/*
@ -1941,7 +1941,7 @@ void dm_report_free(struct dm_report *rh);
* Prefix added to each field name with DM_REPORT_OUTPUT_FIELD_NAME_PREFIX
*/
int dm_report_set_output_field_name_prefix(struct dm_report *rh,
const char *report_prefix);
const char *output_field_name_prefix);
int dm_report_set_selection(struct dm_report *rh, const char *selection);
@ -2081,7 +2081,7 @@ int dm_config_write_one_node_out(const struct dm_config_node *cn, const struct d
struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn, const char *path);
int dm_config_has_node(const struct dm_config_node *cn, const char *path);
int dm_config_remove_node(struct dm_config_node *parent, struct dm_config_node *remove);
int dm_config_remove_node(struct dm_config_node *parent, struct dm_config_node *rem_node);
const char *dm_config_find_str(const struct dm_config_node *cn, const char *path, const char *fail);
const char *dm_config_find_str_allow_empty(const struct dm_config_node *cn, const char *path, const char *fail);
int dm_config_find_int(const struct dm_config_node *cn, const char *path, int fail);
@ -2113,7 +2113,7 @@ unsigned dm_config_maybe_section(const char *str, unsigned len);
const char *dm_config_parent_name(const struct dm_config_node *n);
struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *node, int siblings);
struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *cn, int siblings);
struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key);
struct dm_config_value *dm_config_create_value(struct dm_config_tree *cft);
struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *cn, int siblings);

View File

@ -486,7 +486,7 @@ static void _dm_zfree_string(char *string)
{
if (string) {
memset(string, 0, strlen(string));
asm volatile ("" ::: "memory"); /* Compiler barrier. */
__asm__ volatile ("" ::: "memory"); /* Compiler barrier. */
free(string);
}
}
@ -495,7 +495,7 @@ static void _dm_zfree_dmi(struct dm_ioctl *dmi)
{
if (dmi) {
memset(dmi, 0, dmi->data_size);
asm volatile ("" ::: "memory"); /* Compiler barrier. */
__asm__ volatile ("" ::: "memory"); /* Compiler barrier. */
free(dmi);
}
}

View File

@ -16,6 +16,8 @@
#ifndef LIB_DMTARGETS_H
#define LIB_DMTARGETS_H
#include "device_mapper/all.h"
#include <inttypes.h>
#include <sys/types.h>

View File

@ -511,7 +511,7 @@ int unmangle_string(const char *str, const char *str_name, size_t len,
char *buf, size_t buf_len, dm_string_mangling_t mode)
{
int strict = mode != DM_STRING_MANGLING_NONE;
char str_rest[DM_NAME_LEN];
char str_rest[DM_NAME_LEN + 1];
size_t i, j;
unsigned int code;
int r = 0;

View File

@ -36,7 +36,7 @@ struct target *create_target(uint64_t start,
uint64_t len,
const char *type, const char *params);
int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major,
int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
uid_t uid, gid_t gid, mode_t mode, int check_udev, unsigned rely_on_udev);
int rm_dev_node(const char *dev_name, int check_udev, unsigned rely_on_udev);
int rename_dev_node(const char *old_name, const char *new_name,

View File

@ -1461,9 +1461,9 @@ struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const
return new_cn;
}
struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *node, int sib)
struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *cn, int sib)
{
return dm_config_clone_node_with_mem(cft->mem, node, sib);
return dm_config_clone_node_with_mem(cft->mem, cn, sib);
}
struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key)

View File

@ -152,15 +152,17 @@ struct thin_message {
struct load_segment {
struct dm_list list;
unsigned type;
uint64_t size;
unsigned type;
unsigned area_count; /* Linear + Striped + Mirrored + Crypt */
struct dm_list areas; /* Linear + Striped + Mirrored + Crypt */
uint32_t stripe_size; /* Striped + raid */
uint32_t region_size; /* Mirror + raid */
int persistent; /* Snapshot */
uint32_t chunk_size; /* Snapshot */
struct dm_tree_node *cow; /* Snapshot */
@ -168,7 +170,6 @@ struct load_segment {
struct dm_tree_node *merge; /* Snapshot */
struct dm_tree_node *log; /* Mirror */
uint32_t region_size; /* Mirror + raid */
unsigned clustered; /* Mirror */
unsigned mirror_area_count; /* Mirror */
uint64_t flags; /* Mirror + Raid + Cache */
@ -540,7 +541,8 @@ static struct dm_tree_node *_create_dm_tree_node(struct dm_tree *dtree,
struct dm_tree_node *node;
dev_t dev;
if (!(node = dm_pool_zalloc(dtree->mem, sizeof(*node))) ||
if (!dtree || !dtree->mem ||
!(node = dm_pool_zalloc(dtree->mem, sizeof(*node))) ||
!(node->name = dm_pool_strdup(dtree->mem, name)) ||
!(node->uuid = dm_pool_strdup(dtree->mem, uuid))) {
log_error("_create_dm_tree_node alloc failed.");

View File

@ -31,6 +31,7 @@
struct selection {
struct dm_pool *mem;
struct dm_pool *regex_mem;
struct selection_node *selection_root;
int add_new_fields;
};
@ -204,7 +205,9 @@ static const struct op_def _op_log[] = {
struct selection_str_list {
struct dm_str_list str_list;
unsigned type; /* either SEL_AND or SEL_OR */
struct dm_regex *regex;
size_t regex_num_patterns;
unsigned type; /* either SEL_LIST_LS or SEL_LIST_SUBSET_LS with either SEL_AND or SEL_OR */
};
struct field_selection_value {
@ -547,7 +550,7 @@ static int _report_field_string_list(struct dm_report *rh,
}
/* more than one item - allocate temporary array for string list items for further processing */
if (!(arr = malloc(list_size * sizeof(struct str_pos_len)))) {
if (!(arr = zalloc(list_size * sizeof(struct str_pos_len)))) {
log_error("%s failed to allocate temporary array for processing", _error_msg_prefix);
goto out;
}
@ -589,7 +592,8 @@ static int _report_field_string_list(struct dm_report *rh,
for (i = 0, pos = 0; i < list_size; i++) {
arr[i].item.pos = pos;
memcpy(repstr + pos, arr[i].str, arr[i].item.len);
if (arr[i].str)
memcpy(repstr + pos, arr[i].str, arr[i].item.len);
memcpy(repstr_extra + i + 1, &arr[i].item, sizeof(struct pos_len));
pos += arr[i].item.len;
@ -1411,8 +1415,11 @@ struct dm_report *dm_report_init(uint32_t *report_types,
void dm_report_free(struct dm_report *rh)
{
if (rh->selection)
if (rh->selection) {
dm_pool_destroy(rh->selection->mem);
if (rh->selection->regex_mem)
dm_pool_destroy(rh->selection->regex_mem);
}
if (rh->value_cache)
dm_hash_destroy(rh->value_cache);
dm_pool_destroy(rh->mem);
@ -1751,8 +1758,74 @@ static int _cmp_field_time(struct dm_report *rh,
return 0;
}
static int _str_list_item_match_regex(const struct str_list_sort_value *val, unsigned int i, struct dm_regex *regex)
{
struct pos_len *item = val->items + i;
char *s = (char *) (val->value + item->pos);
char c = s[item->len];
int r;
/*
* The val->items contains the whole string list in the form of a single string,
* where each item is delimited by a delimiter.
*
* The item->pos + item->len pair then points to the exact item within the val->items.
*
* The dm_regex_match accepts a string, not the pos + len pair, so we need to adapt here:
* replace the delimiter with '\0' temporarily so the item is a proper string.
*/
s[item->len] = '\0';
r = dm_regex_match(regex, s);
s[item->len] = c;
return r;
}
static size_t _bitset_count_set(dm_bitset_t bs)
{
size_t i, size = bs[0]/DM_BITS_PER_INT + 1;
size_t count = 0;
for (i = 1; i <= size; i++)
count += hweight32(bs[i]);
return count;
}
/* Matches if all items from selection string list match list value strictly 1:1. */
static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *val,
static int _cmp_field_string_list_strict_regex_all(const struct dm_report *rh,
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
unsigned int i;
dm_bitset_t bs;
int r;
if (!val->items)
return (sel->regex_num_patterns == 1) && dm_regex_match(sel->regex, "") >= 0;
if (!(bs = dm_bitset_create(rh->selection->mem, sel->regex_num_patterns))) {
log_error("Failed to create bitset for regex match counter.");
return 0;
}
for (i = 1; i <= val->items[0].pos; i++) {
if ((r = _str_list_item_match_regex(val, i, sel->regex)) < 0) {
r = 0;
goto out;
}
dm_bit_set(bs, r);
}
r = _bitset_count_set(bs) == sel->regex_num_patterns;
out:
dm_pool_free(rh->selection->mem, bs);
return r;
}
/* Matches if all items from selection string list match list value strictly 1:1. */
static int _cmp_field_string_list_strict_all(const struct dm_report *rh,
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
unsigned int sel_list_size = dm_list_size(&sel->str_list.list);
@ -1784,7 +1857,36 @@ static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *v
}
/* Matches if all items from selection string list match a subset of list value. */
static int _cmp_field_string_list_subset_all(const struct str_list_sort_value *val,
static int _cmp_field_string_list_subset_regex_all(const struct dm_report *rh,
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
dm_bitset_t bs;
unsigned int i;
int r;
if (!val->items)
return (sel->regex_num_patterns == 1) && dm_regex_match(sel->regex, "") >= 0;
if (!(bs = dm_bitset_create(rh->selection->mem, sel->regex_num_patterns))) {
log_error("Failed to create bitset for regex match counter.");
return 0;
}
for (i = 1; i <= val->items[0].pos; i++) {
if ((r = _str_list_item_match_regex(val, i, sel->regex)) < 0)
continue;
dm_bit_set(bs, r);
}
r = _bitset_count_set(bs) == sel->regex_num_patterns;
dm_pool_free(rh->selection->mem, bs);
return r;
}
/* Matches if all items from selection string list match a subset of list value. */
static int _cmp_field_string_list_subset_all(const struct dm_report *rh __attribute__((unused)),
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
unsigned int sel_list_size = dm_list_size(&sel->str_list.list);
@ -1819,8 +1921,26 @@ static int _cmp_field_string_list_subset_all(const struct str_list_sort_value *v
}
/* Matches if any item from selection string list matches list value. */
static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
const struct selection_str_list *sel)
static int _cmp_field_string_list_subset_regex_any(const struct dm_report *rh __attribute__((unused)),
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
unsigned int i;
if (!val->items)
return dm_regex_match(sel->regex, "") >= 0;
for (i = 1; i <= val->items[0].pos; i++) {
if (_str_list_item_match_regex(val, i, sel->regex) >= 0)
return 1;
}
return 0;
}
/* Matches if any item from selection string list matches list value. */
static int _cmp_field_string_list_subset_any(const struct dm_report *rh __attribute__((unused)),
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
struct dm_str_list *sel_item;
unsigned int i;
@ -1849,7 +1969,59 @@ static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
return 0;
}
static int _cmp_field_string_list(struct dm_report *rh __attribute__((unused)),
/* Matches if all items from list value can be matched by any item from selection list. */
static int _cmp_field_string_list_strict_regex_any(const struct dm_report *rh __attribute__((unused)),
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
unsigned int i;
if (!val->items)
return dm_regex_match(sel->regex, "") >= 0;
for (i = 1; i <= val->items[0].pos; i++) {
if (_str_list_item_match_regex(val, i, sel->regex) < 0)
return 0;
}
return 1;
}
/* Matches if all items from list value can be matched by any item from selection list. */
static int _cmp_field_string_list_strict_any(const struct dm_report *rh __attribute__((unused)),
const struct str_list_sort_value *val,
const struct selection_str_list *sel)
{
struct dm_str_list *sel_item;
unsigned int i;
int match;
/* match blank string list with selection that contains blank string */
if (!val->items) {
dm_list_iterate_items(sel_item, &sel->str_list.list) {
if (!strcmp(sel_item->str, ""))
return 1;
}
return 0;
}
for (i = 1; i <= val->items[0].pos; i++) {
match = 0;
dm_list_iterate_items(sel_item, &sel->str_list.list) {
if ((strlen(sel_item->str) == val->items[i].len) &&
!strncmp(sel_item->str, val->value + val->items[i].pos, val->items[i].len)) {
match = 1;
break;
}
}
if (!match)
return 0;
}
return 1;
}
static int _cmp_field_string_list(struct dm_report *rh,
uint32_t field_num, const char *field_id,
const struct str_list_sort_value *val,
struct field_selection *fs)
@ -1871,11 +2043,16 @@ static int _cmp_field_string_list(struct dm_report *rh __attribute__((unused)),
switch (sel->type & SEL_MASK) {
case SEL_AND:
r = subset ? _cmp_field_string_list_subset_all(val, sel)
: _cmp_field_string_list_strict_all(val, sel);
r = subset ? sel->regex ? _cmp_field_string_list_subset_regex_all(rh, val, sel)
: _cmp_field_string_list_subset_all(rh, val, sel)
: sel->regex ? _cmp_field_string_list_strict_regex_all(rh, val, sel)
: _cmp_field_string_list_strict_all(rh, val, sel);
break;
case SEL_OR:
r = _cmp_field_string_list_any(val, sel);
r = subset ? sel->regex ? _cmp_field_string_list_subset_regex_any(rh, val, sel)
: _cmp_field_string_list_subset_any(rh, val, sel)
: sel->regex ? _cmp_field_string_list_strict_regex_any(rh, val, sel)
: _cmp_field_string_list_strict_any(rh, val, sel);
break;
default:
log_error(INTERNAL_ERROR "_cmp_field_string_list: unsupported string "
@ -1909,7 +2086,17 @@ static int _compare_selection_field(struct dm_report *rh,
}
if (fs->flags & FLD_CMP_REGEX)
r = _cmp_field_regex((const char *) f->sort_value, fs);
switch (f->props->flags & DM_REPORT_FIELD_TYPE_MASK) {
case DM_REPORT_FIELD_TYPE_STRING:
r = _cmp_field_regex((const char *) f->sort_value, fs);
break;
case DM_REPORT_FIELD_TYPE_STRING_LIST:
r = _cmp_field_string_list(rh, f->props->field_num, field_id, (const struct str_list_sort_value *) f->sort_value, fs);
break;
default:
log_error(INTERNAL_ERROR "_compare_selection_field: regex: incorrect type %" PRIu32 " for field %s",
f->props->flags & DM_REPORT_FIELD_TYPE_MASK, field_id);
}
else {
switch(f->props->flags & DM_REPORT_FIELD_TYPE_MASK) {
case DM_REPORT_FIELD_TYPE_PERCENT:
@ -1936,7 +2123,8 @@ static int _compare_selection_field(struct dm_report *rh,
r = _cmp_field_time(rh, f->props->field_num, field_id, *(const time_t *) f->sort_value, fs);
break;
default:
log_error(INTERNAL_ERROR "_compare_selection_field: unknown field type for field %s", field_id);
log_error(INTERNAL_ERROR "_compare_selection_field: incorrect type %" PRIu32 " for field %s",
f->props->flags & DM_REPORT_FIELD_TYPE_MASK, field_id);
}
}
@ -2628,11 +2816,9 @@ static int _check_reserved_values_supported(const struct dm_report_field_type fi
static const char *_tok_value_regex(struct dm_report *rh,
const struct dm_report_field_type *ft,
const char *s, const char **begin,
const char **end, uint32_t *flags,
struct reserved_value_wrapper *rvw)
const char **end, uint32_t *flags)
{
char c;
rvw->reserved = NULL;
s = _skip_space(s);
@ -2695,7 +2881,8 @@ static int _add_item_to_string_list(struct dm_pool *mem, const char *begin,
static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
struct dm_pool *mem, const char *s,
const char **begin, const char **end,
struct selection_str_list **sel_str_list)
struct selection_str_list **sel_str_list,
uint32_t *flags)
{
static const char _str_list_item_parsing_failed[] = "Failed to parse string list value "
"for selection field %s.";
@ -2709,12 +2896,11 @@ static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
int list_end = 0;
char c;
if (!(ssl = dm_pool_alloc(mem, sizeof(*ssl)))) {
log_error("_tok_value_string_list: memory allocation failed for selection list");
if (!(ssl = dm_pool_zalloc(mem, sizeof(*ssl)))) {
log_error("_tok_value_string_list: memory allocation failed for selection list.");
goto bad;
}
dm_list_init(&ssl->str_list.list);
ssl->type = 0;
*begin = s;
if (!(op_flags = _tok_op_log(s, &tmp, SEL_LIST_LS | SEL_LIST_SUBSET_LS))) {
@ -2726,7 +2912,7 @@ static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
}
if (!_add_item_to_string_list(mem, begin_item, end_item, &ssl->str_list.list))
goto_bad;
ssl->type = SEL_OR | SEL_LIST_LS;
ssl->type = SEL_OR | SEL_LIST_SUBSET_LS;
goto out;
}
@ -2801,12 +2987,17 @@ static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
else
ssl->type |= SEL_LIST_SUBSET_LS;
/* Sort the list. */
if (!(list_size = dm_list_size(&ssl->str_list.list))) {
log_error(INTERNAL_ERROR "_tok_value_string_list: list has no items");
goto bad;
} else if (list_size == 1)
goto out;
if (*flags & FLD_CMP_REGEX)
/* No need to sort the list for regex. */
goto out;
/* Sort the list. */
if (!(arr = malloc(sizeof(item) * list_size))) {
log_error("_tok_value_string_list: memory allocation failed for sort array");
goto bad;
@ -3322,7 +3513,10 @@ static const char *_tok_value(struct dm_report *rh,
s = _skip_space(s);
s = _get_reserved(rh, expected_type, field_num, implicit, s, begin, end, rvw);
/* recognize possible reserved value (but not in a regex) */
if (!(*flags & FLD_CMP_REGEX))
s = _get_reserved(rh, expected_type, field_num, implicit, s, begin, end, rvw);
if (rvw->reserved) {
/*
* FLD_CMP_NUMBER shares operators with FLD_CMP_TIME,
@ -3333,17 +3527,24 @@ static const char *_tok_value(struct dm_report *rh,
else if (expected_type == DM_REPORT_FIELD_TYPE_NUMBER)
*flags &= ~FLD_CMP_TIME;
*flags |= expected_type;
/* if we matched a reserved value, skip further processing of this token */
return s;
}
switch (expected_type) {
case DM_REPORT_FIELD_TYPE_STRING:
c = _get_and_skip_quote_char(&s);
if (!(s = _tok_value_string(s, begin, end, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL))) {
log_error("Failed to parse string value "
"for selection field %s.", ft->id);
return NULL;
if (*flags & FLD_CMP_REGEX) {
if (!(s = _tok_value_regex(rh, ft, s, begin, end, flags)))
return NULL;
} else {
c = _get_and_skip_quote_char(&s);
if (!(s = _tok_value_string(s, begin, end, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL))) {
log_error("Failed to parse string value "
"for selection field %s.", ft->id);
return NULL;
}
}
*flags |= DM_REPORT_FIELD_TYPE_STRING;
break;
@ -3352,7 +3553,7 @@ static const char *_tok_value(struct dm_report *rh,
if (!(str_list = (struct selection_str_list **) custom))
goto_bad;
s = _tok_value_string_list(ft, mem, s, begin, end, str_list);
s = _tok_value_string_list(ft, mem, s, begin, end, str_list, flags);
if (!(*str_list)) {
log_error("Failed to parse string list value "
"for selection field %s.", ft->id);
@ -3436,7 +3637,7 @@ static const char *_tok_value(struct dm_report *rh,
return s;
bad:
log_error(INTERNAL_ERROR "Forbidden NULL custom detected.");
log_error(INTERNAL_ERROR "_tok_value: Forbidden NULL custom parameter detected.");
return NULL;
}
@ -3507,6 +3708,19 @@ static int _get_reserved_value(struct dm_report *rh, uint32_t field_num,
return 1;
}
static struct dm_regex *_selection_regex_create(struct selection *selection, const char * const *patterns,
unsigned num_patterns)
{
if (!selection->regex_mem) {
if (!(selection->regex_mem = dm_pool_create("report selection regex", 32 * 1024))) {
log_error("Failed to create report selection regex memory pool.");
return NULL;
}
}
return dm_regex_create(selection->regex_mem, patterns, num_patterns);
}
static struct field_selection *_create_field_selection(struct dm_report *rh,
uint32_t field_num,
int implicit,
@ -3524,6 +3738,11 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
struct time_value *tval;
uint64_t factor;
char *s;
const char *s_arr_single[2] = { 0 };
const char **s_arr;
size_t s_arr_size;
struct dm_str_list *sl;
size_t i;
dm_list_iterate_items(fp, &rh->field_props) {
if ((fp->implicit == implicit) && (fp->field_num == field_num)) {
@ -3588,20 +3807,53 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
/* store comparison operand */
if (flags & FLD_CMP_REGEX) {
/* REGEX */
if (!(s = malloc(len + 1))) {
log_error("dm_report: malloc failed to store "
"regex value for selection field %s", field_id);
goto error;
}
memcpy(s, v, len);
s[len] = '\0';
switch (flags & DM_REPORT_FIELD_TYPE_MASK) {
case DM_REPORT_FIELD_TYPE_STRING:
if (!(s = malloc(len + 1))) {
log_error("dm_report: malloc failed to store "
"regex value for selection field %s", field_id);
goto error;
}
memcpy(s, v, len);
s[len] = '\0';
s_arr_single[0] = s;
fs->value->v.r = dm_regex_create(rh->selection->mem, (const char * const *) &s, 1);
free(s);
if (!fs->value->v.r) {
log_error("dm_report: failed to create regex "
"matcher for selection field %s", field_id);
goto error;
fs->value->v.r = _selection_regex_create(rh->selection, s_arr_single, 1);
free(s);
if (!fs->value->v.r) {
log_error("dm_report: failed to create regex "
"matcher for selection field %s", field_id);
goto error;
}
break;
case DM_REPORT_FIELD_TYPE_STRING_LIST:
if (!custom)
goto bad;
fs->value->v.l = *((struct selection_str_list **) custom);
s_arr_size = dm_list_size(&fs->value->v.l->str_list.list);
if (!(s_arr = malloc(sizeof(char *) * s_arr_size))) {
log_error("dm_report: malloc failed for regex array "
"for selection field %s", field_id);
goto error;
}
i = 0;
dm_list_iterate_items(sl, &fs->value->v.l->str_list.list)
s_arr[i++] = sl->str;
fs->value->v.l->regex = _selection_regex_create(rh->selection, s_arr, s_arr_size);
fs->value->v.l->regex_num_patterns = s_arr_size;
free(s_arr);
if (!fs->value->v.l->regex) {
log_error("dm_report: failed to create regex "
"matcher for selection field %s", field_id);
goto error;
}
break;
default:
log_error(INTERNAL_ERROR "_create_field_selection: regex: incorrect type %" PRIu32 " for field %s",
flags & DM_REPORT_FIELD_TYPE_MASK, field_id);
goto error;
}
} else {
/* STRING, NUMBER, SIZE, PERCENT, STRING_LIST, TIME */
@ -3715,8 +3967,8 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
}
break;
default:
log_error(INTERNAL_ERROR "_create_field_selection: "
"unknown type of selection field %s", field_id);
log_error(INTERNAL_ERROR "_create_field_selection: incorrect type %" PRIu32 " for field %s",
flags & DM_REPORT_FIELD_TYPE_MASK, field_id);
goto error;
}
}
@ -3727,7 +3979,7 @@ error_field_id:
field_id);
goto error;
bad:
log_error(INTERNAL_ERROR "Forbidden NULL custom detected.");
log_error(INTERNAL_ERROR "_create_field_selection: Forbidden NULL custom detected.");
error:
dm_pool_free(rh->selection->mem, fs);
@ -3863,7 +4115,7 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
char *tmp;
char c;
/* field name */
/* get field name */
if (!(last = _tok_field_name(s, &ws, &we))) {
log_error("Expecting field name");
goto bad;
@ -3896,7 +4148,7 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
} else
ft = &rh->fields[field_num];
/* comparison operator */
/* get comparison operator */
if (!(flags = _tok_op_cmp(we, &last))) {
_display_selection_help(rh);
log_error("Unrecognised comparison operator: %s", we);
@ -3908,50 +4160,49 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
goto bad;
}
/* comparison value */
/* check we can use the operator with the field */
if (flags & FLD_CMP_REGEX) {
/*
* REGEX value
*/
if (!(last = _tok_value_regex(rh, ft, last, &vs, &ve, &flags, &rvw)))
goto_bad;
} else {
/*
* STRING, NUMBER, SIZE, PERCENT, STRING_LIST, TIME value
*/
if (flags & FLD_CMP_NUMBER) {
if (!(ft->flags & (DM_REPORT_FIELD_TYPE_NUMBER |
DM_REPORT_FIELD_TYPE_SIZE |
DM_REPORT_FIELD_TYPE_PERCENT |
DM_REPORT_FIELD_TYPE_TIME))) {
_display_selection_help(rh);
log_error("Operator can be used only with number, size, time or percent fields: %s", ws);
goto bad;
}
} else if (flags & FLD_CMP_TIME) {
if (!(ft->flags & DM_REPORT_FIELD_TYPE_TIME)) {
_display_selection_help(rh);
log_error("Operator can be used only with time fields: %s", ws);
goto bad;
}
if (!(ft->flags & (DM_REPORT_FIELD_TYPE_STRING |
DM_REPORT_FIELD_TYPE_STRING_LIST))) {
_display_selection_help(rh);
log_error("Operator can be used only with string or string list fields: %s", ws);
goto bad;
}
} else if (flags & FLD_CMP_NUMBER) {
if (!(ft->flags & (DM_REPORT_FIELD_TYPE_NUMBER |
DM_REPORT_FIELD_TYPE_SIZE |
DM_REPORT_FIELD_TYPE_PERCENT |
DM_REPORT_FIELD_TYPE_TIME))) {
_display_selection_help(rh);
log_error("Operator can be used only with number, size, time or percent fields: %s", ws);
goto bad;
}
} else if (flags & FLD_CMP_TIME) {
if (!(ft->flags & DM_REPORT_FIELD_TYPE_TIME)) {
_display_selection_help(rh);
log_error("Operator can be used only with time fields: %s", ws);
goto bad;
}
if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE ||
ft->flags == DM_REPORT_FIELD_TYPE_NUMBER ||
ft->flags == DM_REPORT_FIELD_TYPE_PERCENT)
custom = &factor;
else if (ft->flags & DM_REPORT_FIELD_TYPE_TIME)
custom = &tval;
else if (ft->flags == DM_REPORT_FIELD_TYPE_STRING_LIST)
custom = &str_list;
else
custom = NULL;
if (!(last = _tok_value(rh, ft, field_num, implicit,
last, &vs, &ve, &flags,
&rvw, rh->selection->mem, custom)))
goto_bad;
}
/* assign custom structures to hold extra information for specific value types */
if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE ||
ft->flags == DM_REPORT_FIELD_TYPE_NUMBER ||
ft->flags == DM_REPORT_FIELD_TYPE_PERCENT)
custom = &factor;
else if (ft->flags & DM_REPORT_FIELD_TYPE_TIME)
custom = &tval;
else if (ft->flags == DM_REPORT_FIELD_TYPE_STRING_LIST)
custom = &str_list;
else
custom = NULL;
/* get value to compare with */
if (!(last = _tok_value(rh, ft, field_num, implicit,
last, &vs, &ve, &flags,
&rvw, rh->selection->mem, custom)))
goto_bad;
*next = _skip_space(last);
/* create selection */
@ -4092,7 +4343,7 @@ error:
static int _alloc_rh_selection(struct dm_report *rh)
{
if (!(rh->selection = dm_pool_zalloc(rh->mem, sizeof(struct selection))) ||
!(rh->selection->mem = dm_pool_create("report selection", 10 * 1024))) {
!(rh->selection->mem = dm_pool_create("report selection", 1024))) {
log_error("Failed to allocate report selection structure.");
if (rh->selection)
dm_pool_free(rh->mem, rh->selection);

View File

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

View File

@ -120,7 +120,7 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params,
if (!(pp = _skip_fields(p, 1)))
goto_bad;
/* Raid target can actually report more then real number of legs in a case
/* Raid target can actually report more than real number of legs in a case
* raid legs have been removed during initial raid array resynchronization */
if (i > (pp - p - 1))
i = pp - p - 1;
@ -401,12 +401,12 @@ int dm_get_status_integrity(struct dm_pool *mem, const char *params,
struct dm_status_integrity **status)
{
struct dm_status_integrity *s;
char recalc_str[16] = "\0";
char recalc_str[16] = { 0 };
if (!(s = dm_pool_zalloc(mem, sizeof(*s))))
return_0;
if (sscanf(params, "%llu %llu %s",
if (sscanf(params, "%llu %llu %15s",
(unsigned long long *)&s->number_of_mismatches,
(unsigned long long *)&s->provided_data_sectors,
recalc_str) != 3) {
@ -571,7 +571,7 @@ int dm_get_status_mirror(struct dm_pool *mem, const char *params,
pos += used;
if (num_devs > DM_MIRROR_MAX_IMAGES) {
log_error(INTERNAL_ERROR "More then " DM_TO_STRING(DM_MIRROR_MAX_IMAGES)
log_error(INTERNAL_ERROR "More than " DM_TO_STRING(DM_MIRROR_MAX_IMAGES)
" reported in mirror status.");
goto out;
}

View File

@ -13,6 +13,8 @@
# include <linux/types.h>
#endif
#include <stdint.h>
#define DM_DIR "mapper" /* Slashes not supported */
#define DM_CONTROL_NODE "control"
#define DM_MAX_TYPE_NAME 16

View File

@ -13,7 +13,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dmlib.h"
#include "base/memory/zalloc.h"
#include "device_mapper/misc/dmlib.h"
#include <assert.h>
struct block {

View File

@ -14,7 +14,7 @@
*/
#ifdef VALGRIND_POOL
#include "memcheck.h"
#include <memcheck.h>
#endif
#include "base/memory/zalloc.h"

View File

@ -356,7 +356,7 @@ struct dm_regex *dm_regex_create(struct dm_pool *mem, const char * const *patter
for (i = 0; i < num_patterns; i++) {
ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i], TARGET_TRANS);
if (i < (num_patterns - 1))
if ((i + 1) < num_patterns)
*ptr++ = '|';
}

View File

@ -13,7 +13,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "device_mapper/misc/dmlib.h"
#include "parse_rx.h"
#ifdef DEBUG

View File

@ -16,6 +16,8 @@
#ifndef _DM_PARSE_REGEX_H
#define _DM_PARSE_REGEX_H
#include "device_mapper/misc/dmlib.h"
enum {
CAT,
STAR,

View File

@ -13,7 +13,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "device_mapper/misc/dmlib.h"
#include "ttree.h"
struct node {
@ -84,9 +83,7 @@ int ttree_insert(struct ttree *tt, unsigned int *key, void *data)
} while (*c && count);
if (!*c) {
count++;
while (count--) {
do {
if (!(*c = _tree_node(tt->mem, k)))
return_0;
@ -94,7 +91,7 @@ int ttree_insert(struct ttree *tt, unsigned int *key, void *data)
k = *key++;
c = &((*c)->m);
}
}
} while (count--);
}
(*c)->data = data;

View File

@ -16,6 +16,8 @@
#ifndef _DM_TTREE_H
#define _DM_TTREE_H
#include "device_mapper/misc/dmlib.h"
struct ttree;
struct ttree *ttree_create(struct dm_pool *mem, unsigned int klen);

View File

@ -0,0 +1,24 @@
<!-- Page title -->
[[!meta title="Version 2.03.30 - Bug Fix Release"]]
Version 2.03.30
===============
Small bugfix release:
* **NEW** Create `/dev/disk/by-diskseq/<DISKSEQ>` symlink for public DM devices.
* Lvresize reports origin vdo volume cannot be resized.
* Support setting `reserved_memory|stack` using `--config` on cmdline.
* Fix support for disabling memory locking (2.03.27).
* Do not extend an LV if FS resize unsupported and `--fs resize` used.
* Prevent leftover temporary device when converting in use volume to a pool.
* lvconvert detects volume in use early when converting it to a pool.
* Handle NVMe with quirk changed WWID not matching WWID in devices file.
<!-- remove the pending tag on release, remove draft tag once editing is complete -->
[[!tag]]
<!--
For old releases add Release Timestamp like this, date from git show $COMMIT is fine.
[[!meta date="Tue Jan 14 20:55:33 2025 +0100"]]
-->

View File

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

View File

@ -902,7 +902,7 @@ int devno_dm_uuid(struct cmd_context *cmd, int major, int minor,
const char *uuid;
int r = 0;
if (major != cmd->dev_types->device_mapper_major)
if (major != (int) cmd->dev_types->device_mapper_major)
return 0;
if (dm_devs_cache_use()) {
@ -2014,7 +2014,7 @@ int dev_manager_thin_device_id(struct dev_manager *dm,
if (dm_get_next_target(dmt, NULL, &start, &length,
&target_type, &params)) {
log_error("More then one table line found for %s.",
log_error("More than one table line found for %s.",
display_lvname(lv));
goto out;
}
@ -2067,7 +2067,7 @@ int dev_manager_vdo_pool_status(struct dev_manager *dm,
display_lvname(lv));
if (dm_get_next_target(dmt, NULL, &start, &length, &type, &params)) {
log_error("More then one table line found for %s.",
log_error("More than one table line found for %s.",
display_lvname(lv));
goto out;
}
@ -2121,7 +2121,7 @@ int dev_manager_vdo_pool_size_config(struct dev_manager *dm,
display_lvname(lv));
if (dm_get_next_target(dmt, NULL, &start, &length, &type, &params)) {
log_error("More then one table line found for %s.",
log_error("More than one table line found for %s.",
display_lvname(lv));
goto out;
}
@ -2773,9 +2773,10 @@ static int _add_cvol_subdev_to_dtree(struct dev_manager *dm, struct dm_tree *dtr
const struct logical_volume *pool_lv = lvseg->pool_lv;
struct dm_info info;
char *name ,*dlid;
union lvid lvid = { { lv->vg->id, _get_id_for_meta_or_data(lvseg, meta_or_data) } };
union lvid lvid = { .id = { lv->vg->id, _get_id_for_meta_or_data(lvseg, meta_or_data) } };
lvid.s[sizeof(lvid.id)] = 0;
if (!(dlid = dm_build_dm_uuid(mem, UUID_PREFIX, (const char *)&lvid.s, layer)))
if (!(dlid = dm_build_dm_uuid(mem, UUID_PREFIX, lvid.s, layer)))
return_0;
/* Name is actually not really needed here, but aids debugging... */
@ -3426,9 +3427,10 @@ static int _add_new_cvol_subdev_to_dtree(struct dev_manager *dm,
const struct logical_volume *pool_lv = lvseg->pool_lv;
struct dm_tree_node *dnode;
char *dlid, *dlid_pool, *name;
union lvid lvid = { { lv->vg->id, _get_id_for_meta_or_data(lvseg, meta_or_data) } };
union lvid lvid = { .id = { lv->vg->id, _get_id_for_meta_or_data(lvseg, meta_or_data) } };
lvid.s[sizeof(lvid.id)] = 0;
if (!(dlid = dm_build_dm_uuid(dm->mem, UUID_PREFIX, (const char *)&lvid.s, layer)))
if (!(dlid = dm_build_dm_uuid(dm->mem, UUID_PREFIX, lvid.s, layer)))
return_0;
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, pool_lv->name, layer)))

View File

@ -16,8 +16,12 @@
#ifndef _LVM_TARGETS_H
#define _LVM_TARGETS_H
#include <stddef.h>
#include <stdint.h>
struct dev_manager;
struct lv_segment;
struct dm_tree_node;
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
char *params, size_t paramsize, int *pos,

121
lib/cache/lvmcache.c vendored
View File

@ -21,7 +21,6 @@
#include "lib/device/device_id.h"
#include "lib/locking/locking.h"
#include "lib/metadata/metadata.h"
#include "lib/mm/memlock.h"
#include "lib/format_text/format-text.h"
#include "lib/config/config.h"
#include "lib/filters/filter.h"
@ -1954,7 +1953,7 @@ static int _lvmcache_update_vgname(struct cmd_context *cmd,
log_warn("WARNING: VG name %s is used by VGs %s and %s.",
vgname, vgid_dashed, other_dashed);
log_warn("Fix duplicate VG names with vgrename uuid, a device filter, or system IDs.");
log_warn("WARNING: fix duplicate VG names with vgrename uuid, or vgrename --devices");
}
if (!vginfo_is_allowed && !other_is_allowed) {
@ -2097,12 +2096,17 @@ int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info
vgid = vgname;
}
/* FIXME: remove this, it shouldn't be needed */
/* If PV without mdas is already in a real VG, don't make it orphan */
if (is_orphan_vg(vgname) && info->vginfo &&
mdas_empty_or_ignored(&info->mdas) &&
!is_orphan_vg(info->vginfo->vgname) && critical_section())
/*
* This happens when vgremove does pv_write to make a PV
* that was previously part of a VG into a new orphan.
* FIXME: change pv_write to not use or update lvmcache,
* which should only be updated by label_scan.
*/
if (is_orphan_vg(vgname) && info->vginfo && !is_orphan_vg(info->vginfo->vgname)) {
log_debug("lvmcache change %s to orphan from previous VG %s.",
dev_name(info->dev), info->vginfo->vgname);
return 1;
}
/*
* Creates a new vginfo struct for this vgname/vgid if none exists,
@ -2265,7 +2269,7 @@ int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info
* using the 'vg'.
*/
int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted)
void lvmcache_update_vg_from_read(struct volume_group *vg, int *incorrect_pv_claim)
{
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
char vgid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
@ -2285,9 +2289,11 @@ int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted)
if (!(vginfo = lvmcache_vginfo_from_vgname(vg->name, vgid))) {
log_error(INTERNAL_ERROR "lvmcache_update_vg %s no vginfo", vg->name);
return 0;
return;
}
log_debug_cache("lvmcache_update_vg %s vginfo from metadata", vg->name);
/*
* The label scan doesn't know when a PV with old metadata has been
* removed from the VG. Now with the vg we can tell, so remove the
@ -2326,8 +2332,32 @@ int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted)
continue;
}
log_debug_cache("lvmcache_update_vg %s for info %s",
vg->name, dev_name(info->dev));
/*
* If this PV info is already attached to a different VG, don't
* override that. The info/vginfo map a PV to a VG based on the
* metadata which appears on the PV itself. That has precedence
* over a different mapping of PV to another VG (the vg arg here)
* which is likely outdated metadata from some other device.
*/
if (info->vginfo && !is_orphan_vg(info->vginfo->vgname) &&
(strcmp(info->vginfo->vgname, vg->name) || memcmp(info->vginfo->vgid, &vg->id, ID_LEN))) {
char vgid_old[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
char vgid_new[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
memcpy(vgid_old, &vg->id, ID_LEN);
memcpy(vgid_new, info->vginfo->vgid, ID_LEN);
if (!strcmp(info->vginfo->vgname, vg->name))
log_warn("WARNING: PV %s %s belongs to VGID %s, ignoring claim from VGID %s (%s).",
dev_name(info->dev), pvid, vgid_new, vgid_old, vg->name);
else
log_warn("WARNING: PV %s %s belongs to VG %s, ignoring claim from VG %s.",
dev_name(info->dev), pvid, info->vginfo->vgname, vg->name);
pvl->pv->wrong_vg = 1;
*incorrect_pv_claim = 1;
continue;
}
log_debug_cache("lvmcache_update_vg %s for %s", vg->name, dev_name(info->dev));
/*
* FIXME: use a different function that just attaches info's that
@ -2359,8 +2389,6 @@ int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted)
break;
}
}
return 1;
}
/*
@ -3203,6 +3231,73 @@ bool lvmcache_is_outdated_dev(struct cmd_context *cmd,
return false;
}
/*
* Metadata is being processed which shows 'vg' containing 'pv'.
* Verify that this is consistent with the headers/metadata that
* were scanned from PV. The headers/metadata scanned from the
* actual PV could be different from what 'vg' metadata claims,
* if the 'vg' metadata is old/outdated.
*/
int lvmcache_verify_info_in_vg(struct volume_group *vg, struct lvmcache_info *info)
{
char vgid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
memcpy(vgid, &vg->id, ID_LEN);
if (!info->dev) {
log_error(INTERNAL_ERROR "Verify PV info in %s: skip, no dev", vg->name);
return 1;
}
if (!info->dev->pvid[0]) {
log_debug("Verify PV %s in %s: uncertain, no pvid",
dev_name(info->dev), vg->name);
return 1;
}
if (!info->vginfo) {
log_debug("Verify PV %s %s in %s: uncertain, no vginfo",
info->dev->pvid, dev_name(info->dev), vg->name);
return 1;
}
if (strcmp(vg->name, info->vginfo->vgname)) {
log_debug("Verify PV %s %s in %s: fail, other VG %s",
info->dev->pvid, dev_name(info->dev), vg->name, info->vginfo->vgname);
return 0;
}
if (memcmp(vgid, info->vginfo->vgid, ID_LEN)) {
log_debug("Verify PV %s %s in %s: fail, other vgid %s",
info->dev->pvid, dev_name(info->dev), vg->name, info->vginfo->vgid);
return 0;
}
return 1;
}
int lvmcache_verify_pv_in_vg(struct volume_group *vg, struct physical_volume *pv)
{
struct lvmcache_info *info;
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
memcpy(&pvid, &pv->id.uuid, ID_LEN);
if (!(info = lvmcache_info_from_pvid(pvid, NULL, 0))) {
log_debug("Verify PV %s in %s: skip, no info", pvid, vg->name);
return 1;
}
if (pv->dev != info->dev) {
log_debug("Verify PV %s in %s: skip, different devs", info->dev->pvid, vg->name);
return 1;
}
return lvmcache_verify_info_in_vg(vg, info);
}
const char *dev_filtered_reason(struct device *dev)
{
if (dev->filtered_flags & DEV_FILTERED_REGEX)

View File

@ -83,7 +83,7 @@ void lvmcache_del_dev(struct device *dev);
/* Update things */
int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info *info,
struct lvmcache_vgsummary *vgsummary);
int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted);
void lvmcache_update_vg_from_read(struct volume_group *vg, int *incorrect_pv_claim);
void lvmcache_lock_vgname(const char *vgname, int read_only);
void lvmcache_unlock_vgname(const char *vgname);
@ -98,7 +98,7 @@ struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, struct device *d
struct lvmcache_info *lvmcache_info_from_pv_id(const struct id *pv_id, struct device *dev, int valid_only);
const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid);
const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgname);
struct device *lvmcache_device_from_pv_id(struct cmd_context *cmd, const struct id *pv_id, uint64_t *label_sector);
struct device *lvmcache_device_from_pv_id(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector);
const char *lvmcache_vgname_from_info(struct lvmcache_info *info);
const struct format_type *lvmcache_fmt_from_info(struct lvmcache_info *info);
@ -190,6 +190,9 @@ void lvmcache_save_metadata_size(uint64_t val);
bool lvmcache_has_old_metadata(struct cmd_context *cmd, const char *vgname, const char *vgid, struct device *dev);
int lvmcache_verify_pv_in_vg(struct volume_group *vg, struct physical_volume *pv);
int lvmcache_verify_info_in_vg(struct volume_group *vg, struct lvmcache_info *info);
void lvmcache_get_outdated_devs(struct cmd_context *cmd,
const char *vgname, const char *vgid,
struct dm_list *devs);

View File

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

View File

@ -19,6 +19,8 @@
#include "lib/device/dev-cache.h"
#include "lib/device/dev-type.h"
#include "lib/commands/cmd_enum.h"
#include "lib/log/lvm-logging.h"
#include "lib/misc/lvm-string.h"
#include <limits.h>
@ -163,6 +165,10 @@ struct cmd_context {
unsigned vg_read_print_access_error:1; /* print access errors from vg_read */
unsigned allow_mixed_block_sizes:1;
unsigned force_access_clustered:1;
unsigned lockd_creating_thin_pool:1;
unsigned lockd_creating_thin_volume:1;
unsigned lockd_created_thin_pool:1;
unsigned lockd_created_thin_volume:1;
unsigned lockd_gl_disable:1;
unsigned lockd_vg_disable:1;
unsigned lockd_lv_disable:1;

View File

@ -66,11 +66,16 @@ struct config_source {
* Map each ID to respective definition of the configuration item.
*/
static const struct cfg_def_item _cfg_def_items[CFG_COUNT + 1] = {
#define cfg_section(id, name, parent, flags, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_SECTION, {0}, (flags), since_version, {0}, deprecated_since_version, deprecation_comment, comment},
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) {id, parent, name, type, {.v_##type = (default_value)}, (flags), since_version, {.v_UNCONFIGURED = (unconfigured_value)}, deprecated_since_version, deprecation_comment, comment},
#define cfg_runtime(id, name, parent, flags, type, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, type, {.fn_##type = get_default_##id}, (flags) | CFG_DEFAULT_RUN_TIME, since_version, {.fn_UNCONFIGURED = get_default_unconfigured_##id}, deprecated_since_version, (deprecation_comment), comment},
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_ARRAY | (types), {.v_CFG_TYPE_STRING = (default_value)}, (flags), (since_version), {.v_UNCONFIGURED = (unconfigured_value)}, deprecated_since_version, deprecation_comment, comment},
#define cfg_array_runtime(id, name, parent, flags, types, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_ARRAY | (types), {.fn_CFG_TYPE_STRING = get_default_##id}, (flags) | CFG_DEFAULT_RUN_TIME, (since_version), {.fn_UNCONFIGURED = get_default_unconfigured_##id}, deprecated_since_version, deprecation_comment, comment},
#define cfg_section(id, name, parent, flags, since_version, deprecated_since_version, deprecation_comment, comment)\
{id, parent, name, CFG_TYPE_SECTION, (flags), since_version, deprecated_since_version, {0}, {0}, deprecation_comment, comment},
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment)\
{id, parent, name, type, (flags), since_version, deprecated_since_version, {.v_##type = (default_value)}, {.v_UNCONFIGURED = (unconfigured_value)}, deprecation_comment, comment},
#define cfg_runtime(id, name, parent, flags, type, since_version, deprecated_since_version, deprecation_comment, comment)\
{id, parent, name, type, (flags) | CFG_DEFAULT_RUN_TIME, since_version, deprecated_since_version, {.fn_##type = get_default_##id}, {.fn_UNCONFIGURED = get_default_unconfigured_##id}, (deprecation_comment), comment},
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment)\
{id, parent, name, CFG_TYPE_ARRAY | (types), (flags), (since_version), deprecated_since_version, {.v_CFG_TYPE_STRING = (default_value)}, {.v_UNCONFIGURED = (unconfigured_value)}, deprecation_comment, comment},
#define cfg_array_runtime(id, name, parent, flags, types, since_version, deprecated_since_version, deprecation_comment, comment)\
{id, parent, name, CFG_TYPE_ARRAY | (types), (flags) | CFG_DEFAULT_RUN_TIME, (since_version), deprecated_since_version, {.fn_CFG_TYPE_STRING = get_default_##id}, {.fn_UNCONFIGURED = get_default_unconfigured_##id},deprecation_comment, comment},
#include "lib/config/config_settings.h"
#undef cfg_section
#undef cfg
@ -103,7 +108,7 @@ static inline int _is_file_based_config_source(config_source_t source)
*/
struct dm_config_tree *config_open(config_source_t source,
const char *filename,
int unused)
int keep_open __attribute__((unused)))
{
struct dm_config_tree *cft = dm_config_create();
struct config_source *cs;
@ -520,7 +525,7 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
sz = read(dev_fd(dev), buf + rsize, size - rsize);
} while ((sz < 0) && ((errno == EINTR) || (errno == EAGAIN)));
if (sz < 0) {
if (sz <= 0) {
log_sys_error("read", dev_name(dev));
goto out;
}
@ -927,7 +932,7 @@ static int _check_value_differs_from_default(struct cft_check_handle *handle,
case DM_CFG_FLOAT:
f = v_def ? v_def->v.f
: cfg_def_get_default_value(handle->cmd, def, CFG_TYPE_FLOAT, NULL);
diff = fabs(f - v->v.f) < FLT_EPSILON;
diff = fabsf(f - v->v.f) < FLT_EPSILON;
break;
case DM_CFG_STRING:
/* string value can be a real string but it can also represent bool */
@ -1936,11 +1941,13 @@ int config_write(struct dm_config_tree *cft,
.tree_spec = tree_spec,
.mem = cft->mem
};
int free_fp = 1;
int r = 1;
if (!file) {
baton.fp = stdout;
file = "stdout";
free_fp = 0;
} else if (!(baton.fp = fopen(file, "w"))) {
log_sys_error("open", file);
return 0;
@ -1971,7 +1978,7 @@ int config_write(struct dm_config_tree *cft,
argv++;
}
if (baton.fp && baton.fp != stdout && dm_fclose(baton.fp)) {
if (free_fp && baton.fp && dm_fclose(baton.fp)) {
stack;
r = 0;
}

View File

@ -134,11 +134,11 @@ typedef struct cfg_def_item {
int parent; /* ID of parent item */
const char *name; /* name of the item in configuration tree */
int type; /* configuration item type (bits of cfg_def_type_t) */
cfg_def_value_t default_value; /* default value (only for settings) */
uint16_t flags; /* configuration item definition flags */
uint16_t since_version; /* version this item appeared in */
cfg_def_unconfigured_value_t default_unconfigured_value; /* default value in terms of @FOO@, pre-configured (only for settings) */
uint16_t deprecated_since_version; /* version since this item is deprecated */
cfg_def_value_t default_value; /* default value (only for settings) */
cfg_def_unconfigured_value_t default_unconfigured_value; /* default value in terms of @FOO@, pre-configured (only for settings) */
const char *deprecation_comment; /* comment about reasons for deprecation and settings that supersede this one */
const char *comment; /* comment */
const char *file_preamble; /* comment text to use at the start of the file */
@ -243,7 +243,7 @@ struct dm_config_tree *config_open(config_source_t source, const char *filename,
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_reason_t reason,
off_t offset, size_t size, off_t offset2, size_t size2,
checksum_fn_t checksum_fn, uint32_t checksum,
int skip_parse, int no_dup_node_check, int only_pv_summary);
int checksum_only, int no_dup_node_check, int only_pv_summary);
int config_file_read_from_file(struct dm_config_tree *cft);
struct dm_config_tree *config_file_open_and_read(const char *config_file, config_source_t source,
struct cmd_context *cmd);

View File

@ -681,7 +681,7 @@ cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_
cfg(allocation_thin_pool_crop_metadata_CFG, "thin_pool_crop_metadata", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_CROP_METADATA, vsn(2, 3, 12), NULL, 0, NULL,
"Older version of lvm2 cropped pool's metadata size to 15.81 GiB.\n"
"This is slightly less then the actual maximum 15.88 GiB.\n"
"This is slightly less than the actual maximum 15.88 GiB.\n"
"For compatibility with older version and use of cropped size set to 1.\n")
cfg(allocation_thin_pool_zero_CFG, "thin_pool_zero", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_ZERO, vsn(2, 2, 99), NULL, 0, NULL,

View File

@ -16,7 +16,10 @@
#ifndef _LVM_BTREE_H
#define _LVM_BTREE_H
#include <stdint.h>
struct btree;
struct dm_pool;
struct btree *btree_create(struct dm_pool *mem);

View File

@ -64,7 +64,7 @@ struct block {
/*
* Ownership of engine passes. Engine will be destroyed even if this fails.
*/
struct bcache *bcache_create(sector_t block_size, unsigned nr_cache_blocks,
struct bcache *bcache_create(sector_t block_sectors, unsigned nr_cache_blocks,
struct io_engine *engine);
void bcache_destroy(struct bcache *cache);

View File

@ -871,7 +871,7 @@ static int _insert_dir(const char *dir)
if (bsearch(path + 5, _no_scan, DM_ARRAY_SIZE(_no_scan), sizeof(_no_scan[0]),
(int (*)(const void*, const void*))strcmp)) {
/* Skip insertion of directories that can't have block devices */
log_debug("Skipping \"%s\" (no block devices).", path);
log_debug_devs("Skipping \"%s\" (no block devices).", path);
return 1;
}
}
@ -1161,12 +1161,12 @@ static int _insert(const char *path, const struct stat *info,
}
if (S_ISLNK(tinfo.st_mode)) {
log_debug_devs("%s: Symbolic link to directory", path);
log_debug_devs("Skipping \"%s\" (symbolic link to directory).", path);
return 1;
}
if (info->st_dev != _cache.st_dev) {
log_debug_devs("%s: Different filesystem in directory", path);
log_debug_devs("Skipping \"%s\" (different filesystem in directory).", path);
return 1;
}
@ -1314,7 +1314,7 @@ int dm_devs_cache_update(void)
unsigned devs_features;
uint32_t d;
struct dm_list *dm_devs_new, *l;
int cache_changed = 0;
int cache_changed;
if (!get_dm_active_devices(NULL, &dm_devs_new, &devs_features))
return 1;
@ -1329,6 +1329,7 @@ int dm_devs_cache_update(void)
/* Compare existing cached list with a new one.
* When there is any mismatch, just rebuild whole cache */
if ((l = dm_list_first(dm_devs_new))) {
cache_changed = dm_list_empty(_cache.dm_devs); // 1 for empty cache and new list has entries */
dm_list_iterate_items(dm_dev, _cache.dm_devs) {
dm_dev_new = dm_list_item(l, struct dm_active_device);
if ((dm_dev->devno != dm_dev_new->devno) ||
@ -1394,8 +1395,6 @@ void dm_devs_cache_label_invalidate(struct cmd_context *cmd)
struct dm_active_device *dm_dev;
struct device *dev;
dm_devs_cache_update();
dm_list_iterate_items(dm_dev, _cache.dm_devs) {
if (dm_dev->uuid &&
strncmp(dm_dev->uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1) == 0) {
@ -2385,7 +2384,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
static const char _partitions[] = "/proc/partitions";
char path[PATH_MAX];
char devname[PATH_MAX] = { 0 };
char namebuf[NAME_LEN];
char namebuf[NAME_LEN + 1];
char line[1024];
unsigned major = MAJOR(devno);
unsigned minor = MINOR(devno);

View File

@ -487,7 +487,7 @@ static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device
*/
holder_name = de->d_name;
if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 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.");
continue;
}

View File

@ -16,6 +16,7 @@
#include "lib/misc/lib.h"
#include "lib/device/dev-type.h"
#include "lib/device/device-types.h"
#include "lib/device/filesystem.h"
#include "lib/mm/xlate.h"
#include "lib/config/config.h"
#include "lib/metadata/metadata.h"
@ -23,6 +24,7 @@
#include "lib/label/label.h"
#include "lib/commands/toolcontext.h"
#include "lib/activate/activate.h"
#include "lib/display/display.h"
#include "device_mapper/misc/dm-ioctl.h"
#ifdef BLKID_WIPING_SUPPORT
@ -106,7 +108,7 @@ int dev_is_used_by_active_lv(struct cmd_context *cmd, struct device *dev, int *u
* 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)
if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s%s", cmd->dev_dir, holder_name) < 0)
continue;
/*
@ -1378,6 +1380,22 @@ static unsigned long _dev_topology_attribute(struct dev_types *dt,
return result;
}
static unsigned long _dev_topology_attribute_4k(struct dev_types *dt,
const char *attribute,
struct device *dev,
unsigned long default_value)
{
unsigned long result = _dev_topology_attribute(dt, attribute, dev, default_value);
if ((result > 1) && (result & 0x3)) {
log_warn("WARNING: Ignoring %s = %lu for device %s (not divisible by 4KiB).",
attribute, result << SECTOR_SHIFT, dev_name(dev));
result = 8;
}
return result;
}
unsigned long dev_alignment_offset(struct dev_types *dt, struct device *dev)
{
return _dev_topology_attribute(dt, "alignment_offset", dev, 0UL);
@ -1385,12 +1403,12 @@ unsigned long dev_alignment_offset(struct dev_types *dt, struct device *dev)
unsigned long dev_minimum_io_size(struct dev_types *dt, struct device *dev)
{
return _dev_topology_attribute(dt, "queue/minimum_io_size", dev, 0UL);
return _dev_topology_attribute_4k(dt, "queue/minimum_io_size", dev, 0UL);
}
unsigned long dev_optimal_io_size(struct dev_types *dt, struct device *dev)
{
return _dev_topology_attribute(dt, "queue/optimal_io_size", dev, 0UL);
return _dev_topology_attribute_4k(dt, "queue/optimal_io_size", dev, 0UL);
}
unsigned long dev_discard_max_bytes(struct dev_types *dt, struct device *dev)

View File

@ -16,9 +16,10 @@
#define _LVM_DEV_TYPE_H
#include "lib/device/device.h"
#include "lib/display/display.h"
#include "lib/metadata/metadata-exported.h"
#include "lib/label/label.h"
#include "lib/device/filesystem.h"
struct fs_info;
#define NUMBER_OF_MAJORS 4096
@ -58,10 +59,10 @@ 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 cmd_context *cmd, struct device *dev, uint64_t *sb, int full);
int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev, dev_t *mpath_devno);
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 dev_is_md_component(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full);
int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev, dev_t *holder_devno);
int dev_is_swap(struct cmd_context *cmd, 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);
int dasd_is_cdl_formatted(struct device *dev);
const char *dev_mpath_component_wwid(struct cmd_context *cmd, struct device *dev);

View File

@ -16,11 +16,11 @@
#include "lib/misc/lib.h"
#include "lib/device/device.h"
int device_id_list_remove(struct dm_list *list, struct device *dev)
int device_id_list_remove(struct dm_list *devices, struct device *dev)
{
struct device_id_list *dil;
dm_list_iterate_items(dil, list) {
dm_list_iterate_items(dil, devices) {
if (dil->dev == dev) {
dm_list_del(&dil->list);
return 1;
@ -29,22 +29,22 @@ int device_id_list_remove(struct dm_list *list, struct device *dev)
return 0;
}
struct device_id_list *device_id_list_find_dev(struct dm_list *list, struct device *dev)
struct device_id_list *device_id_list_find_dev(struct dm_list *devices, struct device *dev)
{
struct device_id_list *dil;
dm_list_iterate_items(dil, list) {
dm_list_iterate_items(dil, devices) {
if (dil->dev == dev)
return dil;
}
return NULL;
}
int device_list_remove(struct dm_list *list, struct device *dev)
int device_list_remove(struct dm_list *devices, struct device *dev)
{
struct device_list *devl;
dm_list_iterate_items(devl, list) {
dm_list_iterate_items(devl, devices) {
if (devl->dev == dev) {
dm_list_del(&devl->list);
return 1;
@ -53,11 +53,11 @@ int device_list_remove(struct dm_list *list, struct device *dev)
return 0;
}
struct device_list *device_list_find_dev(struct dm_list *list, struct device *dev)
struct device_list *device_list_find_dev(struct dm_list *devices, struct device *dev)
{
struct device_list *devl;
dm_list_iterate_items(devl, list) {
dm_list_iterate_items(devl, devices) {
if (devl->dev == dev)
return devl;
}

View File

@ -13,6 +13,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LIB_DEVICE_DEVICE_TYPES_H
#define LIB_DEVICE_DEVICE_TYPES_H
#include <stdint.h>
typedef struct {
const char name[15];
const int8_t max_partitions;
@ -65,5 +70,8 @@ static const dev_known_type_t _dev_known_types[] = {
{"nvme", 64, "NVM Express"},
{"zvol", 16, "ZFS Zvols"},
{"VxDMP", 16, "Veritas Dynamic Multipathing"},
{"zram", 1, "zram block device"},
{"", 0, ""}
};
#endif

View File

@ -16,8 +16,10 @@
#ifndef _LVM_DEVICE_H
#define _LVM_DEVICE_H
#include "base/data-struct/list.h"
#include "lib/uuid/uuid.h"
#include <stdint.h>
#include <fcntl.h>
#define DEV_REGULAR 0x00000002 /* Regular file? */

View File

@ -14,8 +14,6 @@
#include "base/memory/zalloc.h"
#include "lib/misc/lib.h"
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
#include "lib/device/device_id.h"
#include "lib/device/dev-type.h"
#include "lib/label/label.h"
@ -26,6 +24,7 @@
#include "lib/datastruct/str_list.h"
#include "lib/metadata/metadata-exported.h"
#include "lib/activate/activate.h"
#include "lib/display/display.h"
#include "device_mapper/misc/dm-ioctl.h"
#include <sys/stat.h>
@ -1432,12 +1431,20 @@ int device_ids_read(struct cmd_context *cmd)
return ret;
}
#define BACKUP_NAME_LEN 35
#define BACKUP_NAME_SIZE BACKUP_NAME_LEN+1 /* +1 null byte */
/*
* backup files with version 1-9999 use a 4 digit suffix:
* 31 chars + 4 chars (zero padded counter) + null byte
*
* backup files with version >9999:
* 31 chars + 5+ chars (uint32 counter, not zero padded, up to 10 chars) + null byte
*/
#define BACKUP_NAME_SIZE 48 /* larger than the longest backup file name */
static int _filter_backup_files(const struct dirent *de)
{
if (strlen(de->d_name) != BACKUP_NAME_LEN)
int len = strlen(de->d_name);
if (len < 35 || len > BACKUP_NAME_SIZE-1)
return 0;
if (strncmp(de->d_name, "system.devices-", 15))
return 0;
@ -1461,6 +1468,7 @@ static void devices_file_backup(struct cmd_context *cmd, char *fc, char *fb, tim
uint32_t low_date = 0, low_time = 0, low_count = 0;
uint32_t de_date, de_time, de_count;
unsigned int backup_limit = 0, backup_count = 0, remove_count;
int namelen;
int sort_count;
int dir_fd;
int i;
@ -1481,10 +1489,21 @@ static void devices_file_backup(struct cmd_context *cmd, char *fc, char *fb, tim
tm = localtime(tp);
strftime(datetime_str, sizeof(datetime_str), "%Y%m%d.%H%M%S", tm);
/* system.devices-YYYYMMDD.HHMMSS.000N (fixed length 35) */
if (dm_snprintf(path, sizeof(path), "%s/devices/backup/system.devices-%s.%04u",
cmd->system_dir, datetime_str, df_counter) < 0)
goto_out;
/* arbitrary max for devicesfile_backup_limit setting */
if (backup_limit > 5000)
backup_limit = 5000;
if (df_counter < 10000) {
/* system.devices-YYYYMMDD.HHMMSS.NNNN (fixed length 35, uses 4 digit zero padded suffix) */
if (dm_snprintf(path, sizeof(path), "%s/devices/backup/system.devices-%s.%04u",
cmd->system_dir, datetime_str, df_counter) < 0)
goto_out;
} else {
/* system.devices-YYYYMMDD.HHMMSS.NNNNN... (variable length, suffix has no fixed width) */
if (dm_snprintf(path, sizeof(path), "%s/devices/backup/system.devices-%s.%u",
cmd->system_dir, datetime_str, df_counter) < 0)
goto_out;
}
if (!(fp = fopen(path, "w+"))) {
log_warn("WARNING: Failed to create backup file %s", path);
@ -1522,7 +1541,10 @@ static void devices_file_backup(struct cmd_context *cmd, char *fc, char *fb, tim
while ((de = readdir(dir))) {
if (de->d_name[0] == '.')
continue;
if (strlen(de->d_name) != BACKUP_NAME_LEN)
namelen = strlen(de->d_name);
if (namelen < 35 || namelen > BACKUP_NAME_SIZE-1)
continue;
memset(de_date_str, 0, sizeof(de_date_str));
@ -1530,16 +1552,22 @@ static void devices_file_backup(struct cmd_context *cmd, char *fc, char *fb, tim
memset(de_count_str, 0, sizeof(de_count_str));
/*
* Save the oldest backup file name.
* system.devices-YYYYMMDD.HHMMSS.NNNN
* Save the oldest backup file name:
*
* backup files with version 1-9999 have 4 digit suffix:
* system.devices-YYYYMMDD.HHMMSS.NNNN
* 12345678901234567890123456789012345 (len 35)
* date YYYYMMDD is 8 chars 16-23
* time HHMMSS is 6 chars 25-30
* count NNNN is 4 chars 32-35
*
* backup files with version >9999 have
* non-zero-padded variable length suffix:
* system.devices-YYYYMMDD.HHMMSS.NNNNN...
*/
memcpy(de_date_str, de->d_name+15, 8);
memcpy(de_time_str, de->d_name+24, 6);
memcpy(de_count_str, de->d_name+31, 4);
memcpy(de_count_str, de->d_name+31, namelen - 31);
de_date = (uint32_t)strtoul(de_date_str, NULL, 10);
de_time = (uint32_t)strtoul(de_time_str, NULL, 10);
@ -1577,7 +1605,7 @@ static void devices_file_backup(struct cmd_context *cmd, char *fc, char *fb, tim
/* Remove the n oldest files by sorting system.devices-*. */
setlocale(LC_COLLATE, "C"); /* Avoid sorting by locales */
sort_count = scandir(dirpath, &namelist, _filter_backup_files, alphasort);
sort_count = scandir(dirpath, &namelist, _filter_backup_files, versionsort);
setlocale(LC_COLLATE, "");
if (sort_count < 0) {
log_warn("WARNING: Failed to sort backup devices files.");
@ -1597,6 +1625,7 @@ static void devices_file_backup(struct cmd_context *cmd, char *fc, char *fb, tim
free(namelist[i]);
}
free(namelist);
out:
if (fp && fclose(fp))
stack;

View File

@ -16,10 +16,13 @@
#ifndef _LVM_DEVICE_ID_H
#define _LVM_DEVICE_ID_H
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
void free_du(struct dev_use *du);
void free_dus(struct dm_list *list);
void free_dus(struct dm_list *dus);
void free_did(struct dev_id *did);
void free_dids(struct dm_list *list);
void free_dids(struct dm_list *ids);
const char *idtype_to_str(uint16_t idtype);
uint16_t idtype_from_str(const char *str);
const char *dev_idtype_for_metadata(struct cmd_context *cmd, struct device *dev);
@ -69,8 +72,8 @@ int read_sys_block_binary(struct cmd_context *cmd, struct device *dev,
int dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, char **idname_out);
int scsi_type_to_idtype(int wwid_type);
int nvme_type_to_idtype(int wwid_type);
int scsi_type_to_idtype(int scsi_type);
int nvme_type_to_idtype(int nvme_type);
int idtype_to_scsi_type(int idtype);
int idtype_to_nvme_type(int idtype);
void free_wwids(struct dm_list *ids);

View File

@ -14,9 +14,9 @@
#include "base/memory/zalloc.h"
#include "lib/misc/lib.h"
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
#include "lib/device/dev-type.h"
#include "lib/device/filesystem.h"
#include "lib/display/display.h"
#include "lib/misc/lvm-exec.h"
#include "lib/activate/dev_manager.h"
@ -239,9 +239,9 @@ int fs_mount_state_is_misnamed(struct cmd_context *cmd, struct logical_volume *l
{
FILE *fp;
char proc_line[PATH_MAX];
char proc_fstype[FSTYPE_MAX];
char proc_devpath[PATH_MAX];
char proc_mntpath[PATH_MAX];
char proc_fstype[FSTYPE_MAX + 1];
char proc_devpath[PATH_MAX + 1];
char proc_mntpath[PATH_MAX + 1];
char mtab_mntpath[PATH_MAX] = { 0 };
char dm_devpath[PATH_MAX];
char tmp_path[PATH_MAX];
@ -327,7 +327,7 @@ int fs_mount_state_is_misnamed(struct cmd_context *cmd, struct logical_volume *l
if (sscanf(proc_line, "%"
DM_TO_STRING(PATH_MAX) "s %"
DM_TO_STRING(PATH_MAX) "s %"
DM_TO_STRING(PATH_MAX) "s", proc_devpath, proc_mntpath, proc_fstype) != 3)
DM_TO_STRING(FSTYPE_MAX) "s", proc_devpath, proc_mntpath, proc_fstype) != 3)
continue;
if (strcmp(fstype, proc_fstype))
continue;

View File

@ -15,6 +15,9 @@
#ifndef _FILESYSTEM_H
#define _FILESYSTEM_H
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
#define FSTYPE_MAX 16
struct fs_info {

View File

@ -14,9 +14,8 @@
#include "base/memory/zalloc.h"
#include "lib/misc/lib.h"
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
#include "lib/device/online.h"
#include "lib/config/defaults.h"
#include <dirent.h>

View File

@ -15,6 +15,9 @@
#ifndef _ONLINE_H
#define _ONLINE_H
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
struct pv_online {
struct dm_list list;
struct device *dev;

View File

@ -934,13 +934,13 @@ void display_name_error(name_error_t name_error)
char yes_no_prompt(const char *prompt, ...)
{
/* Lowercase Yes/No strings */
static const char _yes[] = "yes";
static const char _no[] = "no";
char buf[12] = { 0 };
static const char _yes[sizeof(buf)] = "yes";
static const char _no[sizeof(buf)] = "no";
const char *answer = NULL;
int c = silent_mode() ? EOF : 0;
int ret = 0, sig = 0;
unsigned i = 0;
char buf[12];
va_list ap;
sigint_allow();

View File

@ -17,7 +17,6 @@
#include "base/data-struct/radix-tree.h"
#include "lib/misc/lib.h"
#include "lib/filters/filter.h"
#include "lib/config/config.h"
struct pfilter {
struct radix_tree *devices;
@ -74,7 +73,7 @@ static void _persistent_filter_wipe(struct cmd_context *cmd, struct dev_filter *
_init_hash(pf);
} else {
dm_list_iterate_items(sl, &dev->aliases)
radix_tree_remove(pf->devices, sl->str, strlen(sl->str));
(void) radix_tree_remove(pf->devices, sl->str, strlen(sl->str));
}
}

View File

@ -15,6 +15,7 @@
#include "base/memory/zalloc.h"
#include "lib/misc/lib.h"
#include "lib/filters/filter.h"
#include "lib/config/config.h"
#include "lib/activate/activate.h"
static const char _too_small_to_hold_pv_msg[] = "Too small to hold a PV";

View File

@ -27,7 +27,7 @@ struct dev_filter *md_filter_create(struct cmd_context *cmd, struct dev_types *d
struct dev_filter *fwraid_filter_create(struct dev_types *dt);
struct dev_filter *mpath_filter_create(struct dev_types *dt);
struct dev_filter *partitioned_filter_create(struct dev_types *dt);
struct dev_filter *persistent_filter_create(struct dev_types *dt, struct dev_filter *f);
struct dev_filter *persistent_filter_create(struct dev_types *dt, struct dev_filter *real);
struct dev_filter *sysfs_filter_create(const char *sysfs_dir);
struct dev_filter *signature_filter_create(struct dev_types *dt);
struct dev_filter *deviceid_filter_create(struct cmd_context *cmd);

View File

@ -219,7 +219,7 @@ static void _remove_expired(const char *dir, const char *vgname,
sum /= 1024 * 1024;
if (sum > 128 || archives_size > 8192)
log_print_unless_silent("Consider pruning %s VG archive with more then %u MiB in %u files (see archiving settings in lvm.conf).",
log_print_unless_silent("Consider pruning %s VG archive with more than %u MiB in %u files (see archiving settings in lvm.conf).",
vgname, (unsigned)sum, archives_size);
}

View File

@ -70,7 +70,7 @@ int print_segtype_lvflags(char *buffer, size_t size, uint64_t status);
int read_lvflags(uint64_t *status, const char *flags_str);
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf, uint32_t *alloc_size);
size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf, uint32_t *buf_size);
struct volume_group *text_read_metadata_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc);

View File

@ -16,6 +16,8 @@
#ifndef _LVM_TEXT_EXPORT_H
#define _LVM_TEXT_EXPORT_H
#include <stdint.h>
#define outsize(args...) do {if (!out_size(args)) return_0;} while (0)
#define outhint(args...) do {if (!out_hint(args)) return_0;} while (0)
#define outfc(args...) do {if (!out_text_with_comment(args)) return_0;} while (0)

View File

@ -21,6 +21,7 @@
struct dm_hash_table;
struct lv_segment;
struct dm_config_node;
struct dm_config_value;
int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn,
const struct dm_config_value *cv, uint64_t status);

View File

@ -141,7 +141,6 @@
#include "lib/misc/crc.h"
#include "lib/cache/lvmcache.h"
#include "lib/device/bcache.h"
#include "lib/commands/toolcontext.h"
#include "lib/activate/activate.h"
#include "lib/label/hints.h"
#include "lib/device/dev-type.h"

View File

@ -15,6 +15,8 @@
#ifndef _LVM_HINTS_H
#define _LVM_HINTS_H
#include "lib/commands/toolcontext.h"
struct hint {
struct dm_list list;
dev_t devt;

View File

@ -23,6 +23,7 @@
#include "lib/mm/memlock.h"
#include "lib/config/defaults.h"
#include "lib/cache/lvmcache.h"
#include "lib/display/display.h"
#include "lib/misc/lvm-signal.h"
#include <assert.h>
@ -407,7 +408,7 @@ int lock_global(struct cmd_context *cmd, const char *mode)
return 0;
if (!lockd_global(cmd, mode)) {
lockf_global(cmd, "un");
(void) lockf_global(cmd, "un");
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,9 @@
#define LDLV_MODE_NO_SH 0x00000001
#define LDLV_PERSISTENT 0x00000002
#define LDLV_SH_EXISTS_OK 0x00000004
#define LDLV_CREATING_THIN_VOLUME 0x00000008
#define LDLV_CREATING_THIN_POOL 0x00000010
#define LDLV_CREATING_COW_SNAP_ON_THIN 0x00000020
/* lvmlockd result flags */
#define LD_RF_NO_LOCKSPACES 0x00000001
@ -108,26 +111,31 @@ int lockd_lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
/* lvcreate/lvremove use init/free */
int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv,
struct lvcreate_params *lp);
int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, struct lvcreate_params *lp);
int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv, const char *lock_type, const char *last_args, const char **lock_args);
int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id, const char *lock_args);
int lockd_free_lv_after_update(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id, const char *lock_args);
void lockd_free_lv_queue(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id, const char *lock_args);
void lockd_free_removed_lvs(struct cmd_context *cmd, struct volume_group *vg, int remove_success);
const char *lockd_running_lock_type(struct cmd_context *cmd, int *found_multiple);
int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg);
int lockd_lv_uses_lock(struct logical_volume *lv);
int lockd_lv_refresh(struct cmd_context *cmd, struct lvresize_params *lp);
int lockd_query_lv(struct cmd_context *cmd, struct logical_volume *lv, int *ex, int *sh);
int lockd_lvcreate_prepare(struct cmd_context *cmd, struct volume_group *vg, struct lvcreate_params *lp);
int lockd_lvcreate_lock(struct cmd_context *cmd, struct volume_group *vg, struct lvcreate_params *lp,
int creating_thin_pool, int creating_thin_volume, int creating_cow_snapshot, int creating_vdo_volume);
void lockd_lvcreate_done(struct cmd_context *cmd, struct volume_group *vg, struct lvcreate_params *lp);
int lockd_lvremove_lock(struct cmd_context *cmd, struct logical_volume *lv, struct logical_volume **lv_other, int *other_unlock);
void lockd_lvremove_done(struct cmd_context *cmd, struct logical_volume *lv, struct logical_volume *lv_other, int other_unlock);
#else /* LVMLOCKD_SUPPORT */
static inline void lockd_lockopt_get_flags(const char *str, uint32_t *flags)
@ -248,14 +256,13 @@ static inline int lockd_lv_resize(struct cmd_context *cmd, struct logical_volume
return 1;
}
static inline int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv, struct lvcreate_params *lp)
static inline int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, struct lvcreate_params *lp)
{
return 1;
}
static inline int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv, const char *lock_type, const char *last_args, const char **lock_args)
struct logical_volume *lv, const char *lock_type, const char *last_args, const char **lock_args)
{
return 1;
}
@ -266,10 +273,9 @@ static inline int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg
return 1;
}
static inline int lockd_free_lv_after_update(struct cmd_context *cmd, struct volume_group *vg,
static inline void lockd_free_lv_queue(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id, const char *lock_args)
{
return 1;
}
static inline void lockd_free_removed_lvs(struct cmd_context *cmd, struct volume_group *vg, int remove_success)
@ -282,11 +288,6 @@ static inline const char *lockd_running_lock_type(struct cmd_context *cmd, int *
return NULL;
}
static inline int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg)
{
return 0;
}
static inline int lockd_lv_uses_lock(struct logical_volume *lv)
{
return 0;
@ -302,6 +303,32 @@ static inline int lockd_query_lv(struct cmd_context *cmd, struct logical_volume
return 0;
}
static inline int lockd_lvcreate_prepare(struct cmd_context *cmd, struct volume_group *vg, struct lvcreate_params *lp)
{
return 1;
}
static inline int lockd_lvcreate_lock(struct cmd_context *cmd, struct volume_group *vg, struct lvcreate_params *lp,
int creating_thin_pool, int creating_thin_volume, int creating_cow_snapshot, int creating_vdo_volume)
{
return 1;
}
static inline void lockd_lvcreate_done(struct cmd_context *cmd, struct volume_group *vg, struct lvcreate_params *lp)
{
}
static inline int lockd_lvremove_lock(struct cmd_context *cmd, struct logical_volume *lv, struct logical_volume **lv_other,
int *other_unlock)
{
return 1;
}
static inline void lockd_lvremove_done(struct cmd_context *cmd, struct logical_volume *lv, struct logical_volume *lv_other,
int other_unlock)
{
}
#endif /* LVMLOCKD_SUPPORT */
#endif /* _LVMLOCKD_H */

View File

@ -50,7 +50,7 @@
#define _LOG_STDERR 0x0080 /* force things to go to stderr, even if loglevel would make them go to stdout */
#define _LOG_ONCE 0x0100 /* downgrade to NOTICE if this has been already logged */
#define _LOG_BYPASS_REPORT 0x0200 /* do not log through report even if report available */
#define log_level(x) ((x) & 0x0f) /* obtain message level */
#define log_level(x) ((x) & 0x07) /* obtain message level */
#define log_stderr(x) ((x) & _LOG_STDERR) /* obtain stderr bit */
#define log_once(x) ((x) & _LOG_ONCE) /* obtain once bit */
#define log_bypass_report(x) ((x) & _LOG_BYPASS_REPORT)/* obtain bypass bit */

View File

@ -18,6 +18,8 @@
#include "lib/misc/lvm-file.h"
#include <stdint.h>
__attribute__ ((format(printf, 5, 6)))
void print_log(int level, const char *file, int line, int dm_errno_or_class,
const char *format, ...);

View File

@ -222,7 +222,7 @@ int update_cache_pool_params(struct cmd_context *cmd,
}
if (*chunk_size < min_chunk_size) {
/*
* When using more then 'standard' default,
* When using more than 'standard' default,
* keep user informed he might be using things in unintended direction
*/
log_print_unless_silent("Using %s chunk size instead of default %s, "
@ -559,6 +559,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
struct id *data_id, *metadata_id;
uint64_t data_len, metadata_len;
cache_mode_t cache_mode;
int temp_activated = 0;
int is_clear;
if (!lv_is_cache(cache_lv)) {
@ -573,11 +574,13 @@ int lv_cache_remove(struct logical_volume *cache_lv)
goto remove; /* Already dropped */
}
/* Locally active volume is needed for writeback */
if (!lv_info(cache_lv->vg->cmd, cache_lv, 1, NULL, 0, 0)) {
/* Give up any remote locks */
if (!deactivate_lv_with_sub_lv(cache_lv))
return_0;
/*
* LV is inactive. When used in writeback, it will
* need to be activated to write the cache content
* back to the main LV before detaching it.
*/
cache_mode = (lv_is_cache_pool(cache_seg->pool_lv)) ?
first_seg(cache_seg->pool_lv)->cache_mode : cache_seg->cache_mode;
@ -594,7 +597,6 @@ int lv_cache_remove(struct logical_volume *cache_lv)
return_0;
return 1;
default:
/* Otherwise locally activate volume to sync dirty blocks */
cache_lv->status |= LV_TEMPORARY;
if (!activate_lv(cache_lv->vg->cmd, cache_lv) ||
!lv_is_active(cache_lv)) {
@ -602,6 +604,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
return 0;
}
cache_lv->status &= ~LV_TEMPORARY;
temp_activated = 1;
}
}
@ -620,8 +623,14 @@ int lv_cache_remove(struct logical_volume *cache_lv)
* remove the cache_pool then without waiting for the flush to
* complete.
*/
if (!lv_cache_wait_for_clean(cache_lv, &is_clear))
if (!lv_cache_wait_for_clean(cache_lv, &is_clear)) {
if (temp_activated && !deactivate_lv(cache_lv->vg->cmd, cache_lv))
stack;
return_0;
}
if (temp_activated && !deactivate_lv(cache_lv->vg->cmd, cache_lv))
log_warn("Failed to deactivate after cleaning cache.");
cache_pool_lv = cache_seg->pool_lv;
if (!detach_pool_lv(cache_seg))

View File

@ -80,7 +80,7 @@ static uint64_t _lv_size_bytes_to_integrity_meta_bytes(uint64_t lv_size_bytes, u
initial_bytes = 8 * ONE_MB_IN_BYTES;
else if (lv_size_bytes <= (4ULL * ONE_GB_IN_BYTES))
initial_bytes = 32 * ONE_MB_IN_BYTES;
else if (lv_size_bytes > (4ULL * ONE_GB_IN_BYTES))
else // if (lv_size_bytes > (4ULL * ONE_GB_IN_BYTES))
initial_bytes = 64 * ONE_MB_IN_BYTES;
out:
log_debug("integrity_meta_bytes %llu from lv_size_bytes %llu meta_bytes %llu initial_bytes %llu journal_sectors %u",
@ -132,6 +132,12 @@ static int _lv_create_integrity_metadata(struct cmd_context *cmd,
meta_sectors = meta_bytes / 512;
lp_meta.extents = meta_sectors / vg->extent_size;
/* Use one extent if the VG extent size is larger than the number of sectors needed. */
if (!lp_meta.extents) {
log_debug("Round integrity meta size up to one extent.");
lp_meta.extents = 1;
}
log_verbose("Creating integrity metadata LV %s with size %s.",
metaname, display_size(cmd, meta_sectors));
@ -197,6 +203,8 @@ int lv_extend_integrity_in_raid(struct logical_volume *lv, struct dm_list *pvh)
meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_bytes, 0, 0);
meta_sectors = meta_bytes / 512;
meta_extents = meta_sectors / vg->extent_size;
if (!meta_extents)
meta_extents = 1;
prev_meta_sectors = lv_imeta->size;
prev_meta_extents = prev_meta_sectors / vg->extent_size;
@ -231,16 +239,17 @@ int lv_extend_integrity_in_raid(struct logical_volume *lv, struct dm_list *pvh)
return 1;
}
int lv_remove_integrity_from_raid(struct logical_volume *lv)
int lv_remove_integrity_from_raid(struct logical_volume *lv, char **remove_images)
{
struct logical_volume *iorig_lvs[DEFAULT_RAID_MAX_IMAGES];
struct logical_volume *imeta_lvs[DEFAULT_RAID_MAX_IMAGES];
struct logical_volume *iorig_lvs[DEFAULT_RAID_MAX_IMAGES] = { 0 };
struct logical_volume *imeta_lvs[DEFAULT_RAID_MAX_IMAGES] = { 0 };
struct cmd_context *cmd = lv->vg->cmd;
struct volume_group *vg = lv->vg;
struct lv_segment *seg_top, *seg_image;
struct logical_volume *lv_image;
struct logical_volume *lv_iorig;
struct logical_volume *lv_imeta;
char *max_image_array = remove_images ? *remove_images : NULL;
uint32_t area_count, s;
int is_active = lv_is_active(lv);
@ -253,12 +262,19 @@ int lv_remove_integrity_from_raid(struct logical_volume *lv)
return 0;
}
log_debug("Removing integrity from raid LV %s %s", display_lvname(lv), remove_images ? "partial" : "");
area_count = seg_top->area_count;
for (s = 0; s < area_count; s++) {
if (max_image_array && !max_image_array[s])
continue;
lv_image = seg_lv(seg_top, s);
seg_image = first_seg(lv_image);
log_debug("Removing integrity layers from %s", lv_image->name);
if (!(lv_imeta = seg_image->integrity_meta_dev)) {
log_error("LV %s segment has no integrity metadata device.", display_lvname(lv));
return 0;
@ -293,10 +309,15 @@ int lv_remove_integrity_from_raid(struct logical_volume *lv)
}
for (s = 0; s < area_count; s++) {
if (max_image_array && !max_image_array[s])
continue;
lv_iorig = iorig_lvs[s];
lv_imeta = imeta_lvs[s];
if (is_active) {
log_debug("Deactivating unused integrity layers %s %s", lv_iorig->name, lv_imeta->name);
if (!deactivate_lv(cmd, lv_iorig))
log_error("Failed to deactivate unused iorig LV %s.", lv_iorig->name);
@ -307,6 +328,8 @@ int lv_remove_integrity_from_raid(struct logical_volume *lv)
lv_imeta->status &= ~INTEGRITY_METADATA;
lv_set_visible(lv_imeta);
log_debug("Removing unused integrity LVs %s %s", lv_iorig->name, lv_imeta->name);
if (!lv_remove(lv_iorig))
log_error("Failed to remove unused iorig LV %s.", lv_iorig->name);

View File

@ -65,6 +65,8 @@ struct logical_volume {
uint64_t timestamp;
unsigned new_lock_args:1;
unsigned to_remove:1; /* set when LV is known to be removed */
unsigned lockd_thin_pool_locked:1; /* set after locking thin pool in lvmlockd */
unsigned lockd_thin_pool_unlocked:1; /* set after unlocking thin pool in lvmlockd */
const char *hostname;
const char *lock_args;
};

View File

@ -97,6 +97,8 @@ enum {
LV_TYPE_HISTORY,
LV_TYPE_LINEAR,
LV_TYPE_STRIPED,
LV_TYPE_ERROR,
LV_TYPE_ZERO,
LV_TYPE_MIRROR,
LV_TYPE_RAID,
LV_TYPE_THIN,
@ -154,6 +156,8 @@ static const char _lv_type_names[][24] = {
[LV_TYPE_HISTORY] = "history",
[LV_TYPE_LINEAR] = "linear",
[LV_TYPE_STRIPED] = "striped",
[LV_TYPE_ERROR] = "error",
[LV_TYPE_ZERO] = "zero",
[LV_TYPE_MIRROR] = "mirror",
[LV_TYPE_RAID] = "raid",
[LV_TYPE_THIN] = "thin",
@ -583,7 +587,7 @@ bad:
int lv_layout_and_role(struct dm_pool *mem, const struct logical_volume *lv,
struct dm_list **layout, struct dm_list **role) {
int linear, striped;
int linear, striped, error, zero;
struct lv_segment *seg;
int public_lv = 1;
@ -659,12 +663,16 @@ int lv_layout_and_role(struct dm_pool *mem, const struct logical_volume *lv,
* linear or striped or mixture of these two.
*/
if (dm_list_empty(*layout)) {
linear = striped = 0;
linear = striped = error = zero = 0;
dm_list_iterate_items(seg, &lv->segments) {
if (seg_is_linear(seg))
linear = 1;
else if (seg_is_striped(seg))
striped = 1;
else if (seg_is_error(seg))
error = 1;
else if (seg_is_zero(seg))
zero = 1;
else {
/*
* This should not happen but if it does
@ -687,7 +695,15 @@ int lv_layout_and_role(struct dm_pool *mem, const struct logical_volume *lv,
!str_list_add_no_dup_check(mem, *layout, _lv_type_names[LV_TYPE_STRIPED]))
goto_bad;
if (!linear && !striped &&
if (error &&
!str_list_add_no_dup_check(mem, *layout, _lv_type_names[LV_TYPE_ERROR]))
goto_bad;
if (zero &&
!str_list_add_no_dup_check(mem, *layout, _lv_type_names[LV_TYPE_ZERO]))
goto_bad;
if (!linear && !striped && !error && !zero &&
!str_list_add_no_dup_check(mem, *layout, _lv_type_names[LV_TYPE_UNKNOWN]))
goto_bad;
}
@ -1214,7 +1230,7 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t
if (vg_is_shared(vg)) {
if (!lockd_lv_name(vg->cmd, vg, lv->name, &lv->lvid.id[1], lv->lock_args, "un", LDLV_PERSISTENT))
log_error("Failed to unlock vdo pool in lvmlockd.");
lockd_free_lv_after_update(vg->cmd, vg, lv->name, &lv->lvid.id[1], lv->lock_args);
lockd_free_lv_queue(vg->cmd, vg, lv->name, &lv->lvid.id[1], lv->lock_args);
}
return 1;
}
@ -1694,7 +1710,7 @@ int replace_lv_with_error_segment(struct logical_volume *lv)
* that suggest it is anything other than "error".
*/
/* FIXME Check for other flags that need removing */
lv->status &= ~(MIRROR|MIRRORED|PVMOVE|LOCKED);
lv->status &= ~(MIRROR|MIRRORED|LV_NOTSYNCED|PVMOVE|LOCKED);
/* FIXME Check for any attached LVs that will become orphans e.g. mirror logs */
@ -2615,7 +2631,8 @@ static int _reserve_required_area(struct alloc_handle *ah, struct alloc_state *a
/* Expand areas array if needed after an area was split. */
if (ix_pva >= alloc_state->areas_size) {
alloc_state->areas_size *= 2;
if (!(new_state = realloc(alloc_state->areas, sizeof(*alloc_state->areas) * (alloc_state->areas_size)))) {
if (!alloc_state->areas_size ||
!(new_state = realloc(alloc_state->areas, sizeof(*alloc_state->areas) * (alloc_state->areas_size)))) {
log_error("Memory reallocation for parallel areas failed.");
return 0;
}
@ -3408,7 +3425,8 @@ static int _allocate(struct alloc_handle *ah,
alloc_state.areas_size += _stripes_per_mimage(prev_lvseg) * prev_lvseg->area_count;
/* Allocate an array of pv_areas to hold the largest space on each PV */
if (!(alloc_state.areas = malloc(sizeof(*alloc_state.areas) * alloc_state.areas_size))) {
if (!alloc_state.areas_size ||
!(alloc_state.areas = malloc(sizeof(*alloc_state.areas) * alloc_state.areas_size))) {
log_error("Couldn't allocate areas array.");
return 0;
}
@ -5569,13 +5587,8 @@ static int _lvresize_adjust_extents(struct logical_volume *lv,
log_print_unless_silent("Reached maximum COW size %s (%" PRIu32 " extents).",
display_size(vg->cmd, (uint64_t) vg->extent_size * logical_extents_used),
logical_extents_used);
lp->extents = logical_extents_used; // CHANGES lp->extents
seg_size = lp->extents - existing_logical_extents; // Recalculate
if (lp->extents == existing_logical_extents) {
/* Signal that normal resizing is not required */
lp->size_changed = 1;
return 1;
}
/* Truncate lp->extents to logical_extents_used */
lp->extents = logical_extents_used;
}
} else if (lv_is_thin_pool_metadata(lv)) {
if (!(seg = get_only_segment_using_this_lv(lv)))
@ -7573,12 +7586,12 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
struct volume_group *vg;
int visible, historical;
struct logical_volume *pool_lv = NULL;
struct logical_volume *lock_lv = lv;
struct logical_volume *lockd_pool = NULL;
struct logical_volume *lockd_other = NULL;
struct lv_segment *cache_seg = NULL;
struct seg_list *sl;
struct lv_segment *seg = first_seg(lv);
char msg[NAME_LEN + 300], *msg_dup;
int other_unlock = 0;
vg = lv->vg;
@ -7628,7 +7641,6 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
display_lvname(lv));
return 0;
}
lock_lv = pool_lv;
if (pool_lv->to_remove)
/* Thin pool is to be removed so skip updating it when possible */
pool_lv = NULL;
@ -7639,21 +7651,8 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
return 0;
}
if (vg_is_shared(vg)) {
if (lv_is_thin_type(lv)) {
/* FIXME: is this also needed for other types? */
/* Thin is special because it needs to be active and locked to remove. */
if (lv_is_thin_volume(lv))
lockd_pool = first_seg(lv)->pool_lv;
else if (lv_is_thin_pool(lv))
lockd_pool = lv;
if (!lockd_lv(cmd, lock_lv, "ex", LDLV_PERSISTENT))
return_0;
} else {
if (!lockd_lv(cmd, lock_lv, "ex", LDLV_PERSISTENT))
return_0;
}
}
if (!lockd_lvremove_lock(cmd, lv, &lockd_other, &other_unlock))
return_0;
if (!lv_is_cache_vol(lv)) {
if (!_lv_remove_check_in_use(lv, force))
@ -7802,14 +7801,7 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
display_lvname(pool_lv));
}
if (lockd_pool && !thin_pool_is_active(lockd_pool)) {
if (!lockd_lv_name(cmd, vg, lockd_pool->name, &lockd_pool->lvid.id[1], lockd_pool->lock_args, "un", LDLV_PERSISTENT))
log_warn("WARNING: Failed to unlock %s.", display_lvname(lockd_pool));
} else {
if (!lockd_lv(cmd, lv, "un", LDLV_PERSISTENT))
log_warn("WARNING: Failed to unlock %s.", display_lvname(lv));
}
lockd_free_lv_after_update(cmd, vg, lv->name, &lv->lvid.id[1], lv->lock_args);
lockd_lvremove_done(cmd, lv, lockd_other, other_unlock);
if (!suppress_remove_message && (visible || historical)) {
(void) dm_snprintf(msg, sizeof(msg),
@ -9158,6 +9150,11 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
int thin_pool_was_active = -1; /* not scanned, inactive, active */
int historical;
uint64_t transaction_id;
uint32_t flags = 0;
int creating_thin_pool = 0;
int creating_thin_volume = 0;
int creating_cow_snapshot = 0;
int creating_vdo_volume = 0;
int ret;
if (new_lv_name && lv_name_is_used_in_vg(vg, new_lv_name, &historical)) {
@ -9239,6 +9236,28 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
return NULL;
}
/*
* TODO: do this for each type, and use these
* creating_foo variables in the code below in
* place of the seg_is_ calls.
*/
if ((creating_thin_pool = seg_is_thin_pool(lp)))
log_debug("Creating LV: thin pool");
if ((creating_thin_volume = seg_is_thin_volume(lp)))
log_debug("Creating LV: thin volume");
if ((creating_cow_snapshot = (!seg_is_thin_volume(lp) && lp->snapshot)))
log_debug("Creating LV: cow snapshot");
if ((creating_vdo_volume = seg_is_vdo(lp)))
log_debug("Creating LV: vdo volume");
/*
* Another LV, related to the new LV, may need to be locked before
* creating the new LV, e.g. locking the pool or origin for the new LV.
*/
if (!lockd_lvcreate_lock(cmd, vg, lp, creating_thin_pool, creating_thin_volume,
creating_cow_snapshot, creating_vdo_volume))
return NULL;
if (seg_is_pool(lp))
status |= LVM_WRITE; /* Pool is always writable */
else if (seg_is_cache(lp) || seg_is_thin_volume(lp) || seg_is_vdo(lp)) {
@ -9288,11 +9307,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
return_NULL;
/* New pool is now inactive */
} else {
if (!lockd_lv(cmd, pool_lv, "ex", LDLV_PERSISTENT)) {
log_error("Failed to lock thin pool.");
return NULL;
}
if (!activate_lv(cmd, pool_lv)) {
log_error("Aborting. Failed to locally activate thin pool %s.",
display_lvname(pool_lv));
@ -9457,14 +9471,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
lv->major, lv->minor);
}
/*
* The specific LV may not use a lock. lockd_init_lv() sets
* lv->lock_args to NULL if this LV does not use its own lock.
*/
if (!lockd_init_lv(vg->cmd, vg, lv, lp))
return_NULL;
dm_list_splice(&lv->tags, &lp->tags);
if (!lv_extend(lv, create_segtype,
@ -9574,16 +9580,47 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
if (lv_activation_skip(lv, lp->activate, lp->activation_skip & ACTIVATION_SKIP_IGNORE))
lp->activate = CHANGE_AN;
/* store vg on disk(s) */
if (!vg_write(vg) || !vg_commit(vg))
/* Pool created metadata LV, but better avoid recover when vg_write/commit fails */
/*
* Allocate a lock for the LV, if it needs one.
* (With sanlock this is an on disk allocation.)
*/
if (!lockd_init_lv(cmd, vg, lv, lp))
return_NULL;
/* store vg on disk(s) */
if (!vg_write(vg) || !vg_commit(vg)) {
/* Pool created metadata LV, but better avoid recover when vg_write/commit fails */
/* Reverse the lockd_init_lv. */
if (lv->lock_args)
lockd_free_lv(cmd, vg, lv->name, &lv->lvid.id[1], lv->lock_args);
return_NULL;
}
if (test_mode()) {
log_verbose("Test mode: Skipping activation, zeroing and signature wiping.");
goto out;
}
/*
* The lock for the new thin pool was created during vg_write,
* so we can now acquire it.
*/
if (cmd->lockd_creating_thin_pool) {
log_debug("lockd_creating_thin_pool lockd_lv ex for new thin pool.");
if (!lockd_lv(cmd, lv, "ex", LDLV_PERSISTENT | LDLV_CREATING_THIN_POOL)) {
log_error("Failed to lock thin pool after creating it.");
goto out;
}
cmd->lockd_created_thin_pool = 1;
/* Save pool info to use in lockd_lvcreate_done() */
if (!(lp->lockd_name = dm_pool_strdup(cmd->mem, lv->name)))
stack;
}
if (cmd->lockd_creating_thin_volume)
cmd->lockd_created_thin_volume = 1;
if (seg_is_raid(lp) && lp->raidintegrity) {
log_debug("Adding integrity to new LV");
@ -9620,7 +9657,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
} else if (lv_is_cache_pool(lv)) {
/* Cache pool cannot be activated and zeroed */
log_very_verbose("Cache pool is prepared.");
} else if (lv_is_thin_volume(lv)) {
} else if (pool_lv && lv_is_thin_volume(lv)) {
/* Optimize the case when taking a snapshot within same pool and thin origin
* is an active LV, so we can pass thin message with suspend/resume of this LV. */
if (origin_lv && lv_is_thin_volume(origin_lv) &&
@ -9674,10 +9711,13 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
/* Avoid multiple thin-pool activations in this case */
if (thin_pool_was_active < 0)
thin_pool_was_active = 0;
if (!lockd_lv(cmd, pool_lv, "ex", LDLV_PERSISTENT)) {
log_error("Failed to lock thin pool.");
return NULL;
if (vg_is_shared(vg) && !pool_lv->lockd_thin_pool_locked) {
/* sanity check, shouldn't happen */
log_error(INTERNAL_ERROR "thin pool not locked");
goto revert_new_lv;
}
if (!activate_lv(cmd, pool_lv)) {
log_error("Failed to activate thin pool %s.",
display_lvname(pool_lv));
@ -9707,10 +9747,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
log_error("Failed to deactivate thin pool %s.", display_lvname(pool_lv));
return NULL;
}
if (!lockd_lv(cmd, pool_lv, "un", LDLV_PERSISTENT)) {
log_error("Failed to unlock thin pool.");
return NULL;
}
}
} else if (lp->snapshot) {
lv->status |= LV_TEMPORARY;
@ -9883,6 +9919,7 @@ out:
return lv;
deactivate_and_revert_new_lv:
log_debug("deactivating to revert new lv");
if (!sync_local_dev_names(lv->vg->cmd))
log_error("Failed to sync local devices before reverting %s.",
display_lvname(lv));
@ -9893,7 +9930,13 @@ deactivate_and_revert_new_lv:
}
revert_new_lv:
if (!lockd_lv(cmd, lv, "un", LDLV_PERSISTENT))
log_debug("reverting new lv");
flags = LDLV_PERSISTENT;
if (cmd->lockd_creating_thin_pool)
flags |= LDLV_CREATING_THIN_POOL;
else if (cmd->lockd_creating_thin_volume)
flags |= LDLV_CREATING_THIN_VOLUME;
if (!lockd_lv(cmd, lv, "un", flags))
log_warn("WARNING: Failed to unlock %s.", display_lvname(lv));
lockd_free_lv(vg->cmd, vg, lv->name, &lv->lvid.id[1], lv->lock_args);
@ -9921,8 +9964,6 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
if (!(lp->segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_THIN_POOL)))
return_NULL;
/* We want a lockd lock for the new thin pool, but not the thin lv. */
lp->needs_lockd_init = 1;
/* When creating thin volume with new thin-pool avoid activating
* new empty pool so it's not necessary to reactivate is as used thin-pool */
tmp = lp->activate;
@ -9930,6 +9971,8 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
if (!(lv = _lv_create_an_lv(vg, lp, lp->pool_name)))
return_NULL;
lp->activate = tmp; /* restore activation */
/* The thin pool had a lock created, but thin volumes do not. */
lp->needs_lockd_init = 0;
} else if (seg_is_cache(lp)) {
@ -9960,13 +10003,11 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
if (!(lp->segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_VDO_POOL)))
return_NULL;
/* We want a lockd lock for the new vdo pool, but not the vdo lv. */
lp->needs_lockd_init = 1;
/* Use vpool names for vdo-pool */
if (!(lv = _lv_create_an_lv(vg, lp, lp->pool_name ? : "vpool%d")))
return_NULL;
/* The vdo pool had a lock created, but vdo volumes do not. */
lp->needs_lockd_init = 0;
} else {
log_error(INTERNAL_ERROR "Creation of pool for unsupported segment type %s.",

View File

@ -20,6 +20,7 @@
#include "lib/metadata/pv_alloc.h"
#include "lib/datastruct/str_list.h"
#include "lib/metadata/segtype.h"
#include "lib/display/display.h"
/*
* Attempt to merge two adjacent segments.
@ -85,14 +86,14 @@ int lv_merge_segments(struct logical_volume *lv)
* bogus segment structure setup.
*/
#define raid_seg_error(msg) do { \
log_error("LV %s invalid: %s for %s segment", \
log_error("LV %s invalid: %s for %s segment.", \
display_lvname(seg->lv), (msg), lvseg_name(seg)); \
if ((*error_count)++ > ERROR_MAX) \
return; \
} while (0)
#define raid_seg_error_val(msg, val) do { \
log_error("LV %s invalid: %s (is %u) for %s segment", \
log_error("LV %s invalid: %s (is %u) for %s segment.", \
display_lvname(seg->lv), (msg), (val), lvseg_name(seg)); \
if ((*error_count)++ > ERROR_MAX) \
return; \
@ -281,16 +282,20 @@ static void _check_raid_seg(struct lv_segment *seg, int *error_count)
/* Default < 10, change once raid1 split shift and rename SubLVs works! */
if (seg_is_raid1(seg)) {
if (seg->area_count > DEFAULT_RAID1_MAX_IMAGES) {
log_error("LV %s invalid: maximum supported areas %u (is %u) for %s segment",
seg->lv->name, DEFAULT_RAID1_MAX_IMAGES, seg->area_count, lvseg_name(seg));
if ((*error_count)++ > ERROR_MAX)
return;
}
} else if (seg->area_count > DEFAULT_RAID_MAX_IMAGES) {
log_error("LV %s invalid: maximum supported areas %u (is %u) for %s segment",
seg->lv->name, DEFAULT_RAID_MAX_IMAGES, seg->area_count, lvseg_name(seg));
log_error("LV %s invalid: maximum supported areas %u "
"(is %u) for %s segment.",
seg->lv->name, DEFAULT_RAID1_MAX_IMAGES,
seg->area_count, lvseg_name(seg));
if ((*error_count)++ > ERROR_MAX)
return;
}
} else if (seg->area_count > DEFAULT_RAID_MAX_IMAGES) {
log_error("LV %s invalid: maximum supported areas %u "
"(is %u) for %s segment.",
seg->lv->name, DEFAULT_RAID_MAX_IMAGES,
seg->area_count, lvseg_name(seg));
if ((*error_count)++ > ERROR_MAX)
return;
}
/* FIXME: should we check any non-RAID segment struct members at all? */
@ -626,7 +631,7 @@ int check_lv_segments_complete_vg(struct logical_volume *lv)
seg_le(seg, s))) ||
find_mirror_seg(seg2) != seg)) {
log_error("LV %s: segment %u mirror "
"image %u missing mirror ptr",
"image %u missing mirror ptr.",
lv->name, seg_count, s);
inc_error_count;
}
@ -650,7 +655,9 @@ int check_lv_segments_complete_vg(struct logical_volume *lv)
lv_is_raid(lv) ||
lv_is_snapshot(lv) ||
lv_is_thin_pool(lv) ||
lv_is_thin_volume(lv))) {
lv_is_thin_volume(lv) ||
lv_is_vdo_pool(lv) ||
lv_is_vdo(lv))) {
log_error("LV %s must have exactly one segment.",
lv->name);
inc_error_count;
@ -660,7 +667,7 @@ int check_lv_segments_complete_vg(struct logical_volume *lv)
(!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) ||
seg2->area_count != 1 || seg_type(seg2, 0) != AREA_LV ||
seg_lv(seg2, 0) != lv)) {
log_error("LV %s: segment 1 pool data LV does not point back to same LV",
log_error("LV %s: segment 1 pool data LV does not point back to same LV.",
lv->name);
inc_error_count;
}
@ -731,7 +738,7 @@ int check_lv_segments_incomplete_vg(struct logical_volume *lv)
if (seg->len != seg->area_len &&
seg->len != seg->area_len * data_rimage_count) {
log_error("LV %s: segment %u with len=%u "
" has inconsistent area_len %u",
"has inconsistent area_len %u.",
lv->name, seg_count, seg->len, seg->area_len);
inc_error_count;
}
@ -739,7 +746,7 @@ int check_lv_segments_incomplete_vg(struct logical_volume *lv)
if (seg_is_snapshot(seg)) {
if (seg->cow && seg->cow == seg->origin) {
log_error("LV %s: segment %u has same LV %s for "
"both origin and snapshot",
"both origin and snapshot.",
lv->name, seg_count, seg->cow->name);
inc_error_count;
}
@ -747,8 +754,8 @@ int check_lv_segments_incomplete_vg(struct logical_volume *lv)
for (s = 0; s < seg->area_count; s++) {
if (seg_type(seg, s) == AREA_UNASSIGNED) {
log_error("LV %s: segment %u has unassigned "
"area %u.",
log_error("LV %s: segment %u has "
"unassigned area %u.",
lv->name, seg_count, s);
inc_error_count;
} else if (seg_type(seg, s) == AREA_PV) {
@ -756,7 +763,7 @@ int check_lv_segments_incomplete_vg(struct logical_volume *lv)
seg_pvseg(seg, s)->lvseg != seg ||
seg_pvseg(seg, s)->lv_area != s) {
log_error("LV %s: segment %u has "
"inconsistent PV area %u",
"inconsistent PV area %u.",
lv->name, seg_count, s);
inc_error_count;
}
@ -765,9 +772,11 @@ int check_lv_segments_incomplete_vg(struct logical_volume *lv)
seg_lv(seg, s)->vg != lv->vg ||
seg_lv(seg, s) == lv) {
log_error("LV %s: segment %u has "
"inconsistent LV area %u",
"inconsistent LV area %u.",
lv->name, seg_count, s);
inc_error_count;
/* Can't check more of such segment */
continue;
}
@ -786,15 +795,15 @@ int check_lv_segments_incomplete_vg(struct logical_volume *lv)
seg_found++;
if (!seg_found) {
log_error("LV %s segment %u uses LV %s,"
" but missing ptr from %s to %s",
log_error("LV %s segment %u uses LV %s, "
"but missing ptr from %s to %s.",
lv->name, seg_count,
seg_lv(seg, s)->name,
seg_lv(seg, s)->name, lv->name);
inc_error_count;
} else if (seg_found > 1) {
log_error("LV %s has duplicated links "
"to LV %s segment %u",
"to LV %s segment %u.",
seg_lv(seg, s)->name,
lv->name, seg_count);
inc_error_count;
@ -807,7 +816,7 @@ int check_lv_segments_incomplete_vg(struct logical_volume *lv)
}
if (le != lv->le_count) {
log_error("LV %s: inconsistent LE count %u != %u",
log_error("LV %s: inconsistent LE count %u != %u.",
lv->name, le, lv->le_count);
inc_error_count;
}
@ -843,7 +852,7 @@ int check_lv_segments_incomplete_vg(struct logical_volume *lv)
if (!seg_found) {
log_error("LV %s is used by LV %s:%" PRIu32 "-%" PRIu32
", but missing ptr from %s to %s",
", but missing ptr from %s to %s.",
lv->name, seg->lv->name, seg->le,
seg->le + seg->len - 1,
seg->lv->name, lv->name);
@ -851,7 +860,7 @@ int check_lv_segments_incomplete_vg(struct logical_volume *lv)
} else if (seg_found != sl->count) {
log_error("Reference count mismatch: LV %s has %u "
"links to LV %s:%" PRIu32 "-%" PRIu32
", which has %u links",
", which has %u links.",
lv->name, sl->count, seg->lv->name, seg->le,
seg->le + seg->len - 1, seg_found);
inc_error_count;
@ -866,7 +875,7 @@ int check_lv_segments_incomplete_vg(struct logical_volume *lv)
if (!seg_found) {
log_error("LV segment %s:%" PRIu32 "-%" PRIu32
" is incorrectly listed as being used by LV %s",
" is incorrectly listed as being used by LV %s.",
seg->lv->name, seg->le, seg->le + seg->len - 1,
lv->name);
inc_error_count;
@ -876,16 +885,16 @@ int check_lv_segments_incomplete_vg(struct logical_volume *lv)
dm_list_iterate_items(glvl, &lv->indirect_glvs) {
if (glvl->glv->is_historical) {
if (glvl->glv->historical->indirect_origin != lv->this_glv) {
log_error("LV %s is indirectly used by historical LV %s"
"but that historical LV does not point back to LV %s",
log_error("LV %s is indirectly used by historical LV %s "
"but that historical LV does not point back to LV %s.",
lv->name, glvl->glv->historical->name, lv->name);
inc_error_count;
}
} else {
if (!(seg = first_seg(glvl->glv->live)) ||
seg->indirect_origin != lv->this_glv) {
log_error("LV %s is indirectly used by LV %s"
"but that LV does not point back to LV %s",
log_error("LV %s is indirectly used by LV %s "
"but that LV does not point back to LV %s.",
lv->name, glvl->glv->live->name, lv->name);
inc_error_count;
}
@ -910,7 +919,7 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
if (!seg_can_split(seg)) {
log_error("Unable to split the %s segment at LE %" PRIu32
" in LV %s", lvseg_name(seg), le, lv->name);
" in LV %s.", lvseg_name(seg), le, lv->name);
return 0;
}
@ -927,7 +936,7 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
}
if (!str_list_dup(lv->vg->vgmem, &split_seg->tags, &seg->tags)) {
log_error("LV segment tags duplication failed");
log_error("LV segment tags duplication failed.");
return 0;
}
@ -954,7 +963,7 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
if (!set_lv_segment_area_lv(split_seg, s, seg_lv(seg, s),
seg_le(seg, s) + seg->area_len, 0))
return_0;
log_debug_alloc("Split %s:%u[%u] at %u: %s LE %u", lv->name,
log_debug_alloc("Split %s:%u[%u] at %u: %s LE %u.", lv->name,
seg->le, s, le, seg_lv(seg, s)->name,
seg_le(split_seg, s));
break;
@ -968,14 +977,14 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
seg->area_len,
split_seg, s)))
return_0;
log_debug_alloc("Split %s:%u[%u] at %u: %s PE %u", lv->name,
log_debug_alloc("Split %s:%u[%u] at %u: %s PE %u.", lv->name,
seg->le, s, le,
dev_name(seg_dev(seg, s)),
seg_pe(split_seg, s));
break;
case AREA_UNASSIGNED:
log_error("Unassigned area %u found in segment", s);
log_error("Unassigned area %u found in segment.", s);
return 0;
}
}
@ -994,7 +1003,7 @@ int lv_split_segment(struct logical_volume *lv, uint32_t le)
struct lv_segment *seg;
if (!(seg = find_seg_by_le(lv, le))) {
log_error("Segment with extent %" PRIu32 " in LV %s not found",
log_error("Segment with extent %" PRIu32 " in LV %s not found.",
le, lv->name);
return 0;
}

View File

@ -814,7 +814,7 @@ struct wipe_params {
};
/* Zero out LV and/or wipe signatures */
int wipe_lv(struct logical_volume *lv, struct wipe_params params);
int wipe_lv(struct logical_volume *lv, struct wipe_params wp);
/* Wipe any signatures and zero first sector on @lv */
int activate_and_wipe_lv(struct logical_volume *lv, int commit);
@ -1018,8 +1018,7 @@ struct lvcreate_params {
const char *lv_name; /* all */
const char *origin_name; /* snap */
const char *pool_name; /* thin */
const char *lock_args;
const char *lockd_name;
uint32_t stripes; /* striped/RAID */
uint32_t stripe_size; /* striped/RAID */
@ -1221,7 +1220,7 @@ int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
uint32_t mirrors, uint32_t stripes, uint32_t stripe_size,
uint32_t region_size, uint32_t log_count,
struct dm_list *pvs, alloc_policy_t alloc, uint32_t flags);
int lv_split_mirror_images(struct logical_volume *lv, const char *split_lv_name,
int lv_split_mirror_images(struct logical_volume *lv, const char *split_name,
uint32_t split_count, struct dm_list *removable_pvs);
int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
uint32_t mirrors, uint32_t log_count,
@ -1497,7 +1496,7 @@ struct dm_list *clone_pv_list(struct dm_pool *mem, struct dm_list *pvsl);
int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_settings *settings, struct dm_list *pvh,
struct logical_volume *lv_imeta_0);
int lv_remove_integrity_from_raid(struct logical_volume *lv);
int lv_remove_integrity_from_raid(struct logical_volume *lv, char **remove_images);
void lv_clear_integrity_recalculate_metadata(struct logical_volume *lv);
int lv_has_integrity_recalculate_metadata(struct logical_volume *lv);
int lv_raid_has_integrity(struct logical_volume *lv);

View File

@ -67,6 +67,13 @@ static int _check_pv_ext(struct cmd_context *cmd, struct volume_group *vg)
if (!(info = lvmcache_info_from_pvid(pvl->pv->dev->pvid, pvl->pv->dev, 0)))
continue;
/*
* If this vg metadata is old/outdated, it may no longer reflect the
* actual VG containing this PV, in which case we ignore this check.
*/
if (!lvmcache_verify_info_in_vg(vg, info))
continue;
ext_version = lvmcache_ext_version(info);
if (ext_version < PV_HEADER_EXTENSION_VSN) {
log_warn("WARNING: PV %s in VG %s is using an old PV header, modify the VG to update.",
@ -2934,7 +2941,6 @@ int vg_write(struct volume_group *vg)
struct dm_list *mdah;
struct pv_list *pvl, *pvl_safe, *new_pvl;
struct metadata_area *mda;
struct lv_list *lvl;
struct device *mda_dev;
int revert = 0, wrote = 0;
@ -2943,20 +2949,6 @@ int vg_write(struct volume_group *vg)
log_debug("Writing metadata for VG %s.", vg->name);
if (vg_is_shared(vg)) {
const char *last_args = NULL;
dm_list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->lock_args && !strcmp(lvl->lv->lock_args, "pending")) {
if (!lockd_init_lv_args(vg->cmd, vg, lvl->lv, vg->lock_type, last_args, &lvl->lv->lock_args)) {
log_error("Cannot allocate lock for new LV.");
return 0;
}
last_args = lvl->lv->lock_args;
lvl->lv->new_lock_args = 1;
}
}
}
if (!_handle_historical_lvs(vg)) {
log_error("Failed to handle historical LVs in VG %s.", vg->name);
return 0;
@ -3197,14 +3189,6 @@ int vg_commit(struct volume_group *vg)
void vg_revert(struct volume_group *vg)
{
struct metadata_area *mda;
struct lv_list *lvl;
dm_list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->new_lock_args) {
lockd_free_lv(vg->cmd, vg, lvl->lv->name, &lvl->lv->lvid.id[1], lvl->lv->lock_args);
lvl->lv->new_lock_args = 0;
}
}
_vg_wipe_cached_precommitted(vg); /* VG is no longer needed */
@ -3659,29 +3643,6 @@ int pv_write(struct cmd_context *cmd,
return 1;
}
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv)
{
const char *old_vg_name = pv->vg_name;
pv->vg_name = cmd->fmt->orphan_vg_name;
pv->status = ALLOCATABLE_PV;
pv->pe_alloc_count = 0;
if (!dev_get_size(pv->dev, &pv->size)) {
log_error("%s: Couldn't get size.", pv_dev_name(pv));
return 0;
}
if (!pv_write(cmd, pv, 0)) {
log_error("Failed to clear metadata from physical "
"volume \"%s\" after removal from \"%s\"",
pv_dev_name(pv), old_vg_name);
return 0;
}
return 1;
}
/**
* is_orphan_vg - Determine whether a vg_name is an orphan
* @vg_name: pointer to the vg_name
@ -4136,6 +4097,11 @@ struct metadata_area *fid_get_mda_indexed(struct format_instance *fid,
static char full_key[PATH_MAX];
struct metadata_area *mda = NULL;
if (!fid) {
log_error(INTERNAL_ERROR "FID is not defined!");
return NULL;
}
if (!fid->metadata_areas_index)
return_NULL;
@ -4689,13 +4655,15 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
const char *vgname,
const char *vgid,
unsigned precommitted,
int writing)
int writing,
int *incorrect_pv_claim)
{
const struct format_type *fmt = cmd->fmt;
struct format_instance *fid = NULL;
struct format_instance_ctx fic;
struct volume_group *vg, *vg_ret = NULL;
struct metadata_area *mda, *mda2;
struct pv_list *pvl;
unsigned use_precommitted = precommitted;
struct device *mda_dev, *dev_ret = NULL;
struct cached_vg_fmtdata *vg_fmtdata = NULL; /* Additional format-specific data about the vg */
@ -4933,7 +4901,15 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
* Also, outdated PVs that have been removed from the VG were incorrectly
* attached to the vginfo during label_scan, and now need to be detached.
*/
lvmcache_update_vg_from_read(vg_ret, vg_ret->status & PRECOMMITTED);
lvmcache_update_vg_from_read(vg_ret, incorrect_pv_claim);
/* Undo set_pv_devices for PVs that are incorrectly claimed. */
if (incorrect_pv_claim) {
dm_list_iterate_items(pvl, &vg_ret->pvs) {
if (pvl->pv->wrong_vg)
pvl->pv->dev = NULL;
}
}
/*
* lvmcache_update_vg identified outdated mdas that we read above that
@ -4967,6 +4943,8 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
int original_vgid_set = vgid ? 1 : 0;
int writing = (vg_read_flags & READ_FOR_UPDATE);
int activating = (vg_read_flags & READ_FOR_ACTIVATE);
int is_duplicate_vgname;
int incorrect_pv_claim = 0;
*error_flags = SUCCESS;
if (error_vg)
@ -5031,14 +5009,27 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
goto_bad;
}
/* Update DM cache after grabbing lock
* TODO: do a lazy-update of this cache, only when it's really used */
if (dm_devs_cache_use()) {
log_debug_cache("Rescanning DM cache.");
if (!dm_devs_cache_update()) {
log_error("Can't allocate DM cache memory for VG %s.", vg_name);
failure |= FAILED_ALLOCATION;
goto bad;
}
}
is_duplicate_vgname = lvmcache_has_duplicate_local_vgname(vgid, vg_name);
/*
* vgchange -ay (no vgname arg) will activate multiple local VGs with the same
* name, but if the vgs have the same lv name, activating those lvs will fail.
*/
if (activating && original_vgid_set && lvmcache_has_duplicate_local_vgname(vgid, vg_name))
if (activating && original_vgid_set && is_duplicate_vgname)
log_warn("WARNING: activating multiple VGs with the same name is dangerous and may fail.");
if (!(vg = _vg_read(cmd, vg_name, vgid, 0, writing))) {
if (!(vg = _vg_read(cmd, vg_name, vgid, 0, writing, &incorrect_pv_claim))) {
unlock_vg(cmd, NULL, vg_name);
/* Some callers don't care if the VG doesn't exist and don't want an error message. */
if (!(vg_read_flags & READ_OK_NOTFOUND))
@ -5087,11 +5078,14 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
/* The obvious and common case of a missing device. */
if ((vg_is_foreign(vg) && !cmd->include_foreign_vgs) || cmd->expect_missing_vg_device)
log_debug("VG %s is missing PV %s (last written to %s)", vg_name, uuidstr, pvl->pv->device_hint ?: "na");
log_debug("VG %s is missing PV %s (last written to %s)",
is_duplicate_vgname ? vgid : vg_name, uuidstr, pvl->pv->device_hint ?: "na");
else if (pvl->pv->device_hint)
log_warn("WARNING: VG %s is missing PV %s (last written to %s).", vg_name, uuidstr, pvl->pv->device_hint);
log_warn("WARNING: VG %s is missing PV %s (last written to %s).",
is_duplicate_vgname ? vgid : vg_name, uuidstr, pvl->pv->device_hint);
else
log_warn("WARNING: VG %s is missing PV %s.", vg_name, uuidstr);
log_warn("WARNING: VG %s is missing PV %s.",
is_duplicate_vgname ? vgid : vg_name, uuidstr);
missing_pv_dev++;
} else if (pvl->pv->status & MISSING_PV) {
@ -5165,6 +5159,18 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
goto bad;
}
/*
* If the VG metadata is referencing PVs that don't belong to it,
* then don't allow the VG to be modified or activated, to avoid
* damanging those PVs.
*/
if (incorrect_pv_claim) {
log_error("Cannot use VG %s referencing incorrect PVs.", vg->name);
log_error("(See vgreduce --removemissing with --devices options.)");
failure |= FAILED_NOT_ENABLED;
goto bad;
}
if (!cmd->handles_missing_pvs && (missing_pv_dev || missing_pv_flag)) {
log_error("Cannot change VG %s while PVs are missing.", vg->name);
log_error("See vgreduce --removemissing and vgextend --restoremissing.");

View File

@ -381,10 +381,8 @@ int get_default_pvmetadatasize_sectors(void);
void set_pe_align(struct physical_volume *pv, uint64_t data_alignment);
void set_pe_align_offset(struct physical_volume *pv, uint64_t data_alignment_offset);
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv);
int check_dev_block_size_for_vg(struct device *dev, const struct volume_group *vg,
unsigned int *max_phys_block_size_found);
unsigned int *max_logical_block_size_found);
int check_pv_dev_sizes(struct volume_group *vg);
uint32_t vg_bad_status_bits(const struct volume_group *vg, uint64_t status);
int add_pv_to_vg(struct volume_group *vg, const char *pv_name,

View File

@ -166,7 +166,7 @@ uint32_t adjusted_mirror_region_size(struct cmd_context *cmd,
region_max = (uint64_t) extents * extent_size;
if (region_max < UINT32_MAX && region_size > region_max) {
region_size = UINT64_C(1) << (31 - clz(region_max));
region_size = UINT64_C(1) << (31 - clz(region_max ? : 1));
if (!internal)
log_print_unless_silent("Using reduced mirror region size of %s",
display_size(cmd, region_size));
@ -399,48 +399,55 @@ static int _activate_lv_like_model(struct logical_volume *model,
}
/*
* Delete independent/orphan LV, it must acquire lock.
* Inherit tags @from_lv to @to_lv, tags maybe needed for activation
*/
static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *lv,
int reactivate)
static int _inherit_lv_tags(const struct logical_volume *from_lv, struct logical_volume *to_lv)
{
struct cmd_context *cmd = mirror_lv->vg->cmd;
struct dm_str_list *sl;
/* Inherit tags - maybe needed for activation */
if (!str_list_match_list(&mirror_lv->tags, &lv->tags, NULL)) {
dm_list_iterate_items(sl, &mirror_lv->tags)
if (!str_list_add(cmd->mem, &lv->tags, sl->str)) {
log_error("Aborting. Unable to tag.");
if (to_lv && !str_list_match_list(&from_lv->tags, &to_lv->tags, NULL))
dm_list_iterate_items(sl, &from_lv->tags)
if (!str_list_add(from_lv->vg->cmd->mem, &to_lv->tags, sl->str)) {
log_error("Aborting. Unable to inherit tag.");
return 0;
}
if (!vg_write(mirror_lv->vg) ||
!vg_commit(mirror_lv->vg)) {
log_error("Intermediate VG commit for orphan volume failed.");
return 0;
}
}
return 1;
}
if (reactivate) {
/* FIXME: the 'model' should be 'mirror_lv' not 'lv', I think. */
if (!_activate_lv_like_model(lv, lv))
return_0;
/* FIXME Is this superfluous now? */
if (!sync_local_dev_names(cmd)) {
log_error("Failed to sync local devices when reactivating %s.",
display_lvname(lv));
return 0;
}
if (!deactivate_lv(cmd, lv))
/*
* Deactivates and removes an 'orphan' temporary @lv,
* which is expected to already have an 'error' segment.
* Sets @updated_mda (!NULL) to 1 when LV is removed.
* Sets @deactivation_failed (!NULL) to 1 when deactivation fails.
*
* Note: An external tool might still have the volume open, preventing
* immediate deactivation. If deactivation fails (even after retrying),
* it is safer to proceed with the command and leave the LV visible.
* This allows the user to manually remove it when it is no longer in use.
*
* Any errors will be detected later in the process, as there will be
* more visible LVs than expected.
*/
static int _deactivate_and_remove_lv(struct logical_volume *lv,
int *updated_mda,
int *deactivation_failed)
{
if (lv) {
/* FIXME: convert to use lv_active_change() */
if (!deactivate_lv(lv->vg->cmd, lv)) {
/* Note: still returns success here and fails later */
log_warn("WARNING: Can't deactivate temporary volume %s.",
display_lvname(lv));
if (deactivation_failed)
*deactivation_failed = 1;
} else if (!lv_remove(lv)) {
/* Can't continue with internal metadata problems */
return_0;
} else if (updated_mda)
*updated_mda = 1;
}
if (!lv_remove(lv))
return_0;
return 1;
}
@ -598,6 +605,7 @@ static int _split_mirror_images(struct logical_volume *lv,
char layer_name[NAME_LEN], format[NAME_LEN];
const char *lv_name;
int act;
int deactivation_failed = 0, updated_mda = 0;
if (!lv_is_mirrored(lv)) {
log_error("Unable to split non-mirrored LV %s.",
@ -731,12 +739,19 @@ static int _split_mirror_images(struct logical_volume *lv,
sub_lv = seg_lv(mirrored_seg, 0);
sub_lv->status &= ~MIRROR_IMAGE;
lv_set_visible(sub_lv);
detached_log_lv = detach_mirror_log(mirrored_seg);
/* FIXME: handle mirrored mirror_log, use common code */
if ((detached_log_lv = detach_mirror_log(mirrored_seg)) &&
!replace_lv_with_error_segment(detached_log_lv))
return_0;
if (!remove_layer_from_lv(lv, sub_lv))
return_0;
lv->status &= ~(MIRROR | MIRRORED | LV_NOTSYNCED);
}
if (!_inherit_lv_tags(lv, sub_lv) ||
!_inherit_lv_tags(lv, detached_log_lv))
return_0;
/*
* Suspend and resume the mirror - this includes all
* the sub-LVs and soon-to-be-split sub-LVs
@ -744,21 +759,48 @@ static int _split_mirror_images(struct logical_volume *lv,
if (!lv_update_and_reload(lv))
return_0;
act = lv_is_active(lv_lock_holder(lv));
if ((act = lv_is_active(lv_lock_holder(lv)))) {
if (!_activate_lv_like_model(lv, new_lv)) {
log_error("Failed to rename newly split LV in the kernel");
return 0;
}
if (act && !_activate_lv_like_model(lv, new_lv)) {
log_error("Failed to rename newly split LV in the kernel");
return 0;
if (sub_lv &&
!_activate_lv_like_model(lv, sub_lv))
return_0;
if (detached_log_lv &&
!_activate_lv_like_model(lv, detached_log_lv))
return_0;
if (!sync_local_dev_names(lv->vg->cmd))
stack;
}
/* Remove original mirror layer if it has been converted to linear */
if (sub_lv && !_delete_lv(lv, sub_lv, act))
/* Remove original mirror layer if it has been converted to error */
if (!_deactivate_and_remove_lv(sub_lv, &updated_mda, &deactivation_failed))
return_0;
/* Remove the log if it has been converted to linear */
if (detached_log_lv && !_delete_lv(lv, detached_log_lv, act))
/* Remove the log if it has been converted to error */
if (!_deactivate_and_remove_lv(detached_log_lv, &updated_mda, &deactivation_failed))
return_0;
if (deactivation_failed) {
log_error("ABORTING: Failed to remove orphan volume(s).");
log_print_unless_silent("Please remove orphan volume(s) when possible.");
if (updated_mda) {
/* However some LV was removed so write & commit VG. */
if (!vg_write(lv->vg) || !vg_commit(lv->vg)) {
log_error("Manual intervention may be required to "
"remove/restore abandoned LVs before retrying.");
return 0;
}
}
return 0;
}
return 1;
}
@ -805,7 +847,6 @@ static int _remove_mirror_images(struct logical_volume *lv,
struct lv_list *lvl;
struct dm_list tmp_orphan_lvs;
uint32_t orig_removed = num_removed;
int reactivate;
if (removed)
*removed = 0;
@ -905,8 +946,12 @@ static int _remove_mirror_images(struct logical_volume *lv,
lv->status &= ~(MIRROR | MIRRORED | LV_NOTSYNCED);
mirrored_seg = first_seg(lv);
if (remove_log && !detached_log_lv)
detached_log_lv = detach_mirror_log(mirrored_seg);
if (remove_log && !detached_log_lv) {
/* FIXME: handle mirrored mirror_log, use common code */
if ((detached_log_lv = detach_mirror_log(mirrored_seg)) &&
!replace_lv_with_error_segment(detached_log_lv))
return_0;
}
if (lv_is_pvmove(lv))
dm_list_iterate_items(pvmove_seg, &lv->segments)
@ -917,7 +962,6 @@ static int _remove_mirror_images(struct logical_volume *lv,
/* All mirror images are gone.
* It can happen for vgreduce --removemissing. */
detached_log_lv = detach_mirror_log(mirrored_seg);
lv->status &= ~(MIRROR | MIRRORED | LV_NOTSYNCED);
if (!replace_lv_with_error_segment(lv))
return_0;
} else if (remove_log)
@ -969,6 +1013,19 @@ static int _remove_mirror_images(struct logical_volume *lv,
return_0;
}
if (!collapse) {
dm_list_iterate_items(lvl, &tmp_orphan_lvs) {
if (!_inherit_lv_tags(lv, lvl->lv))
return_0;
if (!replace_lv_with_error_segment(lvl->lv))
return_0;
}
}
if (!_inherit_lv_tags(lv, temp_layer_lv) ||
!_inherit_lv_tags(lv, detached_log_lv))
return_0;
/*
* To successfully remove these unwanted LVs we need to
* remove the LVs from the mirror set, commit that metadata
@ -978,23 +1035,41 @@ static int _remove_mirror_images(struct logical_volume *lv,
return_0;
/* Save or delete the 'orphan' LVs */
reactivate = lv_is_active(lv_lock_holder(lv));
if (lv_is_active(lv_lock_holder(lv))) {
if (!collapse) {
dm_list_iterate_items(lvl, &tmp_orphan_lvs)
if (!_activate_lv_like_model(lv, lvl->lv))
return_0;
}
if (temp_layer_lv &&
!_activate_lv_like_model(lv, temp_layer_lv))
return_0;
if (detached_log_lv &&
!_activate_lv_like_model(lv, detached_log_lv))
return_0;
if (!sync_local_dev_names(lv->vg->cmd))
stack;
}
if (!collapse) {
dm_list_iterate_items(lvl, &tmp_orphan_lvs)
if (!_delete_lv(lv, lvl->lv, reactivate))
if (!_deactivate_and_remove_lv(lvl->lv, NULL, NULL))
return_0;
}
if (temp_layer_lv && !_delete_lv(lv, temp_layer_lv, reactivate))
if (!_deactivate_and_remove_lv(temp_layer_lv, NULL, NULL))
return_0;
if (detached_log_lv && !_delete_lv(lv, detached_log_lv, reactivate))
if (!_deactivate_and_remove_lv(detached_log_lv, NULL, NULL))
return_0;
/* Mirror with only 1 area is 'in sync'. */
if (new_area_count == 1 && is_temporary_mirror_layer(lv)) {
if (!(detached_log_lv = detach_mirror_log(mirrored_seg))) {
log_error("Cannot detach mirror log from %s..",
log_error("Cannot detach mirror log from %s.",
display_lvname(mirrored_seg->lv));
return 0;
}
@ -1552,7 +1627,7 @@ static int _form_mirror(struct cmd_context *cmd, struct alloc_handle *ah,
/*
* create mirror image LVs
*/
img_lvs = alloca(sizeof(*img_lvs) * mirrors);
img_lvs = alloca(sizeof(*img_lvs) * (mirrors + 1));
memset(img_lvs, 0, sizeof(*img_lvs) * mirrors);
if (!_create_mimage_lvs(ah, mirrors, stripes, stripe_size, lv, img_lvs, log))
@ -1620,7 +1695,7 @@ static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd,
if (log_count > 1) {
/* Kernel requires a mirror to be at least 1 region large. */
if (region_size > log_lv->size) {
region_size = UINT64_C(1) << (31 - clz(log_lv->size));
region_size = UINT64_C(1) << (31 - clz(log_lv->size ? : 1));
log_debug("Adjusting region_size to %s for mirrored log.",
display_size(cmd, (uint64_t)region_size));
}

View File

@ -376,15 +376,15 @@ struct lv_segment *find_pool_seg(const struct lv_segment *seg)
struct seg_list *sl;
dm_list_iterate_items(sl, &seg->lv->segs_using_this_lv) {
/* Needs to be he only item in list */
/* Needs to be the only item in list */
if (lv_is_pending_delete(sl->seg->lv))
continue;
if (pool_seg) {
log_error("%s is referenced by more then one segments (%s, %s).",
log_error("%s is referenced by more than one segment (%s, %s).",
display_lvname(seg->lv), display_lvname(pool_seg->lv),
display_lvname(sl->seg->lv));
return NULL; /* More then one segment */
return NULL; /* More than one segment */
}
pool_seg = sl->seg;

View File

@ -63,6 +63,7 @@ struct physical_volume {
/* This is true whenever the represented PV has a label associated. */
uint64_t is_labelled:1;
uint64_t unused_missing_cleared:1;
uint64_t wrong_vg:1; /* vg metadata includes this PVID but the PV is actually in a different vg */
/* NB. label_sector is valid whenever is_labelled is true */
uint64_t label_sector;

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