master - cache: use LV_PENDING_DELETE
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=f5e265a07fb3e0...
Commit: f5e265a07fb3e083416d9f5cf17bd601a1e3f782
Parent: f6932bfcf91cd317629d9c04007a495f2c05ae26
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Nov 10 10:56:43 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Nov 10 22:05:49 2014 +0100
cache: use LV_PENDING_DELETE
---
lib/activate/dev_manager.c | 44 ++++++++++++++++++-
lib/cache_segtype/cache.c | 2 +
lib/format_text/flags.c | 1 +
lib/metadata/cache_manip.c | 86 ++++++++++++++++---------------------
lib/metadata/lv.c | 2 +
lib/metadata/lv_manip.c | 12 +++++-
lib/metadata/metadata-exported.h | 5 ++-
lib/misc/lvm-string.c | 1 +
lib/report/report.c | 2 +-
9 files changed, 100 insertions(+), 55 deletions(-)
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index e81c5d3..2c6ed50 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -1941,8 +1941,14 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
}
}
- if (!origin_only && lv_is_cache(lv)) {
- if (!dm->activation) {
+ if (lv_is_cache(lv)) {
+ if (lv_is_pending_delete(lv)) {
+ if (!_add_lv_to_dtree(dm, dtree, first_seg(lv)->pool_lv, 1)) /* stack */
+ return_0;
+ /* Orhan cache LV exits here */
+ return 1;
+ }
+ if (!origin_only && !dm->activation) {
/* Setup callback for non-activation partial tree */
/* Activation gets own callback when needed */
/* TODO: extend _cached_dm_info() to return dnode */
@@ -1972,6 +1978,14 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
dm->track_pvmove_deps = 1;
}
+ dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
+ if (lv_is_pending_delete(sl->seg->lv) && lv_is_cache(sl->seg->lv)) {
+ if (!_add_lv_to_dtree(dm, dtree, sl->seg->lv, origin_only))
+ return_0;
+ break;
+ }
+ }
+
/* Adding LV head of replicator adds all other related devs */
if (lv_is_replicator_dev(lv) &&
!_add_partial_replicator_to_dtree(dm, dtree, lv))
@@ -2652,6 +2666,30 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
/* Create table */
dm->pvmove_mirror_count = 0u;
+ if (lv_is_pending_delete(lv)) {
+ /* Handle LVs with pending delete */
+ if (lv_is_cache(lv)) {
+ /* Use 'error' for cache, metadata and data volumes */
+ seg = first_seg(lv);
+ if (!dm_tree_node_add_error_target(dnode, seg_lv(seg, 0)->size))
+ return_0;
+ seg = first_seg(seg->pool_lv);
+ if (!(dlid = build_dm_uuid(dm->mem, seg->metadata_lv, NULL)))
+ return_0;
+ if ((dnode = dm_tree_find_node_by_uuid(dtree, dlid)) &&
+ !dm_tree_node_get_context(dnode) &&
+ !dm_tree_node_add_error_target(dnode, seg->metadata_lv->size))
+ return_0;
+ if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, 0), NULL)))
+ return_0;
+ if ((dnode = dm_tree_find_node_by_uuid(dtree, dlid)) &&
+ !dm_tree_node_get_context(dnode) &&
+ !dm_tree_node_add_error_target(dnode, seg_lv(seg, 0)->size))
+ return_0;
+ }
+ return 1;
+ }
+
/* This is unused cache-pool - make metadata accessible */
if (lv_is_cache_pool(lv))
lv = first_seg(lv)->metadata_lv;
@@ -2848,7 +2886,7 @@ static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root, char *
}
/* Not meant to be top level? */
- if (!*layer)
+ if (!*layer && (!(layer = strchr(uuid + 4, '-')) || strstr(layer, "-pool") || strstr(layer, "-tpool")))
continue;
/* If operation was performed on a partial tree, don't remove it */
diff --git a/lib/cache_segtype/cache.c b/lib/cache_segtype/cache.c
index 6dcbf42..c53eb23 100644
--- a/lib/cache_segtype/cache.c
+++ b/lib/cache_segtype/cache.c
@@ -227,6 +227,8 @@ static int _cache_text_import(struct lv_segment *seg,
!dm_config_get_uint32(sn, "cleaner", &seg->cleaner_policy))
return SEG_LOG_ERROR("Could not read cache cleaner in");
+ seg->lv->status |= strstr(seg->lv->name, "_corig") ? LV_PENDING_DELETE : 0;
+
if (!attach_pool_lv(seg, pool_lv, NULL, NULL))
return_0;
diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c
index 55681d4..21555d6 100644
--- a/lib/format_text/flags.c
+++ b/lib/format_text/flags.c
@@ -88,6 +88,7 @@ static const struct flag _lv_flags[] = {
{CACHE_POOL, NULL, 0},
{CACHE_POOL_DATA, NULL, 0},
{CACHE_POOL_METADATA, NULL, 0},
+ {LV_PENDING_DELETE, NULL, 0}, /* TODO: print as COMPATIBLE_FLAG */
{0, NULL, 0}
};
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index b94b867..e50b796 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -21,6 +21,7 @@
#include "segtype.h"
#include "activate.h"
#include "defaults.h"
+#include "lv_alloc.h"
/* https://github.com/jthornber/thin-provisioning-tools/blob/master/caching/... */
#define DM_TRANSACTION_OVERHEAD 4096 /* KiB */
@@ -220,29 +221,6 @@ struct logical_volume *lv_cache_create(struct logical_volume *pool_lv,
}
/*
- * Cleanup orphan device in the table with temporary activation
- * since in the suspend() we can't deactivate unused nodes
- * and the resume() phase mishandles orphan nodes.
- *
- * TODO: improve libdm to handle this case automatically
- */
-static int _cleanup_orphan_lv(struct logical_volume *lv)
-{
- lv->status |= LV_TEMPORARY;
- if (!activate_lv(lv->vg->cmd, lv)) {
- log_error("Failed to activate temporary %s", lv->name);
- return 0;
- }
- if (!deactivate_lv(lv->vg->cmd, lv)) {
- log_error("Failed to deactivate temporary %s", lv->name);
- return 0;
- }
- lv->status &= ~LV_TEMPORARY;
-
- return 1;
-}
-
-/*
* lv_cache_remove
* @cache_lv
*
@@ -268,6 +246,9 @@ int lv_cache_remove(struct logical_volume *cache_lv)
return 0;
}
+ if (lv_is_pending_delete(cache_lv))
+ goto remove; /* Already dropped */
+
/* Localy active volume is needed for writeback */
if (!lv_is_active_locally(cache_lv)) {
/* Give up any remote locks */
@@ -348,43 +329,50 @@ int lv_cache_remove(struct logical_volume *cache_lv)
if (!detach_pool_lv(cache_seg))
return_0;
- /* Regular LV which user may remove if there are problems */
+ /*
+ * Drop layer from cache LV and make _corigin to appear again as regular LV
+ * And use 'existing' _corigin volume to keep reference on cache-pool
+ * This way we still have a way to reference _corigin in dm table and we
+ * know it's been 'cache' LV and we can drop all needed table entries via
+ * activation and deactivation of it.
+ *
+ * This 'cache' LV without origin is temporary LV, which still could be
+ * easily operated by lvm2 commands - it could be activate/deactivated/removed.
+ * However in the dm-table it will use 'error' target for _corigin volume.
+ */
corigin_lv = seg_lv(cache_seg, 0);
lv_set_visible(corigin_lv);
if (!remove_layer_from_lv(cache_lv, corigin_lv))
return_0;
- if (!lv_update_and_reload(cache_lv))
+ /* Replace 'error' with 'cache' segtype */
+ cache_seg = first_seg(corigin_lv);
+ if (!(cache_seg->segtype = get_segtype_from_string(corigin_lv->vg->cmd, "cache")))
return_0;
- /*
- * suspend_lv on this cache LV suspends all components:
- * - the top-level cache LV
- * - the origin
- * - the cache_pool _cdata and _cmeta
- *
- * resume_lv on this (former) cache LV will resume all
- *
- * FIXME: currently we can't easily avoid execution of
- * blkid on resumed error device
- */
+ if (!(cache_seg->areas = dm_pool_zalloc(cache_lv->vg->vgmem, sizeof(*cache_seg->areas))))
+ return_0;
+ if (!set_lv_segment_area_lv(cache_seg, 0, cache_lv, 0, 0))
+ return_0;
- /*
- * cleanup orphan devices
- *
- * FIXME:
- * fix _add_dev() to support this case better
- * since that should be handled internally by resume_lv()
- * which should autoremove any orphans
- */
- if (!_cleanup_orphan_lv(corigin_lv)) /* _corig */
+ cache_seg->area_count = 1;
+ corigin_lv->le_count = cache_lv->le_count;
+ corigin_lv->size = cache_lv->size;
+ corigin_lv->status |= LV_PENDING_DELETE;
+
+ /* Reattach cache pool */
+ if (!attach_pool_lv(cache_seg, cache_pool_lv, NULL, NULL))
return_0;
- if (!_cleanup_orphan_lv(seg_lv(first_seg(cache_pool_lv), 0))) /* _cdata */
+
+ /* Suspend/resume also deactivates deleted LV via support of LV_PENDING_DELETE */
+ if (!lv_update_and_reload(cache_lv))
return_0;
- if (!_cleanup_orphan_lv(first_seg(cache_pool_lv)->metadata_lv)) /* _cmeta */
+ cache_lv = corigin_lv;
+remove:
+ if (!detach_pool_lv(cache_seg))
return_0;
- if (!lv_remove(corigin_lv))
+ if (!lv_remove(cache_lv)) /* Will use LV_PENDING_DELETE */
return_0;
return 1;
@@ -400,7 +388,7 @@ int lv_is_cache_origin(const struct logical_volume *lv)
return 0;
seg = get_only_segment_using_this_lv(lv);
- return seg && lv_is_cache(seg->lv) && (seg_lv(seg, 0) == lv);
+ return seg && lv_is_cache(seg->lv) && !lv_is_pending_delete(seg->lv) && (seg_lv(seg, 0) == lv);
}
/*
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index 4ee751c..85076fa 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -990,6 +990,8 @@ const struct logical_volume *lv_lock_holder(const struct logical_volume *lv)
if (lv_is_external_origin(lv) &&
lv_is_thin_volume(sl->seg->lv))
continue; /* Skip external origin */
+ if (lv_is_pending_delete(sl->seg->lv))
+ continue; /* Skip deleted LVs */
return lv_lock_holder(sl->seg->lv);
}
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index d664453..30944c1 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -1280,7 +1280,8 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
return_0;
/* Remove cache origin only when removing (not on lv_empty()) */
- if (delete && seg_is_cache(seg) && !lv_remove(seg_lv(seg, 0)))
+ if (delete && seg_is_cache(seg) &&
+ !lv_is_pending_delete(seg->lv) && !lv_remove(seg_lv(seg, 0)))
return_0;
if ((pool_lv = seg->pool_lv)) {
@@ -5322,6 +5323,7 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
struct lv_segment *cache_seg = NULL;
int ask_discard;
struct lv_list *lvl;
+ struct seg_list *sl;
int is_last_pool;
vg = lv->vg;
@@ -5420,6 +5422,14 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
if (!archive(vg))
return 0;
+ /* When referenced by the LV with pending delete flag, remove this deleted LV first */
+ dm_list_iterate_items(sl, &lv->segs_using_this_lv)
+ if (lv_is_pending_delete(sl->seg->lv) && !lv_remove(sl->seg->lv)) {
+ log_error("Error releasing logical volume %s with pending delete.",
+ display_lvname(sl->seg->lv));
+ return 0;
+ }
+
if (lv_is_cow(lv)) {
/* Old format1 code */
if (!(lv->vg->fid->fmt->features & FMT_MDAS))
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 5acc511..0ba1ed5 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -117,7 +117,9 @@
#define CACHE_POOL_METADATA UINT64_C(0x0000800000000000) /* LV - Internal use only */
#define CACHE UINT64_C(0x0001000000000000) /* LV - Internal use only */
-/* Next unused flag: UINT64_C(0x0004000000000000) */
+#define LV_PENDING_DELETE UINT64_C(0x0004000000000000) /* LV - Internal use only */
+
+/* Next unused flag: UINT64_C(0x0008000000000000) */
/* Format features flags */
#define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */
@@ -188,6 +190,7 @@
#define lv_is_mirror(lv) (((lv)->status & MIRROR) ? 1 : 0)
#define lv_is_mirror_type(lv) (((lv)->status & (MIRROR | MIRROR_LOG | MIRROR_IMAGE)) ? 1 : 0)
+#define lv_is_pending_delete(lv) (((lv)->status & LV_PENDING_DELETE) ? 1 : 0)
#define lv_is_pvmove(lv) (((lv)->status & PVMOVE) ? 1 : 0)
#define lv_is_raid(lv) (((lv)->status & RAID) ? 1 : 0)
diff --git a/lib/misc/lvm-string.c b/lib/misc/lvm-string.c
index 0101af9..4ed1b28 100644
--- a/lib/misc/lvm-string.c
+++ b/lib/misc/lvm-string.c
@@ -188,6 +188,7 @@ char *build_dm_uuid(struct dm_pool *mem, const struct logical_volume *lv,
*/
/* Suffixes used here MUST match lib/activate/dev_manager.c */
layer = lv_is_cache_origin(lv) ? "real" :
+ (lv_is_cache(lv) && lv_is_pending_delete(lv)) ? "real" :
lv_is_cache_pool_data(lv) ? "cdata" :
lv_is_cache_pool_metadata(lv) ? "cmeta" :
// FIXME: dm-tree needs fixes for mirrors/raids
diff --git a/lib/report/report.c b/lib/report/report.c
index 262b376..e6df787 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -518,7 +518,7 @@ static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
if (lv_is_cow(lv))
return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
- if (lv_is_cache(lv))
+ if (lv_is_cache(lv) && !lv_is_pending_delete(lv))
return _lvname_disp(rh, mem, field, seg_lv(seg, 0), private);
if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
9 years, 6 months
master - cache: _corig has UUID suffix
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=f6932bfcf91cd3...
Commit: f6932bfcf91cd317629d9c04007a495f2c05ae26
Parent: 6effcb16fcc912bdca250b45442b783ebe75c481
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Nov 4 23:19:34 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Nov 10 22:05:49 2014 +0100
cache: _corig has UUID suffix
Use -real suffix for cache origin device.
---
lib/misc/lvm-string.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/lib/misc/lvm-string.c b/lib/misc/lvm-string.c
index ae4adbe..0101af9 100644
--- a/lib/misc/lvm-string.c
+++ b/lib/misc/lvm-string.c
@@ -187,7 +187,8 @@ char *build_dm_uuid(struct dm_pool *mem, const struct logical_volume *lv,
* Should also make internal detection simpler.
*/
/* Suffixes used here MUST match lib/activate/dev_manager.c */
- layer = lv_is_cache_pool_data(lv) ? "cdata" :
+ layer = lv_is_cache_origin(lv) ? "real" :
+ lv_is_cache_pool_data(lv) ? "cdata" :
lv_is_cache_pool_metadata(lv) ? "cmeta" :
// FIXME: dm-tree needs fixes for mirrors/raids
//lv_is_mirror_image(lv) ? "mimage" :
9 years, 6 months
master - cache: option
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=6effcb16fcc912...
Commit: 6effcb16fcc912bdca250b45442b783ebe75c481
Parent: c5c2665a213332904836ad90e2f90dd72b6db4c5
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Nov 10 10:07:41 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Nov 10 22:05:49 2014 +0100
cache: option
---
lib/metadata/cache_manip.c | 30 ++++++++++++++++++++++++++----
1 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index cce2911..b94b867 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -268,8 +268,27 @@ int lv_cache_remove(struct logical_volume *cache_lv)
return 0;
}
- /* Localy active volume is needed (writeback only?) */
+ /* Localy active volume is needed for writeback */
if (!lv_is_active_locally(cache_lv)) {
+ /* Give up any remote locks */
+ if (!deactivate_lv(cache_lv->vg->cmd, cache_lv)) {
+ log_error("Cannot deactivate remotely active cache lv.");
+ return 0;
+ }
+ /* For inactive writethrough just drop cache layer */
+ if (first_seg(cache_seg->pool_lv)->feature_flags &
+ DM_CACHE_FEATURE_WRITETHROUGH) {
+ corigin_lv = seg_lv(cache_seg, 0);
+ if (!detach_pool_lv(cache_seg))
+ return_0;
+ if (!remove_layer_from_lv(cache_lv, corigin_lv))
+ return_0;
+ if (!lv_remove(corigin_lv))
+ return_0;
+ return 1;
+ }
+
+ /* Otherwise localy active volume is need to sync dirty blocks */
cache_lv->status |= LV_TEMPORARY;
if (!activate_lv_excl_local(cache_lv->vg->cmd, cache_lv) ||
!lv_is_active_locally(cache_lv)) {
@@ -297,10 +316,13 @@ int lv_cache_remove(struct logical_volume *cache_lv)
*/
if (!lv_cache_status(cache_lv, &status))
return_0;
+ dirty_blocks = status->cache->dirty_blocks;
+ if (!(status->cache->feature_flags & DM_CACHE_FEATURE_WRITETHROUGH))
+ dirty_blocks++; /* Not writethrough - always dirty */
is_cleaner = !strcmp(status->cache->policy_name, "cleaner");
dm_pool_destroy(status->mem);
- if (!is_cleaner) {
+ if (dirty_blocks && !is_cleaner) {
/* Switch to cleaner policy to flush the cache */
log_print_unless_silent("Flushing cache for %s.", cache_lv->name);
cache_seg->cleaner_policy = 1;
@@ -310,7 +332,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
}
//FIXME: use polling to do this...
- do {
+ while (dirty_blocks) {
if (!lv_cache_status(cache_lv, &status))
return_0;
dirty_blocks = status->cache->dirty_blocks;
@@ -320,7 +342,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
dirty_blocks);
sleep(1);
}
- } while (dirty_blocks);
+ }
cache_pool_lv = cache_seg->pool_lv;
if (!detach_pool_lv(cache_seg))
9 years, 6 months
master - man: _corig is reserved
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=c5c2665a213332...
Commit: c5c2665a213332904836ad90e2f90dd72b6db4c5
Parent: 3e230a8ad80c0c2f48c04979405fe2897f7ef769
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Nov 8 13:16:35 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Nov 10 22:05:49 2014 +0100
man: _corig is reserved
---
WHATS_NEW | 1 +
lib/misc/lvm-string.c | 1 +
man/lvm.8.in | 2 +-
3 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 616d1b0..0b5d892 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.112 -
=====================================
+ Add _corig as reserved suffix.
Reduce vg write and vg commits when creating spare volumes.
When remove_layer_from_lv() removes layer, restore subLV names.
Cache-pool in use becomes invisible LV.
diff --git a/lib/misc/lvm-string.c b/lib/misc/lvm-string.c
index 84c8708..ae4adbe 100644
--- a/lib/misc/lvm-string.c
+++ b/lib/misc/lvm-string.c
@@ -121,6 +121,7 @@ static const char *_lvname_has_reserved_string(const char *lvname)
static const char _strings[][12] = {
"_cdata",
"_cmeta",
+ "_corig",
"_mimage",
"_mlog",
"_pmspare",
diff --git a/man/lvm.8.in b/man/lvm.8.in
index c6f72a3..7b95e2b 100644
--- a/man/lvm.8.in
+++ b/man/lvm.8.in
@@ -346,7 +346,7 @@ VG and LV names cannot begin with a hyphen.
There are also various reserved names that are used internally by lvm that can not be used as LV or VG names.
A VG cannot be called anything that exists in /dev/ at the time of creation, nor can it be called '.' or '..'.
An LV cannot be called '.', '..', 'snapshot' or 'pvmove'. The LV name may also not contain any of the following
-strings: '_cdata', '_cmeta', '_mlog', '_mimage', '_pmspare', '_rimage', '_rlog', '_tdata' or '_tmeta'.
+strings: '_cdata', '_cmeta', '_corig', '_mlog', '_mimage', '_pmspare', '_rimage', '_rlog', '_tdata' or '_tmeta'.
A directory bearing the name of each Volume Group is created under /dev when any of its Logical Volumes are activated.
Each active Logical Volume is accessible from this directory as a symbolic link leading to a device node.
Links or nodes in /dev/mapper are intended only for internal use and the precise format and escaping might change between releases and distributions.
9 years, 6 months
master - cache: new API for libdm
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=3e230a8ad80c0c...
Commit: 3e230a8ad80c0c2f48c04979405fe2897f7ef769
Parent: 824019531cbba02c722cb0bf0957ac84eccef3b9
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sun Nov 9 20:18:00 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Nov 10 22:05:49 2014 +0100
cache: new API for libdm
---
lib/cache_segtype/cache.c | 130 +++++++++++--------------------------
lib/metadata/cache_manip.c | 14 +---
lib/metadata/metadata-exported.h | 13 ++---
tools/lvconvert.c | 2 +-
4 files changed, 48 insertions(+), 111 deletions(-)
diff --git a/lib/cache_segtype/cache.c b/lib/cache_segtype/cache.c
index ea480de..6dcbf42 100644
--- a/lib/cache_segtype/cache.c
+++ b/lib/cache_segtype/cache.c
@@ -38,8 +38,7 @@ static int _cache_pool_text_import(struct lv_segment *seg,
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?
+ struct dm_pool *mem = seg->lv->vg->vgmem;
if (!dm_config_has_node(sn, "data"))
return SEG_LOG_ERROR("Cache data not specified in");
@@ -62,7 +61,7 @@ static int _cache_pool_text_import(struct lv_segment *seg,
/*
* Read in features:
- * cache_mode = {writethrough|writeback}
+ * cache_mode = {passthrough|writethrough|writeback}
*
* 'cache_mode' does not have to be present.
*/
@@ -74,76 +73,30 @@ static int _cache_pool_text_import(struct lv_segment *seg,
}
/*
- * Read in core arguments (these are key/value pairs)
- * core_argc = <# args>
- * core_argv = "[<key> <value>]..."
+ * Read in policy args:
+ * mq {
+ * migration_threshold=2048
+ * sequention_threashold=100
+ * random_threashold=200
+ * read_promote_adjustment=10
+ * write_promote_adjustment=20
+ * discard_promote_adjustment=40
*
- * '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, (char **) 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>]..."
+ * <key> = <value>
+ * <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 the policy is not present, default policy is used.
*/
- 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, (char **) seg->policy_argv))))
- return SEG_LOG_ERROR("policy_argc and policy_argv do"
- " not match in");
- }
+ for (; sn; sn = sn->sib)
+ if (!sn->v) {
+ if (seg->policy_args)
+ return SEG_LOG_ERROR("only a singly policy is supported for");
+
+ if (!(seg->policy_args = dm_config_clone_node_with_mem(mem, sn, 0)))
+ return_0;
+ }
if (!attach_pool_data_lv(seg, data_lv))
return_0;
@@ -165,8 +118,6 @@ static int _cache_pool_text_import_area_count(const struct dm_config_node *sn,
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?!?
const char *cache_mode;
if (!(cache_mode = get_cache_pool_cachemode_name(seg)))
@@ -177,22 +128,8 @@ static int _cache_pool_text_export(const struct lv_segment *seg,
outf(f, "chunk_size = %" PRIu32, seg->chunk_size);
outf(f, "cache_mode = \"%s\"", cache_mode);
- 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);
- }
+ if (seg->policy_args)
+ out_config_node(f, seg->policy_args);
return 1;
}
@@ -284,6 +221,12 @@ static int _cache_text_import(struct lv_segment *seg,
if (!set_lv_segment_area_lv(seg, 0, origin_lv, 0, 0))
return_0;
+
+ seg->cleaner_policy = 0;
+ if (dm_config_has_node(sn, "cleaner") &&
+ !dm_config_get_uint32(sn, "cleaner", &seg->cleaner_policy))
+ return SEG_LOG_ERROR("Could not read cache cleaner in");
+
if (!attach_pool_lv(seg, pool_lv, NULL, NULL))
return_0;
@@ -306,6 +249,9 @@ static int _cache_text_export(const struct lv_segment *seg, struct formatter *f)
outf(f, "cache_pool = \"%s\"", seg->pool_lv->name);
outf(f, "origin = \"%s\"", seg_lv(seg, 0)->name);
+ if (seg->cleaner_policy)
+ outf(f, "cleaner = 1");
+
return 1;
}
@@ -321,6 +267,8 @@ 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;
+ const char *policy_name = seg->cleaner_policy ? "cleaner" :
+ cache_pool_seg->policy_args ? cache_pool_seg->policy_args->key : NULL;
if (!(metadata_uuid = build_dm_uuid(mem, cache_pool_seg->metadata_lv, NULL)))
return_0;
@@ -336,12 +284,12 @@ static int _cache_add_target_line(struct dev_manager *dm,
metadata_uuid,
data_uuid,
origin_uuid,
- NULL,
- cache_pool_seg->policy_name,
+ seg->cleaner_policy ? NULL : cache_pool_seg->policy_args,
+ policy_name,
cache_pool_seg->chunk_size))
return_0;
- return add_areas_line(dm, seg, node, 0u, seg->area_count);
+ return 1;
}
#endif /* DEVMAPPER_SUPPORT */
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index 69a51ef..cce2911 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -301,19 +301,11 @@ int lv_cache_remove(struct logical_volume *cache_lv)
dm_pool_destroy(status->mem);
if (!is_cleaner) {
- /* We must swap in the cleaner to flush the cache */
+ /* Switch to cleaner policy to flush the cache */
log_print_unless_silent("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 = "cleaner";
- cache_seg->policy_argc = 0;
- cache_seg->policy_argv = NULL;
-
+ cache_seg->cleaner_policy = 1;
/* update the kernel to put the cleaner policy in place */
- if (!lv_update_and_reload(cache_lv))
+ if (!lv_update_and_reload_origin(cache_lv))
return_0;
}
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 4c15fee..5acc511 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -425,15 +425,12 @@ struct lv_segment {
thin_discards_t discards; /* For thin_pool */
struct dm_list thin_messages; /* For thin_pool */
struct logical_volume *external_lv; /* For thin */
- struct logical_volume *pool_lv; /* For thin */
+ struct logical_volume *pool_lv; /* For thin, cache */
uint32_t device_id; /* For thin, 24bit */
- uint32_t feature_flags; /* For cache */
- unsigned core_argc; /* For cache */
- const char **core_argv; /* For cache */
- const char *policy_name; /* For cache */
- unsigned policy_argc; /* For cache */
- const char **policy_argv; /* For cache */
+ uint64_t feature_flags; /* For cache_pool */
+ struct dm_config_node *policy_args; /* For cache_pool (-> policy_name) */
+ unsigned cleaner_policy; /* For cache */
struct logical_volume *replicator;/* For replicator-devs - link to replicator LV */
struct logical_volume *rlog_lv; /* For replicators */
@@ -851,7 +848,7 @@ struct lvcreate_params {
uint32_t min_recovery_rate; /* RAID */
uint32_t max_recovery_rate; /* RAID */
- uint32_t feature_flags; /* cache */
+ uint64_t feature_flags; /* cache */
const struct segment_type *segtype; /* all */
unsigned target_attr; /* all */
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 8b09ee6..d4f3db1 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -48,7 +48,7 @@ struct lvconvert_params {
uint32_t stripes;
uint32_t stripe_size;
uint32_t read_ahead;
- uint32_t feature_flags; /* cache_pool */
+ uint64_t feature_flags; /* cache_pool */
const struct segment_type *segtype;
unsigned target_attr;
9 years, 6 months
master - libdm: tunning cache API
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=824019531cbba0...
Commit: 824019531cbba02c722cb0bf0957ac84eccef3b9
Parent: 3dbcd2a1c9027c08faab726a1f1a24085046f0df
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Nov 8 23:20:25 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Nov 10 22:05:48 2014 +0100
libdm: tunning cache API
Support new PASSTHROUGH 'feature' flag.
Add dm_config_node to pass in policy args.
Really use origin_uuid instead of using extra call
to pass seg_areas.
Switch to 64bit feature flag bit set so there is
enough space in future for new bits...
---
WHATS_NEW_DM | 1 +
lib/cache_segtype/cache.c | 9 +---
libdm/libdevmapper.h | 30 ++++++++++---
libdm/libdm-deptree.c | 103 +++++++++++++++++++++++----------------------
4 files changed, 79 insertions(+), 64 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 0305077..f4148bc 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.91 -
====================================
+ Update API for cache creation and dm_config_node to pass policy.
Allow activation of any thin-pool with passed transaction_id == 0.
Don't print uninitialized stack bytes when non-root uses dm_check_version().
Fix selection criteria to not match reserved values when using >, <, >=, <.
diff --git a/lib/cache_segtype/cache.c b/lib/cache_segtype/cache.c
index e5512bf..ea480de 100644
--- a/lib/cache_segtype/cache.c
+++ b/lib/cache_segtype/cache.c
@@ -332,16 +332,13 @@ static int _cache_add_target_line(struct dev_manager *dm,
return_0;
if (!dm_tree_node_add_cache_target(node, len,
+ cache_pool_seg->feature_flags,
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,
+ NULL,
cache_pool_seg->policy_name,
- cache_pool_seg->policy_argc,
- cache_pool_seg->policy_argv))
+ cache_pool_seg->chunk_size))
return_0;
return add_areas_line(dm, seg, node, 0u, seg->area_count);
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 76c4eee..62a5941 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -320,7 +320,7 @@ struct dm_status_cache {
uint64_t demotions;
uint64_t promotions;
- uint32_t feature_flags;
+ uint64_t feature_flags;
int core_argc;
char **core_argv;
@@ -774,19 +774,35 @@ 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
+#define DM_CACHE_FEATURE_PASSTHROUGH 0x00000004
+struct dm_config_node;
+/*
+ * Use for passing cache policy and all its args e.g.:
+ *
+ * mq {
+ * migration_threshold=2048
+ * sequention_threashold=100
+ * ...
+ * }
+ *
+ * For policy without any parameters simply specify policy_name.
+ */
int dm_tree_node_add_cache_target(struct dm_tree_node *node,
uint64_t size,
+ uint64_t feature_flags, /* DM_CACHE_FEATURE_* */
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,
- const char *const *core_argv,
+ const struct dm_config_node *policy,
const char *policy_name,
- unsigned policy_argc,
- const char *const *policy_argv);
+ uint32_t chunk_size);
+
+/*
+ * TODO: Add individual cache policy pairs <key> = value, like:
+ *int dm_tree_node_add_cache_policy_arg(struct dm_tree_node *dnode,
+ * const char *key, uint64_t value);
+ */
/*
* Replicator operation mode
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index d120bf5..6521360 100644
--- a/libdm/libdm-deptree.c
+++ b/libdm/libdm-deptree.c
@@ -171,11 +171,9 @@ struct load_segment {
uint32_t flags; /* Mirror + raid + Cache */
char *uuid; /* Clustered mirror log */
- unsigned core_argc; /* Cache */
- const char *const *core_argv; /* Cache */
const char *policy_name; /* Cache */
unsigned policy_argc; /* Cache */
- const char *const *policy_argv; /* Cache */
+ struct dm_config_node *policy; /* Cache */
const char *cipher; /* Crypt */
const char *chainmode; /* Crypt */
@@ -2366,25 +2364,23 @@ static int _cache_emit_segment_line(struct dm_task *dmt,
char *params, size_t paramsize)
{
int pos = 0;
- unsigned i = 0;
- unsigned feature_count;
- struct seg_area *area;
+ /* unsigned feature_count; */
char data[DM_FORMAT_DEV_BUFSIZE];
char metadata[DM_FORMAT_DEV_BUFSIZE];
char origin[DM_FORMAT_DEV_BUFSIZE];
+ const char *name;
+ struct dm_config_node *cn;
- /* Metadata Dev */
- if (!_build_dev_string(metadata, sizeof(metadata), seg->metadata))
+ /* Cache Dev */
+ if (!_build_dev_string(data, sizeof(data), seg->pool))
return_0;
- /* Cache Dev */
- if (!_build_dev_string(data, sizeof(origin), seg->pool))
+ /* Metadata Dev */
+ if (!_build_dev_string(metadata, sizeof(metadata), seg->metadata))
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))
+ if (!_build_dev_string(origin, sizeof(origin), seg->origin))
return_0;
EMIT_PARAMS(pos, " %s %s %s", metadata, data, origin);
@@ -2393,34 +2389,24 @@ static int _cache_emit_segment_line(struct dm_task *dmt,
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");
+ /* feature_count = hweight32(seg->flags); */
+ /* EMIT_PARAMS(pos, " %u", feature_count); */
+ if (seg->flags & DM_CACHE_FEATURE_PASSTHROUGH)
+ EMIT_PARAMS(pos, " 1 passthrough");
+ else if (seg->flags & DM_CACHE_FEATURE_WRITETHROUGH)
+ EMIT_PARAMS(pos, " 1 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]);
- }
+ EMIT_PARAMS(pos, " 1 writeback");
/* 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 "
- "<key> <value> pairs");
- return 0;
- }
- for (i = 0; i < seg->policy_argc; i++)
- EMIT_PARAMS(pos, " %s", seg->policy_argv[i]);
- }
+ name = seg->policy_name ? : seg->policy ? seg->policy->key : "default";
+
+ EMIT_PARAMS(pos, " %s", name);
+
+ EMIT_PARAMS(pos, " %u", seg->policy_argc * 2);
+ if (seg->policy)
+ for (cn = seg->policy->child; cn; cn = cn->sib)
+ EMIT_PARAMS(pos, " %s %" PRIu64, cn->key, cn->v->v.i);
return 1;
}
@@ -3313,17 +3299,15 @@ bad:
int dm_tree_node_add_cache_target(struct dm_tree_node *node,
uint64_t size,
+ uint64_t feature_flags, /* DM_CACHE_FEATURE_* */
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,
- const char *const *core_argv,
+ const struct dm_config_node *policy,
const char *policy_name,
- unsigned policy_argc,
- const char *const *policy_argv)
+ uint32_t chunk_size)
{
+ struct dm_config_node *cn;
struct load_segment *seg;
if (!(seg = _add_segment(node, SEG_CACHE, size)))
@@ -3347,18 +3331,35 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
if (!_link_tree_nodes(node, seg->metadata))
return_0;
- seg->chunk_size = chunk_size;
+ if (!(seg->origin = dm_tree_find_node_by_uuid(node->dtree,
+ origin_uuid))) {
+ log_error("Missing cache's origin uuid %s.",
+ metadata_uuid);
+ return 0;
+ }
+ if (!_link_tree_nodes(node, seg->origin))
+ return_0;
+
+ seg->chunk_size = chunk_size;
seg->flags = feature_flags;
+ seg->policy_name = policy_name;
- /* FIXME: validation missing */
+ /* FIXME: better validation missing */
+ if (policy) {
+ if (!(seg->policy = dm_config_clone_node_with_mem(node->dtree->mem, policy, 0)))
+ return_0;
- seg->core_argc = core_argc;
- seg->core_argv = core_argv;
+ for (cn = seg->policy->child; cn; cn = cn->sib) {
+ if (!cn->v || (cn->v->type != DM_CFG_INT)) {
+ /* For now only <key> = <int> pairs are supported */
+ log_error("Cache policy parameter %s is without integer value.", cn->key);
+ return 0;
+ }
+ seg->policy_argc++;
+ }
+ }
- seg->policy_name = policy_name;
- seg->policy_argc = policy_argc;
- seg->policy_argv = policy_argv;
return 1;
}
9 years, 6 months
master - cleanup: cache API get/set
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=3dbcd2a1c9027c...
Commit: 3dbcd2a1c9027c08faab726a1f1a24085046f0df
Parent: 2e0c926d56f93880f4b7a7813cec7c3a774a8280
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sun Nov 9 18:51:56 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Nov 10 22:05:48 2014 +0100
cleanup: cache API get/set
---
lib/cache_segtype/cache.c | 22 +++++---------------
lib/metadata/cache_manip.c | 40 ++++++++++++++++++++++---------------
lib/metadata/metadata-exported.h | 4 +-
3 files changed, 32 insertions(+), 34 deletions(-)
diff --git a/lib/cache_segtype/cache.c b/lib/cache_segtype/cache.c
index dceb3c0..e5512bf 100644
--- a/lib/cache_segtype/cache.c
+++ b/lib/cache_segtype/cache.c
@@ -69,7 +69,7 @@ static int _cache_pool_text_import(struct lv_segment *seg,
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 (!get_cache_mode(str, &seg->feature_flags))
+ if (!set_cache_pool_feature(&seg->feature_flags, str))
return SEG_LOG_ERROR("Unknown cache_mode in");
}
@@ -167,25 +167,15 @@ static int _cache_pool_text_export(const struct lv_segment *seg,
{
unsigned i;
char buf[256]; //FIXME: IS THERE AN 'outf' THAT DOESN'T DO NEWLINE?!?
- uint32_t feature_flags = seg->feature_flags;
+ const char *cache_mode;
+
+ if (!(cache_mode = get_cache_pool_cachemode_name(seg)))
+ return_0;
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;
- }
- }
+ outf(f, "cache_mode = \"%s\"", cache_mode);
if (seg->core_argc) {
outf(f, "core_argc = %u", seg->core_argc);
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index ec7f444..69a51ef 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -28,7 +28,7 @@
#define DM_HINT_OVERHEAD_PER_BLOCK 8 /* bytes */
#define DM_MAX_HINT_WIDTH (4+16) /* bytes, TODO: configurable ?? */
-const char *get_cachepool_cachemode_name(const struct lv_segment *seg)
+const char *get_cache_pool_cachemode_name(const struct lv_segment *seg)
{
if (seg->feature_flags & DM_CACHE_FEATURE_WRITEBACK)
return "writeback";
@@ -36,7 +36,29 @@ const char *get_cachepool_cachemode_name(const struct lv_segment *seg)
if (seg->feature_flags & DM_CACHE_FEATURE_WRITETHROUGH)
return "writethrough";
- return "unknown";
+ if (seg->feature_flags & DM_CACHE_FEATURE_PASSTHROUGH)
+ return "passthrough";
+
+ log_error("LV %s has uknown feature flags %" PRIu64,
+ display_lvname(seg->lv), seg->feature_flags);
+
+ return NULL;
+}
+
+int set_cache_pool_feature(uint64_t *feature_flags, const char *str)
+{
+ if (!strcmp(str, "writeback"))
+ *feature_flags |= DM_CACHE_FEATURE_WRITEBACK;
+ else if (!strcmp(str, "writethrough"))
+ *feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
+ else if (!strcmp(str, "passhrough"))
+ *feature_flags |= DM_CACHE_FEATURE_PASSTHROUGH;
+ else {
+ log_error("Cache pool feature \"%s\" is unknown.", str);
+ return 0;
+ }
+
+ return 1;
}
int update_cache_pool_params(const struct segment_type *segtype,
@@ -354,20 +376,6 @@ int lv_cache_remove(struct logical_volume *cache_lv)
return 1;
}
-int get_cache_mode(const char *str, uint32_t *flags)
-{
- if (!strcmp(str, "writethrough"))
- *flags |= DM_CACHE_FEATURE_WRITETHROUGH;
- else if (!strcmp(str, "writeback"))
- *flags |= DM_CACHE_FEATURE_WRITEBACK;
- else {
- log_error("Cache pool cachemode \"%s\" is unknown.", str);
- return 0;
- }
-
- return 1;
-}
-
int lv_is_cache_origin(const struct logical_volume *lv)
{
struct lv_segment *seg;
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 9afce35..4c15fee 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -1095,7 +1095,8 @@ struct lv_status_cache {
dm_percent_t dirty_usage;
};
-const char *get_cachepool_cachemode_name(const struct lv_segment *seg);
+const char *get_cache_pool_cachemode_name(const struct lv_segment *seg);
+int set_cache_pool_feature(uint64_t *feature_flags, const char *str);
int update_cache_pool_params(const struct segment_type *segtype,
struct volume_group *vg, unsigned attr,
int passed_args, uint32_t pool_data_extents,
@@ -1106,7 +1107,6 @@ int validate_lv_cache_create_origin(const struct logical_volume *origin_lv);
struct logical_volume *lv_cache_create(struct logical_volume *pool,
struct logical_volume *origin);
int lv_cache_remove(struct logical_volume *cache_lv);
-int get_cache_mode(const char *str, uint32_t *flags);
int wipe_cache_pool(struct logical_volume *cache_pool_lv);
/* -- metadata/cache_manip.c */
9 years, 6 months
master - cleanup: API get/set fixes
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=2e0c926d56f938...
Commit: 2e0c926d56f93880f4b7a7813cec7c3a774a8280
Parent: 8d7340b7a191376b94c45503f9c5cbee5f337e85
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Nov 8 01:28:38 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Nov 10 22:05:48 2014 +0100
cleanup: API get/set fixes
---
lib/metadata/lv.c | 2 +-
lib/metadata/metadata-exported.h | 4 ++--
lib/metadata/mirror.c | 4 ++--
lib/metadata/thin_manip.c | 4 ++--
lib/report/report.c | 2 +-
lib/thin/thin.c | 2 +-
tools/lvconvert.c | 2 +-
tools/lvcreate.c | 2 +-
tools/lvmcmdline.c | 4 ++--
9 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index 016f299..4ee751c 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -130,7 +130,7 @@ char *lvseg_discards_dup(struct dm_pool *mem, const struct lv_segment *seg)
char *lvseg_cachemode_dup(struct dm_pool *mem, const struct lv_segment *seg)
{
- return dm_pool_strdup(mem, get_cachepool_cachemode_name(seg));
+ return dm_pool_strdup(mem, get_cache_pool_cachemode_name(seg));
}
#ifdef DMEVENTD
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 713b3b6..9afce35 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -763,8 +763,8 @@ int update_thin_pool_params(const struct segment_type *segtype,
uint32_t *pool_metadata_extents,
int *chunk_size_calc_method, uint32_t *chunk_size,
thin_discards_t *discards, int *zero);
-int get_pool_discards(const char *str, thin_discards_t *discards);
const char *get_pool_discards_name(thin_discards_t discards);
+int set_pool_discards(thin_discards_t *discards, const char *str);
struct logical_volume *alloc_pool_metadata(struct logical_volume *pool_lv,
const char *name, uint32_t read_ahead,
uint32_t stripes, uint32_t stripe_size,
@@ -1011,8 +1011,8 @@ int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
uint32_t mirrors, uint32_t log_count,
int (*is_removable)(struct logical_volume *, void *),
void *removable_baton, uint64_t status_mask);
-int get_mirror_log_count(const char *mirrorlog, int *log_count);
const char *get_mirror_log_name(int log_count);
+int set_mirror_log_count(int *log_count, const char *mirrorlog);
int is_temporary_mirror_layer(const struct logical_volume *lv);
struct logical_volume * find_temporary_mirror(const struct logical_volume *lv);
diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c
index a943ac4..ba3ff6b 100644
--- a/lib/metadata/mirror.c
+++ b/lib/metadata/mirror.c
@@ -2273,7 +2273,7 @@ int lv_remove_mirrors(struct cmd_context *cmd __attribute__((unused)),
return remove_mirrors_from_segments(lv, new_mirrors, status_mask);
}
-int get_mirror_log_count(const char *mirrorlog, int *log_count)
+int set_mirror_log_count(int *log_count, const char *mirrorlog)
{
if (!strcmp("core", mirrorlog))
*log_count = MIRROR_LOG_CORE;
@@ -2297,6 +2297,6 @@ const char *get_mirror_log_name(int log_count)
case MIRROR_LOG_MIRRORED: return "mirrored";
default:
log_error(INTERNAL_ERROR "Unknown mirror log count %d.", log_count);
- return "unknown";
+ return NULL;
}
}
diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c
index 50354cc..b4aec73 100644
--- a/lib/metadata/thin_manip.c
+++ b/lib/metadata/thin_manip.c
@@ -436,7 +436,7 @@ int update_thin_pool_params(const struct segment_type *segtype,
log_error(INTERNAL_ERROR "Could not find configuration.");
return 0;
}
- if (!get_pool_discards(str, discards))
+ if (!set_pool_discards(discards, str))
return_0;
}
@@ -512,7 +512,7 @@ int update_thin_pool_params(const struct segment_type *segtype,
return 1;
}
-int get_pool_discards(const char *str, thin_discards_t *discards)
+int set_pool_discards(thin_discards_t *discards, const char *str)
{
if (!strcasecmp(str, "passdown"))
*discards = THIN_DISCARDS_PASSDOWN;
diff --git a/lib/report/report.c b/lib/report/report.c
index 4f505e7..262b376 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -784,7 +784,7 @@ static int _cachemode_disp(struct dm_report *rh, struct dm_pool *mem,
seg = first_seg(seg->pool_lv);
if (seg_is_cache_pool(seg)) {
- cachemode_str = get_cachepool_cachemode_name(seg);
+ cachemode_str = get_cache_pool_cachemode_name(seg);
return dm_report_field_string(rh, field, &cachemode_str);
}
diff --git a/lib/thin/thin.c b/lib/thin/thin.c
index f921bef..f27f240 100644
--- a/lib/thin/thin.c
+++ b/lib/thin/thin.c
@@ -115,7 +115,7 @@ static int _thin_pool_text_import(struct lv_segment *seg,
if (!discards_str)
seg->discards = THIN_DISCARDS_IGNORE;
- else if (!get_pool_discards(discards_str, &seg->discards))
+ else if (!set_pool_discards(&seg->discards, discards_str))
return SEG_LOG_ERROR("Discards option unsupported for");
if (dm_config_has_node(sn, "low_water_mark") &&
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index fcec8e1..8b09ee6 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -267,7 +267,7 @@ static int _read_pool_params(struct cmd_context *cmd, int *pargc, char ***pargv,
if (!cachemode)
cachemode = find_config_tree_str(cmd, allocation_cache_pool_cachemode_CFG, NULL);
- if (!get_cache_mode(cachemode, &lp->feature_flags))
+ if (!set_cache_pool_feature(&lp->feature_flags, cachemode))
return_0;
} else {
if (arg_from_list_is_set(cmd, "is valid only with cache pools",
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index cf2a07c..af00fee 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -567,7 +567,7 @@ static int _read_cache_params(struct cmd_context *cmd,
if (!(cachemode = arg_str_value(cmd, cachemode_ARG, NULL)))
cachemode = find_config_tree_str(cmd, allocation_cache_pool_cachemode_CFG, NULL);
- if (!get_cache_mode(cachemode, &lp->feature_flags))
+ if (!set_cache_pool_feature(&lp->feature_flags, cachemode))
return_0;
return 1;
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 1d3e993..ce45eb4 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -319,7 +319,7 @@ int discards_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_val
{
thin_discards_t discards;
- if (!get_pool_discards(av->value, &discards))
+ if (!set_pool_discards(&discards, av->value))
return_0;
av->i_value = discards;
@@ -332,7 +332,7 @@ int mirrorlog_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_va
{
int log_count;
- if (!get_mirror_log_count(av->value, &log_count))
+ if (!set_mirror_log_count(&log_count, av->value))
return_0;
av->i_value = log_count;
9 years, 6 months
master - report: for cache LV report chunksize
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=8d7340b7a19137...
Commit: 8d7340b7a191376b94c45503f9c5cbee5f337e85
Parent: 6a41286c012e8a15a41f0d807c0cb62de7f515b3
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Nov 10 21:29:32 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Nov 10 22:05:48 2014 +0100
report: for cache LV report chunksize
Cache LV reports chunksize via cache-pool.
---
lib/metadata/lv.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index bdf98f8..016f299 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -177,6 +177,8 @@ uint64_t lvseg_chunksize(const struct lv_segment *seg)
size = (uint64_t) find_snapshot(seg->lv)->chunk_size;
else if (seg_is_pool(seg))
size = (uint64_t) seg->chunk_size;
+ else if (seg_is_cache(seg))
+ return lvseg_chunksize(first_seg(seg->pool_lv));
else
size = UINT64_C(0);
9 years, 6 months
master - snapshot: virtual save commit
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=6a41286c012e8a...
Commit: 6a41286c012e8a15a41f0d807c0cb62de7f515b3
Parent: ff30783a4f44c823544133260acb8c5171fbd0a6
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Nov 5 15:15:07 2014 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Nov 10 22:05:48 2014 +0100
snapshot: virtual save commit
More efficient spare volume creation. Save 1 extra commit
and properly activate this volume according to our cluster
activation rules (using lv_active_change() for this).
---
WHATS_NEW | 1 +
lib/metadata/lv_manip.c | 83 ++++++++++++++++++++++++-----------------------
2 files changed, 43 insertions(+), 41 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index f70c657..616d1b0 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.112 -
=====================================
+ Reduce vg write and vg commits when creating spare volumes.
When remove_layer_from_lv() removes layer, restore subLV names.
Cache-pool in use becomes invisible LV.
Don't prompt for removal of _pmspare in VG without pool metadata LV.
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 99ed6d1..d664453 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -6434,12 +6434,6 @@ static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd,
NULL, ALLOC_INHERIT, 0))
return_NULL;
- /* store vg on disk(s) */
- if (!vg_write(vg) || !vg_commit(vg))
- return_NULL;
-
- backup(vg);
-
return lv;
}
@@ -7084,11 +7078,13 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
}
} else if (lp->snapshot) {
+ lv->status |= LV_TEMPORARY;
if (!activate_lv_local(cmd, lv)) {
log_error("Aborting. Failed to activate snapshot "
"exception store.");
goto revert_new_lv;
}
+ lv->status &= ~LV_TEMPORARY;
} else if (!lv_active_change(cmd, lv, lp->activate, 0)) {
log_error("Failed to activate new LV.");
goto deactivate_and_revert_new_lv;
@@ -7132,41 +7128,25 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
return NULL; /* FIXME: revert */
}
} else if (lp->snapshot) {
+ /* Deactivate zeroed COW, avoid any race usage */
+ if (!deactivate_lv(cmd, lv)) {
+ log_error("Aborting. Couldn't deactivate snapshot COW area %s.",
+ display_lvname(lv));
+ goto deactivate_and_revert_new_lv; /* Let's retry on error path */
+ }
+
+ /* Create zero origin volume for spare snapshot */
+ if (lp->virtual_extents &&
+ !(origin_lv = _create_virtual_origin(cmd, vg, lv->name,
+ lp->permission,
+ lp->virtual_extents)))
+ goto revert_new_lv;
+
/* Reset permission after zeroing */
if (!(lp->permission & LVM_WRITE))
lv->status &= ~LVM_WRITE;
/*
- * For clustered VG deactivate zeroed COW to not keep
- * the LV lock. For non-clustered VG, deactivate
- * if origin is real (not virtual) inactive device.
- */
- if ((vg_is_clustered(vg) ||
- (!lp->virtual_extents && !lv_is_active(origin_lv))) &&
- !deactivate_lv(cmd, lv)) {
- log_error("Aborting. Couldn't deactivate snapshot COW area. "
- "Manual intervention required.");
- return NULL;
- }
-
- /* A virtual origin must be activated explicitly. */
- if (lp->virtual_extents) {
- if (!(origin_lv = _create_virtual_origin(cmd, vg, lv->name,
- lp->permission,
- lp->virtual_extents))) {
- stack;
- goto deactivate_and_revert_new_lv;
- }
- if (!activate_lv_excl(cmd, origin_lv)) {
- log_error("Couldn't get exclusive lock for virtual origin LV %s",
- lv->name);
- if (!lv_remove(origin_lv))
- stack;
- goto deactivate_and_revert_new_lv;
- }
- }
-
- /*
* COW LV is activated via implicit activation of origin LV
* Only the snapshot origin holds the LV lock in cluster
*/
@@ -7176,17 +7156,38 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
goto deactivate_and_revert_new_lv;
}
- /* store vg on disk(s) */
- if (!lv_update_and_reload(origin_lv))
- return_NULL;
+ if (lp->virtual_extents) {
+ /* Store vg on disk(s) */
+ if (!vg_write(vg) || !vg_commit(vg))
+ return_NULL; /* Metadata update fails, deep troubles */
+
+ backup(vg);
+ /*
+ * TODO:
+ * We do not actually need snapshot-origin as an active device,
+ * as virtual origin is already 'hidden' private device without
+ * vg/lv links. As such it is not supposed to be used by any user.
+ * Also it would save one dm table entry, but it needs quite a few
+ * changes in the libdm/lvm2 code base to support it.
+ */
+ /* Activate spare snapshot once it is a complete LV */
+ if (!lv_active_change(cmd, origin_lv, lp->activate, 1)) {
+ log_error("Failed to activate sparce volume %s.",
+ display_lvname(origin_lv));
+ return NULL;
+ }
+ } else if (!lv_update_and_reload(origin_lv)) {
+ log_error("Aborting. Manual intervention required.");
+ return NULL; /* FIXME: revert */
+ }
}
out:
return lv;
deactivate_and_revert_new_lv:
if (!deactivate_lv(cmd, lv)) {
- log_error("Unable to deactivate failed new LV \"%s/%s\". "
- "Manual intervention required.", lv->vg->name, lv->name);
+ log_error("Unable to deactivate failed new LV %s. "
+ "Manual intervention required.", display_lvname(lv));
return NULL;
}
9 years, 6 months