From 5f1a1fa8b586c972c8c9cf1ab6ffd63a76829be5 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Mar 05 2015 13:26:52 +0000 Subject: import lvm2-2.02.115-3.el7 --- diff --git a/.gitignore b/.gitignore index 7f87764..bd1506b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/LVM2.2.02.105.tgz +SOURCES/LVM2.2.02.115.tgz diff --git a/.lvm2.metadata b/.lvm2.metadata index 2f3f5b8..0ed8558 100644 --- a/.lvm2.metadata +++ b/.lvm2.metadata @@ -1 +1 @@ -796163e766480cdc427cd443dc1336ae8e8e3bd7 SOURCES/LVM2.2.02.105.tgz +bc229c7790b796051a8e45c58bd97ab57eadf360 SOURCES/LVM2.2.02.115.tgz diff --git a/SOURCES/lvm2-2_02_106-additional-lvmetad-fixes.patch b/SOURCES/lvm2-2_02_106-additional-lvmetad-fixes.patch deleted file mode 100644 index f828438..0000000 --- a/SOURCES/lvm2-2_02_106-additional-lvmetad-fixes.patch +++ /dev/null @@ -1,127 +0,0 @@ -commit 923b95504e189fb3b9353a66a3c3a9e147a46e39 -Author: Peter Rajnoha -Date: Wed Mar 5 16:48:17 2014 +0100 - - lvmetad_fixes ---- - WHATS_NEW | 3 +++ - daemons/lvmetad/lvmetad-core.c | 20 +++++++++++++++++--- - test/shell/lvmetad-ambiguous.sh | 34 ++++++++++++++++++++++++++++++++++ - 3 files changed, 54 insertions(+), 3 deletions(-) - -diff --git a/WHATS_NEW b/WHATS_NEW -index 224e351..3ee9585 100644 ---- a/WHATS_NEW -+++ b/WHATS_NEW -@@ -1,5 +1,8 @@ - Version 2.02.106 - - ==================================== -+ Fix cache consistency in lvmetad when PV moves around. -+ Fix memleak when lvmetad discovers PV to appear on another device. -+ Fix invalid memory read in lvmetad that could cause a deadlock. - Fix calculation of maximum size of COW device for snapshot (2.02.99). - Do not allow stripe size to be bigger then extent size for lvresize. - Zero snapshot COW header when creating read-only snapshot. -diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c -index e6e222f..f35db89 100644 ---- a/daemons/lvmetad/lvmetad-core.c -+++ b/daemons/lvmetad/lvmetad-core.c -@@ -861,7 +861,7 @@ static response pv_found(lvmetad_state *s, request r) - const char *vgid = daemon_request_str(r, "metadata/id", NULL); - const char *vgid_old = NULL; - struct dm_config_node *pvmeta = dm_config_find_node(r.cft->root, "pvmeta"); -- uint64_t device; -+ uint64_t device, device_old_pvid = 0; - struct dm_config_tree *cft, *pvmeta_old_dev = NULL, *pvmeta_old_pvid = NULL; - char *old; - char *pvid_dup; -@@ -883,9 +883,12 @@ static response pv_found(lvmetad_state *s, request r) - dm_hash_remove(s->pvid_to_pvmeta, old); - vgid_old = dm_hash_lookup(s->pvid_to_vgid, old); - } -- pvmeta_old_pvid = dm_hash_lookup(s->pvid_to_pvmeta, pvid); - -- DEBUGLOG(s, "pv_found %s, vgid = %s, device = %" PRIu64 ", old = %s", pvid, vgid, device, old); -+ if ((pvmeta_old_pvid = dm_hash_lookup(s->pvid_to_pvmeta, pvid))) -+ dm_config_get_uint64(pvmeta_old_pvid->root, "pvmeta/device", &device_old_pvid); -+ -+ DEBUGLOG(s, "pv_found %s, vgid = %s, device = %" PRIu64 " (previously %" PRIu64 "), old = %s", -+ pvid, vgid, device, device_old_pvid, old); - - dm_free(old); - -@@ -903,6 +906,12 @@ static response pv_found(lvmetad_state *s, request r) - return reply_fail("out of memory"); - } - -+ if (pvmeta_old_pvid && device != device_old_pvid) { -+ DEBUGLOG(s, "pv %s no longer on device %" PRIu64, pvid, device_old_pvid); -+ dm_free(dm_hash_lookup_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid))); -+ dm_hash_remove_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid)); -+ } -+ - if (!dm_hash_insert(s->pvid_to_pvmeta, pvid, cft) || - !dm_hash_insert_binary(s->device_to_pvid, &device, sizeof(device), (void*)pvid_dup)) { - dm_hash_remove(s->pvid_to_pvmeta, pvid); -@@ -911,6 +920,7 @@ static response pv_found(lvmetad_state *s, request r) - dm_free(pvid_dup); - return reply_fail("out of memory"); - } -+ - if (pvmeta_old_pvid) - dm_config_destroy(pvmeta_old_pvid); - if (pvmeta_old_dev && pvmeta_old_dev != pvmeta_old_pvid) -@@ -949,9 +959,13 @@ static response pv_found(lvmetad_state *s, request r) - } - - if (vgid_old && (!vgid || strcmp(vgid, vgid_old))) { -+ /* make a copy, because vg_remove_if_missing will deallocate the -+ * storage behind vgid_old */ -+ vgid_old = dm_strdup(vgid_old); - lock_vg(s, vgid_old); - vg_remove_if_missing(s, vgid_old, 1); - unlock_vg(s, vgid_old); -+ dm_free((char*)vgid_old); - } - - return daemon_reply_simple("OK", -diff --git a/test/shell/lvmetad-ambiguous.sh b/test/shell/lvmetad-ambiguous.sh -new file mode 100644 -index 0000000..455aa5d ---- /dev/null -+++ b/test/shell/lvmetad-ambiguous.sh -@@ -0,0 +1,34 @@ -+#!/bin/sh -+# Copyright (C) 2012 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+. lib/test -+ -+test -e LOCAL_LVMETAD || skip -+ -+aux prepare_pvs 2 -+ -+# flip the devices around -+aux init_udev_transaction -+dmsetup remove -f "$dev1" -+dmsetup remove -f "$dev2" -+dmsetup create -u TEST-${PREFIX}pv2 ${PREFIX}pv2 ${PREFIX}pv2.table -+dmsetup create -u TEST-${PREFIX}pv1 ${PREFIX}pv1 ${PREFIX}pv1.table -+aux finish_udev_transaction -+ -+# re-scan them -+pvscan --cache $dev1 -+pvscan --cache $dev2 -+ -+# expect both to be there -+pvs | tee pvs.txt -+grep $dev1 pvs.txt -+grep $dev2 pvs.txt -+ diff --git a/SOURCES/lvm2-2_02_106-cleanup-stray-warning-messages-for-cmirror-addendum.patch b/SOURCES/lvm2-2_02_106-cleanup-stray-warning-messages-for-cmirror-addendum.patch deleted file mode 100644 index 3b4924b..0000000 --- a/SOURCES/lvm2-2_02_106-cleanup-stray-warning-messages-for-cmirror-addendum.patch +++ /dev/null @@ -1,20 +0,0 @@ - daemons/cmirrord/cluster.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/daemons/cmirrord/cluster.c b/daemons/cmirrord/cluster.c -index 67391f1..3fd5d23 100644 ---- a/daemons/cmirrord/cluster.c -+++ b/daemons/cmirrord/cluster.c -@@ -985,9 +985,9 @@ static int do_cluster_work(void *data __attribute__((unused))) - dm_list_iterate_items_safe(entry, tmp, &clog_cpg_list) { - r = cpg_dispatch(entry->handle, CS_DISPATCH_ALL); - if (r != CS_OK) { -- if ((entry->cpg_state == INVALID) && -- (entry->state == LEAVING) && -- (r == CS_ERR_BAD_HANDLE)) -+ if ((r == CS_ERR_BAD_HANDLE) && -+ ((entry->state == INVALID) || -+ (entry->state == LEAVING))) - /* It's ok if we've left the cluster */ - r = CS_OK; - else diff --git a/SOURCES/lvm2-2_02_106-cleanup-stray-warning-messages-for-cmirror.patch b/SOURCES/lvm2-2_02_106-cleanup-stray-warning-messages-for-cmirror.patch deleted file mode 100644 index bff73f3..0000000 --- a/SOURCES/lvm2-2_02_106-cleanup-stray-warning-messages-for-cmirror.patch +++ /dev/null @@ -1,43 +0,0 @@ -commit 52aa3dbcabe85b38b51c68c27fb2397eb0fb1efd -Author: Jonathan Brassow -Date: Wed Mar 5 10:44:20 2014 -0600 - - cmirrord: Clean-up stray warning message - - cmirrord polls for messages on the kernel and cluster interfaces. - Sometimes it is possible for messages to be received on the cluster - interface and be waiting for processing while the node is in the - process of leaving the cluster group. When this happens, the - messages received on the cluster interface are attempted to be - dispatched, but an error is returned because the connection is no - longer valid. It is a harmless situation. So, if we get the - specific error (CS_ERR_BAD_HANDLE) and we know that we have left - the group, then simply don't print the message. ---- - daemons/cmirrord/cluster.c | 13 ++++++++++--- - 1 file changed, 10 insertions(+), 3 deletions(-) - -diff --git a/daemons/cmirrord/cluster.c b/daemons/cmirrord/cluster.c -index fea739a..67391f1 100644 ---- a/daemons/cmirrord/cluster.c -+++ b/daemons/cmirrord/cluster.c -@@ -984,9 +984,16 @@ static int do_cluster_work(void *data __attribute__((unused))) - - dm_list_iterate_items_safe(entry, tmp, &clog_cpg_list) { - r = cpg_dispatch(entry->handle, CS_DISPATCH_ALL); -- if (r != CS_OK) -- LOG_ERROR("cpg_dispatch failed: %s", -- str_ais_error(r)); -+ if (r != CS_OK) { -+ if ((entry->cpg_state == INVALID) && -+ (entry->state == LEAVING) && -+ (r == CS_ERR_BAD_HANDLE)) -+ /* It's ok if we've left the cluster */ -+ r = CS_OK; -+ else -+ LOG_ERROR("cpg_dispatch failed: %s", -+ str_ais_error(r)); -+ } - - if (entry->free_me) { - free(entry); diff --git a/SOURCES/lvm2-2_02_106-enahnce-lvmetad-protocol-for-pvscan-to-lock-vg-properly-and-run-refresh-only-when-needed.patch b/SOURCES/lvm2-2_02_106-enahnce-lvmetad-protocol-for-pvscan-to-lock-vg-properly-and-run-refresh-only-when-needed.patch deleted file mode 100644 index 336de06..0000000 --- a/SOURCES/lvm2-2_02_106-enahnce-lvmetad-protocol-for-pvscan-to-lock-vg-properly-and-run-refresh-only-when-needed.patch +++ /dev/null @@ -1,325 +0,0 @@ - WHATS_NEW | 5 +++ - daemons/lvmetad/lvmetad-core.c | 74 +++++++++++++++++++++++------------------- - lib/cache/lvmetad.c | 9 +++-- - lib/cache/lvmetad.h | 3 +- - lib/locking/file_locking.c | 2 +- - tools/pvscan.c | 32 ++++++++++-------- - 6 files changed, 74 insertions(+), 51 deletions(-) - -diff --git a/WHATS_NEW b/WHATS_NEW -index a3d48f3..b5afb19 100644 ---- a/WHATS_NEW -+++ b/WHATS_NEW -@@ -1,5 +1,10 @@ - Version 2.02.106 - - ==================================== -+ Use VG read lock during 'pvscan --cache -aay' autoactivation. -+ Issue a VG refresh before autoactivation only if the PV has changed/is new. -+ Add flag to lvmetad protocol to indicate the PV scanned has changed/is new. -+ Also add vgname to lvmetad protocol when referencing VGs for PVs scanned. -+ Use correct PATH_MAX for locking dir path. - Update API for internal function build_dm_uuid(). - Do not try to check empty pool with scheduled messages. - Fix return value in pool_has_message() when quering for any message. -diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c -index f35db89..1858ee2 100644 ---- a/daemons/lvmetad/lvmetad-core.c -+++ b/daemons/lvmetad/lvmetad-core.c -@@ -344,8 +344,8 @@ static response pv_lookup(lvmetad_state *s, request r) - pvid = dm_hash_lookup_binary(s->device_to_pvid, &devt, sizeof(devt)); - - if (!pvid) { -- WARN(s, "pv_lookup: could not find device %" PRIu64, devt); - unlock_pvid_to_pvmeta(s); -+ WARN(s, "pv_lookup: could not find device %" PRIu64, devt); - dm_config_destroy(res.cft); - return reply_unknown("device not found"); - } -@@ -809,30 +809,28 @@ static response pv_gone(lvmetad_state *s, request r) - pvid_old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device)); - vgid = dm_hash_lookup(s->pvid_to_vgid, pvid); - -- if (vgid && !(vgid = dm_strdup(vgid))) { -- unlock_pvid_to_pvmeta(s); -- return reply_fail("out of memory"); -- } -- - dm_hash_remove_binary(s->device_to_pvid, &device, sizeof(device)); - dm_hash_remove(s->pvid_to_pvmeta, pvid); - unlock_pvid_to_pvmeta(s); - -+ dm_free(pvid_old); -+ - if (vgid) { -+ if (!(vgid = dm_strdup(vgid))) -+ return reply_fail("out of memory"); -+ - lock_vg(s, vgid); - vg_remove_if_missing(s, vgid, 1); - unlock_vg(s, vgid); - dm_free(vgid); - } - -- if (pvid_old) -- dm_free(pvid_old); -- -- if (pvmeta) { -- dm_config_destroy(pvmeta); -- return daemon_reply_simple("OK", NULL); -- } else -+ if (!pvmeta) - return reply_unknown("PVID does not exist"); -+ -+ dm_config_destroy(pvmeta); -+ -+ return daemon_reply_simple("OK", NULL); - } - - static response pv_clear_all(lvmetad_state *s, request r) -@@ -866,7 +864,7 @@ static response pv_found(lvmetad_state *s, request r) - char *old; - char *pvid_dup; - int complete = 0, orphan = 0; -- int64_t seqno = -1, seqno_old = -1; -+ int64_t seqno = -1, seqno_old = -1, changed = 0; - - if (!pvid) - return reply_fail("need PV UUID"); -@@ -876,58 +874,60 @@ static response pv_found(lvmetad_state *s, request r) - if (!dm_config_get_uint64(pvmeta, "pvmeta/device", &device)) - return reply_fail("need PV device number"); - -+ if (!(cft = dm_config_create()) || -+ (!(pvid_dup = dm_strdup(pvid)))) { -+ if (cft) -+ dm_config_destroy(cft); -+ return reply_fail("out of memory"); -+ } -+ - lock_pvid_to_pvmeta(s); - -+ if ((pvmeta_old_pvid = dm_hash_lookup(s->pvid_to_pvmeta, pvid))) -+ dm_config_get_uint64(pvmeta_old_pvid->root, "pvmeta/device", &device_old_pvid); -+ - if ((old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device)))) { - pvmeta_old_dev = dm_hash_lookup(s->pvid_to_pvmeta, old); - dm_hash_remove(s->pvid_to_pvmeta, old); - vgid_old = dm_hash_lookup(s->pvid_to_vgid, old); - } - -- if ((pvmeta_old_pvid = dm_hash_lookup(s->pvid_to_pvmeta, pvid))) -- dm_config_get_uint64(pvmeta_old_pvid->root, "pvmeta/device", &device_old_pvid); -- - DEBUGLOG(s, "pv_found %s, vgid = %s, device = %" PRIu64 " (previously %" PRIu64 "), old = %s", - pvid, vgid, device, device_old_pvid, old); - -- dm_free(old); -- -- if (!(cft = dm_config_create()) || -- !(cft->root = dm_config_clone_node(cft, pvmeta, 0))) { -- unlock_pvid_to_pvmeta(s); -- if (cft) -- dm_config_destroy(cft); -- return reply_fail("out of memory"); -- } -+ if (!(cft->root = dm_config_clone_node(cft, pvmeta, 0))) -+ goto out_of_mem; - -- if (!(pvid_dup = dm_strdup(pvid))) { -- unlock_pvid_to_pvmeta(s); -- dm_config_destroy(cft); -- return reply_fail("out of memory"); -- } -+ if (!pvmeta_old_pvid || compare_config(pvmeta_old_pvid->root, cft->root)) -+ changed |= 1; - - if (pvmeta_old_pvid && device != device_old_pvid) { - DEBUGLOG(s, "pv %s no longer on device %" PRIu64, pvid, device_old_pvid); - dm_free(dm_hash_lookup_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid))); - dm_hash_remove_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid)); -+ changed |= 1; - } - - if (!dm_hash_insert(s->pvid_to_pvmeta, pvid, cft) || - !dm_hash_insert_binary(s->device_to_pvid, &device, sizeof(device), (void*)pvid_dup)) { - dm_hash_remove(s->pvid_to_pvmeta, pvid); -+out_of_mem: - unlock_pvid_to_pvmeta(s); - dm_config_destroy(cft); - dm_free(pvid_dup); -+ dm_free(old); - return reply_fail("out of memory"); - } - -+ unlock_pvid_to_pvmeta(s); -+ -+ dm_free(old); -+ - if (pvmeta_old_pvid) - dm_config_destroy(pvmeta_old_pvid); - if (pvmeta_old_dev && pvmeta_old_dev != pvmeta_old_pvid) - dm_config_destroy(pvmeta_old_dev); - -- unlock_pvid_to_pvmeta(s); -- - if (metadata) { - if (!vgid) - return reply_fail("need VG UUID"); -@@ -939,6 +939,7 @@ static response pv_found(lvmetad_state *s, request r) - - if (!update_metadata(s, vgname, vgid, metadata, &seqno_old)) - return reply_fail("metadata update failed"); -+ changed |= (seqno_old != dm_config_find_int(metadata, "metadata/seqno", -1)); - } else { - lock_pvid_to_vgid(s); - vgid = dm_hash_lookup(s->pvid_to_vgid, pvid); -@@ -956,6 +957,11 @@ static response pv_found(lvmetad_state *s, request r) - return reply_fail("non-orphan VG without metadata encountered"); - } - unlock_vg(s, vgid); -+ -+ // TODO: separate vgid->vgname lock -+ lock_vgid_to_metadata(s); -+ vgname = dm_hash_lookup(s->vgid_to_vgname, vgid); -+ unlock_vgid_to_metadata(s); - } - - if (vgid_old && (!vgid || strcmp(vgid, vgid_old))) { -@@ -971,7 +977,9 @@ static response pv_found(lvmetad_state *s, request r) - return daemon_reply_simple("OK", - "status = %s", orphan ? "orphan" : - (complete ? "complete" : "partial"), -+ "changed = %d", changed, - "vgid = %s", vgid ? vgid : "#orphan", -+ "vgname = %s", vgname ? vgname : "#orphan", - "seqno_before = %"PRId64, seqno_old, - "seqno_after = %"PRId64, seqno, - NULL); -diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c -index c994874..38d9042 100644 ---- a/lib/cache/lvmetad.c -+++ b/lib/cache/lvmetad.c -@@ -749,7 +749,8 @@ int lvmetad_pv_found(const struct id *pvid, struct device *dev, const struct for - daemon_reply reply; - struct lvmcache_info *info; - struct dm_config_tree *pvmeta, *vgmeta; -- const char *status, *vgid; -+ const char *status, *vgname, *vgid; -+ int64_t changed; - int result; - - if (!lvmetad_active() || test_mode()) -@@ -818,11 +819,13 @@ int lvmetad_pv_found(const struct id *pvid, struct device *dev, const struct for - - if (result && handler) { - status = daemon_reply_str(reply, "status", ""); -+ vgname = daemon_reply_str(reply, "vgname", ""); - vgid = daemon_reply_str(reply, "vgid", ""); -+ changed = daemon_reply_int(reply, "changed", 0); - if (!strcmp(status, "partial")) -- handler(_lvmetad_cmd, vgid, 1, CHANGE_AAY); -+ handler(_lvmetad_cmd, vgname, vgid, 1, changed, CHANGE_AAY); - else if (!strcmp(status, "complete")) -- handler(_lvmetad_cmd, vgid, 0, CHANGE_AAY); -+ handler(_lvmetad_cmd, vgname, vgid, 0, changed, CHANGE_AAY); - else if (!strcmp(status, "orphan")) - ; - else -diff --git a/lib/cache/lvmetad.h b/lib/cache/lvmetad.h -index 85b71c2..d9aa77f 100644 ---- a/lib/cache/lvmetad.h -+++ b/lib/cache/lvmetad.h -@@ -23,7 +23,8 @@ struct dm_config_tree; - enum activation_change; - - typedef int (*activation_handler) (struct cmd_context *cmd, -- const char *vgid, int partial, -+ const char *vgname, const char *vgid, -+ int partial, int changed, - enum activation_change activate); - - #ifdef LVMETAD_SUPPORT -diff --git a/lib/locking/file_locking.c b/lib/locking/file_locking.c -index fb84c5b..734e0b4 100644 ---- a/lib/locking/file_locking.c -+++ b/lib/locking/file_locking.c -@@ -37,7 +37,7 @@ struct lock_list { - }; - - static struct dm_list _lock_list; --static char _lock_dir[NAME_LEN]; -+static char _lock_dir[PATH_MAX]; - static int _prioritise_write_locks; - - static sig_t _oldhandler; -diff --git a/tools/pvscan.c b/tools/pvscan.c -index 4f99f45..5db627a 100644 ---- a/tools/pvscan.c -+++ b/tools/pvscan.c -@@ -95,13 +95,13 @@ static void _pvscan_display_single(struct cmd_context *cmd, - #define REFRESH_BEFORE_AUTOACTIVATION_RETRY_USLEEP_DELAY 100000 - - static int _auto_activation_handler(struct cmd_context *cmd, -- const char *vgid, int partial, -+ const char *vgname, const char *vgid, -+ int partial, int changed, - activation_change_t activate) - { - unsigned int refresh_retries = REFRESH_BEFORE_AUTOACTIVATION_RETRIES; - int refresh_done = 0; - struct volume_group *vg; -- int consistent = 0; - struct id vgid_raw; - int r = 0; - -@@ -113,8 +113,12 @@ static int _auto_activation_handler(struct cmd_context *cmd, - return_0; - - /* NB. This is safe because we know lvmetad is running and we won't hit disk. */ -- if (!(vg = vg_read_internal(cmd, NULL, (const char *) &vgid_raw, 0, &consistent))) -- return 1; -+ vg = vg_read(cmd, vgname, (const char *)&vgid_raw, 0); -+ if (vg_read_error(vg)) { -+ log_error("Failed to read Volume Group \"%s\" (%s) during autoactivation.", vgname, vgid); -+ release_vg(vg); -+ return 0; -+ } - - if (vg_is_clustered(vg)) { - r = 1; goto out; -@@ -139,16 +143,18 @@ static int _auto_activation_handler(struct cmd_context *cmd, - * - * Remove this workaround with "refresh_retries" once we have proper locking in! - */ -- while (refresh_retries--) { -- if (vg_refresh_visible(vg->cmd, vg)) { -- refresh_done = 1; -- break; -+ if (changed) { -+ while (refresh_retries--) { -+ if (vg_refresh_visible(vg->cmd, vg)) { -+ refresh_done = 1; -+ break; -+ } -+ usleep(REFRESH_BEFORE_AUTOACTIVATION_RETRY_USLEEP_DELAY); - } -- usleep(REFRESH_BEFORE_AUTOACTIVATION_RETRY_USLEEP_DELAY); -- } - -- if (!refresh_done) -- log_warn("%s: refresh before autoactivation failed.", vg->name); -+ if (!refresh_done) -+ log_warn("%s: refresh before autoactivation failed.", vg->name); -+ } - - if (!vgchange_activate(vg->cmd, vg, activate)) { - log_error("%s: autoactivation failed.", vg->name); -@@ -158,7 +164,7 @@ static int _auto_activation_handler(struct cmd_context *cmd, - r = 1; - - out: -- release_vg(vg); -+ unlock_and_release_vg(cmd, vg, vgname); - return r; - } - diff --git a/SOURCES/lvm2-2_02_106-fix-dmeventd-logging-with-parallel-wait-processing.patch b/SOURCES/lvm2-2_02_106-fix-dmeventd-logging-with-parallel-wait-processing.patch deleted file mode 100644 index 510cf5b..0000000 --- a/SOURCES/lvm2-2_02_106-fix-dmeventd-logging-with-parallel-wait-processing.patch +++ /dev/null @@ -1,67 +0,0 @@ -commit 6281d212fa5e70e400c70677dfc20e99553e60d1 -Author: Peter Rajnoha -Date: Wed Mar 12 14:36:55 2014 +0100 - - dmeventd parallel processing ---- - WHATS_NEW_DM | 1 + - daemons/dmeventd/dmeventd.c | 16 ++++++++++++++-- - 2 files changed, 15 insertions(+), 2 deletions(-) - -diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM -index 32c2265..e470cd2 100644 ---- a/WHATS_NEW_DM -+++ b/WHATS_NEW_DM -@@ -1,5 +1,6 @@ - Version 1.02.85 - - =================================== -+ Fix dmeventd logging with parallel wait event processing. - Reuse _node_send_messages() for validation of transaction_id in preload. - Transaction_id could be lower by one only when messages are prepared. - Do not call callback when preload fails. -diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c -index 4a17fb2..f27444c 100644 ---- a/daemons/dmeventd/dmeventd.c -+++ b/daemons/dmeventd/dmeventd.c -@@ -661,6 +661,7 @@ static sigset_t _unblock_sigalrm(void) - /* Wait on a device until an event occurs. */ - static int _event_wait(struct thread_status *thread, struct dm_task **task) - { -+ static unsigned _in_event_counter = 0; - sigset_t set; - int ret = DM_WAIT_RETRY; - struct dm_task *dmt; -@@ -677,12 +678,20 @@ static int _event_wait(struct thread_status *thread, struct dm_task **task) - !dm_task_set_event_nr(dmt, thread->event_nr)) - goto out; - -+ _lock_mutex(); -+ /* -+ * Check if there are already some waiting events, -+ * in this case the logging is unmodified. -+ * TODO: audit libdm thread usage -+ */ -+ if (!_in_event_counter++) -+ dm_log_init(_no_intr_log); -+ _unlock_mutex(); - /* - * This is so that you can break out of waiting on an event, - * either for a timeout event, or to cancel the thread. - */ - set = _unblock_sigalrm(); -- dm_log_init(_no_intr_log); - errno = 0; - if (dm_task_run(dmt)) { - thread->current_events |= DM_EVENT_DEVICE_ERROR; -@@ -706,7 +715,10 @@ static int _event_wait(struct thread_status *thread, struct dm_task **task) - } - - pthread_sigmask(SIG_SETMASK, &set, NULL); -- dm_log_init(NULL); -+ _lock_mutex(); -+ if (--_in_event_counter == 0) -+ dm_log_init(NULL); -+ _unlock_mutex(); - - out: - if (ret == DM_WAIT_FATAL || ret == DM_WAIT_RETRY) { diff --git a/SOURCES/lvm2-2_02_106-fix-incorrect-snapshot-calculation-of-cow-size.patch b/SOURCES/lvm2-2_02_106-fix-incorrect-snapshot-calculation-of-cow-size.patch deleted file mode 100644 index 3bff830..0000000 --- a/SOURCES/lvm2-2_02_106-fix-incorrect-snapshot-calculation-of-cow-size.patch +++ /dev/null @@ -1,122 +0,0 @@ -commit d00fc1de784cee27d6ddb1b045a67c930f743074 -Author: Zdenek Kabelac -Date: Thu Feb 27 12:55:50 2014 +0100 - - snapshot: correct previous snapshot commit - - Condition was swapped - however since it's been based on 'random' - memory content it's been missed as attribute has not been set. - - So now we have quite a few possible results when testing. - - We have old status without separate metadata and - we have kernels with fixed snapshot leak bug. - - (in-release update) ---- - lib/metadata/snapshot_manip.c | 4 ++-- - lib/snapshot/snapshot.c | 3 +++ - test/shell/snapshot-usage.sh | 31 ++++++++++++++++++++++++------- - 3 files changed, 29 insertions(+), 9 deletions(-) - -diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c -index 25fee76..8fcab0c 100644 ---- a/lib/metadata/snapshot_manip.c -+++ b/lib/metadata/snapshot_manip.c -@@ -46,9 +46,9 @@ static uint64_t _cow_extra_chunks(struct cmd_context *cmd, uint64_t n_chunks) - segtype->ops->target_present && - segtype->ops->target_present(cmd, NULL, &attrs) && - (attrs & SNAPSHOT_FEATURE_FIXED_LEAK)) -- return (n_chunks + 63) / 64; -+ return 0; - -- return 0; -+ return (n_chunks + 63) / 64; - } - - static uint64_t _cow_max_size(struct cmd_context *cmd, uint64_t origin_size, uint32_t chunk_size) -diff --git a/lib/snapshot/snapshot.c b/lib/snapshot/snapshot.c -index 0b7b845..64919b0 100644 ---- a/lib/snapshot/snapshot.c -+++ b/lib/snapshot/snapshot.c -@@ -165,6 +165,9 @@ static int _snap_target_present(struct cmd_context *cmd, - log_very_verbose("Target snapshot may leak metadata."); - } - -+ if (attributes) -+ *attributes = _snap_attrs; -+ - /* TODO: test everything at once */ - if (seg && (seg->status & MERGING)) { - if (!_snap_merge_checked) { -diff --git a/test/shell/snapshot-usage.sh b/test/shell/snapshot-usage.sh -index cb60556..bd0723d 100644 ---- a/test/shell/snapshot-usage.sh -+++ b/test/shell/snapshot-usage.sh -@@ -33,6 +33,25 @@ vgcreate -s 4M $vg $(cat DEVICES) - TSIZE=15P - aux can_use_16T || TSIZE=15T - -+# With different snapshot target driver we may obtain different results. -+# Older targets have metadata leak bug which needs extra compenstion. -+# Ancient targets do not even provide separate info for metadata. -+EXPECT1="16.00k" -+EXPECT2="512.00k" -+EXPECT3="32.00k" -+EXPECT4="66.67" -+if aux target_at_least dm-snapshot 1 10 0 ; then -+ # Extra metadata size -+ EXPECT4="0.00" -+ -+ if aux target_at_least dm-snapshot 1 12 0 ; then -+ # When fixed leak, expect smaller sizes -+ EXPECT1="12.00k" -+ EXPECT2="384.00k" -+ EXPECT3="28.00k" -+ fi -+fi -+ - lvcreate -s -l 100%FREE -n $lv $vg --virtualsize $TSIZE - - aux extend_filter_LVMTEST -@@ -86,12 +105,12 @@ lvcreate -an -Zn -l1 -n $lv1 $vg1 - not lvcreate -s -l1 $vg1/$lv1 - not lvcreate -s -l3 $vg1/$lv1 - lvcreate -s -l30 -n $lv2 $vg1/$lv1 --check lv_field $vg1/$lv2 size "12.00k" -+check lv_field $vg1/$lv2 size "$EXPECT1" - - not lvcreate -s -c512 -l512 $vg1/$lv1 - lvcreate -s -c128 -l1700 -n $lv3 $vg1/$lv1 - # 3 * 128 --check lv_field $vg1/$lv3 size "384.00k" -+check lv_field $vg1/$lv3 size "$EXPECT2" - lvremove -ff $vg1 - - lvcreate -aey -l20 $vg1 -@@ -110,7 +129,7 @@ lvextend --use-policies $vg1/lvol1 - check lv_field $vg1/lvol1 size "18.00k" - - lvextend -l+33 $vg1/lvol1 --check lv_field $vg1/lvol1 size "32.00k" -+check lv_field $vg1/lvol1 size "$EXPECT3" - - fill 20K - lvremove -f $vg1 -@@ -138,14 +157,12 @@ fsck -n "$DM_DEV_DIR/$vg1/snap" - # This test would trigger read of weird percentage for undeleted header - # And since older snapshot target counts with metadata sectors - # we have 2 valid results (unsure about correct version number) --EXPECT="0.00" --aux target_at_least dm-snapshot 1 10 0 || EXPECT="66.67" --check lv_field $vg1/snap data_percent "$EXPECT" -+check lv_field $vg1/snap data_percent "$EXPECT4" - - vgremove -ff $vg1 - - # Can't test >= 16T devices on 32bit --if test "$TSIZE" -eq 15P ; then -+if test "$TSIZE" = 15P ; then - - # Check usability with largest extent size - pvcreate "$DM_DEV_DIR/$vg/$lv" diff --git a/SOURCES/lvm2-2_02_106-fix-timeout-for-initial-lvmetad-scan-when-done-in-parallel.patch b/SOURCES/lvm2-2_02_106-fix-timeout-for-initial-lvmetad-scan-when-done-in-parallel.patch deleted file mode 100644 index c4c73f4..0000000 --- a/SOURCES/lvm2-2_02_106-fix-timeout-for-initial-lvmetad-scan-when-done-in-parallel.patch +++ /dev/null @@ -1,66 +0,0 @@ -commit a7864d8f81e29dd7228c16f35314843e2f0c7b86 -Author: Peter Rajnoha -Date: Wed Mar 26 09:09:33 2014 +0100 - - 0 ---- - lib/cache/lvmetad.c | 16 +++++++++++----- - libdaemon/client/daemon-client.h | 2 +- - 2 files changed, 12 insertions(+), 6 deletions(-) - -diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c -index 38d9042..c019250 100644 ---- a/lib/cache/lvmetad.c -+++ b/lib/cache/lvmetad.c -@@ -143,6 +143,7 @@ static daemon_reply _lvmetad_send(const char *id, ...) - daemon_reply repl; - daemon_request req; - int try = 0; -+ int time = 0, wait, sleep = 1; - - retry: - req = daemon_request_make(id); -@@ -159,7 +160,7 @@ retry: - daemon_request_destroy(req); - - if (!repl.error && !strcmp(daemon_reply_str(repl, "response", ""), "token_mismatch") && -- try < 60 && !test_mode()) { -+ try < 10 && time < 80000000 && !test_mode()) { - /* - * If another process is trying to scan, they might have the - * same future token id and it's better to wait and avoid doing -@@ -172,12 +173,17 @@ retry: - * the update, we back off for a short while (0.2-2 seconds) and - * try again. - */ -- if (!strcmp(daemon_reply_str(repl, "expected", ""), "update in progress") || try % 5) -- usleep( 50000 + random() % 450000 ); /* 0.05 - 0.5s */ -- else -+ if (!strcmp(daemon_reply_str(repl, "expected", ""), "update in progress") || sleep) { -+ wait = 50000 + random() % 450000; /* 0.05 - 0.5s */ -+ time += wait; -+ usleep( wait ); -+ -- sleep; -+ } else { - /* If the re-scan fails here, we try again later. */ - lvmetad_pvscan_all_devs(_lvmetad_cmd, NULL); -- ++ try; -+ ++ try; -+ sleep = 5; -+ } - daemon_reply_destroy(repl); - goto retry; - } -diff --git a/libdaemon/client/daemon-client.h b/libdaemon/client/daemon-client.h -index 6ba65e6..8a44f8b 100644 ---- a/libdaemon/client/daemon-client.h -+++ b/libdaemon/client/daemon-client.h -@@ -102,7 +102,7 @@ static inline int64_t daemon_reply_int(daemon_reply r, const char *path, int64_t - } - - static inline const char *daemon_reply_str(daemon_reply r, const char *path, const char *def) { -- return dm_config_find_str(r.cft->root, path, def); -+ return dm_config_find_str_allow_empty(r.cft->root, path, def); - } - - diff --git a/SOURCES/lvm2-2_02_106-reinitialise-lvmcache-properly-on-fork-to-fix-premature-polldaemon-exit.patch b/SOURCES/lvm2-2_02_106-reinitialise-lvmcache-properly-on-fork-to-fix-premature-polldaemon-exit.patch deleted file mode 100644 index 2563f9b..0000000 --- a/SOURCES/lvm2-2_02_106-reinitialise-lvmcache-properly-on-fork-to-fix-premature-polldaemon-exit.patch +++ /dev/null @@ -1,185 +0,0 @@ -commit 129b8f8e525126f660fa22f88ee58cd086c5f338 -Author: Peter Rajnoha -Date: Tue Mar 25 11:01:23 2014 +0100 - - lvmcache init ---- - WHATS_NEW | 1 + - lib/cache/lvmcache.c | 9 ++++++--- - lib/cache/lvmcache.h | 2 +- - lib/commands/toolcontext.c | 4 ++-- - test/shell/pvmove-background.sh | 24 ++++++++++++++++++++++++ - tools/lvmcmdline.c | 2 +- - tools/pvscan.c | 2 +- - tools/toollib.c | 1 + - tools/vgrename.c | 2 +- - tools/vgscan.c | 2 +- - 10 files changed, 39 insertions(+), 10 deletions(-) - -diff --git a/WHATS_NEW b/WHATS_NEW -index b5afb19..cf6103d 100644 ---- a/WHATS_NEW -+++ b/WHATS_NEW -@@ -1,5 +1,6 @@ - Version 2.02.106 - - ==================================== -+ Reinitialise lvmcache properly on fork to fix polldaemon exiting prematurely. - Use VG read lock during 'pvscan --cache -aay' autoactivation. - Issue a VG refresh before autoactivation only if the PV has changed/is new. - Add flag to lvmetad protocol to indicate the PV scanned has changed/is new. -diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c -index d40bdce..fe64c8a 100644 ---- a/lib/cache/lvmcache.c -+++ b/lib/cache/lvmcache.c -@@ -1609,7 +1609,7 @@ static void _lvmcache_destroy_lockname(struct dm_hash_node *n) - dm_hash_get_key(_lock_hash, n)); - } - --void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans) -+void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset) - { - struct dm_hash_node *n; - log_verbose("Wiping internal VG cache"); -@@ -1635,8 +1635,11 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans) - } - - if (_lock_hash) { -- dm_hash_iterate(n, _lock_hash) -- _lvmcache_destroy_lockname(n); -+ if (reset) -+ _vg_global_lock_held = 0; -+ else -+ dm_hash_iterate(n, _lock_hash) -+ _lvmcache_destroy_lockname(n); - dm_hash_destroy(_lock_hash); - _lock_hash = NULL; - } -diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h -index bf26664..83d561b 100644 ---- a/lib/cache/lvmcache.h -+++ b/lib/cache/lvmcache.h -@@ -42,7 +42,7 @@ struct lvmcache_vginfo; - int lvmcache_init(void); - void lvmcache_allow_reads_with_lvmetad(void); - --void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans); -+void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset); - - /* Set full_scan to 1 to reread every filtered device label or - * 2 to rescan /dev for new devices */ -diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c -index a709284..d08ca61 100644 ---- a/lib/commands/toolcontext.c -+++ b/lib/commands/toolcontext.c -@@ -1640,7 +1640,7 @@ int refresh_toolcontext(struct cmd_context *cmd) - */ - - activation_release(); -- lvmcache_destroy(cmd, 0); -+ lvmcache_destroy(cmd, 0, 0); - label_exit(); - _destroy_segtypes(&cmd->segtypes); - _destroy_formats(cmd, &cmd->formats); -@@ -1732,7 +1732,7 @@ void destroy_toolcontext(struct cmd_context *cmd) - - archive_exit(cmd); - backup_exit(cmd); -- lvmcache_destroy(cmd, 0); -+ lvmcache_destroy(cmd, 0, 0); - label_exit(); - _destroy_segtypes(&cmd->segtypes); - _destroy_formats(cmd, &cmd->formats); -diff --git a/test/shell/pvmove-background.sh b/test/shell/pvmove-background.sh -new file mode 100644 -index 0000000..0f657be ---- /dev/null -+++ b/test/shell/pvmove-background.sh -@@ -0,0 +1,24 @@ -+#!/bin/sh -+# Copyright (C) 2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+# Check pvmove behavior when it's progress and machine is rebooted -+ -+. lib/test -+ -+aux prepare_vg 3 -+ -+lvcreate -l1 -n $lv1 $vg "$dev1" -+ -+lvs -o +devices | grep $dev1 -+pvmove -i 1 -b "$dev1" "$dev2" -+sleep 5 # arbitrary... -+lvs -o +devices | not grep "pvmove" -+lvs -o +devices | grep "$dev2" -diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c -index 6fe4670..e70e64a 100644 ---- a/tools/lvmcmdline.c -+++ b/tools/lvmcmdline.c -@@ -1183,7 +1183,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) - out: - if (test_mode()) { - log_verbose("Test mode: Wiping internal cache"); -- lvmcache_destroy(cmd, 1); -+ lvmcache_destroy(cmd, 1, 0); - } - - if ((old_cft = remove_config_tree_by_source(cmd, CONFIG_STRING))) { -diff --git a/tools/pvscan.c b/tools/pvscan.c -index 5db627a..af834fe 100644 ---- a/tools/pvscan.c -+++ b/tools/pvscan.c -@@ -373,7 +373,7 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv) - - if (cmd->filter->wipe) - cmd->filter->wipe(cmd->filter); -- lvmcache_destroy(cmd, 1); -+ lvmcache_destroy(cmd, 1, 0); - - /* populate lvmcache */ - if (!lvmetad_vg_list_to_lvmcache(cmd)) -diff --git a/tools/toollib.c b/tools/toollib.c -index 91b0559..6b68f55 100644 ---- a/tools/toollib.c -+++ b/tools/toollib.c -@@ -92,6 +92,7 @@ int become_daemon(struct cmd_context *cmd, int skip_lvm) - - if (!skip_lvm) { - reset_locking(); -+ lvmcache_destroy(cmd, 1, 1); - if (!lvmcache_init()) - /* FIXME Clean up properly here */ - _exit(ECMD_FAILED); -diff --git a/tools/vgrename.c b/tools/vgrename.c -index b5e778f..d97b871 100644 ---- a/tools/vgrename.c -+++ b/tools/vgrename.c -@@ -185,7 +185,7 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path, - /* FIXME lvmcache corruption - vginfo duplicated instead of renamed */ - if (cmd->filter->wipe) - cmd->filter->wipe(cmd->filter); -- lvmcache_destroy(cmd, 1); -+ lvmcache_destroy(cmd, 1, 0); - - return 1; - -diff --git a/tools/vgscan.c b/tools/vgscan.c -index baf25b0..fff0e89 100644 ---- a/tools/vgscan.c -+++ b/tools/vgscan.c -@@ -44,7 +44,7 @@ int vgscan(struct cmd_context *cmd, int argc, char **argv) - - if (cmd->filter->wipe) - cmd->filter->wipe(cmd->filter); -- lvmcache_destroy(cmd, 1); -+ lvmcache_destroy(cmd, 1, 0); - - if (arg_count(cmd, cache_ARG)) { - if (lvmetad_active()) { diff --git a/SOURCES/lvm2-2_02_106-upstream-with-cache-support.patch b/SOURCES/lvm2-2_02_106-upstream-with-cache-support.patch deleted file mode 100644 index b9b3d8c..0000000 --- a/SOURCES/lvm2-2_02_106-upstream-with-cache-support.patch +++ /dev/null @@ -1,13782 +0,0 @@ -commit 8cb42e4d9a3f46998defef78bb5bc38971ef3870 -Author: Peter Rajnoha -Date: Wed Feb 26 16:19:41 2014 +0100 - - v106+cache ---- - WHATS_NEW | 42 +- - WHATS_NEW_DM | 12 + - autoconf/config.guess | 415 +++++++++------- - autoconf/config.sub | 288 +++++++---- - conf/example.conf.in | 28 +- - configure | 37 +- - configure.in | 26 + - daemons/dmeventd/dmeventd.c | 145 +++++- - daemons/dmeventd/dmeventd.h | 1 + - daemons/dmeventd/libdevmapper-event.c | 7 + - daemons/dmeventd/libdevmapper-event.h | 2 +- - daemons/lvmetad/lvmetad-core.c | 20 +- - lib/Makefile.in | 13 +- - lib/activate/activate.c | 168 +++++++ - lib/activate/activate.h | 17 + - lib/activate/dev_manager.c | 68 ++- - lib/activate/dev_manager.h | 3 + - lib/cache/lvmcache.c | 4 +- - lib/cache/lvmetad.c | 29 +- - lib/cache_segtype/.exported_symbols | 1 + - lib/cache_segtype/Makefile.in | 24 + - lib/cache_segtype/cache.c | 448 +++++++++++++++++ - lib/commands/toolcontext.c | 9 +- - lib/config/config.c | 41 +- - lib/config/config.h | 11 +- - lib/config/config_settings.h | 47 +- - lib/config/defaults.h | 7 +- - lib/device/dev-io.c | 4 +- - lib/device/dev-type.c | 71 ++- - lib/device/dev-type.h | 6 +- - lib/device/device-types.h | 9 +- - lib/display/display.c | 16 + - lib/display/display.h | 3 + - lib/format_text/export.c | 6 +- - lib/format_text/flags.c | 4 + - lib/format_text/format-text.c | 16 +- - lib/format_text/tags.c | 10 +- - lib/label/label.c | 1 - - lib/locking/file_locking.c | 17 +- - lib/metadata/cache_manip.c | 278 +++++++++++ - lib/metadata/lv.c | 47 +- - lib/metadata/lv_alloc.h | 2 +- - lib/metadata/lv_manip.c | 543 +++++++++++++++----- - lib/metadata/merge.c | 60 ++- - lib/metadata/metadata-exported.h | 66 ++- - lib/metadata/metadata.c | 65 ++- - lib/metadata/metadata.h | 2 +- - lib/metadata/mirror.c | 14 +- - lib/metadata/pool_manip.c | 325 ++++++++++++ - lib/metadata/raid_manip.c | 10 +- - lib/metadata/segtype.h | 10 + - lib/metadata/snapshot_manip.c | 46 +- - lib/metadata/thin_manip.c | 282 ++--------- - lib/metadata/vg.c | 1 + - lib/metadata/vg.h | 1 + - lib/mirror/mirrored.c | 51 +- - lib/misc/configure.h.in | 3 + - lib/misc/lvm-exec.c | 1 - - lib/raid/raid.c | 40 +- - lib/report/report.c | 17 +- - lib/snapshot/snapshot.c | 15 +- - lib/thin/thin.c | 35 +- - libdm/libdevmapper.h | 134 +++-- - libdm/libdm-common.c | 19 +- - libdm/libdm-deptree.c | 438 ++++++++++++++--- - liblvm/lvm_lv.c | 21 +- - make.tmpl.in | 1 + - man/lvchange.8.in | 5 +- - man/lvconvert.8.in | 46 +- - man/lvcreate.8.in | 61 ++- - man/lvextend.8.in | 7 + - man/lvm.8.in | 199 ++++++++ - man/lvm.conf.5.in | 2 +- - man/lvreduce.8.in | 6 + - man/lvresize.8.in | 11 +- - man/lvs.8.in | 4 +- - man/vgchange.8.in | 7 +- - python/liblvm.c | 25 +- - scripts/Makefile.in | 13 +- - scripts/dm_event_systemd_red_hat.service.in | 5 +- - .../lvm2_activation_generator_systemd_red_hat.c | 2 +- - scripts/lvm2_cluster_activation_red_hat.sh.in | 70 +++ - ...2_cluster_activation_systemd_red_hat.service.in | 17 + - scripts/lvm2_clvmd_systemd_red_hat.service.in | 23 + - scripts/lvm2_cmirrord_systemd_red_hat.service.in | 17 + - scripts/lvm2_lvmetad_systemd_red_hat.service.in | 5 +- - scripts/lvm2_monitoring_init_red_hat.in | 8 +- - scripts/lvm2_monitoring_systemd_red_hat.service.in | 4 +- - test/api/pytest.sh | 15 +- - test/lib/aux.sh | 7 +- - test/lib/check.sh | 17 +- - test/lib/get.sh | 7 + - test/lib/test.sh | 2 +- - test/shell/activation-skip.sh | 32 ++ - test/shell/lock-parallel.sh | 40 ++ - test/shell/lvchange-partial.sh | 6 +- - test/shell/lvchange-raid.sh | 146 +++--- - test/shell/lvconvert-mirror-updown.sh | 36 ++ - test/shell/lvconvert-mirror.sh | 4 + - test/shell/lvconvert-repair-dmeventd.sh | 4 +- - test/shell/lvconvert-repair-thin.sh | 26 +- - test/shell/lvconvert-repair-transient-dmeventd.sh | 2 +- - test/shell/lvconvert-repair-transient.sh | 2 +- - test/shell/lvconvert-thin-external.sh | 20 +- - test/shell/lvcreate-cache.sh | 137 ++++++ - test/shell/lvcreate-large-raid.sh | 4 +- - test/shell/lvcreate-large-raid10.sh | 4 +- - test/shell/lvcreate-large.sh | 4 +- - test/shell/lvcreate-pvtags.sh | 2 +- - test/shell/lvcreate-raid.sh | 118 +++++ - test/shell/lvcreate-raid10.sh | 33 +- - test/shell/lvcreate-thin-external.sh | 18 +- - test/shell/lvcreate-thin-snap.sh | 8 +- - test/shell/lvcreate-thin.sh | 4 +- - test/shell/lvextend-thin-metadata-dmeventd.sh | 93 ++++ - test/shell/lvmetad-disabled.sh | 13 +- - test/shell/lvresize-thin-external-origin.sh | 42 ++ - test/shell/lvresize-thin-metadata.sh | 26 +- - test/shell/lvresize-usage.sh | 9 +- - test/shell/name-mangling.sh | 4 +- - test/shell/process-each-lv.sh | 545 +++++---------------- - test/shell/pvmove-all-segtypes.sh | 25 +- - test/shell/pvmove-cache-segtypes.sh | 178 +++++++ - test/shell/read-ahead.sh | 2 +- - test/shell/snapshot-usage.sh | 49 +- - test/shell/thin-merge.sh | 23 +- - test/shell/thin-vglock.sh | 51 ++ - test/shell/vgsplit-stacked.sh | 4 +- - tools/Makefile.in | 3 +- - tools/args.h | 2 + - tools/commands.h | 38 +- - tools/dumpconfig.c | 10 +- - tools/lvchange.c | 5 +- - tools/lvconvert.c | 229 +++++++-- - tools/lvcreate.c | 311 +++++++++--- - tools/pvmove.c | 43 ++ - tools/tags.c | 23 + - tools/toollib.c | 97 ++-- - tools/toollib.h | 4 +- - tools/vgchange.c | 25 +- - tools/vgsplit.c | 79 +++ - udev/10-dm.rules.in | 6 - - udev/69-dm-lvm-metad.rules.in | 3 + - 143 files changed, 5891 insertions(+), 1889 deletions(-) - -diff --git a/WHATS_NEW b/WHATS_NEW -index 26b63ae..224e351 100644 ---- a/WHATS_NEW -+++ b/WHATS_NEW -@@ -1,3 +1,43 @@ -+Version 2.02.106 - -+==================================== -+ Fix calculation of maximum size of COW device for snapshot (2.02.99). -+ Do not allow stripe size to be bigger then extent size for lvresize. -+ Zero snapshot COW header when creating read-only snapshot. -+ Comment out config lines in dumpconfig output without default values defined. -+ Improve detection of clustered mirror support. -+ Enhance raid code with feature flags, for now checks for raid10. -+ Move parsing of VG metadata from vg_commit() back to vg_write() (2.02.99) -+ Avoid a PV label scan while in a critical section. -+ Remove (always 0) skip argument from lv_activation_skip(). -+ Create /dev/disk/by-id/lvm-pv-uuid- symlink for each PV via udev. -+ lvcreate computes RAID4/5/6 stripes if not given from # of allocatable PVs. -+ Fix merging of old snapshot into thin volume origin. -+ Use --ignoreskippedcluster in lvm2-monitor initscript/systemd unit. -+ Do not use VG read/write state for LV read/write state. -+ Use --ignoreskippedcluster in activation systemd units if use_lvmetad=0. -+ Allow approximate allocation when specifying size in percentage terms. -+ Add basic LVM support for cache[pool] segment types. -+ Use local exclusive activation for creation of raid in cluster. -+ Use correctly signed 64b constant when selecting raid volumes. -+ Add systemd native service for clvmd, cmirrord and clustered LV activation. -+ Remove ExecReload from lvmetad systemd unit: lvmetad -R undefined. (2.02.98) -+ Do not fork lvmetad if running under systemd. -+ Wipe DM_snapshot_cow signature without prompt in new LVs with blkid wiping. -+ Avoid exposing temporary devices when initializing raid metadata volumes. -+ Add internal tags command to display any tags defined on the host. -+ Prohibit use of external origin with size incompatible with thin pool. -+ Avoid trying to convert single to thin pool and volume at the same time. -+ Add support for partitions on ZFS zvol. -+ Fix unwanted drop of hold flocks on forked children. -+ Respect LVM_LVMETAD_PIDFILE env var for lvm command. -+ Avoid exposing temporary devices when initializing thin pool volume. -+ Fix test when checking target version for available thin features. -+ Detect thin feature external_origin_extend and limit extend when missing. -+ Rename internal pool_can_resize_metadata() to thin_pool_feature_supported(). -+ Issue error if libbblkid detects signature and fails to return offset/length. -+ Update autoconf config.guess/sub to 2014-01-01. -+ Online thin pool metadata resize requires 1.10 kernel thin pool target. -+ - Version 2.02.105 - 20th January 2014 - ==================================== - Fix thin LV flagging for udev to skip scanning only if the LV is wiped. -@@ -31,7 +71,7 @@ Version 2.02.105 - 20th January 2014 - Add --splitsnapshot to lvconvert to separate out cow LV. - Reinstate origin reload to complete lvconvert -s with active LVs. (2.02.98) - Select only active volume groups if vgdisplay -A is used. -- Add -p and LVM_LVMETAD_PID env var to lvmetad to change pid file. -+ Add -p and LVM_LVMETAD_PIDFILE env var to lvmetad to change pid file. - Allow lvmetad to reuse stale socket. - Only unlink lvmetad socket on error if created by the same process. - Append missing newline to lvmetad missing socket path error message. -diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM -index ce302f3..32c2265 100644 ---- a/WHATS_NEW_DM -+++ b/WHATS_NEW_DM -@@ -1,3 +1,15 @@ -+Version 1.02.85 - -+=================================== -+ Reuse _node_send_messages() for validation of transaction_id in preload. -+ Transaction_id could be lower by one only when messages are prepared. -+ Do not call callback when preload fails. -+ Wrap is_selinux_enabled() to be called just once. -+ Use correctly signed 64b constant when working with raid volumes. -+ Exit dmeventd with pidfile cleanup instead of raising SIGKILL on DIE request. -+ Add new DM_EVENT_GET_PARAMETERS request to dmeventd protocol. -+ Do not use systemd's reload for dmeventd restart, use dmeventd -R instead. -+ Drop cryptsetup rules from 10-dm.rules - cryptsetup >= 1.1.3 sets them. -+ - Version 1.02.84 - 20th January 2014 - =================================== - Revert activation of activated nodes if a node preload callback fails. -diff --git a/autoconf/config.guess b/autoconf/config.guess -index dc84c68..4438cd7 100755 ---- a/autoconf/config.guess -+++ b/autoconf/config.guess -@@ -1,14 +1,12 @@ - #! /bin/sh - # Attempt to guess a canonical system name. --# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, --# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 --# Free Software Foundation, Inc. -+# Copyright 1992-2014 Free Software Foundation, Inc. - --timestamp='2009-11-20' -+timestamp='2014-01-01' - - # This file is free software; you can redistribute it and/or modify it - # under the terms of the GNU General Public License as published by --# the Free Software Foundation; either version 2 of the License, or -+# the Free Software Foundation; either version 3 of the License, or - # (at your option) any later version. - # - # This program is distributed in the hope that it will be useful, but -@@ -17,26 +15,22 @@ timestamp='2009-11-20' - # General Public License for more details. - # - # 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. -+# along with this program; if not, see . - # - # As a special exception to the GNU General Public License, if you - # distribute this file as part of a program that contains a - # configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. -- -- --# Originally written by Per Bothner. Please send patches (context --# diff format) to and include a ChangeLog --# entry. -+# the same distribution terms that you use for the rest of that -+# program. This Exception is an additional permission under section 7 -+# of the GNU General Public License, version 3 ("GPLv3"). - # --# This script attempts to guess a canonical system name similar to --# config.sub. If it succeeds, it prints the system name on stdout, and --# exits with 0. Otherwise, it exits with 1. -+# Originally written by Per Bothner. - # - # You can get the latest version of this script from: - # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD -+# -+# Please send patches with a ChangeLog entry to config-patches@gnu.org. -+ - - me=`echo "$0" | sed -e 's,.*/,,'` - -@@ -56,8 +50,7 @@ version="\ - GNU config.guess ($timestamp) - - Originally written by Per Bothner. --Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, --2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. -+Copyright 1992-2014 Free Software Foundation, Inc. - - This is free software; see the source for copying conditions. There is NO - warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." -@@ -139,12 +132,33 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown - UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown - UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -+case "${UNAME_SYSTEM}" in -+Linux|GNU|GNU/*) -+ # If the system lacks a compiler, then just pick glibc. -+ # We could probably try harder. -+ LIBC=gnu -+ -+ eval $set_cc_for_build -+ cat <<-EOF > $dummy.c -+ #include -+ #if defined(__UCLIBC__) -+ LIBC=uclibc -+ #elif defined(__dietlibc__) -+ LIBC=dietlibc -+ #else -+ LIBC=gnu -+ #endif -+ EOF -+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` -+ ;; -+esac -+ - # Note: order is significant - the case branches are not exclusive. - - case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - *:NetBSD:*:*) - # NetBSD (nbsd) targets should (where applicable) match one or -- # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, -+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, - # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently - # switched to ELF, *-*-netbsd* would select the old - # object file format. This provides both forward -@@ -180,7 +194,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - fi - ;; - *) -- os=netbsd -+ os=netbsd - ;; - esac - # The OS release -@@ -201,6 +215,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" - exit ;; -+ *:Bitrig:*:*) -+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` -+ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} -+ exit ;; - *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} -@@ -223,7 +241,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - ;; - *5.*) -- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` -+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` - ;; - esac - # According to Compaq, /usr/sbin/psrinfo has been available on -@@ -269,7 +287,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` -- exit ;; -+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code. -+ exitcode=$? -+ trap '' 0 -+ exit $exitcode ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead -@@ -295,12 +316,12 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - echo s390-ibm-zvmoe - exit ;; - *:OS400:*:*) -- echo powerpc-ibm-os400 -+ echo powerpc-ibm-os400 - exit ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} - exit ;; -- arm:riscos:*:*|arm:RISCOS:*:*) -+ arm*:riscos:*:*|arm*:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; - SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) -@@ -394,23 +415,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) -- echo m68k-atari-mint${UNAME_RELEASE} -+ echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} -- exit ;; -+ exit ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) -- echo m68k-atari-mint${UNAME_RELEASE} -+ echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) -- echo m68k-milan-mint${UNAME_RELEASE} -- exit ;; -+ echo m68k-milan-mint${UNAME_RELEASE} -+ exit ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) -- echo m68k-hades-mint${UNAME_RELEASE} -- exit ;; -+ echo m68k-hades-mint${UNAME_RELEASE} -+ exit ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) -- echo m68k-unknown-mint${UNAME_RELEASE} -- exit ;; -+ echo m68k-unknown-mint${UNAME_RELEASE} -+ exit ;; - m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} - exit ;; -@@ -480,8 +501,8 @@ EOF - echo m88k-motorola-sysv3 - exit ;; - AViiON:dgux:*:*) -- # DG/UX returns AViiON for all architectures -- UNAME_PROCESSOR=`/usr/bin/uname -p` -+ # DG/UX returns AViiON for all architectures -+ UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] - then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ -@@ -494,7 +515,7 @@ EOF - else - echo i586-dg-dgux${UNAME_RELEASE} - fi -- exit ;; -+ exit ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; -@@ -551,7 +572,7 @@ EOF - echo rs6000-ibm-aix3.2 - fi - exit ;; -- *:AIX:*:[456]) -+ *:AIX:*:[4567]) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then - IBM_ARCH=rs6000 -@@ -594,52 +615,52 @@ EOF - 9000/[678][0-9][0-9]) - if [ -x /usr/bin/getconf ]; then - sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` -- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` -- case "${sc_cpu_version}" in -- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 -- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 -- 532) # CPU_PA_RISC2_0 -- case "${sc_kernel_bits}" in -- 32) HP_ARCH="hppa2.0n" ;; -- 64) HP_ARCH="hppa2.0w" ;; -+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` -+ case "${sc_cpu_version}" in -+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 -+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 -+ 532) # CPU_PA_RISC2_0 -+ case "${sc_kernel_bits}" in -+ 32) HP_ARCH="hppa2.0n" ;; -+ 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 -- esac ;; -- esac -+ esac ;; -+ esac - fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build -- sed 's/^ //' << EOF >$dummy.c -+ sed 's/^ //' << EOF >$dummy.c - -- #define _HPUX_SOURCE -- #include -- #include -+ #define _HPUX_SOURCE -+ #include -+ #include - -- int main () -- { -- #if defined(_SC_KERNEL_BITS) -- long bits = sysconf(_SC_KERNEL_BITS); -- #endif -- long cpu = sysconf (_SC_CPU_VERSION); -+ int main () -+ { -+ #if defined(_SC_KERNEL_BITS) -+ long bits = sysconf(_SC_KERNEL_BITS); -+ #endif -+ long cpu = sysconf (_SC_CPU_VERSION); - -- switch (cpu) -- { -- case CPU_PA_RISC1_0: puts ("hppa1.0"); break; -- case CPU_PA_RISC1_1: puts ("hppa1.1"); break; -- case CPU_PA_RISC2_0: -- #if defined(_SC_KERNEL_BITS) -- switch (bits) -- { -- case 64: puts ("hppa2.0w"); break; -- case 32: puts ("hppa2.0n"); break; -- default: puts ("hppa2.0"); break; -- } break; -- #else /* !defined(_SC_KERNEL_BITS) */ -- puts ("hppa2.0"); break; -- #endif -- default: puts ("hppa1.0"); break; -- } -- exit (0); -- } -+ switch (cpu) -+ { -+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break; -+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break; -+ case CPU_PA_RISC2_0: -+ #if defined(_SC_KERNEL_BITS) -+ switch (bits) -+ { -+ case 64: puts ("hppa2.0w"); break; -+ case 32: puts ("hppa2.0n"); break; -+ default: puts ("hppa2.0"); break; -+ } break; -+ #else /* !defined(_SC_KERNEL_BITS) */ -+ puts ("hppa2.0"); break; -+ #endif -+ default: puts ("hppa1.0"); break; -+ } -+ exit (0); -+ } - EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` - test -z "$HP_ARCH" && HP_ARCH=hppa -@@ -730,22 +751,22 @@ EOF - exit ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd -- exit ;; -+ exit ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi -- exit ;; -+ exit ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd -- exit ;; -+ exit ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd -- exit ;; -+ exit ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd -- exit ;; -+ exit ;; - CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; -@@ -769,14 +790,14 @@ EOF - exit ;; - F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` -- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` -- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` -- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" -- exit ;; -+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` -+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` -+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" -+ exit ;; - 5000:UNIX_System_V:4.*:*) -- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` -- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` -- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" -+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` -+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` -+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} -@@ -788,30 +809,35 @@ EOF - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} - exit ;; - *:FreeBSD:*:*) -- case ${UNAME_MACHINE} in -- pc98) -- echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; -+ UNAME_PROCESSOR=`/usr/bin/uname -p` -+ case ${UNAME_PROCESSOR} in - amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - *) -- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; -+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - esac - exit ;; - i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin - exit ;; -+ *:MINGW64*:*) -+ echo ${UNAME_MACHINE}-pc-mingw64 -+ exit ;; - *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 - exit ;; -+ i*:MSYS*:*) -+ echo ${UNAME_MACHINE}-pc-msys -+ exit ;; - i*:windows32*:*) -- # uname -m includes "-pc" on this system. -- echo ${UNAME_MACHINE}-mingw32 -+ # uname -m includes "-pc" on this system. -+ echo ${UNAME_MACHINE}-mingw32 - exit ;; - i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 - exit ;; - *:Interix*:*) -- case ${UNAME_MACHINE} in -+ case ${UNAME_MACHINE} in - x86) - echo i586-pc-interix${UNAME_RELEASE} - exit ;; -@@ -848,15 +874,22 @@ EOF - exit ;; - *:GNU:*:*) - # the GNU system -- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` -+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` - exit ;; - *:GNU/*:*:*) - # other systems with GNU libc and userland -- echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu -+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} - exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix - exit ;; -+ aarch64:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} -+ exit ;; -+ aarch64_be:Linux:*:*) -+ UNAME_MACHINE=aarch64_be -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} -+ exit ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in - EV5) UNAME_MACHINE=alphaev5 ;; -@@ -866,52 +899,56 @@ EOF - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; -- esac -+ esac - objdump --private-headers /bin/sh | grep -q ld.so.1 -- if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi -- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} -+ if test "$?" = 0 ; then LIBC="gnulibc1" ; fi -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} -+ exit ;; -+ arc:Linux:*:* | arceb:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - arm*:Linux:*:*) - eval $set_cc_for_build - if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_EABI__ - then -- echo ${UNAME_MACHINE}-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - else -- echo ${UNAME_MACHINE}-unknown-linux-gnueabi -+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ -+ | grep -q __ARM_PCS_VFP -+ then -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi -+ else -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf -+ fi - fi - exit ;; - avr32*:Linux:*:*) -- echo ${UNAME_MACHINE}-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - cris:Linux:*:*) -- echo cris-axis-linux-gnu -+ echo ${UNAME_MACHINE}-axis-linux-${LIBC} - exit ;; - crisv32:Linux:*:*) -- echo crisv32-axis-linux-gnu -+ echo ${UNAME_MACHINE}-axis-linux-${LIBC} - exit ;; - frv:Linux:*:*) -- echo frv-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} -+ exit ;; -+ hexagon:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - i*86:Linux:*:*) -- LIBC=gnu -- eval $set_cc_for_build -- sed 's/^ //' << EOF >$dummy.c -- #ifdef __dietlibc__ -- LIBC=dietlibc -- #endif --EOF -- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` -- echo "${UNAME_MACHINE}-pc-linux-${LIBC}" -+ echo ${UNAME_MACHINE}-pc-linux-${LIBC} - exit ;; - ia64:Linux:*:*) -- echo ${UNAME_MACHINE}-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - m32r*:Linux:*:*) -- echo ${UNAME_MACHINE}-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - m68*:Linux:*:*) -- echo ${UNAME_MACHINE}-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - mips:Linux:*:* | mips64:Linux:*:*) - eval $set_cc_for_build -@@ -930,51 +967,63 @@ EOF - #endif - EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` -- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } -+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } - ;; -+ or1k:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} -+ exit ;; - or32:Linux:*:*) -- echo or32-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - padre:Linux:*:*) -- echo sparc-unknown-linux-gnu -+ echo sparc-unknown-linux-${LIBC} - exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) -- echo hppa64-unknown-linux-gnu -+ echo hppa64-unknown-linux-${LIBC} - exit ;; - parisc:Linux:*:* | hppa:Linux:*:*) - # Look for CPU level - case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in -- PA7*) echo hppa1.1-unknown-linux-gnu ;; -- PA8*) echo hppa2.0-unknown-linux-gnu ;; -- *) echo hppa-unknown-linux-gnu ;; -+ PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; -+ PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; -+ *) echo hppa-unknown-linux-${LIBC} ;; - esac - exit ;; - ppc64:Linux:*:*) -- echo powerpc64-unknown-linux-gnu -+ echo powerpc64-unknown-linux-${LIBC} - exit ;; - ppc:Linux:*:*) -- echo powerpc-unknown-linux-gnu -+ echo powerpc-unknown-linux-${LIBC} -+ exit ;; -+ ppc64le:Linux:*:*) -+ echo powerpc64le-unknown-linux-${LIBC} -+ exit ;; -+ ppcle:Linux:*:*) -+ echo powerpcle-unknown-linux-${LIBC} - exit ;; - s390:Linux:*:* | s390x:Linux:*:*) -- echo ${UNAME_MACHINE}-ibm-linux -+ echo ${UNAME_MACHINE}-ibm-linux-${LIBC} - exit ;; - sh64*:Linux:*:*) -- echo ${UNAME_MACHINE}-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - sh*:Linux:*:*) -- echo ${UNAME_MACHINE}-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - sparc:Linux:*:* | sparc64:Linux:*:*) -- echo ${UNAME_MACHINE}-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} -+ exit ;; -+ tile*:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - vax:Linux:*:*) -- echo ${UNAME_MACHINE}-dec-linux-gnu -+ echo ${UNAME_MACHINE}-dec-linux-${LIBC} - exit ;; - x86_64:Linux:*:*) -- echo x86_64-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - xtensa*:Linux:*:*) -- echo ${UNAME_MACHINE}-unknown-linux-gnu -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - i*86:DYNIX/ptx:4*:*) - # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. -@@ -983,11 +1032,11 @@ EOF - echo i386-sequent-sysv4 - exit ;; - i*86:UNIX_SV:4.2MP:2.*) -- # Unixware is an offshoot of SVR4, but it has its own version -- # number series starting with 2... -- # I am not positive that other SVR4 systems won't match this, -+ # Unixware is an offshoot of SVR4, but it has its own version -+ # number series starting with 2... -+ # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. -- # Use sysv4.2uw... so that sysv4* matches it. -+ # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} - exit ;; - i*86:OS/2:*:*) -@@ -1019,7 +1068,7 @@ EOF - fi - exit ;; - i*86:*:5:[678]*) -- # UnixWare 7.x, OpenUNIX and OpenServer 6. -+ # UnixWare 7.x, OpenUNIX and OpenServer 6. - case `/bin/uname -X | grep "^Machine"` in - *486*) UNAME_MACHINE=i486 ;; - *Pentium) UNAME_MACHINE=i586 ;; -@@ -1047,13 +1096,13 @@ EOF - exit ;; - pc:*:*:*) - # Left here for compatibility: -- # uname -m prints for DJGPP always 'pc', but it prints nothing about -- # the processor, so we play safe by assuming i586. -+ # uname -m prints for DJGPP always 'pc', but it prints nothing about -+ # the processor, so we play safe by assuming i586. - # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configury will decide that - # this is a cross-build. - echo i586-pc-msdosdjgpp -- exit ;; -+ exit ;; - Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; -@@ -1088,8 +1137,8 @@ EOF - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) -- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ -- && { echo i486-ncr-sysv4; exit; } ;; -+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ -+ && { echo i486-ncr-sysv4; exit; } ;; - NCR*:*:4.2:* | MPRAS*:*:4.2:*) - OS_REL='.3' - test -r /etc/.relid \ -@@ -1132,10 +1181,10 @@ EOF - echo ns32k-sni-sysv - fi - exit ;; -- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort -- # says -- echo i586-unisys-sysv4 -- exit ;; -+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort -+ # says -+ echo i586-unisys-sysv4 -+ exit ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes . - # How about differentiating between stratus architectures? -djm -@@ -1161,11 +1210,11 @@ EOF - exit ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then -- echo mips-nec-sysv${UNAME_RELEASE} -+ echo mips-nec-sysv${UNAME_RELEASE} - else -- echo mips-unknown-sysv${UNAME_RELEASE} -+ echo mips-unknown-sysv${UNAME_RELEASE} - fi -- exit ;; -+ exit ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; -@@ -1178,6 +1227,9 @@ EOF - BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - echo i586-pc-haiku - exit ;; -+ x86_64:Haiku:*:*) -+ echo x86_64-unknown-haiku -+ exit ;; - SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} - exit ;; -@@ -1204,19 +1256,31 @@ EOF - exit ;; - *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown -- case $UNAME_PROCESSOR in -- i386) -- eval $set_cc_for_build -- if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then -- if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ -- (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ -- grep IS_64BIT_ARCH >/dev/null -- then -- UNAME_PROCESSOR="x86_64" -- fi -- fi ;; -- unknown) UNAME_PROCESSOR=powerpc ;; -- esac -+ eval $set_cc_for_build -+ if test "$UNAME_PROCESSOR" = unknown ; then -+ UNAME_PROCESSOR=powerpc -+ fi -+ if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then -+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then -+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ -+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ -+ grep IS_64BIT_ARCH >/dev/null -+ then -+ case $UNAME_PROCESSOR in -+ i386) UNAME_PROCESSOR=x86_64 ;; -+ powerpc) UNAME_PROCESSOR=powerpc64 ;; -+ esac -+ fi -+ fi -+ elif test "$UNAME_PROCESSOR" = i386 ; then -+ # Avoid executing cc on OS X 10.9, as it ships with a stub -+ # that puts up a graphical alert prompting to install -+ # developer tools. Any system running Mac OS X 10.7 or -+ # later (Darwin 11 and later) is required to have a 64-bit -+ # processor. This is not true of the ARM version of Darwin -+ # that Apple uses in portable devices. -+ UNAME_PROCESSOR=x86_64 -+ fi - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} - exit ;; - *:procnto*:*:* | *:QNX:[0123456789]*:*) -@@ -1230,7 +1294,10 @@ EOF - *:QNX:*:4*) - echo i386-pc-qnx - exit ;; -- NSE-?:NONSTOP_KERNEL:*:*) -+ NEO-?:NONSTOP_KERNEL:*:*) -+ echo neo-tandem-nsk${UNAME_RELEASE} -+ exit ;; -+ NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} - exit ;; - NSR-?:NONSTOP_KERNEL:*:*) -@@ -1275,13 +1342,13 @@ EOF - echo pdp10-unknown-its - exit ;; - SEI:*:*:SEIUX) -- echo mips-sei-seiux${UNAME_RELEASE} -+ echo mips-sei-seiux${UNAME_RELEASE} - exit ;; - *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` - exit ;; - *:*VMS:*:*) -- UNAME_MACHINE=`(uname -p) 2>/dev/null` -+ UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; -@@ -1299,11 +1366,11 @@ EOF - i*86:AROS:*:*) - echo ${UNAME_MACHINE}-pc-aros - exit ;; -+ x86_64:VMkernel:*:*) -+ echo ${UNAME_MACHINE}-unknown-esx -+ exit ;; - esac - --#echo '(No uname command or uname output not recognized.)' 1>&2 --#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 -- - eval $set_cc_for_build - cat >$dummy.c < - printf ("m68k-sony-newsos%s\n", - #ifdef NEWSOS4 -- "4" -+ "4" - #else -- "" -+ "" - #endif -- ); exit (0); -+ ); exit (0); - #endif - #endif - -diff --git a/autoconf/config.sub b/autoconf/config.sub -index 2a55a50..092cff0 100755 ---- a/autoconf/config.sub -+++ b/autoconf/config.sub -@@ -1,38 +1,31 @@ - #! /bin/sh - # Configuration validation subroutine script. --# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, --# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 --# Free Software Foundation, Inc. -+# Copyright 1992-2014 Free Software Foundation, Inc. - --timestamp='2009-11-20' -+timestamp='2014-01-01' - --# This file is (in principle) common to ALL GNU software. --# The presence of a machine in this file suggests that SOME GNU software --# can handle that machine. It does not imply ALL GNU software can. --# --# This file is free software; you can redistribute it and/or modify --# it under the terms of the GNU General Public License as published by --# the Free Software Foundation; either version 2 of the License, or -+# This file is free software; you can redistribute it and/or modify it -+# under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 3 of the License, or - # (at your option) any later version. - # --# This program is distributed in the hope that it will be useful, --# but WITHOUT ANY WARRANTY; without even the implied warranty of --# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --# GNU General Public License for more details. -+# This program is distributed in the hope that it will be useful, but -+# WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+# General Public License for more details. - # - # 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. -+# along with this program; if not, see . - # - # As a special exception to the GNU General Public License, if you - # distribute this file as part of a program that contains a - # configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. -+# the same distribution terms that you use for the rest of that -+# program. This Exception is an additional permission under section 7 -+# of the GNU General Public License, version 3 ("GPLv3"). - - --# Please send patches to . Submit a context --# diff and a properly formatted GNU ChangeLog entry. -+# Please send patches with a ChangeLog entry to config-patches@gnu.org. - # - # Configuration subroutine to validate and canonicalize a configuration type. - # Supply the specified configuration type as an argument. -@@ -75,8 +68,7 @@ Report bugs and patches to ." - version="\ - GNU config.sub ($timestamp) - --Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, --2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. -+Copyright 1992-2014 Free Software Foundation, Inc. - - This is free software; see the source for copying conditions. There is NO - warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." -@@ -123,13 +115,18 @@ esac - # Here we must recognize all the valid KERNEL-OS combinations. - maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` - case $maybe_os in -- nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ -- uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ -+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ -+ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ -+ knetbsd*-gnu* | netbsd*-gnu* | \ - kopensolaris*-gnu* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; -+ android-linux) -+ os=-linux-android -+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown -+ ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] -@@ -152,12 +149,12 @@ case $os in - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -- -apple | -axis | -knuth | -cray | -microblaze) -+ -apple | -axis | -knuth | -cray | -microblaze*) - os= - basic_machine=$1 - ;; -- -bluegene*) -- os=-cnk -+ -bluegene*) -+ os=-cnk - ;; - -sim | -cisco | -oki | -wec | -winbond) - os= -@@ -173,10 +170,10 @@ case $os in - os=-chorusos - basic_machine=$1 - ;; -- -chorusrdb) -- os=-chorusrdb -+ -chorusrdb) -+ os=-chorusrdb - basic_machine=$1 -- ;; -+ ;; - -hiux*) - os=-hiuxwe2 - ;; -@@ -221,6 +218,12 @@ case $os in - -isc*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; -+ -lynx*178) -+ os=-lynxos178 -+ ;; -+ -lynx*5) -+ os=-lynxos5 -+ ;; - -lynx*) - os=-lynxos - ;; -@@ -245,20 +248,28 @@ case $basic_machine in - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ -+ | aarch64 | aarch64_be \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ -- | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ -+ | arc | arceb \ -+ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ -+ | avr | avr32 \ -+ | be32 | be64 \ - | bfin \ -- | c4x | clipper \ -+ | c4x | c8051 | clipper \ - | d10v | d30v | dlx | dsp16xx \ -+ | epiphany \ - | fido | fr30 | frv \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ -+ | hexagon \ - | i370 | i860 | i960 | ia64 \ - | ip2k | iq2000 \ -+ | k1om \ -+ | le32 | le64 \ - | lm32 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ -- | maxq | mb | microblaze | mcore | mep | metag \ -+ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ -@@ -276,34 +287,45 @@ case $basic_machine in - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ -+ | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | moxie \ - | mt \ - | msp430 \ -- | nios | nios2 \ -+ | nds32 | nds32le | nds32be \ -+ | nios | nios2 | nios2eb | nios2el \ - | ns16k | ns32k \ -- | or32 \ -+ | open8 \ -+ | or1k | or32 \ - | pdp10 | pdp11 | pj | pjl \ -- | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ -+ | powerpc | powerpc64 | powerpc64le | powerpcle \ - | pyramid \ -- | rx \ -+ | rl78 | rx \ - | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ -- | spu | strongarm \ -- | tahoe | thumb | tic4x | tic80 | tron \ -+ | spu \ -+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ - | ubicom32 \ -- | v850 | v850e \ -+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ - | we32k \ -- | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ -+ | x86 | xc16x | xstormy16 | xtensa \ - | z8k | z80) - basic_machine=$basic_machine-unknown - ;; -- m6811 | m68hc11 | m6812 | m68hc12 | picochip) -- # Motorola 68HC11/12. -+ c54x) -+ basic_machine=tic54x-unknown -+ ;; -+ c55x) -+ basic_machine=tic55x-unknown -+ ;; -+ c6x) -+ basic_machine=tic6x-unknown -+ ;; -+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) - basic_machine=$basic_machine-unknown - os=-none - ;; -@@ -313,6 +335,21 @@ case $basic_machine in - basic_machine=mt-unknown - ;; - -+ strongarm | thumb | xscale) -+ basic_machine=arm-unknown -+ ;; -+ xgate) -+ basic_machine=$basic_machine-unknown -+ os=-none -+ ;; -+ xscaleeb) -+ basic_machine=armeb-unknown -+ ;; -+ -+ xscaleel) -+ basic_machine=armel-unknown -+ ;; -+ - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. -@@ -327,25 +364,31 @@ case $basic_machine in - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ -+ | aarch64-* | aarch64_be-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ -- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ -+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ -+ | be32-* | be64-* \ - | bfin-* | bs2000-* \ -- | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ -- | clipper-* | craynv-* | cydra-* \ -+ | c[123]* | c30-* | [cjt]90-* | c4x-* \ -+ | c8051-* | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ -+ | hexagon-* \ - | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* | iq2000-* \ -+ | k1om-* \ -+ | le32-* | le64-* \ - | lm32-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ -- | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ -+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ -+ | microblaze-* | microblazeel-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ -@@ -363,29 +406,34 @@ case $basic_machine in - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ -+ | mipsr5900-* | mipsr5900el-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ -- | nios-* | nios2-* \ -+ | nds32-* | nds32le-* | nds32be-* \ -+ | nios-* | nios2-* | nios2eb-* | nios2el-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ -+ | open8-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ -- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ -+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ - | pyramid-* \ -- | romp-* | rs6000-* | rx-* \ -+ | rl78-* | romp-* | rs6000-* | rx-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ -- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ -- | tahoe-* | thumb-* \ -- | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ -+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ -+ | tahoe-* \ -+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ -+ | tile*-* \ - | tron-* \ - | ubicom32-* \ -- | v850-* | v850e-* | vax-* \ -+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ -+ | vax-* \ - | we32k-* \ -- | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ -+ | x86-* | x86_64-* | xc16x-* | xps100-* \ - | xstormy16-* | xtensa*-* \ - | ymp-* \ - | z8k-* | z80-*) -@@ -410,7 +458,7 @@ case $basic_machine in - basic_machine=a29k-amd - os=-udi - ;; -- abacus) -+ abacus) - basic_machine=abacus-unknown - ;; - adobe68k) -@@ -480,11 +528,20 @@ case $basic_machine in - basic_machine=powerpc-ibm - os=-cnk - ;; -+ c54x-*) -+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ c55x-*) -+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ c6x-*) -+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; -- cegcc) -+ cegcc) - basic_machine=arm-unknown - os=-cegcc - ;; -@@ -516,7 +573,7 @@ case $basic_machine in - basic_machine=craynv-cray - os=-unicosmp - ;; -- cr16) -+ cr16 | cr16-*) - basic_machine=cr16-unknown - os=-elf - ;; -@@ -674,7 +731,6 @@ case $basic_machine in - i370-ibm* | ibm*) - basic_machine=i370-ibm - ;; --# I'm not sure what "Sysv32" means. Should this be sysv3.2? - i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 -@@ -732,11 +788,15 @@ case $basic_machine in - basic_machine=ns32k-utek - os=-sysv - ;; -- microblaze) -+ microblaze*) - basic_machine=microblaze-xilinx - ;; -+ mingw64) -+ basic_machine=x86_64-pc -+ os=-mingw64 -+ ;; - mingw32) -- basic_machine=i386-pc -+ basic_machine=i686-pc - os=-mingw32 - ;; - mingw32ce) -@@ -771,10 +831,18 @@ case $basic_machine in - ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; -+ msys) -+ basic_machine=i686-pc -+ os=-msys -+ ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; -+ nacl) -+ basic_machine=le32-unknown -+ os=-nacl -+ ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 -@@ -839,6 +907,12 @@ case $basic_machine in - np1) - basic_machine=np1-gould - ;; -+ neo-tandem) -+ basic_machine=neo-tandem -+ ;; -+ nse-tandem) -+ basic_machine=nse-tandem -+ ;; - nsr-tandem) - basic_machine=nsr-tandem - ;; -@@ -921,9 +995,10 @@ case $basic_machine in - ;; - power) basic_machine=power-ibm - ;; -- ppc) basic_machine=powerpc-unknown -+ ppc | ppcbe) basic_machine=powerpc-unknown - ;; -- ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ppc-* | ppcbe-*) -+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle | ppc-le | powerpc-little) - basic_machine=powerpcle-unknown -@@ -948,7 +1023,11 @@ case $basic_machine in - basic_machine=i586-unknown - os=-pw32 - ;; -- rdos) -+ rdos | rdos64) -+ basic_machine=x86_64-pc -+ os=-rdos -+ ;; -+ rdos32) - basic_machine=i386-pc - os=-rdos - ;; -@@ -1017,6 +1096,9 @@ case $basic_machine in - basic_machine=i860-stratus - os=-sysv4 - ;; -+ strongarm-* | thumb-*) -+ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; - sun2) - basic_machine=m68000-sun - ;; -@@ -1073,20 +1155,8 @@ case $basic_machine in - basic_machine=t90-cray - os=-unicos - ;; -- tic54x | c54x*) -- basic_machine=tic54x-unknown -- os=-coff -- ;; -- tic55x | c55x*) -- basic_machine=tic55x-unknown -- os=-coff -- ;; -- tic6x | c6x*) -- basic_machine=tic6x-unknown -- os=-coff -- ;; - tile*) -- basic_machine=tile-unknown -+ basic_machine=$basic_machine-unknown - os=-linux-gnu - ;; - tx39) -@@ -1156,6 +1226,9 @@ case $basic_machine in - xps | xps100) - basic_machine=xps100-honeywell - ;; -+ xscale-* | xscalee[bl]-*) -+ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` -+ ;; - ymp) - basic_machine=ymp-cray - os=-unicos -@@ -1253,11 +1326,11 @@ esac - if [ x"$os" != x"" ] - then - case $os in -- # First match some system type aliases -- # that might get confused with valid system types. -+ # First match some system type aliases -+ # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. -- -auroraux) -- os=-auroraux -+ -auroraux) -+ os=-auroraux - ;; - -solaris1 | -solaris1.*) - os=`echo $os | sed -e 's|solaris1|sunos4|'` -@@ -1281,20 +1354,21 @@ case $os in - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ -- | -sym* | -kopensolaris* \ -+ | -sym* | -kopensolaris* | -plan9* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ -- | -openbsd* | -solidbsd* \ -+ | -bitrig* | -openbsd* | -solidbsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* | -cegcc* \ -- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ -- | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ -+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ -+ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ -+ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ -@@ -1341,7 +1415,7 @@ case $os in - -opened*) - os=-openedition - ;; -- -os400*) -+ -os400*) - os=-os400 - ;; - -wince*) -@@ -1390,7 +1464,7 @@ case $os in - -sinix*) - os=-sysv4 - ;; -- -tpf*) -+ -tpf*) - os=-tpf - ;; - -triton*) -@@ -1426,15 +1500,14 @@ case $os in - -aros*) - os=-aros - ;; -- -kaos*) -- os=-kaos -- ;; - -zvmoe) - os=-zvmoe - ;; - -dicos*) - os=-dicos - ;; -+ -nacl*) -+ ;; - -none) - ;; - *) -@@ -1457,10 +1530,10 @@ else - # system, and we'll never get to this point. - - case $basic_machine in -- score-*) -+ score-*) - os=-elf - ;; -- spu-*) -+ spu-*) - os=-elf - ;; - *-acorn) -@@ -1472,8 +1545,23 @@ case $basic_machine in - arm*-semi) - os=-aout - ;; -- c4x-* | tic4x-*) -- os=-coff -+ c4x-* | tic4x-*) -+ os=-coff -+ ;; -+ c8051-*) -+ os=-elf -+ ;; -+ hexagon-*) -+ os=-elf -+ ;; -+ tic54x-*) -+ os=-coff -+ ;; -+ tic55x-*) -+ os=-coff -+ ;; -+ tic6x-*) -+ os=-coff - ;; - # This must come before the *-dec entry. - pdp10-*) -@@ -1493,14 +1581,11 @@ case $basic_machine in - ;; - m68000-sun) - os=-sunos3 -- # This also exists in the configure program, but was not the -- # default. -- # os=-sunos4 - ;; - m68*-cisco) - os=-aout - ;; -- mep-*) -+ mep-*) - os=-elf - ;; - mips*-cisco) -@@ -1509,6 +1594,9 @@ case $basic_machine in - mips*-*) - os=-elf - ;; -+ or1k-*) -+ os=-elf -+ ;; - or32-*) - os=-coff - ;; -@@ -1527,7 +1615,7 @@ case $basic_machine in - *-ibm) - os=-aix - ;; -- *-knuth) -+ *-knuth) - os=-mmixware - ;; - *-wec) -diff --git a/conf/example.conf.in b/conf/example.conf.in -index 79b574e..5e23291 100644 ---- a/conf/example.conf.in -+++ b/conf/example.conf.in -@@ -301,6 +301,21 @@ allocation { - # until version 2.02.85. - mirror_logs_require_separate_pvs = 0 - -+ # Set to 1 to guarantee that cache_pool metadata will always be -+ # placed on different PVs from the cache_pool data. -+ cache_pool_metadata_require_separate_pvs = 0 -+ -+ # Specify the minimal chunk size (in kiB) for cache pool volumes. -+ # Using a chunk_size that is too large can result in wasteful use of -+ # the cache, where small reads and writes can cause large sections of -+ # an LV to be mapped into the cache. 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. The former is -+ # more of a problem than the latter in most cases, so we default to -+ # a value that is on the smaller end of the spectrum. Supported values -+ # range from 32(kiB) to 1048576 in multiples of 32. -+ # cache_pool_chunk_size = 64 -+ - # Set to 1 to guarantee that thin pool metadata will always - # be placed on different PVs from the pool data. - thin_pool_metadata_require_separate_pvs = 0 -@@ -321,14 +336,14 @@ allocation { - # thin_pool_chunk_size_policy = "generic" - - # Specify the minimal chunk size (in KB) for thin pool volumes. -- # Use of the larger chunk size may improve perfomance for plain -+ # Use of the larger chunk size may improve performance for plain - # thin volumes, however using them for snapshot volumes is less efficient, - # as it consumes more space and takes extra time for copying. - # When unset, lvm tries to estimate chunk size starting from 64KB - # Supported values are in range from 64 to 1048576. - # thin_pool_chunk_size = 64 - -- # Specify discards behavior of the thin pool volume. -+ # Specify discards behaviour of the thin pool volume. - # Select one of "ignore", "nopassdown", "passdown" - # thin_pool_discards = "passdown" - -@@ -408,7 +423,7 @@ log { - # Configuration of metadata backups and archiving. In LVM2 when we - # talk about a 'backup' we mean making a copy of the metadata for the - # *current* system. The 'archive' contains old metadata configurations. --# Backups are stored in a human readeable text format. -+# Backups are stored in a human readable text format. - backup { - - # Should we maintain a backup of the current metadata configuration ? -@@ -599,7 +614,7 @@ global { - # "mirror" - LVM will layer the 'mirror' and 'stripe' segment types. It - # will do this by creating a mirror on top of striped sub-LVs; - # effectively creating a RAID 0+1 array. This is suboptimal -- # in terms of providing redunancy and performance. Changing to -+ # in terms of providing redundancy and performance. Changing to - # this setting is not advised. - # Specify the '--type ' option to override this default - # setting. -@@ -663,7 +678,7 @@ global { - # Array of string options passed with thin_check command. By default, - # option "-q" is for quiet output. - # With thin_check version 2.1 or newer you can add "--ignore-non-fatal-errors" -- # to let it pass through ignoreable errors and fix them later. -+ # to let it pass through ignorable errors and fix them later. - # - # thin_check_options = [ "-q" ] - -@@ -691,6 +706,7 @@ global { - # discards_non_power_2 - # external_origin - # metadata_resize -+ # external_origin_extend - # - # thin_disabled_features = [ "discards", "block_size" ] - } -@@ -822,7 +838,7 @@ activation { - # auto_set_activation_skip = 1 - - # For RAID or 'mirror' segment types, 'raid_region_size' is the -- # size (in kiB) of each: -+ # size (in KiB) of each: - # - synchronization operation when initializing - # - each copy operation when performing a 'pvmove' (using 'mirror' segtype) - # This setting has replaced 'mirror_region_size' since version 2.02.99 -diff --git a/configure b/configure -index c96911c..6803010 100755 ---- a/configure -+++ b/configure -@@ -688,6 +688,7 @@ CLUSTER - CLDWHOLEARCHIVE - CLDNOWHOLEARCHIVE - CLDFLAGS -+CACHE - BUILD_LVMETAD - BUILD_DMEVENTD - BUILD_CMIRRORD -@@ -839,6 +840,7 @@ with_thin - with_thin_check - with_thin_dump - with_thin_repair -+with_cache - enable_readline - enable_realtime - enable_ocf -@@ -1622,6 +1624,8 @@ Optional Packages: - --with-thin-check=PATH thin_check tool: [[autodetect]] - --with-thin-dump=PATH thin_dump tool: [[autodetect]] - --with-thin-repair=PATH thin_repair tool: [[autodetect]] -+ --with-cache=TYPE cache support: internal/shared/none -+ [[TYPE=none]] - --with-ocfdir=DIR install OCF files in DIR - [[PREFIX/lib/ocf/resource.d/lvm2]] - --with-default-pid-dir=PID_DIR -@@ -7531,6 +7535,30 @@ cat >>confdefs.h <<_ACEOF - _ACEOF - - -+################################################################################ -+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include cache" >&5 -+$as_echo_n "checking whether to include cache... " >&6; } -+ -+# Check whether --with-cache was given. -+if test "${with_cache+set}" = set; then : -+ withval=$with_cache; CACHE=$withval -+else -+ CACHE=none -+fi -+ -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CACHE" >&5 -+$as_echo "$CACHE" >&6; } -+ -+if [ "x$CACHE" != xnone -a "x$CACHE" != xinternal -a "x$CACHE" != xshared ]; -+ then as_fn_error $? "--with-cache parameter invalid -+" "$LINENO" 5 -+fi; -+ -+if test x$CACHE = xinternal; then -+ -+$as_echo "#define CACHE_INTERNAL 1" >>confdefs.h -+ -+fi - - ################################################################################ - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable readline" >&5 -@@ -10150,6 +10178,7 @@ fi - if [ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \ - -o "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \ - -o "x$RAID" = xshared \ -+ -o "x$CACHE" = xshared \ - \) -a "x$STATIC_LINK" = xyes ]; - then as_fn_error $? "Features cannot be 'shared' when building statically - " "$LINENO" 5 -@@ -11423,8 +11452,9 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' '{print $2}'` - - - -+ - ################################################################################ --ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile conf/Makefile conf/example.conf conf/default.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_monitoring_init_red_hat scripts/dm_event_systemd_red_hat.socket scripts/dm_event_systemd_red_hat.service scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile" -+ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile conf/Makefile conf/example.conf conf/default.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/lvm2_clvmd_systemd_red_hat.service scripts/cmirrord_init_red_hat scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_monitoring_init_red_hat scripts/dm_event_systemd_red_hat.socket scripts/dm_event_systemd_red_hat.service scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile" - - cat >confcache <<\_ACEOF - # This file is a shell script that caches the results of configure -@@ -12142,6 +12172,7 @@ do - "lib/raid/Makefile") CONFIG_FILES="$CONFIG_FILES lib/raid/Makefile" ;; - "lib/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;; - "lib/thin/Makefile") CONFIG_FILES="$CONFIG_FILES lib/thin/Makefile" ;; -+ "lib/cache_segtype/Makefile") CONFIG_FILES="$CONFIG_FILES lib/cache_segtype/Makefile" ;; - "libdaemon/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/Makefile" ;; - "libdaemon/client/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/client/Makefile" ;; - "libdaemon/server/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/server/Makefile" ;; -@@ -12156,8 +12187,12 @@ do - "scripts/blkdeactivate.sh") CONFIG_FILES="$CONFIG_FILES scripts/blkdeactivate.sh" ;; - "scripts/blk_availability_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/blk_availability_init_red_hat" ;; - "scripts/blk_availability_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/blk_availability_systemd_red_hat.service" ;; -+ "scripts/lvm2_cluster_activation_red_hat.sh") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_cluster_activation_red_hat.sh" ;; -+ "scripts/lvm2_cluster_activation_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_cluster_activation_systemd_red_hat.service" ;; - "scripts/clvmd_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/clvmd_init_red_hat" ;; -+ "scripts/lvm2_clvmd_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_clvmd_systemd_red_hat.service" ;; - "scripts/cmirrord_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/cmirrord_init_red_hat" ;; -+ "scripts/lvm2_cmirrord_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_cmirrord_systemd_red_hat.service" ;; - "scripts/lvm2_lvmetad_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_init_red_hat" ;; - "scripts/lvm2_lvmetad_systemd_red_hat.socket") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_systemd_red_hat.socket" ;; - "scripts/lvm2_lvmetad_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_systemd_red_hat.service" ;; -diff --git a/configure.in b/configure.in -index cff7e45..f125209 100644 ---- a/configure.in -+++ b/configure.in -@@ -476,6 +476,25 @@ AC_DEFINE_UNQUOTED([THIN_DUMP_CMD], ["$THIN_DUMP_CMD"], - AC_DEFINE_UNQUOTED([THIN_REPAIR_CMD], ["$THIN_REPAIR_CMD"], - [The path to 'thin_repair', if available.]) - -+################################################################################ -+dnl -- cache inclusion type -+AC_MSG_CHECKING(whether to include cache) -+AC_ARG_WITH(cache, -+ AC_HELP_STRING([--with-cache=TYPE], -+ [cache support: internal/shared/none -+ [[TYPE=none]]]), -+ CACHE=$withval, CACHE=none) -+AC_MSG_RESULT($CACHE) -+ -+if [[ "x$CACHE" != xnone -a "x$CACHE" != xinternal -a "x$CACHE" != xshared ]]; -+ then AC_MSG_ERROR( -+--with-cache parameter invalid -+) -+fi; -+ -+if test x$CACHE = xinternal; then -+ AC_DEFINE([CACHE_INTERNAL], 1, [Define to 1 to include built-in support for cache.]) -+fi - - ################################################################################ - dnl -- Disable readline -@@ -1241,6 +1260,7 @@ dnl -- Check for shared/static conflicts - if [[ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \ - -o "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \ - -o "x$RAID" = xshared \ -+ -o "x$CACHE" = xshared \ - \) -a "x$STATIC_LINK" = xyes ]]; - then AC_MSG_ERROR( - Features cannot be 'shared' when building statically -@@ -1596,6 +1616,7 @@ AC_SUBST(BLKID_WIPING) - AC_SUBST(BUILD_CMIRRORD) - AC_SUBST(BUILD_DMEVENTD) - AC_SUBST(BUILD_LVMETAD) -+AC_SUBST(CACHE) - AC_SUBST(CFLAGS) - AC_SUBST(CFLOW_CMD) - AC_SUBST(CLDFLAGS) -@@ -1752,6 +1773,7 @@ lib/misc/lvm-version.h - lib/raid/Makefile - lib/snapshot/Makefile - lib/thin/Makefile -+lib/cache_segtype/Makefile - libdaemon/Makefile - libdaemon/client/Makefile - libdaemon/server/Makefile -@@ -1766,8 +1788,12 @@ python/setup.py - scripts/blkdeactivate.sh - scripts/blk_availability_init_red_hat - scripts/blk_availability_systemd_red_hat.service -+scripts/lvm2_cluster_activation_red_hat.sh -+scripts/lvm2_cluster_activation_systemd_red_hat.service - scripts/clvmd_init_red_hat -+scripts/lvm2_clvmd_systemd_red_hat.service - scripts/cmirrord_init_red_hat -+scripts/lvm2_cmirrord_systemd_red_hat.service - scripts/lvm2_lvmetad_init_red_hat - scripts/lvm2_lvmetad_systemd_red_hat.socket - scripts/lvm2_lvmetad_systemd_red_hat.service -diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c -index 179775a..4a17fb2 100644 ---- a/daemons/dmeventd/dmeventd.c -+++ b/daemons/dmeventd/dmeventd.c -@@ -514,6 +514,30 @@ static int _get_status(struct message_data *message_data) - - } - -+static int _get_parameters(struct message_data *message_data) { -+ struct dm_event_daemon_message *msg = message_data->msg; -+ char buf[128]; -+ int r = -1; -+ -+ dm_free(msg->data); -+ -+ if (!(dm_snprintf(buf, sizeof(buf), "%s pid=%d daemon=%s exec_method=%s", -+ message_data->id, -+ getpid(), -+ _foreground ? "no" : "yes", -+ _systemd_activation ? "systemd" : "direct"))) -+ goto_out; -+ -+ msg->size = strlen(buf) + 1; -+ if (!(msg->data = dm_malloc(msg->size))) -+ goto_out; -+ if (!dm_strncpy(msg->data, buf, msg->size)) -+ goto_out; -+ r = 0; -+out: -+ return r; -+} -+ - /* Cleanup at exit. */ - static void _exit_dm_lib(void) - { -@@ -1437,6 +1461,14 @@ static int _handle_request(struct dm_event_daemon_message *msg, - { DM_EVENT_CMD_GET_TIMEOUT, _get_timeout}, - { DM_EVENT_CMD_ACTIVE, _active}, - { DM_EVENT_CMD_GET_STATUS, _get_status}, -+ /* dmeventd parameters of running dmeventd, -+ * returns 'pid= daemon= exec_method=' -+ * pid - pidfile of running dmeventd -+ * daemon - running as a daemon or not (foreground)? -+ * exec_method - "direct" if executed directly or -+ * "systemd" if executed via systemd -+ */ -+ { DM_EVENT_CMD_GET_PARAMETERS, _get_parameters}, - }, *req; - - for (req = requests; req < requests + sizeof(requests) / sizeof(struct request); req++) -@@ -1504,7 +1536,11 @@ static void _process_request(struct dm_event_fifos *fifos) - - dm_free(msg.data); - -- if (die) raise(9); -+ if (die) { -+ if (unlink(DMEVENTD_PIDFILE)) -+ perror(DMEVENTD_PIDFILE ": unlink failed"); -+ _exit(0); -+ } - } - - static void _process_initial_registrations(void) -@@ -1732,6 +1768,7 @@ out: - unsetenv(SD_LISTEN_FDS_ENV_VAR_NAME); - return r; - } -+ - #endif - - static void _remove_files_on_exit(void) -@@ -1823,6 +1860,59 @@ static void _daemonize(void) - setsid(); - } - -+static int _reinstate_registrations(struct dm_event_fifos *fifos) -+{ -+ static const char _failed_parsing_msg[] = "Failed to parse existing event registration.\n"; -+ static const char *_delim = " "; -+ struct dm_event_daemon_message msg = { 0 }; -+ char *endp, *dso_name, *dev_name, *mask, *timeout; -+ unsigned long mask_value, timeout_value; -+ int i, ret; -+ -+ ret = daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0); -+ dm_free(msg.data); -+ msg.data = NULL; -+ -+ if (ret) { -+ fprintf(stderr, "Failed to communicate with new instance of dmeventd.\n"); -+ return 0; -+ } -+ -+ for (i = 0; _initial_registrations[i]; ++i) { -+ if (!(strtok(_initial_registrations[i], _delim)) || -+ !(dso_name = strtok(NULL, _delim)) || -+ !(dev_name = strtok(NULL, _delim)) || -+ !(mask = strtok(NULL, _delim)) || -+ !(timeout = strtok(NULL, _delim))) { -+ fprintf(stderr, _failed_parsing_msg); -+ continue; -+ } -+ -+ errno = 0; -+ mask_value = strtoul(mask, &endp, 10); -+ if (errno || !endp || *endp) { -+ fprintf(stderr, _failed_parsing_msg); -+ continue; -+ } -+ -+ errno = 0; -+ timeout_value = strtoul(timeout, &endp, 10); -+ if (errno || !endp || *endp) { -+ fprintf(stderr, _failed_parsing_msg); -+ continue; -+ } -+ -+ if (daemon_talk(fifos, &msg, DM_EVENT_CMD_REGISTER_FOR_EVENT, -+ dso_name, -+ dev_name, -+ (enum dm_event_mask) mask_value, -+ timeout_value)) -+ fprintf(stderr, "Failed to reinstate monitoring for device %s.\n", dev_name); -+ } -+ -+ return 1; -+} -+ - static void restart(void) - { - struct dm_event_fifos fifos = { -@@ -1837,9 +1927,9 @@ static void restart(void) - char *message; - int length; - int version; -+ const char *e; - - /* Get the list of registrations from the running daemon. */ -- - if (!init_fifos(&fifos)) { - fprintf(stderr, "WARNING: Could not initiate communication with existing dmeventd.\n"); - exit(EXIT_FAILURE); -@@ -1885,24 +1975,61 @@ static void restart(void) - } - _initial_registrations[count] = 0; - -+ if (version >= 2) { -+ if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) { -+ fprintf(stderr, "Failed to acquire parameters from old dmeventd.\n"); -+ goto bad; -+ } -+ if (strstr(msg.data, "exec_method=systemd")) -+ _systemd_activation = 1; -+ } -+#ifdef __linux__ -+ /* -+ * If the protocol version is old, just assume that if systemd is running, -+ * the dmeventd is also run as a systemd service via fifo activation. -+ */ -+ if (version < 2) { -+ /* This check is copied from sd-daemon.c. */ -+ struct stat st; -+ if (!lstat("/run/systemd/system/", &st) && !!S_ISDIR(st.st_mode)) -+ _systemd_activation = 1; -+ } -+#endif -+ - if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_DIE, "-", "-", 0, 0)) { - fprintf(stderr, "Old dmeventd refused to die.\n"); - goto bad; - } - -- /* -- * Wait for daemon to die, detected by sending further DIE messages -- * until one fails. -- */ -+ if (!_systemd_activation && -+ ((e = getenv(SD_ACTIVATION_ENV_VAR_NAME)) && strcmp(e, "1"))) -+ _systemd_activation = 1; -+ - for (i = 0; i < 10; ++i) { -- if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_DIE, "-", "-", 0, 0)) -- break; /* yep, it's dead probably */ -+ if ((access(DMEVENTD_PIDFILE, F_OK) == -1) && (errno == ENOENT)) -+ break; - usleep(10); - } - -+ if (!_systemd_activation) { -+ fini_fifos(&fifos); -+ return; -+ } -+ -+ /* Reopen fifos. */ - fini_fifos(&fifos); -+ if (!init_fifos(&fifos)) { -+ fprintf(stderr, "Could not initiate communication with new instance of dmeventd.\n"); -+ exit(EXIT_FAILURE); -+ } - -- return; -+ if (!_reinstate_registrations(&fifos)) { -+ fprintf(stderr, "Failed to reinstate monitoring with new instance of dmeventd.\n"); -+ goto bad; -+ } -+ -+ fini_fifos(&fifos); -+ exit(EXIT_SUCCESS); - bad: - fini_fifos(&fifos); - exit(EXIT_FAILURE); -diff --git a/daemons/dmeventd/dmeventd.h b/daemons/dmeventd/dmeventd.h -index e21cf45..25a4bbb 100644 ---- a/daemons/dmeventd/dmeventd.h -+++ b/daemons/dmeventd/dmeventd.h -@@ -34,6 +34,7 @@ enum dm_event_command { - DM_EVENT_CMD_HELLO, - DM_EVENT_CMD_DIE, - DM_EVENT_CMD_GET_STATUS, -+ DM_EVENT_CMD_GET_PARAMETERS, - }; - - /* Message passed between client and daemon. */ -diff --git a/daemons/dmeventd/libdevmapper-event.c b/daemons/dmeventd/libdevmapper-event.c -index 1b5273d..db9200f 100644 ---- a/daemons/dmeventd/libdevmapper-event.c -+++ b/daemons/dmeventd/libdevmapper-event.c -@@ -619,6 +619,13 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh) - - uuid = dm_task_get_uuid(dmt); - -+ if (!strstr(dmevh->dso, "libdevmapper-event-lvm2thin.so") && -+ !strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") && -+ !strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") && -+ !strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so")) -+ log_warn("WARNING: %s: dmeventd plugins are deprecated", dmevh->dso); -+ -+ - if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg, - dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) { - log_error("%s: event registration failed: %s", -diff --git a/daemons/dmeventd/libdevmapper-event.h b/daemons/dmeventd/libdevmapper-event.h -index 9c1cc6f..532bebf 100644 ---- a/daemons/dmeventd/libdevmapper-event.h -+++ b/daemons/dmeventd/libdevmapper-event.h -@@ -46,7 +46,7 @@ enum dm_event_mask { - }; - - #define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK --#define DM_EVENT_PROTOCOL_VERSION 1 -+#define DM_EVENT_PROTOCOL_VERSION 2 - - struct dm_task; - struct dm_event_handler; -diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c -index eefbf1d..e6e222f 100644 ---- a/daemons/lvmetad/lvmetad-core.c -+++ b/daemons/lvmetad/lvmetad-core.c -@@ -1095,7 +1095,8 @@ static response handler(daemon_state s, client_handle h, request r) - return daemon_reply_simple("token_mismatch", - "expected = %s", state->token, - "received = %s", token, -- "reason = %s", "token mismatch", NULL); -+ "reason = %s", -+ "lvmetad cache is invalid due to a global_filter change or due to a running rescan", NULL); - } - pthread_mutex_unlock(&state->token_lock); - -@@ -1189,7 +1190,7 @@ static int fini(daemon_state *s) - return 1; - } - --static void usage(char *prog, FILE *file) -+static void usage(const char *prog, FILE *file) - { - fprintf(file, "Usage:\n" - "%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path]\n\n" -@@ -1204,27 +1205,19 @@ static void usage(char *prog, FILE *file) - int main(int argc, char *argv[]) - { - signed char opt; -- lvmetad_state ls; -+ lvmetad_state ls = { .log_config = "" }; - daemon_state s = { - .daemon_fini = fini, - .daemon_init = init, - .handler = handler, - .name = "lvmetad", -- .pidfile = getenv("LVM_LVMETAD_PIDFILE"), -+ .pidfile = getenv("LVM_LVMETAD_PIDFILE") ? : LVMETAD_PIDFILE, - .private = &ls, - .protocol = "lvmetad", - .protocol_version = 1, -- .socket_path = getenv("LVM_LVMETAD_SOCKET"), -+ .socket_path = getenv("LVM_LVMETAD_SOCKET") ? : LVMETAD_SOCKET, - }; - -- if (!s.pidfile) -- s.pidfile = LVMETAD_PIDFILE; -- -- if (!s.socket_path) -- s.socket_path = LVMETAD_SOCKET; -- -- ls.log_config = ""; -- - // use getopt_long - while ((opt = getopt(argc, argv, "?fhVl:p:s:")) != EOF) { - switch (opt) { -@@ -1253,5 +1246,6 @@ int main(int argc, char *argv[]) - } - - daemon_start(s); -+ - return 0; - } -diff --git a/lib/Makefile.in b/lib/Makefile.in -index 8fdc194..968ad00 100644 ---- a/lib/Makefile.in -+++ b/lib/Makefile.in -@@ -1,6 +1,6 @@ - # - # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. --# Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved. -+# Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved. - # - # This file is part of LVM2. - # -@@ -44,6 +44,10 @@ ifeq ("@THIN@", "shared") - SUBDIRS += thin - endif - -+ifeq ("@CACHE@", "shared") -+ SUBDIRS += cache_segtype -+endif -+ - SOURCES =\ - activate/activate.c \ - cache/lvmcache.c \ -@@ -83,11 +87,13 @@ SOURCES =\ - locking/locking.c \ - locking/no_locking.c \ - log/log.c \ -+ metadata/cache_manip.c \ - metadata/lv.c \ - metadata/lv_manip.c \ - metadata/merge.c \ - metadata/metadata.c \ - metadata/mirror.c \ -+ metadata/pool_manip.c \ - metadata/pv.c \ - metadata/pv_manip.c \ - metadata/pv_map.c \ -@@ -164,6 +170,10 @@ ifeq ("@THIN@", "internal") - SOURCES += thin/thin.c - endif - -+ifeq ("@CACHE@", "internal") -+ SOURCES += cache_segtype/cache.c -+endif -+ - ifeq ("@DEVMAPPER@", "yes") - SOURCES +=\ - activate/dev_manager.c \ -@@ -198,6 +208,7 @@ ifeq ($(MAKECMDGOALS),distclean) - raid \ - replicator \ - thin \ -+ cache_segtype \ - locking - endif - -diff --git a/lib/activate/activate.c b/lib/activate/activate.c -index 4c8c16d..26dc0e1 100644 ---- a/lib/activate/activate.c -+++ b/lib/activate/activate.c -@@ -285,6 +285,18 @@ int lv_raid_message(const struct logical_volume *lv, const char *msg) - { - return 0; - } -+int lv_cache_block_info(const struct logical_volume *lv, -+ uint32_t *chunk_size, uint64_t *dirty_count, -+ uint64_t *used_count, uint64_t *total_count) -+{ -+ return 0; -+} -+int lv_cache_policy_info(const struct logical_volume *lv, -+ char **policy_name, int *policy_argc, -+ char ***policy_argv) -+{ -+ return 0; -+} - int lv_thin_pool_percent(const struct logical_volume *lv, int metadata, - percent_t *percent) - { -@@ -969,6 +981,162 @@ out: - return r; - } - -+int lv_cache_block_info(struct logical_volume *lv, -+ uint32_t *chunk_size, uint64_t *dirty_count, -+ uint64_t *used_count, uint64_t *total_count) -+{ -+ struct lv_segment *cache_seg; -+ struct logical_volume *cache_lv; -+ struct dev_manager *dm; -+ struct dm_status_cache *status; -+ -+ /* The user is free to choose which args they are interested in */ -+ if (chunk_size) -+ *chunk_size = 0; -+ if (dirty_count) -+ *dirty_count = 0; -+ if (used_count) -+ *used_count = 0; -+ if (total_count) -+ *total_count = 0; -+ -+ if (lv_is_cache(lv)) -+ cache_lv = lv; -+ else if (lv_is_cache_pool(lv)) { -+ if (dm_list_empty(&lv->segs_using_this_lv)) { -+ //FIXME: Ok to return value not sourced from kernel? -+ // This could be valuable - esp for 'lvs' output -+ log_error(INTERNAL_ERROR "Unable to get block info" -+ " of unlinked cache_pool, %s", lv->name); -+ //FIXME: ... because we could do this: -+ if (chunk_size) -+ *chunk_size = first_seg(lv)->chunk_size; -+ /* Unlinked cache_pools have 0 dirty & used blocks */ -+ if (total_count) { -+ *total_count = lv->size; /* in sectors */ -+ *total_count /= first_seg(lv)->chunk_size; -+ } -+ -+ return 1; -+ } -+ if (!(cache_seg = get_only_segment_using_this_lv(lv))) -+ return_0; -+ cache_lv = cache_seg->lv; -+ } else { -+ log_error(INTERNAL_ERROR -+ "Unable to get block info of non-cache LV, %s", -+ lv->name); -+ return 0; -+ } -+ -+ if (!lv_info(cache_lv->vg->cmd, cache_lv, 0, NULL, 0, 0)) -+ return_0; -+ -+ log_debug_activation("Checking cache block info for LV %s/%s", -+ cache_lv->vg->name, cache_lv->name); -+ -+ if (!(dm = dev_manager_create(cache_lv->vg->cmd, cache_lv->vg->name, 1))) -+ return_0; -+ -+ if (!dev_manager_cache_status(dm, cache_lv, &status)) { -+ dev_manager_destroy(dm); -+ return_0; -+ } -+ -+ if (chunk_size) -+ *chunk_size = status->block_size; -+ if (dirty_count) -+ *dirty_count = status->dirty_blocks; -+ if (used_count) -+ *used_count = status->used_blocks; -+ if (total_count) -+ *total_count = status->total_blocks; -+ -+ dev_manager_destroy(dm); -+ -+ return 1; -+} -+ -+int lv_cache_policy_info(struct logical_volume *lv, -+ char **policy_name, int *policy_argc, -+ char ***policy_argv) -+{ -+ int i; -+ struct lv_segment *cache_seg; -+ struct logical_volume *cache_lv; -+ struct dev_manager *dm; -+ struct dm_status_cache *status; -+ struct dm_pool *mem = lv->vg->cmd->mem; -+ -+ /* The user is free to choose which args they are interested in */ -+ if (policy_name) -+ *policy_name = NULL; -+ if (policy_argc) -+ *policy_argc = 0; -+ if (policy_argv) -+ *policy_argv = NULL; -+ -+ if (lv_is_cache(lv)) -+ cache_lv = lv; -+ else if (lv_is_cache_pool(lv)) { -+ if (dm_list_empty(&lv->segs_using_this_lv)) { -+ //FIXME: Ok to return value not sourced from kernel? -+ log_error(INTERNAL_ERROR "Unable to get policy info" -+ " of unlinked cache_pool, %s", lv->name); -+ //FIXME: ... because we could do this: -+ if (policy_name) -+ *policy_name = first_seg(lv)->policy_name; -+ if (policy_argc) -+ *policy_argc = first_seg(lv)->policy_argc; -+ if (policy_argv) -+ *policy_argv = first_seg(lv)->policy_argv; -+ -+ return 1; -+ } -+ if (!(cache_seg = get_only_segment_using_this_lv(lv))) -+ return_0; -+ cache_lv = cache_seg->lv; -+ } else { -+ log_error(INTERNAL_ERROR -+ "Unable to get policy info of non-cache LV, %s", -+ lv->name); -+ return 0; -+ } -+ -+ if (!lv_info(cache_lv->vg->cmd, cache_lv, 0, NULL, 0, 0)) -+ return_0; -+ -+ log_debug_activation("Checking cache policy for LV %s/%s", -+ cache_lv->vg->name, cache_lv->name); -+ -+ if (!(dm = dev_manager_create(cache_lv->vg->cmd, cache_lv->vg->name, 1))) -+ return_0; -+ -+ if (!dev_manager_cache_status(dm, cache_lv, &status)) { -+ dev_manager_destroy(dm); -+ return_0; -+ } -+ -+ if (policy_name && -+ !(*policy_name = dm_pool_strdup(mem, status->policy_name))) -+ return_0; -+ if (policy_argc) -+ *policy_argc = status->policy_argc; -+ if (policy_argv) { -+ if (!(*policy_argv = -+ dm_pool_zalloc(mem, sizeof(char *) * *policy_argc))) -+ return_0; -+ for (i = 0; i < *policy_argc; i++) -+ if (!((*policy_argv)[i] = -+ dm_pool_strdup(mem, status->policy_argv[i]))) -+ return_0; -+ } -+ -+ dev_manager_destroy(dm); -+ -+ return 1; -+} -+ - /* - * Returns data or metadata percent usage, depends on metadata 0/1. - * Returns 1 if percent set, else 0 on failure. -diff --git a/lib/activate/activate.h b/lib/activate/activate.h -index 1881f75..ad14a57 100644 ---- a/lib/activate/activate.h -+++ b/lib/activate/activate.h -@@ -55,6 +55,11 @@ struct lv_activate_opts { - /* target attribute flags */ - #define MIRROR_LOG_CLUSTERED 0x00000001U - -+/* snapshot target attribute flags */ -+enum { -+ SNAPSHOT_FEATURE_FIXED_LEAK = (1 << 0), /* version 1.12 */ -+}; -+ - /* thin target attribute flags */ - enum { - /* bitfields - new features from 1.1 version */ -@@ -64,6 +69,12 @@ enum { - THIN_FEATURE_BLOCK_SIZE = (1 << 3), - THIN_FEATURE_DISCARDS_NON_POWER_2 = (1 << 4), - THIN_FEATURE_METADATA_RESIZE = (1 << 5), -+ THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND = (1 << 6), -+}; -+ -+/* raid target attribute flags */ -+enum { -+ RAID_FEATURE_RAID10 = (1 << 0), /* version 1.3 */ - }; - - void set_activation(int activation); -@@ -134,6 +145,12 @@ int lv_raid_dev_health(const struct logical_volume *lv, char **dev_health); - int lv_raid_mismatch_count(const struct logical_volume *lv, uint64_t *cnt); - int lv_raid_sync_action(const struct logical_volume *lv, char **sync_action); - int lv_raid_message(const struct logical_volume *lv, const char *msg); -+int lv_cache_block_info(struct logical_volume *lv, -+ uint32_t *chunk_size, uint64_t *dirty_count, -+ uint64_t *used_count, uint64_t *total_count); -+int lv_cache_policy_info(struct logical_volume *lv, -+ char **policy_name, int *policy_argc, -+ char ***policy_argv); - int lv_thin_pool_percent(const struct logical_volume *lv, int metadata, - percent_t *percent); - int lv_thin_percent(const struct logical_volume *lv, int mapped, -diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c -index 7b0b6e2..6b5f8c2 100644 ---- a/lib/activate/dev_manager.c -+++ b/lib/activate/dev_manager.c -@@ -1,6 +1,6 @@ - /* - * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. -- * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved. - * - * This file is part of LVM2. - * -@@ -63,7 +63,7 @@ struct lv_layer { - - int read_only_lv(struct logical_volume *lv, struct lv_activate_opts *laopts) - { -- return (laopts->read_only || !(lv->vg->status & LVM_WRITE) || !(lv->status & LVM_WRITE)); -+ return (laopts->read_only || !(lv->status & LVM_WRITE)); - } - - /* -@@ -1160,6 +1160,55 @@ out: - return r; - } - -+int dev_manager_cache_status(struct dev_manager *dm, -+ const struct logical_volume *lv, -+ struct dm_status_cache **status) -+{ -+ int r = 0; -+ const char *dlid; -+ struct dm_task *dmt; -+ struct dm_info info; -+ uint64_t start, length; -+ char *type = NULL; -+ char *params = NULL; -+ const char *layer = lv_layer(lv); -+ -+ if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) -+ return_0; -+ -+ log_debug_activation("Getting cache device status for %s.", lv->name); -+ -+ if (!(dmt = _setup_task(NULL, dlid, 0, DM_DEVICE_STATUS, 0, 0))) -+ return_0; -+ -+ if (!dm_task_no_open_count(dmt)) -+ log_error("Failed to disable open_count."); -+ -+ if (!dm_task_run(dmt)) -+ goto_out; -+ -+ if (!dm_task_get_info(dmt, &info) || !info.exists) -+ goto_out; -+ -+ dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms); -+ -+ if (!type || strcmp(type, "cache")) { -+ log_debug("Expected cache segment type but got %s instead", -+ type ? type : "NULL"); -+ goto out; -+ } -+ -+ if (!dm_get_status_cache(dm->mem, params, status)) -+ goto_out; -+ -+ r = 1; -+out: -+ dm_task_destroy(dmt); -+ -+ return r; -+} -+ -+//FIXME: Can we get rid of this crap below? - #if 0 - log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", name); - -@@ -1863,6 +1912,10 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, - !_add_lv_to_dtree(dm, dtree, seg->pool_lv, 1)) /* stack */ - return_0; - -+ if (seg->pool_lv && lv_is_cache_pool(seg->pool_lv) && -+ !_add_lv_to_dtree(dm, dtree, seg->pool_lv, 0)) -+ return_0; -+ - for (s = 0; s < seg->area_count; s++) { - if (seg_type(seg, s) == AREA_LV && seg_lv(seg, s) && - !_add_lv_to_dtree(dm, dtree, seg_lv(seg, s), 0)) -@@ -2327,15 +2380,18 @@ static int _add_segment_to_dtree(struct dev_manager *dm, - if (seg->external_lv && - !_add_new_external_lv_to_dtree(dm, dtree, seg->external_lv, laopts)) - return_0; -+ - /* Add mirror log */ - if (seg->log_lv && - !_add_new_lv_to_dtree(dm, dtree, seg->log_lv, laopts, NULL)) - return_0; -- /* Add thin pool metadata */ -+ -+ /* Add pool metadata */ - if (seg->metadata_lv && - !_add_new_lv_to_dtree(dm, dtree, seg->metadata_lv, laopts, NULL)) - return_0; -- /* Add thin pool layer */ -+ -+ /* Add pool layer */ - if (seg->pool_lv && - !_add_new_lv_to_dtree(dm, dtree, seg->pool_lv, laopts, - lv_layer(seg->pool_lv))) -@@ -2450,7 +2506,7 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, - dinfo->open_count)) { - if (seg_is_thin_volume(seg) || - /* FIXME Is there anything simpler to check for instead? */ -- !lv_has_target_type(dm->mem, lv, NULL, "snapshot-merge")) -+ !lv_has_target_type(dm->mem, lv, NULL, "snapshot-merge")) - laopts->no_merging = 1; - } - } -@@ -2506,7 +2562,7 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, - return_0; - if (!laopts->no_merging && lv_is_merging_origin(lv)) { - if (!_add_new_lv_to_dtree(dm, dtree, -- find_snapshot(lv)->cow, laopts, "cow")) -+ find_snapshot(lv)->cow, laopts, "cow")) - return_0; - /* - * Must also add "real" LV for use when -diff --git a/lib/activate/dev_manager.h b/lib/activate/dev_manager.h -index 032766e..446b349 100644 ---- a/lib/activate/dev_manager.h -+++ b/lib/activate/dev_manager.h -@@ -60,6 +60,9 @@ int dev_manager_raid_status(struct dev_manager *dm, - int dev_manager_raid_message(struct dev_manager *dm, - const struct logical_volume *lv, - const char *msg); -+int dev_manager_cache_status(struct dev_manager *dm, -+ const struct logical_volume *lv, -+ struct dm_status_cache **status); - int dev_manager_thin_pool_status(struct dev_manager *dm, - const struct logical_volume *lv, - struct dm_status_thin_pool **status, -diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c -index ec8699b..d40bdce 100644 ---- a/lib/cache/lvmcache.c -+++ b/lib/cache/lvmcache.c -@@ -264,9 +264,9 @@ static void _drop_metadata(const char *vgname, int drop_precommitted) - } - - /* -- * Remote node uses this to upgrade precommited metadata to commited state -+ * Remote node uses this to upgrade precommitted metadata to commited state - * when receives vg_commit notification. -- * (Note that devices can be suspended here, if so, precommited metadata are already read.) -+ * (Note that devices can be suspended here, if so, precommitted metadata are already read.) - */ - void lvmcache_commit_metadata(const char *vgname) - { -diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c -index aec6a71..c994874 100644 ---- a/lib/cache/lvmetad.c -+++ b/lib/cache/lvmetad.c -@@ -40,7 +40,7 @@ void lvmetad_disconnect(void) - - void lvmetad_init(struct cmd_context *cmd) - { -- if (!_lvmetad_use && !access(LVMETAD_PIDFILE, F_OK)) -+ if (!_lvmetad_use && !access(getenv("LVM_LVMETAD_PIDFILE") ? : LVMETAD_PIDFILE, F_OK)) - log_warn("WARNING: lvmetad is running but disabled." - " Restart lvmetad before enabling it!"); - _lvmetad_cmd = cmd; -@@ -159,12 +159,27 @@ retry: - daemon_request_destroy(req); - - if (!repl.error && !strcmp(daemon_reply_str(repl, "response", ""), "token_mismatch") && -- try < 2 && !test_mode()) { -- if (lvmetad_pvscan_all_devs(_lvmetad_cmd, NULL)) { -- ++ try; -- daemon_reply_destroy(repl); -- goto retry; -- } -+ try < 60 && !test_mode()) { -+ /* -+ * If another process is trying to scan, they might have the -+ * same future token id and it's better to wait and avoid doing -+ * the work multiple times. For the case the future token is -+ * different, the wait is randomized so that multiple waiting -+ * processes do not start scanning all at once. -+ * -+ * If the token is mismatched because of global_filter changes, -+ * we re-scan immediately, but if we lose the potential race for -+ * the update, we back off for a short while (0.2-2 seconds) and -+ * try again. -+ */ -+ if (!strcmp(daemon_reply_str(repl, "expected", ""), "update in progress") || try % 5) -+ usleep( 50000 + random() % 450000 ); /* 0.05 - 0.5s */ -+ else -+ /* If the re-scan fails here, we try again later. */ -+ lvmetad_pvscan_all_devs(_lvmetad_cmd, NULL); -+ ++ try; -+ daemon_reply_destroy(repl); -+ goto retry; - } - - return repl; -diff --git a/lib/cache_segtype/.exported_symbols b/lib/cache_segtype/.exported_symbols -new file mode 100644 -index 0000000..95cb3ff ---- /dev/null -+++ b/lib/cache_segtype/.exported_symbols -@@ -0,0 +1 @@ -+init_cache_segtypes -diff --git a/lib/cache_segtype/Makefile.in b/lib/cache_segtype/Makefile.in -new file mode 100644 -index 0000000..32a1f2b ---- /dev/null -+++ b/lib/cache_segtype/Makefile.in -@@ -0,0 +1,24 @@ -+# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved. -+# -+# This file is part of LVM2. -+# -+# This copyrighted material is made available to anyone wishing to use, -+# modify, copy, or redistribute it subject to the terms and conditions -+# of the GNU General Public License v.2. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software Foundation, -+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+srcdir = @srcdir@ -+top_srcdir = @top_srcdir@ -+top_builddir = @top_builddir@ -+ -+SOURCES = cache.c -+ -+LIB_SHARED = liblvm2cache.$(LIB_SUFFIX) -+LIB_VERSION = $(LIB_VERSION_LVM) -+ -+include $(top_builddir)/make.tmpl -+ -+install: install_lvm2_plugin -diff --git a/lib/cache_segtype/cache.c b/lib/cache_segtype/cache.c -new file mode 100644 -index 0000000..57c7a5c ---- /dev/null -+++ b/lib/cache_segtype/cache.c -@@ -0,0 +1,448 @@ -+/* -+ * Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved. -+ * -+ * This file is part of LVM2. -+ * -+ * This copyrighted material is made available to anyone wishing to use, -+ * modify, copy, or redistribute it subject to the terms and conditions -+ * of the GNU Lesser General Public License v.2.1. -+ * -+ * You should have received a copy of the GNU Lesser General Public License -+ * along with this program; if not, write to the Free Software Foundation, -+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include "lib.h" -+#include "toolcontext.h" -+#include "segtype.h" -+#include "display.h" -+#include "text_export.h" -+#include "config.h" -+#include "str_list.h" -+#include "targets.h" -+#include "lvm-string.h" -+#include "activate.h" -+#include "metadata.h" -+#include "lv_alloc.h" -+#include "defaults.h" -+ -+#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; -+ -+ -+static const char *_name(const struct lv_segment *seg) -+{ -+ return seg->segtype->name; -+} -+ -+static int _cache_pool_text_import(struct lv_segment *seg, -+ const struct dm_config_node *sn, -+ struct dm_hash_table *pv_hash __attribute__((unused))) -+{ -+ uint32_t chunk_size; -+ struct logical_volume *data_lv, *meta_lv; -+ const char *str = NULL; -+ char *argv_str; -+ struct dm_pool *mem = seg->lv->vg->vgmem; //FIXME: what mempool should be used? -+ -+ if (!dm_config_has_node(sn, "data")) -+ return SEG_LOG_ERROR("Cache data not specified in"); -+ if (!(str = dm_config_find_str(sn, "data", NULL))) -+ return SEG_LOG_ERROR("Cache data must be a string in"); -+ if (!(data_lv = find_lv(seg->lv->vg, str))) -+ return SEG_LOG_ERROR("Unknown logical volume %s specified for " -+ "cache data in", str); -+ -+ if (!dm_config_has_node(sn, "metadata")) -+ return SEG_LOG_ERROR("Cache metadata not specified in"); -+ if (!(str = dm_config_find_str(sn, "metadata", NULL))) -+ return SEG_LOG_ERROR("Cache metadata must be a string in"); -+ if (!(meta_lv = find_lv(seg->lv->vg, str))) -+ return SEG_LOG_ERROR("Unknown logical volume %s specified for " -+ "cache metadata in", str); -+ -+ if (!dm_config_get_uint32(sn, "chunk_size", &chunk_size)) -+ return SEG_LOG_ERROR("Couldn't read cache chunk_size in"); -+ -+ /* -+ * Read in features: -+ * cache_mode = {writethrough|writeback} -+ * -+ * 'cache_mode' does not have to be present. -+ */ -+ if (dm_config_has_node(sn, "cache_mode")) { -+ if (!(str = dm_config_find_str(sn, "cache_mode", NULL))) -+ return SEG_LOG_ERROR("cache_mode must be a string in"); -+ if (!strcmp(str, "writethrough")) -+ seg->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH; -+ else if (!strcmp(str, "writeback")) -+ seg->feature_flags |= DM_CACHE_FEATURE_WRITEBACK; -+ else -+ return SEG_LOG_ERROR("Unknown cache_mode in"); -+ } -+ -+ /* -+ * Read in core arguments (these are key/value pairs) -+ * core_argc = <# args> -+ * core_argv = "[ ]..." -+ * -+ * 'core_argc' does not have to be present. If it is not present, -+ * any other core_* fields are ignored. If it is present, then -+ * 'core_argv' must be present - even if they are -+ * 'core_argc = 0' and 'core_argv = ""'. -+ */ -+ if (dm_config_has_node(sn, "core_argc")) { -+ if (!dm_config_has_node(sn, "core_argv")) -+ return SEG_LOG_ERROR("not all core arguments defined in"); -+ -+ if (!dm_config_get_uint32(sn, "core_argc", &seg->core_argc)) -+ return SEG_LOG_ERROR("Unable to read core_argc in"); -+ -+ str = dm_config_find_str(sn, "core_argv", NULL); -+ if ((str && !seg->core_argc) || (!str && seg->core_argc)) -+ return SEG_LOG_ERROR("core_argc and core_argv do" -+ " not match in"); -+ -+ if (!(seg->core_argv = -+ dm_pool_alloc(mem, sizeof(char *) * seg->core_argc))) -+ return_0; -+ if (str && -+ (!(argv_str = dm_pool_strdup(mem, str)) || -+ ((int)seg->core_argc != dm_split_words(argv_str, seg->core_argc, -+ 0, seg->core_argv)))) -+ return SEG_LOG_ERROR("core_argc and core_argv do" -+ " not match in"); -+ } -+ -+ /* -+ * Read in policy: -+ * policy_name = "" -+ * policy_argc = <# args> -+ * policy_argv = "[ ]..." -+ * -+ * 'policy_name' does not have to be present. If it is not present, -+ * any other policy_* fields are ignored. If it is present, then -+ * the other policy_* fields must be present - even if they are -+ * 'policy_argc = 0' and 'policy_argv = ""'. -+ */ -+ if (dm_config_has_node(sn, "policy_name")) { -+ if (!dm_config_has_node(sn, "policy_argc") || -+ !dm_config_has_node(sn, "policy_argv")) -+ return SEG_LOG_ERROR("not all policy arguments defined in"); -+ if (!(str = dm_config_find_str(sn, "policy_name", NULL))) -+ return SEG_LOG_ERROR("policy_name must be a string in"); -+ seg->policy_name = dm_pool_strdup(mem, str); -+ -+ if (!dm_config_get_uint32(sn, "policy_argc", &seg->policy_argc)) -+ return SEG_LOG_ERROR("Unable to read policy_argc in"); -+ -+ str = dm_config_find_str(sn, "policy_argv", NULL); -+ if ((str && !seg->policy_argc) || (!str && seg->policy_argc)) -+ return SEG_LOG_ERROR("policy_argc and policy_argv do" -+ " not match in"); -+ -+ if (!(seg->policy_argv = -+ dm_pool_alloc(mem, sizeof(char *) * seg->policy_argc))) -+ return_0; -+ if (str && -+ (!(argv_str = dm_pool_strdup(mem, str)) || -+ ((int)seg->policy_argc != dm_split_words(argv_str, -+ seg->policy_argc, -+ 0, seg->policy_argv)))) -+ return SEG_LOG_ERROR("policy_argc and policy_argv do" -+ " not match in"); -+ } -+ -+ if (!attach_pool_data_lv(seg, data_lv)) -+ return_0; -+ if (!attach_pool_metadata_lv(seg, meta_lv)) -+ return_0; -+ seg->chunk_size = chunk_size; -+ -+ return 1; -+} -+ -+static int _cache_pool_text_import_area_count(const struct dm_config_node *sn, -+ uint32_t *area_count) -+{ -+ *area_count = 1; -+ -+ return 1; -+} -+ -+static int _cache_pool_text_export(const struct lv_segment *seg, -+ struct formatter *f) -+{ -+ unsigned i; -+ char buf[256]; //FIXME: IS THERE AN 'outf' THAT DOESN'T DO NEWLINE?!? -+ uint32_t feature_flags = seg->feature_flags; -+ -+ outf(f, "data = \"%s\"", seg_lv(seg, 0)->name); -+ outf(f, "metadata = \"%s\"", seg->metadata_lv->name); -+ outf(f, "chunk_size = %" PRIu32, seg->chunk_size); -+ -+ if (feature_flags) { -+ if (feature_flags & DM_CACHE_FEATURE_WRITETHROUGH) { -+ outf(f, "cache_mode = \"writethrough\""); -+ feature_flags &= ~DM_CACHE_FEATURE_WRITETHROUGH; -+ } else if (feature_flags & DM_CACHE_FEATURE_WRITEBACK) { -+ outf(f, "cache_mode = \"writeback\""); -+ feature_flags &= ~DM_CACHE_FEATURE_WRITEBACK; -+ } else { -+ log_error(INTERNAL_ERROR "Unknown feature flags " -+ "in cache_pool segment for %s", seg->lv->name); -+ return 0; -+ } -+ } -+ -+ if (seg->core_argc) { -+ outf(f, "core_argc = %u", seg->core_argc); -+ outf(f, "core_argv = \""); -+ for (i = 0; i < seg->core_argc; i++) -+ outf(f, "%s%s", i ? " " : "", seg->core_argv[i]); -+ outf(f, "\""); -+ } -+ -+ if (seg->policy_name) { -+ outf(f, "policy_name = \"%s\"", seg->policy_name); -+ outf(f, "policy_argc = %u", seg->policy_argc); -+ buf[0] = '\0'; -+ for (i = 0; i < seg->policy_argc; i++) -+ sprintf(buf, "%s%s", i ? " " : "", seg->policy_argv[i]); -+ outf(f, "policy_argv = \"%s\"", buf); -+ } -+ -+ return 1; -+} -+ -+static int _cache_pool_add_target_line(struct dev_manager *dm, -+ struct dm_pool *mem, -+ struct cmd_context *cmd __attribute__((unused)), -+ void **target_state __attribute__((unused)), -+ struct lv_segment *seg, -+ const struct lv_activate_opts *laopts __attribute__((unused)), -+ struct dm_tree_node *node, uint64_t len, -+ uint32_t *pvmove_mirror_count __attribute__((unused))) -+{ -+ /* -+ * This /could/ be directed at _cdata, but I prefer -+ * not to give a user direct access to a sub-LV via -+ * this cache_pool. -+ */ -+ return dm_tree_node_add_error_target(node, len); -+} -+ -+static int _modules_needed(struct dm_pool *mem, -+ const struct lv_segment *seg __attribute__((unused)), -+ struct dm_list *modules) -+{ -+ if (!str_list_add(mem, modules, "cache")) { -+ log_error("cache module string list allocation failed"); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+static void _destroy(struct segment_type *segtype) -+{ -+ dm_free((void *) segtype); -+} -+ -+#ifdef DEVMAPPER_SUPPORT -+static int _target_present(struct cmd_context *cmd, -+ const struct lv_segment *seg __attribute__((unused)), -+ unsigned *attributes __attribute__((unused))) -+{ -+ uint32_t maj, min, patchlevel; -+ static int _cache_checked = 0; -+ static int _cache_present = 0; -+ -+ if (!_cache_checked) { -+ _cache_present = target_present(cmd, "cache", 1); -+ -+ if (!target_version("cache", &maj, &min, &patchlevel)) { -+ log_error("Failed to determine version of cache kernel module"); -+ return 0; -+ } -+ -+ _cache_checked = 1; -+ -+ if ((maj < 1) || -+ ((maj == 1) && (min < 3))) { -+ log_error("The cache kernel module is version %u.%u.%u." -+ " Version 1.3.0+ is required.", -+ maj, min, patchlevel); -+ return 0; -+ } -+ } -+ -+ return _cache_present; -+} -+ -+#endif /* DEVMAPPER_SUPPORT */ -+ -+static struct segtype_handler _cache_pool_ops = { -+ .name = _name, -+ .text_import = _cache_pool_text_import, -+ .text_import_area_count = _cache_pool_text_import_area_count, -+ .text_export = _cache_pool_text_export, -+ .add_target_line = _cache_pool_add_target_line, -+#ifdef DEVMAPPER_SUPPORT -+ .target_present = _target_present, -+# ifdef DMEVENTD -+# endif /* DMEVENTD */ -+#endif -+ .modules_needed = _modules_needed, -+ .destroy = _destroy, -+}; -+ -+static int _cache_text_import(struct lv_segment *seg, -+ const struct dm_config_node *sn, -+ struct dm_hash_table *pv_hash __attribute__((unused))) -+{ -+ struct logical_volume *pool_lv, *origin_lv; -+ const char *name = NULL; -+ -+ if (!dm_config_has_node(sn, "cache_pool")) -+ return SEG_LOG_ERROR("cache_pool not specified in"); -+ if (!(name = dm_config_find_str(sn, "cache_pool", NULL))) -+ return SEG_LOG_ERROR("cache_pool must be a string in"); -+ if (!(pool_lv = find_lv(seg->lv->vg, name))) -+ return SEG_LOG_ERROR("Unknown logical volume %s specified for " -+ "cache_pool in", name); -+ -+ if (!dm_config_has_node(sn, "origin")) -+ return SEG_LOG_ERROR("Cache origin not specified in"); -+ if (!(name = dm_config_find_str(sn, "origin", NULL))) -+ return SEG_LOG_ERROR("Cache origin must be a string in"); -+ if (!(origin_lv = find_lv(seg->lv->vg, name))) -+ return SEG_LOG_ERROR("Unknown logical volume %s specified for " -+ "cache origin in", name); -+ -+ if (!set_lv_segment_area_lv(seg, 0, origin_lv, 0, 0)) -+ return_0; -+ if (!attach_pool_lv(seg, pool_lv, NULL, NULL)) -+ return_0; -+ -+ return 1; -+} -+ -+static int _cache_text_import_area_count(const struct dm_config_node *sn, -+ uint32_t *area_count) -+{ -+ *area_count = 1; -+ -+ return 1; -+} -+ -+static int _cache_text_export(const struct lv_segment *seg, struct formatter *f) -+{ -+ if (!seg_lv(seg, 0)) -+ return_0; -+ -+ outf(f, "cache_pool = \"%s\"", seg->pool_lv->name); -+ outf(f, "origin = \"%s\"", seg_lv(seg, 0)->name); -+ -+ return 1; -+} -+ -+static int _cache_add_target_line(struct dev_manager *dm, -+ struct dm_pool *mem, -+ struct cmd_context *cmd __attribute__((unused)), -+ void **target_state __attribute__((unused)), -+ struct lv_segment *seg, -+ const struct lv_activate_opts *laopts __attribute__((unused)), -+ struct dm_tree_node *node, uint64_t len, -+ uint32_t *pvmove_mirror_count __attribute__((unused))) -+{ -+ struct lv_segment *cache_pool_seg = first_seg(seg->pool_lv); -+ char *metadata_uuid, *data_uuid, *origin_uuid; -+ -+ if (!(metadata_uuid = build_dm_uuid(mem, cache_pool_seg->metadata_lv->lvid.s, NULL))) -+ return_0; -+ -+ if (!(data_uuid = build_dm_uuid(mem, seg_lv(cache_pool_seg, 0)->lvid.s, NULL))) -+ return_0; -+ -+ if (!(origin_uuid = build_dm_uuid(mem, seg_lv(seg, 0)->lvid.s, NULL))) -+ return_0; -+ -+ if (!dm_tree_node_add_cache_target(node, len, -+ metadata_uuid, -+ data_uuid, -+ origin_uuid, -+ cache_pool_seg->chunk_size, -+ cache_pool_seg->feature_flags, -+ cache_pool_seg->core_argc, -+ cache_pool_seg->core_argv, -+ cache_pool_seg->policy_name, -+ cache_pool_seg->policy_argc, -+ cache_pool_seg->policy_argv)) -+ return_0; -+ -+ return add_areas_line(dm, seg, node, 0u, seg->area_count); -+} -+ -+static struct segtype_handler _cache_ops = { -+ .name = _name, -+ .text_import = _cache_text_import, -+ .text_import_area_count = _cache_text_import_area_count, -+ .text_export = _cache_text_export, -+ .add_target_line = _cache_add_target_line, -+#ifdef DEVMAPPER_SUPPORT -+ .target_present = _target_present, -+# ifdef DMEVENTD -+# endif /* DMEVENTD */ -+#endif -+ .modules_needed = _modules_needed, -+ .destroy = _destroy, -+}; -+ -+#ifdef CACHE_INTERNAL /* Shared */ -+int init_cache_segtypes(struct cmd_context *cmd, -+ struct segtype_library *seglib) -+#else -+int init_cache_segtypes(struct cmd_context *cmd, -+ struct segtype_library *seglib); -+int init_cache_segtypes(struct cmd_context *cmd, -+ struct segtype_library *seglib) -+#endif -+{ -+ struct segment_type *segtype = dm_zalloc(sizeof(*segtype)); -+ -+ if (!segtype) { -+ log_error("Failed to allocate memory for cache_pool segtype"); -+ return 0; -+ } -+ segtype->cmd = cmd; -+ -+ segtype->name = "cache-pool"; -+ segtype->flags = SEG_CACHE_POOL; -+ segtype->ops = &_cache_pool_ops; -+ segtype->private = NULL; -+ -+ if (!lvm_register_segtype(seglib, segtype)) -+ return_0; -+ log_very_verbose("Initialised segtype: %s", segtype->name); -+ -+ segtype = dm_zalloc(sizeof(*segtype)); -+ if (!segtype) { -+ log_error("Failed to allocate memory for cache segtype"); -+ return 0; -+ } -+ segtype->cmd = cmd; -+ -+ segtype->name = "cache"; -+ segtype->flags = SEG_CACHE; -+ segtype->ops = &_cache_ops; -+ segtype->private = NULL; -+ -+ if (!lvm_register_segtype(seglib, segtype)) -+ return_0; -+ log_very_verbose("Initialised segtype: %s", segtype->name); -+ -+ return 1; -+} -+ -diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c -index 9d6ef5e..a709284 100644 ---- a/lib/commands/toolcontext.c -+++ b/lib/commands/toolcontext.c -@@ -1,6 +1,6 @@ -- /* -+/* - * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. -- * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved. - * - * This file is part of LVM2. - * -@@ -1181,6 +1181,11 @@ static int _init_segtypes(struct cmd_context *cmd) - return 0; - #endif - -+#ifdef CACHE_INTERNAL -+ if (!init_cache_segtypes(cmd, &seglib)) -+ return 0; -+#endif -+ - #ifdef HAVE_LIBDL - /* Load any formats in shared libs unless static */ - if (!is_static() && -diff --git a/lib/config/config.c b/lib/config/config.c -index 6e93c40..e51c26f 100644 ---- a/lib/config/config.c -+++ b/lib/config/config.c -@@ -477,20 +477,24 @@ time_t config_file_timestamp(struct dm_config_tree *cft) - - #define cfg_def_get_item_p(id) (&_cfg_def_items[id]) - #define cfg_def_get_default_value(item,type) item->default_value.v_##type --#define cfg_def_get_path(item) (_cfg_def_make_path(_cfg_path,CFG_PATH_MAX_LEN,item->id,item),_cfg_path) -+#define cfg_def_get_path(item) (_cfg_def_make_path(_cfg_path,CFG_PATH_MAX_LEN,item->id,item, 0),_cfg_path) -+#define cfg_def_get_path_xlated(item) (_cfg_def_make_path(_cfg_path,CFG_PATH_MAX_LEN,item->id,item, 1),_cfg_path) - --static int _cfg_def_make_path(char *buf, size_t buf_size, int id, cfg_def_item_t *item) -+static int _cfg_def_make_path(char *buf, size_t buf_size, int id, cfg_def_item_t *item, int xlate) - { -+ int variable = item->flags & CFG_NAME_VARIABLE; - int parent_id = item->parent; - int count, n; - - if (id == parent_id) - return 0; - -- count = _cfg_def_make_path(buf, buf_size, parent_id, cfg_def_get_item_p(parent_id)); -- if ((n = dm_snprintf(buf + count, buf_size - count, "%s%s", -+ count = _cfg_def_make_path(buf, buf_size, parent_id, cfg_def_get_item_p(parent_id), xlate); -+ if ((n = dm_snprintf(buf + count, buf_size - count, "%s%s%s%s", - count ? "/" : "", -- item->flags & CFG_NAME_VARIABLE ? "#" : item->name)) < 0) { -+ xlate && variable ? "<" : "", -+ !xlate && variable ? "#" : item->name, -+ xlate && variable ? ">" : "")) < 0) { - log_error(INTERNAL_ERROR "_cfg_def_make_path: supplied buffer too small for %s/%s", - cfg_def_get_item_p(parent_id)->name, item->name); - buf[0] = '\0'; -@@ -502,7 +506,7 @@ static int _cfg_def_make_path(char *buf, size_t buf_size, int id, cfg_def_item_t - - int config_def_get_path(char *buf, size_t buf_size, int id) - { -- return _cfg_def_make_path(buf, buf_size, id, cfg_def_get_item_p(id)); -+ return _cfg_def_make_path(buf, buf_size, id, cfg_def_get_item_p(id), 0); - } - - static void _get_type_name(char *buf, size_t buf_size, cfg_def_type_t type) -@@ -1086,8 +1090,7 @@ int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft, - - struct out_baton { - FILE *fp; -- int withcomment; -- int withversion; -+ struct config_def_tree_spec *tree_spec; - }; - - static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, void *baton) -@@ -1108,8 +1111,8 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi - - cfg_def = cfg_def_get_item_p(cn->id); - -- if (out->withcomment) { -- path = cfg_def_get_path(cfg_def); -+ if (out->tree_spec->withcomments) { -+ path = cfg_def_get_path_xlated(cfg_def); - fprintf(out->fp, "%s# Configuration %s %s.\n", line, node_type_name, path); - - if (cfg_def->comment) -@@ -1120,9 +1123,15 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi - - if (cfg_def->flags & CFG_UNSUPPORTED) - fprintf(out->fp, "%s# This configuration %s is not officially supported.\n", line, node_type_name); -+ -+ if (cfg_def->flags & CFG_NAME_VARIABLE) -+ fprintf(out->fp, "%s# This configuration %s has variable name.\n", line, node_type_name); -+ -+ if (cfg_def->flags & CFG_DEFAULT_UNDEFINED) -+ fprintf(out->fp, "%s# This configuration %s does not have a default value defined.\n", line, node_type_name); - } - -- if (out->withversion) { -+ if (out->tree_spec->withversions) { - if (dm_snprintf(version, 9, "%u.%u.%u", - (cfg_def->since_version & 0xE000) >> 13, - (cfg_def->since_version & 0x1E00) >> 9, -@@ -1139,7 +1148,10 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi - static int _out_line_fn(const struct dm_config_node *cn, const char *line, void *baton) - { - struct out_baton *out = baton; -- fprintf(out->fp, "%s\n", line); -+ struct cfg_def_item *cfg_def = cfg_def_get_item_p(cn->id); -+ -+ fprintf(out->fp, "%s%s\n", (out->tree_spec->type != CFG_DEF_TREE_CURRENT) && -+ (cfg_def->flags & CFG_DEFAULT_UNDEFINED) ? "#" : "", line); - return 1; - } - -@@ -1149,7 +1161,7 @@ static int _out_suffix_fn(const struct dm_config_node *cn, const char *line, voi - } - - int config_write(struct dm_config_tree *cft, -- int withcomment, int withversion, -+ struct config_def_tree_spec *tree_spec, - const char *file, int argc, char **argv) - { - static const struct dm_config_node_out_spec _out_spec = { -@@ -1159,8 +1171,7 @@ int config_write(struct dm_config_tree *cft, - }; - const struct dm_config_node *cn; - struct out_baton baton = { -- .withcomment = withcomment, -- .withversion = withversion -+ .tree_spec = tree_spec - }; - int r = 1; - -diff --git a/lib/config/config.h b/lib/config/config.h -index 0769c40..f716efb 100644 ---- a/lib/config/config.h -+++ b/lib/config/config.h -@@ -82,6 +82,8 @@ typedef union { - #define CFG_UNSUPPORTED 0x08 - /* whether the configuration item is customizable by a profile */ - #define CFG_PROFILABLE 0x10 -+/* whether the default value is undefned */ -+#define CFG_DEFAULT_UNDEFINED 0x20 - - /* configuration definition item structure */ - typedef struct cfg_def_item { -@@ -109,8 +111,10 @@ typedef enum { - struct config_def_tree_spec { - cfg_def_tree_t type; /* tree type */ - uint16_t version; /* tree at this LVM2 version */ -- int ignoreadvanced; /* do not include advanced configs */ -- int ignoreunsupported; /* do not include unsupported configs */ -+ int ignoreadvanced:1; /* do not include advanced configs */ -+ int ignoreunsupported:1; /* do not include unsupported configs */ -+ int withcomments:1; /* include comments */ -+ int withversions:1; /* include versions */ - uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */ - }; - -@@ -163,8 +167,7 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, - checksum_fn_t checksum_fn, uint32_t checksum); - int config_file_read(struct dm_config_tree *cft); - struct dm_config_tree *config_file_open_and_read(const char *config_file, config_source_t source); --int config_write(struct dm_config_tree *cft, -- int withcomment, int withversion, -+int config_write(struct dm_config_tree *cft, struct config_def_tree_spec *tree_spec, - const char *file, int argc, char **argv); - struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec); - void config_destroy(struct dm_config_tree *cft); -diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h -index 06cff7e..2c0dff2 100644 ---- a/lib/config/config_settings.h -+++ b/lib/config/config_settings.h -@@ -32,6 +32,7 @@ - * CFG_ADVANCED - this node belongs to advanced config set - * CFG_UNSUPPORTED - this node belongs to unsupported config set - * CFG_PROFILABLE - this node is customizable by a profile -+ * CFG_DEFAULT_UNDEFINED - node's default value is undefined - * type: allowed type for the value of simple configuation setting, one of: - * CFG_TYPE_BOOL - * CFG_TYPE_INT -@@ -77,16 +78,16 @@ cfg(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, 0, CFG_TYPE_STRIN - - cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_DEV_DIR, vsn(1, 0, 0), NULL) - cfg_array(devices_scan_CFG, "scan", devices_CFG_SECTION, 0, CFG_TYPE_STRING, "#S/dev", vsn(1, 0, 0), NULL) --cfg_array(devices_loopfiles_CFG, "loopfiles", devices_CFG_SECTION, 0, CFG_TYPE_STRING, NULL, vsn(1, 2, 0), NULL) -+cfg_array(devices_loopfiles_CFG, "loopfiles", devices_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 2, 0), NULL) - cfg(devices_obtain_device_list_from_udev_CFG, "obtain_device_list_from_udev", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV, vsn(2, 2, 85), NULL) --cfg_array(devices_preferred_names_CFG, "preferred_names", devices_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, NULL, vsn(1, 2, 19), NULL) --cfg_array(devices_filter_CFG, "filter", devices_CFG_SECTION, 0, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL) --cfg_array(devices_global_filter_CFG, "global_filter", devices_CFG_SECTION, 0, CFG_TYPE_STRING, NULL, vsn(2, 2, 98), NULL) -+cfg_array(devices_preferred_names_CFG, "preferred_names", devices_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 2, 19), NULL) -+cfg_array(devices_filter_CFG, "filter", devices_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL) -+cfg_array(devices_global_filter_CFG, "global_filter", devices_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 98), NULL) - cfg(devices_cache_CFG, "cache", devices_CFG_SECTION, 0, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL) - cfg(devices_cache_dir_CFG, "cache_dir", devices_CFG_SECTION, 0, CFG_TYPE_STRING, NULL, vsn(1, 2, 19), NULL) - cfg(devices_cache_file_prefix_CFG, "cache_file_prefix", devices_CFG_SECTION, 0, CFG_TYPE_STRING, NULL, vsn(1, 2, 19), NULL) - cfg(devices_write_cache_state_CFG, "write_cache_state", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(1, 0, 0), NULL) --cfg_array(devices_types_CFG, "types", devices_CFG_SECTION, 0, CFG_TYPE_INT | CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL) -+cfg_array(devices_types_CFG, "types", devices_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT | CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL) - cfg(devices_sysfs_scan_CFG, "sysfs_scan", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SYSFS_SCAN, vsn(1, 0, 8), NULL) - cfg(devices_multipath_component_detection_CFG, "multipath_component_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MULTIPATH_COMPONENT_DETECTION, vsn(2, 2, 89), NULL) - cfg(devices_md_component_detection_CFG, "md_component_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MD_COMPONENT_DETECTION, vsn(1, 0, 18), NULL) -@@ -102,11 +103,15 @@ cfg(devices_require_restorefile_with_uuid_CFG, "require_restorefile_with_uuid", - cfg(devices_pv_min_size_CFG, "pv_min_size", devices_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_PV_MIN_SIZE_KB, vsn(2, 2, 85), NULL) - cfg(devices_issue_discards_CFG, "issue_discards", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ISSUE_DISCARDS, vsn(2, 2, 85), NULL) - --cfg_array(allocation_cling_tag_list_CFG, "cling_tag_list", allocation_CFG_SECTION, 0, CFG_TYPE_STRING, NULL, vsn(2, 2, 77), NULL) -+cfg_array(allocation_cling_tag_list_CFG, "cling_tag_list", allocation_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 77), NULL) - cfg(allocation_maximise_cling_CFG, "maximise_cling", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MAXIMISE_CLING, vsn(2, 2, 85), NULL) - cfg(allocation_use_blkid_wiping_CFG, "use_blkid_wiping", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 105), NULL) - cfg(allocation_wipe_signatures_when_zeroing_new_lvs_CFG, "wipe_signatures_when_zeroing_new_lvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 105), NULL) - cfg(allocation_mirror_logs_require_separate_pvs_CFG, "mirror_logs_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MIRROR_LOGS_REQUIRE_SEPARATE_PVS, vsn(2, 2, 85), NULL) -+ -+cfg(allocation_cache_pool_metadata_require_separate_pvs_CFG, "cache_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 106), NULL) -+cfg(allocation_cache_pool_chunk_size_CFG, "cache_pool_chunk_size", allocation_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(2, 2, 106), NULL) -+ - cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 89), NULL) - cfg(allocation_thin_pool_zero_CFG, "thin_pool_zero", allocation_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_ZERO, vsn(2, 2, 99), NULL) - cfg(allocation_thin_pool_discards_CFG, "thin_pool_discards", allocation_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_STRING, DEFAULT_THIN_POOL_DISCARDS, vsn(2, 2, 99), NULL) -@@ -144,8 +149,8 @@ cfg(global_activation_CFG, "activation", global_CFG_SECTION, 0, CFG_TYPE_BOOL, D - cfg(global_suffix_CFG, "suffix", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SUFFIX, vsn(1, 0, 0), NULL) - cfg(global_fallback_to_lvm1_CFG, "fallback_to_lvm1", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_LVM1, vsn(1, 0, 18), NULL) - cfg(global_format_CFG, "format", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_FORMAT, vsn(1, 0, 0), NULL) --cfg_array(global_format_libraries_CFG, "format_libraries", global_CFG_SECTION, 0, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL) --cfg_array(global_segment_libraries_CFG, "segment_libraries", global_CFG_SECTION, 0, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL) -+cfg_array(global_format_libraries_CFG, "format_libraries", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL) -+cfg_array(global_segment_libraries_CFG, "segment_libraries", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL) - cfg(global_proc_CFG, "proc", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_PROC_DIR, vsn(1, 0, 0), NULL) - cfg(global_locking_type_CFG, "locking_type", global_CFG_SECTION, 0, CFG_TYPE_INT, 1, vsn(1, 0, 0), NULL) - cfg(global_wait_for_locks_CFG, "wait_for_locks", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_WAIT_FOR_LOCKS, vsn(2, 2, 50), NULL) -@@ -179,9 +184,9 @@ cfg(activation_use_linear_target_CFG, "use_linear_target", activation_CFG_SECTIO - cfg(activation_reserved_stack_CFG, "reserved_stack", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RESERVED_STACK, vsn(1, 0, 0), NULL) - cfg(activation_reserved_memory_CFG, "reserved_memory", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RESERVED_MEMORY, vsn(1, 0, 0), NULL) - cfg(activation_process_priority_CFG, "process_priority", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_PROCESS_PRIORITY, vsn(1, 0, 0), NULL) --cfg_array(activation_volume_list_CFG, "volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL) --cfg_array(activation_auto_activation_volume_list_CFG, "auto_activation_volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, NULL, vsn(2, 2, 97), NULL) --cfg_array(activation_read_only_volume_list_CFG, "read_only_volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, NULL, vsn(2, 2, 89), NULL) -+cfg_array(activation_volume_list_CFG, "volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY|CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL) -+cfg_array(activation_auto_activation_volume_list_CFG, "auto_activation_volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 97), NULL) -+cfg_array(activation_read_only_volume_list_CFG, "read_only_volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 89), NULL) - cfg(activation_mirror_region_size_CFG, "mirror_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(1, 0, 0), NULL) - cfg(activation_raid_region_size_CFG, "raid_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(2, 2, 99), NULL) - cfg(activation_readahead_CFG, "readahead", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_READ_AHEAD, vsn(1, 0, 23), NULL) -@@ -193,7 +198,7 @@ cfg(activation_snapshot_autoextend_threshold_CFG, "snapshot_autoextend_threshold - cfg(activation_snapshot_autoextend_percent_CFG, "snapshot_autoextend_percent", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT, vsn(2, 2, 75), NULL) - cfg(activation_thin_pool_autoextend_threshold_CFG, "thin_pool_autoextend_threshold", activation_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_INT, DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD, vsn(2, 2, 89), NULL) - cfg(activation_thin_pool_autoextend_percent_CFG, "thin_pool_autoextend_percent", activation_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_INT, DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT, vsn(2, 2, 89), NULL) --cfg_array(activation_mlock_filter_CFG, "mlock_filter", activation_CFG_SECTION, 0, CFG_TYPE_STRING, NULL, vsn(2, 2, 62), NULL) -+cfg_array(activation_mlock_filter_CFG, "mlock_filter", activation_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 62), NULL) - cfg(activation_use_mlockall_CFG, "use_mlockall", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_MLOCKALL, vsn(2, 2, 62), NULL) - cfg(activation_monitoring_CFG, "monitoring", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_DMEVENTD_MONITOR, vsn(2, 2, 63), NULL) - cfg(activation_polling_interval_CFG, "polling_interval", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_INTERVAL, vsn(2, 2, 63), NULL) -@@ -204,13 +209,13 @@ cfg(metadata_vgmetadatacopies_CFG, "vgmetadatacopies", metadata_CFG_SECTION, CFG - cfg(metadata_pvmetadatasize_CFG, "pvmetadatasize", metadata_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_INT, DEFAULT_PVMETADATASIZE, vsn(1, 0, 0), NULL) - cfg(metadata_pvmetadataignore_CFG, "pvmetadataignore", metadata_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_BOOL, DEFAULT_PVMETADATAIGNORE, vsn(2, 2, 69), NULL) - cfg(metadata_stripesize_CFG, "stripesize", metadata_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_INT, DEFAULT_STRIPESIZE, vsn(1, 0, 0), NULL) --cfg_array(metadata_dirs_CFG, "dirs", metadata_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL) -+cfg_array(metadata_dirs_CFG, "dirs", metadata_CFG_SECTION, CFG_ADVANCED | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL) - --cfg_section(metadata_disk_areas_CFG_SUBSECTION, "disk_areas", metadata_CFG_SECTION, CFG_ADVANCED | CFG_UNSUPPORTED, vsn(1, 0, 0), NULL) --cfg_section(disk_area_CFG_SUBSECTION, "disk_area", metadata_disk_areas_CFG_SUBSECTION, CFG_NAME_VARIABLE | CFG_ADVANCED | CFG_UNSUPPORTED, vsn(1, 0, 0), NULL) --cfg(disk_area_start_sector_CFG, "start_sector", disk_area_CFG_SUBSECTION, CFG_ADVANCED | CFG_UNSUPPORTED, CFG_TYPE_INT, 0, vsn(1, 0, 0), NULL) --cfg(disk_area_size_CFG, "size", disk_area_CFG_SUBSECTION, CFG_ADVANCED | CFG_UNSUPPORTED, CFG_TYPE_INT, 0, vsn(1, 0, 0), NULL) --cfg(disk_area_id_CFG, "id", disk_area_CFG_SUBSECTION, CFG_ADVANCED | CFG_UNSUPPORTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL) -+cfg_section(metadata_disk_areas_CFG_SUBSECTION, "disk_areas", metadata_CFG_SECTION, CFG_ADVANCED | CFG_UNSUPPORTED | CFG_DEFAULT_UNDEFINED, vsn(1, 0, 0), NULL) -+cfg_section(disk_area_CFG_SUBSECTION, "disk_area", metadata_disk_areas_CFG_SUBSECTION, CFG_NAME_VARIABLE | CFG_ADVANCED | CFG_UNSUPPORTED | CFG_DEFAULT_UNDEFINED, vsn(1, 0, 0), NULL) -+cfg(disk_area_start_sector_CFG, "start_sector", disk_area_CFG_SUBSECTION, CFG_ADVANCED | CFG_UNSUPPORTED | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, 0, vsn(1, 0, 0), NULL) -+cfg(disk_area_size_CFG, "size", disk_area_CFG_SUBSECTION, CFG_ADVANCED | CFG_UNSUPPORTED | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, 0, vsn(1, 0, 0), NULL) -+cfg(disk_area_id_CFG, "id", disk_area_CFG_SUBSECTION, CFG_ADVANCED | CFG_UNSUPPORTED | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL) - - cfg(report_aligned_CFG, "aligned", report_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_REP_ALIGNED, vsn(1, 0, 0), NULL) - cfg(report_buffered_CFG, "buffered", report_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_REP_BUFFERED, vsn(1, 0, 0), NULL) -@@ -242,11 +247,11 @@ cfg(dmeventd_mirror_library_CFG, "mirror_library", dmeventd_CFG_SECTION, 0, CFG_ - cfg(dmeventd_raid_library_CFG, "raid_library", dmeventd_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_DMEVENTD_RAID_LIB, vsn(2, 2, 87), NULL) - cfg(dmeventd_snapshot_library_CFG, "snapshot_library", dmeventd_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_DMEVENTD_SNAPSHOT_LIB, vsn(1, 2, 26), NULL) - cfg(dmeventd_thin_library_CFG, "thin_library", dmeventd_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_DMEVENTD_THIN_LIB, vsn(2, 2, 89), NULL) --cfg(dmeventd_executable_CFG, "executable", dmeventd_CFG_SECTION, 0, CFG_TYPE_STRING, NULL, vsn(2, 2, 73), NULL) -+cfg(dmeventd_executable_CFG, "executable", dmeventd_CFG_SECTION, 0, CFG_TYPE_STRING, DMEVENTD_PATH, vsn(2, 2, 73), NULL) - - cfg(tags_hosttags_CFG, "hosttags", tags_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_HOSTTAGS, vsn(1, 0, 18), NULL) - --cfg_section(tag_CFG_SUBSECTION, "tag", tags_CFG_SECTION, CFG_NAME_VARIABLE, vsn(1, 0, 18), NULL) --cfg(tag_host_list_CFG, "host_list", tag_CFG_SUBSECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL) -+cfg_section(tag_CFG_SUBSECTION, "tag", tags_CFG_SECTION, CFG_NAME_VARIABLE | CFG_DEFAULT_UNDEFINED, vsn(1, 0, 18), NULL) -+cfg(tag_host_list_CFG, "host_list", tag_CFG_SUBSECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL) - - cfg(CFG_COUNT, NULL, root_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(0, 0, 0), NULL) -diff --git a/lib/config/defaults.h b/lib/config/defaults.h -index 141b7ae..6820def 100644 ---- a/lib/config/defaults.h -+++ b/lib/config/defaults.h -@@ -77,7 +77,12 @@ - #define DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE 512 /* KB */ - #define DEFAULT_THIN_POOL_DISCARDS "passdown" - #define DEFAULT_THIN_POOL_ZERO 1 --#define DEFAULT_POOL_METADATA_SPARE 1 -+#define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */ -+ -+#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0 -+#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */ -+#define DEFAULT_CACHE_POOL_MIN_METADATA_SIZE 2048 /* KB */ -+#define DEFAULT_CACHE_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */ - - #define DEFAULT_UMASK 0077 - -diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c -index 82cc2fc..6697456 100644 ---- a/lib/device/dev-io.c -+++ b/lib/device/dev-io.c -@@ -178,8 +178,8 @@ int dev_get_block_size(struct device *dev, unsigned int *physical_block_size, un - *physical_block_size = (unsigned int) dev->phys_block_size; - *block_size = (unsigned int) dev->block_size; - out: -- if (needs_open) -- dev_close(dev); -+ if (needs_open && !dev_close(dev)) -+ stack; - - return r; - } -diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c -index 02bc99f..1efc447 100644 ---- a/lib/device/dev-type.c -+++ b/lib/device/dev-type.c -@@ -449,25 +449,45 @@ out: - - #ifdef BLKID_WIPING_SUPPORT - -+static inline int _type_in_flag_list(const char *type, uint32_t flag_list) -+{ -+ return (((flag_list & TYPE_LVM2_MEMBER) && !strcmp(type, "LVM2_member")) || -+ ((flag_list & TYPE_LVM1_MEMBER) && !strcmp(type, "LVM1_member")) || -+ ((flag_list & TYPE_DM_SNAPSHOT_COW) && !strcmp(type, "DM_snapshot_cow"))); -+} -+ - static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name, -- int exclude_lvm_member, int yes, force_t force) -+ uint32_t types_to_exclude, uint32_t types_no_prompt, -+ int yes, force_t force) - { -+ static const char _msg_failed_offset[] = "Failed to get offset of the %s signature on %s."; -+ static const char _msg_failed_length[] = "Failed to get length of the %s signature on %s."; -+ static const char _msg_wiping[] = "Wiping %s signature on %s."; - const char *offset = NULL, *type = NULL, *magic = NULL, - *usage = NULL, *label = NULL, *uuid = NULL; - loff_t offset_value; - size_t len; - - if (!blkid_probe_lookup_value(probe, "TYPE", &type, NULL)) { -- if (exclude_lvm_member && -- (!strcmp(type, "LVM1_member") || !strcmp(type, "LVM2_member"))) -+ if (_type_in_flag_list(type, types_to_exclude)) - return 1; -- if (!blkid_probe_lookup_value(probe, "SBMAGIC_OFFSET", &offset, NULL) && -- blkid_probe_lookup_value(probe, "SBMAGIC", &magic, &len)) -- return_0; -+ if (blkid_probe_lookup_value(probe, "SBMAGIC_OFFSET", &offset, NULL)) { -+ log_error(_msg_failed_offset, type, name); -+ return 0; -+ } -+ if (blkid_probe_lookup_value(probe, "SBMAGIC", &magic, &len)) { -+ log_error(_msg_failed_length, type, name); -+ return 0; -+ } - } else if (!blkid_probe_lookup_value(probe, "PTTYPE", &type, NULL)) { -- if (!blkid_probe_lookup_value(probe, "PTMAGIC_OFFSET", &offset, NULL) && -- blkid_probe_lookup_value(probe, "PTMAGIC", &magic, &len)) -- return_0; -+ if (blkid_probe_lookup_value(probe, "PTMAGIC_OFFSET", &offset, NULL)) { -+ log_error(_msg_failed_offset, type, name); -+ return 0; -+ } -+ if (blkid_probe_lookup_value(probe, "PTMAGIC", &magic, &len)) { -+ log_error(_msg_failed_length, type, name); -+ return 0; -+ } - usage = "partition table"; - } else - return_0; -@@ -483,12 +503,15 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name, - "UUID=\"%s\" TYPE=\"%s\" USAGE=\"%s\"", - name, offset, label, uuid, type, usage); - -- if (!yes && (force == PROMPT) && -- yes_no_prompt("WARNING: %s signature detected on %s at offset %s. " -- "Wipe it? [y/n] ", type, name, offset) != 'y') -- return_0; -+ if (!_type_in_flag_list(type, types_no_prompt)) { -+ if (!yes && (force == PROMPT) && -+ yes_no_prompt("WARNING: %s signature detected on %s at offset %s. " -+ "Wipe it? [y/n] ", type, name, offset) != 'y') -+ return_0; -+ log_print_unless_silent(_msg_wiping, type, name); -+ } else -+ log_verbose(_msg_wiping, type, name); - -- log_print_unless_silent("Wiping %s signature on %s.", type, name); - if (!dev_set(dev, offset_value, len, 0)) { - log_error("Failed to wipe %s signature on %s.", type, name); - return 0; -@@ -498,7 +521,8 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name, - } - - static int _wipe_known_signatures_with_blkid(struct device *dev, const char *name, -- int exclude_lvm_member, -+ uint32_t types_to_exclude, -+ uint32_t types_no_prompt, - int yes, force_t force) - { - blkid_probe probe = NULL; -@@ -525,7 +549,7 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam - - while (!blkid_do_probe(probe)) { - found++; -- if (_blkid_wipe(probe, dev, name, exclude_lvm_member, yes, force)) -+ if (_blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force)) - wiped++; - } - -@@ -579,7 +603,8 @@ static int _wipe_signature(struct device *dev, const char *type, const char *nam - } - - static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name, -- int exclude_lvm_member, -+ uint32_t types_to_exclude __attribute__((unused)), -+ uint32_t types_no_prompt __attribute__((unused)), - int yes, force_t force) - { - if (!_wipe_signature(dev, "software RAID md superblock", name, 4, yes, force, dev_is_md) || -@@ -591,16 +616,20 @@ static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name, - } - - int wipe_known_signatures(struct cmd_context *cmd, struct device *dev, -- const char *name, int exclude_lvm_member, -- int yes, force_t force) -+ const char *name, uint32_t types_to_exclude, -+ uint32_t types_no_prompt, int yes, force_t force) - { - #ifdef BLKID_WIPING_SUPPORT - if (find_config_tree_bool(cmd, allocation_use_blkid_wiping_CFG, NULL)) - return _wipe_known_signatures_with_blkid(dev, name, -- exclude_lvm_member, yes, force); -+ types_to_exclude, -+ types_no_prompt, -+ yes, force); - #endif - return _wipe_known_signatures_with_lvm(dev, name, -- exclude_lvm_member, yes, force); -+ types_to_exclude, -+ types_no_prompt, -+ yes, force); - } - - #ifdef __linux__ -diff --git a/lib/device/dev-type.h b/lib/device/dev-type.h -index 284280e..b1520ee 100644 ---- a/lib/device/dev-type.h -+++ b/lib/device/dev-type.h -@@ -60,8 +60,12 @@ int dev_is_swap(struct device *dev, uint64_t *signature); - int dev_is_luks(struct device *dev, uint64_t *signature); - - /* Signature wiping. */ -+#define TYPE_LVM1_MEMBER 0x001 -+#define TYPE_LVM2_MEMBER 0x002 -+#define TYPE_DM_SNAPSHOT_COW 0x004 - int wipe_known_signatures(struct cmd_context *cmd, struct device *dev, const char *name, -- int exclude_lvm_member, int yes, force_t force); -+ uint32_t types_to_exclude, uint32_t types_no_prompt, -+ int yes, force_t force); - - /* Type-specific device properties */ - unsigned long dev_md_stripe_width(struct dev_types *dt, struct device *dev); -diff --git a/lib/device/device-types.h b/lib/device/device-types.h -index d716878..463f847 100644 ---- a/lib/device/device-types.h -+++ b/lib/device/device-types.h -@@ -28,11 +28,13 @@ typedef struct { - * The list can be supplemented with devices/types in the config file. - */ - static const dev_known_type_t _dev_known_types[] = { -- {"ide", 64, "IDE disk"}, - {"sd", 16, "SCSI disk"}, -+ {"ide", 64, "IDE disk"}, - {"md", 1, "Multiple Disk (MD/SoftRAID)"}, -- {"mdp", 1, "Partitionable MD"}, - {"loop", 1, "Loop device"}, -+ {"ramdisk", 1, "RAM disk"}, -+ {"device-mapper", 1, "Mapped device"}, -+ {"mdp", 1, "Partitionable MD"}, - {"dasd", 4, "DASD disk (IBM S/390, zSeries)"}, - {"dac960", 8, "DAC960"}, - {"nbd", 16, "Network Block Device"}, -@@ -46,9 +48,7 @@ static const dev_known_type_t _dev_known_types[] = { - {"i2o_block", 16, "i2o Block Disk"}, - {"iseries/vd", 8, "iSeries disks"}, - {"gnbd", 1, "Network block device"}, -- {"ramdisk", 1, "RAM disk"}, - {"aoe", 16, "ATA over Ethernet"}, -- {"device-mapper", 1, "Mapped device"}, - {"xvd", 16, "Xen virtual block device"}, - {"vdisk", 8, "SUN's LDOM virtual block device"}, - {"ps3disk", 16, "PlayStation 3 internal disk"}, -@@ -62,5 +62,6 @@ static const dev_known_type_t _dev_known_types[] = { - {"scm", 8, "Storage Class Memory (IBM S/390)"}, - {"bcache", 1, "bcache block device cache"}, - {"nvme", 64, "NVM Express"}, -+ {"zvol", 16, "ZFS Zvols"}, - {"", 0, ""} - }; -diff --git a/lib/display/display.c b/lib/display/display.c -index 1babffc..66acb88 100644 ---- a/lib/display/display.c -+++ b/lib/display/display.c -@@ -182,6 +182,13 @@ alloc_policy_t get_alloc_from_string(const char *str) - return ALLOC_INVALID; - } - -+static const char *_percent_types[7] = { "NONE", "VGS", "FREE", "LVS", "PVS", "ORIGIN" }; -+ -+const char *get_percent_string(percent_type_t def) -+{ -+ return _percent_types[def]; -+} -+ - #define BASE_UNKNOWN 0 - #define BASE_SHARED 1 - #define BASE_1024 8 -@@ -921,6 +928,15 @@ void display_segtypes(const struct cmd_context *cmd) - } - } - -+void display_tags(const struct cmd_context *cmd) -+{ -+ const struct str_list *sl; -+ -+ dm_list_iterate_items(sl, &cmd->tags) { -+ log_print("%s", sl->str); -+ } -+} -+ - void display_name_error(name_error_t name_error) - { - if (name_error != NAME_VALID) { -diff --git a/lib/display/display.h b/lib/display/display.h -index 077fff4..41fba03 100644 ---- a/lib/display/display.h -+++ b/lib/display/display.h -@@ -53,6 +53,7 @@ void vgdisplay_short(const struct volume_group *vg); - - void display_formats(const struct cmd_context *cmd); - void display_segtypes(const struct cmd_context *cmd); -+void display_tags(const struct cmd_context *cmd); - - void display_name_error(name_error_t name_error); - -@@ -63,6 +64,8 @@ const char *get_alloc_string(alloc_policy_t alloc); - char alloc_policy_char(alloc_policy_t alloc); - alloc_policy_t get_alloc_from_string(const char *str); - -+const char *get_percent_string(percent_type_t def); -+ - char yes_no_prompt(const char *prompt, ...) __attribute__ ((format(printf, 1, 2))); - - #endif -diff --git a/lib/format_text/export.c b/lib/format_text/export.c -index 73030e4..883e076 100644 ---- a/lib/format_text/export.c -+++ b/lib/format_text/export.c -@@ -367,12 +367,12 @@ static int _print_flag_config(struct formatter *f, uint64_t status, int type) - } - - --static int _out_tags(struct formatter *f, struct dm_list *tags) -+static int _out_tags(struct formatter *f, struct dm_list *tagsl) - { - char *tag_buffer; - -- if (!dm_list_empty(tags)) { -- if (!(tag_buffer = alloc_printed_tags(tags))) -+ if (!dm_list_empty(tagsl)) { -+ if (!(tag_buffer = alloc_printed_tags(tagsl))) - return_0; - if (!out_text(f, "tags = %s", tag_buffer)) { - dm_free(tag_buffer); -diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c -index e31429e..bc48952 100644 ---- a/lib/format_text/flags.c -+++ b/lib/format_text/flags.c -@@ -83,6 +83,10 @@ static const struct flag _lv_flags[] = { - {THIN_POOL, NULL, 0}, - {THIN_POOL_DATA, NULL, 0}, - {THIN_POOL_METADATA, NULL, 0}, -+ {CACHE, NULL, 0}, -+ {CACHE_POOL, NULL, 0}, -+ {CACHE_POOL_DATA, NULL, 0}, -+ {CACHE_POOL_METADATA, NULL, 0}, - {0, NULL, 0} - }; - -diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c -index 6e309a3..b4f96f8 100644 ---- a/lib/format_text/format-text.c -+++ b/lib/format_text/format-text.c -@@ -29,6 +29,7 @@ - #include "label.h" - #include "lvmcache.h" - #include "lvmetad.h" -+#include "memlock.h" - - #include - #include -@@ -1912,8 +1913,19 @@ static int _create_vg_text_instance(struct format_instance *fid, - } - - if (type & FMT_INSTANCE_MDAS) { -- /* Scan PVs in VG for any further MDAs */ -- lvmcache_label_scan(fid->fmt->cmd, 0); -+ /* -+ * TODO in theory, this function should be never reached -+ * while in critical_section(), because lvmcache's -+ * cached_vg should be valid. However, this assumption -+ * sometimes fails (possibly due to inconsistent -+ * (precommit) metadata and/or missing devices), and -+ * calling lvmcache_label_scan inside the critical -+ * section may be fatal (i.e. deadlock). -+ */ -+ if (!critical_section()) -+ /* Scan PVs in VG for any further MDAs */ -+ lvmcache_label_scan(fid->fmt->cmd, 0); -+ - if (!(vginfo = lvmcache_vginfo_from_vgname(vg_name, vg_id))) - goto_out; - if (!lvmcache_fid_add_mdas_vg(vginfo, fid)) -diff --git a/lib/format_text/tags.c b/lib/format_text/tags.c -index b0f0732..d0bf2b1 100644 ---- a/lib/format_text/tags.c -+++ b/lib/format_text/tags.c -@@ -19,14 +19,14 @@ - #include "str_list.h" - #include "lvm-string.h" - --char *alloc_printed_tags(struct dm_list *tags) -+char *alloc_printed_tags(struct dm_list *tagsl) - { - struct str_list *sl; - int first = 1; - size_t size = 0; - char *buffer, *buf; - -- dm_list_iterate_items(sl, tags) -+ dm_list_iterate_items(sl, tagsl) - /* '"' + tag + '"' + ',' + ' ' */ - size += strlen(sl->str) + 4; - /* '[' + ']' + '\0' */ -@@ -40,7 +40,7 @@ char *alloc_printed_tags(struct dm_list *tags) - if (!emit_to_buffer(&buf, &size, "[")) - goto_bad; - -- dm_list_iterate_items(sl, tags) { -+ dm_list_iterate_items(sl, tagsl) { - if (!first) { - if (!emit_to_buffer(&buf, &size, ", ")) - goto_bad; -@@ -61,7 +61,7 @@ bad: - return_NULL; - } - --int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct dm_config_value *cv) -+int read_tags(struct dm_pool *mem, struct dm_list *tagsl, const struct dm_config_value *cv) - { - if (cv->type == DM_CFG_EMPTY_ARRAY) - return 1; -@@ -72,7 +72,7 @@ int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct dm_config_ - return 0; - } - -- if (!str_list_add(mem, tags, dm_pool_strdup(mem, cv->v.str))) -+ if (!str_list_add(mem, tagsl, dm_pool_strdup(mem, cv->v.str))) - return_0; - - cv = cv->next; -diff --git a/lib/label/label.c b/lib/label/label.c -index 25e5f2c..703fef7 100644 ---- a/lib/label/label.c -+++ b/lib/label/label.c -@@ -19,7 +19,6 @@ - #include "xlate.h" - #include "lvmcache.h" - #include "lvmetad.h" --#include "metadata.h" - - #include - #include -diff --git a/lib/locking/file_locking.c b/lib/locking/file_locking.c -index 1fa23b3..fb84c5b 100644 ---- a/lib/locking/file_locking.c -+++ b/lib/locking/file_locking.c -@@ -1,6 +1,6 @@ - /* - * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. -- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved. - * - * This file is part of LVM2. - * -@@ -44,6 +44,15 @@ static sig_t _oldhandler; - static sigset_t _fullsigset, _intsigset; - static volatile sig_atomic_t _handler_installed; - -+/* Drop lock known to be shared with another file descriptor. */ -+static void _drop_shared_flock(const char *file, int fd) -+{ -+ log_debug_locking("_drop_shared_flock %s.", file); -+ -+ if (close(fd) < 0) -+ log_sys_debug("close", file); -+} -+ - static void _undo_flock(const char *file, int fd) - { - struct stat buf1, buf2; -@@ -74,9 +83,9 @@ static int _release_lock(const char *file, int unlock) - log_very_verbose("Unlocking %s", ll->res); - if (flock(ll->lf, LOCK_NB | LOCK_UN)) - log_sys_debug("flock", ll->res); -- } -- -- _undo_flock(ll->res, ll->lf); -+ _undo_flock(ll->res, ll->lf); -+ } else -+ _drop_shared_flock(ll->res, ll->lf); - - dm_free(ll->res); - dm_free(llh); -diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c -new file mode 100644 -index 0000000..673d90e ---- /dev/null -+++ b/lib/metadata/cache_manip.c -@@ -0,0 +1,278 @@ -+/* -+ * Copyright (C) 2014 Red Hat, Inc. All rights reserved. -+ * -+ * This file is part of LVM2. -+ * -+ * This copyrighted material is made available to anyone wishing to use, -+ * modify, copy, or redistribute it subject to the terms and conditions -+ * of the GNU Lesser General Public License v.2.1. -+ * -+ * You should have received a copy of the GNU Lesser General Public License -+ * along with this program; if not, write to the Free Software Foundation, -+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include "lib.h" -+#include "metadata.h" -+#include "locking.h" -+#include "pv_map.h" -+#include "lvm-string.h" -+#include "toolcontext.h" -+#include "lv_alloc.h" -+#include "pv_alloc.h" -+#include "display.h" -+#include "segtype.h" -+#include "archiver.h" -+#include "activate.h" -+#include "str_list.h" -+#include "defaults.h" -+#include "lvm-exec.h" -+ -+int update_cache_pool_params(struct volume_group *vg, unsigned attr, -+ int passed_args, -+ uint32_t data_extents, uint32_t extent_size, -+ int *chunk_size_calc_method, uint32_t *chunk_size, -+ thin_discards_t *discards, -+ uint64_t *pool_metadata_size, int *zero) -+{ -+ uint64_t min_meta_size; -+ -+ if ((*chunk_size < DM_CACHE_MIN_DATA_BLOCK_SIZE) || -+ (*chunk_size > DM_CACHE_MAX_DATA_BLOCK_SIZE)) { -+ log_error("Chunk size must be in the range %s to %s.", -+ display_size(vg->cmd, DM_CACHE_MIN_DATA_BLOCK_SIZE), -+ display_size(vg->cmd, DM_CACHE_MAX_DATA_BLOCK_SIZE)); -+ return 0; -+ } -+ -+ if (*chunk_size & (DM_CACHE_MIN_DATA_BLOCK_SIZE - 1)) { -+ log_error("Chunk size must be a multiple of %u sectors.", -+ DM_CACHE_MIN_DATA_BLOCK_SIZE); -+ return 0; -+ } -+ -+ /* -+ * Default meta size is: -+ * (4MiB + (16 Bytes for each chunk-sized block)) -+ * ... plus a good amount of padding (2x) to cover any -+ * policy hint data that may be added in the future. -+ */ -+ min_meta_size = 16 * (data_extents * vg->extent_size); -+ min_meta_size /= *chunk_size; /* # of Bytes we need */ -+ min_meta_size *= 2; /* plus some padding */ -+ min_meta_size /= 512; /* in sectors */ -+ min_meta_size += 4*1024*2; /* plus 4MiB */ -+ -+ if (!*pool_metadata_size) -+ *pool_metadata_size = min_meta_size; -+ -+ if (*pool_metadata_size < min_meta_size) { -+ *pool_metadata_size = min_meta_size; -+ log_print("Increasing metadata device size to %" -+ PRIu64 " sectors", *pool_metadata_size); -+ } -+ if (*pool_metadata_size > (2 * DEFAULT_CACHE_POOL_MAX_METADATA_SIZE)) { -+ *pool_metadata_size = 2 * DEFAULT_CACHE_POOL_MAX_METADATA_SIZE; -+ log_print("Reducing metadata device size to %" PRIu64 " sectors", -+ *pool_metadata_size); -+ } -+ -+ return 1; -+} -+ -+/* -+ * lv_cache_create -+ * @pool -+ * @origin -+ * -+ * Given a cache_pool and an origin, link the two and create a -+ * cached LV. -+ * -+ * Returns: cache LV on success, NULL on failure -+ */ -+struct logical_volume *lv_cache_create(struct logical_volume *pool, -+ struct logical_volume *origin) -+{ -+ const struct segment_type *segtype; -+ struct cmd_context *cmd = pool->vg->cmd; -+ struct logical_volume *cache_lv; -+ struct lv_segment *seg; -+ -+ if (!lv_is_cache_pool(pool)) { -+ log_error(INTERNAL_ERROR -+ "%s is not a cache_pool LV", pool->name); -+ return NULL; -+ } -+ -+ if (!dm_list_empty(&pool->segs_using_this_lv)) { -+ seg = get_only_segment_using_this_lv(pool); -+ log_error("%s is already in use by %s", -+ pool->name, seg ? seg->lv->name : "another LV"); -+ return NULL; -+ } -+ -+ if (lv_is_cache_type(origin)) { -+ /* -+ * FIXME: We can layer caches, insert_layer_for_lv() would -+ * have to do a better job renaming the LVs in the stack -+ * first so that there isn't a name collision with _corig. -+ * The origin under the origin would become *_corig_corig -+ * before renaming the origin above to *_corig. -+ */ -+ log_error(INTERNAL_ERROR -+ "The origin, %s, cannot be of cache type", -+ origin->name); -+ return NULL; -+ } -+ -+ if (!(segtype = get_segtype_from_string(cmd, "cache"))) -+ return_NULL; -+ -+ cache_lv = origin; -+ if (!(origin = insert_layer_for_lv(cmd, cache_lv, CACHE, "_corig"))) -+ return_NULL; -+ -+ seg = first_seg(cache_lv); -+ seg->segtype = segtype; -+ -+ if (!attach_pool_lv(seg, pool, NULL, NULL)) -+ return_NULL; -+ -+ return cache_lv; -+} -+ -+/* -+ * lv_cache_remove -+ * @cache_lv -+ * -+ * Given a cache LV, remove the cache layer. This will unlink -+ * the origin and cache_pool, remove the cache LV layer, and promote -+ * the origin to a usable non-cached LV of the same name as the -+ * given cache_lv. -+ * -+ * Returns: 1 on success, 0 on failure -+ */ -+int lv_cache_remove(struct logical_volume *cache_lv) -+{ -+ struct cmd_context *cmd = cache_lv->vg->cmd; -+ char *policy_name; -+ uint64_t dirty_blocks; -+ struct segment_type *segtype; -+ struct lv_segment *cache_seg = first_seg(cache_lv); -+ struct logical_volume *origin_lv; -+ struct logical_volume *cache_pool_lv; -+ -+ if (!lv_is_cache(cache_lv)) -+ return_0; -+ -+ /* -+ * FIXME: -+ * Before the link can be broken, we must ensure that the -+ * cache has been flushed. This may already be the case -+ * if the cache mode is writethrough (or the cleaner -+ * policy is in place from a previous half-finished attempt -+ * to remove the cache_pool). It could take a long time to -+ * flush the cache - it should probably be done in the background. -+ * -+ * Also, if we do perform the flush in the background and we -+ * happen to also be removing the cache/origin LV, then we -+ * could check if the cleaner policy is in place and simply -+ * remove the cache_pool then without waiting for the flush to -+ * complete. -+ */ -+ if (!lv_cache_policy_info(cache_lv, &policy_name, NULL, NULL)) -+ return_0; -+ -+ if (strcmp(policy_name, "cleaner")) { -+ /* We must swap in the cleaner to flush the cache */ -+ log_error("Flushing cache for %s", cache_lv->name); -+ -+ /* -+ * Is there are clean way to free the memory for the name -+ * and argv when changing the policy? -+ */ -+ cache_seg->policy_name = (char *)"cleaner"; -+ cache_seg->policy_argc = 0; -+ cache_seg->policy_argv = NULL; -+ -+ /* update the kernel to put the cleaner policy in place */ -+ if (!vg_write(cache_lv->vg)) -+ return_0; -+ if (!suspend_lv(cmd, cache_lv)) -+ return_0; -+ if (!vg_commit(cache_lv->vg)) -+ return_0; -+ if (!resume_lv(cmd, cache_lv)) -+ return_0; -+ } -+ -+ //FIXME: use polling to do this... -+ do { -+ if (!lv_cache_block_info(cache_lv, NULL, -+ &dirty_blocks, NULL, NULL)) -+ return_0; -+ log_error("%" PRIu64 " blocks must still be flushed.", -+ dirty_blocks); -+ if (dirty_blocks) -+ sleep(5); -+ } while (dirty_blocks); -+ -+ cache_pool_lv = first_seg(cache_lv)->pool_lv; -+ if (!detach_pool_lv(first_seg(cache_lv))) -+ return_0; -+ -+ origin_lv = seg_lv(first_seg(cache_lv), 0); -+ lv_set_visible(origin_lv); -+ -+//FIXME: We should be able to use 'remove_layer_from_lv', but -+// there is a call to 'lv_empty' in there that recursively -+// deletes everything down the tree - including the origin_lv -+// that we are trying to preserve! -+// if (!remove_layer_from_lv(cache_lv, origin_lv)) -+// return_0; -+ -+ if (!remove_seg_from_segs_using_this_lv(origin_lv, first_seg(cache_lv))) -+ return_0; -+ if (!move_lv_segments(cache_lv, origin_lv, 0, 0)) -+ return_0; -+ -+ cache_lv->status &= ~CACHE; -+ -+ segtype = get_segtype_from_string(cmd, "error"); -+ if (!lv_add_virtual_segment(origin_lv, 0, -+ cache_lv->le_count, segtype, NULL)) -+ return_0; -+ -+ if (!vg_write(cache_lv->vg)) -+ return_0; -+ -+ /* -+ * suspend_lv on this cache LV will suspend all of the components: -+ * - the top-level cache LV -+ * - the origin -+ * - the cache_pool and all of its sub-LVs -+ */ -+ if (!suspend_lv(cmd, cache_lv)) -+ return_0; -+ -+ if (!vg_commit(cache_lv->vg)) -+ return_0; -+ -+ /* -+ * resume_lv on this (former) cache LV will resume all -+ * but the cache_pool LV. It must be resumed seperately. -+ */ -+ if (!resume_lv(cmd, cache_lv)) -+ return_0; -+ if (!resume_lv(cmd, cache_pool_lv)) -+ return_0; -+ -+ if (!activate_lv(cmd, origin_lv)) -+ return_0; -+ if (!deactivate_lv(cmd, origin_lv)) -+ return_0; -+ if (!lv_remove(origin_lv)) -+ return_0; -+ -+ return 1; -+} -diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c -index 3e1458c..4549f03 100644 ---- a/lib/metadata/lv.c -+++ b/lib/metadata/lv.c -@@ -170,7 +170,7 @@ uint64_t lvseg_chunksize(const struct lv_segment *seg) - - if (lv_is_cow(seg->lv)) - size = (uint64_t) find_snapshot(seg->lv)->chunk_size; -- else if (seg_is_thin_pool(seg)) -+ else if (seg_is_thin_pool(seg) || seg_is_cache_pool(seg)) - size = (uint64_t) seg->chunk_size; - else - size = UINT64_C(0); -@@ -202,6 +202,9 @@ char *lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv) - if (lv_is_cow(lv)) - return lv_name_dup(mem, origin_from_cow(lv)); - -+ if (lv_is_cache(lv) && first_seg(lv)->origin) -+ return lv_name_dup(mem, first_seg(lv)->origin); -+ - if (lv_is_thin_volume(lv) && first_seg(lv)->origin) - return lv_name_dup(mem, first_seg(lv)->origin); - -@@ -246,7 +249,8 @@ char *lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv) - struct lv_segment *seg; - - dm_list_iterate_items(seg, &lv->segments) -- if (seg_is_thin_volume(seg) && seg->pool_lv) -+ if (seg->pool_lv && -+ (seg_is_thin_volume(seg) || seg_is_cache(seg))) - return dm_pool_strdup(mem, seg->pool_lv->name); - - return NULL; -@@ -254,14 +258,16 @@ char *lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv) - - char *lv_data_lv_dup(struct dm_pool *mem, const struct logical_volume *lv) - { -- struct lv_segment *seg = lv_is_thin_pool(lv) ? first_seg(lv) : NULL; -+ struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ? -+ first_seg(lv) : NULL; - - return seg ? dm_pool_strdup(mem, seg_lv(seg, 0)->name) : NULL; - } - - char *lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv) - { -- struct lv_segment *seg = lv_is_thin_pool(lv) ? first_seg(lv) : NULL; -+ struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ? -+ first_seg(lv) : NULL; - - return seg ? dm_pool_strdup(mem, seg->metadata_lv->name) : NULL; - } -@@ -338,7 +344,8 @@ uint64_t lv_origin_size(const struct logical_volume *lv) - - uint64_t lv_metadata_size(const struct logical_volume *lv) - { -- struct lv_segment *seg = lv_is_thin_pool(lv) ? first_seg(lv) : NULL; -+ struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ? -+ first_seg(lv) : NULL; - - return seg ? seg->metadata_lv->size : 0; - } -@@ -386,10 +393,14 @@ uint64_t lv_size(const struct logical_volume *lv) - static int _lv_mimage_in_sync(const struct logical_volume *lv) - { - percent_t percent; -- struct lv_segment *mirror_seg = find_mirror_seg(first_seg(lv)); -+ struct lv_segment *seg = first_seg(lv); -+ struct lv_segment *mirror_seg; - -- if (!(lv->status & MIRROR_IMAGE) || !mirror_seg) -- return_0; -+ if (!(lv->status & MIRROR_IMAGE) || !seg || -+ !(mirror_seg = find_mirror_seg(seg))) { -+ log_error(INTERNAL_ERROR "Cannot find mirror segment."); -+ return 0; -+ } - - if (!lv_mirror_percent(lv->vg->cmd, mirror_seg->lv, 0, &percent, - NULL)) -@@ -403,7 +414,7 @@ static int _lv_raid_image_in_sync(const struct logical_volume *lv) - unsigned s; - percent_t percent; - char *raid_health; -- struct lv_segment *raid_seg; -+ struct lv_segment *seg, *raid_seg = NULL; - - /* - * If the LV is not active locally, -@@ -417,7 +428,8 @@ static int _lv_raid_image_in_sync(const struct logical_volume *lv) - return 0; - } - -- raid_seg = get_only_segment_using_this_lv(first_seg(lv)->lv); -+ if ((seg = first_seg(lv))) -+ raid_seg = get_only_segment_using_this_lv(seg->lv); - if (!raid_seg) { - log_error("Failed to find RAID segment for %s", lv->name); - return 0; -@@ -465,7 +477,7 @@ static int _lv_raid_healthy(const struct logical_volume *lv) - { - unsigned s; - char *raid_health; -- struct lv_segment *raid_seg; -+ struct lv_segment *seg, *raid_seg = NULL; - - /* - * If the LV is not active locally, -@@ -481,8 +493,8 @@ static int _lv_raid_healthy(const struct logical_volume *lv) - - if (lv->status & RAID) - raid_seg = first_seg(lv); -- else -- raid_seg = get_only_segment_using_this_lv(first_seg(lv)->lv); -+ else if ((seg = first_seg(lv))) -+ raid_seg = get_only_segment_using_this_lv(seg->lv); - - if (!raid_seg) { - log_error("Failed to find RAID segment for %s", lv->name); -@@ -546,6 +558,10 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv) - /* Origin takes precedence over mirror and thin volume */ - else if (lv_is_origin(lv) || lv_is_external_origin(lv)) - repstr[0] = (lv_is_merging_origin(lv)) ? 'O' : 'o'; -+ else if (lv_is_cache_pool_metadata(lv)) -+ repstr[0] = 'e'; -+ else if (lv_is_cache_type(lv)) -+ repstr[0] = 'C'; - else if (lv_is_thin_pool_metadata(lv) || - lv_is_pool_metadata_spare(lv) || - (lv->status & RAID_META)) -@@ -638,6 +654,8 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv) - - if (lv_is_thin_pool(lv) || lv_is_thin_volume(lv)) - repstr[6] = 't'; -+ else if (lv_is_cache_type(lv)) -+ repstr[6] = 'C'; - else if (lv_is_raid_type(lv)) - repstr[6] = 'r'; - else if (lv_is_mirror_type(lv)) -@@ -741,7 +759,8 @@ static int _lv_is_exclusive(struct logical_volume *lv) - /* Some devices require exlusivness */ - return seg_is_raid(first_seg(lv)) || - lv_is_origin(lv) || -- lv_is_thin_type(lv); -+ lv_is_thin_type(lv) || -+ lv_is_cache_type(lv); - } - - int lv_active_change(struct cmd_context *cmd, struct logical_volume *lv, -diff --git a/lib/metadata/lv_alloc.h b/lib/metadata/lv_alloc.h -index acfebca..395420d 100644 ---- a/lib/metadata/lv_alloc.h -+++ b/lib/metadata/lv_alloc.h -@@ -54,7 +54,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg, - uint32_t mirrors, uint32_t log_count, - uint32_t log_region_size, uint32_t extents, - struct dm_list *allocatable_pvs, -- alloc_policy_t alloc, -+ alloc_policy_t alloc, int approx_alloc, - struct dm_list *parallel_areas); - - int lv_add_segment(struct alloc_handle *ah, -diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c -index f45c89f..57ce2d9 100644 ---- a/lib/metadata/lv_manip.c -+++ b/lib/metadata/lv_manip.c -@@ -1,6 +1,6 @@ - /* - * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. -- * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved. - * - * This file is part of LVM2. - * -@@ -346,6 +346,11 @@ struct lv_segment *get_only_segment_using_this_lv(struct logical_volume *lv) - { - struct seg_list *sl; - -+ if (!lv) { -+ log_error(INTERNAL_ERROR "get_only_segment_using_this_lv() called with NULL LV."); -+ return NULL; -+ } -+ - if (dm_list_size(&lv->segs_using_this_lv) != 1) { - log_error("%s is expected to have only one segment using it, " - "while it has %d", lv->name, -@@ -542,6 +547,8 @@ struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv, - static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t s, - uint32_t area_reduction, int with_discard) - { -+ struct lv_segment *cache_seg; -+ - if (seg_type(seg, s) == AREA_UNASSIGNED) - return 1; - -@@ -558,13 +565,24 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t - return 1; - } - -- if ((seg_lv(seg, s)->status & MIRROR_IMAGE) || -- (seg_lv(seg, s)->status & THIN_POOL_DATA)) { -+ if (seg_is_cache(seg) || -+ (seg_lv(seg, s)->status & MIRROR_IMAGE) || -+ (seg_lv(seg, s)->status & THIN_POOL_DATA) || -+ (seg_lv(seg, s)->status & CACHE_POOL_DATA)) { - if (!lv_reduce(seg_lv(seg, s), area_reduction)) - return_0; /* FIXME: any upper level reporting */ - return 1; - } - -+ if (seg_is_cache_pool(seg) && -+ !dm_list_empty(&seg->lv->segs_using_this_lv)) { -+ if (!(cache_seg = get_only_segment_using_this_lv(seg->lv))) -+ return_0; -+ -+ if (!lv_cache_remove(cache_seg->lv)) -+ return_0; -+ } -+ - if (seg_lv(seg, s)->status & RAID_IMAGE) { - /* - * FIXME: Use lv_reduce not lv_remove -@@ -905,6 +923,7 @@ struct alloc_handle { - struct dm_pool *mem; - - alloc_policy_t alloc; /* Overall policy */ -+ int approx_alloc; /* get as much as possible up to new_extents */ - uint32_t new_extents; /* Number of new extents required */ - uint32_t area_count; /* Number of parallel areas */ - uint32_t parity_count; /* Adds to area_count, but not area_multiple */ -@@ -924,8 +943,12 @@ struct alloc_handle { - * that is new_extents + log_len and then split that between two - * allocated areas when found. 'alloc_and_split_meta' indicates - * that this is the desired dynamic. -+ * -+ * This same idea is used by cache LVs to get the metadata device -+ * and data device allocated together. - */ - unsigned alloc_and_split_meta; -+ unsigned split_metadata_is_allocated; /* Metadata has been allocated */ - - const struct dm_config_node *cling_tag_list_cn; - -@@ -1025,7 +1048,7 @@ static uint32_t mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint3 - static struct alloc_handle *_alloc_init(struct cmd_context *cmd, - struct dm_pool *mem, - const struct segment_type *segtype, -- alloc_policy_t alloc, -+ alloc_policy_t alloc, int approx_alloc, - uint32_t new_extents, - uint32_t mirrors, - uint32_t stripes, -@@ -1115,6 +1138,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd, - * a correct area_multiple. - */ - ah->area_multiple = _calc_area_multiple(segtype, area_count + parity_count, stripes); -+ //FIXME: s/mirror_logs_separate/metadata_separate/ so it can be used by otehrs? - ah->mirror_logs_separate = find_config_tree_bool(cmd, allocation_mirror_logs_require_separate_pvs_CFG, NULL); - - if (segtype_is_raid(segtype)) { -@@ -1131,23 +1155,53 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd, - * We need 'log_len' extents for each - * RAID device's metadata_area - */ -- ah->new_extents += (ah->log_len * ah->area_multiple); -+ if (!approx_alloc) -+ ah->new_extents += (ah->log_len * ah->area_multiple); - } else { - ah->log_area_count = 0; - ah->log_len = 0; - } -+ if (approx_alloc) { -+ ah->new_extents = ah->new_extents * ah->area_multiple / (ah->area_count + ah->parity_count); -+ ah->new_extents = (ah->new_extents / ah->area_multiple) * ah->area_multiple; -+ log_debug("Adjusted allocation request to %" PRIu32 " data extents.", ah->new_extents); -+ } - } else if (segtype_is_thin_pool(segtype)) { -- ah->log_area_count = metadata_area_count; -- /* thin_pool uses region_size to pass metadata size in extents */ -+ /* -+ * thin_pool uses ah->region_size to -+ * pass metadata size in extents -+ */ - ah->log_len = ah->region_size; -+ ah->log_area_count = metadata_area_count; - ah->region_size = 0; - ah->mirror_logs_separate = - find_config_tree_bool(cmd, allocation_thin_pool_metadata_require_separate_pvs_CFG, NULL); -+ } else if (segtype_is_cache_pool(segtype)) { -+ /* -+ * Like thin_pool, cache_pool uses ah->region_size to -+ * pass metadata size in extents -+ */ -+ ah->log_len = ah->region_size; -+ /* use metadata_area_count, not log_area_count */ -+ ah->metadata_area_count = metadata_area_count; -+ ah->region_size = 0; -+ ah->mirror_logs_separate = -+ find_config_tree_bool(cmd, allocation_cache_pool_metadata_require_separate_pvs_CFG, NULL); -+ if (!ah->mirror_logs_separate) { -+ ah->alloc_and_split_meta = 1; -+ if (!approx_alloc) -+ ah->new_extents += ah->log_len; -+ } - } else { - ah->log_area_count = metadata_area_count; - ah->log_len = !metadata_area_count ? 0 : - mirror_log_extents(ah->region_size, extent_size, - new_extents / ah->area_multiple); -+ if (approx_alloc) { -+ ah->new_extents = ah->new_extents * ah->area_multiple / ah->area_count; -+ ah->new_extents = (ah->new_extents / ah->area_multiple) * ah->area_multiple; -+ log_debug("Adjusted allocation request to %" PRIu32 " data extents.", ah->new_extents); -+ } - } - - for (s = 0; s < alloc_count; s++) -@@ -1159,6 +1213,8 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd, - - ah->maximise_cling = find_config_tree_bool(cmd, allocation_maximise_cling_CFG, NULL); - -+ ah->approx_alloc = approx_alloc; -+ - return ah; - } - -@@ -1384,7 +1440,7 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t max_to_allocat - if (area_len > alloc_state->areas[s].used) - area_len = alloc_state->areas[s].used; - -- len = (ah->alloc_and_split_meta) ? total_area_count * 2 : total_area_count; -+ len = (ah->alloc_and_split_meta && !ah->split_metadata_is_allocated) ? total_area_count * 2 : total_area_count; - len *= sizeof(*aa); - if (!(aa = dm_pool_alloc(ah->mem, len))) { - log_error("alloced_area allocation failed"); -@@ -1404,7 +1460,7 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t max_to_allocat - } - - pva = alloc_state->areas[s + ix_log_skip].pva; -- if (ah->alloc_and_split_meta) { -+ if (ah->alloc_and_split_meta && !ah->split_metadata_is_allocated) { - /* - * The metadata area goes at the front of the allocated - * space for now, but could easily go at the end (or -@@ -1430,7 +1486,7 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t max_to_allocat - dm_list_add(&ah->alloced_areas[s], &aa[s].list); - s -= ah->area_count + ah->parity_count; - } -- aa[s].len = (ah->alloc_and_split_meta) ? len - ah->log_len : len; -+ aa[s].len = (ah->alloc_and_split_meta && !ah->split_metadata_is_allocated) ? len - ah->log_len : len; - /* Skip empty allocations */ - if (!aa[s].len) - continue; -@@ -1448,7 +1504,8 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t max_to_allocat - } - - /* Only need to alloc metadata from the first batch */ -- ah->alloc_and_split_meta = 0; -+ if (ah->alloc_and_split_meta) -+ ah->split_metadata_is_allocated = 1; - - ah->total_area_len += area_len; - -@@ -1950,33 +2007,40 @@ static void _reset_unreserved(struct dm_list *pvms) - } - - static void _report_needed_allocation_space(struct alloc_handle *ah, -- struct alloc_state *alloc_state) -+ struct alloc_state *alloc_state, -+ struct dm_list *pvms) - { - const char *metadata_type; - uint32_t parallel_areas_count, parallel_area_size; - uint32_t metadata_count, metadata_size; - -- parallel_area_size = (ah->new_extents - alloc_state->allocated) / ah->area_multiple - -- ((ah->alloc_and_split_meta) ? ah->log_len : 0); -+ parallel_area_size = ah->new_extents - alloc_state->allocated; -+ parallel_area_size /= ah->area_multiple; -+ parallel_area_size -= (ah->alloc_and_split_meta && !ah->split_metadata_is_allocated) ? ah->log_len : 0; - - parallel_areas_count = ah->area_count + ah->parity_count; - - metadata_size = ah->log_len; - if (ah->alloc_and_split_meta) { -- metadata_type = "RAID metadata area"; -+ metadata_type = "metadata area"; - metadata_count = parallel_areas_count; -+ if (ah->split_metadata_is_allocated) -+ metadata_size = 0; - } else { - metadata_type = "mirror log"; - metadata_count = alloc_state->log_area_count_still_needed; - } - -- log_debug_alloc("Still need %" PRIu32 " total extents:", -- parallel_area_size * parallel_areas_count + metadata_size * metadata_count); -+ log_debug_alloc("Still need %s%" PRIu32 " total extents from %" PRIu32 " remaining:", -+ ah->approx_alloc ? "up to " : "", -+ parallel_area_size * parallel_areas_count + metadata_size * metadata_count, pv_maps_size(pvms)); - log_debug_alloc(" %" PRIu32 " (%" PRIu32 " data/%" PRIu32 - " parity) parallel areas of %" PRIu32 " extents each", - parallel_areas_count, ah->area_count, ah->parity_count, parallel_area_size); -- log_debug_alloc(" %" PRIu32 " %ss of %" PRIu32 " extents each", -- metadata_count, metadata_type, metadata_size); -+ log_debug_alloc(" %" PRIu32 " %s%s of %" PRIu32 " extents each", -+ metadata_count, metadata_type, -+ (metadata_count == 1) ? "" : "s", -+ metadata_size); - } - /* - * Returns 1 regardless of whether any space was found, except on error. -@@ -2015,7 +2079,7 @@ static int _find_some_parallel_space(struct alloc_handle *ah, const struct alloc - _clear_areas(alloc_state); - _reset_unreserved(pvms); - -- _report_needed_allocation_space(ah, alloc_state); -+ _report_needed_allocation_space(ah, alloc_state, pvms); - - /* ix holds the number of areas found on other PVs */ - do { -@@ -2240,11 +2304,11 @@ static int _find_max_parallel_space_for_one_policy(struct alloc_handle *ah, stru - * data together will be split, we must adjust - * the comparison accordingly. - */ -- if (ah->alloc_and_split_meta) -+ if (ah->alloc_and_split_meta && !ah->split_metadata_is_allocated) - max_tmp -= ah->log_len; - if (max_tmp > (spvs->le + spvs->len) * ah->area_multiple) { - max_to_allocate = (spvs->le + spvs->len) * ah->area_multiple - alloc_state->allocated; -- max_to_allocate += ah->alloc_and_split_meta ? ah->log_len : 0; -+ max_to_allocate += (ah->alloc_and_split_meta && !ah->split_metadata_is_allocated) ? ah->log_len : 0; - } - parallel_pvs = &spvs->pvs; - break; -@@ -2272,7 +2336,7 @@ static int _find_max_parallel_space_for_one_policy(struct alloc_handle *ah, stru - } else if (ah->maximise_cling && alloc_parms->alloc == ALLOC_NORMAL && - !(alloc_parms->flags & A_CLING_TO_ALLOCED)) - alloc_parms->flags |= A_CLING_TO_ALLOCED; -- } while ((alloc_parms->alloc != ALLOC_CONTIGUOUS) && alloc_state->allocated != alloc_parms->extents_still_needed && (alloc_parms->flags & A_CAN_SPLIT)); -+ } while ((alloc_parms->alloc != ALLOC_CONTIGUOUS) && alloc_state->allocated != alloc_parms->extents_still_needed && (alloc_parms->flags & A_CAN_SPLIT) && (!ah->approx_alloc || pv_maps_size(pvms))); - - return 1; - } -@@ -2366,7 +2430,7 @@ static int _allocate(struct alloc_handle *ah, - old_allocated = alloc_state.allocated; - log_debug_alloc("Trying allocation using %s policy.", get_alloc_string(alloc)); - -- if (!_sufficient_pes_free(ah, pvms, alloc_state.allocated, ah->new_extents)) -+ if (!ah->approx_alloc && !_sufficient_pes_free(ah, pvms, alloc_state.allocated, ah->new_extents)) - goto_out; - - _init_alloc_parms(ah, &alloc_parms, alloc, prev_lvseg, -@@ -2376,19 +2440,36 @@ static int _allocate(struct alloc_handle *ah, - if (!_find_max_parallel_space_for_one_policy(ah, &alloc_parms, pvms, &alloc_state)) - goto_out; - -- if ((alloc_state.allocated == ah->new_extents && !alloc_state.log_area_count_still_needed) || -+ if ((alloc_state.allocated == ah->new_extents && -+ !alloc_state.log_area_count_still_needed) || - (!can_split && (alloc_state.allocated != old_allocated))) - break; - } - - if (alloc_state.allocated != ah->new_extents) { -- log_error("Insufficient suitable %sallocatable extents " -- "for logical volume %s: %u more required", -- can_split ? "" : "contiguous ", -- lv ? lv->name : "", -- (ah->new_extents - alloc_state.allocated) * ah->area_count -- / ah->area_multiple); -- goto out; -+ if (!ah->approx_alloc) { -+ log_error("Insufficient suitable %sallocatable extents " -+ "for logical volume %s: %u more required", -+ can_split ? "" : "contiguous ", -+ lv ? lv->name : "", -+ (ah->new_extents - alloc_state.allocated) * -+ ah->area_count / ah->area_multiple); -+ goto out; -+ } -+ if (!alloc_state.allocated) { -+ log_error("Insufficient suitable %sallocatable extents " -+ "found for logical volume %s.", -+ can_split ? "" : "contiguous ", -+ lv ? lv->name : ""); -+ goto out; -+ } -+ log_verbose("Found fewer %sallocatable extents " -+ "for logical volume %s than requested: using %" PRIu32 " extents (reduced by %u).", -+ can_split ? "" : "contiguous ", -+ lv ? lv->name : "", -+ alloc_state.allocated, -+ (ah->new_extents - alloc_state.allocated) * ah->area_count / ah->area_multiple); -+ ah->new_extents = alloc_state.allocated; - } - - if (alloc_state.log_area_count_still_needed) { -@@ -2465,7 +2546,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg, - uint32_t mirrors, uint32_t log_count, - uint32_t region_size, uint32_t extents, - struct dm_list *allocatable_pvs, -- alloc_policy_t alloc, -+ alloc_policy_t alloc, int approx_alloc, - struct dm_list *parallel_areas) - { - struct alloc_handle *ah; -@@ -2495,7 +2576,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg, - alloc = vg->alloc; - - new_extents = (lv ? lv->le_count : 0) + extents; -- if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc, -+ if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc, approx_alloc, - new_extents, mirrors, stripes, log_count, - vg->extent_size, region_size, - parallel_areas))) -@@ -2955,26 +3036,38 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah, - - /* - * Entry point for single-step LV allocation + extension. -+ * Extents is the number of logical extents to append to the LV unless -+ * approx_alloc is set when it is an upper limit for the total number of -+ * extents to use from the VG. -+ * -+ * FIXME The approx_alloc raid/stripe conversion should be performed -+ * before calling this function. - */ - int lv_extend(struct logical_volume *lv, - const struct segment_type *segtype, - uint32_t stripes, uint32_t stripe_size, - uint32_t mirrors, uint32_t region_size, - uint32_t extents, const char *thin_pool_name, -- struct dm_list *allocatable_pvs, alloc_policy_t alloc) -+ struct dm_list *allocatable_pvs, alloc_policy_t alloc, -+ int approx_alloc) - { - int r = 1; - int log_count = 0; - struct alloc_handle *ah; - uint32_t sub_lv_count; - -- log_very_verbose("Extending segment type, %s", segtype->name); -+ log_very_verbose("Adding segment of type %s to LV %s.", segtype->name, lv->name); - - if (segtype_is_virtual(segtype)) - return lv_add_virtual_segment(lv, 0u, extents, segtype, thin_pool_name); - -- if (!lv->le_count && segtype_is_thin_pool(segtype)) { -- /* Thin pool allocation treats its metadata device like a mirror log. */ -+ if (!lv->le_count && -+ (segtype_is_thin_pool(segtype) || -+ segtype_is_cache_pool(segtype))) { -+ /* -+ * Thinpool and cache_pool allocations treat the metadata -+ * device like a mirror log. -+ */ - /* FIXME Allow pool and data on same device with NORMAL */ - /* FIXME Support striped metadata pool */ - log_count = 1; -@@ -2984,13 +3077,19 @@ int lv_extend(struct logical_volume *lv, - - if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, - log_count, region_size, extents, -- allocatable_pvs, alloc, NULL))) -+ allocatable_pvs, alloc, approx_alloc, NULL))) - return_0; - -- if (segtype_is_thin_pool(segtype)) { -+ if (ah->approx_alloc) { -+ extents = ah->new_extents; -+ if (segtype_is_raid(segtype)) -+ extents -= ah->log_len * ah->area_multiple; -+ } -+ -+ if (segtype_is_thin_pool(segtype) || segtype_is_cache_pool(segtype)) { - if (lv->le_count) { - /* lv_resize abstracts properly _tdata */ -- log_error(INTERNAL_ERROR "Cannot lv_extend() the existing thin pool segment."); -+ log_error(INTERNAL_ERROR "Cannot lv_extend() the existing %s segment.", segtype->name); - return 0; - } - if (!(r = create_pool(lv, segtype, ah, stripes, stripe_size))) -@@ -3307,6 +3406,7 @@ int lv_rename(struct cmd_context *cmd, struct logical_volume *lv, - - #define SIZE_BUF 128 - -+/* TODO: unify stripe size validation across source code */ - static int _validate_stripesize(struct cmd_context *cmd, - const struct volume_group *vg, - struct lvresize_params *lp) -@@ -3320,11 +3420,11 @@ static int _validate_stripesize(struct cmd_context *cmd, - - if (!(vg->fid->fmt->features & FMT_SEGMENTS)) - log_warn("Varied stripesize not supported. Ignoring."); -- else if (lp->ac_stripesize_value > (uint64_t) vg->extent_size * 2) { -- log_error("Reducing stripe size %s to maximum, " -- "physical extent size %s", -- display_size(cmd,lp->ac_stripesize_value), -- display_size(cmd, (uint64_t) vg->extent_size)); -+ else if (lp->ac_stripesize_value > vg->extent_size) { -+ log_print_unless_silent("Reducing stripe size %s to maximum, " -+ "physical extent size %s", -+ display_size(cmd, lp->ac_stripesize_value), -+ display_size(cmd, vg->extent_size)); - lp->stripe_size = vg->extent_size; - } else - lp->stripe_size = lp->ac_stripesize_value; -@@ -3469,7 +3569,7 @@ static int _adjust_policy_params(struct cmd_context *cmd, - return_0; - if ((PERCENT_0 < percent && percent <= PERCENT_100) && - (percent > policy_threshold)) { -- if (!pool_can_resize_metadata(lv)) { -+ if (!thin_pool_feature_supported(lv, THIN_FEATURE_METADATA_RESIZE)) { - log_error_once("Online metadata resize for %s/%s is not supported.", - lp->vg_name, lp->lv_name); - return 0; -@@ -3535,7 +3635,7 @@ static int _lvresize_poolmetadata_prepare(struct cmd_context *cmd, - - lp->poolmetadataextents = 0; - -- if (!pool_can_resize_metadata(pool_lv)) { -+ if (!thin_pool_feature_supported(pool_lv, THIN_FEATURE_METADATA_RESIZE)) { - log_error("Support for online metadata resize not detected."); - return 0; - } -@@ -3603,7 +3703,7 @@ static int _lvresize_poolmetadata(struct cmd_context *cmd, struct volume_group * - seg_mirrors, - mseg->region_size, - lp->poolmetadataextents - lv->le_count, NULL, -- pvh, alloc)) -+ pvh, alloc, 0)) - return_0; - - return 1; -@@ -3716,7 +3816,7 @@ static int _lvresize_adjust_extents(struct cmd_context *cmd, struct logical_volu - { - struct volume_group *vg = lv->vg; - uint32_t pv_extent_count; -- uint32_t extents_used; -+ uint32_t extents_used, extents; - uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size; - uint32_t seg_mirrors = 0; - struct lv_segment *seg, *uninitialized_var(mirr_seg); -@@ -3728,24 +3828,24 @@ static int _lvresize_adjust_extents(struct cmd_context *cmd, struct logical_volu - /* If percent options were used, convert them into actual numbers of extents */ - switch (lp->percent) { - case PERCENT_VG: -- lp->extents = percent_of_extents(lp->extents, vg->extent_count, -+ extents = percent_of_extents(lp->extents, vg->extent_count, - (lp->sign != SIGN_MINUS)); - break; - case PERCENT_FREE: -- lp->extents = percent_of_extents(lp->extents, vg->free_count, -+ extents = percent_of_extents(lp->extents, vg->free_count, - (lp->sign != SIGN_MINUS)); - break; - case PERCENT_LV: -- lp->extents = percent_of_extents(lp->extents, lv->le_count, -+ extents = percent_of_extents(lp->extents, lv->le_count, - (lp->sign != SIGN_MINUS)); - break; - case PERCENT_PVS: - if (lp->argc) { - pv_extent_count = pv_list_extents_free(pvh); -- lp->extents = percent_of_extents(lp->extents, pv_extent_count, -+ extents = percent_of_extents(lp->extents, pv_extent_count, - (lp->sign != SIGN_MINUS)); - } else -- lp->extents = percent_of_extents(lp->extents, vg->extent_count, -+ extents = percent_of_extents(lp->extents, vg->extent_count, - (lp->sign != SIGN_MINUS)); - break; - case PERCENT_ORIGIN: -@@ -3753,11 +3853,23 @@ static int _lvresize_adjust_extents(struct cmd_context *cmd, struct logical_volu - log_error("Specified LV does not have an origin LV."); - return 0; - } -- lp->extents = percent_of_extents(lp->extents, origin_from_cow(lv)->le_count, -+ extents = percent_of_extents(lp->extents, origin_from_cow(lv)->le_count, - (lp->sign != SIGN_MINUS)); - break; - case PERCENT_NONE: -+ extents = lp->extents; - break; -+ default: -+ log_error(INTERNAL_ERROR "Unsupported percent type %u.", lp->percent); -+ return 0; -+ } -+ -+ if (lp->percent != PERCENT_NONE) { -+ log_verbose("Converted %" PRIu32 "%%%s into %" PRIu32 " extents.", lp->extents, get_percent_string(lp->percent), extents); -+ lp->extents = extents; -+ if (lp->sign == SIGN_NONE && (lp->percent != PERCENT_LV && lp->percent != PERCENT_ORIGIN)) -+ lp->approx_alloc = 1; -+ /* FIXME Adjust for parallel areas here before processing relative allocations */ - } - - if (lp->sign == SIGN_PLUS) { -@@ -4028,6 +4140,26 @@ static int _lvresize_check_type(struct cmd_context *cmd, const struct logical_vo - } - } - -+ if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv && -+ (lp->resize == LV_EXTEND)) { -+ /* -+ * TODO: currently we do not support extension of already reduced thin volume. -+ * But it might be possible to create combined mapping of some part of -+ * the external origin followed by zero target. -+ */ -+ if (first_seg(lv)->external_lv->size > lv->size) { -+ log_error("Extension of reduced thin volume with external origin is unsupported."); -+ return 0; -+ } -+ -+ /* Validate thin target supports bigger size of thin volume then external origin */ -+ if (first_seg(lv)->external_lv->size <= lv->size && -+ !thin_pool_feature_supported(first_seg(lv)->pool_lv, THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND)) { -+ log_error("Thin target does not support external origin smaller then thin volume."); -+ return 0; -+ } -+ } -+ - return 1; - } - -@@ -4096,7 +4228,7 @@ static struct logical_volume *_lvresize_volume(struct cmd_context *cmd, - lp->stripes, lp->stripe_size, - lp->mirrors, first_seg(lv)->region_size, - lp->extents - lv->le_count, NULL, -- pvh, alloc)) -+ pvh, alloc, lp->approx_alloc)) - return_NULL; - - if (lock_lv) { -@@ -4157,6 +4289,11 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv, - struct logical_volume *lock_lv = NULL; - int inactive = 0; - -+ if (lv_is_cache_type(lv)) { -+ log_error("Unable to resize logical volumes of cache type."); -+ return 0; -+ } -+ - if (lp->sizeargs && - !(lock_lv = _lvresize_volume(cmd, lv, lp, pvh))) - return_0; -@@ -4502,6 +4639,7 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv, - int format1_reload_required = 0; - int visible; - struct logical_volume *pool_lv = NULL; -+ struct lv_segment *cache_seg = NULL; - int ask_discard; - - vg = lv->vg; -@@ -4546,6 +4684,27 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv, - } else if (lv_is_thin_volume(lv)) - pool_lv = first_seg(lv)->pool_lv; - -+ /* -+ * If we are removing a cache_pool, we must first unlink -+ * it from any origins (i.e. remove the cache layer). -+ * -+ * If the cache_pool is not linked, we can simply proceed -+ * to remove it. -+ */ -+ if (lv_is_cache_pool(lv) && !dm_list_empty(&lv->segs_using_this_lv)) { -+ if (!(cache_seg = get_only_segment_using_this_lv(lv))) -+ return_0; -+ -+ if (!lv_cache_remove(cache_seg->lv)) -+ return_0; -+ } -+ -+ if (lv_is_cache_pool_data(lv) || lv_is_cache_pool_metadata(lv)) { -+ log_error("Can't remove logical volume %s used by a cache_pool.", -+ lv->name); -+ return 0; -+ } -+ - if (lv->status & LOCKED) { - log_error("Can't remove locked LV %s", lv->name); - return 0; -@@ -4774,12 +4933,14 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume * - if (lv_is_used_thin_pool(lv) && - !_lv_remove_segs_using_this_lv(cmd, lv, force, level, "pool")) - return_0; -- -- if (lv_is_thin_pool(lv) && lv->vg->pool_metadata_spare_lv) { -- /* When removing last thin pool, remove also spare */ -+ if ((lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) && -+ lv->vg->pool_metadata_spare_lv) { -+ /* When removing last pool, also remove the spare */ - is_last_pool = 1; - dm_list_iterate_items(lvl, &lv->vg->lvs) -- if (lv_is_thin_pool(lvl->lv) && lvl->lv != lv) { -+ if ((lv_is_thin_pool(lvl->lv) || -+ lv_is_cache_pool(lvl->lv)) && -+ lvl->lv != lv) { - is_last_pool = 0; - break; - } -@@ -4792,9 +4953,10 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume * - - if (lv_is_pool_metadata_spare(lv) && - (force == PROMPT) && -- (yes_no_prompt("Removal of pool metadata spare logical volume \"%s\" " -- "disables automatic recovery attempts after damage " -- "to a thin pool. Proceed? [y/n]: ", lv->name) == 'n')) -+ (yes_no_prompt("Removal of pool metadata spare logical volume" -+ " \"%s\" disables automatic recovery attempts" -+ " after damage to a thin or cache pool." -+ " Proceed? [y/n]: ", lv->name) == 'n')) - goto no_remove; - - return lv_remove_single(cmd, lv, force, 0); -@@ -5061,6 +5223,8 @@ int remove_layer_from_lv(struct logical_volume *lv, - parent->le_count != layer_lv->le_count) - return_0; - -+ //FIXME: why do we empty the parent? It removes everything below. -+ //This makes the function unusable for 'lv_cache_remove' - if (!lv_empty(parent)) - return_0; - -@@ -5448,7 +5612,9 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp) - if (wp.do_wipe_signatures) { - log_verbose("Wiping known signatures on logical volume \"%s/%s\"", - lv->vg->name, lv->name); -- if (!wipe_known_signatures(lv->vg->cmd, dev, name, 0, wp.yes, wp.force)) -+ if (!wipe_known_signatures(lv->vg->cmd, dev, name, 0, -+ TYPE_DM_SNAPSHOT_COW, -+ wp.yes, wp.force)) - stack; - } - -@@ -5458,8 +5624,9 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp) - if (zero_sectors > lv->size) - zero_sectors = lv->size; - -- log_verbose("Clearing start of logical volume \"%s/%s\"", -- lv->vg->name, lv->name); -+ log_verbose("Initializing %s of logical volume \"%s/%s\" with value %d.", -+ display_size(lv->vg->cmd, zero_sectors), -+ lv->vg->name, lv->name, wp.zero_value); - - if (!dev_set(dev, UINT64_C(0), (size_t) zero_sectors << SECTOR_SHIFT, wp.zero_value)) - stack; -@@ -5503,7 +5670,7 @@ static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd, - return_NULL; - - if (!lv_extend(lv, segtype, 1, 0, 1, 0, voriginextents, -- NULL, NULL, ALLOC_INHERIT)) -+ NULL, NULL, ALLOC_INHERIT, 0)) - return_NULL; - - /* store vg on disk(s) */ -@@ -5549,16 +5716,16 @@ void lv_set_activation_skip(struct logical_volume *lv, int override_default, - * of the 'skip' arg supplied instead. - */ - int lv_activation_skip(struct logical_volume *lv, activation_change_t activate, -- int override_lv_skip_flag, int skip) -+ int override_lv_skip_flag) - { -- /* Do not skip deactivation! */ -- if ((activate == CHANGE_AN) || (activate == CHANGE_ALN)) -+ if (!(lv->status & LV_ACTIVATION_SKIP) || -+ !is_change_activating(activate) || /* Do not skip deactivation */ -+ override_lv_skip_flag) - return 0; - -- if (override_lv_skip_flag) -- return skip; -- -- return (lv->status & LV_ACTIVATION_SKIP) ? 1 : 0; -+ log_verbose("ACTIVATON_SKIP flag set for LV %s/%s, skipping activation.", -+ lv->vg->name, lv->name); -+ return 1; - } - - /* Greatest common divisor */ -@@ -5583,8 +5750,8 @@ static unsigned long _lcm(unsigned long n1, unsigned long n2) - return (n1 * n2) / _gcd(n1, n2); - } - --static int _recalculate_thin_pool_chunk_size_with_dev_hints(struct lvcreate_params *lp, -- struct logical_volume *pool_lv) -+static int _recalculate_pool_chunk_size_with_dev_hints(struct lvcreate_params *lp, -+ struct logical_volume *pool_lv) - { - struct logical_volume *pool_data_lv; - struct lv_segment *seg; -@@ -5592,13 +5759,34 @@ static int _recalculate_thin_pool_chunk_size_with_dev_hints(struct lvcreate_para - struct cmd_context *cmd = pool_lv->vg->cmd; - unsigned long previous_hint = 0, hint = 0; - uint32_t chunk_size = lp->chunk_size; -- uint32_t default_chunk_size = lp->thin_chunk_size_calc_policy == THIN_CHUNK_SIZE_CALC_METHOD_PERFORMANCE ? -- DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE*2 : DEFAULT_THIN_POOL_CHUNK_SIZE*2; -+ uint32_t default_chunk_size; -+ uint32_t min_chunk_size, max_chunk_size; - -- if (lp->passed_args & PASS_ARG_CHUNK_SIZE || -- find_config_tree_int(cmd, allocation_thin_pool_chunk_size_CFG, NULL)) -+ if (lp->passed_args & PASS_ARG_CHUNK_SIZE) - goto out; - -+ if (seg_is_thin_pool(lp)) { -+ if (find_config_tree_int(cmd, allocation_thin_pool_chunk_size_CFG, NULL)) -+ goto out; -+ -+ min_chunk_size = DM_THIN_MIN_DATA_BLOCK_SIZE; -+ max_chunk_size = DM_THIN_MAX_DATA_BLOCK_SIZE; -+ if (lp->thin_chunk_size_calc_policy == THIN_CHUNK_SIZE_CALC_METHOD_PERFORMANCE) -+ default_chunk_size = DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE*2; -+ else -+ default_chunk_size = DEFAULT_THIN_POOL_CHUNK_SIZE*2; -+ } else if (seg_is_cache_pool(lp)) { -+ if (find_config_tree_int(cmd, allocation_cache_pool_chunk_size_CFG, NULL)) -+ goto out; -+ min_chunk_size = DM_CACHE_MIN_DATA_BLOCK_SIZE; -+ max_chunk_size = DM_CACHE_MAX_DATA_BLOCK_SIZE; -+ default_chunk_size = DEFAULT_CACHE_POOL_CHUNK_SIZE*2; -+ } else { -+ log_error(INTERNAL_ERROR "%s is not a thin pool or cache pool", -+ pool_lv->name); -+ return 0; -+ } -+ - pool_data_lv = seg_lv(first_seg(pool_lv), 0); - - dm_list_iterate_items(seg, &pool_data_lv->segments) { -@@ -5616,19 +5804,19 @@ static int _recalculate_thin_pool_chunk_size_with_dev_hints(struct lvcreate_para - } - - if (!hint) { -- log_debug_alloc("No usable device hint found while recalculating " -- "thin pool chunk size for %s.", pool_lv->name); -+ log_debug_alloc("No usable device hint found while recalculating" -+ " thin pool chunk size for %s.", pool_lv->name); - goto out; - } - -- if (hint < DM_THIN_MIN_DATA_BLOCK_SIZE || -- hint > DM_THIN_MAX_DATA_BLOCK_SIZE) { -- log_debug_alloc("Calculated chunk size value of %ld sectors " -- "for thin pool %s is out of allowed range (%d-%d).", -- hint, pool_lv->name, DM_THIN_MIN_DATA_BLOCK_SIZE, -- DM_THIN_MAX_DATA_BLOCK_SIZE); -+ if ((hint < min_chunk_size) || (hint > max_chunk_size)) { -+ log_debug_alloc("Calculated chunk size value of %ld sectors for" -+ " thin pool %s is out of allowed range (%d-%d).", -+ hint, pool_lv->name, -+ min_chunk_size, max_chunk_size); - } else -- chunk_size = hint >= default_chunk_size ? hint : default_chunk_size; -+ chunk_size = (hint >= default_chunk_size) ? -+ hint : default_chunk_size; - out: - first_seg(pool_lv)->chunk_size = chunk_size; - return 1; -@@ -5637,7 +5825,7 @@ out: - static int _should_wipe_lv(struct lvcreate_params *lp, struct logical_volume *lv) { - int r = lp->zero | lp->wipe_signatures; - -- if (!seg_is_thin(lp)) -+ if (!seg_is_thin(lp) && !seg_is_cache_pool(lp)) - return r; - - if (lv_is_thin_volume(lv)) -@@ -5676,9 +5864,11 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - return NULL; - } - -- if ((segtype_is_mirrored(lp->segtype) || -- segtype_is_raid(lp->segtype) || segtype_is_thin(lp->segtype)) && -- !(vg->fid->fmt->features & FMT_SEGMENTS)) { -+ if (!(vg->fid->fmt->features & FMT_SEGMENTS) && -+ (segtype_is_mirrored(lp->segtype) || -+ segtype_is_raid(lp->segtype) || -+ segtype_is_thin(lp->segtype) || -+ segtype_is_cache(lp->segtype))) { - log_error("Metadata does not support %s segments.", - lp->segtype->name); - return NULL; -@@ -5725,7 +5915,59 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - - status |= lp->permission | VISIBLE_LV; - -- if (seg_is_thin(lp) && lp->snapshot) { -+ if (segtype_is_cache(lp->segtype) && lp->pool) { -+ /* We have the cache_pool, create the origin with cache */ -+ if (!(pool_lv = find_lv(vg, lp->pool))) { -+ log_error("Couldn't find origin volume '%s'.", -+ lp->pool); -+ return NULL; -+ } -+ -+ if (pool_lv->status & LOCKED) { -+ log_error("Caching locked devices is not supported."); -+ return NULL; -+ } -+ -+ if (!lp->extents) { -+ log_error("No size given for new cache origin LV"); -+ return NULL; -+ } -+ -+ if (lp->extents < pool_lv->le_count) { -+ log_error("Origin size cannot be smaller than" -+ " the cache_pool"); -+ return NULL; -+ } -+ -+ if (!(lp->segtype = get_segtype_from_string(vg->cmd, "striped"))) -+ return_0; -+ } else if (segtype_is_cache(lp->segtype) && lp->origin) { -+ /* We have the origin, create the cache_pool and cache */ -+ if (!(org = find_lv(vg, lp->origin))) { -+ log_error("Couldn't find origin volume '%s'.", -+ lp->origin); -+ return NULL; -+ } -+ -+ if (org->status & LOCKED) { -+ log_error("Caching locked devices is not supported."); -+ return NULL; -+ } -+ -+ if (!lp->extents) { -+ log_error("No size given for new cache_pool LV"); -+ return NULL; -+ } -+ -+ if (lp->extents > org->le_count) { -+ log_error("cache-pool size cannot be larger than" -+ " the origin"); -+ return NULL; -+ } -+ if (!(lp->segtype = get_segtype_from_string(vg->cmd, -+ "cache-pool"))) -+ return_0; -+ } else if (seg_is_thin(lp) && lp->snapshot) { - if (!(org = find_lv(vg, lp->origin))) { - log_error("Couldn't find origin volume '%s'.", - lp->origin); -@@ -5806,10 +6048,12 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - return NULL; - } - -- if (seg_is_thin_pool(lp) && -- ((uint64_t)lp->extents * vg->extent_size < lp->chunk_size)) { -- log_error("Unable to create thin pool smaller than 1 chunk."); -- return NULL; -+ if (seg_is_thin_pool(lp) || seg_is_cache_pool(lp)) { -+ if (((uint64_t)lp->extents * vg->extent_size < lp->chunk_size)) { -+ log_error("Unable to create %s smaller than 1 chunk.", -+ lp->segtype->name); -+ return NULL; -+ } - } - - if (lp->snapshot && !seg_is_thin(lp) && -@@ -5824,7 +6068,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - } - - if (!seg_is_virtual(lp) && -- vg->free_count < lp->extents) { -+ vg->free_count < lp->extents && !lp->approx_alloc) { - log_error("Volume group \"%s\" has insufficient free space " - "(%u extents): %u required.", - vg->name, vg->free_count, lp->extents); -@@ -5841,7 +6085,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - if (!activation() && - (seg_is_mirrored(lp) || - seg_is_raid(lp) || -- seg_is_thin_pool(lp))) { -+ seg_is_thin_pool(lp) || -+ seg_is_cache_pool(lp))) { - /* - * FIXME: For thin pool add some code to allow delayed - * initialization of empty thin pool volume. -@@ -5850,9 +6095,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - */ - log_error("Can't create %s without using " - "device-mapper kernel driver.", -- segtype_is_raid(lp->segtype) ? lp->segtype->name : -- segtype_is_mirrored(lp->segtype) ? "mirror" : -- "thin pool volume"); -+ seg_is_thin_pool(lp) ? "thin pool volume" : -+ lp->segtype->name); - return NULL; - } - -@@ -5888,10 +6132,9 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - return NULL; - } - -- if (lv_is_active(lvl->lv) || -- ((lp->activate != CHANGE_AN) && (lp->activate != CHANGE_ALN))) -- if (!update_pool_lv(lvl->lv, 1)) -- return_NULL; -+ if ((lv_is_active(lvl->lv) || is_change_activating(lp->activate)) && -+ !update_pool_lv(lvl->lv, 1)) -+ return_NULL; - - /* For thin snapshot we must have matching pool */ - if (org && lv_is_thin_volume(org) && (!lp->pool || -@@ -5938,13 +6181,18 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - if (!lv_extend(lv, lp->segtype, - lp->stripes, lp->stripe_size, - lp->mirrors, -- seg_is_thin_pool(lp) ? lp->poolmetadataextents : lp->region_size, -+ (seg_is_thin_pool(lp) || seg_is_cache_pool(lp)) ? -+ lp->poolmetadataextents : lp->region_size, - seg_is_thin_volume(lp) ? lp->voriginextents : lp->extents, -- thin_name, lp->pvh, lp->alloc)) -+ thin_name, lp->pvh, lp->alloc, lp->approx_alloc)) - return_NULL; - -- if (seg_is_thin_pool(lp)) { -- if (!_recalculate_thin_pool_chunk_size_with_dev_hints(lp, lv)) -+ if (seg_is_cache_pool(lp)) { -+ if (!_recalculate_pool_chunk_size_with_dev_hints(lp, lv)) -+ return_NULL; -+ first_seg(lv)->feature_flags = lp->feature_flags; -+ } else if (seg_is_thin_pool(lp)) { -+ if (!_recalculate_pool_chunk_size_with_dev_hints(lp, lv)) - return_NULL; - first_seg(lv)->zero_new_blocks = lp->zero ? 1 : 0; - first_seg(lv)->discards = lp->discards; -@@ -5960,6 +6208,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - * within the same thin pool - */ - if (lp->snapshot && (first_seg(org)->pool_lv != pool_lv)) { -+ if (!pool_supports_external_origin(first_seg(pool_lv), org)) -+ return_0; - if (org->status & LVM_WRITE) { - log_error("Cannot use writable LV as the external origin."); - return 0; // TODO conversion for inactive -@@ -5978,14 +6228,42 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - } else if (seg_is_raid(lp)) { - first_seg(lv)->min_recovery_rate = lp->min_recovery_rate; - first_seg(lv)->max_recovery_rate = lp->max_recovery_rate; -- if (vg_is_clustered(lv->vg) && -- is_change_activating(lp->activate) && -- (lp->activate != CHANGE_AE)) { -- log_debug_activation("Creating RAID logical volume in a" -- " cluster: setting activation" -- " mode to EX"); -- lp->activate = CHANGE_AE; -+ } -+ -+ if (lp->cache) { -+ struct logical_volume *tmp_lv; -+ -+ if (lp->origin) { -+ /* -+ * FIXME: At this point, create_pool has created -+ * the pool and added the data and metadata sub-LVs, -+ * but only the metadata sub-LV is in the kernel - -+ * a suspend/resume cycle is still necessary on the -+ * cache_pool to actualize it in the kernel. -+ * -+ * Should the suspend/resume be added to create_pool? -+ * I say that would be cleaner, but I'm not sure -+ * about the effects on thinpool yet... -+ */ -+ if (!vg_write(vg) || !suspend_lv(cmd, lv) || -+ !vg_commit(vg) || !resume_lv(cmd, lv)) -+ goto deactivate_and_revert_new_lv; -+ -+ if (!(lvl = find_lv_in_vg(vg, lp->origin))) -+ goto deactivate_and_revert_new_lv; -+ org = lvl->lv; -+ pool_lv = lv; -+ } else { -+ if (!(lvl = find_lv_in_vg(vg, lp->pool))) -+ goto deactivate_and_revert_new_lv; -+ pool_lv = lvl->lv; -+ org = lv; - } -+ -+ if (!(tmp_lv = lv_cache_create(pool_lv, org))) -+ goto deactivate_and_revert_new_lv; -+ -+ lv = tmp_lv; - } - - /* FIXME Log allocation and attachment should have happened inside lv_extend. */ -@@ -6010,11 +6288,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - lp->activate = lv_passes_auto_activation_filter(cmd, lv) ? - CHANGE_ALY : CHANGE_ALN; - -- if (lv_activation_skip(lv, lp->activate, lp->activation_skip & ACTIVATION_SKIP_IGNORE, 0)) { -- log_verbose("ACTIVATION_SKIP flag set for LV %s/%s, skipping activation.", -- lv->vg->name, lv->name); -+ if (lv_activation_skip(lv, lp->activate, lp->activation_skip & ACTIVATION_SKIP_IGNORE)) - lp->activate = CHANGE_AN; -- } - - /* - * For thin pools - deactivate when inactive pool is requested or -@@ -6047,7 +6322,25 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - if (lp->temporary) - lv->status |= LV_TEMPORARY; - -- if (lv_is_thin_pool(lv)) { -+ if (lv_is_cache_type(lv)) { -+ if (!lv_is_active(lv)) { -+ if (!activate_lv_excl(cmd, lv)) { -+ log_error("Failed to activate pool %s.", -+ lv->name); -+ goto deactivate_and_revert_new_lv; -+ } -+ } else { -+ if (!suspend_lv(cmd, lv)) { -+ log_error("Failed to suspend pool %s.", -+ lv->name); -+ goto deactivate_and_revert_new_lv; -+ } -+ if (!resume_lv(cmd, lv)) { -+ log_error("Failed to resume pool %s.", lv->name); -+ goto deactivate_and_revert_new_lv; -+ } -+ } -+ } else if (lv_is_thin_pool(lv)) { - if (is_change_activating(lp->activate)) { - if (vg_is_clustered(lv->vg)) { - if (!activate_lv_excl(cmd, lv)) { -@@ -6227,7 +6520,7 @@ struct logical_volume *lv_create_single(struct volume_group *vg, - struct logical_volume *lv; - - /* Create thin pool first if necessary */ -- if (lp->create_thin_pool) { -+ if (lp->create_pool && !seg_is_cache_pool(lp) && !seg_is_cache(lp)) { - if (!seg_is_thin_pool(lp) && - !(lp->segtype = get_segtype_from_string(vg->cmd, "thin-pool"))) - return_0; -diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c -index 93e4bfa..f6a14a8 100644 ---- a/lib/metadata/merge.c -+++ b/lib/metadata/merge.c -@@ -190,31 +190,54 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg) - inc_error_count; - } - -- if (seg->area_count != 1 || seg_type(seg, 0) != AREA_LV) { -- log_error("LV %s: thin pool segment %u is missing a pool data LV", -- lv->name, seg_count); -+ } -+ if (seg_is_thin_pool(seg) || seg_is_cache_pool(seg)) { -+ if (seg->area_count != 1 || -+ seg_type(seg, 0) != AREA_LV) { -+ log_error("LV %s: %spool segment %u is missing a pool data LV", -+ lv->name, -+ seg_is_thin_pool(seg) ? -+ "thin " : "cache", -+ seg_count); - inc_error_count; - } else if (!(seg2 = first_seg(seg_lv(seg, 0))) || find_pool_seg(seg2) != seg) { -- log_error("LV %s: thin pool segment %u data LV does not refer back to pool LV", -- lv->name, seg_count); -+ log_error("LV %s: %spool segment %u data LV does not refer back to pool LV", -+ lv->name, -+ seg_is_thin_pool(seg) ? -+ "thin " : "cache", -+ seg_count); - inc_error_count; - } - - if (!seg->metadata_lv) { -- log_error("LV %s: thin pool segment %u is missing a pool metadata LV", -- lv->name, seg_count); -+ log_error("LV %s: %spool segment %u is missing a pool metadata LV", -+ lv->name, -+ seg_is_thin_pool(seg) ? -+ "thin " : "cache", -+ seg_count); - inc_error_count; - } else if (!(seg2 = first_seg(seg->metadata_lv)) || - find_pool_seg(seg2) != seg) { -- log_error("LV %s: thin pool segment %u metadata LV does not refer back to pool LV", -- lv->name, seg_count); -+ log_error("LV %s: %spool segment %u metadata LV does not refer back to pool LV", -+ lv->name, -+ seg_is_thin_pool(seg) ? -+ "thin " : "cache", -+ seg_count); - inc_error_count; - } - -- if (seg->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE || -- seg->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE) { -- log_error("LV %s: thin pool segment %u has chunk size %u out of range.", -- lv->name, seg_count, seg->chunk_size); -+ if ((seg_is_thin_pool(seg) && -+ ((seg->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) || -+ (seg->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE))) || -+ (seg_is_cache_pool(seg) && -+ ((seg->chunk_size < DM_CACHE_MIN_DATA_BLOCK_SIZE) || -+ (seg->chunk_size > DM_CACHE_MAX_DATA_BLOCK_SIZE)))) -+{ -+ log_error("LV %s: %spool segment %u has chunk size %u out of range.", -+ lv->name, -+ seg_is_thin_pool(seg) ? -+ "thin " : "cache", -+ seg_count, seg->chunk_size); - inc_error_count; - } - } else { -@@ -271,6 +294,17 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg) - inc_error_count; - } - } -+ } else if (seg_is_cache(seg)) { -+ if (!lv_is_cache(lv)) { -+ log_error("LV %s is missing cache flag for segment %u", -+ lv->name, seg_count); -+ inc_error_count; -+ } -+ if (!seg->pool_lv) { -+ log_error("LV %s: segment %u is missing cache_pool LV", -+ lv->name, seg_count); -+ inc_error_count; -+ } - } else { - if (seg->pool_lv) { - log_error("LV %s: segment %u must not have thin pool LV set", -diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h -index 8e36891..87e6046 100644 ---- a/lib/metadata/metadata-exported.h -+++ b/lib/metadata/metadata-exported.h -@@ -1,6 +1,6 @@ - /* - * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. -- * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved. - * - * This file is part of LVM2. - * -@@ -105,9 +105,15 @@ - #define LV_NOSCAN UINT64_C(0x0000080000000000) /* LV - internal use only - the LV - should not be scanned */ - #define LV_TEMPORARY UINT64_C(0x0000100000000000) /* LV - internal use only - the LV -- is supposed to be created and -- removed during single LVM -- command execution. */ -+ is supposed to be created and -+ removed or reactivated with -+ this flag dropped during single -+ LVM command execution. */ -+ -+#define CACHE_POOL UINT64_C(0x0000200000000000) /* LV */ -+#define CACHE_POOL_DATA UINT64_C(0x0000400000000000) /* LV */ -+#define CACHE_POOL_METADATA UINT64_C(0x0000800000000000) /* LV */ -+#define CACHE UINT64_C(0x0001000000000000) /* LV */ - - /* Format features flags */ - #define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */ -@@ -168,6 +174,12 @@ - #define lv_is_raid(lv) (((lv)->status & (RAID)) ? 1 : 0) - #define lv_is_raid_type(lv) (((lv)->status & (RAID | RAID_IMAGE | RAID_META)) ? 1 : 0) - -+#define lv_is_cache(lv) (((lv)->status & (CACHE)) ? 1 : 0) -+#define lv_is_cache_pool(lv) (((lv)->status & (CACHE_POOL)) ? 1 : 0) -+#define lv_is_cache_pool_data(lv) (((lv)->status & (CACHE_POOL_DATA)) ? 1 : 0) -+#define lv_is_cache_pool_metadata(lv) (((lv)->status & (CACHE_POOL_METADATA)) ? 1 : 0) -+#define lv_is_cache_type(lv) (((lv)->status & (CACHE | CACHE_POOL | CACHE_POOL_DATA | CACHE_POOL_METADATA)) ? 1 : 0) -+ - #define lv_is_virtual(lv) (((lv)->status & VIRTUAL) ? 1 : 0) - #define lv_is_pool_metadata_spare(lv) (((lv)->status & POOL_METADATA_SPARE) ? 1 : 0) - -@@ -384,6 +396,13 @@ struct lv_segment { - struct logical_volume *pool_lv; /* For thin */ - uint32_t device_id; /* For thin, 24bit */ - -+ uint32_t feature_flags; /* For cache */ -+ unsigned core_argc; /* For cache */ -+ char **core_argv; /* For cache */ -+ char *policy_name; /* For cache */ -+ unsigned policy_argc; /* For cache */ -+ char **policy_argv; /* For cache */ -+ - struct logical_volume *replicator;/* For replicator-devs - link to replicator LV */ - struct logical_volume *rlog_lv; /* For replicators */ - const char *rlog_type; /* For replicators */ -@@ -465,6 +484,7 @@ struct lvresize_params { - uint64_t poolmetadatasize; - sign_t poolmetadatasign; - uint32_t poolmetadataextents; -+ int approx_alloc; - percent_type_t percent; - - enum { -@@ -653,7 +673,8 @@ int lv_extend(struct logical_volume *lv, - uint32_t stripes, uint32_t stripe_size, - uint32_t mirrors, uint32_t region_size, - uint32_t extents, const char *thin_pool_name, -- struct dm_list *allocatable_pvs, alloc_policy_t alloc); -+ struct dm_list *allocatable_pvs, alloc_policy_t alloc, -+ int approx_alloc); - - /* lv must be part of lv->vg->lvs */ - int lv_remove(struct logical_volume *lv); -@@ -674,17 +695,19 @@ uint64_t extents_from_size(struct cmd_context *cmd, uint64_t size, - - struct logical_volume *find_pool_lv(const struct logical_volume *lv); - int pool_is_active(const struct logical_volume *pool_lv); --int pool_can_resize_metadata(const struct logical_volume *pool_lv); -+int pool_supports_external_origin(const struct lv_segment *pool_seg, const struct logical_volume *external_lv); -+int thin_pool_feature_supported(const struct logical_volume *pool_lv, int feature); - int update_pool_lv(struct logical_volume *lv, int activate); - int update_profilable_pool_params(struct cmd_context *cmd, struct profile *profile, - int passed_args, int *chunk_size_calc_method, - uint32_t *chunk_size, thin_discards_t *discards, - int *zero); --int update_pool_params(struct volume_group *vg, unsigned attr, int passed_args, -- uint32_t data_extents, uint32_t extent_size, -- int *chunk_size_calc_method, uint32_t *chunk_size, -- thin_discards_t *discards, -- uint64_t *pool_metadata_size, int *zero); -+int update_thin_pool_params(struct volume_group *vg, unsigned attr, -+ int passed_args, -+ uint32_t data_extents, uint32_t extent_size, -+ int *chunk_size_calc_method, uint32_t *chunk_size, -+ thin_discards_t *discards, -+ uint64_t *pool_metadata_size, int *zero); - int get_pool_discards(const char *str, thin_discards_t *discards); - const char *get_pool_discards_name(thin_discards_t discards); - struct logical_volume *alloc_pool_metadata(struct logical_volume *pool_lv, -@@ -729,9 +752,10 @@ static inline int is_change_activating(activation_change_t change) - /* FIXME: refactor and reduce the size of this struct! */ - struct lvcreate_params { - /* flags */ -+ int cache; - int snapshot; /* snap */ - int thin; /* thin */ -- int create_thin_pool; /* thin */ -+ int create_pool; /* thin */ - int zero; /* all */ - int wipe_signatures; /* all */ - int major; /* all */ -@@ -773,6 +797,8 @@ struct lvcreate_params { - uint32_t min_recovery_rate; /* RAID */ - uint32_t max_recovery_rate; /* RAID */ - -+ uint32_t feature_flags; /* cache */ -+ - const struct segment_type *segtype; /* all */ - unsigned target_attr; /* all */ - -@@ -786,6 +812,7 @@ struct lvcreate_params { - - uint32_t permission; /* all */ - uint32_t read_ahead; /* all */ -+ int approx_alloc; /* all */ - alloc_policy_t alloc; /* all */ - - struct dm_list tags; /* all */ -@@ -806,7 +833,7 @@ struct logical_volume *lv_create_single(struct volume_group *vg, - */ - void lv_set_activation_skip(struct logical_volume *lv, int override_default, int add_skip_flag); - int lv_activation_skip(struct logical_volume *lv, activation_change_t activate, -- int override_lv_skip_flag, int skip); -+ int override_lv_skip_flag); - - /* - * Functions for layer manipulation -@@ -996,9 +1023,20 @@ int lv_raid_reshape(struct logical_volume *lv, - int lv_raid_replace(struct logical_volume *lv, struct dm_list *remove_pvs, - struct dm_list *allocate_pvs); - int lv_raid_remove_missing(struct logical_volume *lv); -- - /* -- metadata/raid_manip.c */ - -+/* ++ metadata/cache_manip.c */ -+int update_cache_pool_params(struct volume_group *vg, unsigned attr, -+ int passed_args, -+ uint32_t data_extents, uint32_t extent_size, -+ int *chunk_size_calc_method, uint32_t *chunk_size, -+ thin_discards_t *discards, -+ uint64_t *pool_metadata_size, int *zero); -+struct logical_volume *lv_cache_create(struct logical_volume *pool, -+ struct logical_volume *origin); -+int lv_cache_remove(struct logical_volume *cache_lv); -+/* -- metadata/cache_manip.c */ -+ - struct cmd_vg *cmd_vg_add(struct dm_pool *mem, struct dm_list *cmd_vgs, - const char *vg_name, const char *vgid, - uint32_t flags); -diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c -index 4d4778b..8643b75 100644 ---- a/lib/metadata/metadata.c -+++ b/lib/metadata/metadata.c -@@ -856,30 +856,45 @@ int vgcreate_params_validate(struct cmd_context *cmd, - return 1; - } - --static int _vg_update_vg_ondisk(struct volume_group *vg) -+/* -+ * Update content of precommitted VG -+ * -+ * TODO: Optimize in the future, since lvmetad needs similar -+ * config tree processing in lvmetad_vg_update(). -+ */ -+static int _vg_update_vg_precommitted(struct volume_group *vg) - { - struct dm_config_tree *cft; -- int pool_locked; - -- if (vg->vg_ondisk || is_orphan_vg(vg->name)) /* we already have it */ -- return 1; -+ release_vg(vg->vg_precommitted); -+ vg->vg_precommitted = NULL; - -- pool_locked = dm_pool_locked(vg->vgmem); -- if (pool_locked && !dm_pool_unlock(vg->vgmem, 0)) -+ if (!(cft = export_vg_to_config_tree(vg))) - return_0; - -- cft = export_vg_to_config_tree(vg); -- if (!cft) -- return 0; -+ if (!(vg->vg_precommitted = import_vg_from_config_tree(cft, vg->fid))) -+ stack; - -- vg->vg_ondisk = import_vg_from_config_tree(cft, vg->fid); - dm_config_destroy(cft); - -- /* recompute the pool crc */ -- if (pool_locked && !dm_pool_lock(vg->vgmem, 1)) -+ return vg->vg_precommitted ? 1 : 0; -+} -+ -+static int _vg_update_vg_ondisk(struct volume_group *vg) -+{ -+ if (dm_pool_locked(vg->vgmem)) -+ return 1; -+ -+ if (vg->vg_ondisk || is_orphan_vg(vg->name)) /* we already have it */ -+ return 1; -+ -+ if (!_vg_update_vg_precommitted(vg)) - return_0; - -- return vg->vg_ondisk ? 1 : 0; -+ vg->vg_ondisk = vg->vg_precommitted; -+ vg->vg_precommitted = NULL; -+ -+ return 1; - } - - /* -@@ -1322,8 +1337,7 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name, - /* FIXME Check partition type is LVM unless --force is given */ - - /* Is there a pv here already? */ -- if (!(pv = find_pv_by_name(cmd, name, 1, 1))) -- stack; -+ pv = find_pv_by_name(cmd, name, 1, 1); - - /* Allow partial & exported VGs to be destroyed. */ - /* We must have -ff to overwrite a non orphan */ -@@ -1372,7 +1386,9 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name, - goto bad; - } - -- if (!wipe_known_signatures(cmd, dev, name, 1, pp->yes, pp->force)) { -+ if (!wipe_known_signatures(cmd, dev, name, -+ TYPE_LVM1_MEMBER | TYPE_LVM2_MEMBER, -+ 0, pp->yes, pp->force)) { - log_error("Aborting pvcreate on %s.", name); - goto bad; - } -@@ -2686,6 +2702,9 @@ int vg_write(struct volume_group *vg) - if (!(vg->fid->fmt->features & FMT_PRECOMMIT) && !lvmetad_vg_update(vg)) - return_0; - -+ if (!_vg_update_vg_precommitted(vg)) /* prepare precommited */ -+ return_0; -+ - return 1; - } - -@@ -2752,9 +2771,8 @@ int vg_commit(struct volume_group *vg) - - /* This *is* the original now that it's commited. */ - release_vg(vg->vg_ondisk); -- vg->vg_ondisk = NULL; -- if (!_vg_update_vg_ondisk(vg)) /* make a new one for future edits */ -- return_0; -+ vg->vg_ondisk = vg->vg_precommitted; -+ vg->vg_precommitted = NULL; - } - - /* If update failed, remove any cached precommitted metadata. */ -@@ -2771,6 +2789,9 @@ void vg_revert(struct volume_group *vg) - { - struct metadata_area *mda; - -+ release_vg(vg->vg_precommitted); /* VG is no longer needed */ -+ vg->vg_precommitted = NULL; -+ - dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) { - if (mda->ops->vg_revert && - !mda->ops->vg_revert(vg->fid, vg, mda)) { -@@ -4653,7 +4674,7 @@ int pv_change_metadataignore(struct physical_volume *pv, uint32_t mda_ignored) - return 1; - } - --char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tags) -+char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tagsl) - { - struct str_list *sl; - -@@ -4662,9 +4683,9 @@ char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tags) - return NULL; - } - -- dm_list_iterate_items(sl, tags) { -+ dm_list_iterate_items(sl, tagsl) { - if (!dm_pool_grow_object(mem, sl->str, strlen(sl->str)) || -- (sl->list.n != tags && !dm_pool_grow_object(mem, ",", 1))) { -+ (sl->list.n != tagsl && !dm_pool_grow_object(mem, ",", 1))) { - log_error("dm_pool_grow_object failed"); - return NULL; - } -diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h -index fef4b3f..83959bb 100644 ---- a/lib/metadata/metadata.h -+++ b/lib/metadata/metadata.h -@@ -488,6 +488,6 @@ int add_pv_to_vg(struct volume_group *vg, const char *pv_name, - struct physical_volume *pv, struct pvcreate_params *pp); - - uint64_t find_min_mda_size(struct dm_list *mdas); --char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tags); -+char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tagsl); - - #endif -diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c -index 18917d3..86ec4ca 100644 ---- a/lib/metadata/mirror.c -+++ b/lib/metadata/mirror.c -@@ -279,7 +279,7 @@ static int _write_log_header(struct cmd_context *cmd, struct logical_volume *lv) - */ - static int _init_mirror_log(struct cmd_context *cmd, - struct logical_volume *log_lv, int in_sync, -- struct dm_list *tags, int remove_on_failure) -+ struct dm_list *tagsl, int remove_on_failure) - { - struct str_list *sl; - uint64_t orig_status = log_lv->status; -@@ -315,7 +315,7 @@ static int _init_mirror_log(struct cmd_context *cmd, - lv_set_visible(log_lv); - - /* Temporary tag mirror log for activation */ -- dm_list_iterate_items(sl, tags) -+ dm_list_iterate_items(sl, tagsl) - if (!str_list_add(cmd->mem, &log_lv->tags, sl->str)) { - log_error("Aborting. Unable to tag mirror log."); - goto activate_lv; -@@ -336,7 +336,7 @@ static int _init_mirror_log(struct cmd_context *cmd, - } - - /* Remove the temporary tags */ -- dm_list_iterate_items(sl, tags) -+ dm_list_iterate_items(sl, tagsl) - str_list_del(&log_lv->tags, sl->str); - - if (activation()) { -@@ -376,7 +376,7 @@ deactivate_and_revert_new_lv: - revert_new_lv: - log_lv->status = orig_status; - -- dm_list_iterate_items(sl, tags) -+ dm_list_iterate_items(sl, tagsl) - str_list_del(&log_lv->tags, sl->str); - - if (remove_on_failure && !lv_remove(log_lv)) { -@@ -1676,7 +1676,7 @@ int add_mirrors_to_segments(struct cmd_context *cmd, struct logical_volume *lv, - region_size); - - if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1, mirrors, 0, 0, -- lv->le_count, allocatable_pvs, alloc, -+ lv->le_count, allocatable_pvs, alloc, 0, - parallel_areas))) { - log_error("Unable to allocate mirror extents for %s.", lv->name); - return 0; -@@ -1944,7 +1944,7 @@ int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv, - ah = allocate_extents(lv->vg, NULL, segtype, - 0, 0, log_count - old_log_count, region_size, - lv->le_count, allocatable_pvs, -- alloc, parallel_areas); -+ alloc, 0, parallel_areas); - if (!ah) { - log_error("Unable to allocate extents for mirror log."); - return 0; -@@ -2008,7 +2008,7 @@ int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv, - - ah = allocate_extents(lv->vg, NULL, segtype, - stripes, mirrors, log_count, region_size, lv->le_count, -- allocatable_pvs, alloc, parallel_areas); -+ allocatable_pvs, alloc, 0, parallel_areas); - if (!ah) { - log_error("Unable to allocate extents for mirror(s)."); - return 0; -diff --git a/lib/metadata/pool_manip.c b/lib/metadata/pool_manip.c -new file mode 100644 -index 0000000..0c7bf96 ---- /dev/null -+++ b/lib/metadata/pool_manip.c -@@ -0,0 +1,325 @@ -+/* -+ * Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved. -+ * -+ * This file is part of LVM2. -+ * -+ * This copyrighted material is made available to anyone wishing to use, -+ * modify, copy, or redistribute it subject to the terms and conditions -+ * of the GNU Lesser General Public License v.2.1. -+ * -+ * You should have received a copy of the GNU Lesser General Public License -+ * along with this program; if not, write to the Free Software Foundation, -+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+/* -+ * This file holds common pool functions. -+ */ -+ -+#include "lib.h" -+#include "activate.h" -+#include "locking.h" -+#include "metadata.h" -+#include "segtype.h" -+#include "lv_alloc.h" -+#include "defaults.h" -+ -+int attach_pool_metadata_lv(struct lv_segment *pool_seg, -+ struct logical_volume *metadata_lv) -+{ -+ if (!seg_is_thin_pool(pool_seg) && !seg_is_cache_pool(pool_seg)) { -+ log_error(INTERNAL_ERROR -+ "Unable to attach pool metadata LV to %s segtype.", -+ pool_seg->segtype->ops->name(pool_seg)); -+ return 0; -+ } -+ pool_seg->metadata_lv = metadata_lv; -+ metadata_lv->status |= seg_is_thin_pool(pool_seg) ? -+ THIN_POOL_METADATA : CACHE_POOL_METADATA; -+ lv_set_hidden(metadata_lv); -+ -+ return add_seg_to_segs_using_this_lv(metadata_lv, pool_seg); -+} -+ -+int attach_pool_data_lv(struct lv_segment *pool_seg, -+ struct logical_volume *pool_data_lv) -+{ -+ if (!seg_is_thin_pool(pool_seg) && !seg_is_cache_pool(pool_seg)) { -+ log_error(INTERNAL_ERROR -+ "Unable to attach pool data LV to %s segtype.", -+ pool_seg->segtype->ops->name(pool_seg)); -+ return 0; -+ } -+ -+ if (!set_lv_segment_area_lv(pool_seg, 0, pool_data_lv, -+ 0, seg_is_thin_pool(pool_seg) ? -+ THIN_POOL_DATA : CACHE_POOL_DATA)) -+ return_0; -+ -+ pool_seg->lv->status |= seg_is_thin_pool(pool_seg) ? -+ THIN_POOL : CACHE_POOL; -+ lv_set_hidden(pool_data_lv); -+ -+ return 1; -+} -+ -+int attach_pool_lv(struct lv_segment *seg, -+ struct logical_volume *pool_lv, -+ struct logical_volume *origin, -+ struct logical_volume *merge_lv) -+{ -+ if (!seg_is_thin_volume(seg) && !seg_is_cache(seg)) { -+ log_error(INTERNAL_ERROR "Unable to attach pool to %s/%s" -+ " that is not cache or thin volume.", -+ pool_lv->vg->name, seg->lv->name); -+ return 0; -+ } -+ -+ seg->pool_lv = pool_lv; -+ seg->origin = origin; -+ seg->lv->status |= seg_is_cache(seg) ? CACHE : THIN_VOLUME; -+ -+ if (origin && !add_seg_to_segs_using_this_lv(origin, seg)) -+ return_0; -+ -+ if (!add_seg_to_segs_using_this_lv(pool_lv, seg)) -+ return_0; -+ -+ if (merge_lv) { -+ if (origin != merge_lv) { -+ if (!add_seg_to_segs_using_this_lv(merge_lv, seg)) -+ return_0; -+ } -+ -+ init_snapshot_merge(seg, merge_lv); -+ } -+ -+ return 1; -+} -+ -+int detach_pool_lv(struct lv_segment *seg) -+{ -+ struct lv_thin_message *tmsg, *tmp; -+ struct seg_list *sl, *tsl; -+ int no_update = 0; -+ -+ if (!seg->pool_lv) { -+ log_error(INTERNAL_ERROR -+ "No pool associated with %s LV, %s.", -+ seg->segtype->ops->name(seg), seg->lv->name); -+ return 0; -+ } -+ -+ if (seg_is_cache(seg)) { -+ if (!remove_seg_from_segs_using_this_lv(seg->pool_lv, seg)) -+ return_0; -+ seg->pool_lv = NULL; -+ return 1; -+ } -+ -+ if (!lv_is_thin_pool(seg->pool_lv)) { -+ log_error(INTERNAL_ERROR -+ "Cannot detach pool from LV %s.", -+ seg->lv->name); -+ return 0; -+ } -+ -+ /* Drop any message referencing removed segment */ -+ dm_list_iterate_items_safe(tmsg, tmp, &(first_seg(seg->pool_lv)->thin_messages)) { -+ switch (tmsg->type) { -+ case DM_THIN_MESSAGE_CREATE_SNAP: -+ case DM_THIN_MESSAGE_CREATE_THIN: -+ if (tmsg->u.lv == seg->lv) { -+ log_debug_metadata("Discarding message for LV %s.", -+ tmsg->u.lv->name); -+ dm_list_del(&tmsg->list); -+ no_update = 1; /* Replacing existing */ -+ } -+ break; -+ case DM_THIN_MESSAGE_DELETE: -+ if (tmsg->u.delete_id == seg->device_id) { -+ log_error(INTERNAL_ERROR "Trying to delete %u again.", -+ tmsg->u.delete_id); -+ return 0; -+ } -+ break; -+ default: -+ log_error(INTERNAL_ERROR "Unsupported message type %u.", tmsg->type); -+ break; -+ } -+ } -+ -+ if (!detach_thin_external_origin(seg)) -+ return_0; -+ -+ if (!attach_pool_message(first_seg(seg->pool_lv), -+ DM_THIN_MESSAGE_DELETE, -+ NULL, seg->device_id, no_update)) -+ return_0; -+ -+ if (!remove_seg_from_segs_using_this_lv(seg->pool_lv, seg)) -+ return_0; -+ -+ if (seg->origin && -+ !remove_seg_from_segs_using_this_lv(seg->origin, seg)) -+ return_0; -+ -+ /* If thin origin, remove it from related thin snapshots */ -+ /* -+ * TODO: map removal of origin as snapshot lvconvert --merge? -+ * i.e. rename thin snapshot to origin thin origin -+ */ -+ dm_list_iterate_items_safe(sl, tsl, &seg->lv->segs_using_this_lv) { -+ if (!seg_is_thin_volume(sl->seg) || -+ (seg->lv != sl->seg->origin)) -+ continue; -+ -+ if (!remove_seg_from_segs_using_this_lv(seg->lv, sl->seg)) -+ return_0; -+ /* Thin snapshot is now regular thin volume */ -+ sl->seg->origin = NULL; -+ } -+ -+ seg->lv->status &= ~THIN_VOLUME; -+ seg->pool_lv = NULL; -+ seg->origin = NULL; -+ -+ return 1; -+} -+ -+struct lv_segment *find_pool_seg(const struct lv_segment *seg) -+{ -+ struct lv_segment *pool_seg; -+ -+ pool_seg = get_only_segment_using_this_lv(seg->lv); -+ -+ if (!pool_seg) { -+ log_error("Failed to find pool_seg for %s", seg->lv->name); -+ return NULL; -+ } -+ -+ if ((lv_is_thin_type(seg->lv) && !seg_is_thin_pool(pool_seg)) && -+ !seg_is_cache_pool(pool_seg)) { -+ log_error("%s on %s is not a %s pool segment", -+ pool_seg->lv->name, seg->lv->name, -+ lv_is_thin_type(seg->lv) ? "thin" : "cache"); -+ return NULL; -+ } -+ -+ return pool_seg; -+} -+ -+int create_pool(struct logical_volume *pool_lv, -+ const struct segment_type *segtype, -+ struct alloc_handle *ah, uint32_t stripes, uint32_t stripe_size) -+{ -+ const struct segment_type *striped; -+ struct logical_volume *meta_lv, *data_lv; -+ struct lv_segment *seg; -+ char name[NAME_LEN]; -+ -+ if (pool_lv->le_count) { -+ log_error(INTERNAL_ERROR "Pool %s already has extents.", -+ pool_lv->name); -+ return 0; -+ } -+ -+ /* LV is not yet a pool, so it's extension from lvcreate */ -+ if (!(striped = get_segtype_from_string(pool_lv->vg->cmd, "striped"))) -+ return_0; -+ -+ if (activation() && segtype->ops->target_present && -+ !segtype->ops->target_present(pool_lv->vg->cmd, NULL, NULL)) { -+ log_error("%s: Required device-mapper target(s) not " -+ "detected in your kernel.", segtype->name); -+ return 0; -+ } -+ -+ /* Metadata segment */ -+ if (!lv_add_segment(ah, stripes, 1, pool_lv, striped, 1, 0, 0)) -+ return_0; -+ -+ if (!activation()) -+ log_warn("WARNING: Pool %s is created without initialization.", -+ pool_lv->name); -+ else { -+ if (!vg_write(pool_lv->vg) || !vg_commit(pool_lv->vg)) -+ return_0; -+ -+ /* -+ * If killed here, only the VISIBLE striped pool LV is left -+ * and user could easily remove it. -+ * -+ * FIXME: implement lazy clearing when activation is disabled -+ */ -+ /* -+ * pool_lv is a new LV so the VG lock protects us -+ * Pass in LV_TEMPORARY flag, since device is activated purely for wipe -+ * and later it is either deactivated (in cluster) -+ * or directly converted to invisible device via suspend/resume -+ */ -+ pool_lv->status |= LV_TEMPORARY; -+ if (!activate_lv_local(pool_lv->vg->cmd, pool_lv) || -+ /* Clear 4KB of metadata device for new thin-pool. */ -+ !wipe_lv(pool_lv, (struct wipe_params) { .do_zero = 1 })) { -+ log_error("Aborting. Failed to wipe pool metadata %s.", -+ pool_lv->name); -+ goto bad; -+ } -+ pool_lv->status &= ~LV_TEMPORARY; -+ } -+ -+ if (dm_snprintf(name, sizeof(name), "%s_%s", pool_lv->name, -+ (segtype_is_cache_pool(segtype)) ? -+ "cmeta" : "tmeta") < 0) { -+ log_error("Name is too long to be a pool name."); -+ goto bad; -+ } -+ -+ if (!(meta_lv = lv_create_empty(name, NULL, LVM_READ | LVM_WRITE, -+ ALLOC_INHERIT, pool_lv->vg))) -+ goto_bad; -+ -+ if (!move_lv_segments(meta_lv, pool_lv, 0, 0)) -+ goto_bad; -+ -+ /* Pool data segment */ -+ if (!lv_add_segment(ah, 0, stripes, pool_lv, striped, stripe_size, 0, 0)) -+ goto_bad; -+ -+ if (!(data_lv = insert_layer_for_lv(pool_lv->vg->cmd, pool_lv, -+ pool_lv->status, -+ (segtype_is_cache_pool(segtype)) ? -+ "_cdata" : "_tdata"))) -+ goto_bad; -+ -+ seg = first_seg(pool_lv); -+ /* Drop reference as attach_pool_data_lv() takes it again */ -+ if (!remove_seg_from_segs_using_this_lv(data_lv, seg)) -+ goto_bad; -+ -+ seg->segtype = segtype; /* Set as thin_pool or cache_pool segment */ -+ -+ if (!attach_pool_data_lv(seg, data_lv)) -+ goto_bad; -+ -+ if (!attach_pool_metadata_lv(seg, meta_lv)) -+ goto_bad; -+ -+ return 1; -+ -+bad: -+ if (activation()) { -+ if (deactivate_lv_local(pool_lv->vg->cmd, pool_lv)) { -+ log_error("Aborting. Could not deactivate pool %s.", -+ pool_lv->name); -+ return 0; -+ } -+ if (!lv_remove(pool_lv) || -+ !vg_write(pool_lv->vg) || !vg_commit(pool_lv->vg)) -+ log_error("Manual intervention may be required to " -+ "remove abandoned LV(s) before retrying."); -+ } -+ -+ return 0; -+} -diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c -index a29ea85..d1759ae 100644 ---- a/lib/metadata/raid_manip.c -+++ b/lib/metadata/raid_manip.c -@@ -174,11 +174,13 @@ static int _clear_lv(struct logical_volume *lv) - if (test_mode()) - return 1; - -- if (!was_active && !activate_lv_excl_local(lv->vg->cmd, lv)) { -- log_error("Failed to activate %s for clearing", -+ lv->status |= LV_TEMPORARY; -+ if (!was_active && !activate_lv_local(lv->vg->cmd, lv)) { -+ log_error("Failed to activate localy %s for clearing", - lv->name); - return 0; - } -+ lv->status &= ~LV_TEMPORARY; - - log_verbose("Clearing metadata area of %s/%s", - lv->vg->name, lv->name); -@@ -417,7 +419,7 @@ static int _alloc_image_components(struct logical_volume *lv, - - if (!(ah = allocate_extents(lv->vg, NULL, segtype, 0, count, count, - region_size, extents, pvs, -- lv->alloc, parallel_areas))) -+ lv->alloc, 0, parallel_areas))) - return_0; - - for (s = 0; s < count; s++) { -@@ -481,7 +483,7 @@ static int _alloc_rmeta_for_lv(struct logical_volume *data_lv, - if (!(ah = allocate_extents(data_lv->vg, NULL, seg->segtype, 0, 1, 0, - seg->region_size, - 1 /*RAID_METADATA_AREA_LEN*/, -- &allocatable_pvs, data_lv->alloc, NULL))) -+ &allocatable_pvs, data_lv->alloc, 0, NULL))) - return_0; - - if (!_alloc_image_component(data_lv, base_name, ah, 0, -diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h -index 2c02d1b..75429b4 100644 ---- a/lib/metadata/segtype.h -+++ b/lib/metadata/segtype.h -@@ -41,8 +41,12 @@ struct dev_manager; - #define SEG_RAID 0x00000400U - #define SEG_THIN_POOL 0x00000800U - #define SEG_THIN_VOLUME 0x00001000U -+#define SEG_CACHE 0x00002000U -+#define SEG_CACHE_POOL 0x00004000U - #define SEG_UNKNOWN 0x80000000U - -+#define segtype_is_cache(segtype) ((segtype)->flags & SEG_CACHE ? 1 : 0) -+#define segtype_is_cache_pool(segtype) ((segtype)->flags & SEG_CACHE_POOL ? 1 : 0) - #define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0) - #define segtype_is_raid(segtype) ((segtype)->flags & SEG_RAID ? 1 : 0) - #define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0) -@@ -51,6 +55,8 @@ struct dev_manager; - #define segtype_is_thin_volume(segtype) ((segtype)->flags & SEG_THIN_VOLUME ? 1 : 0) - #define segtype_is_virtual(segtype) ((segtype)->flags & SEG_VIRTUAL ? 1 : 0) - -+#define seg_is_cache(seg) segtype_is_cache((seg)->segtype) -+#define seg_is_cache_pool(seg) segtype_is_cache_pool((seg)->segtype) - #define seg_is_linear(seg) (seg_is_striped(seg) && ((seg)->area_count == 1)) - #define seg_is_mirrored(seg) segtype_is_mirrored((seg)->segtype) - #define seg_is_raid(seg) segtype_is_raid((seg)->segtype) -@@ -147,6 +153,10 @@ int init_replicator_segtype(struct cmd_context *cmd, struct segtype_library *seg - int init_thin_segtypes(struct cmd_context *cmd, struct segtype_library *seglib); - #endif - -+#ifdef CACHE_INTERNAL -+int init_cache_segtypes(struct cmd_context *cmd, struct segtype_library *seglib); -+#endif -+ - #ifdef SNAPSHOT_INTERNAL - struct segment_type *init_snapshot_segtype(struct cmd_context *cmd); - #endif -diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c -index e563a78..25fee76 100644 ---- a/lib/metadata/snapshot_manip.c -+++ b/lib/metadata/snapshot_manip.c -@@ -15,6 +15,7 @@ - - #include "lib.h" - #include "metadata.h" -+#include "segtype.h" - #include "locking.h" - #include "toolcontext.h" - #include "lv_alloc.h" -@@ -31,7 +32,26 @@ int lv_is_cow(const struct logical_volume *lv) - return (!lv_is_thin_volume(lv) && !lv_is_origin(lv) && lv->snapshot) ? 1 : 0; - } - --static uint64_t _cow_max_size(uint64_t origin_size, uint32_t chunk_size) -+/* -+ * Some kernels have a bug that they may leak space in the snapshot on crash. -+ * If the kernel is buggy, we add some extra space. -+ */ -+static uint64_t _cow_extra_chunks(struct cmd_context *cmd, uint64_t n_chunks) -+{ -+ const struct segment_type *segtype; -+ unsigned attrs; -+ -+ if (activation() && -+ (segtype = get_segtype_from_string(cmd, "snapshot")) && -+ segtype->ops->target_present && -+ segtype->ops->target_present(cmd, NULL, &attrs) && -+ (attrs & SNAPSHOT_FEATURE_FIXED_LEAK)) -+ return (n_chunks + 63) / 64; -+ -+ return 0; -+} -+ -+static uint64_t _cow_max_size(struct cmd_context *cmd, uint64_t origin_size, uint32_t chunk_size) - { - /* Snapshot disk layout: - * COW is divided into chunks -@@ -40,21 +60,22 @@ static uint64_t _cow_max_size(uint64_t origin_size, uint32_t chunk_size) - * 3rd. chunk is the 1st. data chunk - */ - -- /* Size of metadata for snapshot in sectors */ -- uint64_t mdata_size = ((origin_size + chunk_size - 1) / chunk_size * 16 + 511) >> SECTOR_SHIFT; -+ uint64_t origin_chunks = (origin_size + chunk_size - 1) / chunk_size; -+ uint64_t chunks_per_metadata_area = (uint64_t)chunk_size << (SECTOR_SHIFT - 4); - -- /* Sum all chunks - header + metadata size + origin size (aligned on chunk boundary) */ -- uint64_t size = chunk_size + -- ((mdata_size + chunk_size - 1) & ~(uint64_t)(chunk_size - 1)) + -- ((origin_size + chunk_size - 1) & ~(uint64_t)(chunk_size - 1)); -+ /* -+ * Note: if origin_chunks is divisible by chunks_per_metadata_area, we -+ * need one extra metadata chunk as a terminator. -+ */ -+ uint64_t metadata_chunks = (origin_chunks + chunks_per_metadata_area) / chunks_per_metadata_area; -+ uint64_t n_chunks = 1 + origin_chunks + metadata_chunks; - -- /* Does not overflow since size is in sectors (9 bits) */ -- return size; -+ return (n_chunks + _cow_extra_chunks(cmd, n_chunks)) * chunk_size; - } - - uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size) - { -- uint64_t size = _cow_max_size(origin->size, chunk_size); -+ uint64_t size = _cow_max_size(origin->vg->cmd, origin->size, chunk_size); - uint32_t extent_size = origin->vg->extent_size; - uint64_t max_size = (uint64_t) MAX_EXTENT_COUNT * extent_size; - -@@ -70,7 +91,8 @@ uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_siz - int lv_is_cow_covering_origin(const struct logical_volume *lv) - { - return lv_is_cow(lv) && -- (lv->size >= _cow_max_size(origin_from_cow(lv)->size, find_snapshot(lv)->chunk_size)); -+ (lv->size >= _cow_max_size(lv->vg->cmd, origin_from_cow(lv)->size, -+ find_snapshot(lv)->chunk_size)); - } - - int lv_is_visible(const struct logical_volume *lv) -@@ -151,7 +173,7 @@ void init_snapshot_merge(struct lv_segment *snap_seg, - origin->snapshot = snap_seg; - origin->status |= MERGING; - -- if (lv_is_thin_volume(origin)) { -+ if (seg_is_thin_volume(snap_seg)) { - snap_seg->merge_lv = origin; - /* Making thin LV inivisible with regular log */ - lv_set_hidden(snap_seg->lv); -diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c -index e12a8ad..b28f5a0 100644 ---- a/lib/metadata/thin_manip.c -+++ b/lib/metadata/thin_manip.c -@@ -17,19 +17,9 @@ - #include "locking.h" - #include "metadata.h" - #include "segtype.h" --#include "lv_alloc.h" - #include "defaults.h" - #include "display.h" - --int attach_pool_metadata_lv(struct lv_segment *pool_seg, struct logical_volume *metadata_lv) --{ -- pool_seg->metadata_lv = metadata_lv; -- metadata_lv->status |= THIN_POOL_METADATA; -- lv_set_hidden(metadata_lv); -- -- return add_seg_to_segs_using_this_lv(metadata_lv, pool_seg); --} -- - int detach_pool_metadata_lv(struct lv_segment *pool_seg, struct logical_volume **metadata_lv) - { - struct logical_volume *lv = pool_seg->metadata_lv; -@@ -48,117 +38,6 @@ int detach_pool_metadata_lv(struct lv_segment *pool_seg, struct logical_volume * - return 1; - } - --int attach_pool_data_lv(struct lv_segment *pool_seg, struct logical_volume *pool_data_lv) --{ -- if (!set_lv_segment_area_lv(pool_seg, 0, pool_data_lv, 0, THIN_POOL_DATA)) -- return_0; -- -- pool_seg->lv->status |= THIN_POOL; -- lv_set_hidden(pool_data_lv); -- -- return 1; --} -- --int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv, -- struct logical_volume *origin, struct logical_volume *merge_lv) --{ -- seg->pool_lv = pool_lv; -- seg->lv->status |= THIN_VOLUME; -- seg->origin = origin; -- -- if (origin && !add_seg_to_segs_using_this_lv(origin, seg)) -- return_0; -- -- if (!add_seg_to_segs_using_this_lv(pool_lv, seg)) -- return_0; -- -- if (merge_lv) { -- if (origin != merge_lv) { -- if (!add_seg_to_segs_using_this_lv(merge_lv, seg)) -- return_0; -- } -- -- init_snapshot_merge(seg, merge_lv); -- } -- -- return 1; --} -- --int detach_pool_lv(struct lv_segment *seg) --{ -- struct lv_thin_message *tmsg, *tmp; -- struct seg_list *sl, *tsl; -- int no_update = 0; -- -- if (!seg->pool_lv || !lv_is_thin_pool(seg->pool_lv)) { -- log_error(INTERNAL_ERROR "Cannot detach pool from non-thin LV %s", -- seg->lv->name); -- return 0; -- } -- -- /* Drop any message referencing removed segment */ -- dm_list_iterate_items_safe(tmsg, tmp, &(first_seg(seg->pool_lv)->thin_messages)) { -- switch (tmsg->type) { -- case DM_THIN_MESSAGE_CREATE_SNAP: -- case DM_THIN_MESSAGE_CREATE_THIN: -- if (tmsg->u.lv == seg->lv) { -- log_debug_metadata("Discarding message for LV %s.", -- tmsg->u.lv->name); -- dm_list_del(&tmsg->list); -- no_update = 1; /* Replacing existing */ -- } -- break; -- case DM_THIN_MESSAGE_DELETE: -- if (tmsg->u.delete_id == seg->device_id) { -- log_error(INTERNAL_ERROR "Trying to delete %u again.", -- tmsg->u.delete_id); -- return 0; -- } -- break; -- default: -- log_error(INTERNAL_ERROR "Unsupported message type %u.", tmsg->type); -- break; -- } -- } -- -- if (!detach_thin_external_origin(seg)) -- return_0; -- -- if (!attach_pool_message(first_seg(seg->pool_lv), -- DM_THIN_MESSAGE_DELETE, -- NULL, seg->device_id, no_update)) -- return_0; -- -- if (!remove_seg_from_segs_using_this_lv(seg->pool_lv, seg)) -- return_0; -- -- if (seg->origin && -- !remove_seg_from_segs_using_this_lv(seg->origin, seg)) -- return_0; -- -- /* If thin origin, remove it from related thin snapshots */ -- /* -- * TODO: map removal of origin as snapshot lvconvert --merge? -- * i.e. rename thin snapshot to origin thin origin -- */ -- dm_list_iterate_items_safe(sl, tsl, &seg->lv->segs_using_this_lv) { -- if (!seg_is_thin_volume(sl->seg) || -- (seg->lv != sl->seg->origin)) -- continue; -- -- if (!remove_seg_from_segs_using_this_lv(seg->lv, sl->seg)) -- return_0; -- /* Thin snapshot is now regular thin volume */ -- sl->seg->origin = NULL; -- } -- -- seg->lv->status &= ~THIN_VOLUME; -- seg->pool_lv = NULL; -- seg->origin = NULL; -- -- return 1; --} -- - int attach_pool_message(struct lv_segment *pool_seg, dm_thin_message_t type, - struct logical_volume *lv, uint32_t delete_id, - int no_update) -@@ -206,9 +85,9 @@ int attach_pool_message(struct lv_segment *pool_seg, dm_thin_message_t type, - - dm_list_add(&pool_seg->thin_messages, &tmsg->list); - -- log_debug_metadata("Added %s message", -+ log_debug_metadata("Added %s message.", - (type == DM_THIN_MESSAGE_CREATE_SNAP || -- type == DM_THIN_MESSAGE_CREATE_THIN) ? "create" : -+ type == DM_THIN_MESSAGE_CREATE_THIN) ? "create" : - (type == DM_THIN_MESSAGE_DELETE) ? "delete" : "unknown"); - - return 1; -@@ -261,7 +140,9 @@ int detach_thin_external_origin(struct lv_segment *seg) - - int lv_is_merging_thin_snapshot(const struct logical_volume *lv) - { -- return (first_seg(lv)->status & MERGING) ? 1 : 0; -+ struct lv_segment *seg = first_seg(lv); -+ -+ return (seg && seg->status & MERGING) ? 1 : 0; - } - - /* -@@ -326,7 +207,7 @@ int pool_is_active(const struct logical_volume *lv) - return 0; - } - --int pool_can_resize_metadata(const struct logical_volume *lv) -+int thin_pool_feature_supported(const struct logical_volume *lv, int feature) - { - static unsigned attr = 0U; - struct lv_segment *seg; -@@ -345,7 +226,7 @@ int pool_can_resize_metadata(const struct logical_volume *lv) - return 0; - } - -- return (attr & THIN_FEATURE_METADATA_RESIZE) ? 1 : 0; -+ return (attr & feature) ? 1 : 0; - } - - int pool_below_threshold(const struct lv_segment *pool_seg) -@@ -360,36 +241,37 @@ int pool_below_threshold(const struct lv_segment *pool_seg) - return_0; - - if (percent >= threshold) -- return_0; -+ return 0; - - /* Metadata */ - if (!lv_thin_pool_percent(pool_seg->lv, 1, &percent)) - return_0; - - if (percent >= threshold) -- return_0; -+ return 0; - - return 1; - } - --struct lv_segment *find_pool_seg(const struct lv_segment *seg) -+/* -+ * Validate given external origin could be used with thin pool -+ */ -+int pool_supports_external_origin(const struct lv_segment *pool_seg, const struct logical_volume *external_lv) - { -- struct lv_segment *pool_seg; -- -- pool_seg = get_only_segment_using_this_lv(seg->lv); -- -- if (!pool_seg) { -- log_error("Failed to find pool_seg for %s", seg->lv->name); -- return NULL; -- } -- -- if (!seg_is_thin_pool(pool_seg)) { -- log_error("%s on %s is not a pool segment", -- pool_seg->lv->name, seg->lv->name); -- return NULL; -+ uint32_t csize = pool_seg->chunk_size; -+ -+ if ((external_lv->size < csize) || (external_lv->size % csize)) { -+ /* TODO: Validate with thin feature flag once, it will be supported */ -+ log_error("Can't use \"%s/%s\" as external origin with \"%s/%s\" pool. " -+ "Size %s is not a multiple of pool's chunk size %s.", -+ external_lv->vg->name, external_lv->name, -+ pool_seg->lv->vg->name, pool_seg->lv->name, -+ display_size(external_lv->vg->cmd, external_lv->size), -+ display_size(external_lv->vg->cmd, csize)); -+ return 0; - } - -- return pool_seg; -+ return 1; - } - - struct logical_volume *find_pool_lv(const struct logical_volume *lv) -@@ -443,107 +325,6 @@ uint32_t get_free_pool_device_id(struct lv_segment *thin_pool_seg) - return max_id; - } - --int create_pool(struct logical_volume *pool_lv, const struct segment_type *segtype, -- struct alloc_handle *ah, uint32_t stripes, uint32_t stripe_size) --{ -- const struct segment_type *striped; -- struct logical_volume *meta_lv, *data_lv; -- struct lv_segment *seg; -- char name[NAME_LEN]; -- -- if (pool_lv->le_count) { -- /* FIXME move code for manipulation from lv_manip.c */ -- log_error(INTERNAL_ERROR "Pool %s has already extents.", pool_lv->name); -- return 0; -- } -- -- /* LV is not yet a pool, so it's extension from lvcreate */ -- if (!(striped = get_segtype_from_string(pool_lv->vg->cmd, "striped"))) -- return_0; -- -- if (activation() && segtype->ops->target_present && -- !segtype->ops->target_present(pool_lv->vg->cmd, NULL, NULL)) { -- log_error("%s: Required device-mapper target(s) not " -- "detected in your kernel.", segtype->name); -- return 0; -- } -- -- /* Metadata segment */ -- if (!lv_add_segment(ah, stripes, 1, pool_lv, striped, 1, 0, 0)) -- return_0; -- -- if (!activation()) -- log_warn("WARNING: Pool %s is created without initialization.", pool_lv->name); -- else { -- if (!vg_write(pool_lv->vg) || !vg_commit(pool_lv->vg)) -- return_0; -- -- /* -- * If killed here, only the VISIBLE striped pool LV is left -- * and user could easily remove it. -- * -- * FIXME: implement lazy clearing when activation is disabled -- */ -- /* pool_lv is a new LV so the VG lock protects us */ -- if (!activate_lv_local(pool_lv->vg->cmd, pool_lv) || -- /* Clear 4KB of metadata device for new thin-pool. */ -- !wipe_lv(pool_lv, (struct wipe_params) { .do_zero = 1 })) { -- log_error("Aborting. Failed to wipe pool metadata %s.", -- pool_lv->name); -- goto bad; -- } -- } -- -- if (dm_snprintf(name, sizeof(name), "%s_tmeta", pool_lv->name) < 0) { -- log_error("Name is too long to be a pool name."); -- goto bad; -- } -- -- if (!(meta_lv = lv_create_empty(name, NULL, LVM_READ | LVM_WRITE, -- ALLOC_INHERIT, pool_lv->vg))) -- goto_bad; -- -- if (!move_lv_segments(meta_lv, pool_lv, 0, 0)) -- goto_bad; -- -- /* Pool data segment */ -- if (!lv_add_segment(ah, 0, stripes, pool_lv, striped, stripe_size, 0, 0)) -- goto_bad; -- -- if (!(data_lv = insert_layer_for_lv(pool_lv->vg->cmd, pool_lv, -- pool_lv->status, "_tdata"))) -- goto_bad; -- -- seg = first_seg(pool_lv); -- /* Drop reference as attach_pool_data_lv() takes it again */ -- if (!remove_seg_from_segs_using_this_lv(data_lv, seg)) -- goto_bad; -- -- if (!attach_pool_data_lv(seg, data_lv)) -- goto_bad; -- -- if (!attach_pool_metadata_lv(seg, meta_lv)) -- goto_bad; -- -- seg->segtype = segtype; /* Set as thin_pool segment */ -- -- return 1; -- --bad: -- if (activation()) { -- if (deactivate_lv_local(pool_lv->vg->cmd, pool_lv)) { -- log_error("Aborting. Could not deactivate pool %s.", -- pool_lv->name); -- return 0; -- } -- if (!lv_remove(pool_lv) || !vg_write(pool_lv->vg) || !vg_commit(pool_lv->vg)) -- log_error("Manual intervention may be required to remove " -- "abandoned LV(s) before retrying."); -- } -- -- return 0; --} -- - int update_pool_lv(struct logical_volume *lv, int activate) - { - int monitored; -@@ -640,11 +421,12 @@ int update_profilable_pool_params(struct cmd_context *cmd, struct profile *profi - return 1; - } - --int update_pool_params(struct volume_group *vg, unsigned attr, int passed_args, -- uint32_t data_extents, uint32_t extent_size, -- int *chunk_size_calc_method, uint32_t *chunk_size, -- thin_discards_t *discards, uint64_t *pool_metadata_size, -- int *zero) -+int update_thin_pool_params(struct volume_group *vg, unsigned attr, -+ int passed_args, -+ uint32_t data_extents, uint32_t extent_size, -+ int *chunk_size_calc_method, uint32_t *chunk_size, -+ thin_discards_t *discards, -+ uint64_t *pool_metadata_size, int *zero) - { - size_t estimate_chunk_size; - struct cmd_context *cmd = vg->cmd; -@@ -897,7 +679,7 @@ int handle_pool_metadata_spare(struct volume_group *vg, uint32_t extents, - seg_mirrors, - seg->region_size, - extents - lv->le_count, NULL, -- pvh, lv->alloc)) -+ pvh, lv->alloc, 0)) - return_0; - - return 1; -diff --git a/lib/metadata/vg.c b/lib/metadata/vg.c -index 877371e..8f23d56 100644 ---- a/lib/metadata/vg.c -+++ b/lib/metadata/vg.c -@@ -89,6 +89,7 @@ void release_vg(struct volume_group *vg) - return; - - release_vg(vg->vg_ondisk); -+ release_vg(vg->vg_precommitted); - _free_vg(vg); - } - -diff --git a/lib/metadata/vg.h b/lib/metadata/vg.h -index 43d27bf..028471b 100644 ---- a/lib/metadata/vg.h -+++ b/lib/metadata/vg.h -@@ -57,6 +57,7 @@ struct volume_group { - * _vg_update_vg_ondisk. - */ - struct volume_group *vg_ondisk; -+ struct volume_group *vg_precommitted; /* Parsed from precommitted */ - - alloc_policy_t alloc; - struct profile *profile; -diff --git a/lib/mirror/mirrored.c b/lib/mirror/mirrored.c -index c3eb27b..5088173 100644 ---- a/lib/mirror/mirrored.c -+++ b/lib/mirror/mirrored.c -@@ -150,7 +150,6 @@ static int _mirrored_text_export(const struct lv_segment *seg, struct formatter - - #ifdef DEVMAPPER_SUPPORT - static int _block_on_error_available = 0; --static unsigned _mirror_attributes = 0; - - static struct mirror_state *_mirrored_init_target(struct dm_pool *mem, - struct cmd_context *cmd) -@@ -462,13 +461,13 @@ static int _mirrored_target_present(struct cmd_context *cmd, - { - static int _mirrored_checked = 0; - static int _mirrored_present = 0; -+ static unsigned _mirror_attributes = 0; - uint32_t maj, min, patchlevel; - unsigned maj2, min2, patchlevel2; - char vsn[80]; -- struct utsname uts; -- unsigned kmaj, kmin, krel; - - if (!_mirrored_checked) { -+ _mirrored_checked = 1; - _mirrored_present = target_present(cmd, "mirror", 1); - - /* -@@ -492,14 +491,16 @@ static int _mirrored_target_present(struct cmd_context *cmd, - sscanf(vsn, "%u.%u.%u", &maj2, &min2, &patchlevel2) == 3 && - maj2 == 4 && min2 == 5 && patchlevel2 == 0))) /* RHEL4U3 */ - _block_on_error_available = 1; -- } - -- /* -- * Check only for modules if atttributes requested and no previous check. -- * FIXME: Fails incorrectly if cmirror was built into kernel. -- */ -- if (attributes) { -- if (!_mirror_attributes) { -+#ifdef CMIRRORD_PIDFILE -+ /* -+ * The cluster mirror log daemon must be running, -+ * otherwise, the kernel module will fail to make -+ * contact. -+ */ -+ if (dm_daemon_is_running(CMIRRORD_PIDFILE)) { -+ struct utsname uts; -+ unsigned kmaj, kmin, krel; - /* - * The dm-log-userspace module was added to the - * 2.6.31 kernel. -@@ -508,31 +509,25 @@ static int _mirrored_target_present(struct cmd_context *cmd, - (sscanf(uts.release, "%u.%u.%u", &kmaj, &kmin, &krel) == 3) && - KERNEL_VERSION(kmaj, kmin, krel) < KERNEL_VERSION(2, 6, 31)) { - if (module_present(cmd, "log-clustered")) -- _mirror_attributes |= MIRROR_LOG_CLUSTERED; -+ _mirror_attributes |= MIRROR_LOG_CLUSTERED; - } else if (module_present(cmd, "log-userspace")) - _mirror_attributes |= MIRROR_LOG_CLUSTERED; - - if (!(_mirror_attributes & MIRROR_LOG_CLUSTERED)) -- log_verbose("Cluster mirror log module is not available"); -- -- /* -- * The cluster mirror log daemon must be running, -- * otherwise, the kernel module will fail to make -- * contact. -- */ --#ifdef CMIRRORD_PIDFILE -- if (!dm_daemon_is_running(CMIRRORD_PIDFILE)) { -- log_verbose("Cluster mirror log daemon is not running"); -- _mirror_attributes &= ~MIRROR_LOG_CLUSTERED; -- } -+ log_verbose("Cluster mirror log module is not available."); -+ } else -+ log_verbose("Cluster mirror log daemon is not running."); - #else -- log_verbose("Cluster mirror log daemon not included in build"); -- _mirror_attributes &= ~MIRROR_LOG_CLUSTERED; -+ log_verbose("Cluster mirror log daemon not included in build."); - #endif -- } -- *attributes = _mirror_attributes; - } -- _mirrored_checked = 1; -+ -+ /* -+ * Check only for modules if atttributes requested and no previous check. -+ * FIXME: Fails incorrectly if cmirror was built into kernel. -+ */ -+ if (attributes) -+ *attributes = _mirror_attributes; - - return _mirrored_present; - } -diff --git a/lib/misc/configure.h.in b/lib/misc/configure.h.in -index 4e9ffd1..c1f088e 100644 ---- a/lib/misc/configure.h.in -+++ b/lib/misc/configure.h.in -@@ -3,6 +3,9 @@ - /* Define to 1 to use libblkid detection of signatures when wiping. */ - #undef BLKID_WIPING_SUPPORT - -+/* Define to 1 to include built-in support for cache. */ -+#undef CACHE_INTERNAL -+ - /* Define to 1 if the `closedir' function returns void instead of `int'. */ - #undef CLOSEDIR_VOID - -diff --git a/lib/misc/lvm-exec.c b/lib/misc/lvm-exec.c -index 01704ad..e862bad 100644 ---- a/lib/misc/lvm-exec.c -+++ b/lib/misc/lvm-exec.c -@@ -18,7 +18,6 @@ - #include "locking.h" - #include "lvm-exec.h" - #include "toolcontext.h" --#include "activate.h" - - #include - #include -diff --git a/lib/raid/raid.c b/lib/raid/raid.c -index 956472e..e592573 100644 ---- a/lib/raid/raid.c -+++ b/lib/raid/raid.c -@@ -221,11 +221,11 @@ static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)), - - for (s = 0; s < seg->area_count; s++) - if (seg_lv(seg, s)->status & LV_REBUILD) -- rebuilds |= 1 << s; -+ rebuilds |= 1ULL << s; - - for (s = 0; s < seg->area_count; s++) - if (seg_lv(seg, s)->status & LV_WRITEMOSTLY) -- writemostly |= 1 << s; -+ writemostly |= 1ULL << s; - - if (mirror_in_sync()) - flags = DM_NOSYNC; -@@ -326,15 +326,45 @@ static int _raid_target_percent(void **target_state, - - static int _raid_target_present(struct cmd_context *cmd, - const struct lv_segment *seg __attribute__((unused)), -- unsigned *attributes __attribute__((unused))) -+ unsigned *attributes) - { -+ /* List of features with their kernel target version */ -+ static const struct feature { -+ uint32_t maj; -+ uint32_t min; -+ unsigned raid_feature; -+ const char *feature; -+ } const _features[] = { -+ { 1, 3, RAID_FEATURE_RAID10, "raid10" }, -+ }; -+ - static int _raid_checked = 0; - static int _raid_present = 0; -+ static int _raid_attrs = 0; -+ uint32_t maj, min, patchlevel; -+ unsigned i; - -- if (!_raid_checked) -+ if (!_raid_checked) { - _raid_present = target_present(cmd, "raid", 1); - -- _raid_checked = 1; -+ if (!target_version("raid", &maj, &min, &patchlevel)) { -+ log_error("Cannot read target version of RAID kernel module."); -+ return 0; -+ } -+ -+ for (i = 0; i < sizeof(_features)/sizeof(*_features); i++) -+ if ((maj > _features[i].maj) || -+ (maj == _features[i].maj && min >= _features[i].min)) -+ _raid_attrs |= _features[i].raid_feature; -+ else -+ log_very_verbose("Target raid does not support %s.", -+ _features[i].feature); -+ -+ _raid_checked = 1; -+ } -+ -+ if (attributes) -+ *attributes = _raid_attrs; - - return _raid_present; - } -diff --git a/lib/report/report.c b/lib/report/report.c -index 3a5119d..681e80c 100644 ---- a/lib/report/report.c -+++ b/lib/report/report.c -@@ -130,10 +130,10 @@ static int _tags_disp(struct dm_report *rh __attribute__((unused)), struct dm_po - struct dm_report_field *field, - const void *data, void *private __attribute__((unused))) - { -- const struct dm_list *tags = (const struct dm_list *) data; -+ const struct dm_list *tagsl = (const struct dm_list *) data; - char *tags_str; - -- if (!(tags_str = tags_format_and_copy(mem, tags))) -+ if (!(tags_str = tags_format_and_copy(mem, tagsl))) - return_0; - - return _field_set_value(field, tags_str, NULL); -@@ -321,7 +321,7 @@ static int _datalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__( - const void *data, void *private __attribute__((unused))) - { - const struct logical_volume *lv = (const struct logical_volume *) data; -- const struct lv_segment *seg = lv_is_thin_pool(lv) ? first_seg(lv) : NULL; -+ const struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ? first_seg(lv) : NULL; - - if (seg) - return _lvname_disp(rh, mem, field, seg_lv(seg, 0), private); -@@ -334,7 +334,7 @@ static int _metadatalv_disp(struct dm_report *rh, struct dm_pool *mem __attribut - const void *data, void *private __attribute__((unused))) - { - const struct logical_volume *lv = (const struct logical_volume *) data; -- const struct lv_segment *seg = lv_is_thin_pool(lv) ? first_seg(lv) : NULL; -+ const struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ? first_seg(lv) : NULL; - - if (seg) - return _lvname_disp(rh, mem, field, seg->metadata_lv, private); -@@ -347,7 +347,8 @@ static int _poollv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__( - const void *data, void *private __attribute__((unused))) - { - const struct logical_volume *lv = (const struct logical_volume *) data; -- struct lv_segment *seg = lv_is_thin_volume(lv) ? first_seg(lv) : NULL; -+ struct lv_segment *seg = (lv_is_thin_volume(lv) || lv_is_cache(lv)) ? -+ first_seg(lv) : NULL; - - if (seg) - return _lvname_disp(rh, mem, field, seg->pool_lv, private); -@@ -373,10 +374,14 @@ static int _origin_disp(struct dm_report *rh, struct dm_pool *mem, - const void *data, void *private) - { - const struct logical_volume *lv = (const struct logical_volume *) data; -+ const struct lv_segment *seg = first_seg(lv); - - if (lv_is_cow(lv)) - return _lvname_disp(rh, mem, field, origin_from_cow(lv), private); - -+ if (lv_is_cache(lv)) -+ return _lvname_disp(rh, mem, field, seg_lv(seg, 0), private); -+ - if (lv_is_thin_volume(lv) && first_seg(lv)->origin) - return _lvname_disp(rh, mem, field, first_seg(lv)->origin, private); - -@@ -1051,7 +1056,7 @@ static int _lvmetadatasize_disp(struct dm_report *rh, struct dm_pool *mem, - const struct logical_volume *lv = (const struct logical_volume *) data; - uint64_t size; - -- if (lv_is_thin_pool(lv)) { -+ if (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) { - size = lv_metadata_size(lv); - return _size64_disp(rh, mem, field, &size, private); - } -diff --git a/lib/snapshot/snapshot.c b/lib/snapshot/snapshot.c -index 91e778f..0b7b845 100644 ---- a/lib/snapshot/snapshot.c -+++ b/lib/snapshot/snapshot.c -@@ -142,19 +142,30 @@ static int _snap_target_percent(void **target_state __attribute__((unused)), - - static int _snap_target_present(struct cmd_context *cmd, - const struct lv_segment *seg, -- unsigned *attributes __attribute__((unused))) -+ unsigned *attributes) - { - static int _snap_checked = 0; - static int _snap_merge_checked = 0; - static int _snap_present = 0; - static int _snap_merge_present = 0; -+ static unsigned _snap_attrs = 0; -+ uint32_t maj, min, patchlevel; - - if (!_snap_checked) { -+ _snap_checked = 1; - _snap_present = target_present(cmd, "snapshot", 1) && - target_present(cmd, "snapshot-origin", 0); -- _snap_checked = 1; -+ -+ if (_snap_present && -+ target_version("snapshot", &maj, &min, &patchlevel) && -+ (maj > 1 || -+ (maj == 1 && (min >= 12 || (min == 10 && patchlevel >= 2))))) -+ _snap_attrs |= SNAPSHOT_FEATURE_FIXED_LEAK; -+ else -+ log_very_verbose("Target snapshot may leak metadata."); - } - -+ /* TODO: test everything at once */ - if (seg && (seg->status & MERGING)) { - if (!_snap_merge_checked) { - _snap_merge_present = target_present(cmd, "snapshot-merge", 0); -diff --git a/lib/thin/thin.c b/lib/thin/thin.c -index ff263d9..7c989f8 100644 ---- a/lib/thin/thin.c -+++ b/lib/thin/thin.c -@@ -215,7 +215,7 @@ static int _thin_pool_text_export(const struct lv_segment *seg, struct formatter - - #ifdef DEVMAPPER_SUPPORT - static int _thin_target_present(struct cmd_context *cmd, -- const struct lv_segment *seg, -+ const struct lv_segment *seg __attribute__((unused)), - unsigned *attributes); - - static int _thin_pool_modules_needed(struct dm_pool *mem, -@@ -262,7 +262,7 @@ static int _thin_pool_add_target_line(struct dev_manager *dm, - uint64_t transaction_id = 0; - unsigned attr; - -- if (!_thin_target_present(cmd, seg, &attr)) -+ if (!_thin_target_present(cmd, NULL, &attr)) - return_0; - - if (!seg->metadata_lv) { -@@ -528,6 +528,7 @@ static int _thin_add_target_line(struct dev_manager *dm, - { - char *pool_dlid, *external_dlid; - uint32_t device_id = seg->device_id; -+ unsigned attr; - - if (!seg->pool_lv) { - log_error(INTERNAL_ERROR "Segment %s has no pool.", -@@ -541,18 +542,19 @@ static int _thin_add_target_line(struct dev_manager *dm, - } - - if (!laopts->no_merging) { -+ if (seg->merge_lv) { -+ log_error(INTERNAL_ERROR "Failed to add merged segment of %s.", -+ seg->lv->name); -+ return 0; -+ } - /* - * merge support for thinp snapshots is implemented by - * simply swapping the thinp device_id of the snapshot - * and origin. - */ -- if (seg->merge_lv) { -- /* snapshot, use merging lv's device_id */ -- device_id = first_seg(seg->merge_lv)->device_id; -- } else if (lv_is_merging_origin(seg->lv)) { -+ if (lv_is_merging_origin(seg->lv) && seg_is_thin_volume(find_snapshot(seg->lv))) - /* origin, use merging snapshot's device_id */ - device_id = find_snapshot(seg->lv)->device_id; -- } - } - - if (!dm_tree_node_add_thin_target(node, len, pool_dlid, device_id)) -@@ -560,6 +562,17 @@ static int _thin_add_target_line(struct dev_manager *dm, - - /* Add external origin LV */ - if (seg->external_lv) { -+ if (!pool_supports_external_origin(first_seg(seg->pool_lv), seg->external_lv)) -+ return_0; -+ if (seg->external_lv->size < seg->lv->size) { -+ /* Validate target supports smaller external origin */ -+ if (!_thin_target_present(cmd, NULL, &attr) || -+ !(attr & THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND)) { -+ log_error("Thin target does not support smaller size of external origin LV %s.", -+ seg->external_lv->name); -+ return 0; -+ } -+ } - if (!(external_dlid = build_dm_uuid(mem, seg->external_lv->lvid.s, - lv_layer(seg->external_lv)))) { - log_error("Failed to build uuid for external origin LV %s.", -@@ -604,7 +617,7 @@ static int _thin_target_percent(void **target_state __attribute__((unused)), - } - - static int _thin_target_present(struct cmd_context *cmd, -- const struct lv_segment *seg, -+ const struct lv_segment *seg __attribute__((unused)), - unsigned *attributes) - { - /* List of features with their kernel target version */ -@@ -618,7 +631,8 @@ static int _thin_target_present(struct cmd_context *cmd, - { 1, 1, THIN_FEATURE_EXTERNAL_ORIGIN, "external_origin" }, - { 1, 4, THIN_FEATURE_BLOCK_SIZE, "block_size" }, - { 1, 5, THIN_FEATURE_DISCARDS_NON_POWER_2, "discards_non_power_2" }, -- { 9, 9, THIN_FEATURE_METADATA_RESIZE, "metadata_resize" }, -+ { 1, 10, THIN_FEATURE_METADATA_RESIZE, "metadata_resize" }, -+ { 9, 11, THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND, "external_origin_extend" }, - }; - - static const char _lvmconf[] = "global/thin_disabled_features"; -@@ -640,7 +654,8 @@ static int _thin_target_present(struct cmd_context *cmd, - } - - for (i = 0; i < sizeof(_features)/sizeof(*_features); i++) -- if (maj >= _features[i].maj && min >= _features[i].min) -+ if ((maj > _features[i].maj) || -+ (maj == _features[i].maj && min >= _features[i].min)) - _attrs |= _features[i].thin_feature; - else - log_very_verbose("Target %s does not support %s.", -diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h -index adfbb76..dd57457 100644 ---- a/libdm/libdevmapper.h -+++ b/libdm/libdevmapper.h -@@ -1,6 +1,6 @@ - /* - * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. -- * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved. - * - * This file is part of the device-mapper userspace tools. - * -@@ -294,6 +294,39 @@ struct dm_status_raid { - int dm_get_status_raid(struct dm_pool *mem, const char *params, - struct dm_status_raid **status); - -+struct dm_status_cache { -+ uint64_t version; /* zero for now */ -+ -+ uint32_t metadata_block_size; /* in 512B sectors */ -+ uint32_t block_size; /* AKA 'chunk_size' */ -+ -+ uint64_t metadata_used_blocks; -+ uint64_t metadata_total_blocks; -+ -+ uint64_t used_blocks; -+ uint64_t dirty_blocks; -+ uint64_t total_blocks; -+ -+ uint64_t read_hits; -+ uint64_t read_misses; -+ uint64_t write_hits; -+ uint64_t write_misses; -+ -+ uint64_t demotions; -+ uint64_t promotions; -+ -+ uint32_t feature_flags; -+ -+ int core_argc; -+ char **core_argv; -+ -+ char *policy_name; -+ int policy_argc; -+ char **policy_argv; -+}; -+ -+int dm_get_status_cache(struct dm_pool *mem, const char *params, -+ struct dm_status_cache **status); - - /* - * Snapshot target's format: -@@ -524,10 +557,10 @@ struct dm_tree_node *dm_tree_add_new_dev_with_udev_flags(struct dm_tree *tree, - * Set major and minor to 0 or uuid to NULL to get the root node. - */ - struct dm_tree_node *dm_tree_find_node(struct dm_tree *tree, -- uint32_t major, -- uint32_t minor); -+ uint32_t major, -+ uint32_t minor); - struct dm_tree_node *dm_tree_find_node_by_uuid(struct dm_tree *tree, -- const char *uuid); -+ const char *uuid); - - /* - * Use this to walk through all children of a given node. -@@ -559,8 +592,8 @@ int dm_tree_node_num_children(const struct dm_tree_node *node, uint32_t inverted - * Ignores devices that don't have a uuid starting with uuid_prefix. - */ - int dm_tree_deactivate_children(struct dm_tree_node *dnode, -- const char *uuid_prefix, -- size_t uuid_prefix_len); -+ const char *uuid_prefix, -+ size_t uuid_prefix_len); - /* - * Preload/create a device plus all dependencies. - * Ignores devices that don't have a uuid starting with uuid_prefix. -@@ -582,8 +615,8 @@ int dm_tree_activate_children(struct dm_tree_node *dnode, - * Ignores devices that don't have a uuid starting with uuid_prefix. - */ - int dm_tree_suspend_children(struct dm_tree_node *dnode, -- const char *uuid_prefix, -- size_t uuid_prefix_len); -+ const char *uuid_prefix, -+ size_t uuid_prefix_len); - - /* - * Skip the filesystem sync when suspending. -@@ -613,36 +646,36 @@ void dm_tree_retry_remove(struct dm_tree_node *dnode); - * Returns 1 if the tree walk has to be aborted. - */ - int dm_tree_children_use_uuid(struct dm_tree_node *dnode, -- const char *uuid_prefix, -- size_t uuid_prefix_len); -+ const char *uuid_prefix, -+ size_t uuid_prefix_len); - - /* - * Construct tables for new nodes before activating them. - */ - int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode, -- uint64_t size, -- const char *origin_uuid); -+ uint64_t size, -+ const char *origin_uuid); - int dm_tree_node_add_snapshot_target(struct dm_tree_node *node, -- uint64_t size, -- const char *origin_uuid, -- const char *cow_uuid, -- int persistent, -- uint32_t chunk_size); -+ uint64_t size, -+ const char *origin_uuid, -+ const char *cow_uuid, -+ int persistent, -+ uint32_t chunk_size); - int dm_tree_node_add_snapshot_merge_target(struct dm_tree_node *node, -- uint64_t size, -- const char *origin_uuid, -- const char *cow_uuid, -- const char *merge_uuid, -- uint32_t chunk_size); -+ uint64_t size, -+ const char *origin_uuid, -+ const char *cow_uuid, -+ const char *merge_uuid, -+ uint32_t chunk_size); - int dm_tree_node_add_error_target(struct dm_tree_node *node, -- uint64_t size); -+ uint64_t size); - int dm_tree_node_add_zero_target(struct dm_tree_node *node, -- uint64_t size); -+ uint64_t size); - int dm_tree_node_add_linear_target(struct dm_tree_node *node, -- uint64_t size); -+ uint64_t size); - int dm_tree_node_add_striped_target(struct dm_tree_node *node, -- uint64_t size, -- uint32_t stripe_size); -+ uint64_t size, -+ uint32_t stripe_size); - - #define DM_CRYPT_IV_DEFAULT UINT64_C(-1) /* iv_offset == seg offset */ - /* -@@ -659,7 +692,7 @@ int dm_tree_node_add_crypt_target(struct dm_tree_node *node, - uint64_t iv_offset, - const char *key); - int dm_tree_node_add_mirror_target(struct dm_tree_node *node, -- uint64_t size); -+ uint64_t size); - - /* Mirror log flags */ - #define DM_NOSYNC 0x00000001 /* Known already in sync */ -@@ -668,11 +701,11 @@ int dm_tree_node_add_mirror_target(struct dm_tree_node *node, - #define DM_CORELOG 0x00000008 /* In-memory log */ - - int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node, -- uint32_t region_size, -- unsigned clustered, -- const char *log_uuid, -- unsigned area_count, -- uint32_t flags); -+ uint32_t region_size, -+ unsigned clustered, -+ const char *log_uuid, -+ unsigned area_count, -+ uint32_t flags); - - int dm_tree_node_add_raid_target(struct dm_tree_node *node, - uint64_t size, -@@ -682,6 +715,22 @@ int dm_tree_node_add_raid_target(struct dm_tree_node *node, - uint64_t rebuilds, - uint64_t flags); - -+/* -+ * Defines bellow are based on kernel's dm-cache.c defines -+ * DM_CACHE_MIN_DATA_BLOCK_SIZE (32 * 1024 >> SECTOR_SHIFT) -+ * DM_CACHE_MAX_DATA_BLOCK_SIZE (1024 * 1024 * 1024 >> SECTOR_SHIFT) -+ */ -+#define DM_CACHE_MIN_DATA_BLOCK_SIZE (UINT32_C(64)) -+#define DM_CACHE_MAX_DATA_BLOCK_SIZE (UINT32_C(2097152)) -+/* -+ * Max supported size for cache pool metadata device. -+ * Limitation is hardcoded into the kernel and bigger device sizes -+ * are not accepted. -+ * -+ * Limit defined in drivers/md/dm-cache-metadata.h -+ */ -+#define DM_CACHE_METADATA_MAX_SECTORS DM_THIN_METADATA_MAX_SECTORS -+ - struct dm_tree_node_raid_params { - const char *raid_type; - -@@ -712,6 +761,23 @@ int dm_tree_node_add_raid_target_with_params(struct dm_tree_node *node, - uint64_t size, - struct dm_tree_node_raid_params *p); - -+/* Cache feature_flags */ -+#define DM_CACHE_FEATURE_WRITEBACK 0x00000001 -+#define DM_CACHE_FEATURE_WRITETHROUGH 0x00000002 -+ -+int dm_tree_node_add_cache_target(struct dm_tree_node *node, -+ uint64_t size, -+ const char *metadata_uuid, -+ const char *data_uuid, -+ const char *origin_uuid, -+ uint32_t chunk_size, -+ uint32_t feature_flags, /* DM_CACHE_FEATURE_* */ -+ unsigned core_argc, -+ char **core_argv, -+ char *policy_name, -+ unsigned policy_argc, -+ char **policy_argv); -+ - /* - * Replicator operation mode - * Note: API for Replicator is not yet stable -@@ -1083,7 +1149,7 @@ void dm_hash_remove(struct dm_hash_table *t, const char *key); - - void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key, uint32_t len); - int dm_hash_insert_binary(struct dm_hash_table *t, const void *key, uint32_t len, -- void *data); -+ void *data); - void dm_hash_remove_binary(struct dm_hash_table *t, const void *key, uint32_t len); - - unsigned dm_hash_get_num_entries(struct dm_hash_table *t); -diff --git a/libdm/libdm-common.c b/libdm/libdm-common.c -index 5ec5769..2ec66e7 100644 ---- a/libdm/libdm-common.c -+++ b/libdm/libdm-common.c -@@ -868,12 +868,27 @@ static int _selabel_lookup(const char *path, mode_t mode, - } - #endif - -+#ifdef HAVE_SELINUX -+static int _is_selinux_enabled(void) -+{ -+ static int _tested = 0; -+ static int _enabled; -+ -+ if (!_tested) { -+ _tested = 1; -+ _enabled = is_selinux_enabled(); -+ } -+ -+ return _enabled; -+} -+#endif -+ - int dm_prepare_selinux_context(const char *path, mode_t mode) - { - #ifdef HAVE_SELINUX - security_context_t scontext = NULL; - -- if (is_selinux_enabled() <= 0) -+ if (_is_selinux_enabled() <= 0) - return 1; - - if (path) { -@@ -901,7 +916,7 @@ int dm_set_selinux_context(const char *path, mode_t mode) - #ifdef HAVE_SELINUX - security_context_t scontext = NULL; - -- if (is_selinux_enabled() <= 0) -+ if (_is_selinux_enabled() <= 0) - return 1; - - if (!_selabel_lookup(path, mode, &scontext)) -diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c -index 42bb9e7..e513885 100644 ---- a/libdm/libdm-deptree.c -+++ b/libdm/libdm-deptree.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2013 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2005-2014 Red Hat, Inc. All rights reserved. - * - * This file is part of the device-mapper userspace tools. - * -@@ -27,6 +27,7 @@ - - /* Supported segment types */ - enum { -+ SEG_CACHE, - SEG_CRYPT, - SEG_ERROR, - SEG_LINEAR, -@@ -59,6 +60,7 @@ struct { - unsigned type; - const char *target; - } dm_segtypes[] = { -+ { SEG_CACHE, "cache" }, - { SEG_CRYPT, "crypt" }, - { SEG_ERROR, "error" }, - { SEG_LINEAR, "linear" }, -@@ -158,18 +160,24 @@ struct load_segment { - uint32_t stripe_size; /* Striped + raid */ - - int persistent; /* Snapshot */ -- uint32_t chunk_size; /* Snapshot */ -+ uint32_t chunk_size; /* Snapshot + cache */ - struct dm_tree_node *cow; /* Snapshot */ -- struct dm_tree_node *origin; /* Snapshot + Snapshot origin */ -+ struct dm_tree_node *origin; /* Snapshot + Snapshot origin + Cache */ - struct dm_tree_node *merge; /* Snapshot */ - - struct dm_tree_node *log; /* Mirror + Replicator */ - uint32_t region_size; /* Mirror + raid */ - unsigned clustered; /* Mirror */ - unsigned mirror_area_count; /* Mirror */ -- uint32_t flags; /* Mirror log */ -+ uint32_t flags; /* Mirror + raid + Cache */ - char *uuid; /* Clustered mirror log */ - -+ unsigned core_argc; /* Cache */ -+ char **core_argv; /* Cache */ -+ char *policy_name; /* Cache */ -+ unsigned policy_argc; /* Cache */ -+ char **policy_argv; /* Cache */ -+ - const char *cipher; /* Crypt */ - const char *chainmode; /* Crypt */ - const char *iv; /* Crypt */ -@@ -189,7 +197,7 @@ struct load_segment { - uint32_t max_recovery_rate; /* raid kB/sec/disk */ - uint32_t min_recovery_rate; /* raid kB/sec/disk */ - -- struct dm_tree_node *metadata; /* Thin_pool */ -+ struct dm_tree_node *metadata; /* Thin_pool + Cache */ - struct dm_tree_node *pool; /* Thin_pool, Thin */ - struct dm_tree_node *external; /* Thin */ - struct dm_list thin_messages; /* Thin_pool */ -@@ -530,7 +538,7 @@ static struct dm_tree_node *_find_dm_tree_node(struct dm_tree *dtree, - dev_t dev = MKDEV((dev_t)major, minor); - - return dm_hash_lookup_binary(dtree->devs, (const char *) &dev, -- sizeof(dev)); -+ sizeof(dev)); - } - - static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree, -@@ -699,8 +707,8 @@ static int _children_suspended(struct dm_tree_node *node, - * Set major and minor to zero for root of tree. - */ - struct dm_tree_node *dm_tree_find_node(struct dm_tree *dtree, -- uint32_t major, -- uint32_t minor) -+ uint32_t major, -+ uint32_t minor) - { - if (!major && !minor) - return &dtree->root; -@@ -712,7 +720,7 @@ struct dm_tree_node *dm_tree_find_node(struct dm_tree *dtree, - * Set uuid to NULL for root of tree. - */ - struct dm_tree_node *dm_tree_find_node_by_uuid(struct dm_tree *dtree, -- const char *uuid) -+ const char *uuid) - { - if (!uuid || !*uuid) - return &dtree->root; -@@ -1470,14 +1478,17 @@ out: - return r; - } - -+/* For preload pass only validate pool's transaction_id */ - static int _node_send_messages(struct dm_tree_node *dnode, - const char *uuid_prefix, -- size_t uuid_prefix_len) -+ size_t uuid_prefix_len, -+ int send) - { - struct load_segment *seg; - struct thin_message *tmsg; - uint64_t trans_id; - const char *uuid; -+ int have_messages; - - if (!dnode->info.exists || (dm_list_size(&dnode->props.segs) != 1)) - return 1; -@@ -1495,32 +1506,34 @@ static int _node_send_messages(struct dm_tree_node *dnode, - } - - if (!_thin_pool_status_transaction_id(dnode, &trans_id)) -- goto_bad; -+ return_0; - -+ have_messages = !dm_list_empty(&seg->thin_messages) ? 1 : 0; - if (trans_id == seg->transaction_id) { -- if (!dm_list_empty(&seg->thin_messages)) -+ dnode->props.send_messages = 0; /* messages already committed */ -+ if (have_messages) - log_debug_activation("Thin pool transaction_id matches %" PRIu64 - ", skipping messages.", trans_id); -- return 1; /* In sync - skip messages */ -+ return 1; - } - -- if (trans_id != (seg->transaction_id - 1)) { -+ /* Error if there are no stacked messages or id mismatches */ -+ if (trans_id != (seg->transaction_id - have_messages)) { - log_error("Thin pool transaction_id=%" PRIu64 ", while expected: %" PRIu64 ".", -- trans_id, seg->transaction_id - 1); -- goto bad; /* Nothing to send */ -+ trans_id, seg->transaction_id - have_messages); -+ return 0; - } - -+ if (!send) -+ return 1; /* transaction_id is matching */ -+ - dm_list_iterate_items(tmsg, &seg->thin_messages) - if (!(_thin_pool_node_message(dnode, tmsg))) -- goto_bad; -+ return_0; - -- return 1; --bad: -- /* Try to deactivate */ -- if (!(dm_tree_deactivate_children(dnode, uuid_prefix, uuid_prefix_len))) -- log_error("Failed to deactivate %s", dnode->name); -+ dnode->props.send_messages = 0; /* messages posted */ - -- return 0; -+ return 1; - } - - /* -@@ -1613,7 +1626,9 @@ static int _dm_tree_deactivate_children(struct dm_tree_node *dnode, - info.minor); - r = 0; - continue; -- } else if (info.suspended && info.live_table) -+ } -+ -+ if (info.suspended && info.live_table) - dec_suspended(); - - if (child->callback && -@@ -1856,14 +1871,9 @@ int dm_tree_activate_children(struct dm_tree_node *dnode, - * resume should continue further, just whole command - * has to report failure. - */ -- if (r && dnode->props.send_messages) { -- if (!(r = _node_send_messages(dnode, uuid_prefix, uuid_prefix_len))) -- stack; -- else -- dnode->props.send_messages = 0; /* messages posted */ -- } -- -- handle = NULL; -+ if (r && dnode->props.send_messages && -+ !(r = _node_send_messages(dnode, uuid_prefix, uuid_prefix_len, 1))) -+ stack; - - return r; - } -@@ -2235,11 +2245,11 @@ static int _raid_emit_segment_line(struct dm_task *dmt, uint32_t major, - EMIT_PARAMS(pos, " region_size %u", seg->region_size); - - for (i = 0; i < (seg->area_count / 2); i++) -- if (seg->rebuilds & (1 << i)) -+ if (seg->rebuilds & (1ULL << i)) - EMIT_PARAMS(pos, " rebuild %u", i); - - for (i = 0; i < (seg->area_count / 2); i++) -- if (seg->writemostly & (1 << i)) -+ if (seg->writemostly & (1ULL << i)) - EMIT_PARAMS(pos, " write_mostly %u", i); - - if (seg->writebehind) -@@ -2262,6 +2272,70 @@ static int _raid_emit_segment_line(struct dm_task *dmt, uint32_t major, - return 1; - } - -+static int _cache_emit_segment_line(struct dm_task *dmt, -+ struct load_segment *seg, -+ char *params, size_t paramsize) -+{ -+ int pos = 0; -+ unsigned i = 0; -+ unsigned feature_count; -+ struct seg_area *area; -+ char data[DM_FORMAT_DEV_BUFSIZE]; -+ char metadata[DM_FORMAT_DEV_BUFSIZE]; -+ char origin[DM_FORMAT_DEV_BUFSIZE]; -+ -+ /* Metadata Dev */ -+ if (!_build_dev_string(metadata, sizeof(metadata), seg->metadata)) -+ return_0; -+ -+ /* Cache Dev */ -+ if (!_build_dev_string(data, sizeof(origin), seg->pool)) -+ return_0; -+ -+ /* Origin Dev */ -+ dm_list_iterate_items(area, &seg->areas) -+ break; /* There is only ever 1 area */ -+ if (!_build_dev_string(origin, sizeof(data), area->dev_node)) -+ return_0; -+ -+ EMIT_PARAMS(pos, " %s %s %s", metadata, data, origin); -+ -+ /* Chunk size */ -+ EMIT_PARAMS(pos, " %u", seg->chunk_size); -+ -+ /* Features */ -+ feature_count = hweight32(seg->flags); -+ EMIT_PARAMS(pos, " %u", feature_count); -+ if (seg->flags & DM_CACHE_FEATURE_WRITETHROUGH) -+ EMIT_PARAMS(pos, " writethrough"); -+ else if (seg->flags & DM_CACHE_FEATURE_WRITEBACK) -+ EMIT_PARAMS(pos, " writeback"); -+ -+ /* Core Arguments (like 'migration_threshold') */ -+ if (seg->core_argc) { -+ EMIT_PARAMS(pos, " %u", seg->core_argc); -+ for (i = 0; i < seg->core_argc; i++) -+ EMIT_PARAMS(pos, " %s", seg->core_argv[i]); -+ } -+ -+ /* Cache Policy */ -+ if (!seg->policy_name) -+ EMIT_PARAMS(pos, " default 0"); -+ else { -+ EMIT_PARAMS(pos, " %s %u", seg->policy_name, seg->policy_argc); -+ if (seg->policy_argc % 2) { -+ log_error(INTERNAL_ERROR -+ "Cache policy arguments must be in " -+ " pairs"); -+ return 0; -+ } -+ for (i = 0; i < seg->policy_argc; i++) -+ EMIT_PARAMS(pos, " %s", seg->policy_argv[i]); -+ } -+ -+ return 1; -+} -+ - static int _thin_pool_emit_segment_line(struct dm_task *dmt, - struct load_segment *seg, - char *params, size_t paramsize) -@@ -2398,6 +2472,10 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major, - if (!_thin_emit_segment_line(dmt, seg, params, paramsize)) - return_0; - break; -+ case SEG_CACHE: -+ if (!_cache_emit_segment_line(dmt, seg, params, paramsize)) -+ return_0; -+ break; - } - - switch(seg->type) { -@@ -2409,6 +2487,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major, - case SEG_ZERO: - case SEG_THIN_POOL: - case SEG_THIN: -+ case SEG_CACHE: - break; - case SEG_CRYPT: - case SEG_LINEAR: -@@ -2550,13 +2629,16 @@ out: - return r; - } - -+/* -+ * Currently try to deactivate only nodes created during preload. -+ * New node is always attached to the front of activated_list -+ */ - static int _dm_tree_revert_activated(struct dm_tree_node *parent) - { - struct dm_tree_node *child; - -- dm_list_iterate_back_items_gen(child, &parent->activated, activated_list) { -- _dm_tree_revert_activated(child); -- log_debug("Reverting preloaded %s.", child->name); -+ dm_list_iterate_items_gen(child, &parent->activated, activated_list) { -+ log_debug_activation("Reverting %s.", child->name); - if (!_deactivate_node(child->name, child->info.major, child->info.minor, - &child->dtree->cookie, child->udev_flags, 0)) { - log_error("Unable to deactivate %s (%" PRIu32 -@@ -2564,6 +2646,8 @@ static int _dm_tree_revert_activated(struct dm_tree_node *parent) - child->info.minor); - return 0; - } -+ if (!_dm_tree_revert_activated(child)) -+ return_0; - } - - return 1; -@@ -2623,7 +2707,7 @@ int dm_tree_preload_children(struct dm_tree_node *dnode, - child->info.minor); - /* If the device was not previously active, we might as well remove this node. */ - if (!child->info.live_table && -- !_deactivate_node(child->name, child->info.major,child->info.minor, -+ !_deactivate_node(child->name, child->info.major, child->info.minor, - &child->dtree->cookie, child->udev_flags, 0)) - log_error("Unable to deactivate %s (%" PRIu32 - ":%" PRIu32 ")", child->name, child->info.major, -@@ -2633,9 +2717,22 @@ int dm_tree_preload_children(struct dm_tree_node *dnode, - continue; - } - -- if (!child->info.live_table) -+ if (!child->info.live_table) { - /* Collect newly introduced devices for revert */ -- dm_list_add(&dnode->activated, &child->activated_list); -+ dm_list_add_h(&dnode->activated, &child->activated_list); -+ -+ /* When creating new node also check transaction_id. */ -+ if (child->props.send_messages && -+ !_node_send_messages(child, uuid_prefix, uuid_prefix_len, 0)) { -+ stack; -+ if (!dm_udev_wait(dm_tree_get_cookie(dnode))) -+ stack; -+ dm_tree_set_cookie(dnode, 0); -+ (void) _dm_tree_revert_activated(dnode); -+ r = 0; -+ continue; -+ } -+ } - - /* Update cached info */ - child->info = newinfo; -@@ -2649,12 +2746,12 @@ int dm_tree_preload_children(struct dm_tree_node *dnode, - } - - if (update_devs_flag || -- (!dnode->info.exists && dnode->callback)) { -+ (r && !dnode->info.exists && dnode->callback)) { - if (!dm_udev_wait(dm_tree_get_cookie(dnode))) - stack; - dm_tree_set_cookie(dnode, 0); - -- if (!dnode->info.exists && dnode->callback && -+ if (r && !dnode->info.exists && dnode->callback && - !dnode->callback(dnode, DM_NODE_CALLBACK_PRELOADED, - dnode->callback_data)) - { -@@ -2724,8 +2821,8 @@ static struct load_segment *_add_segment(struct dm_tree_node *dnode, unsigned ty - } - - int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode, -- uint64_t size, -- const char *origin_uuid) -+ uint64_t size, -+ const char *origin_uuid) - { - struct load_segment *seg; - struct dm_tree_node *origin_node; -@@ -2755,12 +2852,12 @@ int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode, - } - - static int _add_snapshot_target(struct dm_tree_node *node, -- uint64_t size, -- const char *origin_uuid, -- const char *cow_uuid, -- const char *merge_uuid, -- int persistent, -- uint32_t chunk_size) -+ uint64_t size, -+ const char *origin_uuid, -+ const char *cow_uuid, -+ const char *merge_uuid, -+ int persistent, -+ uint32_t chunk_size) - { - struct load_segment *seg; - struct dm_tree_node *origin_node, *cow_node, *merge_node; -@@ -2873,7 +2970,7 @@ int dm_get_status_snapshot(struct dm_pool *mem, const char *params, - } - - int dm_tree_node_add_error_target(struct dm_tree_node *node, -- uint64_t size) -+ uint64_t size) - { - if (!_add_segment(node, SEG_ERROR, size)) - return_0; -@@ -2882,7 +2979,7 @@ int dm_tree_node_add_error_target(struct dm_tree_node *node, - } - - int dm_tree_node_add_zero_target(struct dm_tree_node *node, -- uint64_t size) -+ uint64_t size) - { - if (!_add_segment(node, SEG_ZERO, size)) - return_0; -@@ -2891,7 +2988,7 @@ int dm_tree_node_add_zero_target(struct dm_tree_node *node, - } - - int dm_tree_node_add_linear_target(struct dm_tree_node *node, -- uint64_t size) -+ uint64_t size) - { - if (!_add_segment(node, SEG_LINEAR, size)) - return_0; -@@ -2900,8 +2997,8 @@ int dm_tree_node_add_linear_target(struct dm_tree_node *node, - } - - int dm_tree_node_add_striped_target(struct dm_tree_node *node, -- uint64_t size, -- uint32_t stripe_size) -+ uint64_t size, -+ uint32_t stripe_size) - { - struct load_segment *seg; - -@@ -2936,11 +3033,11 @@ int dm_tree_node_add_crypt_target(struct dm_tree_node *node, - } - - int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node, -- uint32_t region_size, -- unsigned clustered, -- const char *log_uuid, -- unsigned area_count, -- uint32_t flags) -+ uint32_t region_size, -+ unsigned clustered, -+ const char *log_uuid, -+ unsigned area_count, -+ uint32_t flags) - { - struct dm_tree_node *log_node = NULL; - struct load_segment *seg; -@@ -2988,7 +3085,7 @@ int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node, - } - - int dm_tree_node_add_mirror_target(struct dm_tree_node *node, -- uint64_t size) -+ uint64_t size) - { - if (!_add_segment(node, SEG_MIRRORED, size)) - return_0; -@@ -3033,19 +3130,17 @@ int dm_tree_node_add_raid_target(struct dm_tree_node *node, - uint64_t rebuilds, - uint64_t flags) - { -- struct dm_tree_node_raid_params params; -- -- memset(¶ms, 0, sizeof(params)); -- params.raid_type = raid_type; -- params.region_size = region_size; -- params.stripe_size = stripe_size; -- params.rebuilds = rebuilds; -- params.flags = flags; -+ struct dm_tree_node_raid_params params = { -+ .raid_type = raid_type, -+ .region_size = region_size, -+ .stripe_size = stripe_size, -+ .rebuilds = rebuilds, -+ .flags = flags -+ }; - - return dm_tree_node_add_raid_target_with_params(node, size, ¶ms); - } - -- - /* - * Various RAID status versions include: - * Versions < 1.5.0 (4 fields): -@@ -3124,6 +3219,203 @@ bad: - return 0; - } - -+int dm_tree_node_add_cache_target(struct dm_tree_node *node, -+ uint64_t size, -+ const char *metadata_uuid, -+ const char *data_uuid, -+ const char *origin_uuid, -+ uint32_t chunk_size, -+ uint32_t feature_flags, /* DM_CACHE_FEATURE_* */ -+ unsigned core_argc, -+ char **core_argv, -+ char *policy_name, -+ unsigned policy_argc, -+ char **policy_argv) -+{ -+ int i; -+ struct load_segment *seg = NULL; -+ -+ for (i = 0; dm_segtypes[i].target && !seg; i++) { -+ if (strcmp("cache", dm_segtypes[i].target)) -+ continue; -+ if (!(seg = _add_segment(node, dm_segtypes[i].type, size))) -+ return_0; -+ } -+ -+ if (!seg) -+ return_0; -+ -+ if (!(seg->pool = dm_tree_find_node_by_uuid(node->dtree, -+ data_uuid))) { -+ log_error("Missing cache's data uuid %s.", -+ data_uuid); -+ return 0; -+ } -+ if (!_link_tree_nodes(node, seg->pool)) -+ return_0; -+ -+ if (!(seg->metadata = dm_tree_find_node_by_uuid(node->dtree, -+ metadata_uuid))) { -+ log_error("Missing cache's metadata uuid %s.", -+ metadata_uuid); -+ return 0; -+ } -+ if (!_link_tree_nodes(node, seg->metadata)) -+ return_0; -+ -+ seg->chunk_size = chunk_size; -+ -+ seg->flags = feature_flags; -+ -+ /* FIXME: validation missing */ -+ -+ seg->core_argc = core_argc; -+ seg->core_argv = core_argv; -+ -+ seg->policy_name = policy_name; -+ seg->policy_argc = policy_argc; -+ seg->policy_argv = policy_argv; -+ -+ return 1; -+} -+ -+static const char *advance_to_next_word(const char *str, int count) -+{ -+ int i; -+ const char *p; -+ -+ for (p = str, i = 0; i < count; i++, p++) -+ if (!(p = strchr(p, ' '))) -+ return NULL; -+ -+ return p; -+} -+ -+/* -+ * <#used metadata blocks>/<#total metadata blocks> -+ * <#used cache blocks>/<#total cache blocks> -+ * <#read hits> <#read misses> <#write hits> <#write misses> -+ * <#demotions> <#promotions> <#dirty> <#features> * -+ * <#core args> * <#policy args> * -+ * -+ * metadata block size : Fixed block size for each metadata block in -+ * sectors -+ * #used metadata blocks : Number of metadata blocks used -+ * #total metadata blocks : Total number of metadata blocks -+ * cache block size : Configurable block size for the cache device -+ * in sectors -+ * #used cache blocks : Number of blocks resident in the cache -+ * #total cache blocks : Total number of cache blocks -+ * #read hits : Number of times a READ bio has been mapped -+ * to the cache -+ * #read misses : Number of times a READ bio has been mapped -+ * to the origin -+ * #write hits : Number of times a WRITE bio has been mapped -+ * to the cache -+ * #write misses : Number of times a WRITE bio has been -+ * mapped to the origin -+ * #demotions : Number of times a block has been removed -+ * from the cache -+ * #promotions : Number of times a block has been moved to -+ * the cache -+ * #dirty : Number of blocks in the cache that differ -+ * from the origin -+ * #feature args : Number of feature args to follow -+ * feature args : 'writethrough' (optional) -+ * #core args : Number of core arguments (must be even) -+ * core args : Key/value pairs for tuning the core -+ * e.g. migration_threshold -+ * *policy name : Name of the policy -+ * #policy args : Number of policy arguments to follow (must be even) -+ * policy args : Key/value pairs -+ * e.g. sequential_threshold -+ */ -+int dm_get_status_cache(struct dm_pool *mem, const char *params, -+ struct dm_status_cache **status) -+{ -+ int i, feature_argc; -+ char *str; -+ const char *p, *pp; -+ struct dm_status_cache *s; -+ -+ if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_cache)))) -+ return_0; -+ -+ /* Read in args that have definitive placement */ -+ if (sscanf(params, -+ " %" PRIu32 -+ " %" PRIu64 "/%" PRIu64 -+ " %" PRIu32 -+ " %" PRIu64 "/%" PRIu64 -+ " %" PRIu64 " %" PRIu64 -+ " %" PRIu64 " %" PRIu64 -+ " %" PRIu64 " %" PRIu64 -+ " %" PRIu64 -+ " %d", -+ &s->metadata_block_size, -+ &s->metadata_used_blocks, &s->metadata_total_blocks, -+ &s->block_size, /* AKA, chunk_size */ -+ &s->used_blocks, &s->total_blocks, -+ &s->read_hits, &s->read_misses, -+ &s->write_hits, &s->write_misses, -+ &s->demotions, &s->promotions, -+ &s->dirty_blocks, -+ &feature_argc) != 14) -+ goto bad; -+ -+ /* Now jump to "features" section */ -+ if (!(p = advance_to_next_word(params, 12))) -+ goto bad; -+ -+ /* Read in features */ -+ for (i = 0; i < feature_argc; i++) { -+ if (!strncmp(p, "writethrough ", 13)) -+ s->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH; -+ else if (!strncmp(p, "writeback ", 10)) -+ s->feature_flags |= DM_CACHE_FEATURE_WRITEBACK; -+ else -+ log_error("Unknown feature in status: %s", params); -+ -+ if (!(p = advance_to_next_word(p, 1))) -+ goto bad; -+ } -+ -+ /* Read in core_args. */ -+ if (sscanf(p, "%d ", &s->core_argc) != 1) -+ goto bad; -+ if (s->core_argc && -+ (!(s->core_argv = dm_pool_zalloc(mem, sizeof(char *) * s->core_argc)) || -+ !(p = advance_to_next_word(p, 1)) || -+ !(str = dm_pool_strdup(mem, p)) || -+ !(p = advance_to_next_word(p, s->core_argc)) || -+ (dm_split_words(str, s->core_argc, 0, s->core_argv) != s->core_argc))) -+ goto bad; -+ -+ /* Read in policy args */ -+ pp = p; -+ if (!(p = advance_to_next_word(p, 1)) || -+ !(s->policy_name = dm_pool_zalloc(mem, (p - pp)))) -+ goto bad; -+ if (sscanf(pp, "%s %d", s->policy_name, &s->policy_argc) != 2) -+ goto bad; -+ if (s->policy_argc && -+ (!(s->policy_argv = dm_pool_zalloc(mem, sizeof(char *) * s->policy_argc)) || -+ !(p = advance_to_next_word(p, 1)) || -+ !(str = dm_pool_strdup(mem, p)) || -+ (dm_split_words(str, s->policy_argc, 0, s->policy_argv) != s->policy_argc))) -+ goto bad; -+ -+ *status = s; -+ return 1; -+ -+bad: -+ log_error("Failed to parse cache params: %s", params); -+ dm_pool_free(mem, s); -+ *status = NULL; -+ -+ return 0; -+} -+ - int dm_tree_node_add_replicator_target(struct dm_tree_node *node, - uint64_t size, - const char *rlog_uuid, -@@ -3614,9 +3906,9 @@ static int _add_area(struct dm_tree_node *node, struct load_segment *seg, struct - } - - int dm_tree_node_add_target_area(struct dm_tree_node *node, -- const char *dev_name, -- const char *uuid, -- uint64_t offset) -+ const char *dev_name, -+ const char *uuid, -+ uint64_t offset) - { - struct load_segment *seg; - struct stat info; -diff --git a/liblvm/lvm_lv.c b/liblvm/lvm_lv.c -index 3b0e18d..d89e8ae 100644 ---- a/liblvm/lvm_lv.c -+++ b/liblvm/lvm_lv.c -@@ -507,7 +507,7 @@ static int _lv_set_pool_params(struct lvcreate_params *lp, - - lp->pool = pool; - -- lp->create_thin_pool = 1; -+ lp->create_pool = 1; - lp->segtype = get_segtype_from_string(vg->cmd, "thin-pool"); - lp->stripes = 1; - -@@ -757,17 +757,15 @@ struct lvm_property_value lvm_lv_params_get_property( - const lv_create_params_t params, - const char *name) - { -- struct lvm_property_value rc = { -- .is_valid = 0 -- }; -- struct saved_env e = store_user_env(params->vg->cmd); -+ struct lvm_property_value rc = { .is_valid = 0 }; - - if (params && params->magic == LV_CREATE_PARAMS_MAGIC) { -+ struct saved_env e = store_user_env(params->vg->cmd); - rc = get_property(NULL, NULL, NULL, NULL, NULL, ¶ms->lvp, NULL, name); -- } else { -+ restore_user_env(&e); -+ } else - log_error("Invalid lv_create_params parameter"); -- } -- restore_user_env(&e); -+ - return rc; - } - -@@ -775,15 +773,14 @@ int lvm_lv_params_set_property(lv_create_params_t params, const char *name, - struct lvm_property_value *prop) - { - int rc = -1; -- struct saved_env e = store_user_env(params->vg->cmd); - - if (params && params->magic == LV_CREATE_PARAMS_MAGIC) { -+ struct saved_env e = store_user_env(params->vg->cmd); - rc = set_property(NULL, NULL, NULL, ¶ms->lvp, NULL, name, prop); -- } else { -+ restore_user_env(&e); -+ } else - log_error("Invalid lv_create_params parameter"); -- } - -- restore_user_env(&e); - return rc; - } - -diff --git a/make.tmpl.in b/make.tmpl.in -index 65b1da0..7d7d701 100644 ---- a/make.tmpl.in -+++ b/make.tmpl.in -@@ -84,6 +84,7 @@ pkgconfigdir = $(usrlibdir)/pkgconfig - initdir = $(DESTDIR)$(sysconfdir)/rc.d/init.d - systemd_unit_dir = $(DESTDIR)@systemdsystemunitdir@ - systemd_generator_dir = $(DESTDIR)@systemdutildir@/system-generators -+systemd_dir = $(DESTDIR)@systemdutildir@ - tmpfiles_dir = $(DESTDIR)@tmpfilesdir@ - ocf_scriptdir = $(DESTDIR)@OCFDIR@ - pyexecdir = $(DESTDIR)$(prefix) -diff --git a/man/lvchange.8.in b/man/lvchange.8.in -index 49337e4..64231c8 100644 ---- a/man/lvchange.8.in -+++ b/man/lvchange.8.in -@@ -74,8 +74,9 @@ logical volumes. If autoactivation option is used (\-aay), - the logical volume is activated only if it matches an item in - the activation/auto_activation_volume_list set in lvm.conf. - If this list is not set, then all volumes are considered for --autoactivation. The autoactivation is not yet supported for --logical volumes that are part of partial or clustered volume groups. -+activation. The \-aay option should be also used during system -+boot so it's possible to select which volumes to activate using -+the activation/auto_activation_volume_list setting. - .IP - If clustered locking is enabled, -aey will activate exclusively - on one node and -aly will activate only on the local node. -diff --git a/man/lvconvert.8.in b/man/lvconvert.8.in -index c8cb2dc..190e221 100644 ---- a/man/lvconvert.8.in -+++ b/man/lvconvert.8.in -@@ -113,6 +113,30 @@ lvconvert \- convert a logical volume from linear to mirror or snapshot - .RB [ \-v | \-\-verbose ] - .RB [ \-\-version ] - .sp -+.B lvconvert \-\-type cache-pool -+.RB [ \-c | \-\-chunksize -+.IR ChunkSize [ bBsSkKmMgG ]] -+.RB [ \-\-cachemode -+.RI { writeback | writethrough }] -+.RB [[ \-\-poolmetadata -+.IR CachePoolMetadataLogicalVolume { Name | Path }] -+| -+.RB [ \-\-poolmetadatasize -+.IR CachePoolMetadataSize [ bBsSkKmMgG ]] -+.IR LogicalVolume [ Path ] -+.RI [ PhysicalVolume [ Path ][ :PE [ -PE ]]...] -+.RB [ \-h | \-? | \-\-help ] -+.RB [ \-v | \-\-verbose ] -+.RB [ \-\-version ] -+.sp -+.B lvconvert \-\-type cache -+.RB \-\-cachepool -+.IR CachePoolLV { Name | Path } -+.IR LogicalVolume [ Path ] -+.RB [ \-h | \-? | \-\-help ] -+.RB [ \-v | \-\-verbose ] -+.RB [ \-\-version ] -+.sp - - .SH DESCRIPTION - lvconvert is used to change the segment type (i.e. linear, mirror, etc) or -@@ -146,6 +170,10 @@ arguments is required. - .BR \-b ", " \-\-background - Run the daemon in the background. - .TP -+.BR \-\-cachepool " " \fCachePoolLV -+This argument is necessary when converting a logical volume to a cache LV. -+For more information on cache pool LVs and cache LVs, see \fBlvm\fP(8). -+.TP - .BR \-m ", " \-\-mirrors " " \fIMirrors - Specifies the degree of the mirror you wish to create. - For example, "\fB-m 1\fP" would convert the original logical -@@ -176,9 +204,9 @@ A mirror is divided into regions of this size (in MB), and the mirror log - uses this granularity to track which regions are in sync. - .TP - .B \-\-type \fISegmentType --Used to convert a logical volume to another segment type or to explicitly state --the desired RAID1 segment type (\fImirror\fP or \fIraid1\fP) when converting --a linear logical volume to a mirror with the \fB-m\fP argument. -+Used to convert a logical volume to another segment type, like cache-pool, -+cache, raid1, or thin-pool. When converting a logical volume to a cache LV, -+the \-\-cachepool argument is required. - .TP - .BR \-i ", " \-\-interval " " \fISeconds - Report progress as a percentage at regular intervals. -@@ -447,6 +475,18 @@ For the read-only external origin use the new name "vg00/external". - .sp - .B lvconvert \-\-thinpool vg00/lvpool \-\-originname external -T vg00/origin - -+Convert an existing logical volume to a cache pool LV using the -+given cache metadata LV. -+.sp -+.B lvconvert --type cache-pool --poolmetadata vg00/lvx_meta vg00/lvx_data -+.br -+.B lvrename vg00/lvx_data vg00/lvx_cachepool -+ -+Convert an existing logical volume to a cache LV using the given -+cache pool LV. -+.sp -+.B lvconvert \-\-type cache \-\-cachepool vg00/lvx_cachepool vg00/lvx -+ - .SH SEE ALSO - .BR lvm (8), - .BR lvm.conf (5), -diff --git a/man/lvcreate.8.in b/man/lvcreate.8.in -index 4a769cb..325baad 100644 ---- a/man/lvcreate.8.in -+++ b/man/lvcreate.8.in -@@ -59,6 +59,8 @@ lvcreate \- create a logical volume in an existing volume group - .RI { ReadAheadSectors | auto | none }] - .RB [ \-t | \-\-test ] - .RB [ \-T | \-\-thin -+.RB [ \-\-cachemode -+.IR { writeback | writethrough } - .RB [ \-c | \-\-chunksize - .IR ChunkSize [ bBsSkKmMgG ]] - .RB [ \-\-discards -@@ -155,14 +157,29 @@ use \fBlvs\fP command where the state of the flag is reported within - .TP - .IR \fB\-K ", " \fB\-\-ignoreactivationskip - Ignore the flag to skip Logical Volumes during activation. -+ -+.TP -+.BR \-\-cachemode " " { writeback | writethrough } -+Specifying a cache mode determines when the writes to a cache LV -+are considered complete. When \fIwriteback\fP is specified, a write is -+considered complete as soon as it is stored in the cache pool LV. -+If \fIwritethough\fP is specified, a write is considered complete only -+when it has been stored in the cache pool LV and on the origin LV. -+While \fIwritethrough\fP may be slower for writes, it is more -+resilient if something should happen to a device associated with the -+cache pool LV. -+ - .TP - .BR \-c ", " \-\-chunksize " " \fIChunkSize [ \fIbBsSkKmMgG ] --Gives the size of chunk for snapshot and thin pool logical volumes. -+Gives the size of chunk for snapshot, cache pool and thin pool logical volumes. - Default unit is in kilobytes. - .br - For snapshots the value must be power of 2 between 4KiB and 512KiB - and the default value is 4. - .br -+For cache pool LVs the value must be between 32KiB and 1GiB. The default -+is 64KiB. Values must be a multiple of 32KiB. -+.br - For thin pools the value must be between 64KiB and - 1GiB and the default value starts with 64 and scales - up to fit the pool metadata size within 128MiB, -@@ -188,7 +205,11 @@ the extra devices which are necessary for parity are - internally accounted for. Specifying - .BI \-i 3 - would use 3 devices for striped logical volumes, --4 devices for RAID 4/5, and 5 devices for RAID 6. -+4 devices for RAID 4/5, and 5 devices for RAID 6. Alternatively, -+RAID 4/5/6 will stripe across all PVs in the volume group or -+all of the PVs specified if the -+.B \-i -+argument is omitted. - .TP - .BR \-I ", " \-\-stripesize " " \fIStripeSize - Gives the number of kilobytes for the granularity of the stripes. -@@ -203,14 +224,17 @@ is specified. - .TP - .IR \fB\-l ", " \fB\-\-extents " " LogicalExtentsNumber [ % { VG | PVS | FREE | ORIGIN }] - Gives the number of logical extents to allocate for the new --logical volume. -+logical volume. The total number of physical extents allocated will be -+greater than this, for example, if the volume is mirrored. - The number can also be expressed as a percentage of the total space - in the Volume Group with the suffix \fI%VG\fR, as a percentage of the - remaining free space in the Volume Group with the suffix \fI%FREE\fR, as a - percentage of the remaining free space for the specified - PhysicalVolume(s) with the suffix \fI%PVS\fR, or (for a snapshot) as a - percentage of the total space in the Origin Logical Volume with the --suffix \fI%ORIGIN\fR. -+suffix \fI%ORIGIN\fR. When expressed as a percentage, the number is treated -+as an approximate upper limit for the total number of physical extents -+to be allocated (including extents used by any mirrors, for example). - .TP - .IR \fB\-L ", " \fB\-\-size " " LogicalVolumeSize [ bBsSkKmMgGtTpPeE ] - Gives the size to allocate for the new logical volume. -@@ -382,6 +406,7 @@ commandline switch alias that will enable their use - However, this argument must be used when no existing - commandline switch alias is available for the desired type, - as is the case with -+.IR cache , - .IR error , - .IR raid1 , - .IR raid4 , -@@ -390,6 +415,9 @@ as is the case with - .IR raid10 - or - .IR zero . -+Note that the cache segment type requires a dm-cache kernel module version -+1.3.0 or greater. -+ - .TP - .BR \-V ", " \-\-virtualsize " " \fIVirtualSize [ \fIbBsSkKmMgGtTpPeE ] - Creates a sparse device of the given size (in MiB by default) using a snapshot -@@ -471,8 +499,14 @@ a parity drive for a total of 4 devices) and a stripesize of 64KiB: - .sp - .B lvcreate \-\-type raid5 \-L 5G \-i 3 \-I 64 \-n my_lv vg00 - -+Creates a RAID5 logical volume "vg00/my_lv", using all of the free -+space in the VG and spanning all the PVs in the VG: -+.sp -+.B lvcreate \-\-type raid5 \-l 100%FREE \-n my_lv vg00 -+ - Creates a 5GiB RAID10 logical volume "vg00/my_lv", with 2 stripes on --2 2-way mirrors. Note that the \fB-i\fP and \fB-m\fP arguments behave differently. -+2 2-way mirrors. Note that the \fB-i\fP and \fB-m\fP arguments behave -+differently. - The \fB-i\fP specifies the number of stripes. - The \fB-m\fP specifies the number of - .B additional -@@ -499,6 +533,23 @@ in vg00 that will use an existing thin pool "vg00/pool": - .sp - .B lvcreate -s --thinpool vg00/pool origin - -+Create a cache pool LV that can later be used to cache one -+logical volume. -+.sp -+.B lvcreate --type cache-pool -L 1G -n my_lv_cachepool vg /dev/fast1 -+ -+If there is an existing cache pool LV, create the large slow -+device (i.e. the origin LV) and link it to the supplied cache pool LV, -+creating a cache LV. -+.sp -+.B lvcreate --type cache -L 100G -n my_lv vg/my_lv_cachepool /dev/slow1 -+ -+If there is an existing logical volume, create the small and fast -+cache pool LV and link it to the supplied existing logical -+volume (i.e. the origin LV), creating a cache LV. -+.sp -+.B lvcreate --type cache -L 1G -n my_lv_cachepool vg/my_lv /dev/fast1 -+ - .SH SEE ALSO - .BR lvm (8), - .BR lvm.conf (5), -diff --git a/man/lvextend.8.in b/man/lvextend.8.in -index c51a9dc..d9bc0c8 100644 ---- a/man/lvextend.8.in -+++ b/man/lvextend.8.in -@@ -45,6 +45,8 @@ Proceed with size extension without prompting. - Extend or set the logical volume size in units of logical extents. - With the '\fI+\fP' sign the value is added to the actual size - of the logical volume and without it, the value is taken as an absolute one. -+The total number of physical extents allocated will be -+greater than this, for example, if the volume is mirrored. - The number can also be expressed as a percentage of the total space - in the Volume Group with the suffix \fI%VG\fP, relative to the existing - size of the Logical Volume with the suffix \fI%LV\fP, of the remaining -@@ -53,6 +55,11 @@ as a percentage of the remaining free space in the Volume Group - with the suffix \fI%FREE\fP, or (for a snapshot) as a percentage of the total - space in the Origin Logical Volume with the suffix \fI%ORIGIN\fP. - The resulting value is rounded upward. -+N.B. In a future release, when expressed as a percentage with PVS, VG or FREE, -+the number will be treated as an approximate upper limit for the total number -+of physical extents to be allocated (including extents used by any mirrors, for -+example). The code may currently allocate more space than you might otherwise -+expect. - .TP - .IR \fB\-L ", " \fB\-\-size " [" + ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ] - Extend or set the logical volume size in units of megabytes. -diff --git a/man/lvm.8.in b/man/lvm.8.in -index d78281a..39e47d3 100644 ---- a/man/lvm.8.in -+++ b/man/lvm.8.in -@@ -56,6 +56,8 @@ loading \fBlvm.conf\fP(5) and any other configuration files. - .TP - \fBsegtypes\fP \(em Display recognised Logical Volume segment types. - .TP -+\fBtags\fP \(em Display any tags defined on this host. -+.TP - \fBversion\fP \(em Display version information. - .LP - .SH COMMANDS -@@ -301,6 +303,12 @@ is executed. - The Volume Group name that is assumed for - any reference to a Logical Volume that doesn't specify a path. - Not set by default. -+.TP -+.B LVM_LVMETAD_PIDFILE -+Path for the lvmetad pid file. -+.TP -+.B LVM_LVMETAD_SOCKET -+Path for the lvmetad socket file. - .SH VALID NAMES - The following characters are valid for VG and LV names: - .B a-z A-Z 0-9 + _ . - -@@ -381,6 +389,197 @@ discretion over the layout. - To view the way the allocation process currently works in any specific - case, read the debug logging output, for example by adding \fB\-vvvv\fP to - a command. -+ -+.SH LOGICAL VOLUME TYPES -+Some logical volume types are simple to create and can be done with a -+single \fBlvcreate\fP(8) command. The linear and striped logical -+volume types are an example of this. Other logical volume types may -+require more than one command to create. The cache and thin provisioning -+types are examples of this. -+ -+.br -+.SS Cache -+The \fIcache\fP logical volume type uses a small and fast LV to improve -+the performance of a large and slow LV. It does this by storing the -+frequently used blocks on the faster LV. -+LVM refers to the small fast LV as a \fBcache pool LV\fP. The large -+slow LV is called the \fBorigin LV\fP. Due to requirements from dm-cache -+(the kernel driver), LVM further splits the cache pool LV into two -+devices - the \fBcache data LV\fP and \fBcache metadata LV\fP. The cache -+data LV is where copies of data blocks are kept from the -+origin LV to increase speed. The cache metadata LV holds the -+accounting information that specifies where data blocks are stored (e.g. -+on the origin LV or on the cache data LV). Users should be familiar with -+these LVs if they wish to create the best and most robust cached -+logical volumes. -+ -+.SS Cache Terms -+.nf -+origin LV OriginLV large slow LV -+cache data LV CacheDataLV small fast LV for cache pool data -+cache metadata LV CacheMetaLV small fast LV for cache pool metadata -+cache pool LV CachePoolLV CacheDataLV + CacheMetaLV -+cache LV CacheLV OriginLV + CachePoolLV -+.fi -+ -+.SS Cache Steps -+The steps to create a logical volume of \fIcache\fP type are as follows: -+.TP -+0. -+Create an LV or identify an existing LV to be the origin LV. -+.TP -+1. -+Create the cache data LV. The size of this LV is the size of the cache -+and will be reported as the size of the cache pool LV. -+.TP -+2. -+Create the cache metadata LV. -+The size of this LV should be 1000 times smaller than the cache data LV -+with a minimum size of 8MiB. -+.TP -+3. -+Create the cache pool LV by combining the cache data LV (from step 1) -+and cache metadata LV (from step 2). When performing this step, -+behavioral characteristics of the cache pool LV can be set. -+The name of the cache pool LV takes the name of the cache data LV and -+the cache data LV and cache metadata LV are renamed -+to CachePoolLV_cdata and CachePoolLV_cmeta. -+.TP -+4. -+Create a cache LV by linking the cache pool LV to the origin LV. -+The user accessible cache LV takes the name of the origin LV, -+while the origin LV becomes a hidden LV with the name -+OriginLV_corig. Users can perform this step while the origin LV -+is in use. -+ -+.P -+The steps above represent the best way to create a cache LV. -+They provide the most options and have the ability to create the -+most robust logical volumes. The examples below illustrate how these -+steps might be used in practice. -+ -+.SS Cache Commands -+.nf -+0. create OriginLV -+lvcreate -L LargeSize -n OriginLV VG SlowPVs -+ -+1. create CacheDataLV -+lvcreate -L CacheSize -n CacheDataLV VG FastPVs -+ -+2. create CacheMetaLV -+lvcreate -L MetaSize -n CacheMetaLV VG FastPVs -+ -+3. create CachePoolLV -+lvconvert --type cache-pool --poolmetadata VG/CacheMetaLV VG/CacheDataLV -+CachePoolLV takes the name of CacheDataLV. -+CacheDataLV is renamed CachePoolLV_cdata and becomes hidden. -+CacheMetaLV is renamed CachePoolLV_cmeta and becomes hidden. -+ -+4. create CacheLV -+lvconvert --type cache --cachepool VG/CachePoolLV VG/OriginLV -+CacheLV takes the name of OriginLV. -+OriginLV is renamed OriginLV_corig and becomes hidden. -+.fi -+ -+.SS Cache Examples -+ -+.B Example 1: -+Creating a simple cache LV. -+.br -+ -+.nf -+0. Create the origin LV -+# lvcreate -L 10G -n lvx vg /dev/slow_dev -+ -+1. Create a cache data LV -+# lvcreate -L 1G -n lvx_cache vg /dev/fast_dev -+ -+2. Create a cache metadata LV (~1/1000th size of CacheDataLV or 8MiB) -+# lvcreate -L 8M -n lvx_cache_meta vg /dev/fast_dev -+ -+3. Create a cache pool LV, combining cache data LV and cache metadata LV -+# lvconvert --type cache-pool --poolmetadata vg/lvx_cache_meta \\ -+ vg/lvx_cache -+ -+4. Create a cached LV by combining the cache pool LV and origin LV -+# lvconvert --type cache --cachepool vg/lvx_cache vg/lvx -+.fi -+ -+.B Example 2: -+Creating a cache LV with a fault tolerant cache pool LV. -+ -+Users who are concerned about the possibility of failures in their fast devices -+that could lead to data loss might consider making their cache pool sub-LVs -+redundant. Example 2 illustrates how to do that. Note that only steps -+1 & 2 change. -+ -+.nf -+0. Create an origin LV we wish to cache -+# lvcreate -L 10G -n lvx vg /dev/slow_devs -+ -+1. Create a 2-way RAID1 cache data LV -+# lvcreate --type raid1 -m 1 -L 1G -n lvx_cache vg \\ -+ /dev/fast1 /dev/fast2 -+ -+2. Create a 2-way RAID1 cache metadata LV -+# lvcreate --type raid1 -m 1 -L 8M -n lvx_cache_meta vg \\ -+ /dev/fast1 /dev/fast2 -+ -+3. Create a cache pool LV combining cache data LV and cache metadata LV -+# lvconvert --type cache-pool --poolmetadata vg/lvx_cache_meta \\ -+ vg/lvx_cache -+ -+4. Create a cached LV by combining the cache pool LV and origin LV -+# lvconvert --type cache --cachepool vg/lvx_cache vg/lvx -+.fi -+ -+.B Example 3: -+Creating a simple cache LV with \fIwritethough\fP caching. -+ -+Some users wish to ensure that any data written will be stored both in the -+cache pool LV and on the origin LV. The loss of a device associated with -+the cache pool LV in this case would not mean the loss of any data. When -+combining the cache data LV and the cache metadata LV to form the cache pool -+LV, properties of the cache can be specified - in this case, -+\fIwritethrough\fP vs. \fIwriteback\fP. Note that only step 3 is affected -+in this case. -+ -+.nf -+0. Create an origin LV we wish to cache (yours may already exist) -+# lvcreate -L 10G -n lvx vg /dev/slow -+ -+1. Create a cache data LV -+# lvcreate -L 1G -n lvx_cache vg /dev/fast -+ -+2. Create a cache metadata LV -+# lvcreate -L 8M -n lvx_cache_meta vg /dev/fast -+ -+3. Create a cache pool LV specifying cache mode "writethrough" -+# lvconvert --type cache-pool --poolmetadata vg/lvx_cache_meta \\ -+ --cachemode writethrough vg/lvx_cache -+ -+4. Create a cache LV by combining the cache pool LV and origin LV -+# lvconvert --type cache --cachepool vg/lvx_cache vg/lvx -+.fi -+ -+.SS Removing Cache Logical Volumes -+If you wish to remove all logical volumes associated with a cache -+LV, you must remove both top-level, user-visible devices. -+The cache metadata LV and cache data LV cannot be removed -+directly. If only the cache pool LV is specfied for removal, any cached -+blocks not yet on the origin LV will be flush, the cache pool LV will be -+removed, and the now un-cached origin LV will remain. If the user -+specifies a cache LV for removal, then the origin LV is -+removed and only the cache pool LV will remain. The cache pool LV can then -+be used to create another cache LV with a different origin LV if desired. -+ -+When users intend to remove all logical volumes associated with a -+cache LV, it is generally better to start with the origin LV and then -+remove the cache pool LV. If the operations are performed in the -+reverse order, the user will have to wait for the contents of the -+cache pool LV to be flushed before the origin LV is removed. This -+could take some time. -+ - .SH DIAGNOSTICS - All tools return a status code of zero on success or non-zero on failure. - .SH FILES -diff --git a/man/lvm.conf.5.in b/man/lvm.conf.5.in -index 2786df2..73fcf47 100644 ---- a/man/lvm.conf.5.in -+++ b/man/lvm.conf.5.in -@@ -102,7 +102,7 @@ e.g. backup { - .br - An assignment associates a type with an identifier. - .br --e.g. max_archives = 42 -+e.g. level = 7 - .br - .TP - .BR array " = '" [ "' ( " type " '" , "')* " type " '" ] "' | '" [ "' '" ] ' -diff --git a/man/lvreduce.8.in b/man/lvreduce.8.in -index 2c38f5b..2b0f3f8 100644 ---- a/man/lvreduce.8.in -+++ b/man/lvreduce.8.in -@@ -51,6 +51,8 @@ Reduce or set the logical volume size in units of logical extents. - With the \fI-\fP sign the value will be subtracted from - the logical volume's actual size and without it the value will be taken - as an absolute size. -+The total number of physical extents freed will be greater than this logical -+value if, for example, the volume is mirrored. - The number can also be expressed as a percentage of the total space - in the Volume Group with the suffix \fI%VG\fP, relative to the existing - size of the Logical Volume with the suffix \fI%LV\fP, as a percentage of the -@@ -59,6 +61,10 @@ a snapshot) as a percentage of the total space in the Origin Logical - Volume with the suffix \fI%ORIGIN\fP. - The resulting value for the subtraction is rounded downward, for the absolute - size it is rounded upward. -+N.B. In a future release, when expressed as a percentage with VG or FREE, the -+number will be treated as an approximate total number of physical extents to be -+freed (including extents used by any mirrors, for example). The code may -+currently release more space than you might otherwise expect. - .TP - .IR \fB\-L ", " \fB\-\-size " [" \- ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ] - Reduce or set the logical volume size in units of megabytes. -diff --git a/man/lvresize.8.in b/man/lvresize.8.in -index 3606762..75d20a0 100644 ---- a/man/lvresize.8.in -+++ b/man/lvresize.8.in -@@ -49,6 +49,8 @@ Resize underlying filesystem together with the logical volume using - Change or set the logical volume size in units of logical extents. - With the \fI+\fP or \fI-\fP sign the value is added to or subtracted from the actual size - of the logical volume and without it, the value is taken as an absolute one. -+The total number of physical extents affected will be -+greater than this if, for example, the volume is mirrored. - The number can also be expressed as a percentage of the total space - in the Volume Group with the suffix \fI%VG\fP, relative to the existing - size of the Logical Volume with the suffix \fI%LV\fP, as a percentage of -@@ -58,6 +60,11 @@ Volume Group with the suffix \fI%FREE\fP, or (for a snapshot) as a percentage - of the total space in the Origin Logical Volume with the suffix \fI%ORIGIN\fP. - The resulting value is rounded downward for the subtraction otherwise - it is rounded upward. -+N.B. In a future release, when expressed as a percentage with PVS, VG or FREE, -+the number will be treated as an approximate total number of physical extents -+to be allocated or freed (including extents used by any mirrors, for example). -+The code may currently allocate or remove more space than you might otherwise -+expect. - .TP - .IR \fB\-L ", " \fB\-\-size " [" + | - ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ] - Change or set the logical volume size in units of megabytes. -@@ -88,7 +95,9 @@ Defaults to whatever the last segment of the Logical Volume uses. - Not applicable to LVs using the original metadata LVM format, which - must use a single value throughout. - .br --StripeSize must be 2^n (n = 2 to 9). -+StripeSize must be 2^n (n = 2 to 9) for metadata in LVM1 format. -+For metadata in LVM2 format, the stripe size may be a larger -+power of 2 but must not exceed the physical extent size. - .TP - .B \-\-noudevsync - Disable udev synchronisation. The -diff --git a/man/lvs.8.in b/man/lvs.8.in -index 8427aca..95eb25a 100644 ---- a/man/lvs.8.in -+++ b/man/lvs.8.in -@@ -135,12 +135,12 @@ can also be chosen. - The lv_attr bits are: - .RS - .IP 1 3 --Volume type: (m)irrored, (M)irrored without initial sync, (o)rigin, -+Volume type: (C)ache, (m)irrored, (M)irrored without initial sync, (o)rigin, - (O)rigin with merging snapshot, (r)aid, (R)aid without initial sync, - (s)napshot, merging (S)napshot, (p)vmove, (v)irtual, - mirror or raid (i)mage, mirror or raid (I)mage out-of-sync, mirror (l)og device, - under (c)onversion, thin (V)olume, (t)hin pool, (T)hin pool data, raid or --thin pool m(e)tadata or pool metadata spare. -+pool m(e)tadata or pool metadata spare. - .IP 2 3 - Permissions: (w)riteable, (r)ead-only, (R)ead-only activation of non-read-only - volume -diff --git a/man/vgchange.8.in b/man/vgchange.8.in -index 823d134..16adf4df 100644 ---- a/man/vgchange.8.in -+++ b/man/vgchange.8.in -@@ -76,9 +76,10 @@ In other words, makes the logical volumes known/unknown to the kernel. - If autoactivation option is used (\-aay), each logical volume in - the volume group is activated only if it matches an item in the - activation/auto_activation_volume_list set in lvm.conf. If this --list is not set, then all volumes are considered for autoactivation. --The autoactivation is not yet supported for partial or clustered --volume groups. -+list is not set, then all volumes are considered for activation. -+The \-aay option should be also used during system boot so it's -+possible to select which volumes to activate using the -+activation/auto_activation_volume_list settting. - .IP - If clustered locking is enabled, add 'e' to activate/deactivate - exclusively on one node or 'l' to activate/deactivate only -diff --git a/python/liblvm.c b/python/liblvm.c -index 6abd5ff..094aec2 100644 ---- a/python/liblvm.c -+++ b/python/liblvm.c -@@ -1043,22 +1043,22 @@ static PyObject *_liblvm_lvm_vg_list_lvs(vgobject *self) - - static PyObject *_liblvm_lvm_vg_get_tags(vgobject *self) - { -- struct dm_list *tags; -+ struct dm_list *tagsl; - struct lvm_str_list *strl; - PyObject * pytuple; - int i = 0; - - VG_VALID(self); - -- if (!(tags = lvm_vg_get_tags(self->vg))) { -+ if (!(tagsl = lvm_vg_get_tags(self->vg))) { - PyErr_SetObject(_LibLVMError, _liblvm_get_last_error()); - return NULL; - } - -- if (!(pytuple = PyTuple_New(dm_list_size(tags)))) -+ if (!(pytuple = PyTuple_New(dm_list_size(tagsl)))) - return NULL; - -- dm_list_iterate_items(strl, tags) { -+ dm_list_iterate_items(strl, tagsl) { - PyTuple_SET_ITEM(pytuple, i, PyString_FromString(strl->str)); - i++; - } -@@ -1163,8 +1163,9 @@ static PyObject *_liblvm_lvm_vg_create_lv_thin(vgobject *self, PyObject *args) - static void liblvm_lv_dealloc(lvobject *self) - { - /* We can dealloc an object that didn't get fully created */ -- if (self->parent_vgobj) -+ if (self->parent_vgobj) { - Py_DECREF(self->parent_vgobj); -+ } - - PyObject_Del(self); - } -@@ -1291,11 +1292,13 @@ static PyObject *_liblvm_lvm_pv_from_uuid(vgobject *self, PyObject *arg) - - static void _liblvm_pv_dealloc(pvobject *self) - { -- if (self->parent_vgobj) -+ if (self->parent_vgobj) { - Py_DECREF(self->parent_vgobj); -+ } - -- if (self->parent_pvslistobj) -+ if (self->parent_pvslistobj) { - Py_DECREF(self->parent_pvslistobj); -+ } - - self->parent_vgobj = NULL; - self->parent_pvslistobj = NULL; -@@ -1474,22 +1477,22 @@ static PyObject *_liblvm_lvm_lv_remove_tag(lvobject *self, PyObject *args) - - static PyObject *_liblvm_lvm_lv_get_tags(lvobject *self) - { -- struct dm_list *tags; -+ struct dm_list *tagsl; - struct lvm_str_list *strl; - PyObject * pytuple; - int i = 0; - - LV_VALID(self); - -- if (!(tags = lvm_lv_get_tags(self->lv))) { -+ if (!(tagsl = lvm_lv_get_tags(self->lv))) { - PyErr_SetObject(_LibLVMError, _liblvm_get_last_error()); - return NULL; - } - -- if (!(pytuple = PyTuple_New(dm_list_size(tags)))) -+ if (!(pytuple = PyTuple_New(dm_list_size(tagsl)))) - return NULL; - -- dm_list_iterate_items(strl, tags) { -+ dm_list_iterate_items(strl, tagsl) { - PyTuple_SET_ITEM(pytuple, i, PyString_FromString(strl->str)); - i++; - } -diff --git a/scripts/Makefile.in b/scripts/Makefile.in -index ed587ca..8fdb5f7 100644 ---- a/scripts/Makefile.in -+++ b/scripts/Makefile.in -@@ -111,6 +111,14 @@ ifeq ("@BUILD_LVMETAD@", "yes") - $(INSTALL_DATA) lvm2_lvmetad_systemd_red_hat.service $(systemd_unit_dir)/lvm2-lvmetad.service - $(INSTALL_DATA) lvm2_pvscan_systemd_red_hat@.service $(systemd_unit_dir)/lvm2-pvscan@.service - endif -+ifneq ("@CLVMD@", "none") -+ $(INSTALL_DATA) lvm2_clvmd_systemd_red_hat.service $(systemd_unit_dir)/lvm2-clvmd.service -+ $(INSTALL_DATA) lvm2_cluster_activation_systemd_red_hat.service $(systemd_unit_dir)/lvm2-cluster-activation.service -+ $(INSTALL_DATA) lvm2_cluster_activation_red_hat.sh $(systemd_dir)/lvm2-cluster-activation -+endif -+ifeq ("@BUILD_CMIRRORD@", "yes") -+ $(INSTALL_DATA) lvm2_cmirrord_systemd_red_hat.service $(systemd_unit_dir)/lvm2-cmirrord.service -+endif - - install_tmpfiles_configuration: - $(INSTALL_DIR) $(tmpfiles_dir) -@@ -124,4 +132,7 @@ DISTCLEAN_TARGETS += clvmd_init_red_hat cmirrord_init_red_hat \ - lvm2_pvscan_systemd_red_hat@.service \ - lvm2_tmpfiles_red_hat.conf blk_availability_init_red_hat \ - blk_availability_systemd_red_hat.service \ -- blkdeactivate.sh -+ blkdeactivate.sh lvm2_clvmd_systemd_red_hat.service \ -+ lvm2_cmirrord_systemd_red_hat.service \ -+ lvm2_cluster_activation_systemd_red_hat.service \ -+ lvm2_cluster_activation_red_hat.sh -diff --git a/scripts/dm_event_systemd_red_hat.service.in b/scripts/dm_event_systemd_red_hat.service.in -index 96c5225..3791618 100644 ---- a/scripts/dm_event_systemd_red_hat.service.in -+++ b/scripts/dm_event_systemd_red_hat.service.in -@@ -7,9 +7,8 @@ Before=local-fs.target - DefaultDependencies=no - - [Service] --Type=forking --ExecStart=@sbindir@/dmeventd --ExecReload=@sbindir@/dmeventd -R -+Type=simple -+ExecStart=@sbindir@/dmeventd -f - Environment=SD_ACTIVATION=1 - PIDFile=@DMEVENTD_PIDFILE@ - OOMScoreAdjust=-1000 -diff --git a/scripts/lvm2_activation_generator_systemd_red_hat.c b/scripts/lvm2_activation_generator_systemd_red_hat.c -index f2e2e49..07a2563 100644 ---- a/scripts/lvm2_activation_generator_systemd_red_hat.c -+++ b/scripts/lvm2_activation_generator_systemd_red_hat.c -@@ -150,7 +150,7 @@ static int generate_unit(const char *dir, int unit) - "[Service]\n", f); - } - -- fputs("ExecStart=" LVM_PATH " vgchange -aay --sysinit\n" -+ fputs("ExecStart=" LVM_PATH " vgchange -aay --sysinit --ignoreskippedcluster\n" - "Type=oneshot\n", f); - - if (fclose(f) < 0) { -diff --git a/scripts/lvm2_cluster_activation_red_hat.sh.in b/scripts/lvm2_cluster_activation_red_hat.sh.in -new file mode 100644 -index 0000000..0d4676c ---- /dev/null -+++ b/scripts/lvm2_cluster_activation_red_hat.sh.in -@@ -0,0 +1,70 @@ -+#!/bin/bash -+ -+sbindir=@sbindir@ -+ -+lvm_vgchange=${sbindir}/vgchange -+lvm_vgscan=${sbindir}/vgscan -+lvm_vgs=${sbindir}/vgs -+lvm_lvm=${sbindir}/lvm -+ -+parse_clustered_vgs() { -+ while read -r name attrs; -+ do -+ test "${attrs:5:1}" == 'c' && echo -n "$name " -+ done -+} -+ -+# NOTE: replace this with vgs, once display filter per attr is implemented. -+clustered_vgs() { -+ ${lvm_vgs} -o vg_name,vg_attr --noheadings | parse_clustered_vgs -+} -+ -+activate() { -+ eval local $(${lvm_lvm} dumpconfig devices/obtain_device_list_from_udev 2>/dev/null) 2>/dev/null -+ if [ $? -ne 0 ]; then -+ echo "Warning: expected single couple of key=value in output of dumpconfig" -+ fi -+ -+ if [ -z $obtain_device_list_from_udev -o $obtain_device_list_from_udev -ne 1 ]; then -+ echo -n "lvm.conf option obtain_device_list_from_udev!=1: Executing vgscan" -+ ${lvm_vgscan} > /dev/null 2>&1 -+ fi -+ -+ echo -n "Activating ${LVM_VGS:-"all VG(s)"}: " -+ # Respect activation/auto_activation_volume_list! -+ # Call "-aay" which is equal to "-aly" but respects this list. -+ ${lvm_vgchange} -aay $LVM_VGS || return 1 -+ -+ return 0 -+} -+ -+deactivate() -+{ -+ # NOTE: following section will be replaced by blkdeactivate script -+ # with option supporting request to deactivate all clustered volume -+ # groups in the system -+ [ -z $LVM_VGS ] && LVM_VGS="$(clustered_vgs)" -+ if [ -n "$LVM_VGS" ]; then -+ echo -n "Deactivating clustered VG(s): " -+ ${lvm_vgchange} -anl $LVM_VGS || return 1 -+ fi -+ -+ return 0 -+} -+ -+case "$1" in -+ deactivate) -+ deactivate -+ rtrn=$? -+ ;; -+ activate) -+ activate -+ rtrn=$? -+ ;; -+ *) -+ echo $"Usage: $0 {activate|deactivate}" -+ rtrn=3 -+ ;; -+esac -+ -+exit $rtrn -diff --git a/scripts/lvm2_cluster_activation_systemd_red_hat.service.in b/scripts/lvm2_cluster_activation_systemd_red_hat.service.in -new file mode 100644 -index 0000000..970e93a ---- /dev/null -+++ b/scripts/lvm2_cluster_activation_systemd_red_hat.service.in -@@ -0,0 +1,17 @@ -+[Unit] -+Description=Clustered LVM volumes activation service -+Requires=lvm2-clvmd.service -+After=lvm2-clvmd.service lvm2-cmirrord.service -+OnFailure=lvm2-clvmd.service -+DefaultDependencies=no -+Conflicts=shutdown.target -+ -+[Service] -+Type=simple -+RemainAfterExit=yes -+EnvironmentFile=-@sysconfdir@/sysconfig/clvmd -+ExecStart=@systemdutildir@/lvm2-cluster-activation activate -+ExecStop=@systemdutildir@/lvm2-cluster-activation deactivate -+ -+[Install] -+WantedBy=multi-user.target -diff --git a/scripts/lvm2_clvmd_systemd_red_hat.service.in b/scripts/lvm2_clvmd_systemd_red_hat.service.in -new file mode 100644 -index 0000000..2978d21 ---- /dev/null -+++ b/scripts/lvm2_clvmd_systemd_red_hat.service.in -@@ -0,0 +1,23 @@ -+[Unit] -+Description=Clustered LVM daemon -+Documentation=man:clvmd(8) -+After=dlm.service corosync.service -+Before=remote-fs.target -+Requires=network.target dlm.service corosync.service -+RefuseManualStart=true -+RefuseManualStop=true -+StopWhenUnneeded=true -+DefaultDependencies=no -+Conflicts=shutdown.target -+ -+[Service] -+Type=forking -+Environment=CLVMD_OPTS=-T30 -+EnvironmentFile=-@sysconfdir@/sysconfig/clvmd -+ExecStart=@sbindir@/clvmd $CLVMD_OPTS -+SuccessExitStatus=5 -+TimeoutStartSec=30 -+TimeoutStopSec=10 -+OOMScoreAdjust=-1000 -+Restart=on-abort -+PIDFile=@CLVMD_PIDFILE@ -diff --git a/scripts/lvm2_cmirrord_systemd_red_hat.service.in b/scripts/lvm2_cmirrord_systemd_red_hat.service.in -new file mode 100644 -index 0000000..16d38ce ---- /dev/null -+++ b/scripts/lvm2_cmirrord_systemd_red_hat.service.in -@@ -0,0 +1,17 @@ -+[Unit] -+Description=Clustered LVM mirror log daemon -+Documentation=man:cmirrord(8) -+Requires=corosync.service -+After=corosync.service -+Before=remote-fs.target -+DefaultDependencies=no -+Conflicts=shutdown.target -+ -+[Service] -+Type=forking -+ExecStart=@sbindir@/cmirrord -+PIDFile=@CMIRRORD_PIDFILE@ -+Restart=on-abort -+ -+[Install] -+WantedBy=multi-user.target -diff --git a/scripts/lvm2_lvmetad_systemd_red_hat.service.in b/scripts/lvm2_lvmetad_systemd_red_hat.service.in -index 0150726..8f4c60d 100644 ---- a/scripts/lvm2_lvmetad_systemd_red_hat.service.in -+++ b/scripts/lvm2_lvmetad_systemd_red_hat.service.in -@@ -7,10 +7,9 @@ DefaultDependencies=no - Conflicts=shutdown.target - - [Service] --Type=forking -+Type=simple - NonBlocking=true --ExecStart=@sbindir@/lvmetad --ExecReload=@sbindir@/lvmetad -R -+ExecStart=@sbindir@/lvmetad -f - Environment=SD_ACTIVATION=1 - Restart=on-abort - PIDFile=@LVMETAD_PIDFILE@ -diff --git a/scripts/lvm2_monitoring_init_red_hat.in b/scripts/lvm2_monitoring_init_red_hat.in -index cae652c..44de07f 100644 ---- a/scripts/lvm2_monitoring_init_red_hat.in -+++ b/scripts/lvm2_monitoring_init_red_hat.in -@@ -48,10 +48,10 @@ start() - { - ret=0 - # TODO do we want to separate out already active groups only? -- VGSLIST=`$VGS --noheadings -o name --config 'log{command_names=0 prefix=" "}' 2> /dev/null` -+ VGSLIST=`$VGS --noheadings -o name --ignoreskippedcluster --config 'log{command_names=0 prefix=" "}' 2> /dev/null` - for vg in $VGSLIST - do -- action "Starting monitoring for VG $vg:" $VGCHANGE --monitor y --poll y --config 'log{command_names=0 prefix=" "}' $vg || ret=$? -+ action "Starting monitoring for VG $vg:" $VGCHANGE --monitor y --poll y --ignoreskippedcluster --config 'log{command_names=0 prefix=" "}' $vg || ret=$? - done - - return $ret -@@ -66,10 +66,10 @@ stop() - echo "Not stopping monitoring, this is a dangerous operation. Please use force-stop to override." - return 1 - fi -- VGSLIST=`$VGS --noheadings -o name --config 'log{command_names=0 prefix=" "}' 2> /dev/null` -+ VGSLIST=`$VGS --noheadings -o name --ignoreskippedcluster --config 'log{command_names=0 prefix=" "}' 2> /dev/null` - for vg in $VGSLIST - do -- action "Stopping monitoring for VG $vg:" $VGCHANGE --monitor n --config 'log{command_names=0 prefix=" "}' $vg || ret=$? -+ action "Stopping monitoring for VG $vg:" $VGCHANGE --monitor n --ignoreskippedcluster --config 'log{command_names=0 prefix=" "}' $vg || ret=$? - done - return $ret - } -diff --git a/scripts/lvm2_monitoring_systemd_red_hat.service.in b/scripts/lvm2_monitoring_systemd_red_hat.service.in -index 670d0c4..05f911b 100644 ---- a/scripts/lvm2_monitoring_systemd_red_hat.service.in -+++ b/scripts/lvm2_monitoring_systemd_red_hat.service.in -@@ -10,9 +10,9 @@ Conflicts=shutdown.target - [Service] - Type=oneshot - Environment=LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES=1 --ExecStart=@sbindir@/lvm vgchange --monitor y -+ExecStart=@sbindir@/lvm vgchange --monitor y --ignoreskippedcluster - # The lvmetad must be disabled here, it needs https://bugzilla.redhat.com/show_bug.cgi?id=843587 to be resolved first. --ExecStop=@sbindir@/lvm vgchange --monitor n --config 'global{use_lvmetad=0}' -+ExecStop=@sbindir@/lvm vgchange --monitor n --config 'global{use_lvmetad=0}' --ignoreskippedcluster - RemainAfterExit=yes - - [Install] -diff --git a/test/api/pytest.sh b/test/api/pytest.sh -index a0f9a2f..8359c01 100644 ---- a/test/api/pytest.sh -+++ b/test/api/pytest.sh -@@ -20,19 +20,20 @@ - # Until fixed - testing always runs with enabled monitoring - # thus it needs dmeventd - # --aux prepare_dmeventd --test ! -e LOCAL_CLVMD || skip --test ! -e LOCAL_LVMETAD || skip -- --#If you change this change the unit test case too. --aux prepare_pvs 6 - - #Locate the python binding library to use. - python_lib=$(find $abs_top_builddir -name lvm.so) -- - # Unable to test python bindings if library not available - test -n "$python_lib" || skip - -+test -e LOCAL_CLVMD && skip -+test -e LOCAL_LVMETAD && skip -+ -+aux prepare_dmeventd -+ -+#If you change this change the unit test case too. -+aux prepare_pvs 6 -+ - export PYTHONPATH=$(dirname $python_lib):$PYTHONPATH - - #Setup which devices the unit test can use. -diff --git a/test/lib/aux.sh b/test/lib/aux.sh -index 2a882a2..66ed910 100644 ---- a/test/lib/aux.sh -+++ b/test/lib/aux.sh -@@ -52,6 +52,7 @@ prepare_clvmd() { - - prepare_dmeventd() { - if pgrep dmeventd ; then -+ rm -f debug.log - echo "Cannot test dmeventd with real dmeventd ($(pgrep dmeventd)) running." - skip - fi -@@ -392,6 +393,7 @@ disable_dev() { - enable_dev() { - local dev - -+ rm -f debug.log - init_udev_transaction - for dev in "$@"; do - local name=$(echo "$dev" | sed -e 's,.*/,,') -@@ -536,7 +538,7 @@ generate_config() { - devices/dir = "$DM_DEV_DIR" - devices/scan = "$DM_DEV_DIR" - devices/filter = "a|.*|" --devices/global_filter = [ "a|$DM_DEV_DIR/mirror|", "a|$DM_DEV_DIR/mapper/.*pv[0-9_]*$|", "r|.*|" ] -+devices/global_filter = [ "a|$DM_DEV_DIR/mapper/.*pv[0-9_]*$|", "r|.*|" ] - devices/cache_dir = "$TESTDIR/etc" - devices/sysfs_scan = 0 - devices/default_data_alignment = 1 -@@ -654,7 +656,7 @@ skip_if_raid456_replace_broken() { - - udev_wait() { - pgrep udev >/dev/null || return 0 -- which udevadm >/dev/null || return 0 -+ which udevadm &>/dev/null || return 0 - if test -n "$1" ; then - udevadm settle --exit-if-exists="$1" || true - else -@@ -689,6 +691,7 @@ can_use_16T() - # i.e. dm_target_at_least dm-thin-pool 1 0 - target_at_least() - { -+ rm -f debug.log - case "$1" in - dm-*) modprobe "$1" || true ;; - esac -diff --git a/test/lib/check.sh b/test/lib/check.sh -index 84604e3..9c55338 100644 ---- a/test/lib/check.sh -+++ b/test/lib/check.sh -@@ -240,7 +240,7 @@ inactive() { - die "$lv expected inactive, but lvs says it's not:" \ - $(lvl $lv -o+devices) - not dmsetup info $1-$2 2>/dev/null || \ -- die "$lv expected inactive, lvs thinks it is but there are mappings!" -+ die "$lv expected inactive, lvs thinks it is but there are mappings!" - } - - # Check for list of LVs from given VG -@@ -251,10 +251,25 @@ lv_exists() { - shift - lv="$lv $vg/$1" - done -+ test -n "$lv" || lv=$vg - lvl $lv &>/dev/null || \ - die "$lv expected to exist but does not" - } - -+lv_not_exists() { -+ local vg=$1 -+ if test $# -le 1 ; then -+ lvl $vg &>/dev/null || return -+ die "$vg expected to not exist but it does!" -+ else -+ while [ $# -gt 1 ]; do -+ shift -+ lvl $vg/$1 &>/dev/null || continue -+ die "$vg/$1 expected to not exist but it does!" -+ done -+ fi -+} -+ - pv_field() { - local actual=$(get pv_field "$1" "$2" "${@:4}") - test "$actual" = "$3" || \ -diff --git a/test/lib/get.sh b/test/lib/get.sh -index 5dd5451..babc4c9 100644 ---- a/test/lib/get.sh -+++ b/test/lib/get.sh -@@ -70,6 +70,13 @@ lv_tree_devices_() { - lv_tree_devices_ "$1" "$(lv_field_lv_ $lv data_lv)" - lv_tree_devices_ "$1" "$(lv_field_lv_ $lv metadata_lv)" - ;; -+ cache) -+ lv_tree_devices_ "$1" "$(lv_devices $lv)" -+ ;; -+ cache-pool) -+ lv_tree_devices_ "$1" "$(lv_field_lv_ $lv data_lv)" -+ lv_tree_devices_ "$1" "$(lv_field_lv_ $lv metadata_lv)" -+ ;; - esac - } - -diff --git a/test/lib/test.sh b/test/lib/test.sh -index 265d61d..71ad55d 100644 ---- a/test/lib/test.sh -+++ b/test/lib/test.sh -@@ -81,9 +81,9 @@ test -n "$BASH" && set -eE -o pipefail - aux lvmconf - aux prepare_clvmd - test -n "$LVM_TEST_LVMETAD" && { -- aux prepare_lvmetad - export LVM_LVMETAD_SOCKET="$TESTDIR/lvmetad.socket" - export LVM_LVMETAD_PIDFILE="$TESTDIR/lvmetad.pid" -+ aux prepare_lvmetad - } - echo "@TESTDIR=$TESTDIR" - echo "@PREFIX=$PREFIX" -diff --git a/test/shell/activation-skip.sh b/test/shell/activation-skip.sh -new file mode 100644 -index 0000000..7c80283 ---- /dev/null -+++ b/test/shell/activation-skip.sh -@@ -0,0 +1,32 @@ -+#!/bin/bash -+# Copyright (C) 2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+. lib/test -+ -+# Test skip activation flag -k|--setactivationskip -+ -+aux prepare_vg -+ -+lvcreate -an --zero n -l 1 -n $lv1 $vg -+lvcreate -ky -K -l1 -n $lv2 $vg -+get lv_field $vg/$lv2 lv_attr | grep -- "-wi-a----k" -+ -+lvchange -ay -K $vg -+check active $vg $lv1 -+lvchange -an $vg -+ -+lvchange -ay --setactivationskip y $vg/$lv1 -+check inactive $vg $lv1 -+ -+get lv_field $vg/$lv1 lv_attr | grep -- "-wi------k" -+ -+lvchange -ay -K $vg -+check active $vg $lv1 -diff --git a/test/shell/lock-parallel.sh b/test/shell/lock-parallel.sh -new file mode 100644 -index 0000000..4820129 ---- /dev/null -+++ b/test/shell/lock-parallel.sh -@@ -0,0 +1,40 @@ -+#!/bin/sh -+# Copyright (C) 2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+# Test parallel use of lvm commands and check locks aren't dropped -+# RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1049296 -+ -+. lib/test -+ -+which mkfs.ext3 || skip -+ -+aux prepare_vg -+ -+lvcreate -L10 -n $lv1 $vg -+lvcreate -l1 -n $lv2 $vg -+mkfs.ext3 "$DM_DEV_DIR/$vg/$lv1" -+ -+# Slowdown PV for resized LV -+aux delay_dev "$dev1" 20 20 -+ -+lvresize -L-5 -r $vg/$lv1 & -+ -+# Let's wait till resize starts -+sleep 2 -+ -+lvremove -f $vg/$lv2 -+ -+wait -+ -+aux enable_dev "$dev1" -+ -+# Check removed $lv2 does not reappear -+not check lv_exists $vg $lv2 -diff --git a/test/shell/lvchange-partial.sh b/test/shell/lvchange-partial.sh -index 891dd0a..b79004d 100644 ---- a/test/shell/lvchange-partial.sh -+++ b/test/shell/lvchange-partial.sh -@@ -11,11 +11,13 @@ - - . lib/test - --aux target_at_least dm-raid 1 1 0 || skip - - aux prepare_vg 4 - --lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg -+TYPE=raid1 -+aux target_at_least dm-raid 1 1 0 || TYPE=mirror -+ -+lvcreate -aey --type $TYPE -m 1 -l 2 -n $lv1 $vg - lvchange -an $vg/$lv1 - aux disable_dev "$dev1" - -diff --git a/test/shell/lvchange-raid.sh b/test/shell/lvchange-raid.sh -index 91c8e8d..0ee5290 100644 ---- a/test/shell/lvchange-raid.sh -+++ b/test/shell/lvchange-raid.sh -@@ -19,7 +19,7 @@ THIN_POSTFIX="" - # Proper mismatch count 1.5.2 upstream,1.3.5 < x < 1.4.0 in RHEL6 - # - # We will simplify and simple test for 1.5.2 and 1.3.5 < x < 1.4.0 --aux target_at_least dm-raid 1 3 5 && -+aux target_at_least dm-raid 1 3 5 && - ! aux target_at_least dm-raid 1 4 0 || - aux target_at_least dm-raid 1 5 2 || skip - -@@ -29,108 +29,103 @@ aux prepare_vg 6 - - # run_writemostly_check - run_writemostly_check() { -- local d0 -- local d1 - local vg=$1 - local lv=${2}${THIN_POSTFIX} -+ local segtype=$(get lv_field $vg/$lv segtype -a) -+ local d0=$(get lv_devices $vg/${lv}_rimage_0) -+ local d1=$(get lv_devices $vg/${lv}_rimage_1) - - printf "#\n#\n#\n# %s/%s (%s): run_writemostly_check\n#\n#\n#\n" \ -- $vg $lv `lvs -a --noheadings -o segtype $vg/$lv` -- d0=`lvs -a --noheadings -o devices $vg/${lv}_rimage_0 | sed s/\(.\)//` -- d0=$(sed s/^[[:space:]]*// <<< "$d0") -- d1=`lvs -a --noheadings -o devices $vg/${lv}_rimage_1 | sed s/\(.\)//` -- d1=$(sed s/^[[:space:]]*// <<< "$d1") -+ $vg $lv $segtype - - # No writemostly flag should be there yet. -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*-.$' -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_1 | grep '.*-.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*-.$' -+ get lv_field $vg/${lv}_rimage_1 lv_attr -a | grep '.*-.$' - -- if [ `lvs -a --noheadings -o segtype $vg/$lv` != "raid1" ]; then -+ if [ "$segtype" != "raid1" ]; then - not lvchange --writemostly $d0 $vg/$lv - return - fi - - # Set the flag - lvchange --writemostly $d0 $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*w.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*w.$' - - # Running again should leave it set (not toggle) - lvchange --writemostly $d0 $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*w.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*w.$' - - # Running again with ':y' should leave it set - lvchange --writemostly $d0:y $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*w.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*w.$' - - # ':n' should unset it - lvchange --writemostly $d0:n $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*-.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*-.$' - - # ':n' again should leave it unset - lvchange --writemostly $d0:n $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*-.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*-.$' - - # ':t' toggle to set - lvchange --writemostly $d0:t $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*w.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*w.$' - - # ':t' toggle to unset - lvchange --writemostly $d0:t $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*-.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*-.$' - - # ':y' to set - lvchange --writemostly $d0:y $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*w.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*w.$' - - # Toggle both at once - lvchange --writemostly $d0:t --writemostly $d1:t $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*-.$' -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_1 | grep '.*w.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*-.$' -+ get lv_field $vg/${lv}_rimage_1 lv_attr -a | grep '.*w.$' - - # Toggle both at once again - lvchange --writemostly $d0:t --writemostly $d1:t $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*w.$' -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_1 | grep '.*-.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*w.$' -+ get lv_field $vg/${lv}_rimage_1 lv_attr -a | grep '.*-.$' - - # Toggle one, unset the other - lvchange --writemostly $d0:n --writemostly $d1:t $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*-.$' -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_1 | grep '.*w.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*-.$' -+ get lv_field $vg/${lv}_rimage_1 lv_attr -a | grep '.*w.$' - - # Toggle one, set the other - lvchange --writemostly $d0:y --writemostly $d1:t $vg/$lv -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*w.$' -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_1 | grep '.*-.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*w.$' -+ get lv_field $vg/${lv}_rimage_1 lv_attr -a | grep '.*-.$' - - # Partial flag supercedes writemostly flag - aux disable_dev $d0 -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*p.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*p.$' - - # It is possible for the kernel to detect the failed device before - # we re-enable it. If so, the field will be set to 'r'efresh since - # that also takes precedence over 'w'ritemostly. If this has happened, - # we refresh the LV and then check for 'w'. - aux enable_dev $d0 -- if lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*r.$'; then -- lvchange --refresh $vg/$lv -- fi -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*w.$' -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*r.$' && lvchange --refresh $vg/$lv -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*w.$' - - # Catch Bad writebehind values - not lvchange --writebehind "invalid" $vg/$lv - not lvchange --writebehind -256 $vg/$lv - - # Set writebehind -- [ ! `lvs --noheadings -o raid_write_behind $vg/$lv` ] -+ check lv_field $vg/$lv raid_write_behind "" - lvchange --writebehind 512 $vg/$lv -- [ `lvs --noheadings -o raid_write_behind $vg/$lv` -eq 512 ] -+ check lv_field $vg/$lv raid_write_behind "512" - - # Converting to linear should clear flags and writebehind - lvconvert -m 0 $vg/$lv $d1 - lvconvert --type raid1 -m 1 $vg/$lv $d1 -- [ ! `lvs --noheadings -o raid_write_behind $vg/$lv` ] -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_0 | grep '.*-.$' -- lvs -a --noheadings -o lv_attr $vg/${lv}_rimage_1 | grep '.*-.$' -+ check lv_field $vg/$lv raid_write_behind "" -+ get lv_field $vg/${lv}_rimage_0 lv_attr -a | grep '.*-.$' -+ get lv_field $vg/${lv}_rimage_1 lv_attr -a | grep '.*-.$' - } - - # run_syncaction_check -@@ -143,33 +138,29 @@ run_syncaction_check() { - local lv=${2}${THIN_POSTFIX} - - printf "#\n#\n#\n# %s/%s (%s): run_syncaction_check\n#\n#\n#\n" \ -- $vg $lv `lvs -a --noheadings -o segtype $vg/$lv` -+ $vg $lv $(get lv_field $vg/$lv segtype -a) - aux wait_for_sync $vg $lv - -- device=`lvs -a --noheadings -o devices $vg/${lv}_rimage_1 | sed s/\(.\)//` -- device=$(sed s/^[[:space:]]*// <<< "$device") -+ device=$(get lv_devices $vg/${lv}_rimage_1) - -- size=`lvs -a --noheadings -o size --units 1k $vg/${lv}_rimage_1 | sed s/\.00k//` -- size=$(sed s/^[[:space:]]*// <<< "$size") -- size=$(($size / 2)) -+ size=$(get lv_field $vg/${lv}_rimage_1 size -a --units 1k) -+ size=$((${size%\.00k} / 2)) - -- tmp=`pvs --noheadings -o mda_size --units 1k $device | sed s/\.00k//` -- tmp=$(sed s/^[[:space:]]*// <<< "$tmp") -- seek=$tmp # Jump over MDA -+ tmp=$(get pv_field $device mda_size --units 1k) -+ seek=${tmp%\.00k} # Jump over MDA - -- tmp=`lvs -a --noheadings -o size --units 1k $vg/${lv}_rmeta_1 | sed s/\.00k//` -- tmp=$(sed s/^[[:space:]]*// <<< "$tmp") -- seek=$(($seek + $tmp)) # Jump over RAID metadata image -+ tmp=$(get lv_field $vg/${lv}_rmeta_1 size -a --units 1k) -+ seek=$(($seek + ${tmp%\.00k})) # Jump over RAID metadata image - - seek=$(($seek + $size)) # Jump halfway through the RAID image - -- lvs --noheadings -o lv_attr $vg/$lv | grep '.*-.$' -- [ `lvs --noheadings -o raid_mismatch_count $vg/$lv` == 0 ] -+ get lv_field $vg/$lv lv_attr | grep '.*-.$' -+ check lv_field $vg/$lv raid_mismatch_count "0" - - # Overwrite the last half of one of the PVs with crap - dd if=/dev/urandom of=$device bs=1k count=$size seek=$seek - -- if [ ! -z $THIN_POSTFIX ]; then -+ if [ -n "$THIN_POSTFIX" ]; then - # - # Seems to work fine on real devices, - # but can't make the system notice the bad blocks -@@ -189,12 +180,11 @@ run_syncaction_check() { - # 'lvs' should show results - lvchange --syncaction check $vg/$lv - aux wait_for_sync $vg $lv -- if ! lvs --noheadings -o lv_attr $vg/$lv | grep '.*m.$'; then -- lvs --noheadings -o lv_attr $vg/$lv -+ if ! get lv_field $vg/$lv lv_attr -a | grep '.*m.$'; then - dmsetup status | grep $vg - false - fi -- [ `lvs --noheadings -o raid_mismatch_count $vg/$lv` != 0 ] -+ not check lv_field $vg/$lv raid_mismatch_count "0" - - # "repair" will fix discrepancies - lvchange --syncaction repair $vg/$lv -@@ -204,40 +194,35 @@ run_syncaction_check() { - # 'lvs' should show results - lvchange --syncaction check $vg/$lv - aux wait_for_sync $vg $lv -- lvs --noheadings -o lv_attr $vg/$lv | grep '.*-.$' -- [ `lvs --noheadings -o raid_mismatch_count $vg/$lv` == 0 ] -+ get lv_field $vg/$lv lv_attr | grep '.*-.$' -+ check lv_field $vg/$lv raid_mismatch_count "0" - } - - # run_refresh_check - # Assumes "$dev2" is in the array - run_refresh_check() { - local size -+ local sizelv - local vg=$1 - local lv=${2}${THIN_POSTFIX} - - printf "#\n#\n#\n# %s/%s (%s): run_refresh_check\n#\n#\n#\n" \ -- $vg $lv `lvs -a --noheadings -o segtype $vg/$lv` -+ $vg $lv $(get lv_field $vg/$lv segtype -a) - - aux wait_for_sync $vg $lv - -- if [ -z $THIN_POSTFIX ]; then -- size=`lvs -a --noheadings -o size --units 1k $vg/$lv | sed s/\.00k//` -- else -- size=`lvs -a --noheadings -o size --units 1k $vg/thinlv | sed s/\.00k//` -- fi -- size=$(sed s/^[[:space:]]*// <<< "$size") -+ sizelv=$vg/$lv -+ test -z "$THIN_POSTFIX" || sizelv=$vg/thinlv -+ size=$(get lv_field $sizelv size --units 1k) -+ size=${size%\.00k} - - # Disable dev2 and do some I/O to make the kernel notice - aux disable_dev "$dev2" -- if [ -z $THIN_POSTFIX ]; then -- dd if=/dev/urandom of=/dev/$vg/$lv bs=1k count=$size -- else -- dd if=/dev/urandom of=/dev/$vg/thinlv bs=1k count=$size -- sync; sync; sync -- fi -+ dd if=/dev/urandom of=/dev/$sizelv bs=1k count=$size -+ sync - - # Check for 'p'artial flag -- lvs --noheadings -o lv_attr $vg/$lv | grep '.*p.$' -+ get lv_field $vg/$lv lv_attr | grep '.*p.$' - dmsetup status - lvs -a -o name,attr,devices $vg - -@@ -247,18 +232,18 @@ run_refresh_check() { - lvs -a -o name,attr,devices $vg - - # Check for 'r'efresh flag -- lvs --noheadings -o lv_attr $vg/$lv | grep '.*r.$' -+ get lv_field $vg/$lv lv_attr | grep '.*r.$' - - lvchange --refresh $vg/$lv - aux wait_for_sync $vg $lv -- lvs --noheadings -o lv_attr $vg/$lv | grep '.*-.$' -+ get lv_field $vg/$lv lv_attr | grep '.*-.$' - - # Writing random data above should mean that the devices - # were out-of-sync. The refresh should have taken care - # of properly reintegrating the device. - lvchange --syncaction repair $vg/$lv - aux wait_for_sync $vg $lv -- lvs --noheadings -o lv_attr $vg/$lv | grep '.*-.$' -+ get lv_field $vg/$lv lv_attr | grep '.*-.$' - } - - # run_recovery_rate_check -@@ -267,14 +252,13 @@ run_recovery_rate_check() { - local vg=$1 - local lv=${2}${THIN_POSTFIX} - -- printf "#\n#\n#\n# %s/%s (%s): run_recovery_rate_check\n#\n#\n#\n" \ -- $vg $lv `lvs -a --noheadings -o segtype $vg/$lv` -- -+ printf "#\n#\n#\n# %s/%s $(%s): run_recovery_rate_check\n#\n#\n#\n" \ -+ $vg $lv $(get lv_field $vg/$lv segtype -a) - lvchange --minrecoveryrate 50 $vg/$lv - lvchange --maxrecoveryrate 100 $vg/$lv - -- [ `lvs --noheadings -o raid_min_recovery_rate $vg/$lv` == "50" ] -- [ `lvs --noheadings -o raid_max_recovery_rate $vg/$lv` == "100" ] -+ check lv_field $vg/$lv raid_min_recovery_rate "50" -+ check lv_field $vg/$lv raid_max_recovery_rate "100" - } - - # run_checks <"-"|snapshot_dev|"thinpool_data"|"thinpool_meta"> -@@ -292,7 +276,7 @@ run_checks() { - run_refresh_check $1 $2 - run_recovery_rate_check $1 $2 - elif [ 'thinpool_data' == $3 ]; then -- aux target_at_least dm-thin-pool 1 8 0 || return 0 -+ aux have_thin 1 8 0 || return 0 - - # RAID works EX in cluster - # thinpool works EX in cluster -@@ -313,7 +297,7 @@ run_checks() { - run_refresh_check $1 $2 - run_recovery_rate_check $1 $2 - elif [ 'thinpool_meta' == $3 ]; then -- aux target_at_least dm-thin-pool 1 8 0 || return 0 -+ aux have_thin 1 8 0 || return 0 - test -e LOCAL_CLVMD && return 0 - printf "#\n#\n# run_checks: RAID as thinpool metadata\n#\n#\n" - -diff --git a/test/shell/lvconvert-mirror-updown.sh b/test/shell/lvconvert-mirror-updown.sh -new file mode 100644 -index 0000000..3b30738 ---- /dev/null -+++ b/test/shell/lvconvert-mirror-updown.sh -@@ -0,0 +1,36 @@ -+#!/bin/sh -+# Copyright (C) 2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+# Demonstrate problem when upconverting and cutting leg in clvmd -+ -+. lib/test -+ -+aux prepare_pvs 3 -+ -+vgcreate -s 64k $vg $(cat DEVICES) -+ -+lvcreate -aey -l10 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" -+ -+# Slow down device so we are able to start next conversion in parallel -+aux delay_dev "$dev3" 0 200 -+ -+lvconvert -m+1 -b $vg/$lv1 "$dev3" -+ -+# To fix - wait helps here.... -+#lvconvert $vg/$lv1 -+ -+lvs -a $vg -+# -+# It fails so use 'should' and -vvvv for now -+# -+should lvconvert -vvvv -m-1 $vg/$lv1 "$dev2" -+ -+vgremove -f $vg -diff --git a/test/shell/lvconvert-mirror.sh b/test/shell/lvconvert-mirror.sh -index 911e022..097e0d4 100644 ---- a/test/shell/lvconvert-mirror.sh -+++ b/test/shell/lvconvert-mirror.sh -@@ -176,6 +176,10 @@ lvremove -ff $vg - # "remove from original mirror (the original is still mirror)" - lvcreate -aey -l2 --type mirror -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev5" "$dev3:$DEVRANGE" - lvconvert -m+1 -b $vg/$lv1 "$dev4" -+# FIXME: Extra wait here for mirror upconvert synchronization -+# otherwise we may fail her on parallel upconvert and downconvert -+# lvconvert-mirror-updown.sh tests this errornous case separately -+lvconvert $vg/$lv1 - lvconvert -m-1 $vg/$lv1 "$dev2" - lvconvert $vg/$lv1 - -diff --git a/test/shell/lvconvert-repair-dmeventd.sh b/test/shell/lvconvert-repair-dmeventd.sh -index 55eee37..a2d3ef8 100644 ---- a/test/shell/lvconvert-repair-dmeventd.sh -+++ b/test/shell/lvconvert-repair-dmeventd.sh -@@ -14,13 +14,13 @@ - which mkfs.ext2 || skip - aux skip_if_mirror_recovery_broken - --aux prepare_vg 5 - aux prepare_dmeventd -+aux prepare_vg 5 - - lvcreate -aey --type mirror -m 3 --ignoremonitoring -L 1 -n 4way $vg - lvchange --monitor y $vg/4way - aux disable_dev "$dev2" "$dev4" --mkfs.ext2 $DM_DEV_DIR/$vg/4way -+mkfs.ext2 "$DM_DEV_DIR/$vg/4way" - sleep 10 # FIXME: need a "poll" utility, akin to "check" - aux enable_dev "$dev2" "$dev4" - check mirror $vg 4way -diff --git a/test/shell/lvconvert-repair-thin.sh b/test/shell/lvconvert-repair-thin.sh -index aa301d6..b80b855 100644 ---- a/test/shell/lvconvert-repair-thin.sh -+++ b/test/shell/lvconvert-repair-thin.sh -@@ -10,7 +10,7 @@ - # along with this program; if not, write to the Free Software Foundation, - # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - --# Test repairing of broken thin pool metadata -+# Test repairing of broken thin pool metadata - - . lib/test - -@@ -34,8 +34,8 @@ aux prepare_vg 4 - lvcreate -T -L20 -V10 -n $lv1 $vg/pool "$dev1" "$dev2" - lvcreate -T -V10 -n $lv2 $vg/pool - --mkfs.ext2 $DM_DEV_DIR/$vg/$lv1 --mkfs.ext2 $DM_DEV_DIR/$vg/$lv2 -+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv1" -+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv2" - - lvcreate -L20 -n repair $vg - lvcreate -L2 -n fixed $vg -@@ -55,26 +55,26 @@ lvconvert -y -f --poolmetadata $vg/repair --thinpool $vg/pool - - lvchange -aey $vg/repair $vg/fixed - --#dd if=$DM_DEV_DIR/$vg/repair of=back bs=1M -+#dd if="$DM_DEV_DIR/$vg/repair" of=back bs=1M - - # Make some 'repairable' damage?? --dd if=/dev/zero of=$DM_DEV_DIR/$vg/repair bs=1 seek=40960 count=1 -+dd if=/dev/zero of="$DM_DEV_DIR/$vg/repair" bs=1 seek=40960 count=1 - --#dd if=$DM_DEV_DIR/$vg/repair of=back_trashed bs=1M -+#dd if="$DM_DEV_DIR/$vg/repair" of=back_trashed bs=1M - #not vgchange -ay $vg - - #lvconvert --repair $vg/pool - - # Using now SHOULD - since thin tools currently do not seem to work --should not $THIN_CHECK $DM_DEV_DIR/$vg/repair -+should not "$THIN_CHECK" "$DM_DEV_DIR/$vg/repair" - --should not $LVM_TEST_THIN_DUMP_CMD $DM_DEV_DIR/$vg/repair | tee dump -+should not "$LVM_TEST_THIN_DUMP_CMD" "$DM_DEV_DIR/$vg/repair" | tee dump - --should $LVM_TEST_THIN_REPAIR_CMD -i $DM_DEV_DIR/$vg/repair -o $DM_DEV_DIR/$vg/fixed -+should "$LVM_TEST_THIN_REPAIR_CMD" -i "$DM_DEV_DIR/$vg/repair" -o "$DM_DEV_DIR/$vg/fixed" - --should $LVM_TEST_THIN_DUMP_CMD --repair $DM_DEV_DIR/$vg/repair | tee repaired_xml -+should "$LVM_TEST_THIN_DUMP_CMD" --repair "$DM_DEV_DIR/$vg/repair" | tee repaired_xml - --should $LVM_TEST_THIN_CHECK_CMD $DM_DEV_DIR/$vg/fixed -+should "$LVM_TEST_THIN_CHECK_CMD" "$DM_DEV_DIR/$vg/fixed" - - # Swap repaired metadata back - lvconvert -y -f --poolmetadata $vg/fixed --thinpool $vg/pool -@@ -83,7 +83,7 @@ lvs -a $vg - # Activate pool - this should now work - should vgchange -ay $vg - --lvs -a -o+devices $vg -+lvs -a -o+devices $vg - dmsetup table - dmsetup info -c - dmsetup ls --tree -@@ -99,7 +99,7 @@ dmsetup remove $vg-pool_tmeta || true - - dmsetup table - --# FIXME: needs also --yes with double force -+# FIXME: needs also --yes with double force - pvremove --yes -ff "$dev1" - pvremove --yes -ff "$dev2" - -diff --git a/test/shell/lvconvert-repair-transient-dmeventd.sh b/test/shell/lvconvert-repair-transient-dmeventd.sh -index 699195a..6bd1442 100644 ---- a/test/shell/lvconvert-repair-transient-dmeventd.sh -+++ b/test/shell/lvconvert-repair-transient-dmeventd.sh -@@ -18,7 +18,7 @@ aux prepare_dmeventd - lvcreate -aey --type mirror -m 3 --ignoremonitoring -L 1 -n 4way $vg - lvchange --monitor y $vg/4way - aux disable_dev "$dev2" "$dev4" --mkfs.ext3 $DM_DEV_DIR/$vg/4way -+mkfs.ext3 "$DM_DEV_DIR/$vg/4way" - aux enable_dev "$dev2" "$dev4" - sleep 3 - lvs -a -o +devices $vg | tee out -diff --git a/test/shell/lvconvert-repair-transient.sh b/test/shell/lvconvert-repair-transient.sh -index 28b06c6..3baa293 100644 ---- a/test/shell/lvconvert-repair-transient.sh -+++ b/test/shell/lvconvert-repair-transient.sh -@@ -16,7 +16,7 @@ aux prepare_vg 5 - - lvcreate -aey --type mirror -m 3 --ignoremonitoring -L 1 -n 4way $vg - aux disable_dev "$dev2" "$dev4" --mkfs.ext3 $DM_DEV_DIR/$vg/4way & -+mkfs.ext3 "$DM_DEV_DIR/$vg/4way" & - sleep 1 - aux enable_dev "$dev2" "$dev4" - echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out -diff --git a/test/shell/lvconvert-thin-external.sh b/test/shell/lvconvert-thin-external.sh -index d9d4d19..00712bd 100644 ---- a/test/shell/lvconvert-thin-external.sh -+++ b/test/shell/lvconvert-thin-external.sh -@@ -49,16 +49,24 @@ fi - - lvcreate -l10 -T $vg/pool - # Can't convert pool to external origin --lvcreate -l10 -T $vg/pool1 -+lvcreate -l10 -T $vg/pool1 -c 192k - not lvconvert -T --thinpool $vg/pool1 $vg/pool --originname origin --lvremove -f $vg/pool1 -+# Create pool1 chunk_size unaligned LV and check failing conversion -+lvcreate -l2 -n $lv1 $vg -+not lvconvert -T --thinpool $vg/pool1 $vg/$lv1 -+ -+lvremove -f $vg/pool1 $vg/$lv1 - - # create plain LV (will be used for external origin) - lvcreate -L8M -n $lv1 $vg - --mkfs.ext2 $DM_DEV_DIR/$vg/$lv1 -+# Can't convert same LV to the thin pool and thin volume -+not lvconvert --thinpool $vg/$lv1 -T $vg/$lv1 -+check lv_field $vg/$lv1 segtype linear -+ -+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv1" - mkdir mnt --mount $DM_DEV_DIR/$vg/$lv1 mnt -+mount "$DM_DEV_DIR/$vg/$lv1" mnt - - dd if=/dev/zero of=mnt/test1 bs=1M count=1 - -@@ -76,7 +84,7 @@ touch mnt/test - umount mnt - - # check fs is without errors --fsck -n $DM_DEV_DIR/$vg/$lv1 -+fsck -n "$DM_DEV_DIR/$vg/$lv1" - - lvchange -aey $vg/extorg - lvchange -an $vg/$lv1 -@@ -85,7 +93,7 @@ check active $vg extorg - check inactive $vg $lv1 - - # fsck in read-only mode --fsck -n $DM_DEV_DIR/$vg/extorg -+fsck -n "$DM_DEV_DIR/$vg/extorg" - - not lvresize -l+8 $vg/extorg - not lvresize -l-4 $vg/extorg -diff --git a/test/shell/lvcreate-cache.sh b/test/shell/lvcreate-cache.sh -new file mode 100644 -index 0000000..ccfb4ad ---- /dev/null -+++ b/test/shell/lvcreate-cache.sh -@@ -0,0 +1,137 @@ -+#!/bin/sh -+# Copyright (C) 2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+. lib/test -+ -+aux target_at_least dm-cache 1 3 0 || skip -+ -+# Skip in cluster for now, but should test EX mode... -+test -e LOCAL_CLVMD && skip -+ -+aux prepare_vg 5 80 -+ -+#################### -+# Cache_Pool creation -+#################### -+ -+# Full CLI (the advertised form) -+lvcreate --type cache-pool -l 1 -n ${lv}_cache_pool $vg -+lvremove -ff $vg/${lv}_cache_pool -+ -+# Shorthand CLI (not advertised) -- not yet implemented -+# lvcreate --cache -l 1 vg -+# lvremove -ff $vg -+ -+# Shorthand CLI (not advertised) -- not yet implemented -+# lvcreate -H -l 1 vg -+# lvremove -ff $vg -+ -+################ -+# Cache creation -+# Creating a cache is a two phase process -+# - first, cache_pool (or origin) -+# - then, the cache LV (lvcreate distinguishes supplied origin vs cache_pool) -+################ -+ -+# Create/remove cache_pool -+lvcreate --type cache-pool -l 1 -n ${lv}_cache_pool $vg -+lvremove -ff $vg -+ -+# Create cache_pool, then origin with cache, then remove all -+lvcreate --type cache-pool -l 1 -n ${lv}_cache_pool $vg -+lvcreate --type cache -l 2 $vg/${lv}_cache_pool -n $lv1 -+dmsetup table ${vg}-$lv1 | grep cache # ensure it is loaded in kernel -+lvremove -ff $vg -+ -+# Create cache_pool, then origin with cache, then remove cache_pool/cache -+lvcreate --type cache-pool -l 1 -n ${lv}_cache_pool $vg -+lvcreate --type cache -l 2 $vg/${lv}_cache_pool -n $lv1 -+lvremove -ff $vg/${lv}_cache_pool -+lvremove -ff $vg/$lv1 -+ -+# Create cache_pool, then origin with cache, then remove origin -+lvcreate --type cache-pool -l 1 -n ${lv}_cache_pool $vg -+lvcreate --type cache -l 2 $vg/${lv}_cache_pool -n $lv1 -+lvremove -ff $vg/$lv1 -+lvremove -ff $vg/${lv}_cache_pool -+ -+# Shorthand CLI (cache_pool exists, create origin w/ cache) -+#lvcreate --type cache-pool -l 1 -n ${lv}_cache_pool $vg -+#lvcreate --cache -l 2 $vg/${lv}_cache_pool -n $lv1 -+#lvremove -ff $vg -+ -+# Shorthand CLI (cache_pool exists, create origin w/ cache) -+#lvcreate --type cache-pool -l 1 -n ${lv}_cache_pool $vg -+#lvcreate -H -l 2 $vg/${lv}_cache_pool -n $lv1 -+#lvremove -ff $vg -+ -+# Create origin, then cache_pool and cache -+lvcreate -l 2 -n $lv1 $vg -+lvcreate --type cache -l 1 $vg/$lv1 -+dmsetup table ${vg}-$lv1 | grep cache # ensure it is loaded in kernel -+lvremove -ff $vg -+ -+# Shorthand CLI (origin exists, create cache_pool and cache) -+#lvcreate -l 1 -n $lv1 $vg -+#lvcreate --cache -l 2 $vg/$lv1 -+#lvremove -ff $vg -+ -+# Shorthand CLI (origin exists, create cache_pool and cache) -+#lvcreate -l 1 -n $lv1 $vg -+#lvcreate -H -l 2 $vg/$lv1 -+#lvremove -ff $vg -+ -+ -+################################################ -+# Repeat key tests with 'writethrough' cachemode -+################################################ -+# Create/remove cache_pool -+lvcreate --type cache-pool -l 1 -n ${lv}_cache_pool $vg --cachemode writethrough -+lvremove -ff $vg -+ -+# Create cache_pool, then origin with cache, then remove all -+lvcreate --type cache-pool -l 1 -n ${lv}_cache_pool $vg -+lvcreate --type cache -l 2 $vg/${lv}_cache_pool -n $lv1 --cachemode writethrough -+lvremove -ff $vg -+ -+# Create cache_pool, then origin with cache, then remove cache_pool/cache -+lvcreate --type cache-pool -l 1 -n ${lv}_cache_pool $vg -+lvcreate --type cache -l 2 $vg/${lv}_cache_pool -n $lv1 --cachemode writethrough -+lvremove -ff $vg/${lv}_cache_pool -+lvremove -ff $vg/$lv1 -+ -+# Create cache_pool, then origin with cache, then remove origin -+lvcreate --type cache-pool -l 1 -n ${lv}_cache_pool $vg -+lvcreate --type cache -l 2 $vg/${lv}_cache_pool -n $lv1 --cachemode writethrough -+lvremove -ff $vg/$lv1 -+lvremove -ff $vg/${lv}_cache_pool -+ -+# Create origin, then cache_pool and cache -+lvcreate -l 2 -n $lv1 $vg -+lvcreate --type cache -l 1 $vg/$lv1 --cachemode writethrough -+lvremove -ff $vg -+ -+ -+############################## -+# Test things that should fail -+############################## -+ -+# Attempt to create smaller cache than origin should fail -+lvcreate -l 1 -n $lv1 $vg -+not lvcreate --type cache -l 2 $vg/$lv1 -+lvremove -ff $vg -+ -+ -+# Option testing -+# --chunksize -+# --cachepolicy -+# --poolmetadatasize -+# --poolmetadataspare -diff --git a/test/shell/lvcreate-large-raid.sh b/test/shell/lvcreate-large-raid.sh -index 395cf2b..e5d883c 100644 ---- a/test/shell/lvcreate-large-raid.sh -+++ b/test/shell/lvcreate-large-raid.sh -@@ -31,8 +31,8 @@ lvcreate -s -l 20%FREE -n $lv5 $vg --virtualsize 256T - - aux extend_filter_LVMTEST - --pvcreate $DM_DEV_DIR/$vg/$lv[12345] --vgcreate $vg1 $DM_DEV_DIR/$vg/$lv[12345] -+pvcreate "$DM_DEV_DIR"/$vg/$lv[12345] -+vgcreate $vg1 "$DM_DEV_DIR"/$vg/$lv[12345] - - # bz837927 START - -diff --git a/test/shell/lvcreate-large-raid10.sh b/test/shell/lvcreate-large-raid10.sh -index 4f97997..3d02e81 100644 ---- a/test/shell/lvcreate-large-raid10.sh -+++ b/test/shell/lvcreate-large-raid10.sh -@@ -28,8 +28,8 @@ lvcreate -s -l 20%FREE -n $lv5 $vg --virtualsize 256T - - aux extend_filter_LVMTEST - --pvcreate $DM_DEV_DIR/$vg/$lv[12345] --vgcreate $vg1 $DM_DEV_DIR/$vg/$lv[12345] -+pvcreate "$DM_DEV_DIR"/$vg/$lv[12345] -+vgcreate $vg1 "$DM_DEV_DIR"/$vg/$lv[12345] - - # - # Create large RAID LVs -diff --git a/test/shell/lvcreate-large.sh b/test/shell/lvcreate-large.sh -index c8790f1..f3d3f30 100644 ---- a/test/shell/lvcreate-large.sh -+++ b/test/shell/lvcreate-large.sh -@@ -25,8 +25,8 @@ lvcreate -s -l 100%FREE -n $lv $vg --virtualsize 1024T - - aux extend_filter_LVMTEST - --pvcreate $DM_DEV_DIR/$vg/$lv --vgcreate $vg1 $DM_DEV_DIR/$vg/$lv -+pvcreate "$DM_DEV_DIR/$vg/$lv" -+vgcreate $vg1 "$DM_DEV_DIR/$vg/$lv" - - lvcreate -l 100%FREE -n $lv1 $vg1 - check lv_field $vg1/$lv1 size "1024.00t" -diff --git a/test/shell/lvcreate-pvtags.sh b/test/shell/lvcreate-pvtags.sh -index 20a241c..340a4f4 100644 ---- a/test/shell/lvcreate-pvtags.sh -+++ b/test/shell/lvcreate-pvtags.sh -@@ -28,7 +28,7 @@ lvcreate -l3 -i3 $vg @fast - not lvcreate -l4 -i4 $vg @fast - - # 2 stripes is too many with just one PV --not lvcreate -l2 -i2 $vg $DM_DEV_DIR/mapper/pv1 -+not lvcreate -l2 -i2 $vg "$DM_DEV_DIR/mapper/pv1" - - # lvcreate mirror - lvcreate -aey -l1 --type mirror -m1 $vg @fast -diff --git a/test/shell/lvcreate-raid.sh b/test/shell/lvcreate-raid.sh -index 214b162..2053d04 100644 ---- a/test/shell/lvcreate-raid.sh -+++ b/test/shell/lvcreate-raid.sh -@@ -11,6 +11,14 @@ - - . lib/test - -+lv_devices() { -+ local local_vg=$1 -+ local local_lv=$2 -+ local count=$3 -+ -+ [ $count == `lvs --noheadings -o devices $local_vg/$local_lv | sed s/,/' '/g | wc -w` ] -+} -+ - ######################################################## - # MAIN - ######################################################## -@@ -70,3 +78,113 @@ for i in raid4 \ - aux wait_for_sync $vg $lv1 - lvremove -ff $vg - done -+ -+# Create RAID using 100%FREE -+############################ -+# 6 PVs with 18.5m in each PV. -+# 1 metadata LV = 1 extent = .5m -+# 1 image = 36+37+37 extents = 55.00m = lv_size -+lvcreate --type raid1 -m 1 -l 100%FREE -n raid1 $vg -+check lv_field $vg/raid1 size "55.00m" -+lvremove -ff $vg -+ -+# 1 metadata LV = 1 extent -+# 1 image = 36 extents -+# 5 images = 180 extents = 90.00m = lv_size -+lvcreate --type raid5 -i 5 -l 100%FREE -n raid5 $vg -+check lv_field $vg/raid5 size "90.00m" -+lvremove -ff $vg -+ -+# 1 image = 36+37 extents -+# 2 images = 146 extents = 73.00m = lv_size -+lvcreate --type raid5 -i 2 -l 100%FREE -n raid5 $vg -+check lv_field $vg/raid5 size "73.00m" -+lvremove -ff $vg -+ -+# 1 image = 36 extents -+# 4 images = 144 extents = 72.00m = lv_size -+lvcreate --type raid6 -i 4 -l 100%FREE -n raid6 $vg -+check lv_field $vg/raid6 size "72.00m" -+lvremove -ff $vg -+ -+# Eat 18 of 37 extents from dev1, leaving 19 -+lvcreate -l 18 -n lv $vg $dev1 -+# Using 100% free should take the rest of dev1 and equal from dev2 -+# 1 meta takes 1 extent -+# 1 image = 18 extents = 9.00m = lv_size -+lvcreate --type raid1 -m 1 -l 100%FREE -n raid1 $vg $dev1 $dev2 -+check lv_field $vg/raid1 size "9.00m" -+# Ensure image size is the same as the RAID1 size -+check lv_field $vg/raid1 size `lvs --noheadings -o size $vg/raid1_rimage_0` -+# Amount remaining in dev2 should equal the amount taken by 'lv' in dev1 -+check pv_field "$dev2" pv_free `lvs --noheadings -o size $vg/lv` -+lvremove -ff $vg -+ -+# Eat 18 of 37 extents from dev1, leaving 19 -+lvcreate -l 18 -n lv $vg $dev1 -+# Using 100% free should take the rest of dev1 and equal amount from the rest -+# 1 meta takes 1 extent -+# 1 image = 18 extents = 9.00m -+# 5 images = 90 extents = 45.00m = lv_size -+lvcreate --type raid5 -i 5 -l 100%FREE -n raid5 $vg -+check lv_field $vg/raid5 size "45.00m" -+# Amount remaining in dev6 should equal the amount taken by 'lv' in dev1 -+check pv_field "$dev6" pv_free `lvs --noheadings -o size $vg/lv` -+lvremove -ff $vg -+ -+# Eat 18 of 37 extents from dev1, leaving 19 -+lvcreate -l 18 -n lv $vg $dev1 -+# Using 100% free should take the rest of dev1, an equal amount -+# from 2 more devs, and all extents from 3 additional devs -+# 1 meta takes 1 extent -+# 1 image = 18+37 extents -+# 2 images = 110 extents = 55.00m = lv_size -+lvcreate --type raid5 -i 2 -l 100%FREE -n raid5 $vg -+check lv_field $vg/raid5 size "55.00m" -+lvremove -ff $vg -+ -+# Let's do some stripe tests too -+# Eat 18 of 37 extents from dev1, leaving 19 -+lvcreate -l 18 -n lv $vg $dev1 -+# Using 100% free should take the rest of dev1 and an equal amount from rest -+# 1 image = 19 extents -+# 6 images = 114 extents = 57.00m = lv_size -+lvcreate -i 6 -l 100%FREE -n stripe $vg -+check lv_field $vg/stripe size "57.00m" -+lvremove -ff $vg -+ -+# Eat 18 of 37 extents from dev1, leaving 19 -+lvcreate -l 18 -n lv $vg $dev1 -+# Using 100% free should take the rest of dev1, an equal amount from -+# one more dev, and all of the remaining 4 -+# 1 image = 19+37+37 extents -+# 2 images = 186 extents = 93.00m = lv_size -+lvcreate -i 2 -l 100%FREE -n stripe $vg -+check lv_field $vg/stripe size "93.00m" -+lvremove -ff $vg -+ -+# Create RAID (implicit stripe count based on PV count) -+####################################################### -+ -+# Not enough drives -+not lvcreate --type raid1 -l1 $vg $dev1 -+not lvcreate --type raid5 -l2 $vg $dev1 $dev2 -+not lvcreate --type raid6 -l3 $vg $dev1 $dev2 $dev3 $dev4 -+ -+# Implicit count comes from #PVs given (always 2 for mirror though) -+lvcreate --type raid1 -l1 -n raid1 $vg $dev1 $dev2 -+lv_devices $vg raid1 2 -+lvcreate --type raid5 -l2 -n raid5 $vg $dev1 $dev2 $dev3 -+lv_devices $vg raid5 3 -+lvcreate --type raid6 -l3 -n raid6 $vg $dev1 $dev2 $dev3 $dev4 $dev5 -+lv_devices $vg raid6 5 -+lvremove -ff $vg -+ -+# Implicit count comes from total #PVs in VG (always 2 for mirror though) -+lvcreate --type raid1 -l1 -n raid1 $vg -+lv_devices $vg raid1 2 -+lvcreate --type raid5 -l2 -n raid5 $vg -+lv_devices $vg raid5 6 -+lvcreate --type raid6 -l3 -n raid6 $vg -+lv_devices $vg raid6 6 -+lvremove -ff $vg -diff --git a/test/shell/lvcreate-raid10.sh b/test/shell/lvcreate-raid10.sh -index 143e869..ba35fdf 100644 ---- a/test/shell/lvcreate-raid10.sh -+++ b/test/shell/lvcreate-raid10.sh -@@ -11,6 +11,14 @@ - - . lib/test - -+lv_devices() { -+ local local_vg=$1 -+ local local_lv=$2 -+ local count=$3 -+ -+ [ $count == `lvs --noheadings -o devices $local_vg/$local_lv | sed s/,/' '/g | wc -w` ] -+} -+ - ######################################################## - # MAIN - ######################################################## -@@ -23,7 +31,6 @@ vgcreate -s 512k $vg $(cat DEVICES) - # Create RAID10: - # - -- - # Should not allow more than 2-way mirror - not lvcreate --type raid10 -m 2 -i 2 -l 2 -n $lv1 $vg - -@@ -46,6 +53,30 @@ aux wait_for_sync $vg $lv2 - - lvremove -ff $vg - -+# Test 100%FREE option -+# 37 extents / device -+# 1 image = 36 extents (1 for meta) -+# 3 images = 108 extents = 54.00m -+lvcreate --type raid10 -i 3 -l 100%FREE -n raid10 $vg -+check lv_field $vg/raid10 size "54.00m" -+lvremove -ff $vg -+ -+# Create RAID (implicit stripe count based on PV count) -+####################################################### -+ -+# Not enough drives -+not lvcreate --type raid10 -l2 $vg $dev1 $dev2 $dev3 -+ -+# Implicit count comes from #PVs given (always 2-way mirror) -+lvcreate --type raid10 -l2 -n raid10 $vg $dev1 $dev2 $dev3 $dev4 -+lv_devices $vg raid10 4 -+lvremove -ff $vg -+ -+# Implicit count comes from total #PVs in VG (always 2 for mirror though) -+lvcreate --type raid10 -l2 -n raid10 $vg -+lv_devices $vg raid10 6 -+lvremove -ff $vg -+ - # - # FIXME: Add tests that specify particular PVs to use for creation - # -diff --git a/test/shell/lvcreate-thin-external.sh b/test/shell/lvcreate-thin-external.sh -index c9aba6f..1e5b333 100644 ---- a/test/shell/lvcreate-thin-external.sh -+++ b/test/shell/lvcreate-thin-external.sh -@@ -26,11 +26,21 @@ aux prepare_pvs 2 64 - - vgcreate $vg -s 64K $(cat DEVICES) - -+# Test validation for external origin being multiple of thin pool chunk size -+lvcreate -L10M -T $vg/pool192 -c 192k -+lvcreate -an -pr -Zn -l1 -n $lv1 $vg -+not lvcreate -s $vg/$lv1 --thinpool $vg/pool192 -+ -+lvcreate -an -pr -Zn -l5 -n $lv2 $vg -+not lvcreate -s $vg/$lv2 --thinpool $vg/pool192 -+lvremove -f $vg -+ -+# Prepare pool and external origin with filesystem - lvcreate -L10M -V10M -T $vg/pool --name $lv1 --mkfs.ext2 $DM_DEV_DIR/$vg/$lv1 -+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv1" - - lvcreate -L4M -n $lv2 $vg --mkfs.ext2 $DM_DEV_DIR/$vg/$lv2 -+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv2" - - # Fail to create external origin snapshot of rw LV - not lvcreate -s $vg/$lv2 --thinpool $vg/pool -@@ -80,7 +90,7 @@ check active $vg $lv5 - check active $vg $lv6 - check active $vg $lv7 - --fsck -n $DM_DEV_DIR/$vg/$lv1 --fsck -n $DM_DEV_DIR/$vg/$lv7 -+fsck -n "$DM_DEV_DIR/$vg/$lv1" -+fsck -n "$DM_DEV_DIR/$vg/$lv7" - - vgremove -ff $vg -diff --git a/test/shell/lvcreate-thin-snap.sh b/test/shell/lvcreate-thin-snap.sh -index b7511e7..cfc801a 100644 ---- a/test/shell/lvcreate-thin-snap.sh -+++ b/test/shell/lvcreate-thin-snap.sh -@@ -33,11 +33,11 @@ aux prepare_pvs 2 64 - vgcreate $vg -s 64K $(cat DEVICES) - - lvcreate -L10M -V10M -T $vg/pool --name $lv1 --mkfs.ext4 $DM_DEV_DIR/$vg/$lv1 -+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1" - # create thin snapshot of thin LV - lvcreate -K -s $vg/$lv1 --name snap - # check snapshot filesystem was properly frozen before snapping --fsck -n $DM_DEV_DIR/$vg/snap -+fsck -n "$DM_DEV_DIR/$vg/snap" - lvcreate -K -s $vg/$lv1 --name $lv2 - lvcreate -K -s $vg/$lv1 --name $vg/$lv3 - lvcreate --type snapshot $vg/$lv1 -@@ -57,8 +57,8 @@ lvcreate -K -s --name sn4 $vg/sn3 - lvremove -ff $vg - - lvcreate -L10M --zero n -T $vg/pool -V10M --name $lv1 --mkfs.ext4 $DM_DEV_DIR/$vg/$lv1 -+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1" - lvcreate -K -s $vg/$lv1 --name snap --fsck -n $DM_DEV_DIR/$vg/snap -+fsck -n "$DM_DEV_DIR/$vg/snap" - - vgremove -ff $vg -diff --git a/test/shell/lvcreate-thin.sh b/test/shell/lvcreate-thin.sh -index 98ab7eb..a2811d2 100644 ---- a/test/shell/lvcreate-thin.sh -+++ b/test/shell/lvcreate-thin.sh -@@ -136,9 +136,9 @@ check vg_field $vg lv_count 0 - - # Create thin snapshot of thinLV - lvcreate -L10M -V10M -T $vg/pool --name lv1 --mkfs.ext4 $DM_DEV_DIR/$vg/lv1 -+mkfs.ext4 "$DM_DEV_DIR/$vg/lv1" - lvcreate -K -s $vg/lv1 --name snap_lv1 --fsck -n $DM_DEV_DIR/$vg/snap_lv1 -+fsck -n "$DM_DEV_DIR/$vg/snap_lv1" - lvcreate -s $vg/lv1 --name lv2 - lvcreate -s $vg/lv1 --name $vg/lv3 - lvcreate --type snapshot $vg/lv1 --name lv6 -diff --git a/test/shell/lvextend-thin-metadata-dmeventd.sh b/test/shell/lvextend-thin-metadata-dmeventd.sh -new file mode 100644 -index 0000000..cb5261c ---- /dev/null -+++ b/test/shell/lvextend-thin-metadata-dmeventd.sh -@@ -0,0 +1,93 @@ -+#!/bin/sh -+# Copyright (C) 2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+# Test autoextension of thin metadata volume -+. lib/test -+ -+meta_percent_() { -+ get lv_field $vg/pool metadata_percent | cut -d. -f1 -+} -+ -+wait_for_change_() { -+ # dmeventd only checks every 10 seconds :( -+ for i in $(seq 1 15) ; do -+ test "$(meta_percent_)" != "$1" && return -+ sleep 1 -+ done -+ -+ return 1 # timeout -+} -+ -+# -+# Temporary solution to create some occupied thin metadata -+# This heavily depends on thin metadata output format to stay as is. -+# Currently it expects 2MB thin metadata and 200MB data volume size -+# Argument specifies how many devices should be created. -+fake_metadata_() { -+ echo '' -+ for i in $(seq 1 $1) -+ do -+ echo ' ' -+ echo ' ' -+ echo ' ' -+ done -+ echo "" -+} -+ -+aux have_thin 1 10 0 || skip -+ -+aux prepare_dmeventd -+ -+aux lvmconf "activation/thin_pool_autoextend_percent = 10" \ -+ "activation/thin_pool_autoextend_threshold = 70" -+ -+aux prepare_pvs 3 256 -+ -+vgcreate -s 1M $vg $(cat DEVICES) -+ -+# Testing dmeventd autoresize -+lvcreate -L200M -V1G -n thin -T $vg/pool -+lvcreate -L2M -n $lv1 $vg -+lvchange -an $vg/thin $vg/pool -+ -+# Prepare some fake metadata with unmatching id -+# Transaction_id is lower by 1 and there are no message -> ERROR -+fake_metadata_ 10 0 >data -+thin_restore -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1" -+lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1 -+not vgchange -ay $vg 2>&1 | tee out -+grep expected out -+ -+check inactive $vg pool_tmeta -+ -+# Transaction_id is higher by 1 -+fake_metadata_ 10 2 >data -+thin_restore -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1" -+lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1 -+not vgchange -ay $vg 2>&1 | tee out -+grep expected out -+ -+check inactive $vg pool_tmeta -+ -+# Prepare some fake metadata prefilled to ~81% (>70%) -+fake_metadata_ 400 1 >data -+thin_restore -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1" -+ -+# Swap volume with restored fake metadata -+lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1 -+ -+vgchange -ay $vg -+ -+# Check dmeventd resizes metadata -+pre=$(meta_percent_) -+wait_for_change_ $pre -+ -+vgremove -f $vg -diff --git a/test/shell/lvmetad-disabled.sh b/test/shell/lvmetad-disabled.sh -index 41a3a19..c344d7f 100644 ---- a/test/shell/lvmetad-disabled.sh -+++ b/test/shell/lvmetad-disabled.sh -@@ -13,14 +13,17 @@ - - test -e LOCAL_LVMETAD || skip - kill $(cat LOCAL_LVMETAD) -+while test -e "$TESTDIR/lvmetad.socket"; do echo -n .; sleep .1; done # wait for the socket close -+test ! -e "$LVM_LVMETAD_PIDFILE" - --test -e $LVMETAD_PIDFILE && skip - lvmetad --test -e $LVMETAD_PIDFILE --cp $LVMETAD_PIDFILE LOCAL_LVMETAD -+while ! test -e "$TESTDIR/lvmetad.socket"; do echo -n .; sleep .1; done # wait for the socket -+test -e "$LVM_LVMETAD_PIDFILE" -+cp "$LVM_LVMETAD_PIDFILE" LOCAL_LVMETAD -+ - pvs 2>&1 | not grep "lvmetad is running" - aux lvmconf "global/use_lvmetad = 0" - pvs 2>&1 | grep "lvmetad is running" - --kill $(cat $LVMETAD_PIDFILE) --not ls $LVMETAD_PIDFILE -+kill $(cat "$LVM_LVMETAD_PIDFILE") -+not ls "$LVM_LVMETAD_PIDFILE" -diff --git a/test/shell/lvresize-thin-external-origin.sh b/test/shell/lvresize-thin-external-origin.sh -new file mode 100644 -index 0000000..3499196 ---- /dev/null -+++ b/test/shell/lvresize-thin-external-origin.sh -@@ -0,0 +1,42 @@ -+#!/bin/sh -+# Copyright (C) 2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+# Test resize of thin volume with external origin -+. lib/test -+ -+aux have_thin 1 2 0 || skip -+ -+# Pretend we miss the external_origin_extend feature -+aux lvmconf "global/thin_disabled_features = [ \"external_origin_extend\" ]" -+ -+aux prepare_pvs 2 -+ -+vgcreate -s 1M $vg $(cat DEVICES) -+ -+lvcreate -L10 -n $lv1 $vg -+ -+# Prepare thin pool -+lvcreate -L20 -T $vg/pool -+ -+# Convert $lv1 into thin LV with external origin -+lvconvert -T $vg/$lv1 --thinpool $vg/pool --originname ext -+ -+lvs -a $vg -+ -+# Bigger size is not supported without feature external_origin_extend -+not lvresize -L+10 $vg/$lv1 -+ -+# But reduction works -+lvresize -L-5 -f $vg/$lv1 -+not lvresize -L+15 -y $vg/$lv1 -+# Try to resize again back up to the size of external origin -+# But for now we do not support zeroing for rexetended areas. -+not lvresize -L+5 -f $vg/$lv1 -diff --git a/test/shell/lvresize-thin-metadata.sh b/test/shell/lvresize-thin-metadata.sh -index 16a7500..e62d8b6 100644 ---- a/test/shell/lvresize-thin-metadata.sh -+++ b/test/shell/lvresize-thin-metadata.sh -@@ -1,5 +1,5 @@ - #!/bin/sh --# Copyright (C) 2013 Red Hat, Inc. All rights reserved. -+# Copyright (C) 2013-2014 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 -@@ -11,31 +11,35 @@ - - . lib/test - --aux have_thin 9 9 0 || skip -+aux have_thin 1 10 0 || skip - --aux prepare_pvs 3 256 -+aux prepare_pvs 3 1256 - - vgcreate -s 1M $vg $(cat DEVICES) - - for deactivate in true false; do -- lvcreate -l1 -T $vg/pool -- -- test $deactivate && lvchange -an $vg -- -+# Create some thin volumes -+ lvcreate -L20 -V30 -n $lv1 -T $vg/pool -+ lvcreate -s $vg/$lv1 - # Confirm we have basic 2M metadata - check lv_field $vg/pool_tmeta size "2.00m" - -- lvresize --poolmetadata +2 $vg/pool -+ test $deactivate && lvchange -an $vg - -+ lvresize --poolmetadata +2M $vg/pool - # Test it's been resized to 4M - check lv_field $vg/pool_tmeta size "4.00m" - --# TODO: Add more tests when kernel is fixed -- lvresize --alloc anywhere --poolmetadata +256 $vg/pool -+ lvresize --poolmetadata +256M $vg/pool -+ check lv_field $vg/pool_tmeta size "260.00m" -+ -+ lvresize --poolmetadata +3G $vg/pool -+ check lv_field $vg/pool_tmeta size "3.25g" - - vgchange -an $vg - vgchange -ay $vg - --# TODO: Make a full metadata device and test dmeventd support -+# TODO: Add more tests -+ - lvremove -ff $vg - done -diff --git a/test/shell/lvresize-usage.sh b/test/shell/lvresize-usage.sh -index 51ef221..84431ed 100644 ---- a/test/shell/lvresize-usage.sh -+++ b/test/shell/lvresize-usage.sh -@@ -1,5 +1,5 @@ - #!/bin/sh --# Copyright (C) 2007-2008 Red Hat, Inc. All rights reserved. -+# Copyright (C) 2007-2014 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 -@@ -11,7 +11,7 @@ - - . lib/test - --aux prepare_vg 2 -+aux prepare_vg 2 80 - - lvcreate -L 10M -n lv -i2 $vg - lvresize -l +4 $vg/lv -@@ -19,3 +19,8 @@ lvremove -ff $vg - - lvcreate -L 64M -n $lv -i2 $vg - not lvresize -v -l +4 xxx/$lv -+ -+# Check stripe size is reduced to extent size when it's bigger -+ESIZE=$(get vg_field $vg vg_extent_size --units b) -+lvextend -L+64m -i 2 -I$(( ${ESIZE%%B} * 2 ))B $vg/$lv 2>&1 | tee err -+grep "Reducing stripe size" err -diff --git a/test/shell/name-mangling.sh b/test/shell/name-mangling.sh -index 5b92e60..76d90fa 100644 ---- a/test/shell/name-mangling.sh -+++ b/test/shell/name-mangling.sh -@@ -164,8 +164,8 @@ function check_mangle_cmd() - # check dmsetup can process path where the last component is not equal dm name (rhbz #797322) - r=0 - create_dm_dev auto "abc" --ln -s ${DM_DEV_DIR}/mapper/${name_prefix}abc ${DM_DEV_DIR}/${name_prefix}xyz --dmsetup status ${DM_DEV_DIR}/${name_prefix}xyz || r=1 -+ln -s "$DM_DEV_DIR/mapper/${name_prefix}abc" "$DM_DEV_DIR/${name_prefix}xyz" -+dmsetup status "$DM_DEV_DIR/${name_prefix}xyz" || r=1 - remove_dm_dev auto "abc" - if [ r = 1 ]; then - exit 1 -diff --git a/test/shell/process-each-lv.sh b/test/shell/process-each-lv.sh -index 0140c26..207f1ba 100644 ---- a/test/shell/process-each-lv.sh -+++ b/test/shell/process-each-lv.sh -@@ -36,139 +36,88 @@ aux prepare_devs 10 - # test lvremove vg|lv names - # - --# set up vgs/lvs that we will remove --vgcreate $vg1 "$dev1" "$dev2" --vgcreate $vg2 "$dev3" "$dev4" --vgcreate $vg3 "$dev5" "$dev6" --vgcreate $vg4 "$dev7" "$dev8" --vgcreate $vg5 "$dev9" "$dev10" --lvcreate -l 2 -n $lv1 $vg1 --lvcreate -l 2 -n $lv1 $vg2 --lvcreate -l 2 -n $lv2 $vg2 --lvcreate -l 2 -n $lv1 $vg3 --lvcreate -l 2 -n $lv2 $vg3 --lvcreate -l 2 -n $lv3 $vg3 --lvcreate -l 2 -n $lv1 $vg5 --lvcreate -l 2 -n $lv2 $vg5 --lvcreate -l 2 -n $lv3 $vg5 --lvcreate -l 2 -n $lv4 $vg5 --lvcreate -l 2 -n $lv5 $vg5 --vgchange -an $vg1 --vgchange -an $vg2 --vgchange -an $vg3 --vgchange -an $vg4 --vgchange -an $vg5 -+prepare_vgs_() { -+ # set up vgs/lvs that we will remove -+ vgcreate $vg1 "$dev1" "$dev2" -+ vgcreate $vg2 "$dev3" "$dev4" -+ vgcreate $vg3 "$dev5" "$dev6" -+ vgcreate $vg4 "$dev7" "$dev8" -+ vgcreate $vg5 "$dev9" "$dev10" -+ lvcreate -Zn -an -l 2 -n $lv1 $vg1 -+ lvcreate -Zn -an -l 2 -n $lv1 $vg2 -+ lvcreate -Zn -an -l 2 -n $lv2 $vg2 -+ lvcreate -Zn -an -l 2 -n $lv1 $vg3 -+ lvcreate -Zn -an -l 2 -n $lv2 $vg3 -+ lvcreate -Zn -an -l 2 -n $lv3 $vg3 -+ lvcreate -Zn -an -l 2 -n $lv1 $vg5 -+ lvcreate -Zn -an -l 2 -n $lv2 $vg5 -+ lvcreate -Zn -an -l 2 -n $lv3 $vg5 -+ lvcreate -Zn -an -l 2 -n $lv4 $vg5 -+ lvcreate -Zn -an -l 2 -n $lv5 $vg5 -+} -+ -+# -+# -+# -+prepare_vgs_ - - not lvremove - not lvremove garbage - not lvremove $vg1/garbage - - lvremove $vg1 --lvs $vg1 --not lvs $vg1/$lv1 -+check lv_exists $vg1 -+check lv_not_exists $vg1 $lv1 - vgremove $vg1 - - lvremove $vg2 --lvs $vg2 --not lvs $vg2/$lv1 --not lvs $vg2/$lv2 -+check lv_exists $vg2 -+check lv_not_exists $vg2 $lv1 $lv2 - vgremove $vg2 - - lvremove $vg3/$lv1 - lvremove $vg3/$lv2 $vg3/$lv3 --lvs $vg3 --not lvs $vg3/$lv1 --not lvs $vg3/$lv2 --not lvs $vg3/$lv3 -+check lv_exists $vg3 -+check lv_not_exists $vg3 $lv1 $lv2 $lv3 - vgremove $vg3 - - lvremove $vg4 --lvs $vg4 -+check lv_exists $vg4 - vgremove $vg4 - - lvremove $vg5/$lv1 $vg5 $vg5/$lv3 --not lvs $vg5/$lv1 --not lvs $vg5/$lv2 --not lvs $vg5/$lv3 --not lvs $vg5/$lv4 --not lvs $vg5/$lv5 -+check lv_not_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5 - vgremove $vg5 - - - # - # test lvremove vg|lv names from multiple vgs - # -- --# set up vgs/lvs that we will remove --vgcreate $vg1 "$dev1" "$dev2" --vgcreate $vg2 "$dev3" "$dev4" --vgcreate $vg3 "$dev5" "$dev6" --vgcreate $vg4 "$dev7" "$dev8" --vgcreate $vg5 "$dev9" "$dev10" --lvcreate -l 2 -n $lv1 $vg1 --lvcreate -l 2 -n $lv1 $vg2 --lvcreate -l 2 -n $lv2 $vg2 --lvcreate -l 2 -n $lv1 $vg3 --lvcreate -l 2 -n $lv2 $vg3 --lvcreate -l 2 -n $lv3 $vg3 --lvcreate -l 2 -n $lv1 $vg5 --lvcreate -l 2 -n $lv2 $vg5 --lvcreate -l 2 -n $lv3 $vg5 --lvcreate -l 2 -n $lv4 $vg5 --lvcreate -l 2 -n $lv5 $vg5 --vgchange -an $vg1 --vgchange -an $vg2 --vgchange -an $vg3 --vgchange -an $vg4 --vgchange -an $vg5 -+prepare_vgs_ - - lvremove $vg2 $vg3/$lv3 $vg5/$lv1 --not lvs $vg2/$lv1 --not lvs $vg2/$lv2 --not lvs $vg3/$lv3 --not lvs $vg5/$lv1 -+check lv_not_exists $vg2 $lv1 $lv2 -+check lv_not_exists $vg3 $lv3 -+check lv_not_exists $vg5 $lv1 - - lvremove $vg2 $vg1 --not lvs $vg1/$lv1 -+check lv_not_exists $vg1 $lv1 - - lvremove $vg3/$lv1 $vg3 $vg4 $vg5/$lv2 --not lvs $vg3/$lv1 --not lvs $vg3/$lv2 --not lvs $vg5/$lv2 -+check lv_not_exists $vg3 $lv1 $lv2 -+check lv_not_exists $vg5 $lv2 - - lvremove $vg5 $vg1 $vg5/$lv3 --not lvs $vg5/$lv3 --not lvs $vg5/$lv4 --not lvs $vg5/$lv5 -+check lv_not_exists $vg5 $lv3 $lv4 $lv5 - --vgremove $vg1 --vgremove $vg2 --vgremove $vg3 --vgremove $vg4 --vgremove $vg5 -+vgremove $vg1 $vg2 $vg3 $vg4 $vg5 - - - # - # test lvremove @lvtags - # -+prepare_vgs_ - --# set up vgs/lvs that we will remove --vgcreate $vg1 "$dev1" "$dev2" --vgcreate $vg2 "$dev3" "$dev4" --vgcreate $vg3 "$dev5" "$dev6" --vgcreate $vg4 "$dev7" "$dev8" --vgcreate $vg5 "$dev9" "$dev10" --lvcreate -l 2 -n $lv1 $vg1 --lvcreate -l 2 -n $lv1 $vg2 --lvcreate -l 2 -n $lv2 $vg2 --lvcreate -l 2 -n $lv1 $vg3 --lvcreate -l 2 -n $lv2 $vg3 --lvcreate -l 2 -n $lv3 $vg3 --lvcreate -l 2 -n $lv1 $vg5 --lvcreate -l 2 -n $lv2 $vg5 --lvcreate -l 2 -n $lv3 $vg5 --lvcreate -l 2 -n $lv4 $vg5 --lvcreate -l 2 -n $lv5 $vg5 - lvchange --addtag V1L1 $vg1/$lv1 - lvchange --addtag V2L1 $vg2/$lv1 - lvchange --addtag V2L2 $vg2/$lv2 -@@ -185,99 +134,52 @@ lvchange --addtag V5L234 $vg5/$lv2 - lvchange --addtag V5L234 $vg5/$lv3 - lvchange --addtag V5L234 $vg5/$lv4 - lvchange --addtag V5L5 $vg5/$lv5 --vgchange -an $vg1 --vgchange -an $vg2 --vgchange -an $vg3 --vgchange -an $vg4 --vgchange -an $vg5 -+vgchange -an $vg1 $vg2 $vg3 $vg4 $vg5 - - # verify all exist --lvs $vg1/$lv1 --lvs $vg2/$lv1 --lvs $vg2/$lv2 --lvs $vg3/$lv1 --lvs $vg3/$lv2 --lvs $vg3/$lv3 --lvs $vg5/$lv1 --lvs $vg5/$lv2 --lvs $vg5/$lv3 --lvs $vg5/$lv4 --lvs $vg5/$lv5 -+check lv_exists $vg1 $lv1 -+check lv_exists $vg2 $lv1 $lv2 -+check lv_exists $vg3 $lv1 $lv2 $lv3 -+check lv_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5 - - lvremove @garbage - - lvremove @V3L3A --not lvs $vg3/$lv3 -+check lv_not_exists $vg3 $lv3 - # verify unremoved still exist --lvs $vg1/$lv1 --lvs $vg2/$lv1 --lvs $vg2/$lv2 --lvs $vg3/$lv1 --lvs $vg3/$lv2 --lvs $vg5/$lv1 --lvs $vg5/$lv2 --lvs $vg5/$lv3 --lvs $vg5/$lv4 --lvs $vg5/$lv5 -+check lv_exists $vg1 $lv1 -+check lv_exists $vg2 $lv1 $lv2 -+check lv_exists $vg3 $lv1 $lv2 -+check lv_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5 - - lvremove @V5L234 --not lvs $vg5/$lv2 --not lvs $vg5/$lv3 --not lvs $vg5/$lv4 -+check lv_not_exists $vg5 $lv2 $lv3 $lv4 - # verify unremoved still exist --lvs $vg1/$lv1 --lvs $vg2/$lv1 --lvs $vg2/$lv2 --lvs $vg3/$lv1 --lvs $vg3/$lv2 --lvs $vg5/$lv1 --lvs $vg5/$lv5 -+check lv_exists $vg1 $lv1 -+check lv_exists $vg2 $lv1 $lv2 -+check lv_exists $vg3 $lv1 $lv2 -+check lv_exists $vg5 $lv1 $lv5 - - lvremove @V5L1 @V5L5 --not lvs $vg5/$lv1 --not lvs $vg5/$lv5 -+check lv_not_exists $vg5 $lv1 $lv5 - # verify unremoved still exist --lvs $vg1/$lv1 --lvs $vg2/$lv1 --lvs $vg2/$lv2 --lvs $vg3/$lv1 --lvs $vg3/$lv2 -+check lv_exists $vg1 $lv1 -+check lv_exists $vg2 $lv1 $lv2 -+check lv_exists $vg3 $lv1 $lv2 - - lvremove @V23 @V1L1 @V3L2 --not lvs $vg1/$lv1 --not lvs $vg2/$lv1 --not lvs $vg2/$lv2 --not lvs $vg3/$lv1 --not lvs $vg3/$lv2 -+check lv_not_exists $vg1 $lv1 -+check lv_not_exists $vg2 $lv1 $lv2 -+check lv_not_exists $vg3 $lv1 $lv2 - --vgremove $vg1 --vgremove $vg2 --vgremove $vg3 --vgremove $vg4 --vgremove $vg5 -+vgremove $vg1 $vg2 $vg3 $vg4 $vg5 - - - # - # test lvremove @vgtags - # -+prepare_vgs_ - --# set up vgs/lvs that we will remove --vgcreate $vg1 "$dev1" "$dev2" --vgcreate $vg2 "$dev3" "$dev4" --vgcreate $vg3 "$dev5" "$dev6" --vgcreate $vg4 "$dev7" "$dev8" --vgcreate $vg5 "$dev9" "$dev10" --lvcreate -l 2 -n $lv1 $vg1 --lvcreate -l 2 -n $lv1 $vg2 --lvcreate -l 2 -n $lv2 $vg2 --lvcreate -l 2 -n $lv1 $vg3 --lvcreate -l 2 -n $lv2 $vg3 --lvcreate -l 2 -n $lv3 $vg3 --lvcreate -l 2 -n $lv1 $vg5 --lvcreate -l 2 -n $lv2 $vg5 --lvcreate -l 2 -n $lv3 $vg5 --lvcreate -l 2 -n $lv4 $vg5 --lvcreate -l 2 -n $lv5 $vg5 - vgchange --addtag V1 $vg1 - vgchange --addtag V23 $vg2 - vgchange --addtag V23 $vg3 -@@ -285,71 +187,34 @@ vgchange --addtag V35 $vg3 - vgchange --addtag V4 $vg4 - vgchange --addtag V35 $vg5 - vgchange --addtag V5 $vg5 --vgchange -an $vg1 --vgchange -an $vg2 --vgchange -an $vg3 --vgchange -an $vg4 --vgchange -an $vg5 -+vgchange -an $vg1 $vg2 $vg3 $vg4 $vg5 - - lvremove @V4 - # verify unremoved exist --lvs $vg1/$lv1 --lvs $vg2/$lv1 --lvs $vg2/$lv2 --lvs $vg3/$lv1 --lvs $vg3/$lv2 --lvs $vg3/$lv3 --lvs $vg5/$lv1 --lvs $vg5/$lv2 --lvs $vg5/$lv3 --lvs $vg5/$lv4 --lvs $vg5/$lv5 -+check lv_exists $vg1 $lv1 -+check lv_exists $vg2 $lv1 $lv2 -+check lv_exists $vg3 $lv1 $lv2 $lv3 -+check lv_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5 - - lvremove @V5 --not lvs $vg5/$lv1 --not lvs $vg5/$lv2 --not lvs $vg5/$lv3 --not lvs $vg5/$lv4 --not lvs $vg5/$lv5 -+check lv_not_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5 - # verify unremoved exist --lvs $vg1/$lv1 --lvs $vg2/$lv1 --lvs $vg2/$lv2 --lvs $vg3/$lv1 --lvs $vg3/$lv2 --lvs $vg3/$lv3 -+check lv_exists $vg1 $lv1 -+check lv_exists $vg2 $lv1 $lv2 -+check lv_exists $vg3 $lv1 $lv2 $lv3 - - lvremove @V1 @V23 --not lvs $vg1/$lv1 --not lvs $vg2/$lv1 --not lvs $vg2/$lv2 --not lvs $vg3/$lv1 --not lvs $vg3/$lv2 --not lvs $vg3/$lv3 -+check lv_not_exists $vg1 $lv1 -+check lv_not_exists $vg2 $lv1 $lv2 -+check lv_not_exists $vg3 $lv1 $lv2 $lv3 - --vgremove $vg1 --vgremove $vg2 --vgremove $vg3 --vgremove $vg4 --vgremove $vg5 -+vgremove $vg1 $vg2 $vg3 $vg4 $vg5 -+ -+# -+# -+# -+prepare_vgs_ - --# set up vgs/lvs that we will remove --vgcreate $vg1 "$dev1" "$dev2" --vgcreate $vg2 "$dev3" "$dev4" --vgcreate $vg3 "$dev5" "$dev6" --vgcreate $vg4 "$dev7" "$dev8" --vgcreate $vg5 "$dev9" "$dev10" --lvcreate -l 2 -n $lv1 $vg1 --lvcreate -l 2 -n $lv1 $vg2 --lvcreate -l 2 -n $lv2 $vg2 --lvcreate -l 2 -n $lv1 $vg3 --lvcreate -l 2 -n $lv2 $vg3 --lvcreate -l 2 -n $lv3 $vg3 --lvcreate -l 2 -n $lv1 $vg5 --lvcreate -l 2 -n $lv2 $vg5 --lvcreate -l 2 -n $lv3 $vg5 --lvcreate -l 2 -n $lv4 $vg5 --lvcreate -l 2 -n $lv5 $vg5 - vgchange --addtag V1 $vg1 - vgchange --addtag V23 $vg2 - vgchange --addtag V23 $vg3 -@@ -357,59 +222,26 @@ vgchange --addtag V35 $vg3 - vgchange --addtag V4 $vg4 - vgchange --addtag V35 $vg5 - vgchange --addtag V5 $vg5 --vgchange -an $vg1 --vgchange -an $vg2 --vgchange -an $vg3 --vgchange -an $vg4 --vgchange -an $vg5 - - lvremove @V35 @V5 --not lvs $vg3/$lv1 --not lvs $vg3/$lv2 --not lvs $vg3/$lv3 --not lvs $vg5/$lv1 --not lvs $vg5/$lv2 --not lvs $vg5/$lv3 --not lvs $vg5/$lv4 --not lvs $vg5/$lv5 -+check lv_not_exists $vg3 $lv1 $lv2 /$lv3 -+check lv_not_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5 - # verify unremoved exist --lvs $vg1/$lv1 --lvs $vg2/$lv1 --lvs $vg2/$lv2 -+check lv_exists $vg1 $lv1 -+check lv_exists $vg2 $lv1 $lv2 - - lvremove @V1 @V23 --not lvs $vg1/$lv1 --not lvs $vg2/$lv1 --not lvs $vg2/$lv2 -+check lv_not_exists $vg1 $lv1 -+check lv_not_exists $vg2 $lv1 $lv2 - --vgremove $vg1 --vgremove $vg2 --vgremove $vg3 --vgremove $vg4 --vgremove $vg5 -+vgremove $vg1 $vg2 $vg3 $vg4 $vg5 - - - # - # test lvremove vg|lv names and @lvtags - # -+prepare_vgs_ - --# set up vgs/lvs that we will remove --vgcreate $vg1 "$dev1" "$dev2" --vgcreate $vg2 "$dev3" "$dev4" --vgcreate $vg3 "$dev5" "$dev6" --vgcreate $vg4 "$dev7" "$dev8" --vgcreate $vg5 "$dev9" "$dev10" --lvcreate -l 2 -n $lv1 $vg1 --lvcreate -l 2 -n $lv1 $vg2 --lvcreate -l 2 -n $lv2 $vg2 --lvcreate -l 2 -n $lv1 $vg3 --lvcreate -l 2 -n $lv2 $vg3 --lvcreate -l 2 -n $lv3 $vg3 --lvcreate -l 2 -n $lv1 $vg5 --lvcreate -l 2 -n $lv2 $vg5 --lvcreate -l 2 -n $lv3 $vg5 --lvcreate -l 2 -n $lv4 $vg5 --lvcreate -l 2 -n $lv5 $vg5 - lvchange --addtag V1L1 $vg1/$lv1 - lvchange --addtag V2L1 $vg2/$lv1 - lvchange --addtag V2L2 $vg2/$lv2 -@@ -426,56 +258,27 @@ lvchange --addtag V5L234 $vg5/$lv2 - lvchange --addtag V5L234 $vg5/$lv3 - lvchange --addtag V5L234 $vg5/$lv4 - lvchange --addtag V5L5 $vg5/$lv5 --vgchange -an $vg1 --vgchange -an $vg2 --vgchange -an $vg3 --vgchange -an $vg4 --vgchange -an $vg5 -+vgchange -an $vg1 $vg2 $vg3 $vg4 $vg5 - - lvremove $vg1/$lv1 @V3L2 @V5L234 --not lvs $vg1/$lv1 --not lvs $vg3/$lv2 --not lvs $vg5/$lv2 --not lvs $vg5/$lv3 --not lvs $vg5/$lv4 -+check lv_not_exists $vg1 $lv1 -+check lv_not_exists $vg3 $lv2 -+check lv_not_exists $vg5 $lv2 $lv3 $lv4 - # verify unremoved exist --lvs $vg2/$lv1 --lvs $vg2/$lv2 --lvs $vg3/$lv1 --lvs $vg3/$lv3 --lvs $vg5/$lv1 --lvs $vg5/$lv5 -+check lv_exists $vg2 $lv1 $lv2 -+check lv_exists $vg3 $lv1 $lv3 -+check lv_exists $vg5 $lv1 $lv5 - - lvremove $vg2/$lv1 @V23 $vg5/$lv1 @V5L5 - --vgremove $vg1 --vgremove $vg2 --vgremove $vg3 --vgremove $vg4 --vgremove $vg5 -+vgremove $vg1 $vg2 $vg3 $vg4 $vg5 - - - # - # test lvremove vg|lv names and @vgtags - # -+prepare_vgs_ - --# set up vgs/lvs that we will remove --vgcreate $vg1 "$dev1" "$dev2" --vgcreate $vg2 "$dev3" "$dev4" --vgcreate $vg3 "$dev5" "$dev6" --vgcreate $vg4 "$dev7" "$dev8" --vgcreate $vg5 "$dev9" "$dev10" --lvcreate -l 2 -n $lv1 $vg1 --lvcreate -l 2 -n $lv1 $vg2 --lvcreate -l 2 -n $lv2 $vg2 --lvcreate -l 2 -n $lv1 $vg3 --lvcreate -l 2 -n $lv2 $vg3 --lvcreate -l 2 -n $lv3 $vg3 --lvcreate -l 2 -n $lv1 $vg5 --lvcreate -l 2 -n $lv2 $vg5 --lvcreate -l 2 -n $lv3 $vg5 --lvcreate -l 2 -n $lv4 $vg5 --lvcreate -l 2 -n $lv5 $vg5 - vgchange --addtag V1 $vg1 - vgchange --addtag V23 $vg2 - vgchange --addtag V23 $vg3 -@@ -483,56 +286,24 @@ vgchange --addtag V35 $vg3 - vgchange --addtag V4 $vg4 - vgchange --addtag V35 $vg5 - vgchange --addtag V5 $vg5 --vgchange -an $vg1 --vgchange -an $vg2 --vgchange -an $vg3 --vgchange -an $vg4 --vgchange -an $vg5 - - lvremove $vg1/$lv1 @V35 --not lvs $vg1/$lv1 --not lvs $vg3/$lv1 --not lvs $vg3/$lv2 --not lvs $vg3/$lv3 --not lvs $vg5/$lv1 --not lvs $vg5/$lv2 --not lvs $vg5/$lv3 --not lvs $vg5/$lv4 --not lvs $vg5/$lv5 -+check lv_not_exists $vg1 $lv1 -+check lv_not_exists $vg3 $lv1 $lv2 $lv3 -+check lv_not_exists $vg5 $lv1 $lv2 $lv3not $lv4 $lv5 - # verify unremoved exist --lvs $vg2/$lv1 --lvs $vg2/$lv2 -+check lv_exists $vg2 $lv1 $lv2 - - lvremove $vg2/$lv1 @V23 $vg2/$lv2 - --vgremove $vg1 --vgremove $vg2 --vgremove $vg3 --vgremove $vg4 --vgremove $vg5 -+vgremove $vg1 $vg2 $vg3 $vg4 $vg5 - - - # - # test lvremove @lvtags and @vgtags - # -+prepare_vgs_ - --# set up vgs/lvs that we will remove --vgcreate $vg1 "$dev1" "$dev2" --vgcreate $vg2 "$dev3" "$dev4" --vgcreate $vg3 "$dev5" "$dev6" --vgcreate $vg4 "$dev7" "$dev8" --vgcreate $vg5 "$dev9" "$dev10" --lvcreate -l 2 -n $lv1 $vg1 --lvcreate -l 2 -n $lv1 $vg2 --lvcreate -l 2 -n $lv2 $vg2 --lvcreate -l 2 -n $lv1 $vg3 --lvcreate -l 2 -n $lv2 $vg3 --lvcreate -l 2 -n $lv3 $vg3 --lvcreate -l 2 -n $lv1 $vg5 --lvcreate -l 2 -n $lv2 $vg5 --lvcreate -l 2 -n $lv3 $vg5 --lvcreate -l 2 -n $lv4 $vg5 --lvcreate -l 2 -n $lv5 $vg5 - lvchange --addtag V1L1 $vg1/$lv1 - lvchange --addtag V2L1 $vg2/$lv1 - lvchange --addtag V2L2 $vg2/$lv2 -@@ -557,57 +328,25 @@ vgchange --addtag V35 $vg3 - vgchange --addtag V4 $vg4 - vgchange --addtag V35 $vg5 - vgchange --addtag V5 $vg5 --vgchange -an $vg1 --vgchange -an $vg2 --vgchange -an $vg3 --vgchange -an $vg4 --vgchange -an $vg5 - - lvremove @V23 @V35 --not lvs $vg2/$lv1 --not lvs $vg2/$lv2 --not lvs $vg3/$lv1 --not lvs $vg3/$lv2 --not lvs $vg3/$lv3 --not lvs $vg5/$lv1 --not lvs $vg5/$lv2 --not lvs $vg5/$lv3 --not lvs $vg5/$lv4 --not lvs $vg5/$lv5 -+check lv_not_exists $vg2 $lv1 $lv2 -+check lv_not_exists $vg3 $lv1 $lv2 $lv3 -+check lv_not_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5 - # verify unremoved exist --lvs $vg1/$lv1 -+check lv_exists $vg1 $lv1 - - lvremove @V1 @V1L1 --not lvs $vg1/$lv1 -+check lv_not_exists $vg1 $lv1 - --vgremove $vg1 --vgremove $vg2 --vgremove $vg3 --vgremove $vg4 --vgremove $vg5 -+vgremove $vg1 $vg2 $vg3 $vg4 $vg5 - - - # - # test lvremove vg|lv names and @lvtags and @vgtags - # -+prepare_vgs_ - --# set up vgs/lvs that we will remove --vgcreate $vg1 "$dev1" "$dev2" --vgcreate $vg2 "$dev3" "$dev4" --vgcreate $vg3 "$dev5" "$dev6" --vgcreate $vg4 "$dev7" "$dev8" --vgcreate $vg5 "$dev9" "$dev10" --lvcreate -l 2 -n $lv1 $vg1 --lvcreate -l 2 -n $lv1 $vg2 --lvcreate -l 2 -n $lv2 $vg2 --lvcreate -l 2 -n $lv1 $vg3 --lvcreate -l 2 -n $lv2 $vg3 --lvcreate -l 2 -n $lv3 $vg3 --lvcreate -l 2 -n $lv1 $vg5 --lvcreate -l 2 -n $lv2 $vg5 --lvcreate -l 2 -n $lv3 $vg5 --lvcreate -l 2 -n $lv4 $vg5 --lvcreate -l 2 -n $lv5 $vg5 - lvchange --addtag V1L1 $vg1/$lv1 - lvchange --addtag V2L1 $vg2/$lv1 - lvchange --addtag V2L2 $vg2/$lv2 -@@ -632,60 +371,26 @@ vgchange --addtag V35 $vg3 - vgchange --addtag V4 $vg4 - vgchange --addtag V35 $vg5 - vgchange --addtag V5 $vg5 --vgchange -an $vg1 --vgchange -an $vg2 --vgchange -an $vg3 --vgchange -an $vg4 --vgchange -an $vg5 - - lvremove $vg1/$lv1 @V23 @V5L5 --not lvs $vg1/$lv1 --not lvs $vg2/$lv1 --not lvs $vg2/$lv2 --not lvs $vg3/$lv1 --not lvs $vg3/$lv2 --not lvs $vg3/$lv3 --not lvs $vg5/$lv5 -+check lv_not_exists $vg1 $lv1 -+check lv_not_exists $vg2 $lv1 $lv2 -+check lv_not_exists $vg3 $lv1 $lv2 $lv3 -+check lv_not_exists $vg5 $lv5 - # verify unremoved exist --lvs $vg5/$lv1 --lvs $vg5/$lv2 --lvs $vg5/$lv3 --lvs $vg5/$lv4 -+check lv_exists $vg5 $lv1 $lv2 $lv3 $lv4 - - lvremove $vg5/$lv2 @V5L234 @V5 --not lvs $vg5/$lv1 --not lvs $vg5/$lv2 --not lvs $vg5/$lv3 --not lvs $vg5/$lv4 -+check lv_not_exists $vg5 $lv1 $lv2 $lv3 $lv4 - --vgremove $vg1 --vgremove $vg2 --vgremove $vg3 --vgremove $vg4 --vgremove $vg5 -+vgremove $vg1 $vg2 $vg3 $vg4 $vg5 - - - # - # test lvs: empty, vg(s), lv(s), vgtag(s), lvtag(s), garbage, combinations - # -+prepare_vgs_ - --# set up vgs/lvs that we will remove --vgcreate $vg1 "$dev1" "$dev2" --vgcreate $vg2 "$dev3" "$dev4" --vgcreate $vg3 "$dev5" "$dev6" --vgcreate $vg4 "$dev7" "$dev8" --vgcreate $vg5 "$dev9" "$dev10" --lvcreate -l 2 -n $lv1 $vg1 --lvcreate -l 2 -n $lv1 $vg2 --lvcreate -l 2 -n $lv2 $vg2 --lvcreate -l 2 -n $lv1 $vg3 --lvcreate -l 2 -n $lv2 $vg3 --lvcreate -l 2 -n $lv3 $vg3 --lvcreate -l 2 -n $lv1 $vg5 --lvcreate -l 2 -n $lv2 $vg5 --lvcreate -l 2 -n $lv3 $vg5 --lvcreate -l 2 -n $lv4 $vg5 --lvcreate -l 2 -n $lv5 $vg5 - lvchange --addtag V1L1 $vg1/$lv1 - lvchange --addtag V2L1 $vg2/$lv1 - lvchange --addtag V2L2 $vg2/$lv2 -@@ -709,11 +414,6 @@ vgchange --addtag V35 $vg3 - vgchange --addtag V4 $vg4 - vgchange --addtag V35 $vg5 - vgchange --addtag V5 $vg5 --vgchange -an $vg1 --vgchange -an $vg2 --vgchange -an $vg3 --vgchange -an $vg4 --vgchange -an $vg5 - - # empty - lvs -o vg_name,lv_name --separator '-' >err -@@ -951,4 +651,3 @@ not grep $vg5-$lv2 err - not grep $vg5-$lv3 err - not grep $vg5-$lv4 err - not grep $vg5-$lv5 err -- -diff --git a/test/shell/pvmove-all-segtypes.sh b/test/shell/pvmove-all-segtypes.sh -index fcd8913..5e1c71c 100644 ---- a/test/shell/pvmove-all-segtypes.sh -+++ b/test/shell/pvmove-all-segtypes.sh -@@ -13,12 +13,11 @@ test_description="ensure pvmove works with all common segment types" - - . lib/test - --test -e LOCAL_CLVMD && skip - which mkfs.ext2 || skip - which md5sum || skip - - aux prepare_pvs 5 20 --vgcreate -c n -s 256k $vg $(cat DEVICES) -+vgcreate -s 256k $vg $(cat DEVICES) - - # Each of the following tests does: - # 1) Create two LVs - one linear and one other segment type -@@ -27,8 +26,8 @@ vgcreate -c n -s 256k $vg $(cat DEVICES) - # 3) Move only the second LV by name - - # Testing pvmove of linear LV --lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" --lvcreate -l 2 -n $lv1 $vg "$dev1" -+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1" -+lvcreate -aey -l 2 -n $lv1 $vg "$dev1" - check lv_tree_on $vg ${lv1}_foo "$dev1" - check lv_tree_on $vg $lv1 "$dev1" - aux mkdev_md5sum $vg $lv1 -@@ -43,8 +42,8 @@ check dev_md5sum $vg $lv1 - lvremove -ff $vg - - # Testing pvmove of stripe LV --lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" --lvcreate -l 4 -i 2 -n $lv1 $vg "$dev1" "$dev2" -+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1" -+lvcreate -aey -l 4 -i 2 -n $lv1 $vg "$dev1" "$dev2" - check lv_tree_on $vg ${lv1}_foo "$dev1" - check lv_tree_on $vg $lv1 "$dev1" "$dev2" - aux mkdev_md5sum $vg $lv1 -@@ -58,9 +57,14 @@ check lv_tree_on $vg ${lv1}_foo "$dev5" - check dev_md5sum $vg $lv1 - lvremove -ff $vg - -+if test -e LOCAL_CLVMD ; then -+#FIXME these tests currently fail end require cmirrord -+echo "TEST WARNING, FIXME!!! pvmove in clustered VG not fully supported!" -+else -+ - # Testing pvmove of mirror LV --lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" --lvcreate -l 2 --type mirror -m 1 -n $lv1 $vg "$dev1" "$dev2" -+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1" -+lvcreate -aey -l 2 --type mirror -m 1 -n $lv1 $vg "$dev1" "$dev2" - check lv_tree_on $vg ${lv1}_foo "$dev1" - check lv_tree_on $vg $lv1 "$dev1" "$dev2" - aux mkdev_md5sum $vg $lv1 -@@ -76,8 +80,8 @@ lvremove -ff $vg - - # Dummy LV and snap share dev1, while origin is on dev2 - # Testing pvmove of snapshot LV --lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" --lvcreate -l 2 -n $lv1 $vg "$dev2" -+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1" -+lvcreate -aey -l 2 -n $lv1 $vg "$dev2" - lvcreate -s $vg/$lv1 -l 2 -n snap "$dev1" - check lv_tree_on $vg ${lv1}_foo "$dev1" - check lv_tree_on $vg snap "$dev1" -@@ -91,3 +95,4 @@ check lv_tree_on $vg snap "$dev4" - check lv_tree_on $vg ${lv1}_foo "$dev5" - check dev_md5sum $vg snap - lvremove -ff $vg -+fi -diff --git a/test/shell/pvmove-cache-segtypes.sh b/test/shell/pvmove-cache-segtypes.sh -new file mode 100644 -index 0000000..1c2423e ---- /dev/null -+++ b/test/shell/pvmove-cache-segtypes.sh -@@ -0,0 +1,178 @@ -+#!/bin/sh -+# Copyright (C) 2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+test_description="ensure pvmove works with the cache segment types" -+ -+. lib/test -+ -+# pvmove fails when a RAID LV is the origin of a cache LV -+# pvmoving cache types is currently disabled in tools/pvmove.c -+# So, for now we set everything up and make sure pvmove /isn't/ allowed. -+# This allows us to ensure that it is disallowed even when there are -+# stacking complications to consider. -+ -+test -e LOCAL_CLVMD && skip -+which mkfs.ext2 || skip -+which md5sum || skip -+ -+aux target_at_least dm-cache 1 3 0 || skip -+# for stacking -+aux target_at_least dm-thin-pool 1 8 0 || skip -+aux target_at_least dm-raid 1 4 2 || skip -+ -+aux prepare_vg 5 80 -+ -+# Each of the following tests does: -+# 1) Create two LVs - one linear and one other segment type -+# The two LVs will share a PV. -+# 2) Move both LVs together -+# 3) Move only the second LV by name -+ -+# Testing pvmove of cache-pool LV (can't check contents though) -+############################################################### -+lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" -+lvcreate --type cache-pool -n ${lv1}_pool -l 4 $vg "$dev1" -+check lv_tree_on $vg ${lv1}_foo "$dev1" -+check lv_tree_on $vg ${lv1}_pool "$dev1" -+ -+pvmove "$dev1" "$dev5" 2>&1 | tee out -+grep "Skipping cache-pool LV, ${lv1}_pool" out -+grep "Skipping cache-related LV, ${lv1}_pool_cmeta" out -+grep "Skipping cache-related LV, ${lv1}_pool_cdata" out -+check lv_tree_on $vg ${lv1}_foo "$dev5" -+not check lv_tree_on $vg ${lv1}_pool "$dev5" -+ -+#pvmove -n ${lv1}_pool "$dev5" "$dev4" -+#check lv_tree_on $vg ${lv1}_pool "$dev4" -+#check lv_tree_on $vg ${lv1}_foo "$dev5" -+ -+lvremove -ff $vg -+ -+# Testing pvmove of origin LV -+############################# -+lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" -+lvcreate --type cache-pool -n ${lv1}_pool -l 4 $vg "$dev5" -+lvcreate --type cache -n $lv1 -l 8 $vg/${lv1}_pool "$dev1" -+ -+check lv_tree_on $vg ${lv1}_foo "$dev1" -+check lv_tree_on $vg ${lv1}_pool "$dev5" -+check lv_tree_on $vg ${lv1} "$dev1" -+ -+aux mkdev_md5sum $vg $lv1 -+pvmove "$dev1" "$dev3" 2>&1 | tee out -+grep "Skipping cache LV, ${lv1}" out -+check lv_tree_on $vg ${lv1}_foo "$dev3" -+#check lv_tree_on $vg ${lv1}_pool "$dev5" -+lvs -a -o name,attr,devices $vg -+not check lv_tree_on $vg ${lv1} "$dev3" -+#check dev_md5sum $vg $lv1 -+ -+#pvmove -n $lv1 "$dev3" "$dev1" -+#check lv_tree_on $vg ${lv1}_foo "$dev3" -+#check lv_tree_on $vg ${lv1}_pool "$dev5" -+#check lv_tree_on $vg ${lv1} "$dev1" -+#check dev_md5sum $vg $lv1 -+lvremove -ff $vg -+ -+# Testing pvmove of a RAID origin LV -+#################################### -+lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" -+lvcreate --type raid1 -m 1 -l 8 -n $lv1 $vg "$dev1" "$dev2" -+lvcreate --type cache -l 4 -n ${lv1}_pool $vg/$lv1 "$dev5" -+check lv_tree_on $vg ${lv1}_foo "$dev1" -+check lv_tree_on $vg ${lv1} "$dev1" "$dev2" -+check lv_tree_on $vg ${lv1}_pool "$dev5" -+ -+aux mkdev_md5sum $vg $lv1 -+pvmove "$dev1" "$dev3" 2>&1 | tee out -+grep "Skipping cache LV, ${lv1}" out -+check lv_tree_on $vg ${lv1}_foo "$dev3" -+not check lv_tree_on $vg ${lv1} "$dev2" "$dev3" -+#check lv_tree_on $vg ${lv1}_pool "$dev5" -+#check dev_md5sum $vg $lv1 -- THIS IS WHERE THINGS FAIL IF PVMOVE NOT DISALLOWED -+ -+#pvmove -n $lv1 "$dev3" "$dev1" -+#check lv_tree_on $vg ${lv1}_foo "$dev3" -+#check lv_tree_on $vg ${lv1} "$dev1" "$dev2" -+#check lv_tree_on $vg ${lv1}_pool "$dev5" -+#check dev_md5sum $vg $lv1 -+lvremove -ff $vg -+ -+# Testing pvmove of a RAID cachepool (metadata and data) -+######################################################## -+lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" -+lvcreate --type raid1 -L 2M -n meta $vg "$dev1" "$dev2" -+lvcreate --type raid1 -L 4M -n ${lv1}_pool $vg "$dev1" "$dev2" -+lvconvert --type cache-pool $vg/${lv1}_pool --poolmetadata $vg/meta -+lvcreate --type cache -n $lv1 -L 8M $vg/${lv1}_pool "$dev5" -+ -+check lv_tree_on $vg ${lv1}_foo "$dev1" -+check lv_tree_on $vg ${lv1}_pool "$dev1" "$dev2" -+check lv_tree_on $vg ${lv1} "$dev5" -+ -+aux mkdev_md5sum $vg $lv1 -+# This will move ${lv1}_foo and the cache-pool data & meta -+# LVs, both of which contain a RAID1 _rimage & _rmeta LV - 5 total LVs -+pvmove "$dev1" "$dev3" 2>&1 | tee out -+grep "Skipping cache-pool LV, ${lv1}_pool" out -+grep "Skipping cache-related LV, ${lv1}_pool_cmeta" out -+grep "Skipping cache-related LV, ${lv1}_pool_cdata" out -+check lv_tree_on $vg ${lv1}_foo "$dev3" -+not check lv_tree_on $vg ${lv1}_pool "$dev2" "$dev3" -+#check lv_tree_on $vg ${lv1} "$dev5" -+#check dev_md5sum $vg $lv1 -+ -+#pvmove -n ${lv1}_pool "$dev3" "$dev1" -+#check lv_tree_on $vg ${lv1}_foo "$dev3" -+#check lv_tree_on $vg ${lv1}_pool "$dev1" "$dev2" -+#check lv_tree_on $vg ${lv1} "$dev5" -+#check dev_md5sum $vg $lv1 -+lvremove -ff $vg -+ -+# Testing pvmove of Thin-pool on cache LV on RAID -+################################################# -+lvcreate -l 2 -n ${lv1}_foo $vg "$dev1" -+# RAID for cachepool -+lvcreate --type raid1 -m 1 -L 2M -n meta $vg "$dev1" "$dev2" -+lvcreate --type raid1 -m 1 -L 4M -n cachepool $vg "$dev1" "$dev2" -+lvconvert --type cache-pool $vg/cachepool --poolmetadata $vg/meta -+# RAID for thin pool data LV -+lvcreate --type raid1 -m 1 -L 8 -n thinpool $vg "$dev3" "$dev4" -+# Convert thin pool data to a cached LV -+lvconvert --type cache $vg/thinpool --cachepool $vg/cachepool -+# Create simple thin pool meta -+lvcreate -L 2M -n meta $vg "$dev1" -+# Use thin pool data LV to build a thin pool -+lvconvert --thinpool $vg/thinpool --poolmetadata $vg/meta -+# Create a thin lv for fun -+lvcreate -T $vg/thinpool -V 20 -n thin_lv -+ -+check lv_tree_on $vg ${lv1}_foo "$dev1" -+check lv_tree_on $vg cachepool "$dev1" "$dev2" -+check lv_tree_on $vg thinpool "$dev1" "$dev3" "$dev4" -+ -+aux mkdev_md5sum $vg thin_lv -+lvs -a -o name,attr,devices $vg -+# Should move ${lv1}_foo and thinpool_tmeta from dev1 to dev5 -+pvmove "$dev1" "$dev5" 2>&1 | tee out -+lvs -a -o name,attr,devices $vg -+check lv_tree_on $vg ${lv1}_foo "$dev5" -+not check lv_tree_on $vg cachepool "$dev5" "$dev2" -+check lv_tree_on $vg thinpool "$dev3" "$dev4" "$dev5" # Move non-cache tmeta -+#check dev_md5sum $vg/thin_lv -+ -+#pvmove -n $vg/cachepool "$dev5" "$dev1" -+#check lv_tree_on $vg ${lv1}_foo "$dev5" -+#check lv_tree_on $vg $vg/cachepool "$dev1" "$dev2" -+#check lv_tree_on $vg $vg/thinpool "$dev3" "$dev4" -+#check dev_md5sum $vg/thin_lv -+ -+lvremove -ff $vg -\ No newline at end of file -diff --git a/test/shell/read-ahead.sh b/test/shell/read-ahead.sh -index 8c8f42c..264910c 100644 ---- a/test/shell/read-ahead.sh -+++ b/test/shell/read-ahead.sh -@@ -34,7 +34,7 @@ lvremove -ff $vg - blockdev --setra 768 "$dev1" - vgscan - lvcreate -n $lv -L4m $vg "$dev1" --test $(blockdev --getra $DM_DEV_DIR/$vg/$lv) -eq 768 -+test $(blockdev --getra "$DM_DEV_DIR/$vg/$lv") -eq 768 - lvremove -ff $vg - - # Check default, active/inactive values for read_ahead / kernel_read_ahead -diff --git a/test/shell/snapshot-usage.sh b/test/shell/snapshot-usage.sh -index 9e6a14f..cb60556 100644 ---- a/test/shell/snapshot-usage.sh -+++ b/test/shell/snapshot-usage.sh -@@ -13,8 +13,11 @@ - - . lib/test - -+MKFS=mkfs.ext2 -+which $MKFS || skip -+ - fill() { -- dd if=/dev/zero of=$DM_DEV_DIR/$vg1/lvol0 bs=$1 count=1 -+ dd if=/dev/zero of="$DM_DEV_DIR/$vg1/lvol0" bs=$1 count=1 - } - - cleanup_tail() -@@ -37,8 +40,8 @@ aux lvmconf "activation/snapshot_autoextend_percent = 20" \ - "activation/snapshot_autoextend_threshold = 50" - - # Check usability with smallest extent size --pvcreate --setphysicalvolumesize 4T $DM_DEV_DIR/$vg/$lv --vgcreate -s 1K $vg1 $DM_DEV_DIR/$vg/$lv -+pvcreate --setphysicalvolumesize 4T "$DM_DEV_DIR/$vg/$lv" -+vgcreate -s 1K $vg1 "$DM_DEV_DIR/$vg/$lv" - - # Test removal of opened snapshot - lvcreate -V50 -L10 -n $lv1 -s $vg1 -@@ -52,9 +55,12 @@ lvs -a -o+lv_active $vg1 - - trap 'cleanup_tail' EXIT - # Keep device busy (but not mounted) for a while --sleep 30 < $DM_DEV_DIR/$vg1/$lv1 & -+sleep 30 < "$DM_DEV_DIR/$vg1/$lv1" & - SLEEP_PID=$! - -+# give some short time to lock file above -+sleep 0.1 -+ - # Opened virtual snapshot device is not removable - # it should retry device removal for a few seconds - not lvremove -f $vg1/$lv1 -@@ -104,17 +110,46 @@ lvextend --use-policies $vg1/lvol1 - check lv_field $vg1/lvol1 size "18.00k" - - lvextend -l+33 $vg1/lvol1 --check lv_field $vg1/lvol1 size "28.00k" -+check lv_field $vg1/lvol1 size "32.00k" - - fill 20K -+lvremove -f $vg1 -+ -+# Check snapshot really deletes COW header for read-only snapshot -+# Test needs special relation between chunk size and extent size -+# This test expects extent size 1K -+aux lvmconf "allocation/wipe_signatures_when_zeroing_new_lvs = 1" -+lvcreate -aey -L4 -n $lv $vg1 -+lvcreate -c 8 -s -L1 -n snap $vg1/$lv -+# Populate snapshot -+#dd if=/dev/urandom of="$DM_DEV_DIR/$vg1/$lv" bs=4096 count=10 -+$MKFS "$DM_DEV_DIR/$vg1/$lv" -+lvremove -f $vg1/snap -+ -+# Undeleted header would trigger attempt to access -+# beyond end of COW device -+# Fails to create when chunk size is different -+lvcreate -s -pr -l12 -n snap $vg1/$lv -+ -+# When header is undelete, fails to read snapshot without read errors -+#dd if="$DM_DEV_DIR/$vg1/snap" of=/dev/null bs=1M count=2 -+fsck -n "$DM_DEV_DIR/$vg1/snap" -+ -+# This test would trigger read of weird percentage for undeleted header -+# And since older snapshot target counts with metadata sectors -+# we have 2 valid results (unsure about correct version number) -+EXPECT="0.00" -+aux target_at_least dm-snapshot 1 10 0 || EXPECT="66.67" -+check lv_field $vg1/snap data_percent "$EXPECT" -+ - vgremove -ff $vg1 - - # Can't test >= 16T devices on 32bit - if test "$TSIZE" -eq 15P ; then - - # Check usability with largest extent size --pvcreate $DM_DEV_DIR/$vg/$lv --vgcreate -s 4G $vg1 $DM_DEV_DIR/$vg/$lv -+pvcreate "$DM_DEV_DIR/$vg/$lv" -+vgcreate -s 4G $vg1 "$DM_DEV_DIR/$vg/$lv" - - lvcreate -an -Zn -l50%FREE -n $lv1 $vg1 - lvcreate -s -l100%FREE -n $lv2 $vg1/$lv1 -diff --git a/test/shell/thin-merge.sh b/test/shell/thin-merge.sh -index 10a81f0..7eb137e 100644 ---- a/test/shell/thin-merge.sh -+++ b/test/shell/thin-merge.sh -@@ -13,7 +13,8 @@ - - . lib/test - --which mkfs.ext2 || skip -+MKFS=mkfs.ext2 -+which $MKFS || skip - which fsck || skip - - # -@@ -27,14 +28,14 @@ lvcreate -T -L8M $vg/pool -V10M -n $lv1 - lvchange --addtag tagL $vg/$lv1 - - mkdir mnt --mkfs.ext2 $DM_DEV_DIR/$vg/$lv1 --mount $DM_DEV_DIR/$vg/$lv1 mnt -+$MKFS "$DM_DEV_DIR/$vg/$lv1" -+mount "$DM_DEV_DIR/$vg/$lv1" mnt - touch mnt/test - - lvcreate -K -s -n snap --addtag tagS $vg/$lv1 - mkdir mntsnap --mkfs.ext2 $DM_DEV_DIR/$vg/snap --mount $DM_DEV_DIR/$vg/snap mntsnap -+$MKFS "$DM_DEV_DIR/$vg/snap" -+mount "$DM_DEV_DIR/$vg/snap" mntsnap - touch mntsnap/test_snap - - lvs -o+tags,thin_id $vg -@@ -82,10 +83,10 @@ lvchange -ay $vg/$lv1 - check lv_exists $vg $lv1 - check lv_field $vg/$lv1 thin_id "2" - check lv_field $vg/$lv1 tags "tagL" --not check lv_exists $vg snap -+check lv_not_exists $vg snap - --fsck -n $DM_DEV_DIR/$vg/$lv1 --mount $DM_DEV_DIR/$vg/$lv1 mnt -+fsck -n "$DM_DEV_DIR/$vg/$lv1" -+mount "$DM_DEV_DIR/$vg/$lv1" mnt - test -e mnt/test_snap - umount mnt - -@@ -97,8 +98,10 @@ lvcreate -s -n snap $vg/$lv1 - # Also add old snapshot to thin origin - lvcreate -s -L10 -n oldsnapof_${lv1} $vg/$lv1 - not lvconvert --merge $vg/snap --lvremove -f $vg/oldsnapof_${lv1} -- -+$MKFS "$DM_DEV_DIR/$vg/oldsnapof_${lv1}" -+lvconvert --merge $vg/oldsnapof_${lv1} -+fsck -n "$DM_DEV_DIR/$vg/$lv1" -+check lv_not_exists $vg oldsnapof_${lv1} - # Add old snapshot to thin snapshot - lvcreate -s -L10 -n oldsnapof_snap $vg/snap - lvconvert --merge $vg/snap -diff --git a/test/shell/thin-vglock.sh b/test/shell/thin-vglock.sh -new file mode 100644 -index 0000000..083fcd8 ---- /dev/null -+++ b/test/shell/thin-vglock.sh -@@ -0,0 +1,51 @@ -+#!/bin/sh -+# Copyright (C) 2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+# Test locking works and doesn't update metadata -+# RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1063542 -+ -+. lib/test -+ -+MKFS=mkfs.ext2 -+which $MKFS || skip -+ -+aux have_thin 1 0 0 || skip -+aux prepare_vg -+ -+lvcreate -L10 -T -V5 -n $lv1 $vg/pool -+lvcreate -an -V10 -T $vg/pool -+ -+$MKFS "$DM_DEV_DIR/$vg/$lv1" -+mkdir mnt -+mount "$DM_DEV_DIR/$vg/$lv1" mnt -+ -+lvcreate -s -n snap $vg/$lv1 -+check lv_field $vg/snap thin_id "3" -+ -+lvconvert --merge $vg/snap -+ -+umount mnt -+vgchange -an $vg -+ -+# Check reboot case -+vgchange -ay --sysinit $vg -+# Metadata are still not updated (--poll n) -+check lv_field $vg/$lv1 thin_id "1" -+check lv_field $vg/pool transaction_id "3" -+ -+# Check the metadata are updated after refresh -+vgchange --refresh $vg -+check lv_field $vg/$lv1 thin_id "3" -+check lv_field $vg/pool transaction_id "4" -+ -+#lvs -a -o+transaction_id,thin_id $vg -+ -+vgremove -f $vg -diff --git a/test/shell/vgsplit-stacked.sh b/test/shell/vgsplit-stacked.sh -index 3256191..c8b89b5 100644 ---- a/test/shell/vgsplit-stacked.sh -+++ b/test/shell/vgsplit-stacked.sh -@@ -18,8 +18,8 @@ vgcreate $vg1 "$dev1" "$dev2" - lvcreate -n $lv1 -l 100%FREE $vg1 - - #top VG --pvcreate $DM_DEV_DIR/$vg1/$lv1 --vgcreate $vg $DM_DEV_DIR/$vg1/$lv1 "$dev3" -+pvcreate "$DM_DEV_DIR/$vg1/$lv1" -+vgcreate $vg "$DM_DEV_DIR/$vg1/$lv1" "$dev3" - - vgchange -a n $vg $vg1 - -diff --git a/tools/Makefile.in b/tools/Makefile.in -index f18d3ea..253c404 100644 ---- a/tools/Makefile.in -+++ b/tools/Makefile.in -@@ -43,6 +43,7 @@ SOURCES =\ - pvscan.c \ - reporter.c \ - segtypes.c \ -+ tags.c \ - toollib.c \ - vgcfgbackup.c \ - vgcfgrestore.c \ -@@ -166,7 +167,7 @@ liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION): liblvm2cmd.$(LIB_SUFFIX) - - .commands: $(srcdir)/commands.h $(srcdir)/cmdnames.h Makefile - $(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \ -- egrep -v '^ *(|#.*|devtypes|dumpconfig|formats|help|pvdata|segtypes|version) *$$' > .commands -+ egrep -v '^ *(|#.*|devtypes|dumpconfig|formats|help|pvdata|segtypes|tags|version) *$$' > .commands - - ifneq ("$(CFLOW_CMD)", "") - CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES)) -diff --git a/tools/args.h b/tools/args.h -index 1207189..f1a4ef4 100644 ---- a/tools/args.h -+++ b/tools/args.h -@@ -62,6 +62,8 @@ arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0) - arg(config_ARG, '\0', "config", string_arg, 0) - arg(trustcache_ARG, '\0', "trustcache", NULL, 0) - arg(cache_ARG, '\0', "cache", NULL, 0) -+arg(cachemode_ARG, '\0', "cachemode", string_arg, 0) -+arg(cachepool_ARG, '\0', "cachepool", string_arg, 0) - arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0) - arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0) - arg(unquoted_ARG, '\0', "unquoted", NULL, 0) -diff --git a/tools/commands.h b/tools/commands.h -index 938898b..b0d608b 100644 ---- a/tools/commands.h -+++ b/tools/commands.h -@@ -212,13 +212,27 @@ xx(lvconvert, - "\t[-T|--thin ExternalLogicalVolume[Path]\n" - "\t [--originname NewExternalOriginVolumeName]]\n" - "\t[-Z|--zero {y|n}]\n" -- "\t[-d|--debug] [-h|-?|--help] [-v|--verbose]\n", -+ "\t[-d|--debug] [-h|-?|--help] [-v|--verbose]\n\n" - -- alloc_ARG, background_ARG, chunksize_ARG, corelog_ARG, discards_ARG, -- force_ARG, interval_ARG, merge_ARG, mirrorlog_ARG, mirrors_ARG, name_ARG, -- noudevsync_ARG, originname_ARG, poolmetadata_ARG, poolmetadatasize_ARG, -- poolmetadataspare_ARG, readahead_ARG, regionsize_ARG, repair_ARG, -- replace_ARG, snapshot_ARG, splitmirrors_ARG, splitsnapshot_ARG, -+ "lvconvert " -+ "--type cache_pool\n" -+ "\t[--cachemode CacheMode]\n" -+ "\t[--chunksize size]\n" -+ "\t[--poolmetadata CacheMetadataLogicalVolume[Path] |\n" -+ "\t [--poolmetadatasize size]\n" -+ "\t [--poolmetadataspare {y|n}]]\n" -+ "\tCacheDataLogicalVolume[Path]\n\n" -+ -+ "lvconvert " -+ "--type cache\n" -+ "\t--cachepool CachePoolLogicalVolume[Path]\n" -+ "\tLogicalVolume[Path]\n\n", -+ -+ alloc_ARG, background_ARG, cachemode_ARG, cachepool_ARG, chunksize_ARG, -+ corelog_ARG, discards_ARG, force_ARG, interval_ARG, merge_ARG, mirrorlog_ARG, -+ mirrors_ARG, name_ARG, noudevsync_ARG, originname_ARG, poolmetadata_ARG, -+ poolmetadatasize_ARG, poolmetadataspare_ARG, readahead_ARG, regionsize_ARG, -+ repair_ARG, replace_ARG, snapshot_ARG, splitmirrors_ARG, splitsnapshot_ARG, - stripes_long_ARG, stripesize_ARG, test_ARG, thin_ARG, thinpool_ARG, - trackchanges_ARG, type_ARG, use_policies_ARG, zero_ARG) - -@@ -230,6 +244,7 @@ xx(lvcreate, - "\t[-a|--activate [a|e|l]{y|n}]\n" - "\t[--addtag Tag]\n" - "\t[--alloc AllocationPolicy]\n" -+ "\t[--cachemode CacheMode]\n" - "\t[-C|--contiguous {y|n}]\n" - "\t[-d|--debug]\n" - "\t[-h|-?|--help]\n" -@@ -296,9 +311,9 @@ xx(lvcreate, - "\t[PhysicalVolumePath...]\n\n", - - addtag_ARG, alloc_ARG, autobackup_ARG, activate_ARG, available_ARG, -- chunksize_ARG, contiguous_ARG, corelog_ARG, discards_ARG, extents_ARG, -- ignoreactivationskip_ARG, ignoremonitoring_ARG, major_ARG, minor_ARG, -- mirrorlog_ARG, mirrors_ARG, monitor_ARG, minrecoveryrate_ARG, -+ cachemode_ARG, chunksize_ARG, contiguous_ARG, corelog_ARG, discards_ARG, -+ extents_ARG, ignoreactivationskip_ARG, ignoremonitoring_ARG, major_ARG, -+ minor_ARG, mirrorlog_ARG, mirrors_ARG, monitor_ARG, minrecoveryrate_ARG, - maxrecoveryrate_ARG, name_ARG, nosync_ARG, noudevsync_ARG, - permission_ARG, persistent_ARG, poolmetadatasize_ARG, poolmetadataspare_ARG, - raidminrecoveryrate_ARG, raidmaxrecoveryrate_ARG, readahead_ARG, -@@ -789,6 +804,11 @@ xx(segtypes, - PERMITTED_READ_ONLY, - "segtypes\n") - -+xx(tags, -+ "List tags defined on this host", -+ PERMITTED_READ_ONLY, -+ "tags\n") -+ - xx(vgcfgbackup, - "Backup volume group configuration(s)", - PERMITTED_READ_ONLY, -diff --git a/tools/dumpconfig.c b/tools/dumpconfig.c -index 18fba34..cb88bc6 100644 ---- a/tools/dumpconfig.c -+++ b/tools/dumpconfig.c -@@ -193,6 +193,12 @@ int dumpconfig(struct cmd_context *cmd, int argc, char **argv) - goto out; - } - -+ if (arg_count(cmd, withcomments_ARG)) -+ tree_spec.withcomments = 1; -+ -+ if (arg_count(cmd, withversions_ARG)) -+ tree_spec.withversions = 1; -+ - if (cft_check_handle) - tree_spec.check_status = cft_check_handle->status; - -@@ -202,9 +208,7 @@ int dumpconfig(struct cmd_context *cmd, int argc, char **argv) - goto_out; - } - -- if (!config_write(cft, arg_count(cmd, withcomments_ARG), -- arg_count(cmd, withversions_ARG), -- file, argc, argv)) { -+ if (!config_write(cft, &tree_spec, file, argc, argv)) { - stack; - r = ECMD_FAILED; - } -diff --git a/tools/lvchange.c b/tools/lvchange.c -index a0e350f..8ceacc5 100644 ---- a/tools/lvchange.c -+++ b/tools/lvchange.c -@@ -215,11 +215,8 @@ static int _lvchange_activate(struct cmd_context *cmd, struct logical_volume *lv - - activate = (activation_change_t) arg_uint_value(cmd, activate_ARG, CHANGE_AY); - -- if (lv_activation_skip(lv, activate, arg_count(cmd, ignoreactivationskip_ARG), 0)) { -- log_verbose("ACTIVATON_SKIP flag set for LV %s/%s, skipping activation.", -- lv->vg->name, lv->name); -+ if (lv_activation_skip(lv, activate, arg_count(cmd, ignoreactivationskip_ARG))) - return 1; -- } - - if (lv_is_cow(lv) && !lv_is_virtual_origin(origin_from_cow(lv))) - lv = origin_from_cow(lv); -diff --git a/tools/lvconvert.c b/tools/lvconvert.c -index 87eb643..09a64c7 100644 ---- a/tools/lvconvert.c -+++ b/tools/lvconvert.c -@@ -28,6 +28,7 @@ struct lvconvert_params { - int zero; - - const char *origin; -+ const char *cachepool; - const char *lv_name; - const char *lv_split_name; - const char *lv_name_full; -@@ -45,6 +46,7 @@ struct lvconvert_params { - uint32_t stripes; - uint32_t stripe_size; - uint32_t read_ahead; -+ uint32_t feature_flags; /* cache_pool */ - - const struct segment_type *segtype; - unsigned target_attr; -@@ -198,7 +200,9 @@ static int _check_conversion_type(struct cmd_context *cmd, const char *type_str) - } - - /* FIXME: Check thin-pool and thin more thoroughly! */ -- if (!strcmp(type_str, "snapshot") || !strncmp(type_str, "raid", 4) || -+ if (!strcmp(type_str, "snapshot") || -+ !strncmp(type_str, "raid", 4) || -+ !strcmp(type_str, "cache-pool") || !strcmp(type_str, "cache") || - !strcmp(type_str, "thin-pool") || !strcmp(type_str, "thin")) - return 1; - -@@ -217,6 +221,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd, - int argc, char **argv) - { - int i; -+ int cache_pool = 0; - const char *tmp_str; - struct arg_value_group_list *group; - int region_size; -@@ -250,6 +255,20 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd, - return 0; - } - -+ if (!strcmp(type_str, "cache-pool")) { -+ cache_pool = 1; -+ if ((tmp_str = arg_str_value(cmd, cachemode_ARG, NULL))) { -+ if (!strcmp(tmp_str, "writeback")) -+ lp->feature_flags |= DM_CACHE_FEATURE_WRITEBACK; -+ else if (!strcmp(tmp_str, "writethrough")) -+ lp->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH; -+ else { -+ log_error("Unknown cachemode argument"); -+ return 0; -+ } -+ } -+ } -+ - if (!arg_count(cmd, background_ARG)) - lp->wait_completion = 1; - -@@ -270,28 +289,38 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd, - if (arg_count(cmd, thin_ARG)) - lp->thin = 1; - -- if (arg_count(cmd, thinpool_ARG)) { -+ if (arg_count(cmd, cachepool_ARG)) { -+ if (strcmp(type_str, "cache")) { -+ log_error("--cachepool argument is only valid with " -+ " the \"cache\" segment type"); -+ return 0; -+ } -+ lp->cachepool = arg_str_value(cmd, cachepool_ARG, NULL); -+ } else if (arg_count(cmd, thinpool_ARG) || cache_pool) { - if (arg_count(cmd, merge_ARG)) { -- log_error("--thinpool and --merge are mutually exlusive."); -+ log_error("--%spool and --merge are mutually exlusive.", -+ cache_pool ? "type cache_" : "thin"); - return 0; - } - if (mirror_or_raid_type_requested(cmd, type_str)) { -- log_error("--thinpool and --mirrors/--type mirror/--type raid* are mutually exlusive."); -+ log_error("--%spool and --mirrors/--type mirror/--type raid* are mutually exlusive.", cache_pool ? "type cache_" : "thin"); - return 0; - } - if (arg_count(cmd, repair_ARG)) { -- log_error("--thinpool and --repair are mutually exlusive."); -+ log_error("--%spool and --repair are mutually exlusive.", -+ cache_pool ? "type cache_" : "thin"); - return 0; - } - if (snapshot_type_requested(cmd, type_str)) { -- log_error("--thinpool and --snapshot/--type snapshot are mutually exlusive."); -+ log_error("--%spool and --snapshot/--type snapshot are mutually exlusive.", cache_pool ? "type cache_" : "thin"); - return 0; - } - if (arg_count(cmd, splitmirrors_ARG)) { -- log_error("--thinpool and --splitmirrors are mutually exlusive."); -+ log_error("--%spool and --splitmirrors are mutually exlusive.", cache_pool ? "type cache_" : "thin"); - return 0; - } -- lp->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN); -+ if (!cache_pool) -+ lp->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN); - } else if (lp->thin) { - log_error("--thin is only valid with --thinpool."); - return 0; -@@ -442,8 +471,15 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd, - tmp_str))) - return_0; - } -- } else if (arg_count(cmd, thinpool_ARG)) { -- if (!(lp->pool_data_lv_name = arg_str_value(cmd, thinpool_ARG, NULL))) { -+ } else if (arg_count(cmd, thinpool_ARG) || cache_pool) { -+ if (cache_pool) { -+ if (!argc) { -+ log_error("Please specify the pool data LV."); -+ return 0; -+ } -+ lp->pool_data_lv_name = argv[0]; -+ argv++, argc--; -+ } else if (!(lp->pool_data_lv_name = arg_str_value(cmd, thinpool_ARG, NULL))) { - log_error("Missing pool logical volume name."); - return 0; - } -@@ -469,7 +505,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd, - lp->read_ahead = arg_uint_value(cmd, readahead_ARG, - cmd->default_settings.read_ahead); - -- /* If --thinpool contains VG name, extract it. */ -+ /* If pool_data_lv_name contains VG name, extract it. */ - if ((tmp_str = strchr(lp->pool_data_lv_name, (int) '/'))) { - if (!(lp->vg_name = extract_vgname(cmd, lp->pool_data_lv_name))) - return 0; -@@ -484,7 +520,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd, - } - } - -- lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "thin-pool")); -+ lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, cache_pool ? "cache-pool" : "thin-pool")); - if (!lp->segtype) - return_0; - } else { /* Mirrors (and some RAID functions) */ -@@ -861,7 +897,7 @@ int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, - - if (lv_is_merging_origin(lv)) - return poll_daemon(cmd, lv_full_name, uuid, background, 0, -- lv_is_thin_volume(lv) ? -+ seg_is_thin_volume(find_snapshot(lv)) ? - &_lvconvert_thin_merge_fns : &_lvconvert_merge_fns, - "Merged"); - -@@ -2483,6 +2519,9 @@ static int _lvconvert_thinpool_external(struct cmd_context *cmd, - - dm_list_init(&lvc.tags); - -+ if (!pool_supports_external_origin(first_seg(pool_lv), external_lv)) -+ return_0; -+ - if (!(lvc.segtype = get_segtype_from_string(cmd, "thin"))) - return_0; - -@@ -2549,17 +2588,46 @@ revert_new_lv: - return 0; - } - -+static int _lvconvert_update_pool_params(struct logical_volume *pool_lv, -+ struct lvconvert_params *lp) -+{ -+ if (seg_is_cache_pool(lp)) -+ return update_cache_pool_params(pool_lv->vg, lp->target_attr, -+ lp->passed_args, -+ pool_lv->le_count, -+ pool_lv->vg->extent_size, -+ &lp->thin_chunk_size_calc_policy, -+ &lp->chunk_size, -+ &lp->discards, -+ &lp->poolmetadata_size, -+ &lp->zero); -+ -+ return update_thin_pool_params(pool_lv->vg, lp->target_attr, -+ lp->passed_args, -+ pool_lv->le_count, -+ pool_lv->vg->extent_size, -+ &lp->thin_chunk_size_calc_policy, -+ &lp->chunk_size, -+ &lp->discards, -+ &lp->poolmetadata_size, -+ &lp->zero); -+} -+ -+ -+ - /* - * Thin lvconvert version which - * rename metadata - * convert/layers thinpool over data - * attach metadata - */ --static int _lvconvert_thinpool(struct cmd_context *cmd, -- struct logical_volume *pool_lv, -- struct lvconvert_params *lp) -+static int _lvconvert_to_pool(struct cmd_context *cmd, -+ struct logical_volume *pool_lv, -+ struct lvconvert_params *lp) - { - int r = 0; -+ uint64_t min_metadata_size; -+ uint64_t max_metadata_size; - const char *old_name; - struct lv_segment *seg; - struct logical_volume *data_lv; -@@ -2582,6 +2650,12 @@ static int _lvconvert_thinpool(struct cmd_context *cmd, - } - - if (lp->thin) { -+ if (strcmp(pool_lv->name, lp->pool_data_lv_name) == 0) { -+ log_error("Can't use same LV %s/%s for thin pool and thin volume.", -+ pool_lv->vg->name, pool_lv->name); -+ return 0; -+ } -+ - external_lv = pool_lv; - if (!(pool_lv = find_lv(external_lv->vg, lp->pool_data_lv_name))) { - log_error("Can't find pool LV %s/%s.", -@@ -2626,20 +2700,21 @@ static int _lvconvert_thinpool(struct cmd_context *cmd, - return 0; - } - -- if ((dm_snprintf(metadata_name, sizeof(metadata_name), "%s_tmeta", -- pool_lv->name) < 0) || -- (dm_snprintf(data_name, sizeof(data_name), "%s_tdata", -- pool_lv->name) < 0)) { -+ if ((dm_snprintf(metadata_name, sizeof(metadata_name), "%s%s", -+ pool_lv->name, -+ (segtype_is_cache_pool(lp->segtype)) ? -+ "_cmeta" : "_tmeta") < 0) || -+ (dm_snprintf(data_name, sizeof(data_name), "%s%s", -+ pool_lv->name, -+ (segtype_is_cache_pool(lp->segtype)) ? -+ "_cdata" : "_tdata") < 0)) { - log_error("Failed to create internal lv names, " -- "thin pool name is too long."); -+ "pool name is too long."); - return 0; - } - - if (!lp->pool_metadata_lv_name) { -- if (!update_pool_params(pool_lv->vg, lp->target_attr, lp->passed_args, -- pool_lv->le_count, pool_lv->vg->extent_size, -- &lp->thin_chunk_size_calc_policy, &lp->chunk_size, -- &lp->discards, &lp->poolmetadata_size, &lp->zero)) -+ if (!_lvconvert_update_pool_params(pool_lv, lp)) - return_0; - - if (!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size)) -@@ -2733,37 +2808,40 @@ static int _lvconvert_thinpool(struct cmd_context *cmd, - } - - lp->poolmetadata_size = metadata_lv->size; -- if (lp->poolmetadata_size > (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)) { -+ max_metadata_size = (segtype_is_cache_pool(lp->segtype)) ? -+ DEFAULT_CACHE_POOL_MAX_METADATA_SIZE * 2 : -+ DEFAULT_THIN_POOL_MAX_METADATA_SIZE * 2; -+ min_metadata_size = (segtype_is_cache_pool(lp->segtype)) ? -+ DEFAULT_CACHE_POOL_MIN_METADATA_SIZE * 2 : -+ DEFAULT_THIN_POOL_MIN_METADATA_SIZE * 2; -+ -+ if (lp->poolmetadata_size > max_metadata_size) { - log_warn("WARNING: Maximum size used by metadata is %s, rest is unused.", -- display_size(cmd, 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)); -- lp->poolmetadata_size = 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE; -- } else if (lp->poolmetadata_size < (2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)) { -+ display_size(cmd, max_metadata_size)); -+ lp->poolmetadata_size = max_metadata_size; -+ } else if (lp->poolmetadata_size < min_metadata_size) { - log_error("Logical volume %s/%s is too small (<%s) for metadata.", - metadata_lv->vg->name, metadata_lv->name, -- display_size(cmd, 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)); -+ display_size(cmd, min_metadata_size)); - return 0; - } -- if (!update_pool_params(pool_lv->vg, lp->target_attr, lp->passed_args, -- pool_lv->le_count, pool_lv->vg->extent_size, -- &lp->thin_chunk_size_calc_policy, &lp->chunk_size, -- &lp->discards, &lp->poolmetadata_size, &lp->zero)) -+ if (!_lvconvert_update_pool_params(pool_lv, lp)) - return_0; - - metadata_lv->status |= LV_TEMPORARY; - if (!activate_lv_local(cmd, metadata_lv)) { -- log_error("Aborting. Failed to activate thin metadata lv."); -+ log_error("Aborting. Failed to activate metadata lv."); - return 0; - } - -- - if (!wipe_lv(metadata_lv, (struct wipe_params) { .do_zero = 1 })) { -- log_error("Aborting. Failed to wipe thin metadata lv."); -+ log_error("Aborting. Failed to wipe metadata lv."); - return 0; - } - } - - if (!deactivate_lv(cmd, metadata_lv)) { -- log_error("Aborting. Failed to deactivate thin metadata lv. " -+ log_error("Aborting. Failed to deactivate metadata lv. " - "Manual intervention required."); - return 0; - } -@@ -2774,7 +2852,7 @@ static int _lvconvert_thinpool(struct cmd_context *cmd, - - old_name = data_lv->name; /* Use for pool name */ - /* -- * Since we wish to have underlaying devs to match _tdata -+ * Since we wish to have underlaying devs to match _[ct]data - * rename data LV to match pool LV subtree first, - * also checks for visible LV. - */ -@@ -2783,7 +2861,9 @@ static int _lvconvert_thinpool(struct cmd_context *cmd, - return_0; - - if (!(pool_lv = lv_create_empty(old_name, NULL, -- THIN_POOL | VISIBLE_LV | LVM_READ | LVM_WRITE, -+ ((segtype_is_cache_pool(lp->segtype)) ? -+ CACHE_POOL : THIN_POOL) | -+ VISIBLE_LV | LVM_READ | LVM_WRITE, - ALLOC_INHERIT, data_lv->vg))) { - log_error("Creation of pool LV failed."); - return 0; -@@ -2791,8 +2871,8 @@ static int _lvconvert_thinpool(struct cmd_context *cmd, - - /* Allocate a new linear segment */ - if (!(seg = alloc_lv_segment(lp->segtype, pool_lv, 0, data_lv->le_count, -- pool_lv->status, 0, NULL, NULL, 1, data_lv->le_count, -- 0, 0, 0, NULL))) -+ pool_lv->status, 0, NULL, NULL, 1, -+ data_lv->le_count, 0, 0, 0, NULL))) - return_0; - - /* Add the new segment to the layer LV */ -@@ -2838,8 +2918,10 @@ mda_write: - goto out; - } - -- log_print_unless_silent("Converted %s/%s to thin pool.", -- pool_lv->vg->name, pool_lv->name); -+ log_print_unless_silent("Converted %s/%s to %s pool.", -+ pool_lv->vg->name, pool_lv->name, -+ (segtype_is_cache_pool(lp->segtype)) ? -+ "cache" : "thin"); - - r = 1; - out: -@@ -2852,6 +2934,41 @@ out: - return r; - } - -+static int _lvconvert_cache(struct logical_volume *origin, -+ struct lvconvert_params *lp) -+{ -+ struct cmd_context *cmd = origin->vg->cmd; -+ struct logical_volume *cache_lv; -+ struct logical_volume *cachepool; -+ -+ if (!lp->cachepool) { -+ log_error("--cachepool argument is required."); -+ return 0; -+ } -+ -+ if (!(cachepool = find_lv(origin->vg, lp->cachepool))) { -+ log_error("Unable to find cache pool LV, %s", lp->cachepool); -+ return 0; -+ } -+ -+ if (!(cache_lv = lv_cache_create(cachepool, origin))) -+ return_0; -+ -+ if (!vg_write(cache_lv->vg)) -+ return_0; -+ if (!suspend_lv(cmd, cache_lv)) -+ return_0; -+ if (!vg_commit(cache_lv->vg)) -+ return_0; -+ if (!resume_lv(cmd, cache_lv)) -+ return_0; -+ -+ log_print_unless_silent("%s/%s is now cached.", -+ cache_lv->vg->name, cache_lv->name); -+ -+ return 1; -+} -+ - static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv, - void *handle) - { -@@ -2884,7 +3001,9 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv, - !(lv->status & MIRRORED) && !(lv->status & RAID)) { - if (arg_count(cmd, use_policies_ARG)) - return ECMD_PROCESSED; /* nothing to be done here */ -- log_error("Can't repair non-mirrored LV \"%s\".", lv->name); -+ log_error("Can't repair LV \"%s\" of segtype %s.", -+ lv->name, -+ first_seg(lv)->segtype->ops->name(first_seg(lv))); - return ECMD_FAILED; - } - -@@ -2920,11 +3039,25 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv, - if (!_lvconvert_snapshot(cmd, lv, lp)) - return_ECMD_FAILED; - -+ } else if (segtype_is_cache(lp->segtype)) { -+ if (!archive(lv->vg)) -+ return_ECMD_FAILED; -+ -+ if (!_lvconvert_cache(lv, lp)) -+ return_ECMD_FAILED; -+ -+ } else if (segtype_is_cache_pool(lp->segtype)) { -+ if (!archive(lv->vg)) -+ return_ECMD_FAILED; -+ -+ if (!_lvconvert_to_pool(cmd, lv, lp)) -+ return_ECMD_FAILED; -+ - } else if (arg_count(cmd, thinpool_ARG)) { - if (!archive(lv->vg)) - return_ECMD_FAILED; - -- if (!_lvconvert_thinpool(cmd, lv, lp)) -+ if (!_lvconvert_to_pool(cmd, lv, lp)) - return_ECMD_FAILED; - - } else if (segtype_is_raid(lp->segtype) || -@@ -3001,6 +3134,7 @@ static int _poll_logical_volume(struct cmd_context *cmd, struct logical_volume * - log_print_unless_silent("Conversion starts after activation."); - return ECMD_PROCESSED; - } -+ - return lvconvert_poll(cmd, lv, wait_completion ? 0 : 1U); - } - -@@ -3019,8 +3153,7 @@ static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp - if (!lv) - goto_out; - -- if (arg_count(cmd, thinpool_ARG) && -- !get_pool_params(cmd, lv_config_profile(lv), -+ if (!get_pool_params(cmd, lv_config_profile(lv), - &lp->passed_args, &lp->thin_chunk_size_calc_policy, - &lp->chunk_size, &lp->discards, - &lp->poolmetadata_size, &lp->zero)) -diff --git a/tools/lvcreate.c b/tools/lvcreate.c -index d0ca7bc..ad00327 100644 ---- a/tools/lvcreate.c -+++ b/tools/lvcreate.c -@@ -1,6 +1,6 @@ - /* - * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. -- * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved. - * - * This file is part of LVM2. - * -@@ -21,7 +21,7 @@ struct lvcreate_cmdline_params { - percent_type_t percent; - uint64_t size; - char **pvs; -- int pv_count; -+ uint32_t pv_count; - }; - - static int _set_vg_name(struct lvcreate_params *lp, const char *vg_name) -@@ -73,8 +73,45 @@ static int _lvcreate_name_params(struct lvcreate_params *lp, - lp->lv_name = ptr + 1; - } - -- /* Need an origin? */ -- if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) { -+ if (seg_is_cache(lp)) { -+ /* -+ * We are looking for the origin or cache_pool LV. -+ * Could be in the form 'lv' or 'vg/lv' -+ * -+ * We store the lv name in 'lp->origin' for now, but -+ * it must be accessed later (when we can look-up the -+ * LV in the VG) whether it is truly the origin that -+ * was specified, or whether it is the cache_pool. -+ */ -+ if (!argc) { -+ log_error("Please specify a logical volume to act as " -+ "the origin or cache_pool."); -+ return 0; -+ } -+ -+ lp->origin = skip_dev_dir(cmd, argv[0], NULL); -+ if (strrchr(lp->origin, '/')) { -+ if (!_set_vg_name(lp, extract_vgname(cmd, lp->origin))) -+ return_0; -+ -+ /* Strip the volume group from the origin */ -+ if ((ptr = strrchr(lp->origin, (int) '/'))) -+ lp->origin = ptr + 1; -+ } -+ -+ if (!lp->vg_name && -+ !_set_vg_name(lp, extract_vgname(cmd, NULL))) -+ return_0; -+ -+ if (!lp->vg_name) { -+ log_error("The origin or cache_pool name should include" -+ " the volume group."); -+ return 0; -+ } -+ -+ lp->cache = 1; -+ (*pargv)++, (*pargc)--; -+ } else if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) { - /* argv[0] might be origin or vg/origin */ - if (!argc) { - log_error("Please specify a logical volume to act as " -@@ -227,6 +264,68 @@ static int _determine_snapshot_type(struct volume_group *vg, - return 1; - } - -+static int _lvcreate_update_pool_params(struct volume_group *vg, -+ struct lvcreate_params *lp) -+{ -+ if (seg_is_cache_pool(lp)) -+ return update_cache_pool_params(vg, lp->target_attr, -+ lp->passed_args, -+ lp->extents, vg->extent_size, -+ &lp->thin_chunk_size_calc_policy, -+ &lp->chunk_size, &lp->discards, -+ &lp->poolmetadatasize, -+ &lp->zero); -+ -+ return update_thin_pool_params(vg, lp->target_attr, lp->passed_args, -+ lp->extents, vg->extent_size, -+ &lp->thin_chunk_size_calc_policy, -+ &lp->chunk_size, &lp->discards, -+ &lp->poolmetadatasize, &lp->zero); -+} -+ -+/* -+ * _determine_cache_argument -+ * @vg -+ * @lp -+ * -+ * 'lp->origin' is set with an LV that could be either the origin -+ * or the cache_pool of the cached LV which is being created. This -+ * function determines which it is and sets 'lp->origin' or -+ * 'lp->pool' appropriately. -+ */ -+static int _determine_cache_argument(struct volume_group *vg, -+ struct lvcreate_params *lp) -+{ -+ struct lv_list *lvl; -+ -+ if (!seg_is_cache(lp)) { -+ log_error(INTERNAL_ERROR -+ "Unable to determine cache argument on %s segtype", -+ lp->segtype->name); -+ return 0; -+ } -+ -+ if (!(lvl = find_lv_in_vg(vg, lp->origin))) { -+ log_error("LV %s not found in Volume group %s.", -+ lp->origin, vg->name); -+ return 0; -+ } -+ -+ if (lv_is_cache_pool(lvl->lv)) { -+ lp->pool = lp->origin; -+ lp->origin = NULL; -+ } else { -+ lp->pool = NULL; -+ lp->create_pool = 1; -+ lp->poolmetadataspare = arg_int_value(vg->cmd, -+ poolmetadataspare_ARG, -+ DEFAULT_POOL_METADATA_SPARE); -+ lp->origin = lp->origin; -+ } -+ -+ return 1; -+} -+ - /* - * Update extents parameters based on other parameters which affect the size - * calculation. -@@ -264,19 +363,19 @@ static int _update_extents_params(struct volume_group *vg, - } else - lp->pvh = &vg->pvs; - -- switch(lcp->percent) { -+ switch (lcp->percent) { - case PERCENT_VG: -- lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0); -+ extents = percent_of_extents(lp->extents, vg->extent_count, 0); - break; - case PERCENT_FREE: -- lp->extents = percent_of_extents(lp->extents, vg->free_count, 0); -+ extents = percent_of_extents(lp->extents, vg->free_count, 0); - break; - case PERCENT_PVS: - if (lcp->pv_count) { - pv_extent_count = pv_list_extents_free(lp->pvh); -- lp->extents = percent_of_extents(lp->extents, pv_extent_count, 0); -+ extents = percent_of_extents(lp->extents, pv_extent_count, 0); - } else -- lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0); -+ extents = percent_of_extents(lp->extents, vg->extent_count, 0); - break; - case PERCENT_LV: - log_error("Please express size as %%VG, %%PVS, or " -@@ -293,10 +392,21 @@ static int _update_extents_params(struct volume_group *vg, - log_error(INTERNAL_ERROR "Couldn't find origin volume."); - return 0; - } -- lp->extents = percent_of_extents(lp->extents, origin->le_count, 0); -+ extents = percent_of_extents(lp->extents, origin->le_count, 0); - break; - case PERCENT_NONE: -+ extents = lp->extents; - break; -+ default: -+ log_error(INTERNAL_ERROR "Unsupported percent type %u.", lcp->percent); -+ return 0; -+ } -+ -+ if (lcp->percent) { -+ /* FIXME Don't do the adjustment for parallel allocation with PERCENT_ORIGIN! */ -+ lp->approx_alloc = 1; -+ log_verbose("Converted %" PRIu32 "%%%s into %" PRIu32 " extents.", lp->extents, get_percent_string(lcp->percent), extents); -+ lp->extents = extents; - } - - if (lp->snapshot && lp->origin && lp->extents) { -@@ -333,12 +443,8 @@ static int _update_extents_params(struct volume_group *vg, - lp->extents = lp->extents - size_rest; - } - -- if (lp->create_thin_pool) { -- if (!update_pool_params(vg, lp->target_attr, lp->passed_args, -- lp->extents, vg->extent_size, -- &lp->thin_chunk_size_calc_policy, -- &lp->chunk_size, &lp->discards, -- &lp->poolmetadatasize, &lp->zero)) -+ if (lp->create_pool) { -+ if (!_lvcreate_update_pool_params(vg, lp)) - return_0; - - if (!(lp->poolmetadataextents = -@@ -392,9 +498,9 @@ static int _read_size_params(struct lvcreate_params *lp, - - /* If size/extents given with thin, then we are creating a thin pool */ - if (seg_is_thin(lp) && (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG))) -- lp->create_thin_pool = 1; -+ lp->create_pool = 1; - -- if (!lp->create_thin_pool && arg_count(cmd, poolmetadatasize_ARG)) { -+ if (!lp->create_pool && arg_count(cmd, poolmetadatasize_ARG)) { - log_error("--poolmetadatasize may only be specified when allocating the thin pool."); - return 0; - } -@@ -522,20 +628,7 @@ static int _read_raid_params(struct lvcreate_params *lp, - return 0; - } - -- /* -- * get_stripe_params is called before _read_raid_params -- * and already sets: -- * lp->stripes -- * lp->stripe_size -- * -- * For RAID 4/5/6/10, these values must be set. -- */ -- if (!segtype_is_mirrored(lp->segtype) && -- (lp->stripes <= lp->segtype->parity_devs)) { -- log_error("Number of stripes must be at least %d for %s", -- lp->segtype->parity_devs + 1, lp->segtype->name); -- return 0; -- } else if (!strcmp(lp->segtype->name, "raid10") && (lp->stripes < 2)) { -+ if (!strcmp(lp->segtype->name, "raid10") && (lp->stripes < 2)) { - if (arg_count(cmd, stripes_ARG)) { - /* User supplied the bad argument */ - log_error("Segment type 'raid10' requires 2 or more stripes."); -@@ -594,13 +687,45 @@ static int _read_raid_params(struct lvcreate_params *lp, - - if (lp->max_recovery_rate && - (lp->max_recovery_rate < lp->min_recovery_rate)) { -- log_error("Minumum recovery rate cannot be higher than maximum."); -+ log_error("Minimum recovery rate cannot be higher than maximum."); - return 0; - } - return 1; - } - --static int _read_activation_params(struct lvcreate_params *lp, struct cmd_context *cmd, -+static int _read_cache_pool_params(struct lvcreate_params *lp, -+ struct cmd_context *cmd) -+{ -+ const char *str_arg; -+ -+ if (!segtype_is_cache_pool(lp->segtype)) -+ return 1; -+ -+ if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) { -+ log_error("Negative chunk size is invalid."); -+ return 0; -+ } -+ -+ lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, -+ DEFAULT_CACHE_POOL_CHUNK_SIZE * 2); -+ -+ str_arg = arg_str_value(cmd, cachemode_ARG, NULL); -+ if (str_arg) { -+ if (!strcmp(str_arg, "writeback")) -+ lp->feature_flags |= DM_CACHE_FEATURE_WRITEBACK; -+ else if (!strcmp(str_arg, "writethrough")) -+ lp->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH; -+ else { -+ log_error("Unknown cachemode argument"); -+ return 0; -+ } -+ } -+ -+ return 1; -+} -+ -+static int _read_activation_params(struct lvcreate_params *lp, -+ struct cmd_context *cmd, - struct volume_group *vg) - { - unsigned pagesize; -@@ -608,7 +733,7 @@ static int _read_activation_params(struct lvcreate_params *lp, struct cmd_contex - lp->activate = (activation_change_t) - arg_uint_value(cmd, activate_ARG, CHANGE_AY); - -- if (lp->activate == CHANGE_AN || lp->activate == CHANGE_ALN) { -+ if (!is_change_activating(lp->activate)) { - if (lp->zero && !seg_is_thin(lp)) { - log_error("--activate n requires --zero n"); - return 0; -@@ -644,8 +769,12 @@ static int _read_activation_params(struct lvcreate_params *lp, struct cmd_contex - lp->permission = arg_uint_value(cmd, permission_ARG, - LVM_READ | LVM_WRITE); - -- /* Must not zero/wipe read only volume */ -- if (!(lp->permission & LVM_WRITE)) { -+ if (lp->snapshot) { -+ /* Snapshot has to zero COW header */ -+ lp->zero = 1; -+ lp->wipe_signatures = 0; -+ } else if (!(lp->permission & LVM_WRITE)) { -+ /* Must not zero/wipe read only volume */ - lp->zero = 0; - lp->wipe_signatures = 0; - } -@@ -665,7 +794,7 @@ static int _read_activation_params(struct lvcreate_params *lp, struct cmd_contex - - /* Persistent minor */ - if (arg_count(cmd, persistent_ARG)) { -- if (lp->create_thin_pool && !lp->thin) { -+ if (lp->create_pool && !lp->thin) { - log_error("--persistent is not permitted when creating a thin pool device."); - return 0; - } -@@ -774,12 +903,15 @@ static int _lvcreate_params(struct lvcreate_params *lp, - (!seg_is_thin(lp) && arg_count(cmd, virtualsize_ARG))) - lp->snapshot = 1; - -+ if (seg_is_cache_pool(lp)) -+ lp->create_pool = 1; -+ - if (seg_is_thin_pool(lp)) { - if (lp->snapshot) { - log_error("Snapshots are incompatible with thin_pool segment_type."); - return 0; - } -- lp->create_thin_pool = 1; -+ lp->create_pool = 1; - } - - if (seg_is_thin_volume(lp)) -@@ -853,19 +985,16 @@ static int _lvcreate_params(struct lvcreate_params *lp, - } - } - -- if (activation() && lp->segtype->ops->target_present && -- !lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) { -- log_error("%s: Required device-mapper target(s) not " -- "detected in your kernel", lp->segtype->name); -- return 0; -- } else if (!strcmp(lp->segtype->name, "raid10")) { -- uint32_t maj, min, patchlevel; -- if (!target_version("raid", &maj, &min, &patchlevel)) { -- log_error("Failed to determine version of RAID kernel module"); -+ if (activation() && lp->segtype->ops->target_present) { -+ if (!lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) { -+ log_error("%s: Required device-mapper target(s) not detected in your kernel.", -+ lp->segtype->name); - return 0; - } -- if ((maj != 1) || (min < 3)) { -- log_error("RAID module does not support RAID10"); -+ -+ if ((strcmp(lp->segtype->name, "raid10") == 0) && -+ !(lp->target_attr & RAID_FEATURE_RAID10)) { -+ log_error("RAID module does not support RAID10."); - return 0; - } - } -@@ -873,13 +1002,13 @@ static int _lvcreate_params(struct lvcreate_params *lp, - /* - * Should we zero/wipe signatures on the lv. - */ -- lp->zero = strcmp(arg_str_value(cmd, zero_ARG, -- (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n"); -+ lp->zero = (!(lp->segtype->flags & SEG_CANNOT_BE_ZEROED) && -+ (strcmp(arg_str_value(cmd, zero_ARG, "y"), "y") == 0)) ? 1 : 0; - - if (arg_count(cmd, wipesignatures_ARG)) { - /* If -W/--wipesignatures is given on command line directly, respect it. */ -- lp->wipe_signatures = strcmp(arg_str_value(cmd, wipesignatures_ARG, -- (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n"); -+ lp->wipe_signatures =(!(lp->segtype->flags & SEG_CANNOT_BE_ZEROED) && -+ (strcmp(arg_str_value(cmd, wipesignatures_ARG, "y"), "y") == 0)) ? 1 : 0; - } else { - /* - * If -W/--wipesignatures is not given on command line, -@@ -895,13 +1024,14 @@ static int _lvcreate_params(struct lvcreate_params *lp, - if (!_lvcreate_name_params(lp, cmd, &argc, &argv) || - !_read_size_params(lp, lcp, cmd) || - !get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) || -- (lp->create_thin_pool && -+ (lp->create_pool && - !get_pool_params(cmd, NULL, &lp->passed_args, - &lp->thin_chunk_size_calc_policy, - &lp->chunk_size, &lp->discards, - &lp->poolmetadatasize, &lp->zero)) || - !_read_mirror_params(lp, cmd) || -- !_read_raid_params(lp, cmd)) -+ !_read_raid_params(lp, cmd) || -+ !_read_cache_pool_params(lp, cmd)) - return_0; - - if (lp->snapshot && (lp->extents || lcp->size)) { -@@ -920,12 +1050,12 @@ static int _lvcreate_params(struct lvcreate_params *lp, - - if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot"))) - return_0; -- } else if (!lp->create_thin_pool && arg_count(cmd, chunksize_ARG)) { -+ } else if (!lp->create_pool && arg_count(cmd, chunksize_ARG)) { - log_error("--chunksize is only available with snapshots and thin pools."); - return 0; - } - -- if (lp->create_thin_pool) { -+ if (lp->create_pool) { - /* TODO: add lvm.conf default y|n */ - lp->poolmetadataspare = arg_int_value(cmd, poolmetadataspare_ARG, - DEFAULT_POOL_METADATA_SPARE); -@@ -974,7 +1104,7 @@ static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_param - struct lv_list *lvl; - unsigned i; - -- if (!lp->thin && !lp->create_thin_pool && !lp->snapshot) { -+ if (!lp->thin && !lp->create_pool && !lp->snapshot) { - log_error("Please specify device size(s)."); - return 0; - } -@@ -984,7 +1114,7 @@ static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_param - return 0; - } - -- if (!lp->create_thin_pool) { -+ if (!lp->create_pool) { - static const int _argname[] = { - alloc_ARG, - chunksize_ARG, -@@ -1051,6 +1181,45 @@ static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_param - return 1; - } - -+static int _check_raid_parameters(struct volume_group *vg, -+ struct lvcreate_params *lp, -+ struct lvcreate_cmdline_params *lcp) -+{ -+ unsigned devs = lcp->pv_count ? : dm_list_size(&vg->pvs); -+ struct cmd_context *cmd = vg->cmd; -+ -+ /* -+ * If number of devices was not supplied, we can infer from -+ * the PVs given. -+ */ -+ if (!seg_is_mirrored(lp)) { -+ if (!arg_count(cmd, stripes_ARG) && -+ (devs > 2 * lp->segtype->parity_devs)) -+ lp->stripes = devs - lp->segtype->parity_devs; -+ -+ if (!lp->stripe_size) -+ lp->stripe_size = find_config_tree_int(cmd, metadata_stripesize_CFG, NULL) * 2; -+ -+ if (lp->stripes <= lp->segtype->parity_devs) { -+ log_error("Number of stripes must be at least %d for %s", -+ lp->segtype->parity_devs + 1, -+ lp->segtype->name); -+ return 0; -+ } -+ } else if (!strcmp(lp->segtype->name, "raid10")) { -+ if (!arg_count(cmd, stripes_ARG)) -+ lp->stripes = devs / lp->mirrors; -+ if (lp->stripes < 2) { -+ log_error("Unable to create RAID10 LV," -+ " insufficient number of devices."); -+ return 0; -+ } -+ } -+ /* 'mirrors' defaults to 2 - not the number of PVs supplied */ -+ -+ return 1; -+} -+ - /* - * Ensure the set of thin parameters extracted from the command line is consistent. - */ -@@ -1060,14 +1229,14 @@ static int _validate_internal_thin_processing(const struct lvcreate_params *lp) - - /* - The final state should be one of: -- thin create_thin_pool snapshot origin pool -- 1 1 0 0 y/n - create new pool and a thin LV in it -- 1 0 0 0 y - create new thin LV in existing pool -- 0 1 0 0 y/n - create new pool only -- 1 0 1 1 y - create thin snapshot of existing thin LV -+ thin create_pool snapshot origin pool -+ 1 1 0 0 y/n - create new pool and a thin LV in it -+ 1 0 0 0 y - create new thin LV in existing pool -+ 0 1 0 0 y/n - create new pool only -+ 1 0 1 1 y - create thin snapshot of existing thin LV - */ - -- if (!lp->create_thin_pool && !lp->pool) { -+ if (!lp->create_pool && !lp->pool) { - log_error(INTERNAL_ERROR "--thinpool not identified."); - r = 0; - } -@@ -1077,7 +1246,7 @@ static int _validate_internal_thin_processing(const struct lvcreate_params *lp) - r = 0; - } - -- if (!lp->thin && !lp->create_thin_pool && !lp->snapshot) { -+ if (!lp->thin && !lp->create_pool && !lp->snapshot) { - log_error(INTERNAL_ERROR "Failed to identify what type of thin target to use."); - r = 0; - } -@@ -1113,6 +1282,12 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv) - if (seg_is_thin(&lp) && !_check_thin_parameters(vg, &lp, &lcp)) - goto_out; - -+ if (seg_is_cache(&lp) && !_determine_cache_argument(vg, &lp)) -+ goto_out; -+ -+ if (seg_is_raid(&lp) && !_check_raid_parameters(vg, &lp, &lcp)) -+ goto_out; -+ - /* - * Check activation parameters to support inactive thin snapshot creation - * FIXME: anything else needs to be moved past _determine_snapshot_type()? -@@ -1126,7 +1301,7 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv) - if (seg_is_thin(&lp) && !_validate_internal_thin_processing(&lp)) - goto_out; - -- if (lp.create_thin_pool) { -+ if (lp.create_pool) { - if (!handle_pool_metadata_spare(vg, lp.poolmetadataextents, - lp.pvh, lp.poolmetadataspare)) - goto_out; -diff --git a/tools/pvmove.c b/tools/pvmove.c -index 19e1482..a7788ba 100644 ---- a/tools/pvmove.c -+++ b/tools/pvmove.c -@@ -233,6 +233,32 @@ static int sub_lv_of(struct logical_volume *lv, const char *lv_name) - return sub_lv_of(seg->lv, lv_name); - } - -+/* -+ * parent_lv_is_cache_type -+ * -+ * FIXME: This function can be removed when 'pvmove' is supported for -+ * cache types. -+ * -+ * If this LV is below a cache LV (at any depth), return 1. -+ */ -+static int parent_lv_is_cache_type(struct logical_volume *lv) -+{ -+ struct lv_segment *seg; -+ -+ /* Sub-LVs only ever have one segment using them */ -+ if (dm_list_size(&lv->segs_using_this_lv) != 1) -+ return 0; -+ -+ if (!(seg = get_only_segment_using_this_lv(lv))) -+ return_0; -+ -+ if (lv_is_cache_type(seg->lv)) -+ return 1; -+ -+ /* Continue up the tree */ -+ return parent_lv_is_cache_type(seg->lv); -+} -+ - /* Create new LV with mirror segments for the required copies */ - static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, - struct volume_group *vg, -@@ -342,6 +368,23 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, - if (!lv_is_on_pvs(lv, source_pvl)) - continue; - -+ if (lv_is_cache_type(lv)) { -+ log_print_unless_silent("Skipping %s LV, %s", -+ lv_is_cache(lv) ? "cache" : -+ lv_is_cache_pool(lv) ? -+ "cache-pool" : "cache-related", -+ lv->name); -+ lv_skipped = 1; -+ continue; -+ } -+ -+ if (parent_lv_is_cache_type(lv)) { -+ log_print_unless_silent("Skipping %s because a parent" -+ " is of cache type", lv->name); -+ lv_skipped = 1; -+ continue; -+ } -+ - /* - * If the VG is clustered, we are unable to handle - * snapshots, origins, thin types, RAID or mirror -diff --git a/tools/tags.c b/tools/tags.c -new file mode 100644 -index 0000000..bbb446a ---- /dev/null -+++ b/tools/tags.c -@@ -0,0 +1,23 @@ -+/* -+ * Copyright (C) 2014 Red Hat, Inc. All rights reserved. -+ * -+ * This file is part of LVM2. -+ * -+ * This copyrighted material is made available to anyone wishing to use, -+ * modify, copy, or redistribute it subject to the terms and conditions -+ * of the GNU Lesser General Public License v.2.1. -+ * -+ * You should have received a copy of the GNU Lesser General Public License -+ * along with this program; if not, write to the Free Software Foundation, -+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include "tools.h" -+ -+int tags(struct cmd_context *cmd, int argc __attribute__((unused)), -+ char **argv __attribute__((unused))) -+{ -+ display_tags(cmd); -+ -+ return ECMD_PROCESSED; -+} -diff --git a/tools/toollib.c b/tools/toollib.c -index 61c14f1..91b0559 100644 ---- a/tools/toollib.c -+++ b/tools/toollib.c -@@ -184,7 +184,7 @@ int ignore_vg(struct volume_group *vg, const char *vg_name, int allow_inconsiste - int process_each_lv_in_vg(struct cmd_context *cmd, - struct volume_group *vg, - const struct dm_list *arg_lvnames, -- const struct dm_list *tags, -+ const struct dm_list *tagsl, - struct dm_list *failed_lvnames, - void *handle, - process_single_lv_fn_t process_single_lv) -@@ -201,7 +201,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, - if (!vg_check_status(vg, EXPORTED_VG)) - return ECMD_FAILED; - -- if (tags && !dm_list_empty(tags)) -+ if (tagsl && !dm_list_empty(tagsl)) - tags_supplied = 1; - - if (arg_lvnames && !dm_list_empty(arg_lvnames)) -@@ -212,7 +212,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, - process_all = 1; - /* Or if VG tags match */ - else if (tags_supplied && -- str_list_match_list(tags, &vg->tags, NULL)) -+ str_list_match_list(tagsl, &vg->tags, NULL)) - process_all = 1; - - /* -@@ -247,7 +247,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, - /* LV tag match? skip test, when process_all */ - else if (!process_all && - (!tags_supplied || -- !str_list_match_list(tags, &lvl->lv->tags, NULL))) -+ !str_list_match_list(tagsl, &lvl->lv->tags, NULL))) - continue; - - if (sigint_caught()) -@@ -296,7 +296,7 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv, - struct cmd_vg *cvl_vg; - struct dm_list cmd_vgs; - struct dm_list failed_lvnames; -- struct dm_list tags, lvnames; -+ struct dm_list tagsl, lvnames; - struct dm_list arg_lvnames; /* Cmdline vgname or vgname/lvname */ - struct dm_list arg_vgnames; - char *vglv; -@@ -304,7 +304,7 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv, - - const char *vgname; - -- dm_list_init(&tags); -+ dm_list_init(&tagsl); - dm_list_init(&arg_lvnames); - dm_list_init(&failed_lvnames); - -@@ -327,7 +327,7 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv, - vgname); - continue; - } -- if (!str_list_add(cmd->mem, &tags, -+ if (!str_list_add(cmd->mem, &tagsl, - dm_pool_strdup(cmd->mem, - vgname + 1))) { - log_error("strlist allocation failed"); -@@ -395,7 +395,7 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv, - vgnames = &arg_vgnames; - } - -- if (!argc || !dm_list_empty(&tags)) { -+ if (!argc || !dm_list_empty(&tagsl)) { - log_verbose("Finding all logical volumes"); - if (!lvmetad_vg_list_to_lvmcache(cmd)) - stack; -@@ -420,7 +420,7 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv, - continue; - } - -- tags_arg = &tags; -+ tags_arg = &tagsl; - dm_list_init(&lvnames); /* LVs to be processed in this VG */ - dm_list_iterate_items(sll, &arg_lvnames) { - const char *vg_name = sll->str; -@@ -562,7 +562,7 @@ int process_each_segment_in_lv(struct cmd_context *cmd, - - static int _process_one_vg(struct cmd_context *cmd, const char *vg_name, - const char *vgid, -- struct dm_list *tags, struct dm_list *arg_vgnames, -+ struct dm_list *tagsl, struct dm_list *arg_vgnames, - uint32_t flags, void *handle, int ret_max, - process_single_vg_fn_t process_single_vg) - { -@@ -591,10 +591,10 @@ static int _process_one_vg(struct cmd_context *cmd, const char *vg_name, - } - } - -- if (!dm_list_empty(tags) && -+ if (!dm_list_empty(tagsl) && - /* Only process if a tag matches or it's on arg_vgnames */ - !str_list_match_item(arg_vgnames, vg_name) && -- !str_list_match_list(tags, &cvl_vg->vg->tags, NULL)) -+ !str_list_match_list(tagsl, &cvl_vg->vg->tags, NULL)) - break; - - ret = process_single_vg(cmd, vg_name, cvl_vg->vg, handle); -@@ -622,11 +622,11 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv, - - struct str_list *sl; - struct dm_list *vgnames, *vgids; -- struct dm_list arg_vgnames, tags; -+ struct dm_list arg_vgnames, tagsl; - - const char *vg_name, *vgid; - -- dm_list_init(&tags); -+ dm_list_init(&tagsl); - dm_list_init(&arg_vgnames); - - if (argc) { -@@ -642,7 +642,7 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv, - ret_max = EINVALID_CMD_LINE; - continue; - } -- if (!str_list_add(cmd->mem, &tags, -+ if (!str_list_add(cmd->mem, &tagsl, - dm_pool_strdup(cmd->mem, - vg_name + 1))) { - log_error("strlist allocation failed"); -@@ -669,7 +669,7 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv, - vgnames = &arg_vgnames; - } - -- if (!argc || !dm_list_empty(&tags)) { -+ if (!argc || !dm_list_empty(&tagsl)) { - log_verbose("Finding all volume groups"); - if (!lvmetad_vg_list_to_lvmcache(cmd)) - stack; -@@ -681,9 +681,9 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv, - if (sigint_caught()) - return_ECMD_FAILED; - vgid = sl->str; -- if (!(vgid) || !(vg_name = lvmcache_vgname_from_vgid(cmd->mem, vgid))) -+ if (!vgid || !(vg_name = lvmcache_vgname_from_vgid(cmd->mem, vgid))) - continue; -- ret_max = _process_one_vg(cmd, vg_name, vgid, &tags, -+ ret_max = _process_one_vg(cmd, vg_name, vgid, &tagsl, - &arg_vgnames, - flags, handle, - ret_max, process_single_vg); -@@ -695,7 +695,7 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv, - vg_name = sl->str; - if (is_orphan_vg(vg_name)) - continue; /* FIXME Unnecessary? */ -- ret_max = _process_one_vg(cmd, vg_name, NULL, &tags, -+ ret_max = _process_one_vg(cmd, vg_name, NULL, &tagsl, - &arg_vgnames, - flags, handle, - ret_max, process_single_vg); -@@ -706,7 +706,7 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv, - } - - int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, -- const struct dm_list *tags, void *handle, -+ const struct dm_list *tagsl, void *handle, - process_single_pv_fn_t process_single_pv) - { - int ret_max = ECMD_PROCESSED; -@@ -716,8 +716,8 @@ int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, - dm_list_iterate_items(pvl, &vg->pvs) { - if (sigint_caught()) - return_ECMD_FAILED; -- if (tags && !dm_list_empty(tags) && -- !str_list_match_list(tags, &pvl->pv->tags, NULL)) { -+ if (tagsl && !dm_list_empty(tagsl) && -+ !str_list_match_list(tagsl, &pvl->pv->tags, NULL)) { - continue; - } - if ((ret = process_single_pv(cmd, vg, pvl->pv, handle)) > ret_max) -@@ -801,12 +801,12 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv, - struct pv_list *pvl; - struct physical_volume *pv; - struct dm_list *pvslist = NULL, *vgnames; -- struct dm_list tags; -+ struct dm_list tagsl; - struct str_list *sll; - char *at_sign, *tagname; - struct device *dev; - -- dm_list_init(&tags); -+ dm_list_init(&tagsl); - - if (lock_global && !lock_vol(cmd, VG_GLOBAL, LCK_VG_READ, NULL)) { - log_error("Unable to obtain global lock."); -@@ -831,7 +831,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv, - ret_max = EINVALID_CMD_LINE; - continue; - } -- if (!str_list_add(cmd->mem, &tags, -+ if (!str_list_add(cmd->mem, &tagsl, - dm_pool_strdup(cmd->mem, - tagname))) { - log_error("strlist allocation failed"); -@@ -881,7 +881,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv, - if (ret > ret_max) - ret_max = ret; - } -- if (!dm_list_empty(&tags) && (vgnames = get_vgnames(cmd, 1)) && -+ if (!dm_list_empty(&tagsl) && (vgnames = get_vgnames(cmd, 1)) && - !dm_list_empty(vgnames)) { - dm_list_iterate_items(sll, vgnames) { - if (sigint_caught()) { -@@ -895,7 +895,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv, - continue; - } - -- ret = process_each_pv_in_vg(cmd, vg, &tags, -+ ret = process_each_pv_in_vg(cmd, vg, &tagsl, - handle, - process_single_pv); - if (ret > ret_max) -@@ -1215,7 +1215,7 @@ struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int - { - struct dm_list *r; - struct pv_list *pvl; -- struct dm_list tags, arg_pvnames; -+ struct dm_list tagsl, arg_pvnames; - char *pvname = NULL; - char *colon, *at_sign, *tagname; - int i; -@@ -1227,7 +1227,7 @@ struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int - } - dm_list_init(r); - -- dm_list_init(&tags); -+ dm_list_init(&tagsl); - dm_list_init(&arg_pvnames); - - for (i = 0; i < argc; i++) { -@@ -1404,7 +1404,7 @@ int lv_change_activate(struct cmd_context *cmd, struct logical_volume *lv, - * deactivation of origin, which is the only visible LV - */ - if (!deactivate_lv(cmd, find_snapshot(lv)->lv)) { -- if ((activate != CHANGE_AN) && (activate != CHANGE_ALN)) { -+ if (is_change_activating(activate)) { - log_error("Refusing to activate merging \"%s\" while snapshot \"%s\" is still active.", - lv->name, find_snapshot(lv)->lv->name); - return 0; -@@ -1420,8 +1420,7 @@ int lv_change_activate(struct cmd_context *cmd, struct logical_volume *lv, - return_0; - - if (background_polling() && -- (activate != CHANGE_AN) && -- (activate != CHANGE_ALN) && -+ is_change_activating(activate) && - (lv->status & (PVMOVE|CONVERTING|MERGING))) - lv_spawn_background_polling(cmd, lv); - -@@ -1661,14 +1660,28 @@ int get_pool_params(struct cmd_context *cmd, - uint64_t *pool_metadata_size, - int *zero) - { -+ int cache_pool = 0; -+ -+ if (!strcmp("cache-pool", arg_str_value(cmd, type_ARG, "none"))) -+ cache_pool = 1; -+ -+ if (!cache_pool && !arg_count(cmd, thinpool_ARG)) { -+ /* Check for arguments that should only go with pools */ -+ if (arg_count(cmd, poolmetadata_ARG)) { -+ log_error("'--poolmetadata' argument is only valid when" -+ " converting to pool LVs."); -+ return_0; -+ } -+ } -+ - *passed_args = 0; -- if (arg_count(cmd, zero_ARG)) { -+ if (!cache_pool && arg_count(cmd, zero_ARG)) { - *passed_args |= PASS_ARG_ZERO; - *zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n"); - log_very_verbose("Setting pool zeroing: %u", *zero); - } - -- if (arg_count(cmd, discards_ARG)) { -+ if (!cache_pool && arg_count(cmd, discards_ARG)) { - *passed_args |= PASS_ARG_DISCARDS; - *discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, 0); - log_very_verbose("Setting pool discards: %s", -@@ -1681,15 +1694,20 @@ int get_pool_params(struct cmd_context *cmd, - return 0; - } - *passed_args |= PASS_ARG_CHUNK_SIZE; -- *chunk_size = arg_uint_value(cmd, chunksize_ARG, -+ *chunk_size = arg_uint_value(cmd, chunksize_ARG, cache_pool ? -+ DM_CACHE_MIN_DATA_BLOCK_SIZE : - DM_THIN_MIN_DATA_BLOCK_SIZE); - log_very_verbose("Setting pool chunk size: %s", - display_size(cmd, *chunk_size)); - } - -- if (!update_profilable_pool_params(cmd, profile, *passed_args, -- chunk_size_calc_method, chunk_size, -- discards, zero)) -+ if (cache_pool) { -+ //FIXME: add cache_pool support to update_profilable_pool_params -+ if (!(*passed_args & PASS_ARG_CHUNK_SIZE)) -+ *chunk_size = DEFAULT_CACHE_POOL_CHUNK_SIZE * 2; -+ } else if (!update_profilable_pool_params(cmd, profile, *passed_args, -+ chunk_size_calc_method, -+ chunk_size, discards, zero)) - return_0; - - if (arg_count(cmd, poolmetadatasize_ARG)) { -@@ -1699,7 +1717,8 @@ int get_pool_params(struct cmd_context *cmd, - } - *passed_args |= PASS_ARG_POOL_METADATA_SIZE; - } -- *pool_metadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, UINT64_C(0)); -+ *pool_metadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, -+ UINT64_C(0)); - - return 1; - } -diff --git a/tools/toollib.h b/tools/toollib.h -index d809123..54636ab 100644 ---- a/tools/toollib.h -+++ b/tools/toollib.h -@@ -80,14 +80,14 @@ int process_each_segment_in_lv(struct cmd_context *cmd, - process_single_seg_fn_t process_single_seg); - - int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, -- const struct dm_list *tags, void *handle, -+ const struct dm_list *tagsl, void *handle, - process_single_pv_fn_t process_single_pv); - - - int process_each_lv_in_vg(struct cmd_context *cmd, - struct volume_group *vg, - const struct dm_list *arg_lvnames, -- const struct dm_list *tags, -+ const struct dm_list *tagsl, - struct dm_list *failed_lvnames, - void *handle, - process_single_lv_fn_t process_single_lv); -diff --git a/tools/vgchange.c b/tools/vgchange.c -index af4b002..e7b5e59 100644 ---- a/tools/vgchange.c -+++ b/tools/vgchange.c -@@ -117,15 +117,11 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg, - - /* Can't deactivate a pvmove LV */ - /* FIXME There needs to be a controlled way of doing this */ -- if (((activate == CHANGE_AN) || (activate == CHANGE_ALN)) && -- ((lv->status & PVMOVE) )) -+ if ((lv->status & PVMOVE) && !is_change_activating(activate)) - continue; - -- if (lv_activation_skip(lv, activate, arg_count(cmd, ignoreactivationskip_ARG), 0)) { -- log_verbose("ACTIVATION_SKIP flag set for LV %s/%s, skipping activation.", -- lv->vg->name, lv->name); -+ if (lv_activation_skip(lv, activate, arg_count(cmd, ignoreactivationskip_ARG))) - continue; -- } - - if ((activate == CHANGE_AAY) && - !lv_passes_auto_activation_filter(cmd, lv)) -@@ -155,8 +151,8 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg, - - if (expected_count) - log_verbose("%s %d logical volumes in volume group %s", -- (activate == CHANGE_AN || activate == CHANGE_ALN)? -- "Deactivated" : "Activated", count, vg->name); -+ is_change_activating(activate) ? -+ "Activated" : "Deactivated", count, vg->name); - - return (expected_count != count) ? 0 : 1; - } -@@ -196,12 +192,10 @@ static int _vgchange_background_polling(struct cmd_context *cmd, struct volume_g - int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg, - activation_change_t activate) - { -- int lv_open, active, monitored = 0, r = 1, do_activate = 1; -+ int lv_open, active, monitored = 0, r = 1; - const struct lv_list *lvl; - struct lvinfo info; -- -- if ((activate == CHANGE_AN) || (activate == CHANGE_ALN)) -- do_activate = 0; -+ int do_activate = is_change_activating(activate); - - /* - * Safe, since we never write out new metadata here. Required for -@@ -592,8 +586,7 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv) - - if (arg_count(cmd, activate_ARG) && - (arg_count(cmd, monitor_ARG) || arg_count(cmd, poll_ARG))) { -- int activate = arg_uint_value(cmd, activate_ARG, 0); -- if (activate == CHANGE_AN || activate == CHANGE_ALN) { -+ if (!is_change_activating(arg_uint_value(cmd, activate_ARG, 0))) { - log_error("Only -ay* allowed with --monitor or --poll."); - return EINVALID_CMD_LINE; - } -@@ -604,8 +597,8 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv) - return EINVALID_CMD_LINE; - } - -- if (arg_count(cmd, activate_ARG) == 1 -- && arg_count(cmd, autobackup_ARG)) { -+ if ((arg_count(cmd, activate_ARG) == 1) && -+ arg_count(cmd, autobackup_ARG)) { - log_error("-A option not necessary with -a option"); - return EINVALID_CMD_LINE; - } -diff --git a/tools/vgsplit.c b/tools/vgsplit.c -index dfcb120..150be1d 100644 ---- a/tools/vgsplit.c -+++ b/tools/vgsplit.c -@@ -14,6 +14,7 @@ - */ - - #include "tools.h" -+#include "metadata.h" /* for 'get_only_segment_using_this_lv' */ - - /* FIXME Why not (lv->vg == vg) ? */ - static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv) -@@ -72,6 +73,10 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) - lv_is_thin_volume(lv)) - continue; - -+ if (lv_is_cache(lv) || lv_is_cache_pool(lv)) -+ /* further checks by _move_cache() */ -+ continue; -+ - /* Ensure all the PVs used by this LV remain in the same */ - /* VG as each other */ - vg_with = NULL; -@@ -268,6 +273,77 @@ static int _move_thins(struct volume_group *vg_from, - return 1; - } - -+static int _move_cache(struct volume_group *vg_from, -+ struct volume_group *vg_to) -+{ -+ int is_moving; -+ struct dm_list *lvh, *lvht; -+ struct logical_volume *lv, *data, *meta, *orig; -+ struct lv_segment *seg, *cache_seg; -+ -+ dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) { -+ lv = dm_list_item(lvh, struct lv_list)->lv; -+ data = meta = orig = NULL; -+ seg = first_seg(lv); -+ -+ if (!lv_is_cache(lv) && !lv_is_cache_pool(lv)) -+ continue; -+ -+ /* -+ * FIXME: The code seems to move cache LVs fine, but it -+ * hasn't been well tested and it causes problems -+ * when just splitting PVs that don't contain -+ * cache LVs. -+ * Waiting for next release before fixing and enabling. -+ */ -+ log_error("Unable to split VG while it contains cache LVs"); -+ return 0; -+ -+ if (lv_is_cache(lv)) { -+ orig = seg_lv(seg, 0); -+ data = seg_lv(first_seg(seg->pool_lv), 0); -+ meta = first_seg(seg->pool_lv)->metadata_lv; -+ /* Ensure all components are coming along */ -+ is_moving = !!_lv_is_in_vg(vg_to, orig); -+ } else { -+ if (!dm_list_empty(&seg->lv->segs_using_this_lv) && -+ !(cache_seg = get_only_segment_using_this_lv(seg->lv))) -+ return_0; -+ orig = seg_lv(cache_seg, 0); -+ data = seg_lv(seg, 0); -+ meta = seg->metadata_lv; -+ -+ if (_lv_is_in_vg(vg_to, data) || -+ _lv_is_in_vg(vg_to, meta)) -+ is_moving = 1; -+ } -+ -+ if (orig && (!!_lv_is_in_vg(vg_to, orig) != is_moving)) { -+ log_error("Can't split %s and its origin (%s)" -+ " into separate VGs", lv->name, orig->name); -+ return 0; -+ } -+ -+ if (data && (!!_lv_is_in_vg(vg_to, data) != is_moving)) { -+ log_error("Can't split %s and its cache pool" -+ " data LV (%s) into separate VGs", -+ lv->name, data->name); -+ return 0; -+ } -+ -+ if (meta && (!!_lv_is_in_vg(vg_to, meta) != is_moving)) { -+ log_error("Can't split %s and its cache pool" -+ " metadata LV (%s) into separate VGs", -+ lv->name, meta->name); -+ return 0; -+ } -+ if (!_move_one_lv(vg_from, vg_to, lvh)) -+ return_0; -+ } -+ -+ return 1; -+} -+ - /* - * Create or open the destination of the vgsplit operation. - * Returns -@@ -481,6 +557,9 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) - if (!(_move_thins(vg_from, vg_to))) - goto_bad; - -+ if (!(_move_cache(vg_from, vg_to))) -+ goto_bad; -+ - /* Split metadata areas and check if both vgs have at least one area */ - if (!(vg_split_mdas(cmd, vg_from, vg_to)) && vg_from->pv_count) { - log_error("Cannot split: Nowhere to store metadata for new Volume Group"); -diff --git a/udev/10-dm.rules.in b/udev/10-dm.rules.in -index f7088f1..8d7a8ca 100644 ---- a/udev/10-dm.rules.in -+++ b/udev/10-dm.rules.in -@@ -120,12 +120,6 @@ ENV{DM_UDEV_RULES_VSN}="2" - - ENV{DM_UDEV_DISABLE_DM_RULES_FLAG}!="1", ENV{DM_NAME}=="?*", SYMLINK+="(DM_DIR)/$env{DM_NAME}" - --# We have to ignore further rule application for inappropriate events --# and devices. But still send the notification if cookie exists. --ENV{DM_UUID}=="mpath-?*", ENV{DM_ACTION}=="PATH_FAILED", GOTO="dm_disable" --ENV{DM_UUID}=="CRYPT-TEMP-?*", GOTO="dm_disable" --ENV{DM_UUID}!="?*", ENV{DM_NAME}=="temporary-cryptsetup-?*", GOTO="dm_disable" -- - # Avoid processing and scanning a DM device in the other (foreign) - # rules if it is in suspended state. However, we still keep 'disk' - # and 'DM subsystem' related rules enabled in this case. -diff --git a/udev/69-dm-lvm-metad.rules.in b/udev/69-dm-lvm-metad.rules.in -index e8304b5..bd75fc8 100644 ---- a/udev/69-dm-lvm-metad.rules.in -+++ b/udev/69-dm-lvm-metad.rules.in -@@ -34,6 +34,9 @@ ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="lvm_end" - # Inform lvmetad about any PV that is gone. - ACTION=="remove", GOTO="lvm_scan" - -+# Create /dev/disk/by-id/lvm-pv-uuid- symlink for each PV -+ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-id/lvm-pv-uuid-$env{ID_FS_UUID_ENC}" -+ - # If the PV is a special device listed below, scan only if the device is - # properly activated. These devices are not usable after an ADD event, - # but they require an extra setup and they are ready after a CHANGE event. diff --git a/SOURCES/lvm2-2_02_106-various-man-page-cleanups.patch b/SOURCES/lvm2-2_02_106-various-man-page-cleanups.patch deleted file mode 100644 index 7ef5269..0000000 --- a/SOURCES/lvm2-2_02_106-various-man-page-cleanups.patch +++ /dev/null @@ -1,188 +0,0 @@ - man/lvchange.8.in | 6 +++--- - man/lvconvert.8.in | 36 +++++++++++++++++++++++------------- - man/lvcreate.8.in | 8 ++++---- - man/lvmetad.8.in | 11 ++++------- - 4 files changed, 34 insertions(+), 27 deletions(-) - -diff --git a/man/lvchange.8.in b/man/lvchange.8.in -index 64231c8..5de75e0 100644 ---- a/man/lvchange.8.in -+++ b/man/lvchange.8.in -@@ -41,7 +41,7 @@ lvchange \- change attributes of a logical volume - .RB [ \-\-[raid]writebehind - .IR IOCount ] - .RB [ \-\-[raid]writemostly --.IR PhysicalVolume[:{t|n|y}] ] -+.IR PhysicalVolume [ : { t | n | y }]] - .RB [ \-\-sysinit ] - .RB [ \-\-noudevsync ] - .RB [ \-M | \-\-persistent -@@ -166,7 +166,7 @@ If \fIrepair\fP is used, the discrepancies will be corrected as they are - encountered. The 'lvs' command can be used to show the number of - discrepancies found or repaired. - .TP --.BR \-\-[raid]writebehind " IOCount" -+.BR \-\-[raid]writebehind " " \fIIOCount - Specify the maximum number of outstanding writes that are allowed to - devices in a RAID1 logical volume that are marked as \fIwrite-mostly\fP. - Once this value is exceeded, writes become synchronous (i.e. all writes -@@ -174,7 +174,7 @@ to the constituent devices must complete before the array signals the - write has completed). Setting the value to zero clears the preference - and allows the system to choose the value arbitrarily. - .TP --.BR \-\-[raid]writemostly " PhysicalVolume[:{t|y|n}]" -+.IR \fB\-\-[raid]writemostly " " PhysicalVolume [ : { t | y | n }] - Mark a device in a RAID1 logical volume as \fIwrite-mostly\fP. All reads - to these drives will be avoided unless absolutely necessary. This keeps - the number of I/Os to the drive to a minimum. The default behavior is to -diff --git a/man/lvconvert.8.in b/man/lvconvert.8.in -index 190e221..fe6525b 100644 ---- a/man/lvconvert.8.in -+++ b/man/lvconvert.8.in -@@ -91,11 +91,11 @@ lvconvert \- convert a logical volume from linear to mirror or snapshot - .IR ChunkSize [ bBsSkKmMgG ]] - .RB [ \-\-discards - .RI { ignore | nopassdown | passdown }] --.RB [[ \-\-poolmetadata --.IR ThinPoolMetadataLogicalVolume { Name | Path }] -+.RB [{ \-\-poolmetadata -+.IR ThinPoolMetadataLogicalVolume { Name | Path } - | --.RB [ \-\-poolmetadatasize --.IR ThinPoolMetadataSize [ bBsSkKmMgG ]] -+.B \-\-poolmetadatasize -+.IR ThinPoolMetadataSize [ bBsSkKmMgG ]}] - .RB [ \-r | \-\-readahead - .RI { ReadAheadSectors | auto | none }] - .RB [ \-\-stripes -@@ -113,24 +113,24 @@ lvconvert \- convert a logical volume from linear to mirror or snapshot - .RB [ \-v | \-\-verbose ] - .RB [ \-\-version ] - .sp --.B lvconvert \-\-type cache-pool -+.B lvconvert \-\-type \fIcache-pool - .RB [ \-c | \-\-chunksize - .IR ChunkSize [ bBsSkKmMgG ]] - .RB [ \-\-cachemode - .RI { writeback | writethrough }] --.RB [[ \-\-poolmetadata --.IR CachePoolMetadataLogicalVolume { Name | Path }] -+.RB [{ \-\-poolmetadata -+.IR CachePoolMetadataLogicalVolume { Name | Path } - | --.RB [ \-\-poolmetadatasize --.IR CachePoolMetadataSize [ bBsSkKmMgG ]] -+.B \-\-poolmetadatasize -+.IR CachePoolMetadataSize [ bBsSkKmMgG ]}] - .IR LogicalVolume [ Path ] - .RI [ PhysicalVolume [ Path ][ :PE [ -PE ]]...] - .RB [ \-h | \-? | \-\-help ] - .RB [ \-v | \-\-verbose ] - .RB [ \-\-version ] - .sp --.B lvconvert \-\-type cache --.RB \-\-cachepool -+.B lvconvert \-\-type \fIcache -+.B \-\-cachepool - .IR CachePoolLV { Name | Path } - .IR LogicalVolume [ Path ] - .RB [ \-h | \-? | \-\-help ] -@@ -333,14 +333,23 @@ a suitable value automatically. - "None" is equivalent to specifying zero. - .TP - .B \-\-repair --Repair a mirror after suffering a disk failure. The mirror will be brought back --into a consistent state. By default, the original number of mirrors will be -+Repair a mirror after suffering a disk failure or try to fix thin pool metadata. -+ -+The mirror will be brought back into a consistent state. -+By default, the original number of mirrors will be - restored if possible. Specify \fB\-y\fP on the command line to skip - the prompts. Use \fB\-f\fP if you do not want any replacement. - Additionally, you may use \fB\-\-use\-policies\fP to use the device - replacement policy specified in \fBlvm.conf\fP(5), - viz. activation/mirror_log_fault_policy or - activation/mirror_device_fault_policy. -+ -+Thin pool repair automates the use of \fBthin_repair\fP(8) tool. -+Only inactive thin pool volumes can be repaired. -+There is no validation of metadata between kernel and lvm2. -+This requires further manual work. -+After successfull repair the old unmodified metadata are still -+available in \fB_tmeta\fP LV. - .TP - .B \-\-replace \fIPhysicalVolume - Remove the specified device (\fIPhysicalVolume\fP) and replace it with one -@@ -498,4 +507,5 @@ cache pool LV. - .BR lvscan (8), - .BR vgcreate (8), - .BR thin_dump (8), -+.BR thin_repair (8) - .BR thin_restore (8) -diff --git a/man/lvcreate.8.in b/man/lvcreate.8.in -index 325baad..445af80 100644 ---- a/man/lvcreate.8.in -+++ b/man/lvcreate.8.in -@@ -60,7 +60,7 @@ lvcreate \- create a logical volume in an existing volume group - .RB [ \-t | \-\-test ] - .RB [ \-T | \-\-thin - .RB [ \-\-cachemode --.IR { writeback | writethrough } -+.RI { writeback | writethrough } - .RB [ \-c | \-\-chunksize - .IR ChunkSize [ bBsSkKmMgG ]] - .RB [ \-\-discards -@@ -145,7 +145,7 @@ be overridden. If the clustered locking is enabled, - .IR \fB\-a { a | l } y - will activate only on the local node. - .TP --.IR \fB\-k ", " \fB\-\-setactivationskip " " { y | n } -+.IR \fB\-k ", " \fB\-\-setactivationskip " {" y | n } - Controls whether Logical Volumes are persistently flagged to be skipped during - activation. By default, thin snapshot volumes are flagged for activation skip. - To activate such volumes, an extra \fB\-K/\-\-ignoreactivationskip\fP option must -@@ -155,11 +155,11 @@ detach the flag for existing volumes. To see whether the flag is attached, - use \fBlvs\fP command where the state of the flag is reported within - \fBlv_attr\fP bits. - .TP --.IR \fB\-K ", " \fB\-\-ignoreactivationskip -+.BR \-K ", " \-\-ignoreactivationskip - Ignore the flag to skip Logical Volumes during activation. - - .TP --.BR \-\-cachemode " " { writeback | writethrough } -+.IR \fB\-\-cachemode " " { writeback | writethrough } - Specifying a cache mode determines when the writes to a cache LV - are considered complete. When \fIwriteback\fP is specified, a write is - considered complete as soon as it is stored in the cache pool LV. -diff --git a/man/lvmetad.8.in b/man/lvmetad.8.in -index 4956a3f..444c7c0 100644 ---- a/man/lvmetad.8.in -+++ b/man/lvmetad.8.in -@@ -4,14 +4,11 @@ lvmetad \- LVM metadata cache daemon - .SH SYNOPSIS - .B lvmetad - .RB [ \-l --.RI {all|wire|debug} --.RB ] -+.RI { all | wire | debug }] - .RB [ \-p --.RI pidfile_path --.RB ] -+.IR pidfile_path ] - .RB [ \-s --.RI socket_path --.RB ] -+.IR socket_path ] - .RB [ \-f ] - .RB [ \-h ] - .RB [ \-V ] -@@ -34,7 +31,7 @@ Don't fork, but run in the foreground. - .BR \-h ", " \-? - Show help information. - .TP --.BR \-l " {" \fIall | \fIwire | \fIdebug } -+.IR \fB\-l " {" all | wire | debug } - Select the type of log messages to generate. - Messages are logged by syslog. - Additionally, when -f is given they are also sent to standard error. diff --git a/SOURCES/lvm2-2_02_106-various-thin-fixes.patch b/SOURCES/lvm2-2_02_106-various-thin-fixes.patch deleted file mode 100644 index c4e7ef5..0000000 --- a/SOURCES/lvm2-2_02_106-various-thin-fixes.patch +++ /dev/null @@ -1,633 +0,0 @@ -commit 85fc38d398d1bc8acb4027da7acc376af2be0cc1 -Author: Peter Rajnoha -Date: Wed Mar 12 14:37:59 2014 +0100 - - thin fixes ---- - WHATS_NEW | 3 ++ - lib/activate/activate.c | 2 +- - lib/activate/dev_manager.c | 72 +++++++++++++++++++++++++-------------------- - lib/cache_segtype/cache.c | 6 ++-- - lib/metadata/lv_manip.c | 63 +++------------------------------------ - lib/metadata/pool_manip.c | 3 ++ - lib/metadata/thin_manip.c | 2 +- - lib/mirror/mirrored.c | 4 +-- - lib/misc/lvm-string.c | 8 ++++- - lib/misc/lvm-string.h | 3 +- - lib/thin/thin.c | 8 ++--- - test/shell/lvcreate-thin.sh | 4 ++- - test/shell/pvremove-thin.sh | 28 ++++++++++++++++++ - 13 files changed, 101 insertions(+), 105 deletions(-) - -diff --git a/WHATS_NEW b/WHATS_NEW -index 3ee9585..a3d48f3 100644 ---- a/WHATS_NEW -+++ b/WHATS_NEW -@@ -1,5 +1,8 @@ - Version 2.02.106 - - ==================================== -+ Update API for internal function build_dm_uuid(). -+ Do not try to check empty pool with scheduled messages. -+ Fix return value in pool_has_message() when quering for any message. - Fix cache consistency in lvmetad when PV moves around. - Fix memleak when lvmetad discovers PV to appear on another device. - Fix invalid memory read in lvmetad that could cause a deadlock. -diff --git a/lib/activate/activate.c b/lib/activate/activate.c -index 26dc0e1..565634f 100644 ---- a/lib/activate/activate.c -+++ b/lib/activate/activate.c -@@ -1546,7 +1546,7 @@ static char *_build_target_uuid(struct cmd_context *cmd, struct logical_volume * - else - layer = NULL; - -- return build_dm_uuid(cmd->mem, lv->lvid.s, layer); -+ return build_dm_uuid(cmd->mem, lv, layer); - } - - int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso, -diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c -index 6b5f8c2..c723a61 100644 ---- a/lib/activate/dev_manager.c -+++ b/lib/activate/dev_manager.c -@@ -446,6 +446,12 @@ static int _device_is_usable(struct device *dev, int check_lv_names) - !dm_split_lvm_name(NULL, NULL, &vgname, &lvname, &layer)) - goto_out; - -+ if (strlen(uuid) > 68) { -+ log_debug_activation("%s: Reserved uuid %s on internal LV device %s/%s%s%s not usable.", -+ dev_name(dev), uuid, vgname, lvname, *layer ? "-" : "", layer); -+ goto out; -+ } -+ - if (lvname && (is_reserved_lvname(lvname) || *layer)) { - log_debug_activation("%s: Reserved internal LV device %s/%s%s%s not usable.", - dev_name(dev), vgname, lvname, *layer ? "-" : "", layer); -@@ -505,7 +511,7 @@ int dev_manager_info(struct dm_pool *mem, const struct logical_volume *lv, - return 0; - } - -- if (!(dlid = build_dm_uuid(mem, lv->lvid.s, layer))) { -+ if (!(dlid = build_dm_uuid(mem, lv, layer))) { - log_error("dlid build failed for %s", name); - r = 0; - goto out; -@@ -528,7 +534,7 @@ static const struct dm_info *_cached_info(struct dm_pool *mem, - const struct dm_tree_node *dnode; - const struct dm_info *dinfo = NULL; - -- if (!(dlid = build_dm_uuid(mem, lv->lvid.s, layer))) { -+ if (!(dlid = build_dm_uuid(mem, lv, layer))) { - log_error("Failed to build dlid for %s.", lv->name); - return NULL; - } -@@ -641,7 +647,7 @@ int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv, - char *type = NULL; - char *params = NULL; - -- if (!(dlid = build_dm_uuid(mem, lv->lvid.s, layer))) -+ if (!(dlid = build_dm_uuid(mem, lv, layer))) - return_0; - - if (!(dmt = _setup_task(NULL, dlid, 0, -@@ -872,7 +878,7 @@ int dev_manager_transient(struct dev_manager *dm, struct logical_volume *lv) - const struct dm_list *segh = &lv->segments; - struct lv_segment *seg = NULL; - -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) -+ if (!(dlid = build_dm_uuid(dm->mem, lv, layer))) - return_0; - - if (!(dmt = _setup_task(0, dlid, NULL, DM_DEVICE_STATUS, 0, 0))) -@@ -1015,7 +1021,7 @@ int dev_manager_snapshot_percent(struct dev_manager *dm, - if (!(name = dm_build_dm_name(dm->mem, snap_lv->vg->name, snap_lv->name, NULL))) - return_0; - -- if (!(dlid = build_dm_uuid(dm->mem, snap_lv->lvid.s, NULL))) -+ if (!(dlid = build_dm_uuid(dm->mem, snap_lv, NULL))) - return_0; - - /* -@@ -1047,7 +1053,7 @@ int dev_manager_mirror_percent(struct dev_manager *dm, - if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) - return_0; - -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) { -+ if (!(dlid = build_dm_uuid(dm->mem, lv, layer))) { - log_error("dlid build failed for %s", lv->name); - return 0; - } -@@ -1074,7 +1080,7 @@ int dev_manager_raid_status(struct dev_manager *dm, - char *params = NULL; - const char *layer = lv_layer(lv); - -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) -+ if (!(dlid = build_dm_uuid(dm->mem, lv, layer))) - return_0; - - log_debug_activation("Getting raid device status for %s.", lv->name); -@@ -1138,7 +1144,7 @@ int dev_manager_raid_message(struct dev_manager *dm, - return 0; - } - -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) -+ if (!(dlid = build_dm_uuid(dm->mem, lv, layer))) - return_0; - - if (!(dmt = _setup_task(NULL, dlid, 0, DM_DEVICE_TARGET_MSG, 0, 0))) -@@ -1173,7 +1179,7 @@ int dev_manager_cache_status(struct dev_manager *dm, - char *params = NULL; - const char *layer = lv_layer(lv); - -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) -+ if (!(dlid = build_dm_uuid(dm->mem, lv, layer))) - return_0; - - log_debug_activation("Getting cache device status for %s.", lv->name); -@@ -1282,7 +1288,7 @@ int dev_manager_thin_pool_status(struct dev_manager *dm, - int r = 0; - - /* Build dlid for the thin pool layer */ -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, lv_layer(lv)))) -+ if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv)))) - return_0; - - log_debug_activation("Getting thin pool device status for %s.", lv->name); -@@ -1328,7 +1334,7 @@ int dev_manager_thin_pool_percent(struct dev_manager *dm, - lv_layer(lv)))) - return_0; - -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, lv_layer(lv)))) -+ if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv)))) - return_0; - - log_debug_activation("Getting device status percentage for %s", name); -@@ -1351,7 +1357,7 @@ int dev_manager_thin_percent(struct dev_manager *dm, - if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) - return_0; - -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) -+ if (!(dlid = build_dm_uuid(dm->mem, lv, layer))) - return_0; - - log_debug_activation("Getting device status percentage for %s", name); -@@ -1374,7 +1380,7 @@ int dev_manager_thin_device_id(struct dev_manager *dm, - int r = 0; - - /* Build dlid for the thin layer */ -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, lv_layer(lv)))) -+ if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv)))) - return_0; - - log_debug_activation("Getting device id for %s.", dlid); -@@ -1575,7 +1581,7 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, - if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) - return_0; - -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) -+ if (!(dlid = build_dm_uuid(dm->mem, lv, layer))) - return_0; - - log_debug_activation("Getting device info for %s [%s]", name, dlid); -@@ -1648,7 +1654,7 @@ static int _add_partial_replicator_to_dtree(struct dev_manager *dm, - if (!_add_dev_to_dtree(dm, dtree, rlv, NULL)) - return_0; - -- if (!(uuid = build_dm_uuid(dm->mem, rlv->lvid.s, NULL))) -+ if (!(uuid = build_dm_uuid(dm->mem, rlv, NULL))) - return_0; - - rep_node = dm_tree_find_node_by_uuid(dtree, uuid); -@@ -1670,7 +1676,7 @@ static int _add_partial_replicator_to_dtree(struct dev_manager *dm, - /* If replicator exists - try connect existing heads */ - if (rep_node) { - uuid = build_dm_uuid(dm->mem, -- rdev->replicator_dev->lv->lvid.s, -+ rdev->replicator_dev->lv, - NULL); - if (!uuid) - return_0; -@@ -1790,7 +1796,9 @@ static int _thin_pool_register_callback(struct dev_manager *dm, - struct thin_cb_data *data; - - /* Skip metadata testing for unused pool. */ -- if (!first_seg(lv)->transaction_id) -+ if (!first_seg(lv)->transaction_id || -+ ((first_seg(lv)->transaction_id == 1) && -+ pool_has_message(first_seg(lv), NULL, 0))) - return 1; - - if (!(data = dm_pool_alloc(dm->mem, sizeof(*data)))) { -@@ -1836,7 +1844,7 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, - #if 0 - /* ? Use origin_only to avoid 'deep' thin pool suspend ? */ - /* FIXME Implement dm_tree_node_skip_childrens optimisation */ -- if (!(uuid = build_dm_uuid(dm->mem, lv->lvid.s, lv_layer(lv)))) -+ if (!(uuid = build_dm_uuid(dm->mem, lv, lv_layer(lv)))) - return_0; - if ((thin_node = dm_tree_find_node_by_uuid(dtree, uuid))) - dm_tree_node_skip_childrens(thin_node, 1); -@@ -1866,7 +1874,7 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, - /* Setup callback for non-activation partial tree */ - /* Activation gets own callback when needed */ - /* TODO: extend _cached_info() to return dnode */ -- if (!(uuid = build_dm_uuid(dm->mem, lv->lvid.s, lv_layer(lv)))) -+ if (!(uuid = build_dm_uuid(dm->mem, lv, lv_layer(lv)))) - return_0; - if ((thin_node = dm_tree_find_node_by_uuid(dtree, uuid)) && - !_thin_pool_register_callback(dm, thin_node, lv)) -@@ -1977,7 +1985,7 @@ static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree, - - sprintf(errid, "missing_%d_%d", segno, s); - -- if (!(dlid = build_dm_uuid(dm->mem, seg->lv->lvid.s, errid))) -+ if (!(dlid = build_dm_uuid(dm->mem, seg->lv, errid))) - return_NULL; - - if (!(name = dm_build_dm_name(dm->mem, seg->lv->vg->name, -@@ -2085,18 +2093,18 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg, - return_0; - continue; - } -- if (!(dlid = build_dm_uuid(dm->mem, seg_metalv(seg, s)->lvid.s, NULL))) -+ if (!(dlid = build_dm_uuid(dm->mem, seg_metalv(seg, s), NULL))) - return_0; - if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_metale(seg, s))) - return_0; - -- if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, s)->lvid.s, NULL))) -+ if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, s), NULL))) - return_0; - if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s))) - return_0; - } else if (seg_type(seg, s) == AREA_LV) { - -- if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, s)->lvid.s, NULL))) -+ if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, s), NULL))) - return_0; - if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s))) - return_0; -@@ -2125,7 +2133,7 @@ static int _add_layer_target_to_dtree(struct dev_manager *dm, - { - const char *layer_dlid; - -- if (!(layer_dlid = build_dm_uuid(dm->mem, lv->lvid.s, lv_layer(lv)))) -+ if (!(layer_dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv)))) - return_0; - - /* Add linear mapping over layered LV */ -@@ -2144,7 +2152,7 @@ static int _add_origin_target_to_dtree(struct dev_manager *dm, - { - const char *real_dlid; - -- if (!(real_dlid = build_dm_uuid(dm->mem, lv->lvid.s, "real"))) -+ if (!(real_dlid = build_dm_uuid(dm->mem, lv, "real"))) - return_0; - - if (!dm_tree_node_add_snapshot_origin_target(dnode, lv->size, real_dlid)) -@@ -2165,13 +2173,13 @@ static int _add_snapshot_merge_target_to_dtree(struct dev_manager *dm, - return 0; - } - -- if (!(origin_dlid = build_dm_uuid(dm->mem, lv->lvid.s, "real"))) -+ if (!(origin_dlid = build_dm_uuid(dm->mem, lv, "real"))) - return_0; - -- if (!(cow_dlid = build_dm_uuid(dm->mem, merging_snap_seg->cow->lvid.s, "cow"))) -+ if (!(cow_dlid = build_dm_uuid(dm->mem, merging_snap_seg->cow, "cow"))) - return_0; - -- if (!(merge_dlid = build_dm_uuid(dm->mem, merging_snap_seg->cow->lvid.s, NULL))) -+ if (!(merge_dlid = build_dm_uuid(dm->mem, merging_snap_seg->cow, NULL))) - return_0; - - if (!dm_tree_node_add_snapshot_merge_target(dnode, lv->size, origin_dlid, -@@ -2197,10 +2205,10 @@ static int _add_snapshot_target_to_dtree(struct dev_manager *dm, - return 0; - } - -- if (!(origin_dlid = build_dm_uuid(dm->mem, snap_seg->origin->lvid.s, "real"))) -+ if (!(origin_dlid = build_dm_uuid(dm->mem, snap_seg->origin, "real"))) - return_0; - -- if (!(cow_dlid = build_dm_uuid(dm->mem, snap_seg->cow->lvid.s, "cow"))) -+ if (!(cow_dlid = build_dm_uuid(dm->mem, snap_seg->cow, "cow"))) - return_0; - - size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size; -@@ -2514,7 +2522,7 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, - if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) - return_0; - -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) -+ if (!(dlid = build_dm_uuid(dm->mem, lv, layer))) - return_0; - - /* We've already processed this node if it already has a context ptr */ -@@ -2774,7 +2782,7 @@ static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, - /* Restore fs cookie */ - dm_tree_set_cookie(root, fs_get_cookie()); - -- if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, laopts->origin_only ? lv_layer(lv) : NULL))) -+ if (!(dlid = build_dm_uuid(dm->mem, lv, laopts->origin_only ? lv_layer(lv) : NULL))) - goto_out; - - /* Only process nodes with uuid of "LVM-" plus VG id. */ -diff --git a/lib/cache_segtype/cache.c b/lib/cache_segtype/cache.c -index 57c7a5c..df521c4 100644 ---- a/lib/cache_segtype/cache.c -+++ b/lib/cache_segtype/cache.c -@@ -360,13 +360,13 @@ static int _cache_add_target_line(struct dev_manager *dm, - struct lv_segment *cache_pool_seg = first_seg(seg->pool_lv); - char *metadata_uuid, *data_uuid, *origin_uuid; - -- if (!(metadata_uuid = build_dm_uuid(mem, cache_pool_seg->metadata_lv->lvid.s, NULL))) -+ if (!(metadata_uuid = build_dm_uuid(mem, cache_pool_seg->metadata_lv, NULL))) - return_0; - -- if (!(data_uuid = build_dm_uuid(mem, seg_lv(cache_pool_seg, 0)->lvid.s, NULL))) -+ if (!(data_uuid = build_dm_uuid(mem, seg_lv(cache_pool_seg, 0), NULL))) - return_0; - -- if (!(origin_uuid = build_dm_uuid(mem, seg_lv(seg, 0)->lvid.s, NULL))) -+ if (!(origin_uuid = build_dm_uuid(mem, seg_lv(seg, 0), NULL))) - return_0; - - if (!dm_tree_node_add_cache_target(node, len, -diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c -index 57ce2d9..abbcbf8 100644 ---- a/lib/metadata/lv_manip.c -+++ b/lib/metadata/lv_manip.c -@@ -6291,19 +6291,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - if (lv_activation_skip(lv, lp->activate, lp->activation_skip & ACTIVATION_SKIP_IGNORE)) - lp->activate = CHANGE_AN; - -- /* -- * For thin pools - deactivate when inactive pool is requested or -- * for cluster give-up local lock and take proper exlusive lock -- */ -- if (lv_is_thin_pool(lv) && -- (!is_change_activating(lp->activate) || -- vg_is_clustered(lv->vg)) && -- /* Deactivates cleared metadata LV */ -- !deactivate_lv(lv->vg->cmd, lv)) { -- stack; -- goto deactivate_failed; -- } -- - /* store vg on disk(s) */ - if (!vg_write(vg) || !vg_commit(vg)) - return_NULL; -@@ -6322,50 +6309,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - if (lp->temporary) - lv->status |= LV_TEMPORARY; - -- if (lv_is_cache_type(lv)) { -- if (!lv_is_active(lv)) { -- if (!activate_lv_excl(cmd, lv)) { -- log_error("Failed to activate pool %s.", -- lv->name); -- goto deactivate_and_revert_new_lv; -- } -- } else { -- if (!suspend_lv(cmd, lv)) { -- log_error("Failed to suspend pool %s.", -- lv->name); -- goto deactivate_and_revert_new_lv; -- } -- if (!resume_lv(cmd, lv)) { -- log_error("Failed to resume pool %s.", lv->name); -- goto deactivate_and_revert_new_lv; -- } -- } -- } else if (lv_is_thin_pool(lv)) { -- if (is_change_activating(lp->activate)) { -- if (vg_is_clustered(lv->vg)) { -- if (!activate_lv_excl(cmd, lv)) { -- log_error("Failed to activate pool %s.", lv->name); -- goto deactivate_and_revert_new_lv; -- } -- } else { -- /* -- * Suspend cleared plain metadata LV -- * but now already commited as pool LV -- * and resume it as a pool LV. -- * -- * This trick avoids collision with udev watch rule. -- */ -- if (!suspend_lv(cmd, lv)) { -- log_error("Failed to suspend pool %s.", lv->name); -- goto deactivate_and_revert_new_lv; -- } -- if (!resume_lv(cmd, lv)) { -- log_error("Failed to resume pool %s.", lv->name); -- goto deactivate_and_revert_new_lv; -- } -- } -- } -- } else if (lv_is_thin_volume(lv)) { -+ if (lv_is_thin_volume(lv)) { - /* For snapshot, suspend active thin origin first */ - if (org && lv_is_active(org) && lv_is_thin_volume(org)) { - if (!suspend_lv_origin(cmd, org)) { -@@ -6403,7 +6347,9 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, - } - } else if (!lv_active_change(cmd, lv, lp->activate)) { - log_error("Failed to activate new LV."); -- if (lp->zero || lp->wipe_signatures) -+ if (lp->zero || lp->wipe_signatures || -+ lv_is_thin_pool(lv) || -+ lv_is_cache_type(lv)) - goto deactivate_and_revert_new_lv; - return NULL; - } -@@ -6497,7 +6443,6 @@ out: - - deactivate_and_revert_new_lv: - if (!deactivate_lv(cmd, lv)) { --deactivate_failed: - log_error("Unable to deactivate failed new LV \"%s/%s\". " - "Manual intervention required.", lv->vg->name, lv->name); - return NULL; -diff --git a/lib/metadata/pool_manip.c b/lib/metadata/pool_manip.c -index 0c7bf96..f414f3f 100644 ---- a/lib/metadata/pool_manip.c -+++ b/lib/metadata/pool_manip.c -@@ -267,6 +267,9 @@ int create_pool(struct logical_volume *pool_lv, - goto bad; - } - pool_lv->status &= ~LV_TEMPORARY; -+ /* Deactivates cleared metadata LV */ -+ if (!deactivate_lv_local(pool_lv->vg->cmd, pool_lv)) -+ goto_bad; - } - - if (dm_snprintf(name, sizeof(name), "%s_%s", pool_lv->name, -diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c -index b28f5a0..b94a4a8 100644 ---- a/lib/metadata/thin_manip.c -+++ b/lib/metadata/thin_manip.c -@@ -160,7 +160,7 @@ int pool_has_message(const struct lv_segment *seg, - } - - if (!lv && !device_id) -- return dm_list_empty(&seg->thin_messages); -+ return !dm_list_empty(&seg->thin_messages); - - dm_list_iterate_items(tmsg, &seg->thin_messages) { - switch (tmsg->type) { -diff --git a/lib/mirror/mirrored.c b/lib/mirror/mirrored.c -index 5088173..e35a372 100644 ---- a/lib/mirror/mirrored.c -+++ b/lib/mirror/mirrored.c -@@ -356,14 +356,14 @@ static int _add_log(struct dm_pool *mem, struct lv_segment *seg, - - if (seg->log_lv) { - /* If disk log, use its UUID */ -- if (!(log_dlid = build_dm_uuid(mem, seg->log_lv->lvid.s, NULL))) { -+ if (!(log_dlid = build_dm_uuid(mem, seg->log_lv, NULL))) { - log_error("Failed to build uuid for log LV %s.", - seg->log_lv->name); - return 0; - } - } else { - /* If core log, use mirror's UUID and set DM_CORELOG flag */ -- if (!(log_dlid = build_dm_uuid(mem, seg->lv->lvid.s, NULL))) { -+ if (!(log_dlid = build_dm_uuid(mem, seg->lv, NULL))) { - log_error("Failed to build uuid for mirror LV %s.", - seg->lv->name); - return 0; -diff --git a/lib/misc/lvm-string.c b/lib/misc/lvm-string.c -index 380fe81..b96b5cc 100644 ---- a/lib/misc/lvm-string.c -+++ b/lib/misc/lvm-string.c -@@ -15,6 +15,7 @@ - - #include "lib.h" - #include "lvm-string.h" -+#include "metadata-exported.h" - - #include - -@@ -160,8 +161,13 @@ int is_reserved_lvname(const char *name) - return rc; - } - --char *build_dm_uuid(struct dm_pool *mem, const char *lvid, -+char *build_dm_uuid(struct dm_pool *mem, const struct logical_volume *lv, - const char *layer) - { -+ const char *lvid = lv->lvid.s; -+ -+ if (!layer && lv_is_thin_pool(lv)) -+ layer = "pool"; -+ - return dm_build_dm_uuid(mem, UUID_PREFIX, lvid, layer); - } -diff --git a/lib/misc/lvm-string.h b/lib/misc/lvm-string.h -index 13aacf8..82ebb12 100644 ---- a/lib/misc/lvm-string.h -+++ b/lib/misc/lvm-string.h -@@ -23,6 +23,7 @@ - #define UUID_PREFIX "LVM-" - - struct pool; -+struct logical_volume; - - typedef enum name_error { NAME_VALID = 0, NAME_INVALID_EMPTY = -1, - NAME_INVALID_HYPEN = -2, NAME_INVALID_DOTS = -3, -@@ -32,7 +33,7 @@ typedef enum name_error { NAME_VALID = 0, NAME_INVALID_EMPTY = -1, - int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...) - __attribute__ ((format(printf, 3, 4))); - --char *build_dm_uuid(struct dm_pool *mem, const char *lvid, -+char *build_dm_uuid(struct dm_pool *mem, const struct logical_volume *lvid, - const char *layer); - - int validate_name(const char *n); -diff --git a/lib/thin/thin.c b/lib/thin/thin.c -index 7c989f8..494fa92 100644 ---- a/lib/thin/thin.c -+++ b/lib/thin/thin.c -@@ -277,13 +277,13 @@ static int _thin_pool_add_target_line(struct dev_manager *dm, - return 0; - } - -- if (!(metadata_dlid = build_dm_uuid(mem, seg->metadata_lv->lvid.s, NULL))) { -+ if (!(metadata_dlid = build_dm_uuid(mem, seg->metadata_lv, NULL))) { - log_error("Failed to build uuid for metadata LV %s.", - seg->metadata_lv->name); - return 0; - } - -- if (!(pool_dlid = build_dm_uuid(mem, seg_lv(seg, 0)->lvid.s, NULL))) { -+ if (!(pool_dlid = build_dm_uuid(mem, seg_lv(seg, 0), NULL))) { - log_error("Failed to build uuid for pool LV %s.", - seg_lv(seg, 0)->name); - return 0; -@@ -535,7 +535,7 @@ static int _thin_add_target_line(struct dev_manager *dm, - seg->lv->name); - return 0; - } -- if (!(pool_dlid = build_dm_uuid(mem, seg->pool_lv->lvid.s, lv_layer(seg->pool_lv)))) { -+ if (!(pool_dlid = build_dm_uuid(mem, seg->pool_lv, lv_layer(seg->pool_lv)))) { - log_error("Failed to build uuid for pool LV %s.", - seg->pool_lv->name); - return 0; -@@ -573,7 +573,7 @@ static int _thin_add_target_line(struct dev_manager *dm, - return 0; - } - } -- if (!(external_dlid = build_dm_uuid(mem, seg->external_lv->lvid.s, -+ if (!(external_dlid = build_dm_uuid(mem, seg->external_lv, - lv_layer(seg->external_lv)))) { - log_error("Failed to build uuid for external origin LV %s.", - seg->external_lv->name); -diff --git a/test/shell/lvcreate-thin.sh b/test/shell/lvcreate-thin.sh -index a2811d2..ab27dfb 100644 ---- a/test/shell/lvcreate-thin.sh -+++ b/test/shell/lvcreate-thin.sh -@@ -173,7 +173,9 @@ not lvcreate --chunksize 32 -l1 -T $vg/pool1 - # Too large chunk size (max is 1GB) - not lvcreate -L4M --chunksize 2G -T $vg/pool1 - --lvcreate -L4M -V2G --name lv1 -T $vg/pool1 -+# Test creation of inactive pool -+lvcreate -an -L4M -T $vg/pool1 -+lvcreate -V2G --name lv1 -T $vg/pool1 - # Origin name is not accepted - not lvcreate -s $vg/lv1 -L4M -V2G --name $vg/lv4 - -diff --git a/test/shell/pvremove-thin.sh b/test/shell/pvremove-thin.sh -new file mode 100644 -index 0000000..03e6ca3 ---- /dev/null -+++ b/test/shell/pvremove-thin.sh -@@ -0,0 +1,28 @@ -+#!/bin/sh -+# Copyright (C) 2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+# Checks we are not reading our own devices -+# https://bugzilla.redhat.com/show_bug.cgi?id=1064374 -+ -+. lib/test -+ -+aux prepare_vg -+ -+aux target_at_least dm-thin-pool 1 8 0 || skip -+ -+aux extend_filter_LVMTEST -+ -+lvcreate -L10 -V10 -n $lv1 -T $vg/pool1 -+ -+pvcreate "$DM_DEV_DIR/$vg/$lv1" -+pvremove "$DM_DEV_DIR/$vg/$lv1" -+ -+vgremove -ff $vg diff --git a/SOURCES/lvm2-2_02_116-fix-raid-image-splitting.patch b/SOURCES/lvm2-2_02_116-fix-raid-image-splitting.patch new file mode 100644 index 0000000..e94b45d --- /dev/null +++ b/SOURCES/lvm2-2_02_116-fix-raid-image-splitting.patch @@ -0,0 +1,201 @@ + WHATS_NEW | 6 ++++++ + lib/activate/activate.c | 21 +++++++++++++++++++++ + lib/activate/dev_manager.c | 2 +- + lib/metadata/lv.c | 4 ++++ + lib/metadata/raid_manip.c | 30 ++++++++++-------------------- + test/shell/lvconvert-raid.sh | 6 ++++++ + test/shell/lvconvert-repair-thin.sh | 9 ++++++++- + tools/lvconvert.c | 1 + + 8 files changed, 57 insertions(+), 22 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 75c4569..ef5cc83 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,3 +1,9 @@ ++Version 2.02.116 - ++==================================== ++ Preserve chunk size with repair and metadata swap of a thin pool. ++ Fix raid --splitmirror 1 functionality (2.02.112). ++ Fix tree preload to handle splitting raid images. ++ + Version 2.02.115 - 21st January 2015 + ==================================== + Report segment types without monitoring support as undefined. +diff --git a/lib/activate/activate.c b/lib/activate/activate.c +index 424786c..00d3a10 100644 +--- a/lib/activate/activate.c ++++ b/lib/activate/activate.c +@@ -1760,6 +1760,22 @@ static int _preload_detached_lv(struct logical_volume *lv, void *data) + struct detached_lv_data *detached = data; + struct lv_list *lvl_pre; + ++ /* Check and preload removed raid image leg */ ++ if (lv_is_raid_image(lv)) { ++ if ((lvl_pre = find_lv_in_vg_by_lvid(detached->lv_pre->vg, &lv->lvid)) && ++ !lv_is_raid_image(lvl_pre->lv) && ++ !_lv_preload(lvl_pre->lv, detached->laopts, detached->flush_required)) ++ return_0; ++ } ++ ++ /* Check and preload removed of raid metadata */ ++ if (lv_is_raid_metadata(lv)) { ++ if ((lvl_pre = find_lv_in_vg_by_lvid(detached->lv_pre->vg, &lv->lvid)) && ++ !lv_is_raid_metadata(lvl_pre->lv) && ++ !_lv_preload(lvl_pre->lv, detached->laopts, detached->flush_required)) ++ return_0; ++ } ++ + if ((lvl_pre = find_lv_in_vg(detached->lv_pre->vg, lv->name))) { + if (lv_is_visible(lvl_pre->lv) && lv_is_active(lv) && + (!lv_is_cow(lv) || !lv_is_cow(lvl_pre->lv)) && +@@ -1863,6 +1879,11 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s, + if (!for_each_sub_lv((struct logical_volume *)ondisk_lv, &_preload_detached_lv, &detached)) + goto_out; + ++ /* ATM cache/thin pool is not scanned in 'for_each_sub_lv()', TODO explore better way */ ++ if (lv_is_cache(ondisk_lv) && ++ !for_each_sub_lv(first_seg(ondisk_lv)->pool_lv, &_preload_detached_lv, &detached)) ++ goto_out; ++ + /* + * Preload any snapshots that are being removed. + */ +diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c +index 015af5b..dcb2c5d 100644 +--- a/lib/activate/dev_manager.c ++++ b/lib/activate/dev_manager.c +@@ -2295,7 +2295,7 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg, + * is used in the CTR table. + */ + if ((seg_type(seg, s) == AREA_UNASSIGNED) || +- ((seg_lv(seg, s)->status & VISIBLE_LV) && ++ (lv_is_visible(seg_lv(seg, s)) && + !(seg_lv(seg, s)->status & LVM_WRITE))) { + /* One each for metadata area and data area */ + if (!dm_tree_node_add_null_area(node, 0) || +diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c +index 683ec47..9052e63 100644 +--- a/lib/metadata/lv.c ++++ b/lib/metadata/lv.c +@@ -1018,6 +1018,10 @@ const struct logical_volume *lv_lock_holder(const struct logical_volume *lv) + return sl->seg->lv; + } + ++ /* RAID changes visibility of splitted LVs but references them still as leg/meta */ ++ if ((lv_is_raid_image(lv) || lv_is_raid_metadata(lv)) && lv_is_visible(lv)) ++ return lv; ++ + /* For other types, by default look for the first user */ + dm_list_iterate_items(sl, &lv->segs_using_this_lv) { + /* FIXME: complete this exception list */ +diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c +index d502379..22f71c7 100644 +--- a/lib/metadata/raid_manip.c ++++ b/lib/metadata/raid_manip.c +@@ -1149,12 +1149,6 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name, + return 0; + } + +- if (!resume_lv(lv->vg->cmd, lv_lock_holder(lv))) { +- log_error("Failed to resume %s/%s after committing changes", +- lv->vg->name, lv->name); +- return 0; +- } +- + /* + * First activate the newly split LV and LVs on the removal list. + * This is necessary so that there are no name collisions due to +@@ -1164,26 +1158,22 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name, + if (!activate_lv_excl_local(cmd, lvl->lv)) + return_0; + ++ dm_list_iterate_items(lvl, &removal_list) ++ if (!activate_lv_excl_local(cmd, lvl->lv)) ++ return_0; ++ ++ if (!resume_lv(cmd, lv_lock_holder(lv))) { ++ log_error("Failed to resume %s/%s after committing changes", ++ lv->vg->name, lv->name); ++ return 0; ++ } ++ + /* + * Since newly split LV is typically already active - we need to call + * suspend() and resume() to also rename it. + * + * TODO: activate should recognize it and avoid these 2 calls + */ +- if (!suspend_lv(cmd, lvl->lv)) { +- log_error("Failed to suspend %s.", lvl->lv->name); +- return 0; +- } +- +- if (!resume_lv(cmd, lvl->lv)) { +- log_error("Failed to reactivate %s.", lvl->lv->name); +- return 0; +- } +- +- dm_list_iterate_items(lvl, &removal_list) +- if (!activate_lv_excl_local(cmd, lvl->lv)) +- return_0; +- + + /* + * Eliminate the residual LVs +diff --git a/test/shell/lvconvert-raid.sh b/test/shell/lvconvert-raid.sh +index 8621311..12e0420 100644 +--- a/test/shell/lvconvert-raid.sh ++++ b/test/shell/lvconvert-raid.sh +@@ -121,6 +121,12 @@ check active $vg $lv2 + # FIXME: ensure no residual devices + lvremove -ff $vg + ++# 4-way ++lvcreate --type raid1 -m 4 -l 2 -n $lv1 $vg ++aux wait_for_sync $vg $lv1 ++lvconvert --yes --splitmirrors 1 --name $lv2 $vg/$lv1 "$dev2" ++lvremove -ff $vg ++ + ########################################### + # RAID1 split + trackchanges / merge + ########################################### +diff --git a/test/shell/lvconvert-repair-thin.sh b/test/shell/lvconvert-repair-thin.sh +index 0e9534b..73f061c 100644 +--- a/test/shell/lvconvert-repair-thin.sh ++++ b/test/shell/lvconvert-repair-thin.sh +@@ -24,7 +24,9 @@ aux have_thin 1 0 0 || skip + aux prepare_vg 4 + + # Create LV +-lvcreate -T -L20 -V10 -n $lv1 $vg/pool "$dev1" "$dev2" ++# TODO: investigate problem with --zero n and my repairable damage trick ++#lvcreate -T -L20 -V10 -n $lv1 $vg/pool --discards ignore --zero n --chunksize 128 "$dev1" "$dev2" ++lvcreate -T -L20 -V10 -n $lv1 $vg/pool --chunksize 128 --discards ignore "$dev1" "$dev2" + lvcreate -T -V10 -n $lv2 $vg/pool + + mkfs.ext2 "$DM_DEV_DIR/$vg/$lv1" +@@ -71,6 +73,11 @@ lvchange -an $vg + # Swap repaired metadata back + lvconvert -y -f --poolmetadata $vg/fixed --thinpool $vg/pool + ++# Check pool still preserves its original settings ++check lv_field $vg/pool chunksize "128.00k" ++check lv_field $vg/pool discards "ignore" ++check lv_field $vg/pool zero "zero" ++ + # Activate pool - this should now work + vgchange -ay $vg + +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index c7acd5d..20f017a 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -2956,6 +2956,7 @@ static int _lvconvert_pool(struct cmd_context *cmd, + return 0; + } + ++ lp->passed_args |= PASS_ARG_CHUNK_SIZE | PASS_ARG_DISCARDS | PASS_ARG_ZERO; + seg = first_seg(pool_lv); + + /* Normally do NOT change chunk size when swapping */ diff --git a/SOURCES/lvm2-drop-unavailable-libblkid-2_24-BLKID_SUBLKS_BADCSUM-for-signature-detection.patch b/SOURCES/lvm2-drop-unavailable-libblkid-2_24-BLKID_SUBLKS_BADCSUM-for-signature-detection.patch index b1cb821..67b7081 100644 --- a/SOURCES/lvm2-drop-unavailable-libblkid-2_24-BLKID_SUBLKS_BADCSUM-for-signature-detection.patch +++ b/SOURCES/lvm2-drop-unavailable-libblkid-2_24-BLKID_SUBLKS_BADCSUM-for-signature-detection.patch @@ -1,13 +1,13 @@ - configure | 20 ++++++++++---------- - configure.in | 4 ++-- - lib/device/dev-type.c | 3 +-- + configure | 20 ++++++++++---------- + configure.in | 4 ++-- + lib/device/dev-type.c | 3 +-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/configure b/configure -index a156460..c96911c 100755 +index df902c3..d8319e0 100755 --- a/configure +++ b/configure -@@ -9484,12 +9484,12 @@ if test -n "$BLKID_CFLAGS"; then +@@ -10524,12 +10524,12 @@ if test -n "$BLKID_CFLAGS"; then pkg_cv_BLKID_CFLAGS="$BLKID_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ @@ -20,10 +20,10 @@ index a156460..c96911c 100755 test $ac_status = 0; }; then - pkg_cv_BLKID_CFLAGS=`$PKG_CONFIG --cflags "blkid >= 2.24" 2>/dev/null` + pkg_cv_BLKID_CFLAGS=`$PKG_CONFIG --cflags "blkid >= 2.23" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes - fi -@@ -9500,12 +9500,12 @@ if test -n "$BLKID_LIBS"; then +@@ -10541,12 +10541,12 @@ if test -n "$BLKID_LIBS"; then pkg_cv_BLKID_LIBS="$BLKID_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ @@ -36,65 +36,63 @@ index a156460..c96911c 100755 test $ac_status = 0; }; then - pkg_cv_BLKID_LIBS=`$PKG_CONFIG --libs "blkid >= 2.24" 2>/dev/null` + pkg_cv_BLKID_LIBS=`$PKG_CONFIG --libs "blkid >= 2.23" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes - fi -@@ -9525,9 +9525,9 @@ else +@@ -10567,9 +10567,9 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then -- BLKID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "blkid >= 2.24" 2>&1` -+ BLKID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "blkid >= 2.23" 2>&1` +- BLKID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "blkid >= 2.24" 2>&1` ++ BLKID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "blkid >= 2.23" 2>&1` else -- BLKID_PKG_ERRORS=`$PKG_CONFIG --print-errors "blkid >= 2.24" 2>&1` -+ BLKID_PKG_ERRORS=`$PKG_CONFIG --print-errors "blkid >= 2.23" 2>&1` +- BLKID_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "blkid >= 2.24" 2>&1` ++ BLKID_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "blkid >= 2.23" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$BLKID_PKG_ERRORS" >&5 -@@ -9535,7 +9535,7 @@ fi - if test x$BLKID_WIPING = xmaybe; then - BLKID_WIPING=no - else -- as_fn_error $? "bailing out... blkid library >= 2.24 is required" "$LINENO" 5 -+ as_fn_error $? "bailing out... blkid library >= 2.23 is required" "$LINENO" 5 - fi - +@@ -10577,7 +10577,7 @@ fi + if test "$BLKID_WIPING" = maybe; then + BLKID_WIPING=no + else +- as_fn_error $? "bailing out... blkid library >= 2.24 is required" "$LINENO" 5 ++ as_fn_error $? "bailing out... blkid library >= 2.23 is required" "$LINENO" 5 + fi elif test $pkg_failed = untried; then -@@ -9544,7 +9544,7 @@ $as_echo "no" >&6; } - if test x$BLKID_WIPING = xmaybe; then - BLKID_WIPING=no - else -- as_fn_error $? "bailing out... blkid library >= 2.24 is required" "$LINENO" 5 -+ as_fn_error $? "bailing out... blkid library >= 2.23 is required" "$LINENO" 5 - fi - + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +@@ -10585,7 +10585,7 @@ $as_echo "no" >&6; } + if test "$BLKID_WIPING" = maybe; then + BLKID_WIPING=no + else +- as_fn_error $? "bailing out... blkid library >= 2.24 is required" "$LINENO" 5 ++ as_fn_error $? "bailing out... blkid library >= 2.23 is required" "$LINENO" 5 + fi else + BLKID_CFLAGS=$pkg_cv_BLKID_CFLAGS diff --git a/configure.in b/configure.in -index 3e0e508..cff7e45 100644 +index 5b22b93..2c3fcba 100644 --- a/configure.in +++ b/configure.in -@@ -981,14 +981,14 @@ if test x$BLKID_WIPING != xno; then - if test x$PKGCONFIG_INIT != x1; then - pkg_config_init - fi +@@ -1077,12 +1077,12 @@ AC_MSG_RESULT($BLKID_WIPING) + + if test "$BLKID_WIPING" != no; then + pkg_config_init - PKG_CHECK_MODULES(BLKID, blkid >= 2.24, + PKG_CHECK_MODULES(BLKID, blkid >= 2.23, - [if test x$BLKID_WIPING = xmaybe; then - BLKID_WIPING=yes - fi], - [if test x$BLKID_WIPING = xmaybe; then - BLKID_WIPING=no - else -- AC_MSG_ERROR([bailing out... blkid library >= 2.24 is required]) -+ AC_MSG_ERROR([bailing out... blkid library >= 2.23 is required]) - fi - ]) - if test x$BLKID_WIPING = xyes; then + [test "$BLKID_WIPING" = maybe && BLKID_WIPING=yes], + [if test "$BLKID_WIPING" = maybe; then + BLKID_WIPING=no + else +- AC_MSG_ERROR([bailing out... blkid library >= 2.24 is required]) ++ AC_MSG_ERROR([bailing out... blkid library >= 2.23 is required]) + fi]) + if test "$BLKID_WIPING" = yes; then + BLKID_PC="blkid" diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c -index 78b093c..02bc99f 100644 +index 001248d..03752a5 100644 --- a/lib/device/dev-type.c +++ b/lib/device/dev-type.c -@@ -521,8 +521,7 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam +@@ -548,8 +548,7 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam BLKID_SUBLKS_TYPE | BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION | diff --git a/SOURCES/lvm2-enable-lvmetad-by-default.patch b/SOURCES/lvm2-enable-lvmetad-by-default.patch index 26b8224..7f16b92 100644 --- a/SOURCES/lvm2-enable-lvmetad-by-default.patch +++ b/SOURCES/lvm2-enable-lvmetad-by-default.patch @@ -3,28 +3,28 @@ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/example.conf.in b/conf/example.conf.in -index 10f12bd..03bee13 100644 +index d1a1397..812b747 100644 --- a/conf/example.conf.in +++ b/conf/example.conf.in -@@ -594,7 +594,7 @@ global { - # supported in clustered environment. If use_lvmetad=1 and locking_type=3 +@@ -730,7 +730,7 @@ global { # is set at the same time, LVM always issues a warning message about this - # and then it automatically disables lvmetad use. + # and then it automatically disables use_lvmetad. + - use_lvmetad = 0 + use_lvmetad = 1 # Full path of the utility called to check that a thin metadata device # is in a state that allows it to be used. diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h -index c935920..a9f35e6 100644 +index e944b81..7b5beff 100644 --- a/lib/config/config_settings.h +++ b/lib/config/config_settings.h -@@ -158,7 +158,7 @@ cfg(global_metadata_read_only_CFG, "metadata_read_only", global_CFG_SECTION, 0, - cfg(global_mirror_segtype_default_CFG, "mirror_segtype_default", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_MIRROR_SEGTYPE, vsn(2, 2, 87), NULL) +@@ -177,7 +177,7 @@ cfg(global_mirror_segtype_default_CFG, "mirror_segtype_default", global_CFG_SECT cfg(global_raid10_segtype_default_CFG, "raid10_segtype_default", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_RAID10_SEGTYPE, vsn(2, 2, 99), NULL) - cfg(global_lvdisplay_shows_full_device_path_CFG, "lvdisplay_shows_full_device_path", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH, vsn(2, 2, 89), NULL) + cfg(global_sparse_segtype_default_CFG, "sparse_segtype_default", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_SPARSE_SEGTYPE, vsn(2, 2, 112), NULL) + cfg(global_lvdisplay_shows_full_device_path_CFG, "lvdisplay_shows_full_device_path", global_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH, vsn(2, 2, 89), NULL) -cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 93), NULL) +cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 93), NULL) cfg(global_thin_check_executable_CFG, "thin_check_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, THIN_CHECK_CMD, vsn(2, 2, 94), NULL) cfg_array(global_thin_check_options_CFG, "thin_check_options", global_CFG_SECTION, 0, CFG_TYPE_STRING, "#S" DEFAULT_THIN_CHECK_OPTIONS, vsn(2, 2, 96), NULL) - cfg_array(global_thin_disabled_features_CFG, "thin_disabled_features", global_CFG_SECTION, 0, CFG_TYPE_STRING, "#S", vsn(2, 2, 99), NULL) + cfg_array(global_thin_disabled_features_CFG, "thin_disabled_features", global_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, NULL, vsn(2, 2, 99), NULL) diff --git a/SOURCES/lvm2-remove-mpath-device-handling-from-udev-rules.patch b/SOURCES/lvm2-remove-mpath-device-handling-from-udev-rules.patch new file mode 100644 index 0000000..168603b --- /dev/null +++ b/SOURCES/lvm2-remove-mpath-device-handling-from-udev-rules.patch @@ -0,0 +1,18 @@ + udev/10-dm.rules.in | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/udev/10-dm.rules.in b/udev/10-dm.rules.in +index 2755530..8d7a8ca 100644 +--- a/udev/10-dm.rules.in ++++ b/udev/10-dm.rules.in +@@ -120,10 +120,6 @@ ENV{DM_UDEV_RULES_VSN}="2" + + ENV{DM_UDEV_DISABLE_DM_RULES_FLAG}!="1", ENV{DM_NAME}=="?*", SYMLINK+="(DM_DIR)/$env{DM_NAME}" + +-# We have to ignore further rule application for inappropriate events +-# and devices. But still send the notification if cookie exists. +-ENV{DM_UUID}=="mpath-?*", ENV{DM_ACTION}=="PATH_FAILED", GOTO="dm_disable" +- + # Avoid processing and scanning a DM device in the other (foreign) + # rules if it is in suspended state. However, we still keep 'disk' + # and 'DM subsystem' related rules enabled in this case. diff --git a/SOURCES/lvm2-rhel7.patch b/SOURCES/lvm2-rhel7.patch index 862e4aa..80ed52d 100644 --- a/SOURCES/lvm2-rhel7.patch +++ b/SOURCES/lvm2-rhel7.patch @@ -7,12 +7,12 @@ index dd4e60e..39d6c15 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ --2.02.105(2) (2014-01-20) -+2.02.105(2)-RHEL7 (2014-03-26) +-2.02.115(2) (2015-01-21) ++2.02.115(2)-RHEL7 (2015-01-28) diff --git a/VERSION_DM b/VERSION_DM index d53f47a..005fbd4 100644 --- a/VERSION_DM +++ b/VERSION_DM @@ -1 +1 @@ --1.02.84 (2014-01-20) -+1.02.84-RHEL7 (2014-03-26) +-1.02.93 (2015-01-21) ++1.02.93-RHEL7 (2015-01-28) diff --git a/SOURCES/lvm2-set-default-preferred_names.patch b/SOURCES/lvm2-set-default-preferred_names.patch index 3fe0e5b..801177f 100644 --- a/SOURCES/lvm2-set-default-preferred_names.patch +++ b/SOURCES/lvm2-set-default-preferred_names.patch @@ -1,20 +1,11 @@ - conf/example.conf.in | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/conf/example.conf.in b/conf/example.conf.in -index 2032a81..0bd72f1 100644 ---- a/conf/example.conf.in -+++ b/conf/example.conf.in -@@ -53,10 +53,10 @@ devices { - # same block device and the tools need to display a name for device, - # all the pathnames are matched against each item in the following - # list of regular expressions in turn and the first match is used. -- preferred_names = [ ] -+ # preferred_names = [ ] +--- LVM2.2.02.108/conf/example.conf.in 2014-07-23 16:21:02.000000000 +0100 ++++ LVM2.2.02.108-new/conf/example.conf.in 2014-07-23 23:05:06.000000000 +0100 +@@ -58,7 +58,7 @@ + # preferred_names = [ ] # Try to avoid using undescriptive /dev/dm-N names, if present. - # preferred_names = [ "^/dev/mpath/", "^/dev/mapper/mpath", "^/dev/[hs]d" ] + preferred_names = [ "^/dev/mpath/", "^/dev/mapper/mpath", "^/dev/[hs]d" ] - # A filter that tells LVM2 to only use a restricted set of devices. - # The filter consists of an array of regular expressions. These + # In case no prefererred name matches or if preferred_names are not + # defined at all, builtin rules are used to determine the preference. diff --git a/SPECS/lvm2.spec b/SPECS/lvm2.spec index 1d5e3c6..a13d84c 100644 --- a/SPECS/lvm2.spec +++ b/SPECS/lvm2.spec @@ -1,4 +1,4 @@ -%define device_mapper_version 1.02.84 +%define device_mapper_version 1.02.93 %define enable_cache 1 %define enable_cluster 1 @@ -15,10 +15,10 @@ %define resource_agents_version 3.9.5-25 %define dlm_version 3.99.1-1 %define libselinux_version 1.30.19-4 -%define persistent_data_version 0.2.7-1 +%define persistent_data_version 0.3.2-1 %if 0%{?rhel} - %ifnarch i686 x86_64 + %ifnarch i686 x86_64 s390x %define enable_cluster 0 %define enable_cmirror 0 %endif @@ -40,8 +40,8 @@ Summary: Userland logical volume management tools Name: lvm2 Epoch: 7 -Version: 2.02.105 -Release: 14%{?dist} +Version: 2.02.115 +Release: 3%{?dist} License: GPLv2 Group: System Environment/Base URL: http://sources.redhat.com/lvm2 @@ -50,17 +50,8 @@ Patch0: lvm2-rhel7.patch Patch1: lvm2-set-default-preferred_names.patch Patch2: lvm2-enable-lvmetad-by-default.patch Patch3: lvm2-drop-unavailable-libblkid-2_24-BLKID_SUBLKS_BADCSUM-for-signature-detection.patch -Patch4: lvm2-2_02_106-upstream-with-cache-support.patch -Patch5: lvm2-2_02_106-fix-incorrect-snapshot-calculation-of-cow-size.patch -Patch6: lvm2-2_02_106-additional-lvmetad-fixes.patch -Patch7: lvm2-2_02_106-cleanup-stray-warning-messages-for-cmirror.patch -Patch8: lvm2-2_02_106-fix-dmeventd-logging-with-parallel-wait-processing.patch -Patch9: lvm2-2_02_106-various-thin-fixes.patch -Patch10: lvm2-2_02_106-enahnce-lvmetad-protocol-for-pvscan-to-lock-vg-properly-and-run-refresh-only-when-needed.patch -Patch11: lvm2-2_02_106-cleanup-stray-warning-messages-for-cmirror-addendum.patch -Patch12: lvm2-2_02_106-reinitialise-lvmcache-properly-on-fork-to-fix-premature-polldaemon-exit.patch -Patch13: lvm2-2_02_106-fix-timeout-for-initial-lvmetad-scan-when-done-in-parallel.patch -Patch14: lvm2-2_02_106-various-man-page-cleanups.patch +Patch4: lvm2-remove-mpath-device-handling-from-udev-rules.patch +Patch5: lvm2-2_02_116-fix-raid-image-splitting.patch BuildRequires: libselinux-devel >= %{libselinux_version}, libsepol-devel BuildRequires: libblkid-devel >= %{util_linux_version} @@ -78,6 +69,9 @@ BuildRequires: systemd-units BuildRequires: python2-devel BuildRequires: python-setuptools %endif +%if %{enable_thin} +BuildRequires: device-mapper-persistent-data >= %{persistent_data_version} +%endif Requires: %{name}-libs = %{epoch}:%{version}-%{release} Requires: bash >= %{bash_version} Requires(post): systemd-units >= %{systemd_version} @@ -102,17 +96,8 @@ or more physical volumes and creating one or more logical volumes %patch1 -p1 -b .preferred_names %patch2 -p1 -b .enable_lvmetad %patch3 -p1 -b .blkid_sublks_badcsum -%patch4 -p1 -b .v106_upstream_cache -%patch5 -p1 -b .snap_cow_size_calc -%patch6 -p1 -b .lvmetad_fixes -%patch7 -p1 -b .cmirror_messages -%patch8 -p1 -b .dmeventd_parallel_wait -%patch9 -p1 -b .thin_fixes -%patch10 -p1 -b .pvscan_lvmetad -%patch11 -p1 -b .cmirror_messages_addendum -%patch12 -p1 -b .lvmcache_reinitialise -%patch13 -p1 -b .initial_lvmetad_scan_timeout -%patch14 -p1 -b .man_page_cleanups +%patch4 -p1 -b .multipath +%patch5 -p1 -b .raid_split %build %define _default_pid_dir /run @@ -134,7 +119,7 @@ or more physical volumes and creating one or more logical volumes %endif %if %{enable_lvmetad} -%define configure_lvmetad --enable-lvmetad --enable-udev-systemd-background-jobs +%define configure_lvmetad --enable-lvmetad %endif %if %{enable_python} @@ -237,6 +222,8 @@ rm -rf $RPM_BUILD_ROOT %{_sbindir}/vgscan %{_sbindir}/vgsplit %{_mandir}/man5/lvm.conf.5.gz +%{_mandir}/man7/lvmcache.7.gz +%{_mandir}/man7/lvmthin.7.gz %{_mandir}/man8/blkdeactivate.8.gz %{_mandir}/man8/fsadm.8.gz %{_mandir}/man8/lvchange.8.gz @@ -245,6 +232,8 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man8/lvdisplay.8.gz %{_mandir}/man8/lvextend.8.gz %{_mandir}/man8/lvm.8.gz +%{_mandir}/man8/lvm2-activation-generator.8.gz +%{_mandir}/man8/lvm-dumpconfig.8.gz %{_mandir}/man8/lvmchange.8.gz %{_mandir}/man8/lvmconf.8.gz %{_mandir}/man8/lvmdiskscan.8.gz @@ -294,13 +283,15 @@ rm -rf $RPM_BUILD_ROOT %ghost %{_sysconfdir}/lvm/cache/.cache %attr(644, -, -) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/lvm.conf %dir %{_sysconfdir}/lvm/profile -%{_sysconfdir}/lvm/profile/default.profile +%{_sysconfdir}/lvm/profile/command_profile_template.profile +%{_sysconfdir}/lvm/profile/metadata_profile_template.profile +%{_sysconfdir}/lvm/profile/thin-generic.profile %{_sysconfdir}/lvm/profile/thin-performance.profile %dir %{_sysconfdir}/lvm/backup %dir %{_sysconfdir}/lvm/cache %dir %{_sysconfdir}/lvm/archive -%dir %{_default_locking_dir} -%dir %{_default_run_dir} +%ghost %dir %{_default_locking_dir} +%ghost %dir %{_default_run_dir} %{_tmpfilesdir}/%{name}.conf %{_unitdir}/blk-availability.service %{_unitdir}/lvm2-monitor.service @@ -319,8 +310,8 @@ Summary: Development libraries and headers Group: Development/Libraries License: LGPLv2 Requires: %{name} = %{epoch}:%{version}-%{release} -Requires: device-mapper-devel >= %{epoch}:%{device_mapper_version}-%{release} -Requires: device-mapper-event-devel >= %{epoch}:%{device_mapper_version}-%{release} +Requires: device-mapper-devel = %{epoch}:%{device_mapper_version}-%{release} +Requires: device-mapper-event-devel = %{epoch}:%{device_mapper_version}-%{release} Requires: pkgconfig %description devel @@ -340,7 +331,7 @@ the lvm2 libraries. Summary: Shared libraries for lvm2 License: LGPLv2 Group: System Environment/Libraries -Requires: device-mapper-event >= %{epoch}:%{device_mapper_version}-%{release} +Requires: device-mapper-event = %{epoch}:%{device_mapper_version}-%{release} %description libs This package contains shared lvm2 libraries for applications. @@ -388,7 +379,7 @@ logical volumes, physical volumes, and volume groups. ############################################################################## # Cluster subpackage -# The OCF script to manage clvmd instance is part of resource-agents package. +# The 'clvm' OCF script to manage clvmd instance is part of resource-agents. ############################################################################## %if %{enable_cluster} @@ -396,8 +387,8 @@ logical volumes, physical volumes, and volume groups. Summary: Cluster extensions for userland logical volume management tools License: GPLv2 Group: System Environment/Base -Requires: lvm2 >= %{epoch}:%{version}-%{release} -Requires(preun): device-mapper >= %{epoch}:%{device_mapper_version} +Requires: lvm2 = %{epoch}:%{version}-%{release} +Requires(preun): device-mapper = %{epoch}:%{device_mapper_version} Requires(preun): lvm2 >= 2.02 Requires: corosync >= %{corosync_version} Requires: dlm >= %{dlm_version} @@ -429,7 +420,7 @@ fi Summary: Additional files to support clustered LVM2 in standalone mode License: GPLv2 Group: System Environment/Base -Requires: lvm2-cluster >= %{epoch}:%{version}-%{release} +Requires: lvm2-cluster = %{epoch}:%{version}-%{release} %description cluster-standalone @@ -455,10 +446,10 @@ involvement (e.g. pacemaker). %endif -################################################################################# +############################################################################### # Cluster mirror subpackage -# The OCF script to manage cmirrord instance is part of resource-agents package. -################################################################################# +# The 'clvm' OCF script to manage cmirrord instance is part of resource-agents. +############################################################################### %if %{enable_cluster} %if %{enable_cmirror} @@ -466,7 +457,7 @@ involvement (e.g. pacemaker). Summary: Daemon for device-mapper-based clustered mirrors Group: System Environment/Base Requires: corosync >= %{corosync_version} -Requires: device-mapper >= %{epoch}:%{device_mapper_version}-%{release} +Requires: device-mapper = %{epoch}:%{device_mapper_version}-%{release} Requires: resource-agents >= %{resource_agents_version} %description -n cmirror @@ -675,6 +666,88 @@ the device-mapper event library. %{_libdir}/pkgconfig/devmapper-event.pc %changelog +* Wed Jan 28 2015 Peter Rajnoha - 7:2.02.115-3 +- Preserve chunk size with repair and metadata swap of a thin pool. +- Fix raid --splitmirror 1 functionality (2.02.112). +- Fix tree preload to handle splitting raid images. + +* Thu Jan 22 2015 Peter Rajnoha - 7:2.02.115-2 +- Remove rules from 10-dm.rules which handle multipath, rules for handling + multipath devices are directly part of device-mapper-multipath package. + +* Wed Jan 21 2015 Peter Rajnoha - 7:2.02.115-1 +- Report segment types without monitoring support as undefined. +- Support lvchange --errorwhenfull for thin pools. +- Improve the processing and reporting of duplicate PVs. +- Add support for lvcreate --errorwhenfull y|n for thin pools +- Fix lvconvert --repair to honour resilience requirement for segmented RAID LV. +- Also call lvscan --cache in dmeventd for mirror device update in lvmetad. +- Filter out partitioned device-mapper devices as unsuitable for use as PVs. +- Also notify lvmetad about filtered device if using pvscan --cache DevicePath. +- Add report/compact_output to lvm.conf to enable/disable compact report output. +- Rename lv_error_when_full reporting field to lv_when_full. +- Reduce severity of ioctl error message when dmeventd waitevent is interrupted. +- Report 'unknown version' when incompatible version numbers were not obtained. +- Add dm_report_compact_fields to remove empty fields from report output. +- Add BuildRequires: device-mapper-persistent-data for proper thin_check configuration. + +* Wed Jan 14 2015 Peter Rajnoha - 7:2.02.114-5 +- Report lv_health_status and health attribute also for thin pool. +- Add lv_error_when_full reporting field. +- Add support for lvcreate --errorwhenfull y|n for thin pools. +- Report more info from thin pool status (out of data, metadata-ro, fail). +- Support error_if_no_space for thin pool target. +- Do not filter out snapshot origin LVs as unusable devices for an LVM stack. +- Fix process_each_pv to match item by device not by its PV device name only. + +* Wed Jan 07 2015 Peter Rajnoha - 7:2.02.114-4 +- Fix incorrect rimage names when converting from mirror to raid1 LV (2.02.112). +- Avoid excessive re-reading of metadata and related error messages in pvremove. +- Check for cmirror availability during cluster mirror creation and activation. +- Fix possible segfault when using cache_policy and cache_settings fields. +- Fix reserved values recognition for cache_policy and cache_settings fields. + +* Wed Dec 17 2014 Peter Rajnoha - 7:2.02.114-3 +- Add cache_policy and cache_settings reporting fields. +- Add missing recognition for --binary option with {pv,vg,lv}display -C. +- Fix vgimportclone to notify lvmetad about changes done if lvmetad is used. +- Fix vgimportclone to properly override config if it is missing in lvm.conf. +- Fix automatic use of configure --enable-udev-systemd-background-jobs. +- Correctly rename active split LV with -splitmirrors for raid1. +- Still restrict mirror region size to power of 2 when VG extent size is not. +- Fix segfault while using selection with regex and unbuffered reporting. +- Remove unimplemented dm_report_set_output_selection from libdevmapper.h. + +* Mon Dec 01 2014 Peter Rajnoha - 7:2.02.114-2 +- Release socket in daemon_close and protocol string in daemon_open error path. +- Add --cachepolicy and --cachesettings to lvcreate. +- Fix regression when parsing /dev/mapper dir (2.02.112). +- Fix typo in clvmd initscript causing CLVMD_STOP_TIMEOUT var to be ignored. + +* Wed Nov 26 2014 Peter Rajnoha - 7:2.02.113-1 +- Fix missing rounding to 64KB when estimating optimal thin pool chunk size. +- Fix size in pvresize "Resizing to ..." verbose msg to show proper result size. +- Add --cachepolicy and --cachesettings options to lvchange. +- Validate that converted volume and specified pool volume differ in lvconvert. +- Fix regression in vgscan --mknodes usage (2.02.112). +- Respect --prefix when setting CLMVD_PATH configure (2.02.89). +- Default to configure --enable-udev-systemd-background-jobs for systemd>=205. +- Fix ignore_vg() to properly react on various vg_read errors (2.02.112). +- Failed recovery returns FAILED_RECOVERY status flag for vg_read(). +- Exit with non-zero status code when pvck encounters a problem. +- Fix clean_tree after activation/resume for cache target (2.02.112). +- Fix memory corruption with sorting empty string lists (1.02.86). +- Fix man dmsetup.8 syntax warning of Groff +- Accept unquoted strings and / in place of {} when parsing configs. + +* Tue Nov 11 2014 Peter Rajnoha - 7:2.02.112-1 +- Update to latest upstream release with various fixes and + enhancements documented in WHATS_NEW and WHATS_NEW_DM file. + +* Mon Sep 29 2014 Peter Rajnoha - 7:2.02.111-1 +- Update to latest upstream release with various fixes and + enhancements documented in WHATS_NEW and WHATS_NEW_DM file. + * Wed Mar 26 2014 Peter Rajnoha - 7:2.02.105-14 - Increase wait time for finishing initial lvmetad scan that's run in parallel. - Reinitialise lvmcache properly on fork to fix polldaemon exiting prematurely.