master - writecache: allow snapshot of LV with writecache
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=38eaa1035b13ba1633d...
Commit: 38eaa1035b13ba1633d0002fa53071d5b7098ef9
Parent: 712c9efbf6104a863b610a006e72d7da8336fa7e
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Apr 13 15:58:28 2020 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jun 10 12:18:00 2020 -0500
writecache: allow snapshot of LV with writecache
---
lib/metadata/snapshot_manip.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c
index 3faea0eb8..0f48e62e8 100644
--- a/lib/metadata/snapshot_manip.c
+++ b/lib/metadata/snapshot_manip.c
@@ -389,8 +389,6 @@ int validate_snapshot_origin(const struct logical_volume *origin_lv)
err = "raid subvolumes";
} else if (lv_is_raid(origin_lv) && lv_raid_has_integrity((struct logical_volume *)origin_lv)) {
err = "raid with integrity";
- } else if (lv_is_writecache(origin_lv)) {
- err = "writecache";
}
if (err) {
3 years, 10 months
master - fix bad result from _cache_min_metadata_size
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=712c9efbf6104a863b6...
Commit: 712c9efbf6104a863b610a006e72d7da8336fa7e
Parent: 48c1a295a294fefa0886885f13604f134ceaf406
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Apr 10 16:57:12 2020 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jun 10 12:17:34 2020 -0500
fix bad result from _cache_min_metadata_size
fixes regression from switching to use _cache_min_metadata_size
(commit c08704cee7e34a96fdaa453faf900683283e8691) which returns
a bogus value when the cachevol size is 8MB.
---
lib/metadata/cache_manip.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index 49b385052..a786e8bac 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -1094,6 +1094,10 @@ int cache_vol_set_params(struct cmd_context *cmd,
if (!meta_size) {
meta_size = _cache_min_metadata_size(pool_lv->size, chunk_size);
+ /* fix bad value from _cache_min_metadata_size */
+ if (meta_size > (pool_lv->size / 2))
+ meta_size = pool_lv->size / 2;
+
if (meta_size < min_meta_size)
meta_size = min_meta_size;
3 years, 10 months
master - tests: writecache-blocksize
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=48c1a295a294fefa088...
Commit: 48c1a295a294fefa0886885f13604f134ceaf406
Parent: a7b2fc8f5791747ff3326997a07743eeebbd3ef7
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Apr 8 15:33:30 2020 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jun 10 12:16:31 2020 -0500
tests: writecache-blocksize
---
test/shell/writecache-blocksize.sh | 343 +++++++++++++++++++++++++++++++++++++
1 file changed, 343 insertions(+)
diff --git a/test/shell/writecache-blocksize.sh b/test/shell/writecache-blocksize.sh
new file mode 100644
index 000000000..42c963c29
--- /dev/null
+++ b/test/shell/writecache-blocksize.sh
@@ -0,0 +1,343 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test writecache usage
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_writecache 1 0 0 || skip
+which mkfs.xfs || skip
+
+# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
+aux prepare_devs 1
+vgcreate $vg "$dev1"
+lvcreate -n $lv1 -l8 $vg
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
+blkid "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
+lvchange -an $vg
+vgremove -ff $vg
+aux cleanup_scsi_debug_dev
+
+mnt="mnt"
+mkdir -p $mnt
+
+for i in `seq 1 16384`; do echo -n "A" >> fileA; done
+for i in `seq 1 16384`; do echo -n "B" >> fileB; done
+for i in `seq 1 16384`; do echo -n "C" >> fileC; done
+
+# generate random data
+dd if=/dev/urandom of=randA bs=512K count=2
+dd if=/dev/urandom of=randB bs=512K count=3
+dd if=/dev/urandom of=randC bs=512K count=4
+
+_add_new_data_to_mnt() {
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ # add original data
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ mkdir $mnt/1
+ cp fileA $mnt/1
+ cp fileB $mnt/1
+ cp fileC $mnt/1
+ mkdir $mnt/2
+ cp fileA $mnt/2
+ cp fileB $mnt/2
+ cp fileC $mnt/2
+ sync
+}
+
+_add_more_data_to_mnt() {
+ mkdir $mnt/more
+ cp fileA $mnt/more
+ cp fileB $mnt/more
+ cp fileC $mnt/more
+ cp randA $mnt/more
+ cp randB $mnt/more
+ cp randC $mnt/more
+ sync
+}
+
+_verify_data_on_mnt() {
+ diff randA $mnt/randA
+ diff randB $mnt/randB
+ diff randC $mnt/randC
+ diff fileA $mnt/1/fileA
+ diff fileB $mnt/1/fileB
+ diff fileC $mnt/1/fileC
+ diff fileA $mnt/2/fileA
+ diff fileB $mnt/2/fileB
+ diff fileC $mnt/2/fileC
+}
+
+_verify_more_data_on_mnt() {
+ diff randA $mnt/more/randA
+ diff randB $mnt/more/randB
+ diff randC $mnt/more/randC
+ diff fileA $mnt/more/fileA
+ diff fileB $mnt/more/fileB
+ diff fileC $mnt/more/fileC
+}
+
+_verify_data_on_lv() {
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ _verify_data_on_mnt
+ rm $mnt/randA
+ rm $mnt/randB
+ rm $mnt/randC
+ rm -rf $mnt/1
+ rm -rf $mnt/2
+ umount $mnt
+ lvchange -an $vg/$lv1
+}
+
+# the default is brd ram devs with 512 LBS 4K PBS
+aux prepare_devs 2 64
+
+blockdev --getss "$dev1"
+blockdev --getpbsz "$dev1"
+blockdev --getss "$dev2"
+blockdev --getpbsz "$dev2"
+
+# lbs 512, pbs 4k, xfs 4k, wc 4k
+vgcreate $SHARED $vg "$dev1"
+vgextend $vg "$dev2"
+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvchange -ay $vg/$lv1
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep sectsz=4096 out
+_add_new_data_to_mnt
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep 4096 out
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_add_more_data_to_mnt
+_verify_data_on_mnt
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+_verify_data_on_lv
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+vgremove $vg
+
+# lbs 512, pbs 4k, xfs -s 512, wc 512
+vgcreate $SHARED $vg "$dev1"
+vgextend $vg "$dev2"
+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvchange -ay $vg/$lv1
+mkfs.xfs -f -s size=512 "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep sectsz=512 out
+_add_new_data_to_mnt
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep 512 out
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_add_more_data_to_mnt
+_verify_data_on_mnt
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+_verify_data_on_lv
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+vgremove $vg
+
+aux cleanup_scsi_debug_dev
+sleep 1
+
+
+# scsi_debug devices with 512 LBS 512 PBS
+aux prepare_scsi_debug_dev 256
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "512"
+aux prepare_devs 2 64
+
+blockdev --getss "$dev1"
+blockdev --getpbsz "$dev1"
+blockdev --getss "$dev2"
+blockdev --getpbsz "$dev2"
+
+# lbs 512, pbs 512, xfs 512, wc 512
+vgcreate $SHARED $vg "$dev1"
+vgextend $vg "$dev2"
+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvchange -ay $vg/$lv1
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep sectsz=512 out
+_add_new_data_to_mnt
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep 512 out
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_add_more_data_to_mnt
+_verify_data_on_mnt
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+_verify_data_on_lv
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+vgremove $vg
+
+# lbs 512, pbs 512, xfs -s 4096, wc 4096
+vgcreate $SHARED $vg "$dev1"
+vgextend $vg "$dev2"
+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvchange -ay $vg/$lv1
+mkfs.xfs -s size=4096 -f "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep sectsz=4096 out
+_add_new_data_to_mnt
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep 4096 out
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_add_more_data_to_mnt
+_verify_data_on_mnt
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+_verify_data_on_lv
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+vgremove $vg
+
+aux cleanup_scsi_debug_dev
+sleep 1
+
+
+# scsi_debug devices with 512 LBS and 4K PBS
+aux prepare_scsi_debug_dev 256 sector_size=512 physblk_exp=3
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "4096"
+aux prepare_devs 2 64
+
+blockdev --getss "$dev1"
+blockdev --getpbsz "$dev1"
+blockdev --getss "$dev2"
+blockdev --getpbsz "$dev2"
+
+# lbs 512, pbs 4k, xfs 4k, wc 4k
+vgcreate $SHARED $vg "$dev1"
+vgcreate $SHARED $vg "$dev1"
+vgextend $vg "$dev2"
+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvchange -ay $vg/$lv1
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep sectsz=4096 out
+_add_new_data_to_mnt
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep 4096 out
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_add_more_data_to_mnt
+_verify_data_on_mnt
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+_verify_data_on_lv
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+vgremove $vg
+
+aux cleanup_scsi_debug_dev
+sleep 1
+
+
+# scsi_debug devices with 4K LBS and 4K PBS
+aux prepare_scsi_debug_dev 256 sector_size=4096
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "4096"
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "4096"
+aux prepare_devs 2 64
+
+blockdev --getss "$dev1"
+blockdev --getpbsz "$dev1"
+blockdev --getss "$dev2"
+blockdev --getpbsz "$dev2"
+
+# lbs 4k, pbs 4k, xfs 4k, wc 4k
+vgcreate $SHARED $vg "$dev1"
+vgextend $vg "$dev2"
+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvchange -ay $vg/$lv1
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep sectsz=4096 out
+_add_new_data_to_mnt
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep 4096 out
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_add_more_data_to_mnt
+_verify_data_on_mnt
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+_verify_data_on_lv
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+vgremove $vg
+
+aux cleanup_scsi_debug_dev
+
+
3 years, 10 months
master - writecache: add settings cleaner and max_age
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=a7b2fc8f5791747ff33...
Commit: a7b2fc8f5791747ff3326997a07743eeebbd3ef7
Parent: d15c466f9557004fa003b8986b82deca25cc5aaf
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Mar 31 14:14:50 2020 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jun 10 12:15:50 2020 -0500
writecache: add settings cleaner and max_age
available in dm-writecache 1.2
---
device_mapper/all.h | 4 ++++
device_mapper/libdm-deptree.c | 12 ++++++++++
lib/metadata/writecache_manip.c | 8 +++++++
lib/report/report.c | 2 +-
lib/writecache/writecache.c | 49 +++++++++++++++++++++++++++++++++++++++++
tools/lvchange.c | 10 +++++++++
tools/toollib.c | 14 ++++++++++++
7 files changed, 98 insertions(+), 1 deletion(-)
diff --git a/device_mapper/all.h b/device_mapper/all.h
index f00b6a5dc..c3c6219e3 100644
--- a/device_mapper/all.h
+++ b/device_mapper/all.h
@@ -951,6 +951,8 @@ struct writecache_settings {
uint64_t autocommit_time; /* in milliseconds */
uint32_t fua;
uint32_t nofua;
+ uint32_t cleaner;
+ uint32_t max_age;
/*
* Allow an unrecognized key and its val to be passed to the kernel for
@@ -970,6 +972,8 @@ struct writecache_settings {
unsigned autocommit_time_set:1;
unsigned fua_set:1;
unsigned nofua_set:1;
+ unsigned cleaner_set:1;
+ unsigned max_age_set:1;
};
int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
diff --git a/device_mapper/libdm-deptree.c b/device_mapper/libdm-deptree.c
index 9ba24cbbf..2722a2c3b 100644
--- a/device_mapper/libdm-deptree.c
+++ b/device_mapper/libdm-deptree.c
@@ -2670,6 +2670,10 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
count += 1;
if (seg->writecache_settings.nofua_set)
count += 1;
+ if (seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner)
+ count += 1;
+ if (seg->writecache_settings.max_age_set)
+ count += 2;
if (seg->writecache_settings.new_key)
count += 2;
@@ -2713,6 +2717,14 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
EMIT_PARAMS(pos, " nofua");
}
+ if (seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner) {
+ EMIT_PARAMS(pos, " cleaner");
+ }
+
+ if (seg->writecache_settings.max_age_set) {
+ EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age);
+ }
+
if (seg->writecache_settings.new_key) {
EMIT_PARAMS(pos, " %s %s",
seg->writecache_settings.new_key,
diff --git a/lib/metadata/writecache_manip.c b/lib/metadata/writecache_manip.c
index e24bcb76b..7ad8c75e7 100644
--- a/lib/metadata/writecache_manip.c
+++ b/lib/metadata/writecache_manip.c
@@ -454,6 +454,14 @@ int writecache_settings_to_str_list(struct writecache_settings *settings, struct
if (!_writecache_setting_str_list_add("nofua", (uint64_t)settings->nofua, NULL, result, mem))
errors++;
+ if (settings->cleaner_set && settings->cleaner)
+ if (!_writecache_setting_str_list_add("cleaner", (uint64_t)settings->cleaner, NULL, result, mem))
+ errors++;
+
+ if (settings->max_age_set)
+ if (!_writecache_setting_str_list_add("max_age", (uint64_t)settings->max_age, NULL, result, mem))
+ errors++;
+
if (settings->new_key && settings->new_val)
if (!_writecache_setting_str_list_add(settings->new_key, 0, settings->new_val, result, mem))
errors++;
diff --git a/lib/report/report.c b/lib/report/report.c
index 268bed61b..74ec74cf7 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -1434,7 +1434,7 @@ static int _cache_settings_disp(struct dm_report *rh, struct dm_pool *mem,
if (!(result = str_list_create(mem)))
return_0;
- if (!writecache_settings_to_str_list(&seg->writecache_settings, result, mem))
+ if (!writecache_settings_to_str_list((struct writecache_settings *)&seg->writecache_settings, result, mem))
return_0;
return _field_set_string_list(rh, field, result, private, 0, NULL);
diff --git a/lib/writecache/writecache.c b/lib/writecache/writecache.c
index 130922a54..c7aea286d 100644
--- a/lib/writecache/writecache.c
+++ b/lib/writecache/writecache.c
@@ -26,6 +26,9 @@
#include "lib/metadata/lv_alloc.h"
#include "lib/config/defaults.h"
+static int _writecache_cleaner_supported;
+static int _writecache_max_age_supported;
+
#define SEG_LOG_ERROR(t, p...) \
log_error(t " segment %s of logical volume %s.", ## p, \
dm_config_parent_name(sn), seg->lv->name), 0;
@@ -120,6 +123,18 @@ static int _writecache_text_import(struct lv_segment *seg,
seg->writecache_settings.nofua_set = 1;
}
+ if (dm_config_has_node(sn, "cleaner")) {
+ if (!dm_config_get_uint32(sn, "cleaner", &seg->writecache_settings.cleaner))
+ return SEG_LOG_ERROR("Unknown writecache_setting in");
+ seg->writecache_settings.cleaner_set = 1;
+ }
+
+ if (dm_config_has_node(sn, "max_age")) {
+ if (!dm_config_get_uint32(sn, "max_age", &seg->writecache_settings.max_age))
+ return SEG_LOG_ERROR("Unknown writecache_setting in");
+ seg->writecache_settings.max_age_set = 1;
+ }
+
if (dm_config_has_node(sn, "writecache_setting_key")) {
const char *key;
const char *val;
@@ -184,6 +199,14 @@ static int _writecache_text_export(const struct lv_segment *seg,
outf(f, "nofua = %u", seg->writecache_settings.nofua);
}
+ if (seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner) {
+ outf(f, "cleaner = %u", seg->writecache_settings.cleaner);
+ }
+
+ if (seg->writecache_settings.max_age_set) {
+ outf(f, "max_age = %u", seg->writecache_settings.max_age);
+ }
+
if (seg->writecache_settings.new_key && seg->writecache_settings.new_val) {
outf(f, "writecache_setting_key = \"%s\"",
seg->writecache_settings.new_key);
@@ -208,6 +231,7 @@ static int _target_present(struct cmd_context *cmd,
{
static int _writecache_checked = 0;
static int _writecache_present = 0;
+ uint32_t maj, min, patchlevel;
if (!activation())
return 0;
@@ -215,6 +239,19 @@ static int _target_present(struct cmd_context *cmd,
if (!_writecache_checked) {
_writecache_checked = 1;
_writecache_present = target_present(cmd, TARGET_NAME_WRITECACHE, 1);
+
+ if (!target_version(TARGET_NAME_WRITECACHE, &maj, &min, &patchlevel))
+ return_0;
+
+ if (maj < 1) {
+ log_error("writecache target version older than minimum 1.0.0");
+ return 0;
+ }
+
+ if (min >= 2) {
+ _writecache_cleaner_supported = 1;
+ _writecache_max_age_supported = 1;
+ }
}
return _writecache_present;
@@ -257,6 +294,18 @@ static int _writecache_add_target_line(struct dev_manager *dm,
return 0;
}
+ if (!_writecache_cleaner_supported && seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner) {
+ log_warn("WARNING: ignoring writecache setting \"cleaner\" which is not supported by kernel for LV %s.", seg->lv->name);
+ seg->writecache_settings.cleaner = 0;
+ seg->writecache_settings.cleaner_set = 0;
+ }
+
+ if (!_writecache_max_age_supported && seg->writecache_settings.max_age_set) {
+ log_warn("WARNING: ignoring writecache setting \"max_age\" which is not supported by kernel for LV %s.", seg->lv->name);
+ seg->writecache_settings.max_age = 0;
+ seg->writecache_settings.max_age_set = 0;
+ }
+
if ((pmem = lv_on_pmem(seg->writecache)) < 0)
return_0;
diff --git a/tools/lvchange.c b/tools/lvchange.c
index ba24e8239..c0adadf8d 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -658,6 +658,16 @@ static int _lvchange_writecache(struct cmd_context *cmd,
seg->writecache_settings.nofua = settings.nofua;
set_count++;
}
+ if (settings.cleaner_set) {
+ seg->writecache_settings.cleaner_set = settings.cleaner_set;
+ seg->writecache_settings.cleaner = settings.cleaner;
+ set_count++;
+ }
+ if (settings.max_age_set) {
+ seg->writecache_settings.max_age_set = settings.max_age_set;
+ seg->writecache_settings.max_age = settings.max_age;
+ set_count++;
+ }
if (!set_count) {
/*
diff --git a/tools/toollib.c b/tools/toollib.c
index 94e6e6c44..eb0de5501 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -1262,6 +1262,20 @@ static int _get_one_writecache_setting(struct cmd_context *cmd, struct writecach
return 1;
}
+ if (!strncmp(key, "cleaner", strlen("cleaner"))) {
+ if (sscanf(val, "%u", &settings->cleaner) != 1)
+ goto_bad;
+ settings->cleaner_set = 1;
+ return 1;
+ }
+
+ if (!strncmp(key, "max_age", strlen("max_age"))) {
+ if (sscanf(val, "%u", &settings->max_age) != 1)
+ goto_bad;
+ settings->max_age_set = 1;
+ return 1;
+ }
+
if (settings->new_key) {
log_error("Setting %s is not recognized. Only one unrecognized setting is allowed.", key);
return 0;
3 years, 10 months
master - writecache: attach while active using fs block size
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d15c466f9557004fa00...
Commit: d15c466f9557004fa003b8986b82deca25cc5aaf
Parent: 1ee42f13915d852008b1e7b777edee766413ef89
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Mar 30 16:25:15 2020 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jun 10 12:15:34 2020 -0500
writecache: attach while active using fs block size
Use libblkid to detect sector/block size of the fs on the LV.
Use this to choose a compatible writecache block size.
Enable attaching writecache to an active LV.
---
tools/lvconvert.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 164 insertions(+), 13 deletions(-)
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 757e708ff..b25fa1704 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -5433,7 +5433,166 @@ static struct logical_volume *_lv_writecache_create(struct cmd_context *cmd,
return lv_wcorig;
}
-#define DEFAULT_WRITECACHE_BLOCK_SIZE_SECTORS 8 /* 4K */
+/*
+ * Currently only supports writecache block sizes 512 and 4096.
+ * This could be expanded later.
+ */
+static int _set_writecache_block_size(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ uint32_t *block_size_sectors)
+{
+ char pathname[PATH_MAX];
+ struct device *fs_dev;
+ struct dm_list pvs;
+ struct pv_list *pvl;
+ uint32_t fs_block_size = 0;
+ uint32_t block_size_setting = 0;
+ uint32_t block_size = 0;
+ int lbs_unknown = 0, lbs_4k = 0, lbs_512 = 0;
+ int pbs_unknown = 0, pbs_4k = 0, pbs_512 = 0;
+ int rv;
+
+ /* This is set if the user specified a writecache block size on the command line. */
+ if (*block_size_sectors)
+ block_size_setting = *block_size_sectors * 512;
+
+ dm_list_init(&pvs);
+
+ if (!get_pv_list_for_lv(cmd->mem, lv, &pvs)) {
+ log_error("Failed to build list of PVs for %s.", display_lvname(lv));
+ goto_bad;
+ }
+
+ dm_list_iterate_items(pvl, &pvs) {
+ unsigned int pbs = 0;
+ unsigned int lbs = 0;
+
+ if (!dev_get_direct_block_sizes(pvl->pv->dev, &pbs, &lbs)) {
+ lbs_unknown++;
+ pbs_unknown++;
+ continue;
+ }
+
+ if (lbs == 4096)
+ lbs_4k++;
+ else if (lbs == 512)
+ lbs_512++;
+ else
+ lbs_unknown++;
+
+ if (pbs == 4096)
+ pbs_4k++;
+ else if (pbs == 512)
+ pbs_512++;
+ else
+ pbs_unknown++;
+ }
+
+ if (lbs_4k && lbs_512) {
+ log_error("Writecache requires consistent logical block size for LV devices.");
+ goto_bad;
+ }
+
+ if (lbs_4k && block_size_setting && (block_size_setting < 4096)) {
+ log_error("Writecache block size %u not allowed with device logical block size 4096.",
+ block_size_setting);
+ goto_bad;
+ }
+
+ if (dm_snprintf(pathname, sizeof(pathname), "%s%s/%s", cmd->dev_dir,
+ lv->vg->name, lv->name) < 0) {
+ log_error("Path name too long to get LV block size %s", display_lvname(lv));
+ goto_bad;
+ }
+
+ if (!(fs_dev = dev_cache_get(cmd, pathname, NULL))) {
+ log_error("Device for LV not found to check block size %s", display_lvname(lv));
+ goto_bad;
+ }
+
+ /*
+ * get_fs_block_size() returns the libblkid BLOCK_SIZE value,
+ * where libblkid has fs-specific code to set BLOCK_SIZE to the
+ * value we need here.
+ *
+ * The term "block size" here may not equate directly to what the fs
+ * calls the block size, e.g. xfs calls this the sector size (and
+ * something different the block size); while ext4 does call this
+ * value the block size, but it's possible values are not the same
+ * as xfs's, and do not seem to relate directly to the device LBS.
+ *
+ * With 512 LBS and 4K PBS, mkfs.xfs will use xfs sector size 4K.
+ */
+ rv = get_fs_block_size(fs_dev, &fs_block_size);
+ if (!rv || !fs_block_size) {
+ if (lbs_4k && pbs_4k && !pbs_512) {
+ block_size = 4096;
+ } else if (lbs_512 && pbs_512 && !pbs_4k) {
+ block_size = 512;
+ } else if (lbs_512 && pbs_4k) {
+ if (block_size_setting == 4096)
+ block_size = 4096;
+ else
+ block_size = 512;
+ } else {
+ block_size = 512;
+ }
+
+ if (block_size_setting && (block_size_setting != block_size)) {
+ log_error("Cannot use writecache block size %u with unknown file system block size, logical block size %u, physical block size %u.",
+ block_size_setting, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
+ goto bad;
+ }
+
+ if (block_size != 512) {
+ log_warn("WARNING: unable to detect a file system block size on %s", display_lvname(lv));
+ log_warn("WARNING: using a writecache block size larger than the file system block size may corrupt the file system.");
+ if (!arg_is_set(cmd, yes_ARG) &&
+ yes_no_prompt("Use writecache block size %u? [y/n]: ", block_size) == 'n') {
+ log_error("Conversion aborted.");
+ goto bad;
+ }
+ }
+
+ log_print("Using writecache block size %u for unknown file system block size, logical block size %u, physical block size %u.",
+ block_size, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
+ goto out;
+ }
+
+ if (!block_size_setting) {
+ /* User did not specify a block size, so choose according to fs block size. */
+ if (fs_block_size == 4096)
+ block_size = 4096;
+ else if (fs_block_size == 512)
+ block_size = 512;
+ else if (fs_block_size > 4096)
+ block_size = 4096;
+ else if (fs_block_size < 4096)
+ block_size = 512;
+ else
+ goto_bad;
+ } else {
+ if (block_size_setting <= fs_block_size)
+ block_size = block_size_setting;
+ else {
+ log_error("Writecache block size %u cannot be larger than file system block size %u.",
+ block_size_setting, fs_block_size);
+ goto_bad;
+ }
+ }
+
+out:
+ if (block_size == 512)
+ *block_size_sectors = 1;
+ else if (block_size == 4096)
+ *block_size_sectors = 8;
+ else
+ goto_bad;
+
+ return 1;
+bad:
+ return 0;
+}
static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
struct logical_volume *lv,
@@ -5444,7 +5603,7 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
struct logical_volume *lv_fast;
struct writecache_settings settings;
const char *fast_name;
- uint32_t block_size_sectors;
+ uint32_t block_size_sectors = 0;
char *lockd_fast_args = NULL;
char *lockd_fast_name = NULL;
struct id lockd_fast_id;
@@ -5472,16 +5631,6 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
goto bad;
}
- /*
- * To permit this we need to check the block size of the fs using lv
- * (recently in libblkid) so that we can use a matching writecache
- * block size. We also want to do that if the lv is inactive.
- */
- if (lv_is_active(lv)) {
- log_error("LV %s must be inactive to attach writecache.", display_lvname(lv));
- 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));
@@ -5489,13 +5638,15 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
}
memset(&settings, 0, sizeof(settings));
- block_size_sectors = DEFAULT_WRITECACHE_BLOCK_SIZE_SECTORS;
if (!get_writecache_settings(cmd, &settings, &block_size_sectors)) {
log_error("Invalid writecache settings.");
goto bad;
}
+ if (!_set_writecache_block_size(cmd, lv, &block_size_sectors))
+ 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.");
3 years, 10 months
master - writecache: cachesettings in lvchange and lvs
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=1ee42f13915d852008b...
Commit: 1ee42f13915d852008b1e7b777edee766413ef89
Parent: ce772bfab976d89f6a35a442434d1a49ceb634c7
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Feb 26 14:47:29 2020 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jun 10 12:14:00 2020 -0500
writecache: cachesettings in lvchange and lvs
lvchange --cachesettings
lvs -o+cache_settings
---
lib/metadata/metadata-exported.h | 1 +
lib/metadata/writecache_manip.c | 70 ++++++++++++++++++
lib/report/report.c | 10 +++
tools/command-lines.in | 2 +-
tools/lvchange.c | 75 +++++++++++++++++++
tools/lvconvert.c | 153 +--------------------------------------
tools/toollib.c | 150 ++++++++++++++++++++++++++++++++++++++
tools/toollib.h | 3 +
8 files changed, 311 insertions(+), 153 deletions(-)
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 9de088437..0d6be136b 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -1096,6 +1096,7 @@ int lv_is_cow(const struct logical_volume *lv);
int lv_is_cache_origin(const struct logical_volume *lv);
int lv_is_writecache_origin(const struct logical_volume *lv);
int lv_is_writecache_cachevol(const struct logical_volume *lv);
+int writecache_settings_to_str_list(struct writecache_settings *settings, struct dm_list *result, struct dm_pool *mem);
int lv_is_integrity_origin(const struct logical_volume *lv);
diff --git a/lib/metadata/writecache_manip.c b/lib/metadata/writecache_manip.c
index 4f09e69cf..e24bcb76b 100644
--- a/lib/metadata/writecache_manip.c
+++ b/lib/metadata/writecache_manip.c
@@ -22,6 +22,7 @@
#include "lib/metadata/lv_alloc.h"
#include "lib/activate/activate.h"
#include "lib/config/defaults.h"
+#include "lib/datastruct/str_list.h"
int lv_is_writecache_origin(const struct logical_volume *lv)
{
@@ -394,3 +395,72 @@ int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
return _lv_detach_writecache_cachevol_inactive(lv, noflush);
}
+static int _writecache_setting_str_list_add(const char *field, uint64_t val, char *val_str, struct dm_list *result, struct dm_pool *mem)
+{
+ char buf[128];
+ char *list_item;
+ int len;
+
+ if (val_str) {
+ if (dm_snprintf(buf, sizeof(buf), "%s=%s", field, val_str) < 0)
+ return_0;
+ } else {
+ if (dm_snprintf(buf, sizeof(buf), "%s=%llu", field, (unsigned long long)val) < 0)
+ return_0;
+ }
+
+ len = strlen(buf) + 1;
+
+ if (!(list_item = dm_pool_zalloc(mem, len)))
+ return_0;
+
+ memcpy(list_item, buf, len);
+
+ if (!str_list_add_no_dup_check(mem, result, list_item))
+ return_0;
+
+ return 1;
+}
+
+int writecache_settings_to_str_list(struct writecache_settings *settings, struct dm_list *result, struct dm_pool *mem)
+{
+ int errors = 0;
+
+ if (settings->high_watermark_set)
+ if (!_writecache_setting_str_list_add("high_watermark", settings->high_watermark, NULL, result, mem))
+ errors++;
+
+ if (settings->low_watermark_set)
+ if (!_writecache_setting_str_list_add("low_watermark", settings->low_watermark, NULL, result, mem))
+ errors++;
+
+ if (settings->writeback_jobs_set)
+ if (!_writecache_setting_str_list_add("writeback_jobs", settings->writeback_jobs, NULL, result, mem))
+ errors++;
+
+ if (settings->autocommit_blocks_set)
+ if (!_writecache_setting_str_list_add("autocommit_blocks", settings->autocommit_blocks, NULL, result, mem))
+ errors++;
+
+ if (settings->autocommit_time_set)
+ if (!_writecache_setting_str_list_add("autocommit_time", settings->autocommit_time, NULL, result, mem))
+ errors++;
+
+ if (settings->fua_set)
+ if (!_writecache_setting_str_list_add("fua", (uint64_t)settings->fua, NULL, result, mem))
+ errors++;
+
+ if (settings->nofua_set)
+ if (!_writecache_setting_str_list_add("nofua", (uint64_t)settings->nofua, NULL, result, mem))
+ errors++;
+
+ if (settings->new_key && settings->new_val)
+ if (!_writecache_setting_str_list_add(settings->new_key, 0, settings->new_val, result, mem))
+ errors++;
+
+ if (errors)
+ log_warn("Failed to create list of writecache settings.");
+
+ return 1;
+}
+
diff --git a/lib/report/report.c b/lib/report/report.c
index e1c630576..268bed61b 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -1430,6 +1430,16 @@ static int _cache_settings_disp(struct dm_report *rh, struct dm_pool *mem,
struct _str_list_append_baton baton;
struct dm_list dummy_list; /* dummy list to display "nothing" */
+ if (seg_is_writecache(seg)) {
+ if (!(result = str_list_create(mem)))
+ return_0;
+
+ if (!writecache_settings_to_str_list(&seg->writecache_settings, result, mem))
+ return_0;
+
+ return _field_set_string_list(rh, field, result, private, 0, NULL);
+ }
+
if (seg_is_cache(seg) && lv_is_cache_vol(seg->pool_lv))
setting_seg = seg;
diff --git a/tools/command-lines.in b/tools/command-lines.in
index ed3d0413a..98044a918 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -247,7 +247,7 @@ RULE: --profile not --detachprofile
RULE: --metadataprofile not --detachprofile
RULE: --minrecoveryrate --maxrecoveryrate and LV_raid
RULE: --writebehind --writemostly and LV_raid1
-RULE: --cachemode --cachepolicy --cachesettings and LV_cache LV_cachepool
+RULE: --cachemode --cachepolicy --cachesettings and LV_cache LV_cachepool LV_writecache
RULE: --errorwhenfull --discards --zero and LV_thinpool
RULE: --permission not lv_is_external_origin lv_is_raid_metadata lv_is_raid_image LV_thinpool
RULE: --alloc --contiguous --metadataprofile --permission --persistent --profile --readahead not lv_is_thick_origin
diff --git a/tools/lvchange.c b/tools/lvchange.c
index 2d5bb32be..ba24e8239 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -606,6 +606,78 @@ static int _lvchange_persistent(struct cmd_context *cmd,
return 1;
}
+static int _lvchange_writecache(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ uint32_t *mr)
+{
+ struct writecache_settings settings = { 0 };
+ uint32_t block_size_sectors = 0;
+ struct lv_segment *seg = first_seg(lv);
+ int set_count = 0;
+
+ if (!get_writecache_settings(cmd, &settings, &block_size_sectors))
+ return_0;
+
+ if (block_size_sectors && (seg->writecache_block_size != (block_size_sectors * 512))) {
+ log_error("Cannot change existing block size %u bytes.", seg->writecache_block_size);
+ return 0;
+ }
+
+ if (settings.high_watermark_set) {
+ seg->writecache_settings.high_watermark_set = settings.high_watermark_set;
+ seg->writecache_settings.high_watermark = settings.high_watermark;
+ set_count++;
+ }
+ if (settings.low_watermark_set) {
+ seg->writecache_settings.low_watermark_set = settings.low_watermark_set;
+ seg->writecache_settings.low_watermark = settings.low_watermark;
+ set_count++;
+ }
+ if (settings.writeback_jobs_set) {
+ seg->writecache_settings.writeback_jobs_set = settings.writeback_jobs_set;
+ seg->writecache_settings.writeback_jobs = settings.writeback_jobs;
+ set_count++;
+ }
+ if (settings.autocommit_blocks_set) {
+ seg->writecache_settings.autocommit_blocks_set = settings.autocommit_blocks_set;
+ seg->writecache_settings.autocommit_blocks = settings.autocommit_blocks;
+ set_count++;
+ }
+ if (settings.autocommit_time_set) {
+ seg->writecache_settings.autocommit_time_set = settings.autocommit_time_set;
+ seg->writecache_settings.autocommit_time = settings.autocommit_time;
+ set_count++;
+ }
+ if (settings.fua_set) {
+ seg->writecache_settings.fua_set = settings.fua_set;
+ seg->writecache_settings.fua = settings.fua;
+ set_count++;
+ }
+ if (settings.nofua_set) {
+ seg->writecache_settings.nofua_set = settings.nofua_set;
+ seg->writecache_settings.nofua = settings.nofua;
+ set_count++;
+ }
+
+ if (!set_count) {
+ /*
+ * Empty settings can be used to clear all current settings,
+ * lvchange --cachesettings "" vg/lv
+ */
+ if (!arg_count(cmd, yes_ARG) &&
+ yes_no_prompt("Clear all writecache settings? ") == 'n') {
+ log_print("No settings changed.");
+ return 1;
+ }
+ memset(&seg->writecache_settings, 0, sizeof(struct writecache_settings));
+ }
+
+ /* Request caller to commit and reload metadata */
+ *mr |= MR_RELOAD;
+
+ return 1;
+}
+
static int _lvchange_cache(struct cmd_context *cmd,
struct logical_volume *lv,
uint32_t *mr)
@@ -619,6 +691,9 @@ static int _lvchange_cache(struct cmd_context *cmd,
int r = 0, is_clean;
uint32_t chunk_size = 0; /* FYI: lvchange does NOT support its change */
+ if (lv_is_writecache(lv))
+ return _lvchange_writecache(cmd, lv, mr);
+
seg = first_seg(lv);
if (seg_is_cache(seg) && lv_is_cache_vol(seg->pool_lv))
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 7935eb74e..757e708ff 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -5389,157 +5389,6 @@ static int _writecache_zero(struct cmd_context *cmd, struct logical_volume *lv)
return ret;
}
-static int _get_one_writecache_setting(struct cmd_context *cmd, struct writecache_settings *settings,
- char *key, char *val, uint32_t *block_size_sectors)
-{
- /* special case: block_size is not a setting but is set with the --cachesettings option */
- if (!strncmp(key, "block_size", strlen("block_size"))) {
- uint32_t block_size = 0;
- if (sscanf(val, "%u", &block_size) != 1)
- goto_bad;
- if (block_size == 512)
- *block_size_sectors = 1;
- else if (block_size == 4096)
- *block_size_sectors = 8;
- else
- goto_bad;
- return 1;
- }
-
- if (!strncmp(key, "high_watermark", strlen("high_watermark"))) {
- if (sscanf(val, "%llu", (unsigned long long *)&settings->high_watermark) != 1)
- goto_bad;
- if (settings->high_watermark > 100)
- goto_bad;
- settings->high_watermark_set = 1;
- return 1;
- }
-
- if (!strncmp(key, "low_watermark", strlen("low_watermark"))) {
- if (sscanf(val, "%llu", (unsigned long long *)&settings->low_watermark) != 1)
- goto_bad;
- if (settings->low_watermark > 100)
- goto_bad;
- settings->low_watermark_set = 1;
- return 1;
- }
-
- if (!strncmp(key, "writeback_jobs", strlen("writeback_jobs"))) {
- if (sscanf(val, "%llu", (unsigned long long *)&settings->writeback_jobs) != 1)
- goto_bad;
- settings->writeback_jobs_set = 1;
- return 1;
- }
-
- if (!strncmp(key, "autocommit_blocks", strlen("autocommit_blocks"))) {
- if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_blocks) != 1)
- goto_bad;
- settings->autocommit_blocks_set = 1;
- return 1;
- }
-
- if (!strncmp(key, "autocommit_time", strlen("autocommit_time"))) {
- if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_time) != 1)
- goto_bad;
- settings->autocommit_time_set = 1;
- return 1;
- }
-
- if (!strncmp(key, "fua", strlen("fua"))) {
- if (settings->nofua_set) {
- log_error("Setting fua and nofua cannot both be set.");
- return 0;
- }
- if (sscanf(val, "%u", &settings->fua) != 1)
- goto_bad;
- settings->fua_set = 1;
- return 1;
- }
-
- if (!strncmp(key, "nofua", strlen("nofua"))) {
- if (settings->fua_set) {
- log_error("Setting fua and nofua cannot both be set.");
- return 0;
- }
- if (sscanf(val, "%u", &settings->nofua) != 1)
- goto_bad;
- settings->nofua_set = 1;
- return 1;
- }
-
- if (settings->new_key) {
- log_error("Setting %s is not recognized. Only one unrecognized setting is allowed.", key);
- return 0;
- }
-
- log_warn("Unrecognized writecache setting \"%s\" may cause activation failure.", key);
- if (yes_no_prompt("Use unrecognized writecache setting? [y/n]: ") == 'n') {
- log_error("Aborting writecache conversion.");
- return 0;
- }
-
- log_warn("Using unrecognized writecache setting: %s = %s.", key, val);
-
- settings->new_key = dm_pool_strdup(cmd->mem, key);
- settings->new_val = dm_pool_strdup(cmd->mem, val);
- return 1;
-
- bad:
- log_error("Invalid setting: %s", key);
- return 0;
-}
-
-static int _get_writecache_settings(struct cmd_context *cmd, struct writecache_settings *settings,
- uint32_t *block_size_sectors)
-{
- struct arg_value_group_list *group;
- const char *str;
- char key[64];
- char val[64];
- int num;
- int pos;
-
- /*
- * "grouped" means that multiple --cachesettings options can be used.
- * Each option is also allowed to contain multiple key = val pairs.
- */
-
- dm_list_iterate_items(group, &cmd->arg_value_groups) {
- if (!grouped_arg_is_set(group->arg_values, cachesettings_ARG))
- continue;
-
- if (!(str = grouped_arg_str_value(group->arg_values, cachesettings_ARG, NULL)))
- break;
-
- pos = 0;
-
- while (pos < strlen(str)) {
- /* scan for "key1=val1 key2 = val2 key3= val3" */
-
- memset(key, 0, sizeof(key));
- memset(val, 0, sizeof(val));
-
- if (sscanf(str + pos, " %63[^=]=%63s %n", key, val, &num) != 2) {
- log_error("Invalid setting at: %s", str+pos);
- return 0;
- }
-
- pos += num;
-
- if (!_get_one_writecache_setting(cmd, settings, key, val, block_size_sectors))
- return_0;
- }
- }
-
- if (settings->high_watermark_set && settings->low_watermark_set &&
- (settings->high_watermark <= settings->low_watermark)) {
- log_error("High watermark must be greater than low watermark.");
- return 0;
- }
-
- return 1;
-}
-
static struct logical_volume *_lv_writecache_create(struct cmd_context *cmd,
struct logical_volume *lv,
struct logical_volume *lv_fast,
@@ -5642,7 +5491,7 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
memset(&settings, 0, sizeof(settings));
block_size_sectors = DEFAULT_WRITECACHE_BLOCK_SIZE_SECTORS;
- if (!_get_writecache_settings(cmd, &settings, &block_size_sectors)) {
+ if (!get_writecache_settings(cmd, &settings, &block_size_sectors)) {
log_error("Invalid writecache settings.");
goto bad;
}
diff --git a/tools/toollib.c b/tools/toollib.c
index 89b637407..94e6e6c44 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -1184,6 +1184,156 @@ out:
return ok;
}
+static int _get_one_writecache_setting(struct cmd_context *cmd, struct writecache_settings *settings,
+ char *key, char *val, uint32_t *block_size_sectors)
+{
+ /* special case: block_size is not a setting but is set with the --cachesettings option */
+ if (!strncmp(key, "block_size", strlen("block_size"))) {
+ uint32_t block_size = 0;
+ if (sscanf(val, "%u", &block_size) != 1)
+ goto_bad;
+ if (block_size == 512)
+ *block_size_sectors = 1;
+ else if (block_size == 4096)
+ *block_size_sectors = 8;
+ else
+ goto_bad;
+ return 1;
+ }
+
+ if (!strncmp(key, "high_watermark", strlen("high_watermark"))) {
+ if (sscanf(val, "%llu", (unsigned long long *)&settings->high_watermark) != 1)
+ goto_bad;
+ if (settings->high_watermark > 100)
+ goto_bad;
+ settings->high_watermark_set = 1;
+ return 1;
+ }
+
+ if (!strncmp(key, "low_watermark", strlen("low_watermark"))) {
+ if (sscanf(val, "%llu", (unsigned long long *)&settings->low_watermark) != 1)
+ goto_bad;
+ if (settings->low_watermark > 100)
+ goto_bad;
+ settings->low_watermark_set = 1;
+ return 1;
+ }
+
+ if (!strncmp(key, "writeback_jobs", strlen("writeback_jobs"))) {
+ if (sscanf(val, "%llu", (unsigned long long *)&settings->writeback_jobs) != 1)
+ goto_bad;
+ settings->writeback_jobs_set = 1;
+ return 1;
+ }
+
+ if (!strncmp(key, "autocommit_blocks", strlen("autocommit_blocks"))) {
+ if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_blocks) != 1)
+ goto_bad;
+ settings->autocommit_blocks_set = 1;
+ return 1;
+ }
+
+ if (!strncmp(key, "autocommit_time", strlen("autocommit_time"))) {
+ if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_time) != 1)
+ goto_bad;
+ settings->autocommit_time_set = 1;
+ return 1;
+ }
+
+ if (!strncmp(key, "fua", strlen("fua"))) {
+ if (settings->nofua_set) {
+ log_error("Setting fua and nofua cannot both be set.");
+ return 0;
+ }
+ if (sscanf(val, "%u", &settings->fua) != 1)
+ goto_bad;
+ settings->fua_set = 1;
+ return 1;
+ }
+
+ if (!strncmp(key, "nofua", strlen("nofua"))) {
+ if (settings->fua_set) {
+ log_error("Setting fua and nofua cannot both be set.");
+ return 0;
+ }
+ if (sscanf(val, "%u", &settings->nofua) != 1)
+ goto_bad;
+ settings->nofua_set = 1;
+ return 1;
+ }
+
+ if (settings->new_key) {
+ log_error("Setting %s is not recognized. Only one unrecognized setting is allowed.", key);
+ return 0;
+ }
+
+ log_warn("Unrecognized writecache setting \"%s\" may cause activation failure.", key);
+ if (yes_no_prompt("Use unrecognized writecache setting? [y/n]: ") == 'n') {
+ log_error("Aborting writecache conversion.");
+ return 0;
+ }
+
+ log_warn("Using unrecognized writecache setting: %s = %s.", key, val);
+
+ settings->new_key = dm_pool_strdup(cmd->mem, key);
+ settings->new_val = dm_pool_strdup(cmd->mem, val);
+ return 1;
+
+ bad:
+ log_error("Invalid setting: %s", key);
+ return 0;
+}
+
+int get_writecache_settings(struct cmd_context *cmd, struct writecache_settings *settings,
+ uint32_t *block_size_sectors)
+{
+ struct arg_value_group_list *group;
+ const char *str;
+ char key[64];
+ char val[64];
+ int num;
+ int pos;
+
+ /*
+ * "grouped" means that multiple --cachesettings options can be used.
+ * Each option is also allowed to contain multiple key = val pairs.
+ */
+
+ dm_list_iterate_items(group, &cmd->arg_value_groups) {
+ if (!grouped_arg_is_set(group->arg_values, cachesettings_ARG))
+ continue;
+
+ if (!(str = grouped_arg_str_value(group->arg_values, cachesettings_ARG, NULL)))
+ break;
+
+ pos = 0;
+
+ while (pos < strlen(str)) {
+ /* scan for "key1=val1 key2 = val2 key3= val3" */
+
+ memset(key, 0, sizeof(key));
+ memset(val, 0, sizeof(val));
+
+ if (sscanf(str + pos, " %63[^=]=%63s %n", key, val, &num) != 2) {
+ log_error("Invalid setting at: %s", str+pos);
+ return 0;
+ }
+
+ pos += num;
+
+ if (!_get_one_writecache_setting(cmd, settings, key, val, block_size_sectors))
+ return_0;
+ }
+ }
+
+ if (settings->high_watermark_set && settings->low_watermark_set &&
+ (settings->high_watermark <= settings->low_watermark)) {
+ log_error("High watermark must be greater than low watermark.");
+ return 0;
+ }
+
+ return 1;
+}
/* FIXME move to lib */
static int _pv_change_tag(struct physical_volume *pv, const char *tag, int addtag)
diff --git a/tools/toollib.h b/tools/toollib.h
index 53a5e5b4f..f3a60fbc4 100644
--- a/tools/toollib.h
+++ b/tools/toollib.h
@@ -217,6 +217,9 @@ int get_cache_params(struct cmd_context *cmd,
const char **name,
struct dm_config_tree **settings);
+int get_writecache_settings(struct cmd_context *cmd, struct writecache_settings *settings,
+ uint32_t *block_size_sectors);
+
int change_tag(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv, struct physical_volume *pv, int arg);
3 years, 10 months
master - writecache: show error in lv_health_status and lv_attr
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=ce772bfab976d89f6a3...
Commit: ce772bfab976d89f6a35a442434d1a49ceb634c7
Parent: 240062a18365a7f6725ebcf1b035a6e0a3b12803
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Feb 25 16:20:05 2020 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jun 10 12:13:48 2020 -0500
writecache: show error in lv_health_status and lv_attr
lv_attr is 'E' and lv_health_status is 'error'
when dm-writecache status reports error.
---
lib/metadata/lv.c | 3 +++
lib/report/report.c | 6 ++++++
man/lvs.8_end | 4 ++++
3 files changed, 13 insertions(+)
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index 4ee58b419..fac47e530 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -1412,6 +1412,9 @@ char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_
} else if (lvdm->seg_status.type == SEG_STATUS_THIN) {
if (lvdm->seg_status.thin->fail)
repstr[8] = 'F';
+ } else if (lvdm->seg_status.type == SEG_STATUS_WRITECACHE) {
+ if (lvdm->seg_status.writecache->error)
+ repstr[8] = 'E';
} else if (lvdm->seg_status.type == SEG_STATUS_UNKNOWN)
repstr[8] = 'X'; /* Unknown */
diff --git a/lib/report/report.c b/lib/report/report.c
index 170df6995..e1c630576 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -3802,6 +3802,12 @@ static int _lvhealthstatus_disp(struct dm_report *rh, struct dm_pool *mem,
health = "failed";
else if (lvdm->seg_status.cache->read_only)
health = "metadata_read_only";
+ } else if (lv_is_writecache(lv) && (lvdm->seg_status.type != SEG_STATUS_NONE)) {
+ if (lvdm->seg_status.type != SEG_STATUS_WRITECACHE)
+ return _field_set_value(field, GET_FIRST_RESERVED_NAME(health_undef),
+ GET_FIELD_RESERVED_VALUE(health_undef));
+ if (lvdm->seg_status.writecache->error)
+ health = "error";
} else if (lv_is_thin_pool(lv) && (lvdm->seg_status.type != SEG_STATUS_NONE)) {
if (lvdm->seg_status.type != SEG_STATUS_THIN_POOL)
return _field_set_value(field, GET_FIRST_RESERVED_NAME(health_undef),
diff --git a/man/lvs.8_end b/man/lvs.8_end
index 6efc9cb4f..5a4ecc83c 100644
--- a/man/lvs.8_end
+++ b/man/lvs.8_end
@@ -74,5 +74,9 @@ 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.
3 years, 10 months
master - writecache: remove from an active lv
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=240062a18365a7f6725...
Commit: 240062a18365a7f6725ebcf1b035a6e0a3b12803
Parent: 8806f2d5ed4792042b246b930fb44f24b9ee45c2
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Feb 24 13:52:12 2020 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jun 10 12:13:31 2020 -0500
writecache: remove from an active lv
---
lib/metadata/lv_manip.c | 17 ++-
lib/metadata/metadata-exported.h | 3 +-
lib/metadata/writecache_manip.c | 288 +++++++++++++++++++++++++++++++++------
test/shell/writecache-split.sh | 35 +++--
tools/lvconvert.c | 42 ++----
5 files changed, 294 insertions(+), 91 deletions(-)
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 1311f70bd..c1c86aa4c 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -6568,7 +6568,20 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
}
}
- if (lv_is_used_cache_pool(lv) || lv_is_cache_vol(lv)) {
+ if (lv_is_cache_vol(lv)) {
+ if ((cache_seg = get_only_segment_using_this_lv(lv))) {
+ /* When used with cache, lvremove on cachevol also removes the cache! */
+ if (seg_is_cache(cache_seg)) {
+ if (!lv_cache_remove(cache_seg->lv))
+ return_0;
+ } else if (seg_is_writecache(cache_seg)) {
+ log_error("Detach cachevol before removing.");
+ return 0;
+ }
+ }
+ }
+
+ if (lv_is_used_cache_pool(lv)) {
/* Cache pool removal drops cache layer
* If the cache pool is not linked, we can simply remove it. */
if (!(cache_seg = get_only_segment_using_this_lv(lv)))
@@ -6832,7 +6845,7 @@ static int _lv_update_and_reload(struct logical_volume *lv, int origin_only)
}
if (!(origin_only ? suspend_lv_origin(vg->cmd, lock_lv) : suspend_lv(vg->cmd, lock_lv))) {
- log_error("Failed to lock logical volume %s.",
+ log_error("Failed to suspend logical volume %s.",
display_lvname(lock_lv));
vg_revert(vg);
} else if (!(r = vg_commit(vg)))
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 083f74a28..9de088437 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -89,8 +89,7 @@
#define PARTIAL_LV UINT64_C(0x0000000001000000) /* LV - derived flag, not
written out in metadata*/
-//#define POSTORDER_FLAG UINT64_C(0x0000000002000000) /* Not real flags, reserved for
-//#define POSTORDER_OPEN_FLAG UINT64_C(0x0000000004000000) temporary use inside vg_read_internal. */
+#define WRITECACHE_ORIGIN UINT64_C(0x0000000002000000)
#define INTEGRITY_METADATA UINT64_C(0x0000000004000000) /* LV - Internal use only */
#define VIRTUAL_ORIGIN UINT64_C(0x0000000008000000) /* LV - internal use only */
diff --git a/lib/metadata/writecache_manip.c b/lib/metadata/writecache_manip.c
index 31d069edb..4f09e69cf 100644
--- a/lib/metadata/writecache_manip.c
+++ b/lib/metadata/writecache_manip.c
@@ -19,6 +19,7 @@
#include "lib/commands/toolcontext.h"
#include "lib/display/display.h"
#include "lib/metadata/segtype.h"
+#include "lib/metadata/lv_alloc.h"
#include "lib/activate/activate.h"
#include "lib/config/defaults.h"
@@ -26,6 +27,15 @@ int lv_is_writecache_origin(const struct logical_volume *lv)
{
struct lv_segment *seg;
+ /*
+ * This flag is needed when removing writecache from an origin
+ * in which case the lv connections have been destroyed and
+ * identifying a writecache origin by these connections doesn't
+ * work.
+ */
+ if (lv->status & WRITECACHE_ORIGIN)
+ return 1;
+
/* Make sure there's exactly one segment in segs_using_this_lv! */
if (dm_list_empty(&lv->segs_using_this_lv) ||
(dm_list_size(&lv->segs_using_this_lv) > 1))
@@ -48,46 +58,6 @@ int lv_is_writecache_cachevol(const struct logical_volume *lv)
return 0;
}
-static int _lv_writecache_detach(struct cmd_context *cmd, struct logical_volume *lv,
- struct logical_volume *lv_fast)
-{
- struct lv_segment *seg = first_seg(lv);
- struct logical_volume *origin;
-
- if (!seg_is_writecache(seg)) {
- log_error("LV %s segment is not writecache.", display_lvname(lv));
- return 0;
- }
-
- if (!seg->writecache) {
- log_error("LV %s writecache segment has no writecache.", display_lvname(lv));
- return 0;
- }
-
- if (!(origin = seg_lv(seg, 0))) {
- log_error("LV %s writecache segment has no origin", display_lvname(lv));
- return 0;
- }
-
- if (!remove_seg_from_segs_using_this_lv(seg->writecache, seg))
- return_0;
-
- lv_set_visible(seg->writecache);
-
- lv->status &= ~WRITECACHE;
- seg->writecache = NULL;
-
- lv_fast->status &= ~LV_CACHE_VOL;
-
- if (!remove_layer_from_lv(lv, origin))
- return_0;
-
- if (!lv_remove(origin))
- return_0;
-
- return 1;
-}
-
static int _get_writecache_kernel_error(struct cmd_context *cmd,
struct logical_volume *lv,
uint32_t *kernel_error)
@@ -131,13 +101,64 @@ fail:
return 0;
}
-int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
+static void _rename_detached_cvol(struct cmd_context *cmd, struct logical_volume *lv_fast)
+{
+ struct volume_group *vg = lv_fast->vg;
+ char cvol_name[NAME_LEN];
+ char *suffix, *cvol_name_dup;
+
+ /*
+ * Rename lv_fast back to its original name, without the _cvol
+ * suffix that was added when lv_fast was attached for caching.
+ * If the name is in use, generate new lvol%d.
+ * Failing to rename is not really a problem, so we intentionally
+ * do not consider some things here as errors.
+ */
+ if (!dm_strncpy(cvol_name, lv_fast->name, sizeof(cvol_name)) ||
+ !(suffix = strstr(cvol_name, "_cvol"))) {
+ log_debug("LV %s has no suffix for cachevol (skipping rename).",
+ display_lvname(lv_fast));
+ return;
+ }
+
+ *suffix = 0;
+ if (lv_name_is_used_in_vg(vg, cvol_name, NULL) &&
+ !generate_lv_name(vg, "lvol%d", cvol_name, sizeof(cvol_name))) {
+ log_warn("Failed to generate new unique name for unused LV %s", lv_fast->name);
+ return;
+ }
+
+ if (!(cvol_name_dup = dm_pool_strdup(vg->vgmem, cvol_name))) {
+ stack;
+ return;
+ }
+
+ lv_fast->name = cvol_name_dup;
+}
+
+static int _lv_detach_writecache_cachevol_inactive(struct logical_volume *lv, int noflush)
{
struct cmd_context *cmd = lv->vg->cmd;
+ struct volume_group *vg = lv->vg;
struct logical_volume *lv_fast;
+ struct logical_volume *lv_wcorig;
+ struct lv_segment *seg = first_seg(lv);
uint32_t kernel_error = 0;
- lv_fast = first_seg(lv)->writecache;
+ if (!seg_is_writecache(seg)) {
+ log_error("LV %s segment is not writecache.", display_lvname(lv));
+ return 0;
+ }
+
+ if (!(lv_fast = seg->writecache)) {
+ log_error("LV %s writecache segment has no writecache.", display_lvname(lv));
+ return 0;
+ }
+
+ if (!(lv_wcorig = seg_lv(seg, 0))) {
+ log_error("LV %s writecache segment has no origin", display_lvname(lv));
+ return 0;
+ }
if (noflush)
goto detach;
@@ -157,6 +178,8 @@ int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
if (!sync_local_dev_names(cmd)) {
log_error("Failed to sync local devices before detaching writecache.");
+ if (!deactivate_lv(cmd, lv))
+ log_error("Failed to deactivate %s.", display_lvname(lv));
return 0;
}
@@ -176,7 +199,8 @@ int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
if (kernel_error) {
log_error("Failed to flush writecache (error %u) for %s.", kernel_error, display_lvname(lv));
- deactivate_lv(cmd, lv);
+ if (!deactivate_lv(cmd, lv))
+ log_error("Failed to deactivate %s.", display_lvname(lv));
return 0;
}
@@ -188,11 +212,185 @@ int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
lv->status &= ~LV_TEMPORARY;
detach:
- if (!_lv_writecache_detach(cmd, lv, lv_fast)) {
- log_error("Failed to detach writecache from %s", display_lvname(lv));
+ if (!remove_seg_from_segs_using_this_lv(lv_fast, seg))
+ return_0;
+
+ lv->status &= ~WRITECACHE;
+ seg->writecache = NULL;
+
+ if (!remove_layer_from_lv(lv, lv_wcorig))
+ return_0;
+
+ if (!lv_remove(lv_wcorig))
+ return_0;
+
+ lv_set_visible(lv_fast);
+ lv_fast->status &= ~LV_CACHE_VOL;
+
+ _rename_detached_cvol(cmd, lv_fast);
+
+ if (!vg_write(vg) || !vg_commit(vg))
+ return_0;
+
+ return 1;
+}
+
+static int _lv_detach_writecache_cachevol_active(struct logical_volume *lv, int noflush)
+{
+ struct cmd_context *cmd = lv->vg->cmd;
+ struct volume_group *vg = lv->vg;
+ struct logical_volume *lv_fast;
+ struct logical_volume *lv_wcorig;
+ struct logical_volume *lv_old;
+ struct lv_segment *seg = first_seg(lv);
+ uint32_t kernel_error = 0;
+
+ if (!seg_is_writecache(seg)) {
+ log_error("LV %s segment is not writecache.", display_lvname(lv));
+ return 0;
+ }
+
+ if (!(lv_fast = seg->writecache)) {
+ log_error("LV %s writecache segment has no writecache.", display_lvname(lv));
+ return 0;
+ }
+
+ if (!(lv_wcorig = seg_lv(seg, 0))) {
+ log_error("LV %s writecache segment has no origin", display_lvname(lv));
+ return 0;
+ }
+
+ if (noflush)
+ goto detach;
+
+ if (!lv_writecache_message(lv, "flush_on_suspend")) {
+ log_error("Failed to set flush_on_suspend in writecache detach %s.", display_lvname(lv));
+ return 0;
+ }
+
+ detach:
+ if (!remove_seg_from_segs_using_this_lv(lv_fast, seg)) {
+ log_error("Failed to remove seg in writecache detach.");
+ return 0;
+ }
+
+ lv->status &= ~WRITECACHE;
+ seg->writecache = NULL;
+
+ if (!remove_layer_from_lv(lv, lv_wcorig)) {
+ log_error("Failed to remove lv layer in writecache detach.");
+ return 0;
+ }
+
+ /*
+ * vg_write(), suspend_lv(), vg_commit(), resume_lv().
+ * usually done by lv_update_and_reload for an active lv,
+ * but in this case we need to check for writecache errors
+ * after suspend.
+ */
+
+ if (!vg_write(vg)) {
+ log_error("Failed to write VG in writecache detach.");
+ return 0;
+ }
+
+ /*
+ * The version of LV before removal of writecache. When need to
+ * check for kernel errors based on the old version of LV which
+ * is still present in the kernel.
+ */
+ if (!(lv_old = (struct logical_volume *)lv_committed(lv))) {
+ log_error("Failed to get lv_committed in writecache detach.");
+ return 0;
+ }
+
+ /*
+ * suspend does not use 'lv' as we know it here, but grabs the
+ * old (precommitted) version of 'lv' using lv_committed(),
+ * which is from vg->vg_comitted.
+ */
+ log_debug("Suspending writecache to detach %s", display_lvname(lv));
+
+ if (!suspend_lv(cmd, lv)) {
+ log_error("Failed to suspend LV in writecache detach.");
+ vg_revert(vg);
+ return 0;
+ }
+
+ log_debug("Checking writecache errors to detach.");
+
+ if (!_get_writecache_kernel_error(cmd, lv_old, &kernel_error)) {
+ log_error("Failed to get writecache error status for %s.", display_lvname(lv_old));
+ return 0;
+ }
+
+ if (kernel_error) {
+ log_error("Failed to flush writecache (error %u) for %s.", kernel_error, display_lvname(lv));
+ return 0;
+ }
+
+ if (!vg_commit(vg)) {
+ log_error("Failed to commit VG in writecache detach.");
+ return 0;
+ }
+
+ /*
+ * Since vg_commit has happened, vg->vg_committed is now the
+ * newest copy of lv, so resume uses the 'lv' that we know
+ * here.
+ */
+ log_debug("Resuming after writecache detached %s", display_lvname(lv));
+
+ if (!resume_lv(cmd, lv)) {
+ log_error("Failed to resume LV in writecache detach.");
+ return 0;
+ }
+
+ log_debug("Deactivating previous cachevol %s", display_lvname(lv_fast));
+
+ if (!deactivate_lv(cmd, lv_fast))
+ log_error("Failed to deactivate previous cachevol in writecache detach.");
+
+ /*
+ * Needed for lv_is_writecache_origin to know lv_wcorig was
+ * a writecache origin, which is needed so that the -real
+ * dm uuid suffix is applied, which is needed for deactivate to
+ * work. This is a hacky roundabout way of setting the -real
+ * uuid suffix (it would be nice to have a deactivate command
+ * that accepts a dm uuid.)
+ */
+ lv_wcorig->status |= WRITECACHE_ORIGIN;
+
+ log_debug("Deactivating previous wcorig %s", display_lvname(lv_wcorig));
+
+ if (!lv_deactivate(cmd, NULL, lv_wcorig))
+ log_error("Failed to deactivate previous wcorig LV in writecache detach.");
+
+ log_debug("Removing previous wcorig %s", display_lvname(lv_wcorig));
+
+ if (!lv_remove(lv_wcorig)) {
+ log_error("Failed to remove previous wcorig LV in writecache detach.");
+ return 0;
+ }
+
+ lv_set_visible(lv_fast);
+ lv_fast->status &= ~LV_CACHE_VOL;
+
+ _rename_detached_cvol(cmd, lv_fast);
+
+ if (!vg_write(vg) || !vg_commit(vg)) {
+ log_error("Failed to write and commit VG in writecache detach.");
return 0;
}
return 1;
}
+int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
+{
+ if (lv_is_active(lv))
+ return _lv_detach_writecache_cachevol_active(lv, noflush);
+ else
+ return _lv_detach_writecache_cachevol_inactive(lv, noflush);
+}
+
diff --git a/test/shell/writecache-split.sh b/test/shell/writecache-split.sh
index 0f2dc4729..9553ade0c 100644
--- a/test/shell/writecache-split.sh
+++ b/test/shell/writecache-split.sh
@@ -20,29 +20,21 @@ mkfs_mount_umount()
{
lvt=$1
- lvchange -ay $vg/$lvt
-
mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lvt"
mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
cp pattern1 "$mount_dir/pattern1"
dd if=/dev/zero of="$mount_dir/zeros2M" bs=1M count=32 conv=fdatasync
umount "$mount_dir"
-
- lvchange -an $vg/$lvt
}
mount_umount()
{
lvt=$1
- lvchange -ay $vg/$lvt
-
mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
diff pattern1 "$mount_dir/pattern1"
dd if="$mount_dir/zeros2M" of=/dev/null bs=1M count=32
umount "$mount_dir"
-
- lvchange -an $vg/$lvt
}
aux have_writecache 1 0 0 || skip
@@ -62,18 +54,39 @@ lvcreate -n $lv1 -l 16 -an $vg "$dev1" "$dev4"
lvcreate -n $lv2 -l 4 -an $vg "$dev2"
#
-# split when no devs are missing
+# split while inactive
+#
+
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+
+lvchange -ay $vg/$lv1
+mkfs_mount_umount $lv1
+lvchange -an $vg/$lv1
+
+lvconvert --splitcache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+lvs -o segtype $vg/$lv2 | grep linear
+
+lvchange -ay $vg/$lv1
+mount_umount $lv1
+lvchange -an $vg/$lv1
+
+#
+# split while active
#
lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+lvchange -ay $vg/$lv1
mkfs_mount_umount $lv1
lvconvert --splitcache $vg/$lv1
lvs -o segtype $vg/$lv1 | grep linear
lvs -o segtype $vg/$lv2 | grep linear
+lvchange -ay $vg/$lv1
mount_umount $lv1
+lvchange -an $vg/$lv1
#
# split while cachevol is missing
@@ -81,7 +94,9 @@ mount_umount $lv1
lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+lvchange -ay $vg/$lv1
mkfs_mount_umount $lv1
+lvchange -an $vg/$lv1
aux disable_dev "$dev2"
@@ -108,7 +123,9 @@ lvcreate -n $lv2 -l 14 -an $vg "$dev2" "$dev3"
lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+lvchange -ay $vg/$lv1
mkfs_mount_umount $lv1
+lvchange -an $vg/$lv1
aux disable_dev "$dev3"
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 76e00f0a2..7935eb74e 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -5311,19 +5311,8 @@ static int _lvconvert_detach_writecache(struct cmd_context *cmd,
struct logical_volume *lv,
struct logical_volume *lv_fast)
{
- char cvol_name[NAME_LEN];
- char *c;
int noflush = 0;
- /*
- * LV must be inactive externally before detaching cache.
- */
-
- if (lv_info(cmd, lv, 1, NULL, 0, 0)) {
- log_error("LV %s must be inactive to detach writecache.", display_lvname(lv));
- return 0;
- }
-
if (!archive(lv->vg))
return_0;
@@ -5347,31 +5336,18 @@ static int _lvconvert_detach_writecache(struct cmd_context *cmd,
noflush = 1;
}
- if (!lv_detach_writecache_cachevol(lv, noflush))
- return_0;
-
/*
- * Rename lv_fast back to its original name, without the _cvol
- * suffix that was added when lv_fast was attached for caching.
+ * TODO: send a message to writecache in the kernel to start writing
+ * back cache data to the origin. Then release the vg lock and monitor
+ * the progress of that writeback. When it's complete we can reacquire
+ * the vg lock, rescan the vg (ensure it hasn't changed), and do the
+ * detach which should be quick since the writeback is complete. If
+ * this command is canceled while monitoring writeback, it should just
+ * be rerun. The LV will continue to have the writecache until this
+ * command is run to completion.
*/
- if (!dm_strncpy(cvol_name, lv_fast->name, sizeof(cvol_name)) ||
- !(c = strstr(cvol_name, "_cvol"))) {
- log_debug("LV %s has no suffix for cachevol (skipping rename).",
- display_lvname(lv_fast));
- } else {
- *c = 0;
- /* If the name is in use, generate new lvol%d */
- if (lv_name_is_used_in_vg(lv->vg, cvol_name, NULL) &&
- !generate_lv_name(lv->vg, "lvol%d", cvol_name, sizeof(cvol_name))) {
- log_error("Failed to generate unique name for unused logical volume.");
- return 0;
- }
- if (!lv_rename_update(cmd, lv_fast, cvol_name, 0))
- return_0;
- }
-
- if (!vg_write(lv->vg) || !vg_commit(lv->vg))
+ if (!lv_detach_writecache_cachevol(lv, noflush))
return_0;
backup(lv->vg);
3 years, 10 months
master - blkdeactivate: add missing VDO_AVAILABLE check in deactivate_vdo
by Peter Rajnoha
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=8806f2d5ed4792042b2...
Commit: 8806f2d5ed4792042b246b930fb44f24b9ee45c2
Parent: fa9eb76a5dc8d76a1f06a44337f909c75df1fee9
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Mon Jun 8 15:41:35 2020 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Mon Jun 8 15:41:35 2020 +0200
blkdeactivate: add missing VDO_AVAILABLE check in deactivate_vdo
---
scripts/blkdeactivate.sh.in | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/scripts/blkdeactivate.sh.in b/scripts/blkdeactivate.sh.in
index 57b3e58bf..7c517b87b 100644
--- a/scripts/blkdeactivate.sh.in
+++ b/scripts/blkdeactivate.sh.in
@@ -330,6 +330,12 @@ deactivate_vdo() {
test -b "$DEV_DIR/mapper/$xname" || return 0
test -z "${SKIP_DEVICE_LIST["$kname"]}" || return 1
+ # Skip VDO device deactivation if VDO tools missing.
+ test "$VDO_AVAILABLE" -eq 0 && {
+ add_device_to_skip_list
+ return 1
+ }
+
deactivate_holders "$DEV_DIR/mapper/$xname" || return 1
echo -n " [VDO]: deactivating VDO volume $xname... "
3 years, 10 months
master - improve info about vgck updatemetadata
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=fa9eb76a5dc8d76a1f0...
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"
3 years, 10 months