Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=88b92d4225b90db82047f…
Commit: 88b92d4225b90db82047f3bac55d8059918e9c1b
Parent: b7885dbb734de97e39dca28a38850cbb623cf57f
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Jun 23 12:19:35 2020 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jun 24 15:01:03 2020 +0200
make: make generate
update
---
conf/example.conf.in | 6 +-
man/lvconvert.8_pregen | 58 ++++++++++++
man/lvcreate.8_pregen | 246 +++++++++++++++++++++++++++++++++++++++++++++----
man/lvs.8_pregen | 4 +
man/vgck.8_pregen | 9 ++
5 files changed, 303 insertions(+), 20 deletions(-)
diff --git a/conf/example.conf.in b/conf/example.conf.in
index 05b085792..a3d8ca380 100644
--- a/conf/example.conf.in
+++ b/conf/example.conf.in
@@ -488,7 +488,7 @@ allocation {
# This configuration option does not have a default value defined.
# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
- # Thin pool metdata and data will always use different PVs.
+ # Thin pool metadata and data will always use different PVs.
thin_pool_metadata_require_separate_pvs = 0
# Configuration option allocation/thin_pool_zero.
@@ -526,6 +526,10 @@ allocation {
# This configuration option has an automatic default value.
# thin_pool_chunk_size_policy = "generic"
+ # Configuration option allocation/zero_metadata.
+ # Zero whole metadata area before use with thin or cache pool.
+ zero_metadata = 1
+
# Configuration option allocation/thin_pool_chunk_size.
# The minimal chunk size in KiB for thin pool volumes.
# Larger chunk sizes may improve performance for plain thin volumes,
diff --git a/man/lvconvert.8_pregen b/man/lvconvert.8_pregen
index 74409848c..37b0a47d2 100644
--- a/man/lvconvert.8_pregen
+++ b/man/lvconvert.8_pregen
@@ -22,6 +22,10 @@ lvconvert - Change logical volume layout
\fB-H\fP|\fB--cache\fP
.ad b
.br
+.ad l
+ \fB--cachedevice\fP \fIPV\fP
+.ad b
+.br
.ad l
\fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP
.ad b
@@ -42,6 +46,10 @@ lvconvert - Change logical volume layout
\fB--cachesettings\fP \fIString\fP
.ad b
.br
+.ad l
+ \fB--cachesize\fP \fISize\fP[m|UNIT]
+.ad b
+.br
.ad l
\fB--cachevol\fP \fILV\fP
.ad b
@@ -738,6 +746,44 @@ Attach a cache to an LV, converts the LV to type cache.
.br
-
+Add a writecache to an LV, using a specified cache device.
+.br
+.P
+\fBlvconvert\fP \fB--type\fP \fBwritecache\fP \fB--cachedevice\fP \fIPV\fP \fILV\fP
+.br
+.RS 4
+.ad l
+[ \fB--cachesize\fP \fISize\fP[m|UNIT] ]
+.ad b
+.br
+.ad l
+[ \fB--cachesettings\fP \fIString\fP ]
+.ad b
+.br
+[ COMMON_OPTIONS ]
+.RE
+.br
+-
+
+Add a cache to an LV, using a specified cache device.
+.br
+.P
+\fBlvconvert\fP \fB--type\fP \fBcache\fP \fB--cachedevice\fP \fIPV\fP \fILV\fP
+.br
+.RS 4
+.ad l
+[ \fB--cachesize\fP \fISize\fP[m|UNIT] ]
+.ad b
+.br
+.ad l
+[ \fB--cachesettings\fP \fIString\fP ]
+.ad b
+.br
+[ COMMON_OPTIONS ]
+.RE
+.br
+-
+
Convert LV to type thin-pool.
.br
.P
@@ -1135,6 +1181,12 @@ See \fBlvmcache\fP(7) for more information about LVM caching.
.ad b
.HP
.ad l
+\fB--cachedevice\fP \fIPV\fP
+.br
+The name of a device to use for a cache.
+.ad b
+.HP
+.ad l
\fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP
.br
Specifies the cache metadata format used by cache target.
@@ -1182,6 +1234,12 @@ See \fBlvmcache\fP(7) for more information.
.ad b
.HP
.ad l
+\fB--cachesize\fP \fISize\fP[m|UNIT]
+.br
+The size of cache to use.
+.ad b
+.HP
+.ad l
\fB--cachevol\fP \fILV\fP
.br
The name of a cache volume.
diff --git a/man/lvcreate.8_pregen b/man/lvcreate.8_pregen
index be8e78389..ee6903431 100644
--- a/man/lvcreate.8_pregen
+++ b/man/lvcreate.8_pregen
@@ -30,6 +30,10 @@ lvcreate - Create a logical volume
\fB-H\fP|\fB--cache\fP
.ad b
.br
+.ad l
+ \fB--cachedevice\fP \fIPV\fP
+.ad b
+.br
.ad l
\fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP
.ad b
@@ -50,6 +54,14 @@ lvcreate - Create a logical volume
\fB--cachesettings\fP \fIString\fP
.ad b
.br
+.ad l
+ \fB--cachesize\fP \fISize\fP[m|UNIT]
+.ad b
+.br
+.ad l
+ \fB--cachevol\fP \fILV\fP
+.ad b
+.br
.ad l
\fB-c\fP|\fB--chunksize\fP \fISize\fP[k|UNIT]
.ad b
@@ -816,11 +828,9 @@ where the new thin pool is named by the --thinpool arg.
.RE
-
-Create a cache LV, first creating a new origin LV,
+Create a new LV, then attach the specified cachepool
.br
-then combining it with the existing cache pool named
-.br
-by the --cachepool arg.
+which converts the new LV to type cache.
.br
.P
\fBlvcreate\fP \fB--type\fP \fBcache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT]
@@ -881,6 +891,190 @@ by the --cachepool arg.
.RE
-
+Create a new LV, then attach the specified cachevol
+.br
+which converts the new LV to type cache.
+.br
+.P
+\fBlvcreate\fP \fB--type\fP \fBcache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT]
+.RS 5
+ \fB--cachevol\fP \fILV\fP \fIVG\fP
+.RE
+.br
+.RS 4
+.ad l
+[ \fB-l\fP|\fB--extents\fP \fINumber\fP[PERCENT] ]
+.ad b
+.br
+.ad l
+[ \fB-c\fP|\fB--chunksize\fP \fISize\fP[k|UNIT] ]
+.ad b
+.br
+.ad l
+[ \fB-i\fP|\fB--stripes\fP \fINumber\fP ]
+.ad b
+.br
+.ad l
+[ \fB-I\fP|\fB--stripesize\fP \fISize\fP[k|UNIT] ]
+.ad b
+.br
+.ad l
+[ \fB--cachemode\fP \fBwritethrough\fP|\fBwriteback\fP|\fBpassthrough\fP ]
+.ad b
+.br
+.ad l
+[ \fB--cachepolicy\fP \fIString\fP ]
+.ad b
+.br
+.ad l
+[ \fB--cachesettings\fP \fIString\fP ]
+.ad b
+.br
+.ad l
+[ \fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP ]
+.ad b
+.br
+[ COMMON_OPTIONS ]
+.RE
+.br
+.RS 4
+[ \fIPV\fP ... ]
+.RE
+-
+
+Create a new LV, then attach a cachevol created from
+.br
+the specified cache device, which converts the
+.br
+new LV to type cache.
+.br
+.P
+\fBlvcreate\fP \fB--type\fP \fBcache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT]
+.RS 5
+ \fB--cachedevice\fP \fIPV\fP \fIVG\fP
+.RE
+.br
+.RS 4
+.ad l
+[ \fB-l\fP|\fB--extents\fP \fINumber\fP[PERCENT] ]
+.ad b
+.br
+.ad l
+[ \fB-c\fP|\fB--chunksize\fP \fISize\fP[k|UNIT] ]
+.ad b
+.br
+.ad l
+[ \fB-i\fP|\fB--stripes\fP \fINumber\fP ]
+.ad b
+.br
+.ad l
+[ \fB-I\fP|\fB--stripesize\fP \fISize\fP[k|UNIT] ]
+.ad b
+.br
+.ad l
+[ \fB--cachemode\fP \fBwritethrough\fP|\fBwriteback\fP|\fBpassthrough\fP ]
+.ad b
+.br
+.ad l
+[ \fB--cachepolicy\fP \fIString\fP ]
+.ad b
+.br
+.ad l
+[ \fB--cachesettings\fP \fIString\fP ]
+.ad b
+.br
+.ad l
+[ \fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP ]
+.ad b
+.br
+.ad l
+[ \fB--cachesize\fP \fISize\fP[m|UNIT] ]
+.ad b
+.br
+[ COMMON_OPTIONS ]
+.RE
+.br
+.RS 4
+[ \fIPV\fP ... ]
+.RE
+-
+
+Create a new LV, then attach the specified cachevol
+.br
+which converts the new LV to type writecache.
+.br
+.P
+\fBlvcreate\fP \fB--type\fP \fBwritecache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT]
+.RS 5
+ \fB--cachevol\fP \fILV\fP \fIVG\fP
+.RE
+.br
+.RS 4
+.ad l
+[ \fB-l\fP|\fB--extents\fP \fINumber\fP[PERCENT] ]
+.ad b
+.br
+.ad l
+[ \fB-i\fP|\fB--stripes\fP \fINumber\fP ]
+.ad b
+.br
+.ad l
+[ \fB-I\fP|\fB--stripesize\fP \fISize\fP[k|UNIT] ]
+.ad b
+.br
+.ad l
+[ \fB--cachesettings\fP \fIString\fP ]
+.ad b
+.br
+[ COMMON_OPTIONS ]
+.RE
+.br
+.RS 4
+[ \fIPV\fP ... ]
+.RE
+-
+
+Create a new LV, then attach a cachevol created from
+.br
+the specified cache device, which converts the
+.br
+new LV to type writecache.
+.br
+.P
+\fBlvcreate\fP \fB--type\fP \fBwritecache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT]
+.RS 5
+ \fB--cachedevice\fP \fIPV\fP \fIVG\fP
+.RE
+.br
+.RS 4
+.ad l
+[ \fB-l\fP|\fB--extents\fP \fINumber\fP[PERCENT] ]
+.ad b
+.br
+.ad l
+[ \fB-i\fP|\fB--stripes\fP \fINumber\fP ]
+.ad b
+.br
+.ad l
+[ \fB-I\fP|\fB--stripesize\fP \fISize\fP[k|UNIT] ]
+.ad b
+.br
+.ad l
+[ \fB--cachesize\fP \fISize\fP[m|UNIT] ]
+.ad b
+.br
+.ad l
+[ \fB--cachesettings\fP \fIString\fP ]
+.ad b
+.br
+[ COMMON_OPTIONS ]
+.RE
+.br
+.RS 4
+[ \fIPV\fP ... ]
+.RE
+-
+
Common options for command:
.
.RS 4
@@ -1091,6 +1285,12 @@ See \fBlvmcache\fP(7) for more information about LVM caching.
.ad b
.HP
.ad l
+\fB--cachedevice\fP \fIPV\fP
+.br
+The name of a device to use for a cache.
+.ad b
+.HP
+.ad l
\fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP
.br
Specifies the cache metadata format used by cache target.
@@ -1138,6 +1338,18 @@ See \fBlvmcache\fP(7) for more information.
.ad b
.HP
.ad l
+\fB--cachesize\fP \fISize\fP[m|UNIT]
+.br
+The size of cache to use.
+.ad b
+.HP
+.ad l
+\fB--cachevol\fP \fILV\fP
+.br
+The name of a cache volume.
+.ad b
+.HP
+.ad l
\fB-c\fP|\fB--chunksize\fP \fISize\fP[k|UNIT]
.br
The size of chunks in a snapshot, cache pool or thin pool.
@@ -2659,11 +2871,11 @@ config setting sparse_segtype_default.
.RE
-
-Create a cache LV, first creating a new origin LV,
+Create a new LV, then attach the specified cachepool
.br
-then combining it with the existing cache pool named
+which converts the new LV to type cache
.br
-by the --cachepool arg (variant, infers --type cache).
+(variant, infers --type cache.)
.br
.P
\fBlvcreate\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT] \fB--cachepool\fP \fILV\fP\fI_cachepool\fP \fIVG\fP
@@ -2717,11 +2929,11 @@ by the --cachepool arg (variant, infers --type cache).
.RE
-
-Create a cache LV, first creating a new origin LV,
+Create a new LV, then attach the specified cachepool
.br
-then combining it with the existing cache pool named
+which converts the new LV to type cache.
.br
-in the first arg (variant, also use --cachepool).
+(variant, also use --cachepool).
.br
.P
\fBlvcreate\fP \fB--type\fP \fBcache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT] \fILV\fP\fI_cachepool\fP
@@ -2779,19 +2991,15 @@ in the first arg (variant, also use --cachepool).
.RE
-
-When LV is a cache pool, create a cache LV,
-.br
-first creating a new origin LV, then combining it with
-.br
-the existing cache pool named in the first arg
+When the LV arg is a cachepool, then create a new LV and
.br
-(variant, infers --type cache, also use --cachepool).
+attach the cachepool arg to it.
.br
-When LV is not a cache pool, convert the specified LV
+(variant, use --type cache and --cachepool.)
.br
-to type cache after creating a new cache pool LV to use
+When the LV arg is not a cachepool, then create a new cachepool
.br
-(use lvconvert).
+and attach it to the LV arg (alternative, use lvconvert.)
.br
.P
\fBlvcreate\fP \fB-H\fP|\fB--cache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT] \fILV\fP
diff --git a/man/lvs.8_pregen b/man/lvs.8_pregen
index 8c3091dee..8aea3566a 100644
--- a/man/lvs.8_pregen
+++ b/man/lvs.8_pregen
@@ -577,6 +577,10 @@ Related to Thin Logical Volumes: (F)ailed.
.br
(F)ailed is set when related thin pool enters Failed state and no further I/O
is permitted at all.
+.IP
+Related to writecache logical volumes: (E)rror.
+.br
+(E)rror is set dm-writecache reports an error.
.IP 10 3
s(k)ip activation: this volume is flagged to be skipped during activation.
.SH SEE ALSO
diff --git a/man/vgck.8_pregen b/man/vgck.8_pregen
index a66de5d7f..2a1ec2364 100644
--- a/man/vgck.8_pregen
+++ b/man/vgck.8_pregen
@@ -199,6 +199,15 @@ back metadata it believes has changed but hasn't.
\fB--updatemetadata\fP
.br
Update VG metadata to correct problems.
+If VG metadata was updated while a PV was missing, and the PV
+reappears with an old version of metadata, then this option
+(or any other command that writes metadata) will update the
+metadata on the previously missing PV. If a PV was removed
+from a VG while it was missing, and the PV reappears, using
+this option will clear the outdated metadata from the previously
+missing PV. If metadata text is damaged on one PV, using this
+option will replace the damaged metadata text. For more severe
+damage, e.g. with headers, see \fBpvck\fP(8).
.ad b
.HP
.ad l
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=b7885dbb734de97e39dca…
Commit: b7885dbb734de97e39dca28a38850cbb623cf57f
Parent: cca2a652d1ac2fa67677e3dca50141efa8e2c1a9
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Jun 23 12:19:54 2020 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jun 24 15:01:03 2020 +0200
man: update cache page
Few more sentences around migration threshold.
---
man/lvmcache.7_main | 55 +++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 51 insertions(+), 4 deletions(-)
diff --git a/man/lvmcache.7_main b/man/lvmcache.7_main
index 244ea1e48..37d0e3359 100644
--- a/man/lvmcache.7_main
+++ b/man/lvmcache.7_main
@@ -129,6 +129,17 @@ attached.
LV VG Attr Type Devices
fast vg -wi------- linear /dev/fast_ssd
main vg -wi------- linear /dev/slow_hhd
+
+To stop caching the main LV and also remove unneeded cache pool,
+use the --uncache:
+
+.nf
+ $ lvconvert --uncache vg/main
+
+ $ lvs -a
+ LV VG Attr Type Devices
+ main vg -wi------- linear /dev/slow_hhd
+
.fi
.SS Create a new LV with caching.
@@ -170,8 +181,10 @@ same fast LV. This option can be used with dm-writecache or dm-cache.
Pass this option a cachepool LV or a standard LV. When using a cache
pool, lvm places cache data and cache metadata on different LVs. The two
-LVs together are called a cache pool. This permits specific placement of
-data and metadata. A cache pool is represented as a special type of LV
+LVs together are called a cache pool. This has a bit better performance
+for dm-cache and permits specific placement and segment type selection
+for data and metadata volumes.
+A cache pool is represented as a special type of LV
that cannot be used directly. If a standard LV is passed with this
option, lvm will first convert it to a cache pool by combining it with
another LV to use for metadata. This option can be used with dm-cache.
@@ -361,11 +374,16 @@ $ lvconvert --type cache --cachevol fast \\
The size of data blocks managed by dm-cache can be specified with the
--chunksize option when caching is started. The default unit is KiB. The
-value must be a multiple of 32KiB between 32KiB and 1GiB.
+value must be a multiple of 32KiB between 32KiB and 1GiB. Cache chunks
+bigger then 512KiB shall be only used when necessary.
Using a chunk size that is too large can result in wasteful use of the
cache, in which small reads and writes cause large sections of an LV to be
-stored in the cache. However, choosing a chunk size that is too small
+stored in the cache. It can also require increasing migration threshold
+which defaults to 2048 sectors (1 MiB). Lvm2 ensures migration threshold is
+at least 8 chunks in size. This may in some cases result in very
+high bandwidth load of transfering data between the cache LV and its
+cache origin LV. However, choosing a chunk size that is too small
can result in more overhead trying to manage the numerous chunks that
become mapped into the cache. Overhead can include both excessive CPU
time searching for chunks, and excessive memory tracking chunks.
@@ -383,6 +401,35 @@ The default value is shown by:
.br
.B lvmconfig --type default allocation/cache_pool_chunk_size
+Checking migration threshold (in sectors) of running cached LV:
+.br
+.B lvs -o+kernel_cache_settings VG/LV
+
+
+.SS dm-cache migration threshold
+
+\&
+
+Migrating data between the origin and cache LV uses bandwidth.
+The user can set a throttle to prevent more than a certain amount of
+migration occurring at any one time. Currently dm-cache is not taking any
+account of normal io traffic going to the devices.
+
+User can set migration threshold via cache policy settings as
+"migration_threshold=<#sectors>" to set the maximum number
+of sectors being migrated, the default being 2048 sectors (1MiB).
+
+Command to set migration threshold to 2MiB (4096 sectors):
+.br
+.B lvcreate --cachepolicy 'migration_threshold=4096' VG/LV
+
+
+Command to display the migration threshold:
+.br
+.B lvs -o+kernel_cache_settings,cache_settings VG/LV
+.br
+.B lvs -o+chunksize VG/LV
+
.SS dm-cache cache policy
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=6eb9eba59bf53101b5148…
Commit: 6eb9eba59bf53101b5148ace3ddaf4140592495f
Parent: 04bba5ea421b02275197bfb16b4d1bbf8879b240
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Jun 24 13:37:23 2020 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jun 24 15:01:03 2020 +0200
bcache: support longer writes
When initiated larger write request, it may have happened, bcache
got out of free chunks - fix the loop, that is supposed to wait
until next free chunk becomes avain available.
---
WHATS_NEW | 1 +
lib/device/bcache.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index c0267b7a3..c6dad99e2 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.03.10 -
=================================
+ Fix running out of free buffers for async writing for larger writes.
Add integrity with raid capability.
Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index a7d805526..7e7e18542 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -950,7 +950,7 @@ static struct block *_new_block(struct bcache *cache, int fd, block_address i, b
struct block *b;
b = _alloc_block(cache);
- while (!b && !dm_list_empty(&cache->clean)) {
+ while (!b) {
b = _find_unused_clean_block(cache);
if (!b) {
if (can_wait) {
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=1fb7a9d9e53cbde38250b…
Commit: 1fb7a9d9e53cbde38250bb9ece72a25191899b78
Parent: 7ea50a47d15dea016f252a5940c6aa5c0d598bb6
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Jun 1 16:22:09 2020 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jun 23 11:32:32 2020 -0500
scanning: optimize by checking text offset and checksum
stable backport of 0c1316cda876849d5d1375d40e8cdc08db37c2b5
which includes a number of extra supporting functions.
In stable, the optimization is only applied to reporting
and display commands, so this change applies only to those
cases.
After the VG lock is taken for vg_read, reread the mda_header
from disk and compare the metadata text offset and checksum
to what was seen during label scan. If it is unchanged, then
the metadata has not changed since the label scan, and the
metadata does not need to be reread under the lock for command
processing. If it is changed, then reread the metadata from disk.
This fixes a problem with the original optimization where lvm
reuses cached data from the label_scan phase for vg_read. This
works if the mda_header and metadata text are both read from
cache, or both read from disk, but in some cases the mda_header
could have been dropped from the cache and read from disk, while
the metadata blocks remained in the cache and were not read from
disk. If in addition to this, another concurrent command happened
to update the metadata between the label_scan and vg_read, then
the new mda_header from disk would refer to cached blocks that did
not contain the new metadata text. This would cause the lvm command
report an error about invalid metadata.
---
lib/cache/lvmcache.c | 24 +++++++++
lib/cache/lvmcache.h | 4 ++
lib/device/bcache-utils.c | 15 ++++++
lib/device/bcache.h | 1 +
lib/format_text/format-text.c | 16 +++++-
lib/format_text/layout.h | 2 +-
lib/format_text/text_label.c | 2 +-
lib/label/label.c | 5 ++
lib/label/label.h | 1 +
lib/metadata/metadata.c | 117 +++++++++++++++++++++++++++++++++++++++++-
lib/metadata/metadata.h | 4 +-
11 files changed, 186 insertions(+), 5 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index c12ec2b0c..ed605dc0f 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -3064,3 +3064,27 @@ uint64_t lvmcache_max_metadata_size(void)
return _max_metadata_size;
}
+void lvmcache_get_mdas(struct cmd_context *cmd,
+ const char *vgname, const char *vgid,
+ struct dm_list *mda_list)
+{
+ struct lvmcache_vginfo *vginfo;
+ struct lvmcache_info *info;
+ struct mda_list *mdal;
+ struct metadata_area *mda, *mda2;
+
+ if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) {
+ log_error(INTERNAL_ERROR "lvmcache_get_mdas no vginfo %s", vgname);
+ return;
+ }
+
+ dm_list_iterate_items(info, &vginfo->infos) {
+ dm_list_iterate_items_safe(mda, mda2, &info->mdas) {
+ if (!(mdal = dm_zalloc(sizeof(*mdal))))
+ continue;
+ mdal->mda = mda;
+ dm_list_add(mda_list, &mdal->list);
+ }
+ }
+}
+
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index f43678507..541e8bee5 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -228,4 +228,8 @@ void lvmcache_drop_saved_vgid(const char *vgid);
uint64_t lvmcache_max_metadata_size(void);
void lvmcache_save_metadata_size(uint64_t val);
+void lvmcache_get_mdas(struct cmd_context *cmd,
+ const char *vgname, const char *vgid,
+ struct dm_list *mda_list);
+
#endif
diff --git a/lib/device/bcache-utils.c b/lib/device/bcache-utils.c
index a533a66ee..2f0b01d13 100644
--- a/lib/device/bcache-utils.c
+++ b/lib/device/bcache-utils.c
@@ -79,6 +79,21 @@ bool bcache_read_bytes(struct bcache *cache, int fd, uint64_t start, size_t len,
return true;
}
+bool bcache_invalidate_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
+{
+ block_address bb, be;
+ bool result = true;
+
+ byte_range_to_block_range(cache, start, len, &bb, &be);
+
+ for (; bb != be; bb++) {
+ if (!bcache_invalidate(cache, fd, bb))
+ result = false;
+ }
+
+ return result;
+}
+
//----------------------------------------------------------------
// Writing bytes and zeroing bytes are very similar, so we factor out
diff --git a/lib/device/bcache.h b/lib/device/bcache.h
index c5e6da1ad..e22755ed5 100644
--- a/lib/device/bcache.h
+++ b/lib/device/bcache.h
@@ -163,6 +163,7 @@ bool bcache_read_bytes(struct bcache *cache, int fd, uint64_t start, size_t len,
bool bcache_write_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, void *data);
bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len);
bool bcache_set_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, uint8_t val);
+bool bcache_invalidate_bytes(struct bcache *cache, int fd, uint64_t start, size_t len);
void bcache_set_last_byte(struct bcache *cache, int fd, uint64_t offset, int sector_size);
void bcache_unset_last_byte(struct bcache *cache, int fd);
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 026f93a13..225d6424c 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -1199,6 +1199,7 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
}
int read_metadata_location_summary(const struct format_type *fmt,
+ struct metadata_area *mda,
struct mda_header *mdah, int primary_mda, struct device_area *dev_area,
struct lvmcache_vgsummary *vgsummary, uint64_t *mda_free_sectors)
{
@@ -1251,6 +1252,19 @@ int read_metadata_location_summary(const struct format_type *fmt,
return 0;
}
+ /*
+ * This function is used to read the vg summary during label scan.
+ * Save the text start location and checksum during scan. After the VG
+ * lock is acquired in vg_read, we can reread the mda_header, and
+ * compare rlocn->offset,checksum to what was saved during scan. If
+ * unchanged, it means that the metadata was not changed between scan
+ * and the read.
+ */
+ if (mda) {
+ mda->scan_text_offset = rlocn->offset;
+ mda->scan_text_checksum = rlocn->checksum;
+ }
+
/* We found a VG - now check the metadata */
if (rlocn->offset + rlocn->size > mdah->size)
wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
@@ -1374,7 +1388,7 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
continue;
}
- if (read_metadata_location_summary(fmt, mdah, 0, &rl->dev_area, &vgsummary, NULL)) {
+ if (read_metadata_location_summary(fmt, NULL, mdah, 0, &rl->dev_area, &vgsummary, NULL)) {
vg = _vg_read_raw_area(&fid, vgsummary.vgname, &rl->dev_area, NULL, NULL, 0, 0);
if (vg) {
lvmcache_update_vg(vg, 0);
diff --git a/lib/format_text/layout.h b/lib/format_text/layout.h
index 2671bbf02..460195276 100644
--- a/lib/format_text/layout.h
+++ b/lib/format_text/layout.h
@@ -104,7 +104,7 @@ struct mda_context {
#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
#define MDA_ORIGINAL_ALIGNMENT 512 /* Original alignment used for start of VG metadata content */
-int read_metadata_location_summary(const struct format_type *fmt, struct mda_header *mdah, int primary_mda,
+int read_metadata_location_summary(const struct format_type *fmt, struct metadata_area *mda, struct mda_header *mdah, int primary_mda,
struct device_area *dev_area, struct lvmcache_vgsummary *vgsummary,
uint64_t *mda_free_sectors);
diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c
index 7d10e065b..fc8294e3f 100644
--- a/lib/format_text/text_label.c
+++ b/lib/format_text/text_label.c
@@ -345,7 +345,7 @@ static int _read_mda_header_and_metadata(struct metadata_area *mda, void *baton)
return 1;
}
- if (!read_metadata_location_summary(fmt, mdah, mda_is_primary(mda), &mdac->area,
+ if (!read_metadata_location_summary(fmt, mda, mdah, mda_is_primary(mda), &mdac->area,
&vgsummary, &mdac->free_sectors)) {
if (vgsummary.zero_offset)
return 1;
diff --git a/lib/label/label.c b/lib/label/label.c
index 70b793441..8a4b66246 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -1418,6 +1418,11 @@ bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data)
return true;
}
+bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len)
+{
+ return bcache_invalidate_bytes(scan_bcache, dev->bcache_fd, start, len);
+}
+
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len)
{
if (test_mode())
diff --git a/lib/label/label.h b/lib/label/label.h
index 42c9946cb..ea29c84ee 100644
--- a/lib/label/label.h
+++ b/lib/label/label.h
@@ -128,6 +128,7 @@ bool dev_read_bytes(struct device *dev, uint64_t start, size_t len, void *data);
bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data);
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len);
bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val);
+bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len);
void dev_set_last_byte(struct device *dev, uint64_t offset);
void dev_unset_last_byte(struct device *dev);
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 666ad7823..0bdbda69b 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -33,6 +33,8 @@
#include "lvmlockd.h"
#include "time.h"
#include "lvmnotify.h"
+#include "format_text/format-text.h"
+#include "format_text/layout.h"
#include <math.h>
#include <sys/param.h>
@@ -3758,6 +3760,118 @@ out:
return r;
}
+/*
+ * Reread an mda_header. If the text offset is the same as was seen and saved
+ * by label scan, it means the metadata is unchanged and we do not need to
+ * reread metadata.
+ *
+ * This is used to ensure that the metadata seen during scan still matches
+ * what's on disk. If the scan data still matches what's on disk we don't
+ * need to reread the metadata from disk. When we read the metadata from
+ * bcache it may come from the cache or from disk again if the cache has
+ * dropped it.
+ */
+
+static bool _scan_text_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid)
+{
+ struct dm_list mda_list;
+ struct mda_list *mdal, *safe;
+ struct metadata_area *mda;
+ struct mda_context *mdac;
+ struct device_area *area;
+ struct mda_header *mdah;
+ struct raw_locn *rlocn;
+ struct device *dev;
+ bool ret = true;
+
+ /*
+ * if cmd->can_use_one_scan, check one mda_header is unchanged,
+ * else check that all mda_headers are unchanged.
+ */
+
+ dm_list_init(&mda_list);
+
+ lvmcache_get_mdas(cmd, vgname, vgid, &mda_list);
+
+ dm_list_iterate_items(mdal, &mda_list) {
+ mda = mdal->mda;
+
+ if (!mda->scan_text_offset)
+ continue;
+
+ if (!mda_is_primary(mda))
+ continue;
+
+ if (!(dev = mda_get_device(mda))) {
+ log_debug("rescan for text mismatch - no mda dev");
+ goto out;
+ }
+
+ mdac = mda->metadata_locn;
+ area = &mdac->area;
+
+ /*
+ * Invalidate mda_header in bcache so it will be reread from disk.
+ */
+ if (!dev_invalidate_bytes(dev, 4096, 512)) {
+ log_debug("rescan for text mismatch - cannot invalidate");
+ goto out;
+ }
+
+ if (!(mdah = raw_read_mda_header(cmd->fmt, area, 1))) {
+ log_debug("rescan for text mismatch - no mda header");
+ goto out;
+ }
+
+ rlocn = mdah->raw_locns;
+
+ if (rlocn->checksum != mda->scan_text_checksum) {
+ log_debug("rescan for text checksum mismatch on %s - now %x prev %x offset now %llu prev %llu",
+ dev_name(dev),
+ rlocn->checksum, mda->scan_text_checksum,
+ (unsigned long long)rlocn->offset,
+ (unsigned long long)mda->scan_text_offset);
+ } else if (rlocn->offset != mda->scan_text_offset) {
+ log_debug("rescan for text offset mismatch on %s - now %llu prev %llu checksum %x",
+ dev_name(dev),
+ (unsigned long long)rlocn->offset,
+ (unsigned long long)mda->scan_text_offset,
+ rlocn->checksum);
+ } else {
+ /* the common case where fields match and no rescan needed */
+ ret = false;
+ }
+
+ dm_pool_free(cmd->mem, mdah);
+
+ /* For can_use_one_scan commands, return result from checking one mda. */
+ if (cmd->can_use_one_scan)
+ goto out;
+
+ /* For other commands, return mismatch immediately. */
+ if (ret)
+ goto_out;
+ }
+
+ if (ret) {
+ /* shouldn't happen */
+ log_debug("rescan for text mismatch - no mdas");
+ goto out;
+ }
+out:
+ if (!ret)
+ log_debug("rescan skipped - unchanged offset %llu checksum %x",
+ (unsigned long long)mda->scan_text_offset,
+ mda->scan_text_checksum);
+
+ dm_list_iterate_items_safe(mdal, safe, &mda_list) {
+ dm_list_del(&mdal->list);
+ free(mdal);
+ }
+
+ return ret;
+}
+
/* Caller sets consistent to 1 if it's safe for vg_read_internal to correct
* inconsistent metadata on disk (i.e. the VG write lock is held).
* This guarantees only consistent metadata is returned.
@@ -3902,7 +4016,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
* lock is taken prior to the label scan, and still held here,
* we can also skip the rescan in that case.
*/
- if (!cmd->can_use_one_scan || lvmcache_scan_mismatch(cmd, vgname, vgid)) {
+ if (!cmd->can_use_one_scan ||
+ lvmcache_scan_mismatch(cmd, vgname, vgid) || _scan_text_mismatch(cmd, vgname, vgid)) {
/* the skip rescan special case is for clvmd vg_read_by_vgid */
/* FIXME: this is not a warn flag, pass this differently */
if (warn_flags & SKIP_RESCAN)
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index f8083e5a8..96bbb5690 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -173,6 +173,8 @@ struct metadata_area {
struct metadata_area_ops *ops;
void *metadata_locn;
uint32_t status;
+ uint64_t scan_text_offset; /* rlocn->offset seen during scan */
+ uint32_t scan_text_checksum; /* rlocn->checksum seen during scan */
};
struct metadata_area *mda_copy(struct dm_pool *mem,
struct metadata_area *mda);
@@ -234,7 +236,7 @@ struct name_list {
struct mda_list {
struct dm_list list;
- struct device_area mda;
+ struct metadata_area *mda;
};
struct peg_list {
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=3bd9d81b29fb8ba490d87…
Commit: 3bd9d81b29fb8ba490d87b3557861bf00047855d
Parent: ae5634a8be3eedb556325a4b81540896fa6cac16
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Jun 11 17:01:01 2020 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Jun 22 11:24:02 2020 -0500
man: lvmcache info about cachedevice usage
---
man/lvmcache.7_main | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/man/lvmcache.7_main b/man/lvmcache.7_main
index 425904e4a..244ea1e48 100644
--- a/man/lvmcache.7_main
+++ b/man/lvmcache.7_main
@@ -34,8 +34,6 @@ LVM refers to this using the LV type \fBwritecache\fP.
.SH USAGE
-Both kinds of caching use similar lvm commands:
-
.B 1. Identify main LV that needs caching
The main LV may already exist, and is located on larger, slower devices.
@@ -133,6 +131,22 @@ attached.
main vg -wi------- linear /dev/slow_hhd
.fi
+.SS Create a new LV with caching.
+
+A new LV can be created with caching attached at the time of creation
+using the following command:
+
+.nf
+$ lvcreate --type cache|writecache -n Name -L Size
+ --cachedevice /dev/fast_ssd vg /dev/slow_hhd
+.fi
+
+The main LV is created with the specified Name and Size from the slow_hhd.
+A hidden fast LV is created on the fast_ssd and is then attached to the
+new main LV. If the fast_ssd is unused, the entire disk will be used as
+the cache unless the --cachesize option is used to specify a size for the
+fast LV. The --cachedevice option can be repeated to use multiple disks
+for the fast LV.
.SH OPTIONS
@@ -162,6 +176,18 @@ that cannot be used directly. If a standard LV is passed with this
option, lvm will first convert it to a cache pool by combining it with
another LV to use for metadata. This option can be used with dm-cache.
+.B --cachedevice
+.I PV
+.br
+
+This option can be used in place of --cachevol, in which case a cachevol
+LV will be created using the specified device. This option can be
+repeated to create a cachevol using multiple devices, or a tag name can be
+specified in which case the cachevol will be created using any of the
+devices with the given tag. If a named cache device is unused, the entire
+device will be used to create the cachevol. To create a cachevol of a
+specific size from the cache devices, include the --cachesize option.
+
\&
.SS dm-cache block size
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=2aed2a41f7602e9168613…
Commit: 2aed2a41f7602e9168613a0c37d8dd557e7dba9b
Parent: 21b37964eb88d404998e37acae5530ec102a2116
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Apr 10 13:17:37 2020 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jun 16 13:46:51 2020 -0500
lvcreate: new cache or writecache lv with single command
To create a new cache or writecache LV with a single command:
lvcreate --type cache|writecache
-n Name -L Size --cachedevice PVfast VG [PVslow ...]
- A new main linear|striped LV is created as usual, using the
specified -n Name and -L Size, and using the optionally
specified PVslow devices.
- Then, a new cachevol LV is created internally, using PVfast
specified by the cachedevice option.
- Then, the cachevol is attached to the main LV, converting the
main LV to type cache|writecache.
Include --cachesize Size to specify the size of cache|writecache
to create from the specified --cachedevice PVs, otherwise the
entire cachedevice PV is used. The --cachedevice option can be
repeated to create the cache from multiple devices, or the
cachedevice option can contain a tag name specifying a set of PVs
to allocate the cache from.
To create a new cache or writecache LV with a single command
using an existing cachevol LV:
lvcreate --type cache|writecache
-n Name -L Size --cachevol LVfast VG [PVslow ...]
- A new main linear|striped LV is created as usual, using the
specified -n Name and -L Size, and using the optionally
specified PVslow devices.
- Then, the cachevol LVfast is attached to the main LV, converting
the main LV to type cache|writecache.
In cases where more advanced types (for the main LV or cachevol LV)
are needed, they should be created independently and then combined
with lvconvert.
Example
-------
user creates a new VG with one slow device and one fast device:
$ vgcreate vg /dev/slow1 /dev/fast1
user creates a new 8G main LV on /dev/slow1 that uses all of
/dev/fast1 as a writecache:
$ lvcreate --type writecache --cachedevice /dev/fast1
-n main -L 8G vg /dev/slow1
Example
-------
user creates a new VG with two slow devs and two fast devs:
$ vgcreate vg /dev/slow1 /dev/slow2 /dev/fast1 /dev/fast2
user creates a new 8G main LV on /dev/slow1 and /dev/slow2
that uses all of /dev/fast1 and /dev/fast2 as a writecache:
$ lvcreate --type writecache --cachedevice /dev/fast1 --cachedevice /dev/fast2
-n main -L 8G vg /dev/slow1 /dev/slow2
Example
-------
A user has several slow devices and several fast devices in their VG,
the slow devs have tag @slow, the fast devs have tag @fast.
user creates a new 8G main LV on the slow devs with a
2G writecache on the fast devs:
$ lvcreate --type writecache -n main -L 8G
--cachedevice @fast --cachesize 2G vg @slow
---
lib/metadata/metadata-exported.h | 1 +
tools/args.h | 2 +-
tools/command-lines.in | 126 ++++++++++++++++-------------
tools/command.c | 3 +
tools/lvconvert.c | 166 ++++++++++++++++++++++-----------------
tools/lvcreate.c | 153 +++++++++++++++++++++++++++++++++++-
tools/lvmcmdline.c | 6 ++
tools/tools.h | 11 +++
8 files changed, 341 insertions(+), 127 deletions(-)
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 0d6be136b..0cc5f37a0 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -954,6 +954,7 @@ struct lvcreate_params {
int thin_chunk_size_calc_policy;
unsigned suppress_zero_warn : 1;
unsigned needs_lockd_init : 1;
+ unsigned ignore_type : 1;
const char *vg_name; /* only-used when VG is not yet opened (in /tools) */
const char *lv_name; /* all */
diff --git a/tools/args.h b/tools/args.h
index c69a0ecce..3a7e5d488 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -126,7 +126,7 @@ arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0,
arg(cachevol_ARG, '\0', "cachevol", lv_VAL, 0, 0,
"The name of a cache volume.\n")
-arg(cachedevice_ARG, '\0', "cachedevice", pv_VAL, 0, 0,
+arg(cachedevice_ARG, '\0', "cachedevice", pv_VAL, ARG_GROUPABLE, 0,
"The name of a device to use for a cache.\n")
arg(cachesize_ARG, '\0', "cachesize", sizemb_VAL, 0, 0,
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 8d389b665..0051b77b5 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -1219,87 +1219,107 @@ lvcreate --type cache --size SizeMB --cachepool LV_cachepool VG
OO: --cache, OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
-ID: lvcreate_cache_vol_with_new_origin
-DESC: Create a cache LV, first creating a new origin LV,
-DESC: then combining it with the existing cache pool named
-DESC: by the --cachepool arg.
+ID: lvcreate_and_attach_cachepool
+DESC: Create a new LV, then attach the specified cachepool
+DESC: which converts the new LV to type cache.
# alternate form of lvcreate --type cache
+# (omits the --type cache option which is inferred)
lvcreate --size SizeMB --cachepool LV_cachepool VG
OO: --type cache, --cache, OO_LVCREATE_CACHE, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
-ID: lvcreate_cache_vol_with_new_origin
-DESC: Create a cache LV, first creating a new origin LV,
-DESC: then combining it with the existing cache pool named
-DESC: by the --cachepool arg (variant, infers --type cache).
+ID: lvcreate_and_attach_cachepool_v2
+DESC: Create a new LV, then attach the specified cachepool
+DESC: which converts the new LV to type cache
+DESC: (variant, infers --type cache.)
FLAGS: SECONDARY_SYNTAX
# alternate form of lvcreate --type cache
+# (moves cachepool from option arg to position arg,
+# dropping the normal VG position arg)
lvcreate --type cache --size SizeMB LV_cachepool
OO: --cache, OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
-ID: lvcreate_cache_vol_with_new_origin
-DESC: Create a cache LV, first creating a new origin LV,
-DESC: then combining it with the existing cache pool named
-DESC: in the first arg (variant, also use --cachepool).
+ID: lvcreate_and_attach_cachepool_v3
+DESC: Create a new LV, then attach the specified cachepool
+DESC: which converts the new LV to type cache.
+DESC: (variant, also use --cachepool).
FLAGS: SECONDARY_SYNTAX
-# This is a ridiculously crazy command which nobody could
-# understand. It should be be eliminated. It does two different
-# things depending on whether LV in pos 1 is a cachepool LV
-# or not. Both variations are unnecessary.
-#
-# 1. If LV is a cachepool, then it's an alternate form of
-# an already complicated command above.
-#
-# # alternate form for lvcreate_cache_vol_with_new_origin
-# lvcreate --cache --size SizeMB LV_cachepool
-# OO: --type cache, --cache, OO_LVCREATE_CACHE, OO_LVCREATE, --stripes Number, --stripesize SizeKB
-# OP: PV ...
-# ID: lvcreate_cache_vol_with_new_origin
-# DESC: Create a cache LV, first creating a new origin LV,
-# DESC: then combining it with the existing cache pool named
-# DESC: in the first arg (variant, infers --type cache,
-# DESC: also use --cachepool).
-#
-# 2. If LV is not a cachepool, then it's a disguised lvconvert.
-#
-# # FIXME: this should be done by lvconvert, and this command removed
-# lvcreate --type cache --size SizeMB LV
-# OO: OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE
-# OP: PV ...
-# ID: lvcreate_convert_to_cache_vol_with_cachepool
-# DESC: Convert the specified LV to type cache after creating a new
-# DESC: cache pool LV to use (use lvconvert).
+# This command has two different meanings which ought to
+# have separate command defs, but since the syntax is the
+# same for both they have to share one command def with
+# an ambiguous meaning. Which command is performed depends
+# on whether the LV in the first arg position is a
+# cachepool or not (we can't have two different command
+# defs that differ only in the type of LV in the arg position
+# because when parsing commands we don't know the LV type.)
+#
+# 1. An alternate form of lvcreate_and_attach_cachepool_v3
+# this syntax: lvcreate --cache --size SizeMB LV_cachepool
+# is alternative for: lvcreate --type cache --size SizeMB LV_cachepool
+#
+# 2. An alternative to using lvconvert to convert LV to type cache,
+# but in this case the cachepool is created internally and
+# then attached to the LV arg.
#
# Note that stripes are accepted by the first and not by the
# second, but it's not possible to validate this until after
# the LV type is known.
-#
-# So, to define this syntax we have to combine both of
-# those variants, each crazy on it's own, into one
-# ridiculous command.
-# def1: alternate form of lvcreate --type cache, or
-# def2: it should be done by lvconvert.
lvcreate --cache --size SizeMB LV
OO: OO_LVCREATE_CACHE, OO_LVCREATE_POOL, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
-ID: lvcreate_cache_vol_with_new_origin_or_convert_to_cache_vol_with_cachepool
-DESC: When LV is a cache pool, create a cache LV,
-DESC: first creating a new origin LV, then combining it with
-DESC: the existing cache pool named in the first arg
-DESC: (variant, infers --type cache, also use --cachepool).
-DESC: When LV is not a cache pool, convert the specified LV
-DESC: to type cache after creating a new cache pool LV to use
-DESC: (use lvconvert).
+ID: lvcreate_new_plus_old_cachepool_or_lvconvert_old_plus_new_cachepool
+DESC: When the LV arg is a cachepool, then create a new LV and
+DESC: attach the cachepool arg to it.
+DESC: (variant, use --type cache and --cachepool.)
+DESC: When the LV arg is not a cachepool, then create a new cachepool
+DESC: and attach it to the LV arg (alternative, use lvconvert.)
FLAGS: SECONDARY_SYNTAX
---
+# These all create a new origin LV, then forwards to lvconvert
+# which combines it with a cachevol (which already exists or
+# which needs to be created from cachedevice), converting
+# the new LV to type cache or writecache.
+
+lvcreate --type cache --size SizeMB --cachevol LV VG
+OO: OO_LVCREATE, OO_LVCREATE_CACHE, --stripes Number, --stripesize SizeKB
+OP: PV ...
+ID: lvcreate_and_attach_cachevol_for_cache
+DESC: Create a new LV, then attach the specified cachevol
+DESC: which converts the new LV to type cache.
+
+lvcreate --type cache --size SizeMB --cachedevice PV VG
+OO: OO_LVCREATE, OO_LVCREATE_CACHE, --cachesize SizeMB, --stripes Number, --stripesize SizeKB
+OP: PV ...
+ID: lvcreate_and_attach_cachedevice_for_cache
+DESC: Create a new LV, then attach a cachevol created from
+DESC: the specified cache device, which converts the
+DESC: new LV to type cache.
+
+lvcreate --type writecache --size SizeMB --cachevol LV VG
+OO: OO_LVCREATE, --cachesettings String, --stripes Number, --stripesize SizeKB
+OP: PV ...
+ID: lvcreate_and_attach_cachevol_for_writecache
+DESC: Create a new LV, then attach the specified cachevol
+DESC: which converts the new LV to type writecache.
+
+lvcreate --type writecache --size SizeMB --cachedevice PV VG
+OO: OO_LVCREATE, --cachesize SizeMB, --cachesettings String, --stripes Number, --stripesize SizeKB
+OP: PV ...
+ID: lvcreate_and_attach_cachedevice_for_writecache
+DESC: Create a new LV, then attach a cachevol created from
+DESC: the specified cache device, which converts the
+DESC: new LV to type writecache.
+
+---
+
lvdisplay
OO: --aligned, --all, --binary, --colon, --columns,
--configreport ConfigReport, --foreign, --history, --ignorelockingfailure,
diff --git a/tools/command.c b/tools/command.c
index 511dda13d..2d0184941 100644
--- a/tools/command.c
+++ b/tools/command.c
@@ -1420,6 +1420,9 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name)
if (line[0] == '\n')
break;
+ if (!strcmp(line, "---") || !strcmp(line, "--"))
+ continue;
+
if ((n = strchr(line, '\n')))
*n = '\0';
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 76a9160f3..0155fdbf9 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -4248,18 +4248,25 @@ int lvconvert_to_pool_cmd(struct cmd_context *cmd, int argc, char **argv)
NULL, NULL, &_lvconvert_to_pool_single);
}
+#define MAX_CACHEDEVS 8
+
static int _lv_create_cachevol(struct cmd_context *cmd,
struct volume_group *vg,
struct logical_volume *lv,
- const char *dev_name,
struct logical_volume **cachevol_lv)
{
char cvname[NAME_LEN];
- struct device *dev_fast;
struct dm_list *use_pvh;
- uint64_t cache_size_sectors;
- struct logical_volume *cachevol;
struct pv_list *pvl;
+ char *dev_name;
+ struct device *dev_fast;
+ char *dev_argv[MAX_CACHEDEVS];
+ int dev_argc = 0;
+ uint64_t cache_size_sectors = 0;
+ uint64_t full_size_sectors = 0;
+ uint64_t pv_size_sectors;
+ struct logical_volume *cachevol;
+ struct arg_value_group_list *group;
struct lvcreate_params lp = {
.activate = CHANGE_AN,
.alloc = ALLOC_INHERIT,
@@ -4275,48 +4282,86 @@ static int _lv_create_cachevol(struct cmd_context *cmd,
.suppress_zero_warn = 1,
};
- if (dm_snprintf(cvname, NAME_LEN, "%s_cache", lv->name) < 0) {
- log_error("Failed to create cachevol LV name.");
- return 0;
- }
+ /*
+ * If cache size is not set, and all cachedevice's are unused,
+ * then the cache size is the sum of all cachedevice sizes.
+ */
+ cache_size_sectors = arg_uint64_value(cmd, cachesize_ARG, 0);
- if (!(dev_fast = dev_cache_get(cmd, dev_name, cmd->filter))) {
- log_error("Device %s not found.", dev_name);
- return 0;
- }
+ dm_list_iterate_items(group, &cmd->arg_value_groups) {
+ if (!grouped_arg_is_set(group->arg_values, cachedevice_ARG))
+ continue;
- if (!(pvl = find_pv_in_vg(vg, dev_name))) {
- log_error("PV %s not found in VG.", dev_name);
- return 0;
- }
+ if (!(dev_name = (char *)grouped_arg_str_value(group->arg_values, cachedevice_ARG, NULL)))
+ break;
- /*
- * If fast_dev is used in the VG, then require a cachesize to allocate
- * from it. If fast_dev is not used in the VG, then prompt asking if
- * the entire dev should be used.
- */
- if (!(cache_size_sectors = arg_uint64_value(cmd, cachesize_ARG, 0))) {
- if (pvl->pv->pe_alloc_count) {
+ if (dev_name[0] == '@') {
+ if (!cache_size_sectors) {
+ log_error("With tag as cachedevice, --cachesize is required.");
+ return 0;
+ }
+ goto add_dev_arg;
+ }
+
+ if (!(dev_fast = dev_cache_get(cmd, dev_name, cmd->filter))) {
+ log_error("Device %s not found.", dev_name);
+ return 0;
+ }
+
+ if (!(pvl = find_pv_in_vg(vg, dev_name))) {
+ log_error("PV %s not found in VG.", dev_name);
+ return 0;
+ }
+
+ /*
+ * If the dev is used in the VG, then require a cachesize to allocate
+ * from it. If it is not used in the VG, then prompt asking if the
+ * entire dev should be used.
+ */
+ if (!cache_size_sectors && pvl->pv->pe_alloc_count) {
log_error("PV %s is in use, --cachesize is required.", dev_name);
return 0;
}
- cache_size_sectors = (pvl->pv->pe_count * vg->extent_size);
+ if (!cache_size_sectors) {
+ pv_size_sectors = (pvl->pv->pe_count * vg->extent_size);
- if (!arg_is_set(cmd, yes_ARG) &&
- yes_no_prompt("Use all %s from %s for cache? [y/n]: ",
- display_size(cmd, cache_size_sectors), dev_name) == 'n') {
- log_print("Use --cachesize SizeMB to use a part of the cachedevice.");
- log_error("Conversion aborted.");
+ if (!arg_is_set(cmd, yes_ARG) &&
+ yes_no_prompt("Use all %s from %s for cache? [y/n]: ",
+ display_size(cmd, pv_size_sectors), dev_name) == 'n') {
+ log_print("Use --cachesize SizeMB to use a part of the cachedevice.");
+ log_error("Conversion aborted.");
+ return 0;
+ }
+ full_size_sectors += pv_size_sectors;
+ }
+ add_dev_arg:
+ if (dev_argc >= MAX_CACHEDEVS) {
+ log_error("Cannot allocate from more than %u cache devices.", MAX_CACHEDEVS);
return 0;
}
+
+ dev_argv[dev_argc++] = dev_name;
+ }
+
+ if (!cache_size_sectors)
+ cache_size_sectors = full_size_sectors;
+
+ if (!dev_argc) {
+ log_error("No cachedevice specified to create a cachevol.");
+ return 0;
}
- if (!(use_pvh = create_pv_list(cmd->mem, vg, 1, (char **)&dev_name, 1))) {
+ if (!(use_pvh = create_pv_list(cmd->mem, vg, dev_argc, dev_argv, 1))) {
log_error("cachedevice not found in VG %s.", dev_name);
return 0;
}
+ if (dm_snprintf(cvname, NAME_LEN, "%s_cache", lv->name) < 0) {
+ log_error("Failed to create cachevol LV name.");
+ return 0;
+ }
+
lp.lv_name = cvname;
lp.pvh = use_pvh;
lp.extents = cache_size_sectors / vg->extent_size;
@@ -4338,27 +4383,19 @@ static int _lv_create_cachevol(struct cmd_context *cmd,
return 1;
}
-static int _lvconvert_cachevol_attach_single(struct cmd_context *cmd,
- struct logical_volume *lv,
- struct processing_handle *handle)
+int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle)
{
struct volume_group *vg = lv->vg;
struct logical_volume *lv_fast;
- const char *fast_name, *dev_name;
-
- fast_name = arg_str_value(cmd, cachevol_ARG, NULL);
- dev_name = arg_str_value(cmd, cachedevice_ARG, NULL);
-
- if (!fast_name && !dev_name)
- goto_bad;
-
- if (fast_name && dev_name)
- goto_bad;
+ const char *fast_name;
/*
- * User specifies an existing cachevol to use.
+ * User specifies an existing cachevol to use or a cachedevice
+ * to create a cachevol from.
*/
- if (fast_name) {
+ if ((fast_name = arg_str_value(cmd, cachevol_ARG, NULL))) {
if (!validate_lvname_param(cmd, &vg->name, &fast_name))
goto_bad;
@@ -4385,13 +4422,8 @@ static int _lvconvert_cachevol_attach_single(struct cmd_context *cmd,
if (!lockd_lv(cmd, lv_fast, "ex", 0))
goto_bad;
- }
-
- /*
- * User specifies a device and lvm creates a cachevol on it.
- */
- if (dev_name) {
- if (!_lv_create_cachevol(cmd, vg, lv, dev_name, &lv_fast))
+ } else {
+ if (!_lv_create_cachevol(cmd, vg, lv, &lv_fast))
goto_bad;
}
@@ -5705,7 +5737,7 @@ bad:
return 0;
}
-static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
+int lvconvert_writecache_attach_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
@@ -5713,7 +5745,7 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
struct logical_volume *lv_wcorig;
struct logical_volume *lv_fast;
struct writecache_settings settings;
- const char *fast_name, *dev_name;
+ const char *fast_name;
uint32_t block_size_sectors = 0;
char *lockd_fast_args = NULL;
char *lockd_fast_name = NULL;
@@ -5721,16 +5753,11 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
char cvol_name[NAME_LEN];
int is_active;
- fast_name = arg_str_value(cmd, cachevol_ARG, NULL);
- dev_name = arg_str_value(cmd, cachedevice_ARG, NULL);
-
- if (!fast_name && !dev_name)
- goto_bad;
-
/*
- * User specifies an existing cachevol to use.
+ * User specifies an existing cachevol to use or a cachedevice
+ * to create a cachevol from.
*/
- if (fast_name) {
+ if ((fast_name = arg_str_value(cmd, cachevol_ARG, NULL))) {
if (!validate_lvname_param(cmd, &vg->name, &fast_name))
goto_bad;
@@ -5765,13 +5792,8 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
log_error("Conversion aborted.");
goto bad;
}
- }
-
- /*
- * User specifies a device and lvm creates a cachevol on it.
- */
- if (dev_name) {
- if (!_lv_create_cachevol(cmd, vg, lv, dev_name, &lv_fast))
+ } else {
+ if (!_lv_create_cachevol(cmd, vg, lv, &lv_fast))
goto_bad;
}
@@ -5808,7 +5830,7 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
/* Ensure the LV is not active elsewhere. */
if (!lockd_lv(cmd, lv, "ex", 0))
goto_bad;
- if (!dev_name && !lockd_lv(cmd, lv_fast, "ex", 0))
+ if (fast_name && !lockd_lv(cmd, lv_fast, "ex", 0))
goto_bad;
if (!archive(vg))
@@ -5899,7 +5921,7 @@ int lvconvert_to_writecache_cmd(struct cmd_context *cmd, int argc, char **argv)
cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS;
ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, handle, NULL,
- &_lvconvert_writecache_attach_single);
+ &lvconvert_writecache_attach_single);
destroy_processing_handle(cmd, handle);
@@ -5922,7 +5944,7 @@ int lvconvert_to_cache_with_cachevol_cmd(struct cmd_context *cmd, int argc, char
cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS;
ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, handle, NULL,
- &_lvconvert_cachevol_attach_single);
+ &lvconvert_cachevol_attach_single);
destroy_processing_handle(cmd, handle);
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index 5c978b3cc..3357a08c5 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -766,7 +766,9 @@ static int _lvcreate_params(struct cmd_context *cmd,
*
* Ordering of following type tests is IMPORTANT
*/
- if ((segtype_str = arg_str_value(cmd, type_ARG, NULL))) {
+ if (lp->ignore_type) {
+ segtype_str = SEG_TYPE_NAME_STRIPED;
+ } else if ((segtype_str = arg_str_value(cmd, type_ARG, NULL))) {
lp->type = 1;
if (!strcmp(segtype_str, "linear")) {
segtype_str = "striped";
@@ -1799,3 +1801,152 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
destroy_processing_handle(cmd, handle);
return ret;
}
+
+static int _lvcreate_and_attach_writecache_single(struct cmd_context *cmd,
+ const char *vg_name, struct volume_group *vg, struct processing_handle *handle)
+{
+ struct processing_params *pp = (struct processing_params *) handle->custom_handle;
+ struct lvcreate_params *lp = pp->lp;
+ struct logical_volume *lv;
+ int ret;
+
+ ret = _lvcreate_single(cmd, vg_name, vg, handle);
+
+ if (ret == ECMD_FAILED)
+ return ret;
+
+ if (!(lv = find_lv(vg, lp->lv_name))) {
+ log_error("Failed to find LV %s to add writecache.", lp->lv_name);
+ return ECMD_FAILED;
+ }
+
+ ret = lvconvert_writecache_attach_single(cmd, lv, handle);
+
+ if (ret == ECMD_FAILED) {
+ log_error("Removing new LV after failing to add writecache.");
+ if (!deactivate_lv(cmd, lv))
+ log_error("Failed to deactivate new LV %s.", display_lvname(lv));
+ if (!lv_remove_with_dependencies(cmd, lv, 1, 0))
+ log_error("Failed to remove new LV %s.", display_lvname(lv));
+ return ECMD_FAILED;
+ }
+
+ return ECMD_PROCESSED;
+}
+
+int lvcreate_and_attach_writecache_cmd(struct cmd_context *cmd, int argc, char **argv)
+{
+ struct processing_handle *handle = NULL;
+ struct processing_params pp;
+ struct lvcreate_params lp = {
+ .major = -1,
+ .minor = -1,
+ };
+ struct lvcreate_cmdline_params lcp = { 0 };
+ int ret;
+
+ /*
+ * Tell lvcreate to ignore --type since we are using lvcreate
+ * to create a linear LV and using lvconvert to add cache.
+ * (Would be better if lvcreate code was split up so we could
+ * call a specific function that just created a linear/striped LV.)
+ */
+ lp.ignore_type = 1;
+
+ if (!_lvcreate_params(cmd, argc, argv, &lp, &lcp)) {
+ stack;
+ return EINVALID_CMD_LINE;
+ }
+
+ pp.lp = &lp;
+ pp.lcp = &lcp;
+
+ if (!(handle = init_processing_handle(cmd, NULL))) {
+ log_error("Failed to initialize processing handle.");
+ return ECMD_FAILED;
+ }
+
+ handle->custom_handle = &pp;
+
+ ret = process_each_vg(cmd, 0, NULL, lp.vg_name, NULL, READ_FOR_UPDATE, 0, handle,
+ &_lvcreate_and_attach_writecache_single);
+
+ _destroy_lvcreate_params(&lp);
+ destroy_processing_handle(cmd, handle);
+ return ret;
+}
+
+static int _lvcreate_and_attach_cache_single(struct cmd_context *cmd,
+ const char *vg_name, struct volume_group *vg, struct processing_handle *handle)
+{
+ struct processing_params *pp = (struct processing_params *) handle->custom_handle;
+ struct lvcreate_params *lp = pp->lp;
+ struct logical_volume *lv;
+ int ret;
+
+ ret = _lvcreate_single(cmd, vg_name, vg, handle);
+
+ if (ret == ECMD_FAILED)
+ return ret;
+
+ if (!(lv = find_lv(vg, lp->lv_name))) {
+ log_error("Failed to find LV %s to add cache.", lp->lv_name);
+ return ECMD_FAILED;
+ }
+
+ ret = lvconvert_cachevol_attach_single(cmd, lv, handle);
+
+ if (ret == ECMD_FAILED) {
+ log_error("Removing new LV after failing to add cache.");
+ if (!deactivate_lv(cmd, lv))
+ log_error("Failed to deactivate new LV %s.", display_lvname(lv));
+ if (!lv_remove_with_dependencies(cmd, lv, 1, 0))
+ log_error("Failed to remove new LV %s.", display_lvname(lv));
+ return ECMD_FAILED;
+ }
+
+ return ECMD_PROCESSED;
+}
+
+int lvcreate_and_attach_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
+{
+ struct processing_handle *handle = NULL;
+ struct processing_params pp;
+ struct lvcreate_params lp = {
+ .major = -1,
+ .minor = -1,
+ };
+ struct lvcreate_cmdline_params lcp = { 0 };
+ int ret;
+
+ /*
+ * Tell lvcreate to ignore --type since we are using lvcreate
+ * to create a linear LV and using lvconvert to add cache.
+ * (Would be better if lvcreate code was split up so we could
+ * call a specific function that just created a linear/striped LV.)
+ */
+ lp.ignore_type = 1;
+
+ if (!_lvcreate_params(cmd, argc, argv, &lp, &lcp)) {
+ stack;
+ return EINVALID_CMD_LINE;
+ }
+
+ pp.lp = &lp;
+ pp.lcp = &lcp;
+
+ if (!(handle = init_processing_handle(cmd, NULL))) {
+ log_error("Failed to initialize processing handle.");
+ return ECMD_FAILED;
+ }
+
+ handle->custom_handle = &pp;
+
+ ret = process_each_vg(cmd, 0, NULL, lp.vg_name, NULL, READ_FOR_UPDATE, 0, handle,
+ &_lvcreate_and_attach_cache_single);
+
+ _destroy_lvcreate_params(&lp);
+ destroy_processing_handle(cmd, handle);
+ return ret;
+}
+
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 9c345bd99..7cf4e3ff0 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -154,6 +154,12 @@ static const struct command_function _command_functions[CMD_COUNT] = {
/* lvconvert for integrity */
{ lvconvert_integrity_CMD, lvconvert_integrity_cmd },
+ /* lvcreate */
+ { lvcreate_and_attach_cachevol_for_cache_CMD, lvcreate_and_attach_cache_cmd },
+ { lvcreate_and_attach_cachedevice_for_cache_CMD, lvcreate_and_attach_cache_cmd },
+ { lvcreate_and_attach_cachevol_for_writecache_CMD, lvcreate_and_attach_writecache_cmd },
+ { lvcreate_and_attach_cachedevice_for_writecache_CMD, lvcreate_and_attach_writecache_cmd },
+
{ pvscan_display_CMD, pvscan_display_cmd },
{ pvscan_cache_CMD, pvscan_cache_cmd },
};
diff --git a/tools/tools.h b/tools/tools.h
index 7f2434d06..c3d780d36 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -278,7 +278,18 @@ int lvconvert_to_vdopool_param_cmd(struct cmd_context *cmd, int argc, char **arg
int lvconvert_integrity_cmd(struct cmd_context *cmd, int argc, char **argv);
+int lvcreate_and_attach_writecache_cmd(struct cmd_context *cmd, int argc, char **argv);
+int lvcreate_and_attach_cache_cmd(struct cmd_context *cmd, int argc, char **argv);
+
int pvscan_display_cmd(struct cmd_context *cmd, int argc, char **argv);
int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv);
+
+int lvconvert_writecache_attach_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle);
+int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle);
+
#endif
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=21b37964eb88d404998e3…
Commit: 21b37964eb88d404998e37acae5530ec102a2116
Parent: 950d2d59c140c82fea35e56d34c92289562d4d6f
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Feb 5 13:42:36 2020 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jun 16 13:46:51 2020 -0500
lvconvert: single step cachevol creation and attachment
To add a cache or writecache to a main LV with a single command:
lvconvert --type cache|writecache --cachedevice /dev/ssd vg/main
A cachevol LV will be allocated from the specified cache device,
then attached to the main LV. Include --cachesize to specify the
size of cachevol to create, otherwise the entire cachedevice is
used. The cachedevice option can be repeated to create a cachevol
from multiple devices.
Example
-------
A user has an existing main LV that they want to speed up
using a new ssd.
user adds the new ssd to the VG:
$ vgextend vg /dev/ssd
user attaches the new ssd their main LV:
$ lvconvert --type writecache --cachedevice /dev/ssd vg/main
Example
-------
A user has two existing main LVs that they want to speed up
with a new ssd.
user adds the new 16G ssd to the VG:
$ vgextend vg /dev/ssd
user attaches some of the new ssd to the first main LV,
using half of the space:
$ lvconvert --type writecache --cachedevice /dev/ssd
--cachesize 8G vg/main1
user attaches some of the new ssd to the second main LV,
using the other half of the space:
$ lvconvert --type writecache --cachedevice /dev/ssd
--cachesize 8G vg/main2
Example
-------
A user has an existing main LV that they want to speed up using
two new ssds.
user adds the new two ssds the VG:
$ vgextend vg /dev/ssd1
$ vgextend vg /dev/ssd2
user attaches both ssds their main LV:
$ lvconvert --type writecache
--cachedevice /dev/ssd1 --cachedevice /dev/ssd2 vg/main
---
tools/args.h | 6 ++
tools/command-lines.in | 14 +++
tools/lvconvert.c | 250 +++++++++++++++++++++++++++++++++++++------------
tools/lvmcmdline.c | 2 +
4 files changed, 211 insertions(+), 61 deletions(-)
diff --git a/tools/args.h b/tools/args.h
index 5fae21abb..c69a0ecce 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -126,6 +126,12 @@ arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0,
arg(cachevol_ARG, '\0', "cachevol", lv_VAL, 0, 0,
"The name of a cache volume.\n")
+arg(cachedevice_ARG, '\0', "cachedevice", pv_VAL, 0, 0,
+ "The name of a device to use for a cache.\n")
+
+arg(cachesize_ARG, '\0', "cachesize", sizemb_VAL, 0, 0,
+ "The size of cache to use.\n")
+
arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0,
"The command profile to use for command configuration.\n"
"See \\fBlvm.conf\\fP(5) for more information about profiles.\n")
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 98044a918..8d389b665 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -497,6 +497,20 @@ FLAGS: SECONDARY_SYNTAX
---
+lvconvert --type writecache --cachedevice PV LV
+OO: OO_LVCONVERT, --cachesize SizeMB, --cachesettings String
+ID: lvconvert_to_writecache_with_device
+DESC: Add a writecache to an LV, using a specified cache device.
+RULE: all and lv_is_visible
+
+lvconvert --type cache --cachedevice PV LV
+OO: OO_LVCONVERT, --cachesize SizeMB, --cachesettings String
+ID: lvconvert_to_cache_with_device
+DESC: Add a cache to an LV, using a specified cache device.
+RULE: all and lv_is_visible
+
+---
+
lvconvert --type thin-pool LV_linear_striped_raid_cache
OO: --stripes_long Number, --stripesize SizeKB,
--discards Discards, OO_LVCONVERT_POOL, OO_LVCONVERT
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 94ea70fa5..76a9160f3 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -4248,51 +4248,159 @@ int lvconvert_to_pool_cmd(struct cmd_context *cmd, int argc, char **argv)
NULL, NULL, &_lvconvert_to_pool_single);
}
+static int _lv_create_cachevol(struct cmd_context *cmd,
+ struct volume_group *vg,
+ struct logical_volume *lv,
+ const char *dev_name,
+ struct logical_volume **cachevol_lv)
+{
+ char cvname[NAME_LEN];
+ struct device *dev_fast;
+ struct dm_list *use_pvh;
+ uint64_t cache_size_sectors;
+ struct logical_volume *cachevol;
+ struct pv_list *pvl;
+ struct lvcreate_params lp = {
+ .activate = CHANGE_AN,
+ .alloc = ALLOC_INHERIT,
+ .major = -1,
+ .minor = -1,
+ .permission = LVM_READ | LVM_WRITE,
+ .pvh = &vg->pvs,
+ .read_ahead = DM_READ_AHEAD_NONE,
+ .stripes = 1,
+ .vg_name = vg->name,
+ .zero = 0,
+ .wipe_signatures = 0,
+ .suppress_zero_warn = 1,
+ };
+
+ if (dm_snprintf(cvname, NAME_LEN, "%s_cache", lv->name) < 0) {
+ log_error("Failed to create cachevol LV name.");
+ return 0;
+ }
+
+ if (!(dev_fast = dev_cache_get(cmd, dev_name, cmd->filter))) {
+ log_error("Device %s not found.", dev_name);
+ return 0;
+ }
+
+ if (!(pvl = find_pv_in_vg(vg, dev_name))) {
+ log_error("PV %s not found in VG.", dev_name);
+ return 0;
+ }
+
+ /*
+ * If fast_dev is used in the VG, then require a cachesize to allocate
+ * from it. If fast_dev is not used in the VG, then prompt asking if
+ * the entire dev should be used.
+ */
+ if (!(cache_size_sectors = arg_uint64_value(cmd, cachesize_ARG, 0))) {
+ if (pvl->pv->pe_alloc_count) {
+ log_error("PV %s is in use, --cachesize is required.", dev_name);
+ return 0;
+ }
+
+ cache_size_sectors = (pvl->pv->pe_count * vg->extent_size);
+
+ if (!arg_is_set(cmd, yes_ARG) &&
+ yes_no_prompt("Use all %s from %s for cache? [y/n]: ",
+ display_size(cmd, cache_size_sectors), dev_name) == 'n') {
+ log_print("Use --cachesize SizeMB to use a part of the cachedevice.");
+ log_error("Conversion aborted.");
+ return 0;
+ }
+ }
+
+ if (!(use_pvh = create_pv_list(cmd->mem, vg, 1, (char **)&dev_name, 1))) {
+ log_error("cachedevice not found in VG %s.", dev_name);
+ return 0;
+ }
+
+ lp.lv_name = cvname;
+ lp.pvh = use_pvh;
+ lp.extents = cache_size_sectors / vg->extent_size;
+
+ log_print("Creating cachevol LV %s with size %s.",
+ cvname, display_size(cmd, cache_size_sectors));
+
+ dm_list_init(&lp.tags);
+
+ if (!(lp.segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
+ return_0;
+
+ if (!(cachevol = lv_create_single(vg, &lp))) {
+ log_error("Failed to create cachevol LV");
+ return 0;
+ }
+
+ *cachevol_lv = cachevol;
+ return 1;
+}
+
static int _lvconvert_cachevol_attach_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
struct volume_group *vg = lv->vg;
- struct logical_volume *cachevol_lv;
- const char *cachevol_name;
+ struct logical_volume *lv_fast;
+ const char *fast_name, *dev_name;
- if (!(cachevol_name = arg_str_value(cmd, cachevol_ARG, NULL)))
- goto_out;
+ fast_name = arg_str_value(cmd, cachevol_ARG, NULL);
+ dev_name = arg_str_value(cmd, cachedevice_ARG, NULL);
- if (!validate_lvname_param(cmd, &vg->name, &cachevol_name))
- goto_out;
+ if (!fast_name && !dev_name)
+ goto_bad;
- if (!(cachevol_lv = find_lv(vg, cachevol_name))) {
- log_error("Cache single %s not found.", cachevol_name);
- goto out;
- }
+ if (fast_name && dev_name)
+ goto_bad;
- if (lv_is_cache_vol(cachevol_lv)) {
- log_error("LV %s is already used as a cachevol.", display_lvname(cachevol_lv));
- goto out;
- }
+ /*
+ * User specifies an existing cachevol to use.
+ */
+ if (fast_name) {
+ if (!validate_lvname_param(cmd, &vg->name, &fast_name))
+ goto_bad;
- /* Ensure the LV is not active elsewhere. */
- if (!lockd_lv(cmd, lv, "ex", 0))
- goto_out;
+ if (!(lv_fast = find_lv(vg, fast_name))) {
+ log_error("LV %s not found.", fast_name);
+ goto bad;
+ }
- if (!dm_list_empty(&cachevol_lv->segs_using_this_lv)) {
- log_error("LV %s is already in use.", display_lvname(cachevol_lv));
- goto out;
+ if (lv_is_cache_vol(lv_fast)) {
+ log_error("LV %s is already used as a cachevol.", display_lvname(lv_fast));
+ goto bad;
+ }
+
+ if (!dm_list_empty(&lv_fast->segs_using_this_lv)) {
+ log_error("LV %s is already in use.", display_lvname(lv_fast));
+ goto bad;
+ }
+
+ if (!arg_is_set(cmd, yes_ARG) &&
+ yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(lv_fast)) == 'n') {
+ log_error("Conversion aborted.");
+ goto bad;
+ }
+
+ if (!lockd_lv(cmd, lv_fast, "ex", 0))
+ goto_bad;
}
- if (!arg_is_set(cmd, yes_ARG) &&
- yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(cachevol_lv)) == 'n') {
- log_error("Conversion aborted.");
- goto out;
+ /*
+ * User specifies a device and lvm creates a cachevol on it.
+ */
+ if (dev_name) {
+ if (!_lv_create_cachevol(cmd, vg, lv, dev_name, &lv_fast))
+ goto_bad;
}
/* Ensure the LV is not active elsewhere. */
- if (!lockd_lv(cmd, cachevol_lv, "ex", LDLV_PERSISTENT))
- goto_out;
+ if (!lockd_lv(cmd, lv, "ex", 0))
+ goto_bad;
- if (!wipe_cache_pool(cachevol_lv))
- goto_out;
+ if (!wipe_cache_pool(lv_fast))
+ goto_bad;
/* When the lv arg is a thinpool, redirect command to data sub lv. */
@@ -4302,17 +4410,17 @@ static int _lvconvert_cachevol_attach_single(struct cmd_context *cmd,
}
if (_raid_split_image_conversion(lv))
- goto_out;
+ goto_bad;
/* Attach the cache to the main LV. */
- if (!_cache_vol_attach(cmd, lv, cachevol_lv))
- goto_out;
+ if (!_cache_vol_attach(cmd, lv, lv_fast))
+ goto_bad;
log_print_unless_silent("Logical volume %s is now cached.", display_lvname(lv));
return ECMD_PROCESSED;
- out:
+ bad:
return ECMD_FAILED;
}
@@ -5605,7 +5713,7 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
struct logical_volume *lv_wcorig;
struct logical_volume *lv_fast;
struct writecache_settings settings;
- const char *fast_name;
+ const char *fast_name, *dev_name;
uint32_t block_size_sectors = 0;
char *lockd_fast_args = NULL;
char *lockd_fast_name = NULL;
@@ -5613,32 +5721,58 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
char cvol_name[NAME_LEN];
int is_active;
- fast_name = arg_str_value(cmd, cachevol_ARG, "");
+ fast_name = arg_str_value(cmd, cachevol_ARG, NULL);
+ dev_name = arg_str_value(cmd, cachedevice_ARG, NULL);
- if (!(lv_fast = find_lv(vg, fast_name))) {
- log_error("LV %s not found.", fast_name);
- goto bad;
- }
+ if (!fast_name && !dev_name)
+ goto_bad;
- if (lv_fast == lv) {
- log_error("Invalid cachevol LV.");
- goto bad;
- }
+ /*
+ * User specifies an existing cachevol to use.
+ */
+ if (fast_name) {
+ if (!validate_lvname_param(cmd, &vg->name, &fast_name))
+ goto_bad;
- if (!seg_is_linear(first_seg(lv_fast))) {
- log_error("LV %s must be linear to use as a writecache.", display_lvname(lv_fast));
- goto bad;
- }
+ if (!(lv_fast = find_lv(vg, fast_name))) {
+ log_error("LV %s not found.", fast_name);
+ goto bad;
+ }
- if (lv_is_cache_vol(lv_fast)) {
- log_error("LV %s is already used as a cachevol.", display_lvname(lv_fast));
- goto bad;
+ if (lv_fast == lv) {
+ log_error("Invalid cachevol LV.");
+ goto bad;
+ }
+
+ if (lv_is_cache_vol(lv_fast)) {
+ log_error("LV %s is already used as a cachevol.", display_lvname(lv_fast));
+ goto bad;
+ }
+
+ if (!seg_is_linear(first_seg(lv_fast))) {
+ log_error("LV %s must be linear to use as a writecache.", display_lvname(lv_fast));
+ goto bad;
+ }
+
+ /* fast LV shouldn't generally be active by itself, but just in case. */
+ if (lv_is_active(lv_fast)) {
+ log_error("LV %s must be inactive to attach.", display_lvname(lv_fast));
+ goto bad;
+ }
+
+ if (!arg_is_set(cmd, yes_ARG) &&
+ yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(lv_fast)) == 'n') {
+ log_error("Conversion aborted.");
+ goto bad;
+ }
}
- /* fast LV shouldn't generally be active by itself, but just in case. */
- if (lv_info(cmd, lv_fast, 1, NULL, 0, 0)) {
- log_error("LV %s must be inactive to attach.", display_lvname(lv_fast));
- goto bad;
+ /*
+ * User specifies a device and lvm creates a cachevol on it.
+ */
+ if (dev_name) {
+ if (!_lv_create_cachevol(cmd, vg, lv, dev_name, &lv_fast))
+ goto_bad;
}
is_active = lv_is_active(lv);
@@ -5671,16 +5805,10 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
}
}
- if (!arg_is_set(cmd, yes_ARG) &&
- yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(lv_fast)) == 'n') {
- log_error("Conversion aborted.");
- goto bad;
- }
-
- /* Ensure the two LVs are not active elsewhere. */
+ /* Ensure the LV is not active elsewhere. */
if (!lockd_lv(cmd, lv, "ex", 0))
goto_bad;
- if (!lockd_lv(cmd, lv_fast, "ex", 0))
+ if (!dev_name && !lockd_lv(cmd, lv_fast, "ex", 0))
goto_bad;
if (!archive(vg))
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index d87a8f053..9c345bd99 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -124,8 +124,10 @@ static const struct command_function _command_functions[CMD_COUNT] = {
{ lvconvert_to_cachepool_CMD, lvconvert_to_pool_cmd },
{ lvconvert_to_thin_with_external_CMD, lvconvert_to_thin_with_external_cmd },
{ lvconvert_to_cache_with_cachevol_CMD, lvconvert_to_cache_with_cachevol_cmd },
+ { lvconvert_to_cache_with_device_CMD, lvconvert_to_cache_with_cachevol_cmd },
{ lvconvert_to_cache_with_cachepool_CMD, lvconvert_to_cache_with_cachepool_cmd },
{ lvconvert_to_writecache_CMD, lvconvert_to_writecache_cmd },
+ { lvconvert_to_writecache_with_device_CMD, lvconvert_to_writecache_cmd },
{ lvconvert_swap_pool_metadata_CMD, lvconvert_swap_pool_metadata_cmd },
{ lvconvert_to_thinpool_or_swap_metadata_CMD, lvconvert_to_pool_or_swap_metadata_cmd },
{ lvconvert_to_cachepool_or_swap_metadata_CMD, lvconvert_to_pool_or_swap_metadata_cmd },
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=fa9eb76a5dc8d76a1f06a…
Commit: fa9eb76a5dc8d76a1f06a44337f909c75df1fee9
Parent: b59127a8386a407407a0361b9bcad028ce31a733
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Jun 3 12:38:27 2020 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jun 3 12:38:27 2020 -0500
improve info about vgck updatemetadata
Add man page info about this option, and add log messages
pointing to this option.
---
lib/cache/lvmcache.c | 4 ++++
lib/metadata/metadata.c | 4 +++-
tools/args.h | 11 ++++++++++-
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 6cb5ff0d8..b1d05fb07 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -84,6 +84,7 @@ static DM_LIST_INIT(_unused_duplicates);
static DM_LIST_INIT(_prev_unused_duplicate_devs);
static int _vgs_locked = 0;
static int _found_duplicate_vgnames = 0;
+static int _outdated_warning = 0;
int lvmcache_init(struct cmd_context *cmd)
{
@@ -1776,6 +1777,9 @@ int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted)
log_warn("WARNING: outdated PV %s seqno %u has been removed in current VG %s seqno %u.",
dev_name(info->dev), info->summary_seqno, vg->name, vginfo->seqno);
+ if (!_outdated_warning++)
+ log_warn("See vgck --updatemetadata to clear outdated metadata.");
+
_drop_vginfo(info, vginfo); /* remove from vginfo->infos */
dm_list_add(&vginfo->outdated_infos, &info->list);
}
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 4b8dce902..c0d42066d 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -4875,8 +4875,10 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
}
}
- if (found_old_metadata)
+ if (found_old_metadata) {
log_warn("WARNING: Inconsistent metadata found for VG %s.", vgname);
+ log_warn("See vgck --updatemetadata to correct inconsistency.");
+ }
vg = NULL;
diff --git a/tools/args.h b/tools/args.h
index d1f604b0c..5fae21abb 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -1428,7 +1428,16 @@ arg(thin_ARG, 'T', "thin", 0, 0, 0,
"See \\fBlvmthin\\fP(7) for more information about LVM thin provisioning.\n")
arg(updatemetadata_ARG, '\0', "updatemetadata", 0, 0, 0,
- "Update VG metadata to correct problems.\n")
+ "Update VG metadata to correct problems.\n"
+ "If VG metadata was updated while a PV was missing, and the PV\n"
+ "reappears with an old version of metadata, then this option\n"
+ "(or any other command that writes metadata) will update the\n"
+ "metadata on the previously missing PV. If a PV was removed\n"
+ "from a VG while it was missing, and the PV reappears, using\n"
+ "this option will clear the outdated metadata from the previously\n"
+ "missing PV. If metadata text is damaged on one PV, using this\n"
+ "option will replace the damaged metadata text. For more severe\n"
+ "damage, e.g. with headers, see \\fBpvck\\fP(8).\n")
arg(uuid_ARG, 'u', "uuid", 0, 0, 0,
"#pvchange\n"