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

Compare commits

...

89 Commits

Author SHA1 Message Date
Heinz Mauelshagen
c6d7cd1489 metadata: adjust extents_round_to_boundary(); remove pagesize check inv lvcreate.c 2016-08-18 00:45:12 +02:00
Heinz Mauelshagen
eec8bd228c metadata: support tiny extent sizes better
RAID requires minimum allocation units for its SubLVs, because
the kernel does page io on them. Enforce 64 KiB units to be
safe in case RaidLVs are being accessed on PPC with that page size.
2016-08-18 00:16:13 +02:00
David Teigland
8c71fc1cc2 man: lvconvert mention required option 2016-08-17 14:56:01 -05:00
David Teigland
0336b41828 man: lvconvert change location of sentence
The details about each option are explained in the
section for that option.
2016-08-17 14:13:17 -05:00
Heinz Mauelshagen
c0a0eedf2e vgsplit: fix regression processing thin external origins
a579ba2ac2 fixed a regression causing a segfault if no external
origin existed but broke the logic leading to erroneous error
messages and creations of split off exported VGs in case the
external origin and the pool LVs were allocated on different PVs.

- resolves rhbz1367459
2016-08-16 23:57:09 +02:00
Heinz Mauelshagen
73df2aedf9 lvcreate: better error message creating RAID LV on < 4 KiB VG extent size
Creating a RaidLV in VGs with very small extent sizes caused
late failure in the kernel giving a not very informative error
message. Catch the attempt early and display failure message
'Unable to create RAID LV: requires minimum VG extent size 4.00 KiB'.

- resoves rhbz1179970
2016-08-16 13:39:40 +02:00
Alasdair G Kergon
114db6f745 tools: Suppress some unnecessary --stripesize warnings.
https://bugzilla.redhat.com/1366745
2016-08-15 19:38:45 +01:00
Heinz Mauelshagen
d83f2d766d pvmove: fix regression introduced with 8e9d5d12ae
'pvmove -n name pv1 pv2' called with the name of a top-level LV
failed with mentioned commit.

Enhance pvmove-raid-segtypes.sh to test for prohibited RAID SubLV moves.
2016-08-15 19:31:04 +02:00
Heinz Mauelshagen
8e9d5d12ae pvmove: prohibit non-resilient collocation of RAID SubLVs
'pvmove -n name pv1 pv2' allows to collocate multiple RAID SubLVs
on pv2 (e.g. results in collocated raidlv_rimage_0 and raidlv_rimage_1),
thus causing loss of resilence and/or performance of the RaidLV.

Fix this pvmove flaw leading to potential data loss in case of PV failure
by preventing any SubLVs from collocation on any PVs of the RaidLV.
Still allow to collocate any DataLVs of a RaidLV with their sibling MetaLVs
and vice-versa though (e.g. raidlv_rmeta_0 on pv1 may still be moved to pv2
already holding raidlv_rimage_0).

Because access to the top-level RaidLV name is needed,
promote local _top_level_lv_name() from raid_manip.c
to global top_level_lv_name().

- resolves rhbz1202497
2016-08-15 18:22:32 +02:00
Alasdair G Kergon
c7bd33d951 post-release 2016-08-15 13:23:06 +01:00
Alasdair G Kergon
8297276967 pre-release 2016-08-15 13:17:47 +01:00
Peter Rajnoha
2ff893cd85 conf: add comment about cfg_runtime 2016-08-15 10:38:38 +02:00
Heinz Mauelshagen
9c9b9b276a raid_manip: pay attention to PVs listed on command line when allocating MetaLVs
Adding MetaLVs to given DataLVs (e.g. raid0 -> raid0_meta takeover) wasn't
paying attention to any PVs listed on the lvconvert command line.
2016-08-13 00:20:01 +02:00
Heinz Mauelshagen
6d52b17dfc raid_manip: add missing code avoiding MetaLV collocation on the same PV
Adding MetaLVs to given DataLVs (e.g. raid0 -> raid0_meta takeover),
_avoid_pvs_with_other_images_of_lv() was missing code to prohibit
allocation when called with a just allocated MetaLV to prohibit
collaocation of the next allocated MetaLV on the same PV.

- resolves rhbz1366738
2016-08-12 22:46:57 +02:00
Tony Asleson
0973d6e331 notify: Fix hang with lvm shell & --enable-notify-dbus
When lvm is compiled with --enable-notify-dbus and a user uses lvm
shell, after they issue 200+ commands the lvm shell will hang for
~30 seconds trying to notify the lvm dbus service that a change
has occurred.  This appears to be caused by resource exhaustion,
because the sockets used for dbus communication are not be closed.
2016-08-12 14:36:43 -05:00
Heinz Mauelshagen
a185a2bea2 lvcreate/lvconvert: fix validation of maximum mirrors/stripes
Enforce mirror/raid0/1/10/4/5/6 type specific maximum images when
creating LVs or converting them from mirror <-> raid1.

Document those maxima in the lvcreate/lvconvert man pages.

- resolves rhbz1366060
2016-08-12 19:14:28 +02:00
Alasdair G Kergon
93b61c07eb raid: Avoid double suffix on rmeta LV name paired with rimage LV. 2016-08-11 23:31:49 +01:00
Marian Csontos
e30fb19030 spec: Add new files 2016-08-11 14:10:59 +02:00
Peter Rajnoha
2fed8d8515 lvmcmdline: use long int for number returned by strtol 2016-08-10 09:10:37 +02:00
Alasdair G Kergon
480c1c9599 post-release 2016-08-10 03:01:55 +01:00
Alasdair G Kergon
37b8b84fee pre-release 2016-08-10 02:42:35 +01:00
Peter Rajnoha
b4f0503d1b man: fix references to names for --configreport arg in pvs, vgs and lvs man page 2016-08-09 18:49:11 +02:00
Peter Rajnoha
6fcfa2855b man: add lvm fullreport man page 2016-08-09 18:49:11 +02:00
Peter Rajnoha
5ac008116b report: add report_reset_cmdlog_seqnum and call it for each new cmd executed in lvm shell 2016-08-09 18:49:11 +02:00
Peter Rajnoha
29f7dc2922 conf: mark selected settings with CFG_DISALLOW_INTERACTIVE flag 2016-08-09 18:49:11 +02:00
Peter Rajnoha
e8985c71bc config: add support for CFG_DISALLOW_INTERACTIVE flag to mark settings as not suitable for override in interactive mode
Some settings are not suitable for override in interactive/shell
mode because such settings may confuse the code and it may end
up with unexpected behaviour. This is because of the fact that
once we're in the interactive/shell mode, we have already applied
some settings for the shell itself and we can't override them
further because we're already using those settings to drive the
interactive/shell mode. Such settings would get ignored silently
or, in worse case, they would mess up the existing configuration.
2016-08-09 18:49:11 +02:00
Peter Rajnoha
54bf15555b refactor: modify original _check_profile fn and rename to config_force_check for general use 2016-08-09 18:49:11 +02:00
Peter Rajnoha
785e2c31f5 conf: add lvmdbusd.profile 2016-08-09 18:49:11 +02:00
Peter Rajnoha
7111d48748 lvm: shell: honor log/command_log_selection as default and reset to this value after lastlog 2016-08-09 18:49:11 +02:00
Peter Rajnoha
e805ef2d66 lvmcmdline: profile: early profile load for lvm shell
Make it possible to also load profile for lvm shell by honouring
LVM_COMMAND_PROFILE environment variable.
2016-08-09 18:49:11 +02:00
Peter Rajnoha
f21afddeb7 lvm: shell: extend log report to cover whole lvm shell's main loop
When lvm commands are executed in lvm shell, we cover the whole lvm
command execution within this shell now. That means, all messages logged
and status caught during each command execution is now recorded in the
log report, including overall command's return code.
2016-08-09 18:49:10 +02:00
Peter Rajnoha
7d1125e5b7 libdm: report: add dm_report_group_output_and_pop_all
The dm_report_group_output_and_pop_all calls dm_report_output and
dm_report_group_pop for all the items that are currently in report
group. This is just a shortcut that makes it easier to output and
pop group's content so the group handle can be reused again without
a need to initialize and configure it again.

The functionality of dm_report_group_output_and_pop_all is the
same as dm_report_destroy but without destroying the report group
handle.
2016-08-09 18:24:45 +02:00
Peter Rajnoha
d86caf952e libdm: report: postpone printing of JSON starting '{' character till it's needed
This patch moves printing of starting '{' character for JSON output up
untili it's known there's any further output following - either the
content or ending '}' character.

Also, remove unnecessary switch for different report group types and
calling individual functions to handle dm_report_group_create as that
code is shared for all existing types at the moment.
2016-08-09 18:24:45 +02:00
Peter Rajnoha
9c21139284 libdm: report: add dm_report_destroy_rows
Calling dm_report_destroy_rows makes it possible to destroy any report
content we have but at the same time it doesn't destroy the report
handle itself, thus it's possible to reuse that handle again for new
report content.

Functionally, this is the same as calling dm_report_output with the
report handle but omitting the output iself. This functionality may
be useful if we, for whatever reason, need to discard the report
content and start a fresh new one but with the same report configuration
and initialization and thus we can just reuse the existing handle.
2016-08-09 18:24:45 +02:00
Peter Rajnoha
5649834f7d lvmcmdline: return 0/NULL if cmd->arg_values not set and arg_count/grouped_arg_count/arg_value called
We may call arg_count/grouped_arg_count/arg_value soon enough that
cmd->arg_values is not set yet.

Normally, when running a command, we execute lvm_run_command which in
turn calls _process_command_line to allocate and parse the command line
values and stores them in cmd->arg_values.

However, if we run lvm shell, this one doesn't accept any command line
options and we parse the command line for each command that is executed
within the lvm shell then. If we used any code that tries to access
cmd->arg_values through any of the the arg handling functions too
early, we could end up with a segfault due to uninitialized (NULL)
cmd->arg_values.

This patch just saves extra checks in all the code where arg handling
may be called too early so that the cmd->arg_values is not set up yet.
This does not apply to any of existing code, but subsequent patches
will need that.
2016-08-09 18:24:45 +02:00
Peter Rajnoha
1fde4bf4d0 refactor: move report grouping and log reporting handles from processing_handle to cmd_context
With patches that will follow, this will make it possible to widen log
report coverage when commands are executed from lvm shell so the amount
of messages that may end up in stderr/stdout instead of log report are
minimized.
2016-08-09 18:24:45 +02:00
Peter Rajnoha
ef69934746 shell: also collect last command's return code for subsequent 'lastlog' invocation
Add new log_context=shell and with log_object_type=cmd and
log_object_name=<command_name> for command log report to collect
overall return code from last command (this is reported under
log_type=status).
2016-08-09 18:24:45 +02:00
Peter Rajnoha
06ce9b4e42 log: separate output and make it possible to use given FDs
Currently, the output is separated in 3 parts and each part can go into
a separate and user-defined file descriptor:

  - common output (stdout by default, customizable by LVM_OUT_FD environment variable)
  - error output (stderr by default, customizable by LVM_ERR_FD environment variable)
  - report output (stdout by default, customizable by LVM_REPORT_FD environment variable)

For example, each type of output goes to different output file:

  [0] fedora/~ # export LVM_REPORT_FD=3

  [0] fedora/~ # lvs fedora vg/abc 1>out 2>err 3>report

  [0] fedora/~ # cat out

  [0] fedora/~ # cat err
    Volume group "vg" not found
    Cannot process volume group vg

  [0] fedora/~ # cat report
    LV   VG     Attr       LSize   Layout     Role       CTime
    root fedora -wi-ao----  19.00g linear     public     Wed May 27 2015 08:09:21
    swap fedora -wi-ao---- 500.00m linear     public     Wed May 27 2015 08:09:21

Another example in LVM shell where the report goes to "report" file:

  [0] fedora/~ # export LVM_REPORT_FD=3
  [0] fedora/~ # lvm 3>report

  (in lvm shell)
  lvm> vgs

  (content of "report" file)
  [1] fedora/~ # cat report
    VG     #PV #LV #SN Attr   VSize  VFree
    fedora   1   2   0 wz--n- 19.49g    0

  (in lvm shell)
  lvm> lvs

  (content of "report" file)
  [1] fedora/~ # cat report
    VG     #PV #LV #SN Attr   VSize  VFree
    fedora   1   2   0 wz--n- 19.49g    0
    LV   VG     Attr       LSize   Layout     Role       CTime
    root fedora -wi-ao----  19.00g linear     public     Wed May 27 2015 08:09:21
    swap fedora -wi-ao---- 500.00m linear     public     Wed May 27 2015 08:09:21
2016-08-09 18:24:45 +02:00
Heinz Mauelshagen
bb9789f2b3 test: fix/enhance lvcreate-large-raid*.sh
Multi-step extend to even larger raid10 LV lvcreate-large-raid.sh.

Comment fixes.
2016-08-09 18:16:01 +02:00
Heinz Mauelshagen
48e14390c1 test: fix lvcreate-large-raid.sh
RAID6 LVs may not be created with --nosync or data corruption
may occur in case of device failures.  The underlying MD raid6
personality used to drive the RaidLV performs read-modify-write
updates on stripes and thus relies on properly written parity
(P and Q Syndromes) during initial synchronization.

Once on it, enhance test to create/extend more and
larger RaidLVs and check sync/nosync status.
2016-08-09 17:45:37 +02:00
Heinz Mauelshagen
3d3f62e10a test: add lvconvert-raid-takeover.sh
Commit 76ef2d15d8 introduced
raid0 <-> raid4 takeover and full mirror <-> raid1 support.

Add tests for these conversions.

Tests exposed a kernel semantics change freezing resynchronization
on conversions from raid0[_meta] -> raid4 or adding raid1 legs
because kernel kept the RAID mapped device in 'frozen' state unless
an 'idle' message was sent or the table was reloaded (kernel patch pending).
2016-08-09 14:17:26 +02:00
Alasdair G Kergon
e5a5fd3669 lvconvert: Fix repair and replace routing. 2016-08-08 23:13:34 +01:00
Bryn M. Reeves
dad02900f1 man: explain deletion of 1st group member in dmstats.8.in
Although the use of the first region_id in a group to store the
DMS_GROUP=... aux_data tag is an internal implementation detail,
it has a user visible consequence in that deleting this region will
cause the group to disappear: add an explanation of this to the
'group' command and 'Regions, areas, and groups' section.
2016-08-08 19:29:12 +01:00
Bryn M. Reeves
4bcbcdb1a2 man: minor fixes to dmstats.8.in
Remove obsolete reference to '--target'.
2016-08-08 19:07:56 +01:00
Alasdair G Kergon
175e0905d5 test: Drop --mirrorlog when not a mirror. 2016-08-08 18:43:54 +01:00
David Teigland
fc93085c7a lvconvert: separate type raid to mirror
By the current division of unique operations,
converting type raid to type mirror is distinct
from converting type raid to raid.
2016-08-08 10:37:24 -05:00
Heinz Mauelshagen
6f90c954b7 WHATS_NEW: reject --nosync option for RAID6 LVs in lvcreate 2016-08-08 16:00:49 +02:00
Alasdair G Kergon
c55134aa48 lvconvert: Limit --corelog and --mirrorlog to mirrors.
It's an error to specify a log when the final result is not of type
mirror.
2016-08-08 14:39:55 +01:00
Heinz Mauelshagen
7d6cf12554 lvcreate: reject '--nosync' option for RAID6 LVs
The MD raid6 personality being used to drive lvm raid6 LVs does
read-modify-write updates to any stripes and thus relies on correct
P and Q Syndromes being written during initial synchronization or
it may fail reconstructing proper user data in case of SubLVs failing.

We may not allow the '--nosync' option on
creation of raid6 LVs for that reason.

Update/fix 'man lvcreate' in that regard.

add lvcreate-raid-nosync.sh test script.

- Resolves rhbz1358532
2016-08-08 13:52:35 +02:00
Peter Rajnoha
57fa5d4329 lvmcmdline: do not refresh whole cmd context if profile dropped after processing LVM cmd
We don't need to refresh whole cmd context if we drop profile after
processing LVM command - just like we don't refresh cmd context when
we're applying the profile. It's because profiles contain only safe
subset of settings which do not require complete cmd context refresh.

This patch calls process_profilable_config instead of
refresh_toolcontext if there was profile applied for the LVM
command only, not --config which requires toolcontext refresh.
The process_profilable_config just sets proper values based on
values of profilable settings, but it does not do complete
reinitialization of various parts (e.g. filters, logging etc.).
2016-08-08 11:57:13 +02:00
Alasdair G Kergon
76ef2d15d8 lvconvert: Support raid0<->raid4 and mirror<->raid1.
Only simple takeover cases so far.
2016-08-07 00:56:08 +01:00
Alasdair G Kergon
de7f1deb80 raid: Report supported lvconvert conversions if invalid. 2016-08-07 00:30:26 +01:00
Alasdair G Kergon
6f236c3353 raid: Add workaround to prepare for raid4 conversions. 2016-08-07 00:07:06 +01:00
Alasdair G Kergon
ba0c26a078 raid: Pass list of LVs to remove into more fns. 2016-08-06 23:46:45 +01:00
Alasdair G Kergon
30884208d4 raid: Move two functions. 2016-08-06 23:29:27 +01:00
Heinz Mauelshagen
802bd34562 WHATS_NEW: fixup order 2016-08-05 16:31:46 +02:00
Heinz Mauelshagen
8f25ad6416 raid_manip: fix log print format from commit d2c3b23e6d 2016-08-05 16:29:56 +02:00
Heinz Mauelshagen
9aefe9aa7a WHATS_NEW: add '--rebuild PV' option to lvchange to allow for PV selective rebuilds 2016-08-05 16:07:14 +02:00
Heinz Mauelshagen
d2c3b23e6d lvchange: Allow device specification when requesting a repair
'lvchange --resync LV' or 'lvchange --syncaction repair LV' request the
RAID layout specific parity blocks in raid4/5/6 to be recreated or the
mirrored blocks to be copied again from the master leg/copy for raid1/10,
thus not allowing a rebuild of a particular PV.

Introduce repeatable option '--[raid]rebuild PV' to allow to request
rebuilds of specific PVs in a RaidLV which are known to contain corrupt
data (e.g. rebuild a raid1 master leg).

Add test lvchange-rebuild-raid.sh to test/shell doing rebuild
variations on raid1/10 and 5; add aux function check_status_chars
to support the new test.

 - Resolves rhbz1064592
2016-08-05 16:01:46 +02:00
Alasdair G Kergon
91f866f786 raid: Tell lib whether stripesize was specified 2016-08-05 14:28:14 +01:00
Alasdair G Kergon
7482ff93b8 raid: Turn lv_raid_change_image_count into wrapper
Eventually the separate entry point will disappear.
2016-08-05 14:17:54 +01:00
Alasdair G Kergon
b66fa91c46 segtypes: Further segtype macros. 2016-08-05 14:00:40 +01:00
Alasdair G Kergon
b1b0b134ec raid0: Validate presence of raid0 meta_areas more tightly. 2016-08-04 21:15:07 +01:00
David Teigland
d1a25fe597 lvconvert: add FIXME
operations are no longer identified correctly.
2016-08-04 13:01:48 -05:00
Alasdair G Kergon
4a15abe865 striped: Add precise macros for original segtype.
The existing striped macros include raid0 segments.
2016-08-04 01:24:39 +01:00
Alasdair G Kergon
5c3141a8b9 lvconvert: Improve error message when no -m. 2016-08-03 23:43:59 +01:00
David Teigland
be497175e0 man: minor corrections in pvscan 2016-08-03 15:49:43 -05:00
David Teigland
2b01dca28a man: include info about disabled lvmetad 2016-08-03 15:42:12 -05:00
Alasdair G Kergon
8b1a368b59 lvconvert: Provide entry point for new functionality.
Prepare for new segment type conversion functionality in cases that
currently fail.  In the short-term, we need to do this while limiting
the changes to the code paths for the conversions that are already
supported.
2016-08-03 03:53:29 +01:00
Alasdair G Kergon
fdc3fcbfce lvconvert: Pass region_size to lv_raid_convert. 2016-08-02 23:51:20 +01:00
Alasdair G Kergon
a234cebbed lvconvert: Preserve mirror region size with --repair. 2016-08-02 19:50:04 +01:00
Alasdair G Kergon
415c5fd5d8 lvconvert: Divide into 12 categories. 2016-08-02 16:44:21 +01:00
Alasdair G Kergon
6361bc4734 lvconvert: Treat --repair as an independent case. 2016-08-02 16:22:12 +01:00
Alasdair G Kergon
804a397643 lvconvert: Forbid stripe parameters with --repair. 2016-08-02 15:59:12 +01:00
Heinz Mauelshagen
d0d03f315b vg_validate: correct min_recovery_rate check message 2016-08-02 15:27:13 +02:00
Heinz Mauelshagen
5765a28456 vg_validate: new RAID segment checks in check_lv_segments()
introduced with commit 8f62b7bfe5 rely on complete
             defintions of the relations between the LVs of a VG.
             Hence only run these checks when the complete_vg flag
             is set on calls to check_lv_segments().

             lvconvert failed in test lvconvert-thin-raid.sh when
             calling check_lv_segments() from _read_segments() without
             providing a complete definition.
2016-08-01 22:42:05 +02:00
Alasdair G Kergon
c490be9134 Revert "thin: when converting a thin pool data or metadata LV from"
This reverts commit 237f84e038.

This case failed:
    lvcreate --type raid1 -m1 -l2 vg99
    lvcreate -aey -l2 -s vg99/lvol0
    lvconvert -m2 vg99/lvol0
2016-08-01 15:17:44 +01:00
Alasdair G Kergon
d0df1ff995 lvconvert: Set lp->segtype in only one place. 2016-07-30 18:20:04 +01:00
Alasdair G Kergon
1ce958bc5e lvconvert: Rely upon lp->thin and lp->cache. 2016-07-30 15:58:09 +01:00
Alasdair G Kergon
48d9c46daa lvconvert: Fix --type thin recognition.
lp->thin already holds the result of the cmdline arg resolution.
2016-07-30 15:08:50 +01:00
Alasdair G Kergon
52d2fa7022 tools: Also recognise segtype with thin and cache.
(--type thin still needs this for lvcreate - more logic should be
shared between lvcreate and lvconvert)
2016-07-30 04:12:58 +01:00
Alasdair G Kergon
d1ff254c3c tools: mirror also supports stripesize 2016-07-30 03:52:49 +01:00
Alasdair G Kergon
b3fbcd1ff7 lvconvert: Move stripe validation code later.
Simpler to delay it all until the actual LV being changed is available,
rather than having it split in two parts.
2016-07-30 02:52:06 +01:00
Alasdair G Kergon
4ffe15bf6a tools: Unify stripesize parameter validation.
Move it all into get_stripe_params().
Some code paths missed --stripesize checks.
E.g. lvcreate --type raid4 -i1
2016-07-30 02:05:50 +01:00
Alasdair G Kergon
d01b1b6cc1 lvconvert: Rearrange code that decides segtype. 2016-07-30 00:22:13 +01:00
Alasdair G Kergon
a8e4790810 lvconvert: Only obtain --type parameter once. 2016-07-29 21:45:22 +01:00
Alasdair G Kergon
800c0d3dd6 lvconvert: Remove hard-coded segment names. 2016-07-29 21:11:12 +01:00
Heinz Mauelshagen
237f84e038 thin: when converting a thin pool data or metadata LV from
linear to raid1, the linear wasnt't switched to the
      raid1 mapping, thus creating the false impression of
      resilience.
2016-07-29 19:17:12 +02:00
Alasdair G Kergon
6b6e258e0c post-release 2016-07-28 19:58:22 +01:00
60 changed files with 2812 additions and 760 deletions

View File

@@ -1 +1 @@
2.02.162(2)-git (2016-07-28)
2.02.165(2)-git (2016-08-15)

View File

@@ -1 +1 @@
1.02.132-git (2016-07-28)
1.02.134-git (2016-08-15)

View File

@@ -1,3 +1,34 @@
Version 2.02.165 -
===================================
Suppress some unnecessary --stripesize parameter warnings.
Fix 'pvmove -n name ...' to prohibit collocation of RAID SubLVs
Version 2.02.164 - 15th August 2016
===================================
Fix selection of PVs when allocating raid0_meta.
Fix sdbus socket leak leading to hang in lvmnotify.
Specify max stripes for raid LV types: raid0:64; 1:10; 4,5:63; 6:62; 10:32.
Avoid double suffix when naming _rmeta LV paired with _rimage LV.
Version 2.02.163 - 10th August 2016
===================================
Add profile for lvmdbusd which uses lvm shell json report output.
Restrict in-command modification of some parms in lvm shell.
Apply LVM_COMMAND_PROFILE early for lvm shell.
Refactor reporting so lvm shell log report collects whole of cmd execution.
Support LVM_*_FD envvars to redirect output to file descriptors.
Limit use of --corelog and --mirrorlog to mirrors in lvconvert.
Reject --nosync option for RAID6 LVs in lvcreate.
Do not refresh whole cmd context if profile dropped after processing LVM cmd.
Support straightforward lvconvert between striped and raid4 LVs.
Support straightforward lvconvert between raid1 and mirror LVs.
Report supported conversions when asked for unsupported raid lvconvert.
Add "--rebuild PV" option to lvchange to allow for PV selective rebuilds.
Preserve existing mirror region size when using --repair.
Forbid stripe parameters with lvconvert --repair.
Unify stripe size validation into get_stripe_params to catch missing cases.
Further lvconvert validation logic refactoring.
Version 2.02.162 - 28th July 2016
=================================
Extend vg_validate also to check raid configurations thoroughly.

View File

@@ -1,3 +1,11 @@
Version 1.02.134 -
===================================
Version 1.02.133 - 10th August 2016
===================================
Add dm_report_destroy_rows/dm_report_group_output_and_pop_all for lvm shell.
Adjust group handling and json production for lvm shell.
Version 1.02.132 - 28th July 2016
=================================
Fix json reporting to escape '"' character that may appear in reported string.

View File

@@ -24,7 +24,8 @@ PROFILES=$(PROFILE_TEMPLATES) \
$(srcdir)/cache-mq.profile \
$(srcdir)/cache-smq.profile \
$(srcdir)/thin-generic.profile \
$(srcdir)/thin-performance.profile
$(srcdir)/thin-performance.profile \
$(srcdir)/lvmdbusd.profile
include $(top_builddir)/make.tmpl

50
conf/lvmdbusd.profile Normal file
View File

@@ -0,0 +1,50 @@
#
# DO NOT EDIT THIS FILE!
#
# LVM configuration profile used by lvmdbusd daemon.
#
# This sets up LVM to produce output in the most suitable format for processing
# by lvmdbusd daemon which utilizes LVM shell to execute LVM commands.
#
# Do not edit this file in any way. This profile is distributed together with
# lvmdbusd and it contains configuration that is important for lvmdbusd to
# cooperate and interface with LVM correctly.
#
global {
# use bytes for expected and deterministic output
units=b
# no need for suffix if we have units set
suffix=0
}
report {
compact_output=0
compact_output_cols=""
binary_values_as_numeric=0
# time in number of seconds since the Epoch
time_format="%s"
mark_hidden_devices=1
# lvmdbusd expects JSON output
output_format=json
# *_cols_full for lvm fullreport's fields which lvmdbusd relies on to update its state
vgs_cols_full="vg_name,vg_uuid,vg_fmt,vg_size,vg_free,vg_sysid,vg_extent_size,vg_extent_count,vg_free_count,vg_profile,max_lv,max_pv,pv_count,lv_count,snap_count,vg_seqno,vg_mda_count,vg_mda_free,vg_mda_size,vg_mda_used_count,vg_attr,vg_tags"
pvs_cols_full="pv_name,pv_uuid,pv_fmt,pv_size,pv_free,pv_used,dev_size,pv_mda_size,pv_mda_free,pv_ba_start,pv_ba_size,pe_start,pv_pe_count,pv_pe_alloc_count,pv_attr,pv_tags,vg_name,vg_uuid"
lvs_cols_full="lv_uuid,lv_name,lv_path,lv_size,vg_name,pool_lv_uuid,pool_lv,origin_uuid,origin,data_percent,lv_attr,lv_tags,vg_uuid,lv_active,data_lv,metadata_lv,lv_parent,lv_role,lv_layout"
pvsegs_cols_full="pvseg_start,pvseg_size,segtype,pv_uuid,lv_uuid,pv_name"
segs_cols_full="seg_pe_ranges,segtype,lv_uuid"
vgs_sort_full="vg_name"
pvs_sort_full="pv_name"
lvs_sort_full="vg_name,lv_name"
pvsegs_sort_full="pv_uuid,pvseg_start"
segs_sort_full="lv_uuid,seg_start"
}
log {
# lvmdbusd relies on command log report to inspect LVM command's execution status
report_command_log=1
# display only outermost LVM shell-related log that lvmdbusd inspects first after LVM command execution (it calls 'lastlog' for more detailed log afterwards if needed)
command_log_selection="log_context=shell"
command_log_cols="log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code"
command_log_sort="log_seq_num"
}

View File

@@ -950,6 +950,9 @@ static void _destroy_config(struct cmd_context *cmd)
* they will get loaded again automatically.
*/
dm_list_iterate_items_safe(profile, tmp_profile, &cmd->profile_params->profiles) {
if (cmd->is_interactive && (profile == cmd->profile_params->shell_profile))
continue;
config_destroy(profile->cft);
profile->cft = NULL;
dm_list_move(&cmd->profile_params->profiles_to_load, &profile->list);
@@ -1649,37 +1652,6 @@ static void _init_globals(struct cmd_context *cmd)
init_mirror_in_sync(0);
}
/*
* Close and reopen stream on file descriptor fd.
*/
static int _reopen_stream(FILE *stream, int fd, const char *mode, const char *name, FILE **new_stream)
{
int fd_copy, new_fd;
if ((fd_copy = dup(fd)) < 0) {
log_sys_error("dup", name);
return 0;
}
if (fclose(stream))
log_sys_error("fclose", name);
if ((new_fd = dup2(fd_copy, fd)) < 0)
log_sys_error("dup2", name);
else if (new_fd != fd)
log_error("dup2(%d, %d) returned %d", fd_copy, fd, new_fd);
if (close(fd_copy) < 0)
log_sys_error("close", name);
if (!(*new_stream = fdopen(fd, mode))) {
log_sys_error("fdopen", name);
return 0;
}
return 1;
}
/*
* init_connections();
* _init_lvmetad();
@@ -1835,7 +1807,6 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
unsigned set_filters)
{
struct cmd_context *cmd;
FILE *new_stream;
int flags;
#ifdef M_MMAP_MAX
@@ -1885,9 +1856,8 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
if (is_valid_fd(STDIN_FILENO) &&
((flags = fcntl(STDIN_FILENO, F_GETFL)) > 0) &&
(flags & O_ACCMODE) != O_WRONLY) {
if (!_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream))
if (!reopen_standard_stream(&stdin, "r"))
goto_out;
stdin = new_stream;
if (setvbuf(stdin, cmd->linebuffer, _IOLBF, linebuffer_size)) {
log_sys_error("setvbuf", "");
goto out;
@@ -1897,9 +1867,8 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
if (is_valid_fd(STDOUT_FILENO) &&
((flags = fcntl(STDOUT_FILENO, F_GETFL)) > 0) &&
(flags & O_ACCMODE) != O_RDONLY) {
if (!_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream))
if (!reopen_standard_stream(&stdout, "w"))
goto_out;
stdout = new_stream;
if (setvbuf(stdout, cmd->linebuffer + linebuffer_size,
_IOLBF, linebuffer_size)) {
log_sys_error("setvbuf", "");
@@ -1911,7 +1880,6 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
/* Without buffering, must not use stdin/stdout */
init_silent(1);
#endif
/*
* Environment variable LVM_SYSTEM_DIR overrides this below.
*/
@@ -2227,7 +2195,6 @@ int refresh_toolcontext(struct cmd_context *cmd)
void destroy_toolcontext(struct cmd_context *cmd)
{
struct dm_config_tree *cft_cmdline;
FILE *new_stream;
int flags;
if (cmd->dump_filter && cmd->filter && cmd->filter->dump &&
@@ -2254,9 +2221,6 @@ void destroy_toolcontext(struct cmd_context *cmd)
if (cmd->cft_def_hash)
dm_hash_destroy(cmd->cft_def_hash);
if (cmd->log_rh)
dm_report_free(cmd->log_rh);
if (cmd->libmem)
dm_pool_destroy(cmd->libmem);
@@ -2266,20 +2230,18 @@ void destroy_toolcontext(struct cmd_context *cmd)
if (is_valid_fd(STDIN_FILENO) &&
((flags = fcntl(STDIN_FILENO, F_GETFL)) > 0) &&
(flags & O_ACCMODE) != O_WRONLY) {
if (_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream)) {
stdin = new_stream;
if (reopen_standard_stream(&stdin, "r"))
setlinebuf(stdin);
} else
else
cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */
}
if (is_valid_fd(STDOUT_FILENO) &&
((flags = fcntl(STDOUT_FILENO, F_GETFL)) > 0) &&
(flags & O_ACCMODE) != O_RDONLY) {
if (_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream)) {
stdout = new_stream;
if (reopen_standard_stream(&stdout, "w"))
setlinebuf(stdout);
} else
else
cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */
}

View File

@@ -66,6 +66,15 @@ struct cmd_context_initialized_parts {
unsigned connections:1;
};
struct cmd_report {
int log_only;
dm_report_group_type_t report_group_type;
struct dm_report_group *report_group;
struct dm_report *log_rh;
const char *log_name;
log_report_t saved_log_report_state;
};
/* FIXME Split into tool & library contexts */
/* command-instance-related variables needed by library */
struct cmd_context {
@@ -186,9 +195,9 @@ struct cmd_context {
char proc_dir[PATH_MAX];
/*
* Command log reporting.
* Reporting.
*/
struct dm_report *log_rh; /* keep log report of last cmd for further queries if cmd line is interactive (e.g. lvm shell) */
struct cmd_report cmd_report;
/*
* Buffers.

View File

@@ -385,6 +385,13 @@ int override_config_tree_from_string(struct cmd_context *cmd,
return 0;
}
if (cmd->is_interactive &&
!config_force_check(cmd, CONFIG_STRING, cft_new)) {
log_error("Ignoring invalid configuration string.");
dm_config_destroy(cft_new);
return_0;
}
if (!(cs = dm_pool_zalloc(cft_new->mem, sizeof(struct config_source)))) {
log_error("Failed to allocate config source.");
dm_config_destroy(cft_new);
@@ -984,6 +991,20 @@ static int _config_def_check_node_is_profilable(struct cft_check_handle *handle,
return 1;
}
static int _config_def_check_node_is_allowed(struct cft_check_handle *handle,
const char *rp, struct dm_config_node *cn,
const cfg_def_item_t *def)
{
if (handle->disallowed_flags & def->flags) {
log_warn_suppress(handle->suppress_messages,
"Configuration %s \"%s\" is not allowed here.",
cn->v ? "option" : "section", rp);
return 0;
}
return 1;
}
static int _config_def_check_node(struct cft_check_handle *handle,
const char *vp, char *pvp, char *rp, char *prp,
size_t buf_size, struct dm_config_node *cn)
@@ -1034,6 +1055,9 @@ static int _config_def_check_node(struct cft_check_handle *handle,
!_config_def_check_node_is_profilable(handle, rp, cn, def))
return_0;
if (!_config_def_check_node_is_allowed(handle, rp, cn, def))
return_0;
handle->status[def->id] |= CFG_VALID;
return 1;
}
@@ -2113,7 +2137,7 @@ bad:
return NULL;
}
static int _check_profile(struct cmd_context *cmd, struct profile *profile)
int config_force_check(struct cmd_context *cmd, config_source_t source, struct dm_config_tree *cft)
{
struct cft_check_handle *handle;
int r;
@@ -2124,13 +2148,19 @@ static int _check_profile(struct cmd_context *cmd, struct profile *profile)
}
handle->cmd = cmd;
handle->cft = profile->cft;
handle->source = profile->source;
/* the check is compulsory - allow only profilable items in a profile config! */
handle->cft = cft;
handle->source = source;
handle->force_check = 1;
/* provide warning messages only if config/checks=1 */
handle->suppress_messages = !find_config_tree_bool(cmd, config_checks_CFG, NULL);
/*
* Some settings can't be changed if we're running commands interactively
* within lvm shell so check for them in case we're in this interactive mode.
*/
if (cmd->is_interactive)
handle->disallowed_flags |= CFG_DISALLOW_INTERACTIVE;
r = config_def_check(handle);
dm_pool_free(cmd->libmem, handle);
@@ -2252,7 +2282,7 @@ int load_profile(struct cmd_context *cmd, struct profile *profile) {
* messages to be suppressed, but the check itself is always done
* for profiles!
*/
if (!_check_profile(cmd, profile)) {
if (!config_force_check(cmd, profile->source, profile->cft)) {
log_error("Ignoring invalid %s %s.",
_config_source_names[profile->source], profile->name);
config_destroy(profile->cft);

View File

@@ -48,6 +48,7 @@ struct profile_params {
struct profile *global_metadata_profile; /* profile (as given by --metadataprofile cmd arg) that overrides any other VG/LV-based profile */
struct dm_list profiles_to_load; /* list of profiles which are only added, but still need to be loaded for any use */
struct dm_list profiles; /* list of profiles which are loaded already and which are ready for use */
struct profile *shell_profile; /* master profile used in interactive/shell mode */
};
#define CFG_PATH_MAX_LEN 128
@@ -98,31 +99,34 @@ typedef union {
/* whether the configuration item name is variable */
#define CFG_NAME_VARIABLE 0x001
#define CFG_NAME_VARIABLE 0x0001
/* whether empty value is allowed */
#define CFG_ALLOW_EMPTY 0x002
#define CFG_ALLOW_EMPTY 0x0002
/* whether the configuration item is for advanced use only */
#define CFG_ADVANCED 0x004
#define CFG_ADVANCED 0x0004
/* whether the configuration item is not officially supported */
#define CFG_UNSUPPORTED 0x008
#define CFG_UNSUPPORTED 0x0008
/* whether the configuration item is customizable by a profile */
#define CFG_PROFILABLE 0x010
/* whether the configuration item is customizable by a profile */
/* and whether it can be attached to VG/LV metadata at the same time
#define CFG_PROFILABLE 0x0010
/* whether the configuration item is customizable by a profile
* and whether it can be attached to VG/LV metadata at the same time
* The CFG_PROFILABLE_METADATA flag incorporates CFG_PROFILABLE flag!!! */
#define CFG_PROFILABLE_METADATA 0x030
#define CFG_PROFILABLE_METADATA 0x0030
/* whether the default value is undefned */
#define CFG_DEFAULT_UNDEFINED 0x040
#define CFG_DEFAULT_UNDEFINED 0x0040
/* whether the default value is commented out on output */
#define CFG_DEFAULT_COMMENTED 0x080
#define CFG_DEFAULT_COMMENTED 0x0080
/* whether the default value is calculated during run time */
#define CFG_DEFAULT_RUN_TIME 0x100
#define CFG_DEFAULT_RUN_TIME 0x0100
/* whether the configuration setting is disabled (and hence defaults always used) */
#define CFG_DISABLED 0x200
#define CFG_DISABLED 0x0200
/* whether to print integers in octal form (prefixed by "0") */
#define CFG_FORMAT_INT_OCTAL 0x400
#define CFG_FORMAT_INT_OCTAL 0x0400
/* whether to disable checks for the whole config section subtree */
#define CFG_SECTION_NO_CHECK 0x800
#define CFG_SECTION_NO_CHECK 0x0800
/* whether to disallow a possibility to override configuration
* setting for commands run interactively (e.g. in lvm shell) */
#define CFG_DISALLOW_INTERACTIVE 0x1000
/* configuration definition item structure */
typedef struct cfg_def_item {
@@ -212,11 +216,15 @@ struct cft_check_handle {
unsigned check_diff:1; /* check if the value used differs from default one */
unsigned ignoreadvanced:1; /* do not include advnced configs */
unsigned ignoreunsupported:1; /* do not include unsupported configs */
uint16_t disallowed_flags; /* set of disallowed flags */
uint8_t status[CFG_COUNT]; /* flags for each configuration item - the result of the check */
};
int config_def_get_path(char *buf, size_t buf_size, int id);
/* Checks config using given handle - the handle may be reused. */
int config_def_check(struct cft_check_handle *handle);
/* Forces config check and automatically creates a new handle inside with defaults and discards the handle after the check. */
int config_force_check(struct cmd_context *cmd, config_source_t source, struct dm_config_tree *cft);
int override_config_tree_from_string(struct cmd_context *cmd, const char *config_settings);
int override_config_tree_from_profile(struct cmd_context *cmd, struct profile *profile);

View File

@@ -23,6 +23,11 @@
* - define a configuration array of one or more types:
* cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_default_value, deprecated_since_version, deprecation_comment, comment)
*
* - define a configuration setting where the default value is evaluated in runtime
* cfg_runtime(id, name, parent, flags, type, since_version, deprecated_since_version, deprecation_comment, comment)
* (for each cfg_runtime, you need to define 'get_default_<name>(struct cmd_context *cmd, struct profile *profile)' function
* to get the default value in runtime - usually, these functions are placed in config.[ch] file)
*
*
* If default value can't be assigned statically because it depends on some
* run-time checks or if it depends on other settings already defined,
@@ -52,6 +57,7 @@
* CFG_DISABLED - configuration is disabled (defaults always used)
* CFG_FORMAT_INT_OCTAL - print integer number in octal form (also prefixed by "0")
* CFG_SECTION_NO_CHECK - do not check content of the section at all - use with care!!!
* CFG_DISALLOW_INTERACTIVE - disallow configuration node for use in interactive environment (e.g. cmds run in lvm shell)
*
* type: Allowed type for the value of simple configuation setting, one of:
* CFG_TYPE_BOOL
@@ -166,7 +172,7 @@ cfg(config_checks_CFG, "checks", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2,
cfg(config_abort_on_errors_CFG, "abort_on_errors", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2,2,99), NULL, 0, NULL,
"Abort the LVM process if a configuration mismatch is found.\n")
cfg_runtime(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, 0, CFG_TYPE_STRING, vsn(2, 2, 99), 0, NULL,
cfg_runtime(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, vsn(2, 2, 99), 0, NULL,
"Directory where LVM looks for configuration profiles.\n")
cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_DEV_DIR, vsn(1, 0, 0), NULL, 0, NULL,
@@ -553,7 +559,7 @@ cfg_runtime(allocation_thin_pool_chunk_size_CFG, "thin_pool_chunk_size", allocat
cfg(allocation_physical_extent_size_CFG, "physical_extent_size", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_EXTENT_SIZE, vsn(2, 2, 112), NULL, 0, NULL,
"Default physical extent size in KiB to use for new VGs.\n")
cfg(log_report_command_log_CFG, "report_command_log", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_COMMAND_LOG_REPORT, vsn(2, 2, 158), NULL, 0, NULL,
cfg(log_report_command_log_CFG, "report_command_log", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_BOOL, DEFAULT_COMMAND_LOG_REPORT, vsn(2, 2, 158), NULL, 0, NULL,
"Enable or disable LVM log reporting.\n"
"If enabled, LVM will collect a log of operations, messages,\n"
"per-object return codes with object identification and associated\n"
@@ -569,17 +575,17 @@ cfg(log_report_command_log_CFG, "report_command_log", log_CFG_SECTION, CFG_PROFI
"You can also use log/command_log_selection to define selection\n"
"criteria used each time the log is reported.\n")
cfg(log_command_log_sort_CFG, "command_log_sort", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_SORT, vsn(2, 2, 158), NULL, 0, NULL,
cfg(log_command_log_sort_CFG, "command_log_sort", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_SORT, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to sort by when reporting command log.\n"
"See <lvm command> --logonly --configreport log -o help\n"
"for the list of possible fields.\n")
cfg(log_command_log_cols_CFG, "command_log_cols", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_COLS, vsn(2, 2, 158), NULL, 0, NULL,
cfg(log_command_log_cols_CFG, "command_log_cols", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_COLS, vsn(2, 2, 158), NULL, 0, NULL,
"List of columns to report when reporting command log.\n"
"See <lvm command> --logonly --configreport log -o help\n"
"for the list of possible fields.\n")
cfg(log_command_log_selection_CFG, "command_log_selection", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_SELECTION, vsn(2, 2, 158), NULL, 0, NULL,
cfg(log_command_log_selection_CFG, "command_log_selection", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_SELECTION, vsn(2, 2, 158), NULL, 0, NULL,
"Selection criteria used when reporting command log.\n"
"You can define selection criteria that are applied each\n"
"time log is reported. This way, it is possible to control the\n"
@@ -1509,7 +1515,7 @@ cfg(disk_area_start_sector_CFG, "start_sector", disk_area_CFG_SUBSECTION, CFG_UN
cfg(disk_area_size_CFG, "size", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg(disk_area_id_CFG, "id", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg(report_output_format_CFG, "output_format", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_REP_OUTPUT_FORMAT, vsn(2, 2, 158), NULL, 0, NULL,
cfg(report_output_format_CFG, "output_format", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_REP_OUTPUT_FORMAT, vsn(2, 2, 158), NULL, 0, NULL,
"Format of LVM command's report output.\n"
"If there is more than one report per command, then the format\n"
"is applied for all reports. You can also change output format\n"

View File

@@ -66,8 +66,13 @@
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
#define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
// FIXME Increase this to 64
#define DEFAULT_RAID_MAX_IMAGES 8 /* limited by kernel failed devices bitfield in superblock (raid4/5/6 max 253) */
/* Limited by kernel failed devices bitfield in superblock (raid4/5/6 MD max 253) */
/*
* FIXME: Increase these to 64 and further to the MD maximum
* once the SubLVs split and name shift got enhanced
*/
#define DEFAULT_RAID1_MAX_IMAGES 10
#define DEFAULT_RAID_MAX_IMAGES 64
#define DEFAULT_ALLOCATION_STRIPE_ALL_DEVICES 0 /* Don't stripe across all devices if not -i/--stripes given */
#define DEFAULT_RAID_FAULT_POLICY "warn"

View File

@@ -18,6 +18,7 @@
#include "memlock.h"
#include "defaults.h"
#include "report.h"
#include "lvm-file.h"
#include <stdio.h>
#include <stdarg.h>
@@ -59,6 +60,154 @@ static log_report_t _log_report = {
.object_group = NULL
};
#define LOG_STREAM_BUFFER_SIZE 4096
struct log_stream_item {
FILE *stream;
char *buffer;
};
struct log_stream {
struct log_stream_item out;
struct log_stream_item err;
struct log_stream_item report;
} _log_stream = {{NULL, NULL},
{NULL, NULL},
{NULL, NULL}};
#define out_stream (_log_stream.out.stream ? : stdout)
#define err_stream (_log_stream.err.stream ? : stderr)
#define report_stream (_log_stream.report.stream ? : stdout)
static int _set_custom_log_stream(struct log_stream_item *stream_item, int custom_fd)
{
FILE *final_stream = NULL;
int flags;
int r = 1;
if (custom_fd < 0)
goto out;
if (is_valid_fd(custom_fd)) {
if ((flags = fcntl(custom_fd, F_GETFL)) > 0) {
if ((flags & O_ACCMODE) == O_RDONLY) {
log_error("File descriptor %d already open in read-only "
"mode, expected write-only or read-write mode.",
(int) custom_fd);
r = 0;
goto out;
}
}
if (custom_fd == STDIN_FILENO) {
log_error("Can't set standard input for log output.");
r = 0;
goto out;
}
if (custom_fd == STDOUT_FILENO) {
final_stream = stdout;
goto out;
}
if (custom_fd == STDERR_FILENO) {
final_stream = stderr;
goto out;
}
}
if (!(final_stream = fdopen(custom_fd, "w"))) {
log_error("Failed to open stream for file descriptor %d.",
(int) custom_fd);
r = 0;
goto out;
}
if (!(stream_item->buffer = dm_malloc(LOG_STREAM_BUFFER_SIZE))) {
log_error("Failed to allocate buffer for stream on file "
"descriptor %d.", (int) custom_fd);
} else {
if (setvbuf(final_stream, stream_item->buffer, _IOLBF, LOG_STREAM_BUFFER_SIZE)) {
log_sys_error("setvbuf", "");
dm_free(stream_item->buffer);
stream_item->buffer = NULL;
}
}
out:
stream_item->stream = final_stream;
return r;
}
int init_custom_log_streams(struct custom_fds *custom_fds)
{
return _set_custom_log_stream(&_log_stream.out, custom_fds->out) &&
_set_custom_log_stream(&_log_stream.err, custom_fds->err) &&
_set_custom_log_stream(&_log_stream.report, custom_fds->report);
}
static void _check_and_replace_standard_log_streams(FILE *old_stream, FILE *new_stream)
{
if (_log_stream.out.stream == old_stream)
_log_stream.out.stream = new_stream;
if (_log_stream.err.stream == old_stream)
_log_stream.err.stream = new_stream;
if (_log_stream.report.stream == old_stream)
_log_stream.report.stream = new_stream;
}
/*
* Close and reopen standard stream on file descriptor fd.
*/
int reopen_standard_stream(FILE **stream, const char *mode)
{
int fd, fd_copy, new_fd;
const char *name;
FILE *old_stream = *stream;
FILE *new_stream;
if (old_stream == stdin) {
fd = STDIN_FILENO;
name = "stdin";
} else if (old_stream == stdout) {
fd = STDOUT_FILENO;
name = "stdout";
} else if (old_stream == stderr) {
fd = STDERR_FILENO;
name = "stderr";
} else {
log_error(INTERNAL_ERROR "reopen_standard_stream called on non-standard stream");
return 0;
}
if ((fd_copy = dup(fd)) < 0) {
log_sys_error("dup", name);
return 0;
}
if (fclose(old_stream))
log_sys_error("fclose", name);
if ((new_fd = dup2(fd_copy, fd)) < 0)
log_sys_error("dup2", name);
else if (new_fd != fd)
log_error("dup2(%d, %d) returned %d", fd_copy, fd, new_fd);
if (close(fd_copy) < 0)
log_sys_error("close", name);
if (!(new_stream = fdopen(fd, mode))) {
log_sys_error("fdopen", name);
return 0;
}
_check_and_replace_standard_log_streams(old_stream, new_stream);
*stream = new_stream;
return 1;
}
void init_log_fn(lvm2_log_fn_t log_fn)
{
_lvm2_log_fn = log_fn;
@@ -207,10 +356,10 @@ void fin_log(void)
if (_log_to_file) {
if (dm_fclose(_log_file)) {
if (errno)
fprintf(stderr, "failed to write log file: %s\n",
fprintf(err_stream, "failed to write log file: %s\n",
strerror(errno));
else
fprintf(stderr, "failed to write log file\n");
fprintf(err_stream, "failed to write log file\n");
}
_log_to_file = 0;
@@ -300,6 +449,7 @@ static const char *_get_log_level_name(int use_stderr, int level)
const char *log_get_report_context_name(log_report_context_t context)
{
static const char *log_context_names[LOG_REPORT_CONTEXT_COUNT] = {[LOG_REPORT_CONTEXT_NULL] = "",
[LOG_REPORT_CONTEXT_SHELL] = "shell",
[LOG_REPORT_CONTEXT_PROCESSING] = "processing"};
return log_context_names[context];
}
@@ -308,6 +458,7 @@ const char *log_get_report_context_name(log_report_context_t context)
const char *log_get_report_object_type_name(log_report_object_type_t object_type)
{
static const char *log_object_type_names[LOG_REPORT_OBJECT_TYPE_COUNT] = {[LOG_REPORT_OBJECT_TYPE_NULL] = "",
[LOG_REPORT_OBJECT_TYPE_CMD] = "cmd",
[LOG_REPORT_OBJECT_TYPE_ORPHAN] = "orphan",
[LOG_REPORT_OBJECT_TYPE_PV] = "pv",
[LOG_REPORT_OBJECT_TYPE_LABEL] = "label",
@@ -378,8 +529,8 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
/* When newer glibc returns >= sizeof(locn), we will just log what
* has fit into buffer, it's '\0' terminated string */
if (n < 0) {
fprintf(stderr, _("vsnprintf failed: skipping external "
"logging function"));
fprintf(err_stream, _("vsnprintf failed: skipping external "
"logging function"));
goto log_it;
}
}
@@ -426,7 +577,7 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
_log_report.object_name, _log_report.object_id,
_log_report.object_group, _log_report.object_group_id,
message, _lvm_errno, 0))
fprintf(stderr, _("failed to report cmdstatus"));
fprintf(err_stream, _("failed to report cmdstatus"));
else
logged_via_report = 1;
@@ -468,10 +619,10 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
break;
/* fall through */
default:
/* Typically only log_warn goes to stdout */
stream = (use_stderr || (level != _LOG_WARN)) ? stderr : stdout;
if (stream == stderr)
fflush(stdout);
/* Typically only log_warn goes to out_stream */
stream = (use_stderr || (level != _LOG_WARN)) ? err_stream : out_stream;
if (stream == err_stream)
fflush(out_stream);
fprintf(stream, "%s%s%s%s", buf, log_command_name(),
_msg_prefix, indent_spaces);
vfprintf(stream, trformat, ap);
@@ -556,6 +707,7 @@ void print_log(int level, const char *file, int line, int dm_errno_or_class,
void print_log_libdm(int level, const char *file, int line, int dm_errno_or_class,
const char *format, ...)
{
FILE *orig_out_stream = out_stream;
va_list ap;
/*
@@ -567,9 +719,13 @@ void print_log_libdm(int level, const char *file, int line, int dm_errno_or_clas
((level & ~(_LOG_STDERR|_LOG_ONCE|_LOG_BYPASS_REPORT)) == _LOG_WARN))
level |= _LOG_BYPASS_REPORT;
_log_stream.out.stream = report_stream;
va_start(ap, format);
_vprint_log(level, file, line, dm_errno_or_class, format, ap);
va_end(ap);
_log_stream.out.stream = orig_out_stream;
}
log_report_t log_get_report_state(void)

View File

@@ -16,6 +16,8 @@
#ifndef _LVM_LOGGING_H
#define _LVM_LOGGING_H
#include "lvm-file.h"
__attribute__ ((format(printf, 5, 6)))
void print_log(int level, const char *file, int line, int dm_errno_or_class,
const char *format, ...);
@@ -35,6 +37,9 @@ void print_log_libdm(int level, const char *file, int line, int dm_errno_or_clas
#include "log.h"
int init_custom_log_streams(struct custom_fds *custom_fds);
int reopen_standard_stream(FILE **stream, const char *mode);
typedef void (*lvm2_log_fn_t) (int level, const char *file, int line,
int dm_errno_or_class, const char *message);
@@ -72,12 +77,14 @@ void syslog_suppress(int suppress);
/* Hooks to handle logging through report. */
typedef enum {
LOG_REPORT_CONTEXT_NULL,
LOG_REPORT_CONTEXT_SHELL,
LOG_REPORT_CONTEXT_PROCESSING,
LOG_REPORT_CONTEXT_COUNT
} log_report_context_t;
typedef enum {
LOG_REPORT_OBJECT_TYPE_NULL,
LOG_REPORT_OBJECT_TYPE_CMD,
LOG_REPORT_OBJECT_TYPE_ORPHAN,
LOG_REPORT_OBJECT_TYPE_PV,
LOG_REPORT_OBJECT_TYPE_LABEL,
@@ -96,6 +103,10 @@ typedef struct log_report {
const char *object_group_id;
} log_report_t;
#define LOG_STATUS_NAME "status"
#define LOG_STATUS_SUCCESS "success"
#define LOG_STATUS_FAILURE "failure"
log_report_t log_get_report_state(void);
void log_restore_report_state(log_report_t log_report);

View File

@@ -38,9 +38,6 @@ typedef enum {
NEXT_AREA
} area_use_t;
/* FIXME: remove RAID_METADATA_AREA_LEN macro after defining 'raid_log_extents'*/
#define RAID_METADATA_AREA_LEN 1
/* FIXME These ended up getting used differently from first intended. Refactor. */
/* Only one of A_CONTIGUOUS_TO_LVSEG, A_CLING_TO_LVSEG, A_CLING_TO_ALLOCED may be set */
#define A_CONTIGUOUS_TO_LVSEG 0x01 /* Must be contiguous to an existing segment */
@@ -119,6 +116,7 @@ enum {
LV_TYPE_RAID10,
LV_TYPE_RAID4,
LV_TYPE_RAID5,
LV_TYPE_RAID5_N,
LV_TYPE_RAID5_LA,
LV_TYPE_RAID5_RA,
LV_TYPE_RAID5_LS,
@@ -169,6 +167,7 @@ static const char *_lv_type_names[] = {
[LV_TYPE_RAID10] = SEG_TYPE_NAME_RAID10,
[LV_TYPE_RAID4] = SEG_TYPE_NAME_RAID4,
[LV_TYPE_RAID5] = SEG_TYPE_NAME_RAID5,
[LV_TYPE_RAID5_N] = SEG_TYPE_NAME_RAID5_N,
[LV_TYPE_RAID5_LA] = SEG_TYPE_NAME_RAID5_LA,
[LV_TYPE_RAID5_RA] = SEG_TYPE_NAME_RAID5_RA,
[LV_TYPE_RAID5_LS] = SEG_TYPE_NAME_RAID5_LS,
@@ -876,22 +875,38 @@ dm_percent_t copy_percent(const struct logical_volume *lv)
return denominator ? dm_make_percent(numerator, denominator) : DM_PERCENT_100;
}
/* Round up extents to next stripe boundary for number of stripes */
static uint32_t _round_to_stripe_boundary(struct volume_group *vg, uint32_t extents,
uint32_t stripes, int extend)
/*
* Round up @extents to next stripe boundary number of
* @stripes (if any) and/or to next RAID io boundary.
*/
uint32_t extents_round_to_boundary(struct volume_group *vg,
const struct segment_type *segtype,
uint32_t extents,
uint32_t stripes,
int extend)
{
int ensure_raid_min = segtype_is_raid(segtype);
uint32_t size_rest, new_extents = extents;
if (!stripes)
return extents;
do {
/* Round up extents to stripe divisible amount if given @stripes */
if (stripes > 1 && (size_rest = new_extents % stripes))
new_extents += extend ? stripes - size_rest : -size_rest;
/* Round up extents to stripe divisible amount */
if ((size_rest = extents % stripes)) {
new_extents += extend ? stripes - size_rest : -size_rest;
log_print_unless_silent("Rounding size %s (%d extents) up to stripe boundary size %s (%d extents).",
if (ensure_raid_min) {
/* Require multiples of 64 KiB to not fail in kernel RAID page size IO */
if ((new_extents * vg->extent_size) % ((stripes ?: 1) * RAID_ALLOC_CHUNK_SECTORS))
extend ? new_extents++ : new_extents--;
else
ensure_raid_min = 0;
}
} while (ensure_raid_min);
if (extents != new_extents)
log_print_unless_silent("Rounding size %s (%d extents) up to %s i/o boundary size %s (%d extents).",
display_size(vg->cmd, (uint64_t) extents * vg->extent_size), extents,
segtype_is_raid(segtype) ? (stripes > 1 ? "stripe/RAID" : "RAID") : "stripe",
display_size(vg->cmd, (uint64_t) new_extents * vg->extent_size), new_extents);
}
return new_extents;
}
@@ -1254,7 +1269,7 @@ static int _lv_segment_reduce(struct lv_segment *seg, uint32_t reduction)
*/
static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
{
struct lv_segment *seg;
struct lv_segment *seg = first_seg(lv);
uint32_t count = extents;
uint32_t reduction;
struct logical_volume *pool_lv;
@@ -1265,6 +1280,9 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
clear_snapshot_merge(lv);
}
if (!delete && seg)
extents = extents_round_to_boundary(lv->vg, seg->segtype, extents, seg->area_count - seg->segtype->parity_devs, 0);
dm_list_iterate_back_items(seg, &lv->segments) {
if (!count)
break;
@@ -1579,11 +1597,12 @@ static uint32_t _mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint
/* Is there enough total space or should we give up immediately? */
static int _sufficient_pes_free(struct alloc_handle *ah, struct dm_list *pvms,
uint32_t allocated, uint32_t extents_still_needed)
uint32_t allocated, uint32_t extents_still_needed,
uint32_t extent_size)
{
uint32_t area_extents_needed = (extents_still_needed - allocated) * ah->area_count / ah->area_multiple;
uint32_t parity_extents_needed = (extents_still_needed - allocated) * ah->parity_count / ah->area_multiple;
uint32_t metadata_extents_needed = ah->alloc_and_split_meta ? 0 : ah->metadata_area_count * RAID_METADATA_AREA_LEN; /* One each */
uint32_t metadata_extents_needed = ah->alloc_and_split_meta ? 0 : ah->metadata_area_count * lv_raid_metadata_area_len(extent_size);
uint32_t total_extents_needed = area_extents_needed + parity_extents_needed + metadata_extents_needed;
uint32_t free_pes = pv_maps_size(pvms);
@@ -3040,7 +3059,7 @@ static int _allocate(struct alloc_handle *ah,
old_allocated = alloc_state.allocated;
log_debug_alloc("Trying allocation using %s policy.", get_alloc_string(alloc));
if (!ah->approx_alloc && !_sufficient_pes_free(ah, pvms, alloc_state.allocated, ah->new_extents))
if (!ah->approx_alloc && !_sufficient_pes_free(ah, pvms, alloc_state.allocated, ah->new_extents, vg->extent_size))
goto_out;
_init_alloc_parms(ah, &alloc_parms, alloc, prev_lvseg,
@@ -3233,7 +3252,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
ah->metadata_area_count = area_count;
ah->alloc_and_split_meta = 1;
ah->log_len = RAID_METADATA_AREA_LEN;
ah->log_len = existing_extents ? 0 : lv_raid_metadata_area_len(extent_size);
/*
* We need 'log_len' extents for each
@@ -3279,7 +3298,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
log_debug("Adjusted allocation request to %" PRIu32 " logical extents. Existing size %" PRIu32 ". New size %" PRIu32 ".",
total_extents, existing_extents, total_extents + existing_extents);
if (ah->log_len)
log_debug("Mirror log of %" PRIu32 " extents of size %" PRIu32 "sectors needed for region size %" PRIu32 ".",
log_debug("Mirror log of %" PRIu32 " extents of size %" PRIu32 " sectors needed for region size %" PRIu32 ".",
ah->log_len, extent_size, ah->region_size);
if (mirrors || stripes)
@@ -3936,6 +3955,35 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
return 1;
}
/* Return maximum number of extents for size of MetaLV of RaidLV @lv with bitmap */
#define RAID_HEADER_SIZE (2 * 4096) /* dm-raid superblock and bitmap superblock */
static uint32_t _max_raid_extents(struct logical_volume *lv)
{
uint64_t max_image_size;
uint64_t mlv_bytes; /* dm-raid superblock and bitmap superblock */
struct lv_segment *seg = first_seg(lv);
struct logical_volume *mlv;
if (!seg ||
!seg_is_raid(seg) ||
!seg->meta_areas ||
!(mlv = seg_metalv(seg, 0)) ||
!seg->region_size)
return ~0U;
mlv_bytes = (mlv->le_count * lv->vg->extent_size) << SECTOR_SHIFT;
if (mlv_bytes < RAID_HEADER_SIZE) {
log_error("Metadata LV %s too small to even hold the RAID headers",
display_lvname(mlv));
return 0;
}
/* Subtract space for 2 headers (superblock and bitmap) */
max_image_size = (mlv_bytes - RAID_HEADER_SIZE) * 8 * seg->region_size;
return max_image_size / lv->vg->extent_size * (seg_is_raid1(seg) ? 1 : seg->area_count - seg->segtype->parity_devs);
}
/*
* Entry point for single-step LV allocation + extension.
* Extents is the number of logical extents to append to the LV unless
@@ -3980,6 +4028,8 @@ int lv_extend(struct logical_volume *lv,
}
/* FIXME log_count should be 1 for mirrors */
extents = extents_round_to_boundary(lv->vg, segtype, extents, stripes, 1);
if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors,
log_count, region_size, extents,
allocatable_pvs, alloc, approx_alloc, NULL)))
@@ -3997,6 +4047,8 @@ int lv_extend(struct logical_volume *lv,
stripe_size, 0u, 0)))
stack;
} else {
uint32_t max_extents;
/*
* For RAID, all the devices are AREA_LV.
* However, for 'mirror on stripe' using non-RAID targets,
@@ -4021,6 +4073,14 @@ int lv_extend(struct logical_volume *lv,
stripes, stripe_size)))
goto_out;
if ((max_extents = _max_raid_extents(lv)) < lv->le_count) {
log_error("Can't extend LV %s larger than %s because of MetaLV size",
display_lvname(lv),
display_size(lv->vg->cmd, max_extents * lv->vg->extent_size));
r = 0;
goto out;
}
/*
* If we are expanding an existing mirror, we can skip the
* resync of the extension if the LV is currently in-sync
@@ -7082,29 +7142,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
}
if (lp->stripe_size > vg->extent_size) {
if (seg_is_raid(lp) && (vg->extent_size < STRIPE_SIZE_MIN)) {
/*
* FIXME: RAID will simply fail to load the table if
* this is the case, but we should probably
* honor the stripe minimum for regular stripe
* volumes as well. Avoiding doing that now
* only to minimize the change.
*/
log_error("The extent size in volume group %s is too "
"small to support striped RAID volumes.",
vg->name);
return NULL;
}
log_print_unless_silent("Reducing requested stripe size %s to maximum, "
"physical extent size %s.",
display_size(cmd, (uint64_t) lp->stripe_size),
display_size(cmd, (uint64_t) vg->extent_size));
lp->stripe_size = vg->extent_size;
}
lp->extents = _round_to_stripe_boundary(vg, lp->extents, lp->stripes, 1);
lp->extents = extents_round_to_boundary(vg, lp->segtype, lp->extents, lp->stripes, 1);
if (!lp->extents && !seg_is_thin_volume(lp)) {
log_error(INTERNAL_ERROR "Unable to create new logical volume with no extents.");

View File

@@ -97,6 +97,9 @@ static void _check_raid0_seg(struct lv_segment *seg, int *error_count)
if (seg_is_raid0_meta(seg) &&
!seg->meta_areas)
raid_seg_error("no meta areas");
if (!seg_is_raid0_meta(seg) &&
seg->meta_areas)
raid_seg_error("meta areas");
if (!seg->stripe_size)
raid_seg_error("zero stripe size");
if (!is_power_of_2(seg->stripe_size))
@@ -121,7 +124,7 @@ static void _check_raid_region_recovery(struct lv_segment *seg, int *error_count
/* min/max recovery rate may be zero but min may not be larger than max if set */
if (seg->max_recovery_rate &&
seg->min_recovery_rate > seg->max_recovery_rate)
raid_seg_error_val("min recovery larger than max recovery larger", seg->min_recovery_rate);
raid_seg_error_val("min recovery larger than max recovery", seg->min_recovery_rate);
}
/* Check raid1 segment properties in @seg */
@@ -258,10 +261,17 @@ static void _check_raid_seg(struct lv_segment *seg, int *error_count)
if (seg->extents_copied > seg->area_len)
raid_seg_error_val("extents_copied too large", seg->extents_copied);
/* Default still 8, change! */
if (seg->area_count > DEFAULT_RAID_MAX_IMAGES) {
/* 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));
seg->lv->name, DEFAULT_RAID_MAX_IMAGES, seg->area_count, lvseg_name(seg));
if ((*error_count)++ > ERROR_MAX)
return;
}
@@ -289,8 +299,10 @@ static void _check_raid_seg(struct lv_segment *seg, int *error_count)
/* Check for any MetaLV flaws like non-existing ones or size variations */
if (seg->meta_areas)
for (area_len = s = 0; s < seg->area_count; s++) {
if (seg_metatype(seg, s) != AREA_LV)
if (seg_metatype(seg, s) != AREA_LV) {
raid_seg_error("no MetaLV");
continue;
}
if (!lv_is_raid_metadata(seg_metalv(seg, s)))
raid_seg_error("MetaLV without RAID metadata flag");
if (area_len &&
@@ -391,7 +403,7 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
dm_list_iterate_items(seg, &lv->segments) {
seg_count++;
if (seg_is_raid(seg))
if (complete_vg && seg_is_raid(seg))
_check_raid_seg(seg, &error_count);
if (seg->le != le) {

View File

@@ -36,6 +36,7 @@
#define MAX_RESTRICTED_LVS 255 /* Used by FMT_RESTRICTED_LVIDS */
#define MAX_EXTENT_SIZE ((uint32_t) -1)
#define MIN_NON_POWER2_EXTENT_SIZE (128U * 2U) /* 128KB in sectors */
#define RAID_ALLOC_CHUNK_SECTORS (64 * 2) /* Allocate RAID in these minimal chunks to ensure page io doesn't fail */
#define HISTORICAL_LV_PREFIX "-"
@@ -832,6 +833,12 @@ uint32_t extents_from_percent_size(struct volume_group *vg, const struct dm_list
uint32_t extents, int roundup,
percent_type_t percent, uint64_t size);
/* Round @extents to stripe and/or RAID io boundary */
uint32_t extents_round_to_boundary(struct volume_group *vg,
const struct segment_type *segtype,
uint32_t extents, uint32_t stripes,
int extend);
struct logical_volume *find_pool_lv(const struct logical_volume *lv);
int pool_is_active(const struct logical_volume *pool_lv);
int pool_supports_external_origin(const struct lv_segment *pool_seg, const struct logical_volume *external_lv);
@@ -1190,7 +1197,7 @@ struct logical_volume *first_replicator_dev(const struct logical_volume *lv);
int lv_is_raid_with_tracking(const struct logical_volume *lv);
uint32_t lv_raid_image_count(const struct logical_volume *lv);
int lv_raid_change_image_count(struct logical_volume *lv,
uint32_t new_count, struct dm_list *pvs);
uint32_t new_count, struct dm_list *allocate_pvs);
int lv_raid_split(struct logical_volume *lv, const char *split_name,
uint32_t new_count, struct dm_list *splittable_pvs);
int lv_raid_split_and_track(struct logical_volume *lv,
@@ -1200,12 +1207,16 @@ int lv_raid_convert(struct logical_volume *lv,
const struct segment_type *new_segtype,
int yes, int force,
const unsigned stripes,
const unsigned new_stripe_size_supplied,
const unsigned new_stripe_size,
const uint32_t new_region_size,
struct dm_list *allocate_pvs);
int lv_raid_rebuild(struct logical_volume *lv, struct dm_list *rebuild_pvs);
int lv_raid_replace(struct logical_volume *lv, struct dm_list *remove_pvs,
struct dm_list *allocate_pvs);
int lv_raid_remove_missing(struct logical_volume *lv);
int partial_raid_lv_supports_degraded_activation(const struct logical_volume *lv);
uint32_t lv_raid_metadata_area_len(uint32_t extent_size);
/* -- metadata/raid_manip.c */
/* ++ metadata/cache_manip.c */
@@ -1269,6 +1280,7 @@ uint32_t find_free_lvnum(struct logical_volume *lv);
dm_percent_t copy_percent(const struct logical_volume *lv_mirr);
char *generate_lv_name(struct volume_group *vg, const char *format,
char *buffer, size_t len);
char *top_level_lv_name(struct volume_group *vg, const char *lv_name);
struct generic_logical_volume *get_or_create_glv(struct dm_pool *mem, struct logical_volume *lv, int *glv_created);
struct glv_list *get_or_create_glvl(struct dm_pool *mem, struct logical_volume *lv, int *glv_created);

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,7 @@ struct segment_type *get_segtype_from_flag(struct cmd_context *cmd, uint64_t fla
if (flag & segtype->flags)
return segtype;
log_error(INTERNAL_ERROR "Unrecognised segment type flag 0x%" PRIx64, flag);
log_error(INTERNAL_ERROR "Unrecognised segment type flag 0x%016" PRIx64, flag);
return NULL;
}

View File

@@ -68,6 +68,8 @@ struct dev_manager;
#define SEG_RAID6_N_6 0x0000000800000000ULL
#define SEG_RAID6 SEG_RAID6_ZR
#define SEG_STRIPED_TARGET 0x0000008000000000ULL
#define SEG_UNKNOWN 0x8000000000000000ULL
#define SEG_TYPE_NAME_LINEAR "linear"
@@ -88,6 +90,7 @@ struct dev_manager;
#define SEG_TYPE_NAME_RAID10 "raid10"
#define SEG_TYPE_NAME_RAID4 "raid4"
#define SEG_TYPE_NAME_RAID5 "raid5"
#define SEG_TYPE_NAME_RAID5_N "raid5_n"
#define SEG_TYPE_NAME_RAID5_LA "raid5_la"
#define SEG_TYPE_NAME_RAID5_LS "raid5_ls"
#define SEG_TYPE_NAME_RAID5_RA "raid5_ra"
@@ -96,8 +99,14 @@ struct dev_manager;
#define SEG_TYPE_NAME_RAID6_NC "raid6_nc"
#define SEG_TYPE_NAME_RAID6_NR "raid6_nr"
#define SEG_TYPE_NAME_RAID6_ZR "raid6_zr"
#define SEG_TYPE_NAME_RAID6_LA_6 "raid6_la_6"
#define SEG_TYPE_NAME_RAID6_LS_6 "raid6_ls_6"
#define SEG_TYPE_NAME_RAID6_RA_6 "raid6_ra_6"
#define SEG_TYPE_NAME_RAID6_RS_6 "raid6_rs_6"
#define SEG_TYPE_NAME_RAID6_N_6 "raid6_n_6"
#define segtype_is_linear(segtype) (!strcmp(segtype->name, SEG_TYPE_NAME_LINEAR))
#define segtype_is_striped_target(segtype) ((segtype)->flags & SEG_STRIPED_TARGET ? 1 : 0)
#define segtype_is_cache(segtype) ((segtype)->flags & SEG_CACHE ? 1 : 0)
#define segtype_is_cache_pool(segtype) ((segtype)->flags & SEG_CACHE_POOL ? 1 : 0)
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
@@ -111,6 +120,7 @@ struct dev_manager;
#define segtype_is_raid4(segtype) ((segtype)->flags & SEG_RAID4 ? 1 : 0)
#define segtype_is_any_raid5(segtype) ((segtype)->flags & \
(SEG_RAID5_LS|SEG_RAID5_LA|SEG_RAID5_RS|SEG_RAID5_RA|SEG_RAID5_N) ? 1 : 0)
#define segtype_is_raid5_n(segtype) ((segtype)->flags & SEG_RAID5_N ? 1 : 0)
#define segtype_is_raid5_la(segtype) ((segtype)->flags & SEG_RAID5_LA ? 1 : 0)
#define segtype_is_raid5_ra(segtype) ((segtype)->flags & SEG_RAID5_RA ? 1 : 0)
#define segtype_is_raid5_ls(segtype) ((segtype)->flags & SEG_RAID5_LS ? 1 : 0)
@@ -120,8 +130,11 @@ struct dev_manager;
SEG_RAID6_LA_6|SEG_RAID6_LS_6|SEG_RAID6_RA_6|SEG_RAID6_RS_6|SEG_RAID6_N_6) ? 1 : 0)
#define segtype_is_raid6_nc(segtype) ((segtype)->flags & SEG_RAID6_NC ? 1 : 0)
#define segtype_is_raid6_nr(segtype) ((segtype)->flags & SEG_RAID6_NR ? 1 : 0)
#define segtype_is_raid6_n_6(segtype) ((segtype)->flags & SEG_RAID6_N_6 ? 1 : 0)
#define segtype_is_raid6_zr(segtype) ((segtype)->flags & SEG_RAID6_ZR ? 1 : 0)
#define segtype_is_any_raid10(segtype) ((segtype)->flags & SEG_RAID10 ? 1 : 0)
#define segtype_is_raid10(segtype) ((segtype)->flags & SEG_RAID10 ? 1 : 0)
#define segtype_is_raid10_near(segtype) segtype_is_raid10(segtype)
#define segtype_is_raid_with_meta(segtype) (segtype_is_raid(segtype) && !segtype_is_raid0(segtype))
#define segtype_is_snapshot(segtype) ((segtype)->flags & SEG_SNAPSHOT ? 1 : 0)
#define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
@@ -131,6 +144,13 @@ struct dev_manager;
#define segtype_is_virtual(segtype) ((segtype)->flags & SEG_VIRTUAL ? 1 : 0)
#define segtype_is_unknown(segtype) ((segtype)->flags & SEG_UNKNOWN ? 1 : 0)
#define segtype_supports_stripe_size(segtype) \
((segtype_is_striped(segtype) || segtype_is_mirror(segtype) || \
segtype_is_cache(segtype) || segtype_is_cache_pool(segtype) || \
segtype_is_thin(segtype) || segtype_is_snapshot(segtype) || \
(segtype_is_raid(segtype) && !segtype_is_raid1(segtype))) ? 1 : 0)
#define seg_is_striped_target(seg) segtype_is_striped_target((seg)->segtype)
#define seg_is_cache(seg) segtype_is_cache((seg)->segtype)
#define seg_is_cache_pool(seg) segtype_is_cache_pool((seg)->segtype)
#define seg_is_linear(seg) (seg_is_striped(seg) && ((seg)->area_count == 1))
@@ -144,6 +164,7 @@ struct dev_manager;
#define seg_is_raid1(seg) segtype_is_raid1((seg)->segtype)
#define seg_is_raid4(seg) segtype_is_raid4((seg)->segtype)
#define seg_is_any_raid5(seg) segtype_is_any_raid5((seg)->segtype)
#define seg_is_raid5_n(seg) segtype_is_raid5_n((seg)->segtype)
#define seg_is_raid5_la(seg) segtype_is_raid5_la((seg)->segtype)
#define seg_is_raid5_ra(seg) segtype_is_raid5_ra((seg)->segtype)
#define seg_is_raid5_ls(seg) segtype_is_raid5_ls((seg)->segtype)
@@ -152,7 +173,10 @@ struct dev_manager;
#define seg_is_raid6_zr(seg) segtype_is_raid6_zr((seg)->segtype)
#define seg_is_raid6_nr(seg) segtype_is_raid6_nr((seg)->segtype)
#define seg_is_raid6_nc(seg) segtype_is_raid6_nc((seg)->segtype)
#define seg_is_raid6_n_6(seg) segtype_is_raid6_n_6((seg)->segtype)
#define seg_is_any_raid10(seg) segtype_is_any_raid10((seg)->segtype)
#define seg_is_raid10(seg) segtype_is_raid10((seg)->segtype)
#define seg_is_raid10_near(seg) segtype_is_raid10_near((seg)->segtype)
#define seg_is_raid_with_meta(seg) segtype_is_raid_with_meta((seg)->segtype)
#define seg_is_replicator(seg) ((seg)->segtype->flags & SEG_REPLICATOR ? 1 : 0)
#define seg_is_replicator_dev(seg) ((seg)->segtype->flags & SEG_REPLICATOR_DEV ? 1 : 0)

View File

@@ -16,6 +16,12 @@
#ifndef _LVM_FILE_H
#define _LVM_FILE_H
struct custom_fds {
int out;
int err;
int report;
};
/*
* Create a temporary filename, and opens a descriptor to the file.
*/

View File

@@ -73,7 +73,7 @@ void lvmnotify_send(struct cmd_context *cmd)
out:
sd_bus_error_free(&error);
sd_bus_message_unref(m);
sd_bus_unref(bus);
sd_bus_flush_close_unref(bus);
}
void set_vg_notify(struct cmd_context *cmd)

View File

@@ -38,6 +38,9 @@ struct lvm_report_object {
struct label *label;
};
static uint32_t log_seqnum = 1;
/*
* Enum for field_num index to use in per-field reserved value definition.
* Each field is represented by enum value with name "field_<id>" where <id>
@@ -3867,9 +3870,7 @@ int report_cmdlog(void *handle, const char *type, const char *context,
const char *object_group_id, const char *msg,
int current_errno, int ret_code)
{
static uint32_t seq_num = 1;
struct cmd_log_item log_item = {seq_num++, type, context, object_type_name,
struct cmd_log_item log_item = {log_seqnum++, type, context, object_type_name,
object_name ? : "", object_id ? : "",
object_group ? : "", object_group_id ? : "",
msg ? : "", current_errno, ret_code};
@@ -3880,6 +3881,11 @@ int report_cmdlog(void *handle, const char *type, const char *context,
return 1;
}
void report_reset_cmdlog_seqnum(void)
{
log_seqnum = 1;
}
int report_current_object_cmdlog(const char *type, const char *msg, int32_t ret_code)
{
log_report_t log_state = log_get_report_state();

View File

@@ -81,9 +81,7 @@ struct processing_handle;
typedef int (*field_report_fn) (struct report_handle * dh, struct field * field,
const void *data);
int report_format_init(struct cmd_context *cmd, dm_report_group_type_t *report_group_type,
struct dm_report_group **report_group, struct dm_report **log_rh,
int *log_only, log_report_t *saved_log_report_state);
int report_format_init(struct cmd_context *cmd);
void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
report_type_t *report_type, const char *separator,
@@ -113,6 +111,7 @@ int report_cmdlog(void *handle, const char *type, const char *context,
const char *object_id, const char *object_group,
const char *object_group_id, const char *msg,
int current_errno, int ret_code);
void report_reset_cmdlog_seqnum(void);
#define REPORT_OBJECT_CMDLOG_NAME "status"
#define REPORT_OBJECT_CMDLOG_SUCCESS "success"
#define REPORT_OBJECT_CMDLOG_FAILURE "failure"

View File

@@ -233,7 +233,7 @@ struct segment_type *init_striped_segtype(struct cmd_context *cmd)
segtype->ops = &_striped_ops;
segtype->name = SEG_TYPE_NAME_STRIPED;
segtype->flags =
segtype->flags = SEG_STRIPED_TARGET |
SEG_CAN_SPLIT | SEG_AREAS_STRIPED | SEG_FORMAT1_SUPPORT;
log_very_verbose("Initialised segtype: %s", segtype->name);

View File

@@ -0,0 +1,2 @@
dm_report_destroy_rows
dm_report_group_output_and_pop_all

View File

@@ -2907,6 +2907,11 @@ int dm_report_compact_given_fields(struct dm_report *rh, const char *fields);
*/
int dm_report_is_empty(struct dm_report *rh);
/*
* Destroy report content without doing output.
*/
void dm_report_destroy_rows(struct dm_report *rh);
int dm_report_output(struct dm_report *rh);
/*
@@ -2969,6 +2974,7 @@ typedef enum {
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data);
int dm_report_group_push(struct dm_report_group *group, struct dm_report *report, void *data);
int dm_report_group_pop(struct dm_report_group *group);
int dm_report_group_output_and_pop_all(struct dm_report_group *group);
int dm_report_group_destroy(struct dm_report_group *group);
/*

View File

@@ -4674,6 +4674,14 @@ static struct report_group_item *_get_topmost_report_group_item(struct dm_report
return item;
}
static void _json_output_start(struct dm_report_group *group)
{
if (!group->indent) {
log_print(JSON_OBJECT_START);
group->indent += JSON_INDENT_UNIT;
}
}
static int _json_output_array_start(struct dm_pool *mem, struct report_group_item *item)
{
const char *name = (const char *) item->data;
@@ -4713,6 +4721,8 @@ bad:
static int _prepare_json_report_output(struct dm_report *rh)
{
_json_output_start(rh->group_item->group);
if (rh->group_item->output_done && dm_list_empty(&rh->rows))
return 1;
@@ -4790,21 +4800,9 @@ out:
return r;
}
static int _report_group_create_single(struct dm_report_group *group)
void dm_report_destroy_rows(struct dm_report *rh)
{
return 1;
}
static int _report_group_create_basic(struct dm_report_group *group)
{
return 1;
}
static int _report_group_create_json(struct dm_report_group *group)
{
log_print(JSON_OBJECT_START);
group->indent += JSON_INDENT_UNIT;
return 1;
_destroy_rows(rh);
}
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data)
@@ -4834,23 +4832,6 @@ struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void
dm_list_add_h(&group->items, &item->list);
switch (type) {
case DM_REPORT_GROUP_SINGLE:
if (!_report_group_create_single(group))
goto_bad;
break;
case DM_REPORT_GROUP_BASIC:
if (!_report_group_create_basic(group))
goto_bad;
break;
case DM_REPORT_GROUP_JSON:
if (!_report_group_create_json(group))
goto_bad;
break;
default:
goto_bad;
}
return group;
bad:
dm_pool_destroy(mem);
@@ -4902,6 +4883,7 @@ static int _report_group_push_json(struct report_group_item *item, const char *n
DM_REPORT_OUTPUT_COLUMNS_AS_ROWS);
item->report->flags |= DM_REPORT_OUTPUT_BUFFERED;
} else {
_json_output_start(item->group);
if (name) {
if (!_json_output_array_start(item->group->mem, item))
return_0;
@@ -5046,56 +5028,40 @@ int dm_report_group_pop(struct dm_report_group *group)
return 1;
}
static int _report_group_destroy_single(void)
int dm_report_group_output_and_pop_all(struct dm_report_group *group)
{
return 1;
}
struct report_group_item *item, *tmp_item;
static int _report_group_destroy_basic(void)
{
return 1;
}
dm_list_iterate_items_safe(item, tmp_item, &group->items) {
if (!item->parent) {
item->store.finished_count = 0;
continue;
}
if (item->report && !dm_report_output(item->report))
return_0;
if (!dm_report_group_pop(group))
return_0;
}
if (group->type == DM_REPORT_GROUP_JSON) {
_json_output_start(group);
log_print(JSON_OBJECT_END);
group->indent -= JSON_INDENT_UNIT;
}
static int _report_group_destroy_json(void)
{
log_print(JSON_OBJECT_END);
return 1;
}
int dm_report_group_destroy(struct dm_report_group *group)
{
struct report_group_item *item, *tmp_item;
int r = 0;
int r = 1;
if (!group)
return 1;
dm_list_iterate_items_safe(item, tmp_item, &group->items) {
if (item->report && !dm_report_output(item->report))
goto_out;
if (!dm_report_group_pop(group))
goto_out;
}
if (!dm_report_group_output_and_pop_all(group))
r = 0;
switch (group->type) {
case DM_REPORT_GROUP_SINGLE:
if (!_report_group_destroy_single())
goto_out;
break;
case DM_REPORT_GROUP_BASIC:
if (!_report_group_destroy_basic())
goto_out;
break;
case DM_REPORT_GROUP_JSON:
if (!_report_group_destroy_json())
goto_out;
break;
default:
goto_out;
}
r = 1;
out:
dm_pool_destroy(group->mem);
return r;
}

View File

@@ -30,7 +30,7 @@ LVMDBUSDMAN = lvmdbusd.8
MAN5=lvm.conf.5
MAN7=lvmsystemid.7
MAN8=lvm-config.8 lvm-dumpconfig.8 lvm-lvpoll.8 \
MAN8=lvm-config.8 lvm-dumpconfig.8 lvm-fullreport.8 lvm-lvpoll.8 \
lvchange.8 lvmconfig.8 lvconvert.8 lvcreate.8 lvdisplay.8 lvextend.8 \
lvm.8 lvmchange.8 lvmconf.8 lvmdiskscan.8 lvmdump.8 lvmsadc.8 lvmsar.8 \
lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \

View File

@@ -509,7 +509,7 @@ regions (with the exception of in-flight IO counters).
Creates one or more new statistics regions on the specified device(s).
The region will span the entire device unless \fB\-\-start\fP and
\fB\-\-length\fP or \fB\-\-target\fP are given. The \fB\-\-start\fP and
\fB\-\-length\fP or \fB\-\-segments\fP are given. The \fB\-\-start\fP an
\fB\-\-length\fP options allow a region of arbitrary length to be placed
at an arbitrary offset into the device. The \fB\-\-segments\fP option
causes a new region to be created for each target in the corresponding
@@ -600,6 +600,11 @@ the number of histogram bins and their bounds must match exactly.
On success the group list and newly created \fBgroup_id\fP are
printed to stdout.
The group metadata is stored with the first (lowest numbered)
\fBregion_id\fP in the group: deleting this region will also delete
the group and other group members will be returned to their prior
state.
.
.HP
.CMD_HELP
@@ -672,8 +677,16 @@ each with its own counter set. In this case a summary value for the
entire region is also available for use in reports.
In addition, one or more regions on one device can be combined into
a statistics group allowing reporting of aggregate values for all
regions and areas making up the group.
a statistics group. Groups allow several regions to be aggregated and
reported as a single entity; counters for all regions and areas are
summed and used to report totals for all group members. Groups also
permit the assignment of an optional alias, allowing meaningful names
to be associated with sets of regions.
The group metadata is stored with the first (lowest numbered)
\fBregion_id\fP in the group: deleting this region will also delete
the group and other group members will be returned to their prior
state.
By default new regions span the entire device. The \fB\-\-start\fP and
\fB\-\-length\fP options allows a region of any size to be placed at any

View File

@@ -25,6 +25,8 @@ lvchange \(em change attributes of a logical volume
.IR AllocationPolicy ]
.RB [ \-A | \-\-autobackup
.RB { y | n }]
.RB [ \-\-rebuild
.IR PhysicalVolume ]
.RB [ \-\-cachemode
.RB { passthrough | writeback | writethrough }]
.RB [ \-\-cachepolicy
@@ -326,6 +328,31 @@ immediately poll a logical volume when it is activated, use
\fB\-\-poll n\fP to defer and then \fB\-\-poll y\fP to restart the process.
.
.HP
.BR \-\- [ raid ] rebuild
.BR \fIPhysicalVolume
.br
Option can be repeated multiple times.
Selects PhysicalVolume(s) to be rebuild in a RaidLV.
Use this option instead of
.BR \-\-resync
or
.BR \-\- [ raid ] syncaction
\fBrepair\fP in case the PVs with corrupted data are known and their data
should be reconstructed rather than reconstructing default (rotating) data.
.br
E.g. in a raid1 mirror, the master leg on /dev/sda may hold corrupt data due
to a known transient disk error, thus
.br
\fBlvchange --rebuild /dev/sda LV\fP
.br
will request the master leg to be rebuild rather than rebuilding
all other legs from the master.
On a raid5 with rotating data and parity
.br
\fBlvchange --rebuild /dev/sda LV\fP
.br
will rebuild all data and parity blocks in the stripe on /dev/sda.
.HP
.BR \-\- [ raid ] maxrecoveryrate
.BR \fIRate [ b | B | s | S | k | K | m | M | g | G ]
.br

View File

@@ -452,6 +452,12 @@ Convert RaidLV to use a different raid level.
\[bu]
Required options depend on the raid level.
.B lvconvert \-\-type mirror
VG/RaidLV
.br
\[bu]
Convert RaidLV to type mirror.
.B lvconvert \-\-type striped
VG/RaidLV
.br
@@ -605,6 +611,9 @@ VG/ThinPoolLV
Convert the data portion of ThinPoolLV to type cache.
.br
\[bu]
Requires \-\-cachepool to specify the cache pool to use.
.br
\[bu]
Operates on the data sub LV of the thin pool LV.
.br
\[bu]
@@ -799,6 +808,8 @@ Specifies the number mirror images in addition to the original LV image,
e.g. \fB\-\-mirrors 1\fP means two copies of the data, the original and
one mirror image.
The current maximum is 9 providing 10 raid1 images.
This option is required when converting an LV to a \fBraid1\fP or
\fBmirror\fP LV.

View File

@@ -381,10 +381,11 @@ would result in a mirror with two-sides; that is,
a linear volume plus one copy.
Specifying the optional argument \fB\-\-nosync\fP will cause the creation
of the mirror to skip the initial resynchronization. Any data written
afterwards will be mirrored, but the original contents will not be
copied. This is useful for skipping a potentially long and resource
intensive initial sync of an empty device.
of the mirror LV to skip the initial resynchronization. Any data written
afterwards will be mirrored, but the original contents will not be copied.
This is useful for skipping a potentially long and resource intensive initial
sync of an empty mirrored RaidLV.
There are two implementations of mirroring which can be used and correspond
to the "\fIraid1\fP" and "\fImirror\fP" segment types.
@@ -398,6 +399,9 @@ to configure default mirror segment type.
The options
\fB\-\-mirrorlog\fP and \fB\-\-corelog\fP apply
to the legacy "\fImirror\fP" segment type only.
Note the current maxima for mirrors are 7 for "mirror" providing
8 mirror legs and 9 for "raid1" providing 10 legs.
.
.HP
.BR \-\-mirrorlog
@@ -440,7 +444,21 @@ Without this option a default name of "lvol#" will be generated where
.HP
.BR \-\-nosync
.br
Causes the creation of the mirror to skip the initial resynchronization.
Causes the creation of mirror, raid1, raid4, raid5 and raid10 to skip the
initial resynchronization. In case of mirror, raid1 and raid10, any data
written afterwards will be mirrored, but the original contents will not be
copied. In case of raid4 and raid5, no parity blocks will be written,
though any data written afterwards will cause parity blocks to be stored.
.br
This is useful for skipping a potentially long and resource intensive initial
sync of an empty mirror/raid1/raid4/raid5 and raid10 LV.
.br
This option is not valid for raid6, because raid6 relies on proper parity
(P and Q Syndromes) being created during initial synchronization in order
to reconstruct proper user date in case of device failures.
raid0 and raid0_meta don't provide any data copies or parity support
and thus don't support initial resynchronization.
.
.HP
.BR \-\-noudevsync
@@ -618,15 +636,21 @@ section of \fBlvm.conf (5)\fP or add
\fB\-\-config allocation/raid_stripe_all_devices=1\fP
.br
to the command.
.br
Note the current limitation of 8 stripes total in any RaidLV including parity devices.
Note the current maxima for stripes depend on the created RAID type.
For raid10, the maximum of stripes is 32,
for raid0, it is 64,
for raid4/5, it is 63
and for raid6 it is 62.
See the \fB\-\-nosync\fP option to optionally avoid initial syncrhonization of RaidLVs.
Two implementations of basic striping are available in the kernel.
The original device-mapper implementation is the default and should
normally be used. The alternative implementation using MD, available
since version 1.7 of the RAID device-mapper kernel target (kernel
version 4.2) is provided to facilitate the development of new RAID
features. It may be accessed with \fB--type raid0\fP, but is best
features. It may be accessed with \fB--type raid0[_meta]\fP, but is best
avoided at present because of assorted restrictions on resizing and converting
such devices.
.HP

145
man/lvm-fullreport.8.in Normal file
View File

@@ -0,0 +1,145 @@
.TH LVM-FULLREPORT 8 "LVM TOOLS #VERSION#" "Red Hat, Inc" \" -*- nroff -*-
.SH NAME
lvm fullreport \(em Report information about PVs, PV segments, VGs, LVs and LV segments, all at once for each VG.
.SH SYNOPSIS
.B lvm fullreport
.RB [ \-a | \-\-all ]
.RB [ \-\-aligned ]
.RB [ \-\-binary ]
.RB [ \-\-commandprofile
.IR ProfileName ]
.RB [[ \-\-configreport
.IR ReportName ]
.RB [ \-o | \-\-options
.RI [ + | \- | # ] Field1 [, Field2 ...]
.RB [ \-O | \-\-sort
.RI [ + | \- ] Key1 [, Key2 ...]]
.RB [ \-S | \-\-select
.IR Selection ]
.RB ...]
.RB [ \-d | \-\-debug ]
.RB [ \-h | \-? | \-\-help ]
.RB [ \-\-ignorelockingfailure ]
.RB [ \-\-ignoreskippedcluster ]
.RB [ \-\-logonly ]
.RB [ \-\-nameprefixes ]
.RB [ \-\-noheadings ]
.RB [ \-\-nosuffix ]
.RB [ \-P | \-\-partial ]
.RB [ \-\-reportformat
.RB { basic | json }]
.RB [ \-\-rows ]
.RB [ \-\-separator
.IR Separator ]
.RB [ \-\-unbuffered ]
.RB [ \-\-units
.IR hHbBsSkKmMgGtTpPeE ]
.RB [ \-\-unquoted ]
.RB [ \-v | \-\-verbose ]
.RB [ \-\-version ]
.RI [ VolumeGroupName
.RI [ VolumeGroupName ...]]
.SH DESCRIPTION
lvm fullreport produces formatted output about PVs, PV segments, VGs, LVs
and LV segments, all at once for each VG and guarded by per-VG lock
for consistency.
.SH OPTIONS
See \fBlvm\fP(8) for common options.
.TP
.B \-\-all
Include information in the output about internal Logical Volumes that
are components of normally-accessible Logical Volumes, such as mirrors,
but which are not independently accessible (e.g. not mountable).
The names of such Logical Volumes are enclosed within square brackets
in the output. For example, after creating a mirror using
.B lvcreate -m1 \-\-mirrorlog disk
, this option will reveal three internal Logical
Volumes, with suffixes mimage_0, mimage_1, and mlog.
.TP
.B \-\-aligned
Use with \fB\-\-separator\fP to align the output columns.
.TP
.B \-\-binary
Use binary values "0" or "1" instead of descriptive literal values
for columns that have exactly two valid values to report (not counting
the "unknown" value which denotes that the value could not be determined).
.TP
.B \-\-configreport \fI ReportName
Make any subsequent \fB\-o, \-\-options\fP, \fB\-O, \-\-sort\fP or
\fB\-S, \-\-select\fP to apply for \fIReportName\fP where \fIReportName\fP
is 'pv' for PV subreport, 'pvseg' for PV segment subreport, 'vg' for
VG subreport, 'lv' for LV subreport, 'seg' for LV segment subreport or 'log'
for log report. If \fB\-\-configreport\fP option is not used to identify a
report, then all command's subreports are assumed except log report. The log
report is available only if enabled by \fBlog/report_command_log\fP
\fBlvm.conf\fP(5) setting or if \fB\-\-logonly\fP option is used.
.TP
.B \-\-logonly
Suppress the main report itself and display only log report on output.
.TP
.B \-\-nameprefixes
Add an "LVM2_" prefix plus the field name to the output. Useful
with \fB\-\-noheadings\fP to produce a list of field=value pairs that can
be used to set environment variables (for example, in \fBudev\fP(7) rules).
.TP
.B \-\-noheadings
Suppress the headings line that is normally the first line of output.
Useful if grepping the output.
.TP
.B \-\-nosuffix
Suppress the suffix on output sizes. Use with \fB\-\-units\fP
(except h and H) if processing the output.
.TP
.BR \-o ", " \-\-options
Comma-separated ordered list of columns.
.IP
Precede the list with '\fI+\fP' to append to the current list
of columns, '\fI-\fP' to remove from the current list of columns
or '\fI#\fP' to compact given columns. The \fI\-o\fP option can
be repeated, providing several lists. These lists are evaluated
from left to right.
.IP
For the list of columns, see \fBpvs\fP(8), \fBvgs\fP(8),
\fBlvs\fP(8) man page or check \fBpvs\fP, \fBvgs\fP, \fBlvs -o help\fP
output.
.TP
.BR \-O ", " \-\-sort
Comma-separated ordered list of columns to sort by. Replaces the default
selection. Precede any column with '\fI\-\fP' for a reverse sort on that
column.
.TP
.B \-\-rows
Output columns as rows.
.TP
.BR \-S ", " \-\-select " " \fISelection
Display only rows that match Selection criteria. All rows are displayed with
the additional "selected" column (\fB-o selected\fP) showing 1 if the row
matches the Selection and 0 otherwise. The Selection criteria are defined
by specifying column names and their valid values (that can include reserved
values) while making use of supported comparison operators. See \fBlvm\fP(8)
and \fB\-S\fP, \fB\-\-select\fP description for more detailed information
about constructing the Selection criteria. As a quick help and to see full
list of column names that can be used in Selection including the list of
reserved values and the set of supported selection operators, check the
output of \fBpvs\fP, \fBvgs\fP, \fBlvs -S help\fP command.
.TP
.B \-\-separator \fISeparator
String to use to separate each column. Useful if grepping the output.
.TP
.B \-\-unbuffered
Produce output immediately without sorting or aligning the columns properly.
.TP
.B \-\-units \fIhHbBsSkKmMgGtTpPeE
All sizes are output in these units: (h)uman-readable, (b)ytes, (s)ectors,
(k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes.
Capitalise to use multiples of 1000 (S.I.) instead of 1024. Can also specify
custom units e.g. \-\-units 3M
.TP
.B \-\-unquoted
When used with \fB\-\-nameprefixes\fP, output values in the field=value
pairs are not quoted.
.SH SEE ALSO
.BR lvm (8),
.BR pvs (8),
.BR vgs (8),
.BR lvs (8)

View File

@@ -65,6 +65,10 @@ The same as \fBlvmconfig\fP(8) below.
.B formats
Display recognised metadata formats.
.TP
.B fullreport
Report information about PVs, PV segments, VGs, LVs and LV segments,
all at once.
.TP
.B help
Display the help text.
.TP
@@ -748,6 +752,15 @@ All tools return a status code of zero on success or non-zero on failure.
Directory containing \fI.lvm_history\fP if the internal readline
shell is invoked.
.TP
.B LVM_OUT_FD
File descriptor to use for common output from LVM commands.
.TP
.B LVM_ERR_FD
File descriptor to use for error output from LVM commands.
.TP
.B LVM_REPORT_FD
File descriptor to use for report output from LVM commands.
.TP
.B LVM_COMMAND_PROFILE
Name of default command profile to use for LVM commands. This profile
is overriden by direct use of \fB\-\-commandprofile\fP command line option.

View File

@@ -19,35 +19,45 @@ lvmetad \(em LVM metadata cache daemon
.SH DESCRIPTION
The lvmetad daemon caches LVM metadata, so that LVM commands can read
metadata without scanning disks.
The lvmetad daemon caches LVM metadata so that LVM commands can read
metadata from the cache rather than scanning disks. This can be an
advantage because scanning disks is time consuming and may interfere with
the normal work of the system. lvmetad can be a disadvantage when disk
event notifications from the system are unreliable.
Metadata caching can be an advantage because scanning disks is time
consuming and may interfere with the normal work of the system and disks.
lvmetad does not read metadata from disks itself. Instead, it relies on
an LVM command, like pvscan \-\-cache, to read metadata from disks and
send it to lvmetad to be cached.
lvmetad does not read metadata from disks itself. The 'pvscan \-\-cache'
command scans disks, reads the LVM metadata and sends it to lvmetad.
New LVM disks that appear on the system must be scanned by pvscan before
lvmetad knows about them. If lvmetad does not know about a disk, then LVM
New LVM disks that appear on the system must be scanned before lvmetad
knows about them. If lvmetad does not know about a disk, then LVM
commands using lvmetad will also not know about it. When disks are added
or removed from the system, lvmetad must be updated.
lvmetad is usually combined with event-based system services that
automatically run pvscan \-\-cache on new disks. This way, the lvmetad
cache is automatically updated with metadata from new disks when they
lvmetad is usually combined with event\-based system services that
automatically run pvscan \-\-cache on disks added or removed. This way,
the cache is automatically updated with metadata from new disks when they
appear. LVM udev rules and systemd services implement this automation.
Automatic scanning is usually combined with automatic activation. For
more information, see
.BR pvscan (8).
If lvmetad is started or restarted after disks have been added to the
system, or if the global_filter has changed, the cache must be updated by
running 'pvscan \-\-cache'.
system, or if the global_filter has changed, the cache must be updated.
This can be done by running pvscan \-\-cache, or it will be done
automatically by the next LVM command that's run.
When lvmetad is not used, LVM commands revert to scanning disks for LVM
metadata.
In some cases, lvmetad will be temporarily disabled while it continues
running. In this state, LVM commands will ignore the lvmetad cache and
revert to scanning disks. A warning will also be printed which includes
the reason why lvmetad is not being used. The most common reason is the
existence of duplicate PVs (lvmetad cannot cache data for duplicate PVs.)
Once duplicates have been resolved, the lvmetad cache is can be updated
with pvscan \-\-cache and commands will return to using the cache.
Use of lvmetad is enabled/disabled by:
.br
.BR lvm.conf (5)

View File

@@ -71,7 +71,7 @@ the "unknown" value which denotes that the value could not be determined).
.B \-\-configreport \fI ReportName
Make any subsequent \fB\-o, \-\-options\fP, \fB\-O, \-\-sort\fP or
\fB\-S, \-\-select\fP to apply for \fIReportName\fP where \fIReportName\fP
is either 'lvs' for command's main report or 'log' for log report.
is either 'lv' for command's main report or 'log' for log report.
If \fB\-\-configreport\fP option is not used to identify a report, then
command's main report is assumed. The log report is available only if
enabled by \fBlog/report_command_log\fP \fBlvm.conf\fP(5) setting or

View File

@@ -60,7 +60,7 @@ the "unknown" value which denotes that the value could not be determined).
.B \-\-configreport \fI ReportName
Make any subsequent \fB\-o, \-\-options\fP, \fB\-O, \-\-sort\fP or
\fB\-S, \-\-select\fP to apply for \fIReportName\fP where \fIReportName\fP
is either 'pvs' for command's main report or 'log' for log report.
is either 'pv' for command's main report or 'log' for log report.
If \fB\-\-configreport\fP option is not used to identify a report, then
command's main report is assumed. The log report is available only if
enabled by \fBlog/report_command_log\fP \fBlvm.conf\fP(5) setting or

View File

@@ -79,7 +79,7 @@ When given specific device name arguments, pvscan \-\-cache will only
read the named devices.
.IP \[bu] 2
LVM udev rules and systemd services are used to intiate automatic device
LVM udev rules and systemd services are used to initiate automatic device
scanning.
.IP \[bu] 2
@@ -99,8 +99,8 @@ if the global_filter has changed, then all devices must be rescanned
for metadata with the command pvscan \-\-cache.
.IP \[bu] 2
lvmetad ignores older metadata formats, e.g. lvm1, and should not be
used if they exist.
lvmetad does not cache older metadata formats, e.g. lvm1, and will
be temporarily disabled if they are seen.
.IP \[bu] 2
To notify lvmetad about a device that is no longer present, the major and

View File

@@ -58,7 +58,7 @@ the "unknown" value which denotes that the value could not be determined).
.B \-\-configreport \fI ReportName
Make any subsequent \fB\-o, \-\-options\fP, \fB\-O, \-\-sort\fP or
\fB\-S, \-\-select\fP to apply for \fIReportName\fP where \fIReportName\fP
is either 'vgs' for command's main report or 'log' for log report.
is either 'vg' for command's main report or 'log' for log report.
If \fB\-\-configreport\fP option is not used to identify a report, then
command's main report is assumed. The log report is available only if
enabled by \fBlog/report_command_log\fP \fBlvm.conf\fP(5) setting or

View File

@@ -115,6 +115,7 @@ fi
%{_mandir}/man8/lvmconfig.8.gz
%{_mandir}/man8/lvmdiskscan.8.gz
%{_mandir}/man8/lvmdump.8.gz
%{_mandir}/man8/lvm-fullreport.8.gz
%{_mandir}/man8/lvmsadc.8.gz
%{_mandir}/man8/lvmsar.8.gz
%{_mandir}/man8/lvreduce.8.gz
@@ -179,6 +180,7 @@ fi
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/thin-performance.profile
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/cache-mq.profile
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/cache-smq.profile
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/lvmdbusd.profile
%dir %{_sysconfdir}/lvm/backup
%dir %{_sysconfdir}/lvm/cache
%dir %{_sysconfdir}/lvm/archive

View File

@@ -1265,6 +1265,12 @@ wait_for_sync() {
return 1
}
# aux check_status_chars $vg $lv "Aaaaa"
check_status_chars() {
[ `dmsetup status $1-$2|awk '{print $6}'` = $3 ] && return
return 1
}
# Check if tests are running on 64bit architecture
can_use_16T() {
test "$(getconf LONG_BIT)" -eq 64

View File

@@ -97,7 +97,15 @@ test_lvconvert() {
alloc="--alloc anywhere"
fi
lvconvert --type mirror -m $finish_count --mirrorlog $finish_log_type \
# --mirrorlog is invalid with -m0
if [ "$finish_count" -eq 0 ]; then
mirrorlog=""
finish_log_type=""
else
mirrorlog="--mirrorlog"
fi
lvconvert --type mirror -m $finish_count $mirrorlog $finish_log_type \
$vg/$lv1 $alloc
test $active || lvchange -aey $vg/$lv1

View File

@@ -0,0 +1,126 @@
#!/bin/sh
# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
SKIP_WITH_LVMLOCKD=1
SKIP_WITH_LVMPOLLD=1
. lib/inittest
aux have_raid 1 9 0 || skip
aux prepare_vg 9 288
# Delay 1st leg so that rebuilding status characters
# can be read before resync finished too quick.
# aux delay_dev "$dev1" 0 1
# Create 3-way mirror
lvcreate --yes --type mirror -m 2 -L 256M -n $lv1 $vg
check lv_field $vg/$lv1 segtype "mirror"
check lv_field $vg/$lv1 stripes 3
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
aux wait_for_sync $vg $lv1
fsck -fn /dev/mapper/$vg-$lv1
# Convert 3-way to 4-way mirror
lvconvert -m 3 $vg/$lv1
check lv_field $vg/$lv1 segtype "mirror"
check lv_field $vg/$lv1 stripes 4
fsck -fn /dev/mapper/$vg-$lv1
aux wait_for_sync $vg $lv1
fsck -fn /dev/mapper/$vg-$lv1
# Takeover 4-way mirror to raid1
lvconvert --yes --type raid1 $vg/$lv1
check lv_field $vg/$lv1 segtype "raid1"
check lv_field $vg/$lv1 stripes 4
fsck -fn /dev/mapper/$vg-$lv1
## Convert 4-way raid1 to 5-way
lvconvert -m 4 $vg/$lv1
check lv_field $vg/$lv1 segtype "raid1"
check lv_field $vg/$lv1 stripes 5
fsck -fn /dev/mapper/$vg-$lv1
aux wait_for_sync $vg $lv1
fsck -fn /dev/mapper/$vg-$lv1
# FIXME: enable once lvconvert rejects early
## Try converting 4-way raid1 to 9-way
#not lvconvert --yes -m 8 $vg/$lv1
#check lv_field $vg/$lv1 segtype "raid1"
#check lv_field $vg/$lv1 stripes 4
# Convert 5-way raid1 to 2-way
lvconvert --yes -m 1 $vg/$lv1
lvs $vg/$lv1
dmsetup status $vg-$lv1
dmsetup table $vg-$lv1
check lv_field $vg/$lv1 segtype "raid1"
check lv_field $vg/$lv1 stripes 2
fsck -fn /dev/mapper/$vg-$lv1
# Convert 2-way raid1 to mirror
lvconvert --yes --type mirror $vg/$lv1
check lv_field $vg/$lv1 segtype "mirror"
check lv_field $vg/$lv1 stripes 2
aux wait_for_sync $vg $lv1
fsck -fn /dev/mapper/$vg-$lv1
aux wait_for_sync $vg $lv1
# Clean up
lvremove --yes $vg/$lv1
# Create 3-way raid0
lvcreate -y --type raid0 -i 3 -L 256M -n $lv1 $vg
check lv_field $vg/$lv1 segtype "raid0"
check lv_field $vg/$lv1 stripes 3
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
fsck -fn /dev/mapper/$vg-$lv1
# Convert raid0 -> raid4
lvconvert -y --ty raid4 $vg/$lv1
lvchange --refresh $vg/$lv1
check lv_field $vg/$lv1 segtype "raid4"
check lv_field $vg/$lv1 stripes 4
fsck -fn /dev/mapper/$vg-$lv1
aux wait_for_sync $vg $lv1
fsck -fn /dev/mapper/$vg-$lv1
# Convert raid4 -> raid0_meta
lvconvert -y --ty raid0_meta $vg/$lv1
check lv_field $vg/$lv1 segtype "raid0_meta"
check lv_field $vg/$lv1 stripes 3
fsck -fn /dev/mapper/$vg-$lv1
# Convert raid0_meta -> raid4
lvconvert -y --ty raid4 $vg/$lv1
fsck -fn /dev/mapper/$vg-$lv1
check lv_field $vg/$lv1 segtype "raid4"
check lv_field $vg/$lv1 stripes 4
aux wait_for_sync $vg $lv1
fsck -fn /dev/mapper/$vg-$lv1
# Convert raid4 -> raid0
lvconvert -y --ty raid0 $vg/$lv1
check lv_field $vg/$lv1 segtype "raid0"
check lv_field $vg/$lv1 stripes 3
fsck -fn /dev/mapper/$vg-$lv1
# Convert raid0 -> raid4
lvconvert -y --ty raid4 $vg/$lv1
lvchange --refresh $vg/$lv1
check lv_field $vg/$lv1 segtype "raid4"
check lv_field $vg/$lv1 stripes 4
fsck -fn /dev/mapper/$vg-$lv1
aux wait_for_sync $vg $lv1
fsck -fn /dev/mapper/$vg-$lv1
vgremove -ff $vg

View File

@@ -1,5 +1,5 @@
#!/bin/sh
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
# Copyright (C) 2012,2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
@@ -21,13 +21,13 @@ aux can_use_16T || skip
aux have_raid 1 3 0 || skip
aux prepare_vg 5
aux prepare_vg 5 32
lvcreate --type snapshot -s -l 20%FREE -n $lv1 $vg --virtualsize 256T
lvcreate --type snapshot -s -l 20%FREE -n $lv2 $vg --virtualsize 256T
lvcreate --type snapshot -s -l 20%FREE -n $lv3 $vg --virtualsize 256T
lvcreate --type snapshot -s -l 20%FREE -n $lv4 $vg --virtualsize 256T
lvcreate --type snapshot -s -l 20%FREE -n $lv5 $vg --virtualsize 256T
# Fake 5 PiB volume group $vg1 via snapshot LVs
for device in "$lv1" "$lv2" "$lv3" "$lv4" "$lv5"
do
lvcreate --type snapshot -s -l 20%FREE -n $device $vg --virtualsize 1P
done
#FIXME this should be 1024T
#check lv_field $vg/$lv size "128.00m"
@@ -35,43 +35,79 @@ lvcreate --type snapshot -s -l 20%FREE -n $lv5 $vg --virtualsize 256T
aux extend_filter_LVMTEST
pvcreate "$DM_DEV_DIR"/$vg/$lv[12345]
vgcreate $vg1 "$DM_DEV_DIR"/$vg/$lv[12345]
vgcreate -s 2M $vg1 "$DM_DEV_DIR"/$vg/$lv[12345]
# Delay PVs so that resynchronization doesn't fill
# the snapshots before removal of the RaidLV
for device in "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
do
aux delay_dev "$device" 0 1
done
# bz837927 START
#
# Create large RAID LVs
#
# We need '--nosync' or our virtual devices won't work
# 200 TiB raid1
lvcreate --type raid1 -m 1 -L 200T -n $lv1 $vg1 --nosync
check lv_field $vg1/$lv1 size "200.00t"
aux check_status_chars $vg1 $lv1 "AA"
lvremove -ff $vg1
for segtype in raid4 raid5 raid6; do
# 1 PiB raid1
lvcreate --type raid1 -m 1 -L 1P -n $lv1 $vg1 --nosync
check lv_field $vg1/$lv1 size "1.00p"
aux check_status_chars $vg1 $lv1 "AA"
lvremove -ff $vg1
# 750 TiB raid4/5
for segtype in raid4 raid5; do
lvcreate --type $segtype -i 3 -L 750T -n $lv1 $vg1 --nosync
check lv_field $vg1/$lv1 size "750.00t"
aux check_status_chars $vg1 $lv1 "AAAA"
lvremove -ff $vg1
done
#
# Convert large linear to RAID1 (belong in different test script?)
#
lvcreate -aey -L 200T -n $lv1 $vg1
# Need to deactivate or the up-convert will start sync'ing
lvchange -an $vg1/$lv1
lvconvert --type raid1 -m 1 $vg1/$lv1
check lv_field $vg1/$lv1 size "200.00t"
# 750 TiB raid6 (with --nosync rejection check)
[ aux have_raid 1 9 0 ] && not lvcreate --type raid6 -i 3 -L 750T -n $lv1 $vg1 --nosync
lvcreate --type raid6 -i 3 -L 750T -n $lv1 $vg1
check lv_field $vg1/$lv1 size "750.00t"
aux check_status_chars $vg1 $lv1 "aaaaa"
lvremove -ff $vg1
# 1 PiB raid6 (with --nosync rejection check), then extend up to 2 PiB
[ aux have_raid 1 9 0 ] && not lvcreate --type raid6 -i 3 -L -L 1P -n $lv1 $vg1 --nosync
lvcreate --type raid6 -i 3 -L 1P -n $lv1 $vg1
check lv_field $vg1/$lv1 size "1.00p"
aux check_status_chars $vg1 $lv1 "aaaaa"
lvextend -L +1P $vg1/$lv1
check lv_field $vg1/$lv1 size "2.00p"
aux check_status_chars $vg1 $lv1 "aaaaa"
lvremove -ff $vg1
#
# Extending large RAID LV (belong in different script?)
# Convert large 200 TiB linear to RAID1 (belong in different test script?)
#
lvcreate -aey -L 200T -n $lv1 $vg1
lvconvert --type raid1 -m 1 $vg1/$lv1
check lv_field $vg1/$lv1 size "200.00t"
aux check_status_chars $vg1 $lv1 "aa"
lvremove -ff $vg1
#
# Extending large 200 TiB RAID LV to 400 TiB (belong in different script?)
#
lvcreate --type raid1 -m 1 -L 200T -n $lv1 $vg1 --nosync
check lv_field $vg1/$lv1 size "200.00t"
aux check_status_chars $vg1 $lv1 "AA"
lvextend -L +200T $vg1/$lv1
check lv_field $vg1/$lv1 size "400.00t"
aux check_status_chars $vg1 $lv1 "AA"
lvremove -ff $vg1
# bz837927 END
vgremove -ff $vg1
vgremove -ff $vg

View File

@@ -1,5 +1,5 @@
#!/bin/sh
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
# Copyright (C) 2012,2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
@@ -22,24 +22,31 @@ aux have_raid 1 3 0 || skip
aux prepare_vg 5
lvcreate --type snapshot -s -l 20%FREE -n $lv1 $vg --virtualsize 256T
lvcreate --type snapshot -s -l 20%FREE -n $lv2 $vg --virtualsize 256T
lvcreate --type snapshot -s -l 20%FREE -n $lv3 $vg --virtualsize 256T
lvcreate --type snapshot -s -l 20%FREE -n $lv4 $vg --virtualsize 256T
lvcreate --type snapshot -s -l 20%FREE -n $lv5 $vg --virtualsize 256T
# Fake ~2.5PiB volume group $vg1 via snapshot LVs
for device in "$lv1" "$lv2" "$lv3" "$lv4" "$lv5"
do
lvcreate --type snapshot -s -l 20%FREE -n $device $vg --virtualsize 520T
done
aux extend_filter_LVMTEST
pvcreate "$DM_DEV_DIR"/$vg/$lv[12345]
vgcreate $vg1 "$DM_DEV_DIR"/$vg/$lv[12345]
#
# Create large RAID LVs
# Create and extend large RAID10 LV
#
# We need '--nosync' or our virtual devices won't work
lvcreate --type raid10 -m 1 -i 2 -L 200T -n $lv1 $vg1 --nosync
check lv_field $vg1/$lv1 size "200.00t"
vgremove -ff $vg1
lvextend -L +200T $vg1/$lv1
check lv_field $vg1/$lv1 size "400.00t"
lvextend -L +100T $vg1/$lv1
check lv_field $vg1/$lv1 size "500.00t"
lvextend -L 1P $vg1/$lv1
check lv_field $vg1/$lv1 size "1.00p"
vgremove -ff $vg1
vgremove -ff $vg

View File

@@ -0,0 +1,85 @@
#!/bin/sh
# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
SKIP_WITH_LVMLOCKD=1
SKIP_WITH_LVMPOLLD=1
. lib/inittest
aux have_raid 1 7 0 || skip
aux prepare_vg 6
# Delay 1st leg so that rebuilding status characters
# can be read before resync finished too quick.
aux delay_dev "$dev1" 0 1
# raid0/raid0_meta don't support resynchronization
for r in raid0 raid0_meta
do
lvcreate --yes --type raid0 -i 3 -l 1 -n $lv1 $vg
aux check_status_chars $vg $lv1 "AAA"
lvremove --yes $vg/$lv1
done
# raid1 supports resynchronization
lvcreate --yes --type raid1 -m 2 -l 1 -n $lv1 $vg
aux check_status_chars $vg $lv1 "aaa"
aux wait_for_sync $vg $lv1
aux check_status_chars $vg $lv1 "AAA"
lvremove --yes $vg/$lv1
# raid1 supports --nosync
lvcreate --yes --type raid1 --nosync -m 2 -l 1 -n $lv1 $vg
aux check_status_chars $vg $lv1 "AAA"
lvremove --yes $vg/$lv1
for r in raid4 raid5
do
# raid4/5 support resynchronization
lvcreate --yes --type $r -i 3 -l 1 -n $lv1 $vg
aux check_status_chars $vg $lv1 "aaaa"
aux wait_for_sync $vg $lv1
aux check_status_chars $vg $lv1 "AAAA"
lvremove --yes $vg/$lv1
# raid4/5 support --nosync
lvcreate --yes --type $r --nosync -i 3 -l 1 -n $lv1 $vg
aux check_status_chars $vg $lv1 "AAAA"
lvremove --yes $vg/$lv1
done
# raid6 supports resynchronization
lvcreate --yes --type raid6 -i 3 -l 1 -n $lv1 $vg
aux check_status_chars $vg $lv1 "aaaaa"
aux wait_for_sync $vg $lv1
aux check_status_chars $vg $lv1 "AAAAA"
lvremove --yes $vg/$lv1
# raid6 rejects --nosync; it has to initialize P- and Q-Syndromes
not lvcreate --yes --type raid6 --nosync -i 3 -l 1 -n $lv1 $vg
# raid10 supports resynchronization
lvcreate --yes --type raid10 -m 1 -i 3 -l 1 -n $lv1 $vg
aux check_status_chars $vg $lv1 "aaaaaa"
aux wait_for_sync $vg $lv1
aux check_status_chars $vg $lv1 "AAAAAA"
aux wait_for_sync $vg $lv1
lvremove --yes $vg/$lv1
# raid10 supports --nosync
lvcreate --yes --type raid10 --nosync -m 1 -i 3 -l 1 -n $lv1 $vg
aux check_status_chars $vg $lv1 "AAAAAA"
aux wait_for_sync $vg $lv1
lvremove --yes $vg/$lv1
vgremove -ff $vg

View File

@@ -53,6 +53,15 @@ lvcreate -l 4 --type raid10 -i 2 -m 1 -n $lv1 $vg \
check lv_tree_on $vg ${lv1}_foo "$dev1"
check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
aux mkdev_md5sum $vg $lv1
# Check collocation of SubLVs is prohibited
not pvmove $mode -n ${lv1}_rimage_0 "$dev1" "$dev2"
check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
not pvmove $mode -n ${lv1}_rimage_1 "$dev2" "$dev1"
check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
not pvmove $mode -n ${lv1}_rmeta_0 "$dev1" "$dev3"
check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
pvmove $mode "$dev1" "$dev5"
check lv_tree_on $vg ${lv1}_foo "$dev5"
check lv_tree_on $vg $lv1 "$dev2" "$dev3" "$dev4" "$dev5"

View File

@@ -88,6 +88,7 @@ arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0, 0)
arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", yes_no_arg, 0, 0)
arg(profile_ARG, '\0', "profile", string_arg, 0, 0)
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", int_arg, 0, 0)
arg(raidrebuild_ARG, '\0', "raidrebuild", string_arg, ARG_GROUPABLE, 0)
arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", size_kb_arg, 0, 0)
arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", size_kb_arg, 0, 0)
arg(raidsyncaction_ARG, '\0', "raidsyncaction", string_arg, 0, 0)
@@ -96,6 +97,7 @@ arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_arg, ARG_GROUPABLE, 0)
arg(readonly_ARG, '\0', "readonly", NULL, 0, 0)
arg(refresh_ARG, '\0', "refresh", NULL, 0, 0)
arg(removemissing_ARG, '\0', "removemissing", NULL, 0, 0)
arg(rebuild_ARG, '\0', "rebuild", string_arg, ARG_GROUPABLE, 0)
arg(repair_ARG, '\0', "repair", NULL, 0, 0)
arg(replace_ARG, '\0', "replace", string_arg, ARG_GROUPABLE, 0)
arg(reportformat_ARG, '\0', "reportformat", string_arg, 0, 0)

View File

@@ -195,6 +195,7 @@ xx(lvchange,
"\t[--activationmode {complete|degraded|partial}"
"\t[--addtag <Tag>]\n"
"\t[--alloc <AllocationPolicy>]\n"
"\t[--rebuild PhysicalVolume]\n"
"\t[-C|--contiguous {y|n}]\n"
"\t[--cachemode <CacheMode>]\n"
"\t[--cachepolicy <policyname>] [--cachesettings <parameter=value>]\n"
@@ -244,10 +245,10 @@ xx(lvchange,
ignoreskippedcluster_ARG, major_ARG, metadataprofile_ARG, minor_ARG,
monitor_ARG, minrecoveryrate_ARG, maxrecoveryrate_ARG, noudevsync_ARG,
partial_ARG, permission_ARG, persistent_ARG, poll_ARG,
raidminrecoveryrate_ARG, raidmaxrecoveryrate_ARG, raidsyncaction_ARG,
raidwritebehind_ARG, raidwritemostly_ARG, readahead_ARG, reportformat_ARG,
resync_ARG, refresh_ARG, select_ARG, setactivationskip_ARG, syncaction_ARG,
sysinit_ARG, test_ARG, writebehind_ARG, writemostly_ARG, zero_ARG)
raidrebuild_ARG, raidminrecoveryrate_ARG, raidmaxrecoveryrate_ARG,
raidsyncaction_ARG, raidwritebehind_ARG, raidwritemostly_ARG, readahead_ARG,
reportformat_ARG, rebuild_ARG, resync_ARG, refresh_ARG, select_ARG, setactivationskip_ARG,
syncaction_ARG, sysinit_ARG, test_ARG, writebehind_ARG, writemostly_ARG, zero_ARG)
#define COMMON_OPTS \
"\t[--commandprofile <ProfileName>] [-d|--debug] [-h|-?|--help]\n" \
@@ -259,6 +260,7 @@ xx(lvconvert,
"lvconvert "
"[-m|--mirrors <Mirrors> [--mirrorlog {disk|core|mirrored}|--corelog]]\n"
"\t[--type <SegmentType>]\n"
"\t[--rebuild PhysicalVolume]\n"
"\t[--repair [--use-policies]]\n"
"\t[--replace PhysicalVolume]\n"
"\t[-R|--regionsize <MirrorLogRegionSize>]\n"

View File

@@ -750,6 +750,60 @@ static int _lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv, int
return 1;
}
static int _lvchange_rebuild(struct logical_volume *lv)
{
int pv_count, i = 0;
char **rebuild_pvs;
const char *tmp_str;
struct dm_list *rebuild_pvh = NULL;
struct arg_value_group_list *group;
struct volume_group *vg = lv->vg;
struct cmd_context *cmd = vg->cmd;
struct lv_segment *raid_seg = first_seg(lv);
if (!seg_is_raid(raid_seg) || seg_is_any_raid0(raid_seg)) {
log_error("--rebuild can only be used with 'raid4/5/6/10' segment types.");
return 0;
}
if (!(pv_count = arg_count(cmd, rebuild_ARG))) {
log_error("No --rebuild found!");
return 0;
}
if (!arg_is_set(cmd, yes_ARG) &&
yes_no_prompt("Do you really want to rebuild %u PVs "
"of logical volume %s [y/n]: ",
pv_count, display_lvname(lv)) == 'n') {
log_error("Logical volume %s not rebuild.",
display_lvname(lv));
return 0;
}
/* rebuild can be specified more than once */
if (!(rebuild_pvs = dm_pool_alloc(vg->vgmem, sizeof(char *) * pv_count)))
return_0;
dm_list_iterate_items(group, &cmd->arg_value_groups) {
if (!grouped_arg_is_set(group->arg_values, rebuild_ARG))
continue;
if (!(tmp_str = grouped_arg_str_value(group->arg_values,
rebuild_ARG, NULL)))
return_0;
if (!(rebuild_pvs[i++] = dm_pool_strdup(cmd->mem, tmp_str)))
return_0;
}
if (!(rebuild_pvh = create_pv_list(cmd->mem, vg,
pv_count, rebuild_pvs, 0)))
return_ECMD_FAILED;
/* Rebuild PVs listed on @rebuild_pvh */
return lv_raid_rebuild(lv, rebuild_pvh);
}
static int _lvchange_writemostly(struct logical_volume *lv)
{
int s, pv_count, i = 0;
@@ -1132,6 +1186,14 @@ static int _lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
docmds++;
}
/* rebuild selected PVs */
if (arg_is_set(cmd, rebuild_ARG)) {
if (!archive(lv->vg))
return_ECMD_FAILED;
doit += _lvchange_rebuild(lv);
docmds++;
}
/* change writemostly/writebehind */
if (arg_is_set(cmd, writemostly_ARG) || arg_is_set(cmd, writebehind_ARG)) {
if (!archive(lv->vg))
@@ -1245,6 +1307,7 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
errorwhenfull_ARG,
maxrecoveryrate_ARG,
minrecoveryrate_ARG,
rebuild_ARG,
resync_ARG,
syncaction_ARG,
writebehind_ARG,

View File

@@ -38,12 +38,10 @@
*/
struct lvconvert_params {
/* Exactly one of these options is chosen */
/* Exactly one of these 12 command categories is determined */
int merge; /* Either merge_snapshot or merge_mirror is also set */
int cache;
int corelog;
int mirrorlog;
int mirrors_supplied; /* When type_str is not set, this may be set with keep_mimages for --splitmirrors */
int keep_mimages; /* --splitmirrors */
int repair;
int replace;
int snapshot;
@@ -52,9 +50,16 @@ struct lvconvert_params {
int splitsnapshot;
int thin;
int uncache;
const char *type_str; /* When this is set, mirrors_supplied may optionally also be set */
int other_conversion; /* Everything else */
const struct segment_type *segtype;
int corelog; /* Equivalent to --mirrorlog core */
int mirrorlog; /* Only one of corelog and mirrorlog may be set */
int mirrors_supplied; /* When type_str is not set, this may be set with keep_mimages for --splitmirrors */
const char *type_str; /* When this is set, mirrors_supplied may optionally also be set */
/* Holds what you asked for based on --type or other arguments, else "" */
const struct segment_type *segtype; /* Holds what segment type you will get */
int merge_snapshot; /* merge is also set */
int merge_mirror; /* merge is also set */
@@ -79,9 +84,9 @@ struct lvconvert_params {
uint32_t mirrors;
sign_t mirrors_sign;
uint32_t keep_mimages; /* --splitmirrors */
uint32_t stripes;
uint32_t stripe_size;
uint32_t stripe_size_supplied;
uint32_t read_ahead;
cache_mode_t cache_mode; /* cache */
const char *policy_name; /* cache */
@@ -154,9 +159,9 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
}
if (!strstr((*pargv)[0], "_rimage_")) { /* Snapshot */
if (!(lp->segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_SNAPSHOT)))
return_0;
lp->type_str = SEG_TYPE_NAME_SNAPSHOT;
lp->merge_snapshot = 1;
return 1;
}
@@ -273,52 +278,22 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
return 1;
}
static int _check_conversion_type(struct cmd_context *cmd, const char *type_str)
{
if (!type_str || !*type_str)
return 1;
if (!strcmp(type_str, "mirror")) {
if (!arg_is_set(cmd, mirrors_ARG)) {
log_error("Conversions to --type mirror require -m/--mirrors");
return 0;
}
return 1;
}
/* FIXME: Check thin-pool and thin more thoroughly! */
if (!strcmp(type_str, "snapshot") || !strcmp(type_str, "linear") ||
!strcmp(type_str, "striped") ||
!strncmp(type_str, "raid", 4) ||
!strcmp(type_str, "cache-pool") || !strcmp(type_str, "cache") ||
!strcmp(type_str, "thin-pool") || !strcmp(type_str, "thin"))
return 1;
log_error("Conversion using --type %s is not supported.", type_str);
return 0;
}
/* -s/--snapshot and --type snapshot are synonyms */
static int _snapshot_type_requested(struct cmd_context *cmd, const char *type_str)
{
return (arg_is_set(cmd, snapshot_ARG) || !strcmp(type_str, "snapshot"));
return (arg_is_set(cmd, snapshot_ARG) || !strcmp(type_str, SEG_TYPE_NAME_SNAPSHOT));
}
static int _raid0_type_requested(struct cmd_context *cmd, const char *type_str)
static int _raid0_type_requested(const char *type_str)
{
return (!strcmp(type_str, "raid0") || !strcmp(type_str, "raid0_meta"));
return (!strcmp(type_str, SEG_TYPE_NAME_RAID0) || !strcmp(type_str, SEG_TYPE_NAME_RAID0_META));
}
/* mirror/raid* (1,10,4,5,6 and their variants) reshape */
static int _mirror_or_raid_type_requested(struct cmd_context *cmd, const char *type_str)
{
return (arg_is_set(cmd, mirrors_ARG) || !strcmp(type_str, "mirror") ||
(!strncmp(type_str, "raid", 4) && !_raid0_type_requested(cmd, type_str)));
}
static int _striped_type_requested(struct cmd_context *cmd, const char *type_str)
{
return (!strcmp(type_str, SEG_TYPE_NAME_STRIPED) || !strcmp(type_str, SEG_TYPE_NAME_LINEAR));
return (arg_is_set(cmd, mirrors_ARG) || !strcmp(type_str, SEG_TYPE_NAME_MIRROR) ||
(!strncmp(type_str, SEG_TYPE_NAME_RAID, 4) && !_raid0_type_requested(type_str)));
}
static int _linear_type_requested(const char *type_str)
@@ -326,35 +301,57 @@ static int _linear_type_requested(const char *type_str)
return (!strcmp(type_str, SEG_TYPE_NAME_LINEAR));
}
static int _striped_type_requested(const char *type_str)
{
return (!strcmp(type_str, SEG_TYPE_NAME_STRIPED) || _linear_type_requested(type_str));
}
static int _check_conversion_type(struct cmd_context *cmd, const char *type_str)
{
if (!type_str || !*type_str)
return 1;
/* FIXME: Check thin-pool and thin more thoroughly! */
if (!strcmp(type_str, SEG_TYPE_NAME_SNAPSHOT) || _striped_type_requested(type_str) ||
!strncmp(type_str, SEG_TYPE_NAME_RAID, 4) || !strcmp(type_str, SEG_TYPE_NAME_MIRROR) ||
!strcmp(type_str, SEG_TYPE_NAME_CACHE_POOL) || !strcmp(type_str, SEG_TYPE_NAME_CACHE) ||
!strcmp(type_str, SEG_TYPE_NAME_THIN_POOL) || !strcmp(type_str, SEG_TYPE_NAME_THIN))
return 1;
log_error("Conversion using --type %s is not supported.", type_str);
return 0;
}
static int _read_pool_params(struct cmd_context *cmd, int *pargc, char ***pargv,
struct lvconvert_params *lp)
{
int cachepool = 0;
int thinpool = 0;
struct segment_type *segtype;
if ((lp->pool_data_name = arg_str_value(cmd, cachepool_ARG, NULL))) {
if (lp->type_str[0] &&
strcmp(lp->type_str, "cache") &&
strcmp(lp->type_str, "cache-pool")) {
strcmp(lp->type_str, SEG_TYPE_NAME_CACHE) &&
strcmp(lp->type_str, SEG_TYPE_NAME_CACHE_POOL)) {
log_error("--cachepool argument is only valid with "
"the cache or cache-pool segment type.");
return 0;
}
cachepool = 1;
lp->type_str = "cache-pool";
} else if (!strcmp(lp->type_str, "cache-pool"))
lp->type_str = SEG_TYPE_NAME_CACHE_POOL;
} else if (!strcmp(lp->type_str, SEG_TYPE_NAME_CACHE_POOL))
cachepool = 1;
else if ((lp->pool_data_name = arg_str_value(cmd, thinpool_ARG, NULL))) {
if (lp->type_str[0] &&
strcmp(lp->type_str, "thin") &&
strcmp(lp->type_str, "thin-pool")) {
strcmp(lp->type_str, SEG_TYPE_NAME_THIN) &&
strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL)) {
log_error("--thinpool argument is only valid with "
"the thin or thin-pool segment type.");
return 0;
}
thinpool = 1;
lp->type_str = "thin-pool";
} else if (!strcmp(lp->type_str, "thin-pool"))
lp->type_str = SEG_TYPE_NAME_THIN_POOL;
} else if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL))
thinpool = 1;
if (lp->cache && !cachepool) {
@@ -388,10 +385,10 @@ static int _read_pool_params(struct cmd_context *cmd, int *pargc, char ***pargv,
splitmirrors_ARG, splitsnapshot_ARG, -1))
return_0;
if (!(lp->segtype = get_segtype_from_string(cmd, lp->type_str)))
if (!(segtype = get_segtype_from_string(cmd, lp->type_str)))
return_0;
if (!get_pool_params(cmd, lp->segtype, &lp->passed_args,
if (!get_pool_params(cmd, segtype, &lp->passed_args,
&lp->pool_metadata_size,
&lp->poolmetadataspare,
&lp->chunk_size, &lp->discards,
@@ -440,7 +437,7 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
lp->type_str = arg_str_value(cmd, type_ARG, "");
if (arg_is_set(cmd, type_ARG) && !_check_conversion_type(cmd, lp->type_str))
if (*lp->type_str && !_check_conversion_type(cmd, lp->type_str))
return_0;
/* If --repair, check for incompatible args. */
@@ -448,7 +445,6 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
if (arg_outside_list_is_set(cmd, "cannot be used with --repair",
repair_ARG,
alloc_ARG, usepolicies_ARG,
stripes_long_ARG, stripesize_ARG,
force_ARG, noudevsync_ARG, test_ARG,
-1))
return_0;
@@ -505,30 +501,29 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
if (arg_is_set(cmd, cache_ARG))
lp->cache = 1;
if (!strcmp(lp->type_str, "cache"))
if (!strcmp(lp->type_str, SEG_TYPE_NAME_CACHE))
lp->cache = 1;
else if (lp->cache) {
if (lp->type_str[0]) {
log_error("--cache is incompatible with --type %s", lp->type_str);
return 0;
}
lp->type_str = "cache";
lp->type_str = SEG_TYPE_NAME_CACHE;
}
if (arg_is_set(cmd, thin_ARG))
lp->thin = 1;
if (!strcmp(lp->type_str, "thin"))
if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN))
lp->thin = 1;
else if (lp->thin) {
if (lp->type_str[0]) {
log_error("--thin is incompatible with --type %s", lp->type_str);
return 0;
}
lp->type_str = "thin";
lp->type_str = SEG_TYPE_NAME_THIN;
}
/* May set lp->segtype */
if (!_read_pool_params(cmd, &argc, &argv, lp))
return_0;
@@ -594,12 +589,12 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
!lp->splitcache && !lp->split && !lp->snapshot && !lp->uncache && !lp->cache && !lp->thin &&
!lp->replace && !lp->repair && !lp->mirrorlog && !lp->corelog &&
(arg_is_set(cmd, stripes_long_ARG) || arg_is_set(cmd, stripesize_ARG)))
lp->type_str = "striped";
lp->type_str = SEG_TYPE_NAME_STRIPED;
if ((_snapshot_type_requested(cmd, lp->type_str) || lp->merge) &&
(lp->mirrorlog || _mirror_or_raid_type_requested(cmd, lp->type_str) ||
lp->repair || arg_is_set(cmd, thinpool_ARG) || _raid0_type_requested(cmd, lp->type_str) ||
_striped_type_requested(cmd, lp->type_str))) {
lp->repair || arg_is_set(cmd, thinpool_ARG) || _raid0_type_requested(lp->type_str) ||
_striped_type_requested(lp->type_str))) {
log_error("--snapshot/--type snapshot or --merge argument "
"cannot be mixed with --mirrors/--type mirror/--type raid*/--stripes/--type striped/--type linear, "
"--mirrorlog, --repair or --thinpool.");
@@ -607,8 +602,8 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
}
if ((arg_is_set(cmd, stripes_long_ARG) || arg_is_set(cmd, stripesize_ARG)) &&
!(_mirror_or_raid_type_requested(cmd, lp->type_str) || _striped_type_requested(cmd, lp->type_str) ||
_raid0_type_requested(cmd, lp->type_str) || lp->repair || arg_is_set(cmd, thinpool_ARG))) {
!(_mirror_or_raid_type_requested(cmd, lp->type_str) || _striped_type_requested(lp->type_str) ||
_raid0_type_requested(lp->type_str) || lp->repair || arg_is_set(cmd, thinpool_ARG))) {
log_error("--stripes or --stripesize argument is only valid "
"with --mirrors/--type mirror/--type raid*/--type striped/--type linear, --repair and --thinpool");
return 0;
@@ -625,6 +620,14 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
/* We should have caught all these cases already. */
if (lp->merge + lp->splitsnapshot + lp->splitcache + lp->split + lp->uncache +
lp->cache + lp->thin + lp->keep_mimages + lp->snapshot + lp->replace + lp->repair > 1) {
log_error(INTERNAL_ERROR "Unexpected combination of incompatible options selected.");
return 0;
} else
lp->other_conversion = 1;
/*
* Final checking of each case:
* lp->merge
@@ -634,9 +637,11 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
* lp->uncache
* lp->cache
* lp->thin
* lp->keep_mimages
* lp->snapshot
* lp->replace
* --type mirror|raid lp->repair lp->mirrorlog lp->corelog
* lp->repair
* --type mirror|raid lp->mirrorlog lp->corelog
* --type raid0|striped
*/
if (lp->merge) { /* Snapshot or mirror merge */
@@ -693,11 +698,7 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
}
log_verbose("Setting chunk size to %s.", display_size(cmd, lp->chunk_size));
if (!(lp->segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_SNAPSHOT)))
return_0;
lp->zero = (lp->segtype->flags & SEG_CANNOT_BE_ZEROED)
? 0 : arg_int_value(cmd, zero_ARG, 1);
lp->type_str = SEG_TYPE_NAME_SNAPSHOT;
} else if (lp->replace) { /* RAID device replacement */
lp->replace_pv_count = arg_count(cmd, replace_ARG);
@@ -719,8 +720,10 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
tmp_str)))
return_0;
}
} else if (_mirror_or_raid_type_requested(cmd, lp->type_str) ||
lp->repair || lp->mirrorlog || lp->corelog) { /* Mirrors (and some RAID functions) */
} else if (lp->repair)
;
else if (_mirror_or_raid_type_requested(cmd, lp->type_str) ||
lp->mirrorlog || lp->corelog) { /* Mirrors (and some RAID functions) */
if (arg_is_set(cmd, chunksize_ARG)) {
log_error("--chunksize is only available with snapshots or pools.");
return 0;
@@ -771,49 +774,22 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
return 0;
}
/* Default is never striped, regardless of existing LV configuration. */
if (!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size))
return_0;
/* FIXME man page says in one place that --type and --mirrors can't be mixed */
if (lp->mirrors_supplied && !lp->mirrors) {
if (lp->mirrors_supplied && !lp->mirrors)
/* down-converting to linear/stripe? */
if (!(lp->segtype =
get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
return_0;
} else if (arg_is_set(cmd, type_ARG)) {
/* changing mirror type? */
if (!(lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, find_config_tree_str(cmd, global_mirror_segtype_default_CFG, NULL)))))
return_0;
}
} else if (_raid0_type_requested(cmd, lp->type_str) || _striped_type_requested(cmd, lp->type_str)) { /* striped or linear or raid0 */
lp->type_str = SEG_TYPE_NAME_STRIPED;
} else if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str)) { /* striped or linear or raid0 */
if (arg_from_list_is_set(cmd, "cannot be used with --type raid0 or --type striped or --type linear",
chunksize_ARG, corelog_ARG, mirrors_ARG, mirrorlog_ARG, regionsize_ARG, zero_ARG,
-1))
return_0;
if (!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size))
return_0;
/* FIXME Shouldn't need to override get_stripe_params which defaults to 1 stripe (i.e. linear)! */
/* The default keeps existing number of stripes, handled inside the library code */
if (!arg_is_set(cmd, stripes_long_ARG) && !_linear_type_requested(lp->type_str))
lp->stripes = 0;
if (!(lp->segtype = get_segtype_from_string(cmd, lp->type_str)))
return_0;
} /* else segtype will default to current type */
lp->force = arg_count(cmd, force_ARG);
lp->yes = arg_count(cmd, yes_ARG);
if (activation() && lp->segtype && lp->segtype->ops->target_present &&
!lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) {
log_error("%s: Required device-mapper target(s) not "
"detected in your kernel.", lp->segtype->name);
return 0;
}
if (!_lvconvert_name_params(lp, cmd, &argc, &argv))
return_0;
@@ -1382,7 +1358,7 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
uint32_t new_log_count)
{
uint32_t region_size;
struct lv_segment *seg;
struct lv_segment *seg = first_seg(lv);
struct logical_volume *layer_lv;
uint32_t old_mimage_count = lv_mirror_count(lv);
uint32_t old_log_count = _get_log_count(lv);
@@ -1395,14 +1371,12 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
region_size = adjusted_mirror_region_size(lv->vg->extent_size,
lv->le_count,
lp->region_size, 0,
lp->region_size ? : seg->region_size, 0,
vg_is_clustered(lv->vg));
if (!operable_pvs)
operable_pvs = lp->pvh;
seg = first_seg(lv);
/*
* Up-convert from linear to mirror
*/
@@ -1622,6 +1596,10 @@ static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
failed_mimages = _failed_mirrors_count(lv);
failed_logs = _failed_logs_count(lv);
/* Retain existing region size in case we need it later */
if (!lp->region_size)
lp->region_size = first_seg(lv)->region_size;
if (!mirror_remove_missing(cmd, lv, 0))
return_0;
@@ -1717,12 +1695,16 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
struct logical_volume *lv,
struct lvconvert_params *lp)
{
const char *new_type;
uint32_t old_mimage_count;
uint32_t old_log_count;
uint32_t new_mimage_count;
uint32_t new_log_count;
if ((lp->corelog || lp->mirrorlog) && *lp->type_str && strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) {
log_error("--corelog and --mirrorlog are only compatible with mirror devices");
return 0;
}
if (lp->merge_mirror) {
log_error("Unable to merge mirror images"
"of segment type 'mirror'.");
@@ -1746,8 +1728,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
return 0;
}
if ((new_type = arg_str_value(cmd, type_ARG, NULL)) &&
!strcmp(new_type, SEG_TYPE_NAME_LINEAR)) {
if (_linear_type_requested(lp->type_str)) {
if (arg_is_set(cmd, mirrors_ARG) && (arg_uint_value(cmd, mirrors_ARG, 0) != 0)) {
log_error("Cannot specify mirrors with linear type.");
return 0;
@@ -1786,6 +1767,9 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
if (!lp->need_polling)
log_print_unless_silent("Logical volume %s converted.",
display_lvname(lv));
else
log_print_unless_silent("Logical volume %s being converted.",
display_lvname(lv));
backup(lv->vg);
@@ -1837,18 +1821,13 @@ static void _lvconvert_raid_repair_ask(struct cmd_context *cmd,
static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp)
{
const char *new_type;
int replace = 0, image_count = 0;
struct dm_list *failed_pvs;
struct cmd_context *cmd = lv->vg->cmd;
struct lv_segment *seg = first_seg(lv);
dm_percent_t sync_percent;
if (!lp->segtype)
lp->segtype = seg->segtype;
if ((new_type = arg_str_value(cmd, type_ARG, NULL)) &&
!strcmp(new_type, SEG_TYPE_NAME_LINEAR)) {
if (_linear_type_requested(lp->type_str)) {
if (arg_is_set(cmd, mirrors_ARG) && (arg_uint_value(cmd, mirrors_ARG, 0) != 0)) {
log_error("Cannot specify mirrors with linear type.");
return 0;
@@ -1858,25 +1837,36 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
}
/* Can only change image count for raid1 and linear */
if (lp->mirrors_supplied && !seg_is_mirrored(seg) && !seg_is_linear(seg)) {
log_error("'--mirrors/-m' is not compatible with %s.",
lvseg_name(seg));
return 0;
if (lp->mirrors_supplied) {
if (_raid0_type_requested(lp->type_str)) {
log_error("--mirrors/-m is not compatible with conversion to %s.",
lp->type_str);
return 0;
}
if (!seg_is_mirrored(seg) && !seg_is_linear(seg)) {
log_error("--mirrors/-m is not compatible with %s.",
lvseg_name(seg));
return 0;
}
}
if (!_lvconvert_validate_thin(lv, lp))
return_0;
if (!_is_valid_raid_conversion(seg->segtype, lp->segtype)) {
log_error("Unable to convert %s from %s to %s.",
display_lvname(lv), lvseg_name(seg),
lp->segtype->name);
return 0;
}
if (!_is_valid_raid_conversion(seg->segtype, lp->segtype))
goto try_new_takeover_or_reshape;
if (seg_is_linear(seg) && !lp->merge_mirror && !lp->mirrors_supplied) {
log_error("Raid conversions require -m/--mirrors.");
return 0;
if (_raid0_type_requested(lp->type_str)) {
log_error("Linear LV %s cannot be converted to %s.",
display_lvname(lv), lp->type_str);
return 0;
} else if (!strcmp(lp->type_str, SEG_TYPE_NAME_RAID1)) {
log_error("Raid conversions of LV %s require -m/--mirrors.",
display_lvname(lv));
return 0;
}
goto try_new_takeover_or_reshape;
}
/* Change number of RAID1 images */
@@ -1897,10 +1887,15 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
/* --trackchanges requires --splitmirrors which always has SIGN_MINUS */
if (lp->track_changes && lp->mirrors != 1) {
log_error("Exactly one image must be split off from %s when tracking changes.",
log_error("Exactly one image must be split off from %s when tracking changes.",
display_lvname(lv));
return 0;
}
return 0;
}
}
if ((lp->corelog || lp->mirrorlog) && strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) {
log_error("--corelog and --mirrorlog are only compatible with mirror devices");
return 0;
}
if (lp->merge_mirror)
@@ -1912,18 +1907,44 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
if (lp->keep_mimages)
return lv_raid_split(lv, lp->lv_split_name, image_count, lp->pvh);
if (lp->mirrors_supplied)
return lv_raid_change_image_count(lv, image_count, lp->pvh);
if (lp->mirrors_supplied) {
if (!*lp->type_str || !strcmp(lp->type_str, SEG_TYPE_NAME_RAID1) || !strcmp(lp->type_str, SEG_TYPE_NAME_LINEAR) ||
(!strcmp(lp->type_str, SEG_TYPE_NAME_STRIPED) && image_count == 1)) {
if (image_count > DEFAULT_RAID1_MAX_IMAGES) {
log_error("Only up to %u mirrors in %s LV %s supported currently.",
DEFAULT_RAID1_MAX_IMAGES, lp->segtype->name, display_lvname(lv));
return 0;
}
if (!lv_raid_change_image_count(lv, image_count, lp->pvh))
return_0;
log_print_unless_silent("Logical volume %s successfully converted.",
display_lvname(lv));
return 1;
}
goto try_new_takeover_or_reshape;
} else if (!lp->repair && !lp->replace && (!*lp->type_str || seg->segtype == lp->segtype)) {
log_error("Conversion operation not yet supported.");
return 0;
}
if ((seg_is_linear(seg) || seg_is_striped(seg) || seg_is_mirrored(seg) || lv_is_raid(lv)) &&
(lp->type_str && lp->type_str[0])) {
/* Activation is required later which precludes existing unsupported raid0 segment */
if (segtype_is_any_raid0(lp->segtype) &&
!(lp->target_attr & RAID_FEATURE_RAID0)) {
log_error("RAID module does not support RAID0.");
return 0;
}
if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size, lp->pvh))
if (!arg_is_set(cmd, stripes_long_ARG))
lp->stripes = 0;
if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size_supplied, lp->stripe_size,
lp->region_size, lp->pvh))
return_0;
log_print_unless_silent("Logical volume %s successfully converted.",
display_lvname(lv));
return 1;
@@ -1941,8 +1962,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
return 0;
}
if (!seg_is_striped(seg) && !seg_is_any_raid0(seg) &&
!lv_raid_percent(lv, &sync_percent)) {
if (!seg_is_striped(seg) && !lv_raid_percent(lv, &sync_percent)) {
log_error("Unable to determine sync status of %s.",
display_lvname(lv));
return 0;
@@ -1984,8 +2004,27 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
return 1;
}
log_error("Conversion operation not yet supported.");
try_new_takeover_or_reshape:
/* FIXME This needs changing globally. */
if (!arg_is_set(cmd, stripes_long_ARG))
lp->stripes = 0;
/* Only let raid4 through for now. */
if (lp->type_str && lp->type_str[0] && lp->segtype != seg->segtype &&
((seg_is_raid4(seg) && seg_is_striped(lp) && lp->stripes > 1) ||
(seg_is_striped(seg) && seg->area_count > 1 && seg_is_raid4(lp)))) {
if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size_supplied, lp->stripe_size,
lp->region_size, lp->pvh))
return_0;
log_print_unless_silent("Logical volume %s successfully converted.",
display_lvname(lv));
return 1;
}
log_error("Conversion operation not yet supported.");
return 0;
}
@@ -2420,9 +2459,6 @@ static int _lvconvert_merge_thin_snapshot(struct cmd_context *cmd,
if (!archive(lv->vg))
return_0;
// FIXME: allow origin to be specified
// FIXME: verify snapshot is descendant of specified origin
/*
* Prevent merge with open device(s) as it would likely lead
* to application/filesystem failure. Merge on origin's next
@@ -3146,7 +3182,8 @@ static int _lvconvert_pool(struct cmd_context *cmd,
if (!_lvconvert_update_pool_params(pool_lv, lp))
return_0;
if (!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size))
if (!get_stripe_params(cmd, get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED),
&lp->stripes, &lp->stripe_size))
return_0;
if (!archive(vg))
@@ -3889,6 +3926,16 @@ static int _convert_raid_raid(struct cmd_context *cmd, struct logical_volume *lv
return _lvconvert_raid(lv, lp);
}
/*
* Convert a raid* LV to a mirror LV.
* lvconvert --type mirror LV
*/
static int _convert_raid_mirror(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
return _lvconvert_raid(lv, lp);
}
/*
* Convert a raid* LV to a striped LV.
* lvconvert --type striped LV
@@ -4081,8 +4128,6 @@ static int _convert_thin_volume(struct cmd_context *cmd, struct logical_volume *
static int _convert_thin_pool(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
const char *new_type = arg_str_value(cmd, type_ARG, NULL);
if (arg_is_set(cmd, splitcache_ARG))
return _convert_thin_pool_splitcache(cmd, lv, lp);
@@ -4092,7 +4137,7 @@ static int _convert_thin_pool(struct cmd_context *cmd, struct logical_volume *lv
if (arg_is_set(cmd, uncache_ARG))
return _convert_thin_pool_uncache(cmd, lv, lp);
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_CACHE)) || arg_is_set(cmd, cache_ARG))
if (lp->cache)
return _convert_thin_pool_cache(cmd, lv, lp);
if (arg_is_set(cmd, repair_ARG))
@@ -4116,8 +4161,6 @@ static int _convert_thin_pool(struct cmd_context *cmd, struct logical_volume *lv
static int _convert_cache_volume(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
const char *new_type = arg_str_value(cmd, type_ARG, NULL);
if (arg_is_set(cmd, splitcache_ARG))
return _convert_cache_volume_splitcache(cmd, lv, lp);
@@ -4132,7 +4175,7 @@ static int _convert_cache_volume(struct cmd_context *cmd, struct logical_volume
/* Using --thinpool is ambiguous and not preferred. */
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_THIN_POOL)) || arg_is_set(cmd, thinpool_ARG))
if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL) || arg_is_set(cmd, thinpool_ARG))
return _convert_cache_volume_thin_pool(cmd, lv, lp);
/* The --thinpool alternative for --type thin-pool is not preferred, so not shown. */
@@ -4170,12 +4213,6 @@ static int _convert_cache_pool(struct cmd_context *cmd, struct logical_volume *l
static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
const char *new_type = arg_str_value(cmd, type_ARG, NULL);
const struct segment_type *new_segtype = NULL;
if (new_type)
new_segtype = get_segtype_from_string(cmd, new_type);
if (arg_is_set(cmd, mirrors_ARG))
return _convert_mirror_number(cmd, lv, lp);
@@ -4188,10 +4225,10 @@ static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv,
if (arg_is_set(cmd, repair_ARG))
return _convert_mirror_repair(cmd, lv, lp);
if (new_type && !strcmp(new_type, SEG_TYPE_NAME_LINEAR))
if (_linear_type_requested(lp->type_str))
return _convert_mirror_linear(cmd, lv, lp);
if (new_type && new_segtype && segtype_is_raid(new_segtype))
if (segtype_is_raid(lp->segtype))
return _convert_mirror_raid(cmd, lv, lp);
/*
@@ -4226,12 +4263,6 @@ static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv,
static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
const char *new_type = arg_str_value(cmd, type_ARG, NULL);
const struct segment_type *new_segtype = NULL;
if (new_type)
new_segtype = get_segtype_from_string(cmd, new_type);
if (arg_is_set(cmd, mirrors_ARG))
return _convert_raid_number(cmd, lv, lp);
@@ -4247,32 +4278,35 @@ static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
if (arg_is_set(cmd, replace_ARG))
return _convert_raid_replace(cmd, lv, lp);
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_SNAPSHOT)) || arg_is_set(cmd, snapshot_ARG))
if (!strcmp(lp->type_str, SEG_TYPE_NAME_SNAPSHOT) || arg_is_set(cmd, snapshot_ARG))
return _convert_raid_snapshot(cmd, lv, lp);
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_THIN)) || arg_is_set(cmd, thin_ARG))
if (lp->thin)
return _convert_raid_thin(cmd, lv, lp);
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_CACHE)) || arg_is_set(cmd, cache_ARG))
if (lp->cache)
return _convert_raid_cache(cmd, lv, lp);
/* Using --thinpool is ambiguous and not preferred. */
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_THIN_POOL)) || arg_is_set(cmd, thinpool_ARG))
if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL) || arg_is_set(cmd, thinpool_ARG))
return _convert_raid_thin_pool(cmd, lv, lp);
/* Using --cachepool is ambiguous and not preferred. */
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_CACHE_POOL)) || arg_is_set(cmd, cachepool_ARG))
if (!strcmp(lp->type_str, SEG_TYPE_NAME_CACHE_POOL) || arg_is_set(cmd, cachepool_ARG))
return _convert_raid_cache_pool(cmd, lv, lp);
if (new_type && new_segtype && segtype_is_raid(new_segtype))
if (segtype_is_raid(lp->segtype))
return _convert_raid_raid(cmd, lv, lp);
if (new_type && !strcmp(new_type, SEG_TYPE_NAME_STRIPED))
if (segtype_is_mirror(lp->segtype))
return _convert_raid_mirror(cmd, lv, lp);
if (!strcmp(lp->type_str, SEG_TYPE_NAME_STRIPED))
return _convert_raid_striped(cmd, lv, lp);
if (new_type && !strcmp(new_type, SEG_TYPE_NAME_LINEAR))
if (_linear_type_requested(lp->type_str))
return _convert_raid_linear(cmd, lv, lp);
/* The --thinpool alternative for --type thin-pool is not preferred, so not shown. */
@@ -4290,6 +4324,7 @@ static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
" --type thin-pool\n"
" --type cache-pool\n"
" --type raid*\n"
" --type mirror\n"
" --type striped\n"
" --type linear\n");
return 0;
@@ -4298,40 +4333,35 @@ static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
const char *new_type = arg_str_value(cmd, type_ARG, NULL);
const struct segment_type *new_segtype = NULL;
const char *mirrors_type = find_config_tree_str(cmd, global_mirror_segtype_default_CFG, NULL);
if (new_type)
new_segtype = get_segtype_from_string(cmd, new_type);
/* FIXME: add --merge-mirror to make this distinct from --merge-snapshot. */
if (arg_is_set(cmd, merge_ARG))
return _convert_striped_merge(cmd, lv, lp);
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_SNAPSHOT)) || arg_is_set(cmd, snapshot_ARG))
if (!strcmp(lp->type_str, SEG_TYPE_NAME_SNAPSHOT) || arg_is_set(cmd, snapshot_ARG))
return _convert_striped_snapshot(cmd, lv, lp);
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_THIN)) || arg_is_set(cmd, thin_ARG))
if (lp->thin)
return _convert_striped_thin(cmd, lv, lp);
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_CACHE)) || arg_is_set(cmd, cache_ARG))
if (lp->cache)
return _convert_striped_cache(cmd, lv, lp);
/* Using --thinpool is ambiguous and not preferred. */
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_THIN_POOL)) || arg_is_set(cmd, thinpool_ARG))
if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL) || arg_is_set(cmd, thinpool_ARG))
return _convert_striped_thin_pool(cmd, lv, lp);
/* Using --cachepool is ambiguous and not preferred. */
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_CACHE_POOL)) || arg_is_set(cmd, cachepool_ARG))
if (!strcmp(lp->type_str, SEG_TYPE_NAME_CACHE_POOL) || arg_is_set(cmd, cachepool_ARG))
return _convert_striped_cache_pool(cmd, lv, lp);
if (new_type && !strcmp(new_type, SEG_TYPE_NAME_MIRROR))
if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR))
return _convert_striped_mirror(cmd, lv, lp);
if (new_type && new_segtype && segtype_is_raid(new_segtype))
if (segtype_is_raid(lp->segtype))
return _convert_striped_raid(cmd, lv, lp);
/* --mirrors can mean --type mirror or --type raid1 depending on config setting. */
@@ -4359,6 +4389,7 @@ static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv,
}
/*
* Main entry point.
* lvconvert performs a specific <operation> on a specific <lv_type>.
*
* The <operation> is specified by command line args.
@@ -4366,14 +4397,20 @@ static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv,
*
* for each lvtype,
* _convert_lvtype();
* for each arg_is_set(operation)
* _convert_lvtype_operation();
* for each arg_is_set(operation)
* _convert_lvtype_operation();
*
* FIXME: this code (identifying/routing each unique operation through
* _convert_lvtype_op) was designed to work based on the new type that
* the user entered after --type, not the final segment type in lp->type_str.
* Sometimes the two differ because tricks are played with lp->type_str.
* So, when the use of arg_type_str(type_ARG) here was replaced with
* lp->type_str, some commands are no longer identified/routed correctly.
*/
static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
struct lv_segment *lv_seg = first_seg(lv);
struct lv_segment *seg = first_seg(lv);
int ret = 0;
/*
@@ -4411,11 +4448,50 @@ static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
}
}
/* Set up segtype either from type_str or else to match the existing one. */
if (!*lp->type_str)
lp->segtype = seg->segtype;
else if (!(lp->segtype = get_segtype_from_string(cmd, lp->type_str)))
return_0;
if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) {
if (!lp->mirrors_supplied && !seg_is_raid1(seg)) {
log_error("Conversions to --type mirror require -m/--mirrors");
return 0;
}
}
if (activation() && lp->segtype && lp->segtype->ops->target_present &&
!lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) {
log_error("%s: Required device-mapper target(s) not "
"detected in your kernel.", lp->segtype->name);
return 0;
}
/* Process striping parameters */
/* FIXME This is incomplete */
if (_mirror_or_raid_type_requested(cmd, lp->type_str) || _raid0_type_requested(lp->type_str) ||
_striped_type_requested(lp->type_str) || lp->repair || lp->mirrorlog || lp->corelog) {
/* FIXME Handle +/- adjustments too? */
if (!get_stripe_params(cmd, lp->segtype, &lp->stripes, &lp->stripe_size))
return_0;
/* FIXME Move this into the get function */
lp->stripe_size_supplied = arg_is_set(cmd, stripesize_ARG);
if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str))
/* FIXME Shouldn't need to override get_stripe_params which defaults to 1 stripe (i.e. linear)! */
/* The default keeps existing number of stripes, handled inside the library code */
if (!arg_is_set(cmd, stripes_long_ARG))
lp->stripes = 0;
}
if (lp->snapshot)
lp->zero = (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? 0 : arg_int_value(cmd, zero_ARG, 1);
/*
* Each LV type that can be converted.
* (The existing type of the LV, not a requested type.)
*/
if (lv_is_cow(lv)) {
ret = _convert_cow_snapshot(cmd, lv, lp);
goto out;
@@ -4453,10 +4529,10 @@ static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
/*
* FIXME: add lv_is_striped() and lv_is_linear()?
* This does not include raid0.
* This does not include raid0 which is caught by the test above.
* If operations differ between striped and linear, split this case.
*/
if (segtype_is_striped(lv_seg->segtype) || segtype_is_linear(lv_seg->segtype)) {
if (segtype_is_striped(seg->segtype) || segtype_is_linear(seg->segtype)) {
ret = _convert_striped(cmd, lv, lp);
goto out;
}

View File

@@ -495,9 +495,7 @@ static int _read_raid_params(struct cmd_context *cmd,
lp->segtype->name);
return 0;
}
} else if (!lp->stripe_size)
lp->stripe_size = find_config_tree_int(cmd, metadata_stripesize_CFG, NULL) * 2;
}
if (arg_is_set(cmd, mirrors_ARG) && segtype_is_raid(lp->segtype) &&
!segtype_is_raid1(lp->segtype) && !segtype_is_raid10(lp->segtype)) {
@@ -529,8 +527,21 @@ static int _read_mirror_and_raid_params(struct cmd_context *cmd,
struct lvcreate_params *lp)
{
int pagesize = lvm_getpagesize();
unsigned max_images = segtype_is_raid(lp->segtype) ? DEFAULT_RAID_MAX_IMAGES :
DEFAULT_MIRROR_MAX_IMAGES;
unsigned max_images;
if (seg_is_raid(lp)) {
if (seg_is_raid1(lp))
max_images = DEFAULT_RAID1_MAX_IMAGES;
else {
max_images = DEFAULT_RAID_MAX_IMAGES;
if (seg_is_raid4(lp) ||
seg_is_any_raid5(lp))
max_images--;
else if (seg_is_any_raid6(lp))
max_images -= 2;
}
} else
max_images = DEFAULT_MIRROR_MAX_IMAGES;
/* Common mirror and raid params */
if (arg_is_set(cmd, mirrors_ARG)) {
@@ -558,13 +569,27 @@ static int _read_mirror_and_raid_params(struct cmd_context *cmd,
/* Default to 2 mirrored areas if '--type mirror|raid1|raid10' */
lp->mirrors = seg_is_mirrored(lp) ? 2 : 1;
if (max(lp->mirrors, lp->stripes) > max_images) {
log_error("Only up to %u images in %s supported currently.",
/* FIMXE: raid10 check has to change once we support data copies and odd numbers of stripes */
if (seg_is_raid10(lp) && lp->mirrors * lp->stripes > max_images) {
log_error("Only up to %u stripes in %s supported currently.",
max_images, lp->segtype->name);
return 0;
} else if (seg_is_mirrored(lp)) {
if (lp->mirrors > max_images) {
log_error("Only up to %u mirrors in %s supported currently.",
max_images, lp->segtype->name);
return 0;
}
} else if (lp->stripes > max_images) {
log_error("Only up to %u stripes in %s supported currently.",
max_images, lp->segtype->name);
return 0;
}
lp->nosync = arg_is_set(cmd, nosync_ARG);
if ((lp->nosync = arg_is_set(cmd, nosync_ARG)) && seg_is_any_raid6(lp)) {
log_error("nosync option prohibited on RAID6");
return 0;
}
if (!(lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0)) &&
((lp->region_size = get_default_region_size(cmd)) <= 0)) {
@@ -572,14 +597,6 @@ static int _read_mirror_and_raid_params(struct cmd_context *cmd,
return 0;
}
/*
* FIXME This is working around a bug in get_stripe_params() where
* stripes is incorrectly assumed to be 1 when it is not supplied
* leading to the actual value of stripesize getting lost.
*/
if (arg_is_set(cmd, stripesize_ARG))
lp->stripe_size = arg_uint_value(cmd, stripesize_ARG, 0);
if (!is_power_of_2(lp->region_size)) {
log_error("Region size (%" PRIu32 ") must be a power of 2",
lp->region_size);
@@ -1044,7 +1061,7 @@ static int _lvcreate_params(struct cmd_context *cmd,
if (!_lvcreate_name_params(cmd, &argc, &argv, lp) ||
!_read_size_params(cmd, lp, lcp) ||
!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) ||
!get_stripe_params(cmd, lp->segtype, &lp->stripes, &lp->stripe_size) ||
(lp->create_pool &&
!get_pool_params(cmd, lp->segtype, &lp->passed_args,
&lp->pool_metadata_size, &lp->pool_metadata_spare,

View File

@@ -181,66 +181,124 @@ static void _write_history(void)
log_very_verbose("Couldn't write history to %s.", hist_file);
}
static int _log_shell_command_status(struct cmd_context *cmd, int ret_code)
{
log_report_t log_state;
if (!cmd->cmd_report.log_rh)
return 1;
log_state = log_get_report_state();
return report_cmdlog(cmd->cmd_report.log_rh, REPORT_OBJECT_CMDLOG_NAME,
log_get_report_context_name(log_state.context),
log_get_report_object_type_name(log_state.object_type),
log_state.object_name, log_state.object_id,
log_state.object_group, log_state.object_group_id,
ret_code == ECMD_PROCESSED ? REPORT_OBJECT_CMDLOG_SUCCESS
: REPORT_OBJECT_CMDLOG_FAILURE,
stored_errno(), ret_code);
}
static void _discard_log_report_content(struct cmd_context *cmd)
{
if (cmd->cmd_report.log_rh)
dm_report_destroy_rows(cmd->cmd_report.log_rh);
}
int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
{
int argc, ret;
log_report_t saved_log_report_state = log_get_report_state();
char *orig_command_log_selection = NULL;
int is_lastlog_cmd = 0, argc, ret;
char *input = NULL, *args[MAX_ARGS], **argv;
rl_readline_name = "lvm";
rl_attempted_completion_function = (rl_completion_func_t *) _completion;
_read_history(cmd);
_cmdline = cmdline;
cmd->is_interactive = 1;
if (!report_format_init(cmd))
return_ECMD_FAILED;
orig_command_log_selection = dm_pool_strdup(cmd->libmem, find_config_tree_str(cmd, log_command_log_selection_CFG, NULL));
log_set_report_context(LOG_REPORT_CONTEXT_SHELL);
log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_CMD);
while (1) {
report_reset_cmdlog_seqnum();
if (cmd->cmd_report.log_rh) {
/*
* If previous command was lastlog, reset log report selection to
* its original value as set by log/command_log_selection config setting.
*/
if (is_lastlog_cmd &&
!dm_report_set_selection(cmd->cmd_report.log_rh, orig_command_log_selection))
log_error("Failed to reset log report selection.");
}
log_set_report(cmd->cmd_report.log_rh);
log_set_report_object_name_and_id(NULL, NULL);
free(input);
input = readline("lvm> ");
/* EOF */
if (!input) {
_discard_log_report_content(cmd);
/* readline sends prompt to stdout */
printf("\n");
break;
}
/* empty line */
if (!*input)
if (!*input) {
_discard_log_report_content(cmd);
continue;
}
add_history(input);
argv = args;
if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
_discard_log_report_content(cmd);
log_error("Too many arguments, sorry.");
continue;
}
if (!argc)
if (!argc) {
_discard_log_report_content(cmd);
continue;
}
if (!strcmp(argv[0], "lvm")) {
argv++;
argc--;
}
if (!argc)
if (!argc) {
_discard_log_report_content(cmd);
continue;
}
log_set_report_object_name_and_id(argv[0], NULL);
is_lastlog_cmd = !strcmp(argv[0], "lastlog");
if (!is_lastlog_cmd)
_discard_log_report_content(cmd);
if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
_discard_log_report_content(cmd);
remove_history(history_length - 1);
log_error("Exiting.");
break;
}
if (cmd->log_rh && strcmp(argv[0], "lastlog")) {
/* drop old log report */
dm_report_free(cmd->log_rh);
cmd->log_rh = NULL;
}
ret = lvm_run_command(cmd, argc, argv);
if (ret == ENO_SUCH_CMD)
log_error("No such command '%s'. Try 'help'.",
@@ -251,10 +309,38 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
log_error("Command failed with status code %d.", ret);
}
_write_history();
if (!is_lastlog_cmd)
_log_shell_command_status(cmd, ret);
log_set_report(NULL);
dm_report_group_output_and_pop_all(cmd->cmd_report.report_group);
if (cmd->cmd_report.log_rh &&
!(dm_report_group_push(cmd->cmd_report.report_group,
cmd->cmd_report.log_rh,
(void *) cmd->cmd_report.log_name))) {
log_set_report(NULL);
log_error("Failed to add log report.");
break;
}
}
log_restore_report_state(saved_log_report_state);
cmd->is_interactive = 0;
free(input);
if (cmd->cmd_report.report_group) {
dm_report_group_destroy(cmd->cmd_report.report_group);
cmd->cmd_report.report_group = NULL;
}
if (cmd->cmd_report.log_rh) {
dm_report_free(cmd->cmd_report.log_rh);
cmd->cmd_report.report_group = NULL;
}
return 0;
}

View File

@@ -63,12 +63,12 @@ static struct cmdline_context _cmdline;
/* Command line args */
unsigned arg_count(const struct cmd_context *cmd, int a)
{
return cmd->arg_values[a].count;
return cmd->arg_values ? cmd->arg_values[a].count : 0;
}
unsigned grouped_arg_count(const struct arg_values *av, int a)
{
return av[a].count;
return av ? av[a].count : 0;
}
unsigned arg_is_set(const struct cmd_context *cmd, int a)
@@ -182,7 +182,7 @@ const char *arg_long_option_name(int a)
const char *arg_value(const struct cmd_context *cmd, int a)
{
return cmd->arg_values[a].value;
return cmd->arg_values ? cmd->arg_values[a].value : NULL;
}
const char *arg_str_value(const struct cmd_context *cmd, int a, const char *def)
@@ -1167,6 +1167,7 @@ static int _get_settings(struct cmd_context *cmd)
!_merge_synonym(cmd, allocation_ARG, resizeable_ARG) ||
!_merge_synonym(cmd, virtualoriginsize_ARG, virtualsize_ARG) ||
!_merge_synonym(cmd, available_ARG, activate_ARG) ||
!_merge_synonym(cmd, raidrebuild_ARG, rebuild_ARG) ||
!_merge_synonym(cmd, raidsyncaction_ARG, syncaction_ARG) ||
!_merge_synonym(cmd, raidwritemostly_ARG, writemostly_ARG) ||
!_merge_synonym(cmd, raidminrecoveryrate_ARG, minrecoveryrate_ARG) ||
@@ -1394,6 +1395,7 @@ static int _prepare_profiles(struct cmd_context *cmd)
cmd->profile_params->global_metadata_profile = profile;
}
remove_config_tree_by_source(cmd, source);
if (!override_config_tree_from_profile(cmd, profile)) {
log_error(_failed_to_apply_profile_msg, source_name, name);
return 0;
@@ -1419,6 +1421,8 @@ static int _prepare_profiles(struct cmd_context *cmd)
log_error(_failed_to_add_profile_msg, source_name, name);
return 0;
}
remove_config_tree_by_source(cmd, CONFIG_PROFILE_COMMAND);
if (!override_config_tree_from_profile(cmd, profile)) {
log_error(_failed_to_apply_profile_msg, source_name, name);
return 0;
@@ -1426,6 +1430,9 @@ static int _prepare_profiles(struct cmd_context *cmd)
log_debug(_setting_global_profile_msg, _command_profile_source_name, profile->name);
cmd->profile_params->global_command_profile = profile;
if (!cmd->arg_values)
cmd->profile_params->shell_profile = profile;
}
@@ -1437,6 +1444,7 @@ static int _prepare_profiles(struct cmd_context *cmd)
log_error(_failed_to_add_profile_msg, source_name, name);
return 0;
}
remove_config_tree_by_source(cmd, CONFIG_PROFILE_METADATA);
if (!override_config_tree_from_profile(cmd, profile)) {
log_error(_failed_to_apply_profile_msg, source_name, name);
return 0;
@@ -1733,10 +1741,13 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
config_profile_metadata_cft = remove_config_tree_by_source(cmd, CONFIG_PROFILE_METADATA);
cmd->profile_params->global_metadata_profile = NULL;
if (config_string_cft || config_profile_command_cft || config_profile_metadata_cft) {
if (config_string_cft) {
/* Move this? */
if (!refresh_toolcontext(cmd))
stack;
} else if (config_profile_command_cft || config_profile_metadata_cft) {
if (!process_profilable_config(cmd))
stack;
}
if (ret == EINVALID_CMD_LINE && !cmd->is_interactive)
@@ -1834,6 +1845,39 @@ static int _check_standard_fds(void)
return 1;
}
#define LVM_OUT_FD_ENV_VAR_NAME "LVM_OUT_FD"
#define LVM_ERR_FD_ENV_VAR_NAME "LVM_ERR_FD"
#define LVM_REPORT_FD_ENV_VAR_NAME "LVM_REPORT_FD"
static int _do_get_custom_fd(const char *env_var_name, int *fd)
{
const char *str;
char *endptr;
long int tmp_fd;
*fd = -1;
if (!(str = getenv(env_var_name)))
return 1;
errno = 0;
tmp_fd = strtol(str, &endptr, 10);
if (errno || *endptr || (tmp_fd < 0) || (tmp_fd > INT_MAX)) {
log_error("%s: invalid file descriptor.", env_var_name);
return 0;
}
*fd = tmp_fd;
return 1;
}
static int _get_custom_fds(struct custom_fds *custom_fds)
{
return _do_get_custom_fd(LVM_OUT_FD_ENV_VAR_NAME, &custom_fds->out) &&
_do_get_custom_fd(LVM_ERR_FD_ENV_VAR_NAME, &custom_fds->err) &&
_do_get_custom_fd(LVM_REPORT_FD_ENV_VAR_NAME, &custom_fds->report);
}
static const char *_get_cmdline(pid_t pid)
{
static char _proc_cmdline[32];
@@ -1901,7 +1945,7 @@ static void _close_descriptor(int fd, unsigned suppress_warnings,
fprintf(stderr, " Parent PID %" PRIpid_t ": %s\n", ppid, parent_cmdline);
}
static int _close_stray_fds(const char *command)
static int _close_stray_fds(const char *command, struct custom_fds *custom_fds)
{
#ifndef VALGRIND_POOL
struct rlimit rlim;
@@ -1935,17 +1979,27 @@ static int _close_stray_fds(const char *command)
return 1;
}
for (fd = 3; fd < (int)rlim.rlim_cur; fd++)
_close_descriptor(fd, suppress_warnings, command, ppid,
parent_cmdline);
for (fd = 3; fd < (int)rlim.rlim_cur; fd++) {
if ((fd != custom_fds->out) &&
(fd != custom_fds->err) &&
(fd != custom_fds->report)) {
_close_descriptor(fd, suppress_warnings, command, ppid,
parent_cmdline);
}
}
return 1;
}
while ((dirent = readdir(d))) {
fd = atoi(dirent->d_name);
if (fd > 2 && fd != dirfd(d))
if ((fd > 2) &&
(fd != dirfd(d)) &&
(fd != custom_fds->out) &&
(fd != custom_fds->err) &&
(fd != custom_fds->report)) {
_close_descriptor(fd, suppress_warnings,
command, ppid, parent_cmdline);
}
}
if (closedir(d))
@@ -2107,6 +2161,7 @@ int lvm2_main(int argc, char **argv)
{
const char *base;
int ret, alias = 0;
struct custom_fds custom_fds;
struct cmd_context *cmd;
if (!argv)
@@ -2120,7 +2175,13 @@ int lvm2_main(int argc, char **argv)
if (!_check_standard_fds())
return -1;
if (!_close_stray_fds(base))
if (!_get_custom_fds(&custom_fds))
return -1;
if (!_close_stray_fds(base, &custom_fds))
return -1;
if (!init_custom_log_streams(&custom_fds))
return -1;
if (is_static() && strcmp(base, "lvm.static") &&
@@ -2163,6 +2224,10 @@ int lvm2_main(int argc, char **argv)
#ifdef READLINE_SUPPORT
if (!alias && argc == 1) {
_nonroot_warning();
if (!_prepare_profiles(cmd)) {
ret = ECMD_FAILED;
goto out;
}
ret = lvm_shell(cmd, &_cmdline);
goto out;
}

View File

@@ -144,6 +144,75 @@ static struct dm_list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
return allocatable_pvs;
}
/*
* If @lv_name's a RAID SubLV, check for any PVs
* on @trim_list holding it's sibling (rimage/rmeta)
* and remove it from the @trim_list in order to allow
* for pvmove collocation of DataLV/MetaLV pairs.
*/
static int _remove_sibling_pvs_from_trim_list(struct logical_volume *lv,
const char *lv_name,
struct dm_list *trim_list)
{
char *idx, *suffix, *sublv_name;
size_t len;
struct logical_volume *sublv;
struct dm_list untrim_list, *pvh1, *pvh2;
struct pv_list *pvl1, *pvl2;
/* Give up with success unless @lv_name _and_ valid raid segment type */
if (!lv_name || !*lv_name ||
!seg_is_raid(first_seg(lv)) ||
seg_is_raid0(first_seg(lv)) ||
!strcmp(lv->name, lv_name))
return 1;
dm_list_init(&untrim_list);
if (!(suffix = first_substring(lv_name, "_rimage_", "_rmeta_", NULL)))
return 0;
if (!(idx = strstr(suffix + 1, "_")))
return 0;
idx++;
/* + 2 for the longer rimage string */
if (!(sublv_name = dm_pool_alloc(lv->vg->cmd->mem, strlen(lv_name + 2))))
return_0;
/* Create the siblings name (e.g. "raidlv_rmeta_N" -> "raidlv_rimage_N" */
len = suffix - lv_name;
strncpy(sublv_name, lv_name, len);
sprintf(sublv_name + len, strstr(suffix, "_rimage_") ? "_rmeta_%s" : "_rimage_%s", idx);
if (!(sublv = find_lv(lv->vg, sublv_name))) {
log_error("Can't find sub LV %s?", sublv_name);
return_0;
}
if (!get_pv_list_for_lv(lv->vg->cmd->mem, sublv, &untrim_list)) {
log_error("Can't find PVs for sub LV %s?", sublv_name);
return_0;
}
dm_list_iterate(pvh1, &untrim_list) {
pvl1 = dm_list_item(pvh1, struct pv_list);
dm_list_iterate(pvh2, trim_list) {
pvl2 = dm_list_item(pvh2, struct pv_list);
if (pvl1->pv == pvl2->pv) {
log_debug("Removing PV %s from trim list",
pvl2->pv->dev->pvid);
dm_list_del(&pvl2->list);
break;
}
}
}
return 1;
}
/*
* _trim_allocatable_pvs
* @alloc_list
@@ -324,7 +393,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
if (lv == lv_mirr)
continue;
if (lv_name && strcmp(lv->name, lv_name))
if (lv_name && strcmp(lv->name, top_level_lv_name(vg, lv_name)))
continue;
/*
@@ -334,7 +403,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
*
* Allow clustered mirror, but not raid mirror.
*/
if (vg_is_clustered(lv->vg) && !lv_is_mirror_type(lv))
if (vg_is_clustered(vg) && !lv_is_mirror_type(lv))
continue;
if (!lv_is_on_pvs(lv, source_pvl))
@@ -351,8 +420,18 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
seg_is_mirrored(first_seg(lv))) {
dm_list_init(&trim_list);
if (!get_pv_list_for_lv(lv->vg->cmd->mem,
lv, &trim_list))
if (!get_pv_list_for_lv(vg->cmd->mem, lv, &trim_list))
return_NULL;
/*
* Remove any PVs holding SubLV siblings to allow
* for collocation (e.g. *rmeta_0 -> *rimage_0).
*
* Callee checks for lv_name and valid raid segment type.
*
* FIXME: don't rely on namespace
*/
if (!_remove_sibling_pvs_from_trim_list(lv, lv_name, &trim_list))
return_NULL;
if (!_trim_allocatable_pvs(allocatable_pvs,
@@ -370,6 +449,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
lv = lvl->lv;
if (lv == lv_mirr)
continue;
if (lv_name) {
if (strcmp(lv->name, lv_name) && !sub_lv_of(lv, lv_name))
continue;

View File

@@ -1055,7 +1055,7 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
goto_out;
if (!(args->log_only && (single_args->report_type != CMDLOG))) {
if (!dm_report_group_push(handle->report_group, report_handle, (void *) single_args->report_name))
if (!dm_report_group_push(cmd->cmd_report.report_group, report_handle, (void *) single_args->report_name))
goto_out;
report_in_group = 1;
}
@@ -1174,7 +1174,7 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
unlock_vg(cmd, NULL, VG_GLOBAL);
out:
if (report_handle) {
if (report_in_group && !dm_report_group_pop(handle->report_group))
if (report_in_group && !dm_report_group_pop(cmd->cmd_report.report_group))
stack;
dm_report_free(report_handle);
}
@@ -1197,7 +1197,7 @@ static int _full_report_single(struct cmd_context *cmd,
args->full_report_vg = vg;
if (!args->log_only && !dm_report_group_push(handle->report_group, NULL, NULL))
if (!args->log_only && !dm_report_group_push(cmd->cmd_report.report_group, NULL, NULL))
goto out;
if (orphan) {
@@ -1213,7 +1213,7 @@ static int _full_report_single(struct cmd_context *cmd,
stack;
}
if (!args->log_only && !dm_report_group_pop(handle->report_group))
if (!args->log_only && !dm_report_group_pop(cmd->cmd_report.report_group))
goto_out;
out:
args->full_report_vg = NULL;
@@ -1367,15 +1367,15 @@ static int _report(struct cmd_context *cmd, int argc, char **argv, report_type_t
handle->internal_report_for_select = 0;
handle->include_historical_lvs = cmd->include_historical_lvs;
args.report_group_type = handle->report_group_type;
args.log_only = handle->log_only;
args.report_group_type = cmd->cmd_report.report_group_type;
args.log_only = cmd->cmd_report.log_only;
if (!_config_report(cmd, &args, single_args)) {
destroy_processing_handle(cmd, handle);
return_ECMD_FAILED;
}
if (!args.log_only && !dm_report_group_push(handle->report_group, NULL, report_name)) {
if (!args.log_only && !dm_report_group_push(cmd->cmd_report.report_group, NULL, report_name)) {
log_error("Failed to add main report section to report group.");
destroy_processing_handle(cmd, handle);
return ECMD_FAILED;
@@ -1387,6 +1387,11 @@ static int _report(struct cmd_context *cmd, int argc, char **argv, report_type_t
} else
r = _do_report(cmd, handle, &args, single_args);
if (!args.log_only && !dm_report_group_pop(cmd->cmd_report.report_group)) {
log_error("Failed to finalize main report section in report group.");
r = ECMD_FAILED;
}
destroy_processing_handle(cmd, handle);
return r;
}
@@ -1433,9 +1438,7 @@ int devtypes(struct cmd_context *cmd, int argc, char **argv)
#define REPORT_FORMAT_NAME_BASIC "basic"
#define REPORT_FORMAT_NAME_JSON "json"
int report_format_init(struct cmd_context *cmd, dm_report_group_type_t *report_group_type,
struct dm_report_group **report_group, struct dm_report **log_rh,
int *log_only, log_report_t *saved_log_report_state)
int report_format_init(struct cmd_context *cmd)
{
int config_set = find_config_tree_node(cmd, report_output_format_CFG, NULL) != NULL;
const char *config_format_str = find_config_tree_str(cmd, report_output_format_CFG, NULL);
@@ -1446,7 +1449,7 @@ int report_format_init(struct cmd_context *cmd, dm_report_group_type_t *report_g
struct dm_report_group *new_report_group;
struct dm_report *tmp_log_rh = NULL;
args.log_only = arg_is_set(cmd, logonly_ARG) || *log_rh;
args.log_only = arg_is_set(cmd, logonly_ARG);
report_command_log = args.log_only || find_config_tree_bool(cmd, log_report_command_log_CFG, NULL);
if (!format_str || !strcmp(format_str, REPORT_FORMAT_NAME_BASIC)) {
@@ -1462,10 +1465,8 @@ int report_format_init(struct cmd_context *cmd, dm_report_group_type_t *report_g
return 0;
}
if (report_group_type)
*report_group_type = args.report_group_type;
if (log_only)
*log_only = args.log_only;
cmd->cmd_report.report_group_type = args.report_group_type;
cmd->cmd_report.log_only = args.log_only;
if (!(new_report_group = dm_report_group_create(args.report_group_type, NULL))) {
log_error("Failed to create report group.");
@@ -1476,40 +1477,33 @@ int report_format_init(struct cmd_context *cmd, dm_report_group_type_t *report_g
single_args = &args.single_args[REPORT_IDX_LOG];
single_args->report_type = CMDLOG;
if (!*log_rh) {
if (!_config_report(cmd, &args, single_args))
goto_bad;
if (!_config_report(cmd, &args, single_args))
goto_bad;
if (!(tmp_log_rh = report_init(NULL, single_args->options, single_args->keys, &single_args->report_type,
args.separator, args.aligned, args.buffered, args.headings,
args.field_prefixes, args.quoted, args.columns_as_rows,
single_args->selection, 1))) {
log_error("Failed to create log report.");
goto bad;
}
} else {
/*
* We reusing existing log report handle.
* Just get report's name and prefix now.
*/
if (!_set_report_prefix_and_name(&args, single_args))
goto_bad;
if (!(tmp_log_rh = report_init(NULL, single_args->options, single_args->keys, &single_args->report_type,
args.separator, args.aligned, args.buffered, args.headings,
args.field_prefixes, args.quoted, args.columns_as_rows,
single_args->selection, 1))) {
log_error("Failed to create log report.");
goto bad;
}
if (!(dm_report_group_push(new_report_group, tmp_log_rh ? : *log_rh, (void *) single_args->report_name))) {
if (!(dm_report_group_push(new_report_group, tmp_log_rh, (void *) single_args->report_name))) {
log_error("Failed to add log report to report group.");
goto bad;
}
cmd->cmd_report.log_rh = tmp_log_rh;
if (!(cmd->cmd_report.log_name = dm_pool_strdup(cmd->libmem, single_args->report_name))) {
log_error("Failed to set log report name for command context.");
goto bad;
}
}
*report_group = new_report_group;
if (tmp_log_rh)
*log_rh = tmp_log_rh;
cmd->cmd_report.report_group = new_report_group;
cmd->cmd_report.saved_log_report_state = log_get_report_state();
log_set_report(cmd->cmd_report.log_rh);
if (saved_log_report_state) {
*saved_log_report_state = log_get_report_state();
log_set_report(*log_rh);
}
return 1;
bad:
if (!dm_report_group_destroy(new_report_group))
@@ -1519,35 +1513,22 @@ bad:
return 0;
}
int lastlog(struct cmd_context *cmd, int argc, char **argv)
int lastlog(struct cmd_context *cmd, int argc __attribute((unused)), char **argv __attribute__((unused)))
{
struct dm_report_group *report_group = NULL;
const char *selection;
int r = ECMD_FAILED;
if (!cmd->log_rh) {
if (!cmd->cmd_report.log_rh) {
log_error("No log report stored.");
goto out;
return ECMD_FAILED;
}
if (!report_format_init(cmd, NULL, &report_group, &cmd->log_rh, NULL, NULL))
goto_out;
if (!_do_report_get_selection(cmd, CMDLOG, 1, NULL, &selection))
goto_out;
return_ECMD_FAILED;
if (!dm_report_set_selection(cmd->log_rh, selection)) {
if (!dm_report_set_selection(cmd->cmd_report.log_rh, selection)) {
log_error("Failed to set selection for log report.");
goto out;
return ECMD_FAILED;
}
if (!dm_report_output(cmd->log_rh) ||
!dm_report_group_pop(report_group))
goto_out;
r = ECMD_PROCESSED;
out:
if (!dm_report_group_destroy(report_group))
stack;
return r;
return ECMD_PROCESSED;
}

View File

@@ -1273,18 +1273,34 @@ int get_pool_params(struct cmd_context *cmd,
/*
* Generic stripe parameter checks.
*/
static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
uint32_t *stripe_size)
static int _validate_stripe_params(struct cmd_context *cmd, const struct segment_type *segtype,
uint32_t *stripes, uint32_t *stripe_size)
{
if (*stripes == 1 && *stripe_size) {
log_print_unless_silent("Ignoring stripesize argument with single stripe.");
int stripe_size_required = segtype_supports_stripe_size(segtype);
if (!stripe_size_required && *stripe_size) {
log_print_unless_silent("Ignoring stripesize argument for %s devices.", segtype->name);
*stripe_size = 0;
} else if (*stripes == 1 && (segtype_is_striped(segtype) || segtype_is_mirror(segtype))) {
stripe_size_required = 0;
if (*stripe_size) {
log_print_unless_silent("Ignoring stripesize argument with single stripe.");
*stripe_size = 0;
}
}
if (*stripes > 1 && !*stripe_size) {
*stripe_size = find_config_tree_int(cmd, metadata_stripesize_CFG, NULL) * 2;
log_print_unless_silent("Using default stripesize %s.",
display_size(cmd, (uint64_t) *stripe_size));
if (stripe_size_required) {
if (!*stripe_size) {
*stripe_size = find_config_tree_int(cmd, metadata_stripesize_CFG, NULL) * 2;
log_print_unless_silent("Using default stripesize %s.",
display_size(cmd, (uint64_t) *stripe_size));
}
if (*stripe_size < STRIPE_SIZE_MIN || !is_power_of_2(*stripe_size)) {
log_error("Invalid stripe size %s.",
display_size(cmd, (uint64_t) *stripe_size));
return 0;
}
}
if (*stripes < 1 || *stripes > MAX_STRIPES) {
@@ -1293,13 +1309,6 @@ static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
return 0;
}
if (*stripes > 1 && (*stripe_size < STRIPE_SIZE_MIN ||
!is_power_of_2(*stripe_size))) {
log_error("Invalid stripe size %s.",
display_size(cmd, (uint64_t) *stripe_size));
return 0;
}
return 1;
}
@@ -1309,9 +1318,10 @@ static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
* power of 2, we must divide UINT_MAX by four and add 1 (to round it
* up to the power of 2)
*/
int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stripe_size)
int get_stripe_params(struct cmd_context *cmd, const struct segment_type *segtype, uint32_t *stripes, uint32_t *stripe_size)
{
/* stripes_long_ARG takes precedence (for lvconvert) */
/* FIXME Cope with relative +/- changes for lvconvert. */
*stripes = arg_uint_value(cmd, arg_is_set(cmd, stripes_long_ARG) ? stripes_long_ARG : stripes_ARG, 1);
*stripe_size = arg_uint_value(cmd, stripesize_ARG, 0);
@@ -1328,7 +1338,7 @@ int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stri
}
}
return _validate_stripe_params(cmd, stripes, stripe_size);
return _validate_stripe_params(cmd, segtype, stripes, stripe_size);
}
static int _validate_cachepool_params(const char *name,
@@ -1746,15 +1756,13 @@ struct processing_handle *init_processing_handle(struct cmd_context *cmd, struct
handle->internal_report_for_select = arg_is_set(cmd, select_ARG);
handle->include_historical_lvs = cmd->include_historical_lvs;
if (!parent_handle) {
if (!report_format_init(cmd, &handle->report_group_type, &handle->report_group,
&handle->log_rh, &handle->log_only,
&handle->saved_log_report_state)) {
if (!parent_handle && !cmd->cmd_report.report_group) {
if (!report_format_init(cmd)) {
dm_pool_free(cmd->mem, handle);
return NULL;
}
} else
handle->saved_log_report_state = log_get_report_state();
cmd->cmd_report.saved_log_report_state = log_get_report_state();
log_set_report_context(LOG_REPORT_CONTEXT_PROCESSING);
return handle;
@@ -1790,19 +1798,17 @@ void destroy_processing_handle(struct cmd_context *cmd, struct processing_handle
if (handle->selection_handle && handle->selection_handle->selection_rh)
dm_report_free(handle->selection_handle->selection_rh);
log_restore_report_state(handle->saved_log_report_state);
log_restore_report_state(cmd->cmd_report.saved_log_report_state);
if (!dm_report_group_destroy(handle->report_group))
stack;
if (handle->log_rh) {
if (cmd->is_interactive) {
/*
* Keep log report if we're interactive so
* we can do further queries on this report.
*/
cmd->log_rh = handle->log_rh;
} else
dm_report_free(handle->log_rh);
if (!cmd->is_interactive) {
if (!dm_report_group_destroy(cmd->cmd_report.report_group))
stack;
cmd->cmd_report.report_group = NULL;
if (cmd->cmd_report.log_rh) {
dm_report_free(cmd->cmd_report.log_rh);
cmd->cmd_report.log_rh = NULL;
}
}
/*
* TODO: think about better alternatives:

View File

@@ -73,11 +73,6 @@ struct processing_handle {
int internal_report_for_select;
int include_historical_lvs;
struct selection_handle *selection_handle;
dm_report_group_type_t report_group_type;
struct dm_report_group *report_group;
struct dm_report *log_rh;
int log_only;
log_report_t saved_log_report_state;
void *custom_handle;
};
@@ -201,8 +196,8 @@ int get_pool_params(struct cmd_context *cmd,
thin_discards_t *discards,
int *zero);
int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
uint32_t *stripe_size);
int get_stripe_params(struct cmd_context *cmd, const struct segment_type *segtype,
uint32_t *stripes, uint32_t *stripe_size);
int get_cache_params(struct cmd_context *cmd,
cache_mode_t *cache_mode,

View File

@@ -331,7 +331,7 @@ static int _move_thins(struct volume_group *vg_from,
data_lv = seg_lv(first_seg(seg->pool_lv), 0);
/* Ignore, if no allocations on PVs of @vg_to */
if (!lv_is_on_pvs(data_lv, &vg_to->pvs) ||
if (!lv_is_on_pvs(data_lv, &vg_to->pvs) &&
(seg->external_lv && !lv_is_on_pvs(seg->external_lv, &vg_to->pvs)))
continue;