master - thin: validate external origin size
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=155405b0e1d310...
Commit: 155405b0e1d310fbc44f263c5e3a5c5d23043207
Parent: 8074d8056acd419fd38d53b32db5373df76d825f
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Jan 29 14:27:13 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jan 29 14:58:13 2014 +0100
thin: validate external origin size
Avoid use of external origin with size unaligned/incompatible with
thin pool chunk size, since the last chunk is not correctly provisioned
when it is overwritten.
---
WHATS_NEW | 1 +
lib/metadata/lv_manip.c | 4 +++-
lib/metadata/metadata-exported.h | 1 +
lib/metadata/thin_manip.c | 21 +++++++++++++++++++++
lib/thin/thin.c | 2 ++
tools/lvconvert.c | 3 +++
6 files changed, 31 insertions(+), 1 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 3a4c7ec..d28ec3c 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.106 -
====================================
+ 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.
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 2e240fc..a2831cf 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.
*
@@ -5980,6 +5980,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
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index bdf5c9d..1ebf69f 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -682,6 +682,7 @@ 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_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,
diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c
index 1abc2f1..60e93f0 100644
--- a/lib/metadata/thin_manip.c
+++ b/lib/metadata/thin_manip.c
@@ -252,6 +252,27 @@ int pool_below_threshold(const struct lv_segment *pool_seg)
return 1;
}
+/*
+ * 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)
+{
+ 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 1;
+}
+
struct logical_volume *find_pool_lv(const struct logical_volume *lv)
{
struct lv_segment *seg;
diff --git a/lib/thin/thin.c b/lib/thin/thin.c
index 0b8eaf8..8eaa73d 100644
--- a/lib/thin/thin.c
+++ b/lib/thin/thin.c
@@ -561,6 +561,8 @@ 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, first_seg(seg->pool_lv), &attr) ||
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index ffbf768..2ab4115 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -2483,6 +2483,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;
10 years, 2 months
master - thin:drop stack trace when pool is above threshold
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=8074d8056acd41...
Commit: 8074d8056acd419fd38d53b32db5373df76d825f
Parent: 5a1e1d0d398ad5ca32092047738ce6f7624837e9
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Jan 29 14:26:06 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jan 29 14:26:06 2014 +0100
thin:drop stack trace when pool is above threshold
Since this path is expected, do not log_debug stacktrace.
---
lib/metadata/thin_manip.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c
index b26723b..1abc2f1 100644
--- a/lib/metadata/thin_manip.c
+++ b/lib/metadata/thin_manip.c
@@ -240,14 +240,14 @@ 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;
}
10 years, 2 months
master - cleanup: fix cut&paste and move initialization
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=5a1e1d0d398ad5...
Commit: 5a1e1d0d398ad5ca32092047738ce6f7624837e9
Parent: e9d9852c55cbc2c509c293691287fa5443868926
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Jan 29 08:58:50 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jan 29 09:00:16 2014 +0100
cleanup: fix cut&paste and move initialization
Use C initializers and fix cut&paste core_arg error.
(in release fix)
---
lib/cache_segtype/cache.c | 27 ++++++++++++---------------
1 files changed, 12 insertions(+), 15 deletions(-)
diff --git a/lib/cache_segtype/cache.c b/lib/cache_segtype/cache.c
index c12ac2f..bfc84c3 100644
--- a/lib/cache_segtype/cache.c
+++ b/lib/cache_segtype/cache.c
@@ -343,19 +343,24 @@ static int _cache_add_target_line(struct dev_manager *dm,
struct dm_tree_node *node, uint64_t len,
uint32_t *pvmove_mirror_count __attribute__((unused)))
{
- struct lv_segment *cache_pool_seg;
struct logical_volume *data, *metadata, *origin;
- struct dm_tree_node_cache_params params;
+ struct lv_segment *cache_pool_seg = first_seg(seg->pool_lv);
+ struct dm_tree_node_cache_params params = {
+ .chunk_size = cache_pool_seg->chunk_size,
+
+ /* Cache features, core args, and policy are stored in the cache_pool */
+ .feature_flags = cache_pool_seg->feature_flags,
+ .core_argc = cache_pool_seg->core_argc,
+ .core_argv = cache_pool_seg->core_argv,
+ .policy_name = cache_pool_seg->policy_name,
+ .policy_argc = cache_pool_seg->policy_argc,
+ .policy_argv = cache_pool_seg->policy_argv
+ };
- cache_pool_seg = first_seg(seg->pool_lv);
data = seg_lv(cache_pool_seg, 0);
metadata = cache_pool_seg->metadata_lv;
origin = seg_lv(seg, 0);
- memset(¶ms, 0, sizeof(params));
-
- params.chunk_size = cache_pool_seg->chunk_size;
-
if (!(params.data_uuid = build_dm_uuid(mem, data->lvid.s, NULL)))
return_0;
@@ -365,14 +370,6 @@ static int _cache_add_target_line(struct dev_manager *dm,
if (!(params.origin_uuid = build_dm_uuid(mem, origin->lvid.s, NULL)))
return_0;
- /* Cache features, core args, and policy are stored in the cache_pool */
- params.feature_flags = cache_pool_seg->feature_flags;
- params.policy_argc = cache_pool_seg->core_argc;
- params.policy_argv = cache_pool_seg->core_argv;
- params.policy_name = cache_pool_seg->policy_name;
- params.policy_argc = cache_pool_seg->policy_argc;
- params.policy_argv = cache_pool_seg->policy_argv;
-
if (!dm_tree_node_add_cache_target(node, len, ¶ms))
return_0;
10 years, 2 months
master - thin: more validation of thin name
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=e9d9852c55cbc2...
Commit: e9d9852c55cbc2c509c293691287fa5443868926
Parent: bc5f40ee1c7c409c17f85a55f6a8b2606067e76e
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Jan 28 13:21:39 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Tue Jan 28 13:21:39 2014 +0100
thin: more validation of thin name
Avoid starting conversion of the LV to the thin pool and thin volume
at the same time. Since this is mostly a user mistake, do not try
to just convert to one of those type, since we cannot assume if the
user wanted LV to become thin volume or thin pool.
Before the fix tool reported pretty strange internal error:
Internal error: Referenced LV lvol1_tdata not listed in VG mvg.
Fixed output:
lvconvert --thinpool lvol0 -T mvg/lvol0
Can't use same LV mvg/lvol0 for thin pool and thin volume.
---
WHATS_NEW | 1 +
test/shell/lvconvert-thin-external.sh | 4 ++++
tools/lvconvert.c | 6 ++++++
3 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index ca56623..3a4c7ec 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.106 -
====================================
+ 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.
diff --git a/test/shell/lvconvert-thin-external.sh b/test/shell/lvconvert-thin-external.sh
index d9d4d19..53758fc 100644
--- a/test/shell/lvconvert-thin-external.sh
+++ b/test/shell/lvconvert-thin-external.sh
@@ -56,6 +56,10 @@ lvremove -f $vg/pool1
# create plain LV (will be used for external origin)
lvcreate -L8M -n $lv1 $vg
+# 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
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 87eb643..ffbf768 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -2582,6 +2582,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.",
10 years, 2 months
master - tests: check for mkfs
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=bc5f40ee1c7c40...
Commit: bc5f40ee1c7c409c17f85a55f6a8b2606067e76e
Parent: c0bd436dcb45849aff2e953432e5b40e55e0f712
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Jan 28 09:54:22 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Tue Jan 28 10:40:08 2014 +0100
tests: check for mkfs
Test mkfs.ext3 presence for test.
Test also on singlenode cluster.
Speed up a bit slowed down device.
---
test/shell/lock-parallel.sh | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/test/shell/lock-parallel.sh b/test/shell/lock-parallel.sh
index f8e72c3..4820129 100644
--- a/test/shell/lock-parallel.sh
+++ b/test/shell/lock-parallel.sh
@@ -14,19 +14,20 @@
. lib/test
+which mkfs.ext3 || skip
+
aux prepare_vg
-test -e LOCAL_CLVMD && skip
lvcreate -L10 -n $lv1 $vg
lvcreate -l1 -n $lv2 $vg
-mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mkfs.ext3 "$DM_DEV_DIR/$vg/$lv1"
# Slowdown PV for resized LV
-aux delay_dev "$dev1" 40 40
+aux delay_dev "$dev1" 20 20
lvresize -L-5 -r $vg/$lv1 &
-# Let's wait till resize start
+# Let's wait till resize starts
sleep 2
lvremove -f $vg/$lv2
10 years, 2 months
master - thin: disable extension of reduced thin with etx.origin
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=c0bd436dcb4584...
Commit: c0bd436dcb45849aff2e953432e5b40e55e0f712
Parent: 7786443530915505e17fcc42f0c750cb81cdc522
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Jan 28 10:24:50 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Tue Jan 28 10:40:08 2014 +0100
thin: disable extension of reduced thin with etx.origin
Since we are currently incapable of providing zeroes for
reextended thin volume area, let's disable extension of
such already reduce thin volumes.
(in-release change)
---
lib/metadata/lv_manip.c | 28 +++++++++++++++++++-------
test/shell/lvresize-thin-external-origin.sh | 6 ++--
2 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index c875b69..2e240fc 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -2452,14 +2452,6 @@ int lv_add_virtual_segment(struct logical_volume *lv, uint64_t status,
lv->le_count += extents;
lv->size += (uint64_t) extents *lv->vg->extent_size;
- /* Validate thin target supports bigger size of thin volume then external origin */
- if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv &&
- 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;
}
@@ -4036,6 +4028,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;
}
diff --git a/test/shell/lvresize-thin-external-origin.sh b/test/shell/lvresize-thin-external-origin.sh
index d9739c0..3499196 100644
--- a/test/shell/lvresize-thin-external-origin.sh
+++ b/test/shell/lvresize-thin-external-origin.sh
@@ -37,6 +37,6 @@ not lvresize -L+10 $vg/$lv1
# But reduction works
lvresize -L-5 -f $vg/$lv1
not lvresize -L+15 -y $vg/$lv1
-# We may size again back up to the size of external origin
-# TODO: hmm do we really want this???
-lvresize -L+5 -f $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
10 years, 2 months
master - devices: support zvol
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=77864435309155...
Commit: 7786443530915505e17fcc42f0c750cb81cdc522
Parent: df181cc51e32fb54dac6652574e303e93b51b8bd
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Jan 27 13:13:32 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Tue Jan 28 10:33:29 2014 +0100
devices: support zvol
Support partitions on ZFS zvol.
Requested via https://bugzilla.redhat.com/show_bug.cgi?id=913597
Author: hakimian(a)aha.com
---
WHATS_NEW | 1 +
lib/device/device-types.h | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index f56ad20..ca56623 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.106 -
====================================
+ 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.
diff --git a/lib/device/device-types.h b/lib/device/device-types.h
index d716878..666f7b6 100644
--- a/lib/device/device-types.h
+++ b/lib/device/device-types.h
@@ -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, ""}
};
10 years, 2 months
master - cache: Add DM interface for retrieving a cache's status
by Jonathan Brassow
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=df181cc51e32fb...
Commit: df181cc51e32fb54dac6652574e303e93b51b8bd
Parent: 1ff7e214e0cf0e7ef0280b71ab128e029172a1d9
Author: Jonathan Brassow <jbrassow(a)redhat.com>
AuthorDate: Mon Jan 27 05:30:10 2014 -0600
Committer: Jonathan Brassow <jbrassow(a)redhat.com>
CommitterDate: Mon Jan 27 05:30:42 2014 -0600
cache: Add DM interface for retrieving a cache's status
This patch defines a structure for holding all of the device-mapper
cache target's status information. The associated function provides
an easy way for higher levels (LVM) to consume the information.
This patch finishes the device-mapper interface for the cache and
cachepool segment types (i.e. the cache target).
---
libdm/libdevmapper.h | 35 ++++++++++++-
libdm/libdm-deptree.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 171 insertions(+), 1 deletions(-)
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index ae9a91a..670c5e09 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:
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index d3f6640..32d53be 100644
--- a/libdm/libdm-deptree.c
+++ b/libdm/libdm-deptree.c
@@ -3249,6 +3249,143 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
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;
+}
+
+/*
+ * <metadata block size> <#used metadata blocks>/<#total metadata blocks>
+ * <cache block size> <#used cache blocks>/<#total cache blocks>
+ * <#read hits> <#read misses> <#write hits> <#write misses>
+ * <#demotions> <#promotions> <#dirty> <#features> <features>*
+ * <#core args> <core args>* <policy name> <#policy 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,
10 years, 2 months
master - cache: New 'cache' segment type
by Jonathan Brassow
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=1ff7e214e0cf0e...
Commit: 1ff7e214e0cf0e7ef0280b71ab128e029172a1d9
Parent: 90bbed325544365efa177a9823019c44f5109dbb
Author: Jonathan Brassow <jbrassow(a)redhat.com>
AuthorDate: Mon Jan 27 05:29:35 2014 -0600
Committer: Jonathan Brassow <jbrassow(a)redhat.com>
CommitterDate: Mon Jan 27 05:29:35 2014 -0600
cache: New 'cache' segment type
This patch adds the cache segment type - the second of two necessary
to create cache logical volumes. This segment type references the
cachepool (the small fast device) and the origin (the large slow device);
linking them to create the cache device. The cache device is the
hierarchical device-mapper device that the user ulitmately makes use
of.
The cache segment sources the information necessary to construct the
device-mapper cache target from the origin and cachepool segments to
which it links.
---
lib/cache_segtype/cache.c | 126 +++++++++++++++++++++++++++++++++++++++++
libdm/libdevmapper.h | 22 +++++++
libdm/libdm-deptree.c | 137 +++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 279 insertions(+), 6 deletions(-)
diff --git a/lib/cache_segtype/cache.c b/lib/cache_segtype/cache.c
index 0c60b7e..c12ac2f 100644
--- a/lib/cache_segtype/cache.c
+++ b/lib/cache_segtype/cache.c
@@ -284,6 +284,116 @@ static struct segtype_handler _cache_pool_ops = {
.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;
+ struct logical_volume *data, *metadata, *origin;
+ struct dm_tree_node_cache_params params;
+
+ cache_pool_seg = first_seg(seg->pool_lv);
+ data = seg_lv(cache_pool_seg, 0);
+ metadata = cache_pool_seg->metadata_lv;
+ origin = seg_lv(seg, 0);
+
+ memset(¶ms, 0, sizeof(params));
+
+ params.chunk_size = cache_pool_seg->chunk_size;
+
+ if (!(params.data_uuid = build_dm_uuid(mem, data->lvid.s, NULL)))
+ return_0;
+
+ if (!(params.metadata_uuid = build_dm_uuid(mem, metadata->lvid.s, NULL)))
+ return_0;
+
+ if (!(params.origin_uuid = build_dm_uuid(mem, origin->lvid.s, NULL)))
+ return_0;
+
+ /* Cache features, core args, and policy are stored in the cache_pool */
+ params.feature_flags = cache_pool_seg->feature_flags;
+ params.policy_argc = cache_pool_seg->core_argc;
+ params.policy_argv = cache_pool_seg->core_argv;
+ params.policy_name = cache_pool_seg->policy_name;
+ params.policy_argc = cache_pool_seg->policy_argc;
+ params.policy_argv = cache_pool_seg->policy_argv;
+
+ if (!dm_tree_node_add_cache_target(node, len, ¶ms))
+ 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)
@@ -311,6 +421,22 @@ int init_cache_segtypes(struct cmd_context *cmd,
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/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 3074500..ae9a91a 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -715,6 +715,28 @@ int dm_tree_node_add_raid_target_with_params(struct dm_tree_node *node,
/* Cache feature_flags */
#define DM_CACHE_FEATURE_WRITEBACK 0x00000001
#define DM_CACHE_FEATURE_WRITETHROUGH 0x00000002
+struct dm_tree_node_cache_params {
+ uint32_t version;
+
+ uint32_t chunk_size;
+ uint32_t feature_flags; /* DM_CACHE_FEATURE_* */
+
+ int core_argc;
+ char **core_argv;
+
+ char *policy_name;
+ int policy_argc;
+ char **policy_argv;
+
+ const char *data_uuid;
+ const char *metadata_uuid;
+ const char *origin_uuid;
+ /* 'version == 0' end */
+};
+
+int dm_tree_node_add_cache_target(struct dm_tree_node *node,
+ uint64_t size,
+ struct dm_tree_node_cache_params *p);
/*
* Replicator operation mode
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index 42bb9e7..d3f6640 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 */
+ int core_argc; /* Cache */
+ char **core_argv; /* Cache */
+ char *policy_name; /* Cache */
+ int 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 */
@@ -2262,6 +2270,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 i, pos = 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;
+ EMIT_PARAMS(pos, " %s", metadata);
+
+ /* Cache Dev */
+ if (!_build_dev_string(data, sizeof(origin), seg->pool))
+ return_0;
+ EMIT_PARAMS(pos, " %s", data);
+
+ /* 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", origin);
+
+ /* Chunk size */
+ EMIT_PARAMS(pos, " %u", seg->chunk_size);
+
+ /* Features */
+ feature_count = hweight32(seg->flags);
+ EMIT_PARAMS(pos, " %d", 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, " %d", 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 %d", seg->policy_name, seg->policy_argc);
+ if (seg->policy_argc % 2) {
+ log_error(INTERNAL_ERROR
+ "Cache policy arguments must be in "
+ "<key> <value> 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 +2470,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 +2485,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:
@@ -3045,7 +3122,6 @@ int dm_tree_node_add_raid_target(struct dm_tree_node *node,
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 +3200,55 @@ bad:
return 0;
}
+int dm_tree_node_add_cache_target(struct dm_tree_node *node,
+ uint64_t size,
+ struct dm_tree_node_cache_params *p)
+{
+ 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,
+ p->data_uuid))) {
+ log_error("Missing cache's data uuid, %s",
+ p->data_uuid);
+ return 0;
+ }
+ if (!_link_tree_nodes(node, seg->pool))
+ return_0;
+
+ if (!(seg->metadata = dm_tree_find_node_by_uuid(node->dtree,
+ p->metadata_uuid))) {
+ log_error("Missing cache's metadata uuid, %s",
+ p->metadata_uuid);
+ return 0;
+ }
+ if (!_link_tree_nodes(node, seg->metadata))
+ return_0;
+
+ seg->chunk_size = p->chunk_size;
+
+ seg->flags = p->feature_flags;
+
+ seg->core_argc = p->core_argc;
+ seg->core_argv = p->core_argv;
+
+ seg->policy_name = p->policy_name;
+ seg->policy_argc = p->policy_argc;
+ seg->policy_argv = p->policy_argv;
+
+ return 1;
+}
+
int dm_tree_node_add_replicator_target(struct dm_tree_node *node,
uint64_t size,
const char *rlog_uuid,
10 years, 2 months
master - cache: New 'cachepool' segment type
by Jonathan Brassow
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=90bbed32554436...
Commit: 90bbed325544365efa177a9823019c44f5109dbb
Parent: 94377dfd5ee7bbbdeb8836eeeea2198bc32c07f5
Author: Jonathan Brassow <jbrassow(a)redhat.com>
AuthorDate: Mon Jan 27 05:27:16 2014 -0600
Committer: Jonathan Brassow <jbrassow(a)redhat.com>
CommitterDate: Mon Jan 27 05:27:16 2014 -0600
cache: New 'cachepool' segment type
This patch adds the new cachepool segment type - the first of two
necessary to eventually create 'cache' logical volumes. In addition
to the new segment type, updates to makefiles, configure files, the
lv_segment struct, and some necessary libdevmapper flags.
The cachepool is the LV and corresponding segment type that will hold
all information pertinent to the cache itself - it's size, cachemode,
cache policy, core arguments (like migration_threshold), etc.
---
configure | 32 ++++-
configure.in | 22 +++
lib/Makefile.in | 11 +-
lib/cache_segtype/.exported_symbols | 1 +
lib/cache_segtype/Makefile.in | 24 +++
lib/cache_segtype/cache.c | 316 +++++++++++++++++++++++++++++++++++
lib/commands/toolcontext.c | 9 +-
lib/metadata/metadata-exported.h | 7 +
lib/metadata/segtype.h | 10 +
lib/misc/configure.h.in | 3 +
libdm/libdevmapper.h | 4 +
11 files changed, 435 insertions(+), 4 deletions(-)
diff --git a/configure b/configure
index a156460..20d99dd 100755
--- a/configure
+++ b/configure
@@ -606,6 +606,7 @@ kernelvsn
missingkernel
kerneldir
interface
+CACHE
CMIRRORD_PIDFILE
CLVMD_PIDFILE
LVMETAD_PIDFILE
@@ -839,6 +840,7 @@ with_thin
with_thin_check
with_thin_dump
with_thin_repair
+with_cache
enable_readline
enable_realtime
enable_ocf
@@ -1615,6 +1617,7 @@ Optional Packages:
--with-mirrors=TYPE mirror support: internal/shared/none
[[TYPE=internal]]
--with-raid=TYPE raid support: internal/shared/none [[TYPE=internal]]
+ --with-cache=TYPE cache support: internal/shared/none [[TYPE=internal]]
--with-replicators=TYPE replicator support: internal/shared/none
[[TYPE=none]]
--with-thin=TYPE thin provisioning support: internal/shared/none
@@ -7117,6 +7120,31 @@ $as_echo "#define RAID_INTERNAL 1" >>confdefs.h
fi
################################################################################
+{ $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=internal
+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 include replicators" >&5
$as_echo_n "checking whether to include replicators... " >&6; }
@@ -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
@@ -11424,7 +11453,7 @@ 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/cache_segtype/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.s
h 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"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -12140,6 +12169,7 @@ do
"lib/replicator/Makefile") CONFIG_FILES="$CONFIG_FILES lib/replicator/Makefile" ;;
"lib/misc/lvm-version.h") CONFIG_FILES="$CONFIG_FILES lib/misc/lvm-version.h" ;;
"lib/raid/Makefile") CONFIG_FILES="$CONFIG_FILES lib/raid/Makefile" ;;
+ "lib/cache_segtype/Makefile") CONFIG_FILES="$CONFIG_FILES lib/cache_segtype/Makefile" ;;
"lib/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;;
"lib/thin/Makefile") CONFIG_FILES="$CONFIG_FILES lib/thin/Makefile" ;;
"libdaemon/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/Makefile" ;;
diff --git a/configure.in b/configure.in
index 3e0e508..7b56b13 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=internal]]]),
+ CACHE=$withval, CACHE=internal)
+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
diff --git a/lib/Makefile.in b/lib/Makefile.in
index c3ace5f..3808269 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 \
@@ -165,6 +169,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 \
@@ -199,6 +207,7 @@ ifeq ($(MAKECMDGOALS),distclean)
raid \
replicator \
thin \
+ cache_segtype \
locking
endif
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..0c60b7e
--- /dev/null
+++ b/lib/cache_segtype/cache.c
@@ -0,0 +1,316 @@
+/*
+ * 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 "text_import.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 = "[<key> <value>]..."
+ *
+ * '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_int(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)) ||
+ (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_name>"
+ * policy_argc = <# args>
+ * policy_argv = "[<key> <value>]..."
+ *
+ * '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_int(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)) ||
+ (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)
+{
+ int 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 = %d", 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 = %d", 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)))
+{
+ static int _cache_checked = 0;
+ static int _cache_present = 0;
+
+ if (!_cache_checked)
+ _cache_present = target_present(cmd, "cache", 1);
+
+ _cache_checked = 1;
+
+ 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,
+};
+
+#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);
+
+ 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/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 2f1f9ec..bdf5c9d 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -385,6 +385,13 @@ struct lv_segment {
struct logical_volume *pool_lv; /* For thin */
uint32_t device_id; /* For thin, 24bit */
+ uint32_t feature_flags; /* For cache */
+ int core_argc; /* For cache */
+ char **core_argv; /* For cache */
+ char *policy_name; /* For cache */
+ int 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 */
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/misc/configure.h.in b/lib/misc/configure.h.in
index 4e9ffd1..0acb9b7 100644
--- a/lib/misc/configure.h.in
+++ b/lib/misc/configure.h.in
@@ -558,6 +558,9 @@
/* The path to 'thin_repair', if available. */
#undef THIN_REPAIR_CMD
+/* Define to 1 to include built-in support for cache[pool] segment types. */
+#undef CACHE_INTERNAL
+
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 3bf8bd6..3074500 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -712,6 +712,10 @@ 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
+
/*
* Replicator operation mode
* Note: API for Replicator is not yet stable
10 years, 2 months