[lvm-devel] [LVM PATCH 2/6] cache: Add functions that create/remove cache LVs
Jonathan Brassow
jbrassow at redhat.com
Sat Feb 1 00:03:08 UTC 2014
A cache LV - from LVM's perpective - is a user accessible device that
links the cachepool LV and the origin LV. The following functions
were added to facilitate the creation and removal of this top-level
LV:
1) 'lv_cache_create' - takes a cachepool and an origin device and links
them into a new top-level LV of 'cache' segment type. No allocation
is necessary in this function, as the sub-LVs contain all of the
necessary allocated space. Only the top-level layer needs to be
created.
2) 'lv_cache_remove' - this function removes the top-level LV of a
cache LV - promoting the cachepool and origin sub-LVs to top-level
devices and leaving them exposed to the user. That is, the
cachepool is unlinked and free to be used with another origin to
form a new cache LV; and the origin is no longer cached.
---
lib/Makefile.in | 1 +
lib/metadata/cache_manip.c | 219 ++++++++++++++++++++++++++++++++++++++
lib/metadata/metadata-exported.h | 9 ++-
3 files changed, 227 insertions(+), 2 deletions(-)
create mode 100644 lib/metadata/cache_manip.c
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 3808269..968ad00 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -87,6 +87,7 @@ SOURCES =\
locking/locking.c \
locking/no_locking.c \
log/log.c \
+ metadata/cache_manip.c \
metadata/lv.c \
metadata/lv_manip.c \
metadata/merge.c \
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
new file mode 100644
index 0000000..cfe3ce6
--- /dev/null
+++ b/lib/metadata/cache_manip.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "lib.h"
+#include "metadata.h"
+#include "locking.h"
+#include "pv_map.h"
+#include "lvm-string.h"
+#include "toolcontext.h"
+#include "lv_alloc.h"
+#include "pv_alloc.h"
+#include "display.h"
+#include "segtype.h"
+#include "archiver.h"
+#include "activate.h"
+#include "str_list.h"
+#include "defaults.h"
+#include "lvm-exec.h"
+
+/*
+ * lv_cache_create
+ * @pool
+ * @origin
+ *
+ * Given a cache_pool and an origin, link the two and create a
+ * cached LV.
+ *
+ * Returns: cache LV on success, NULL on failure
+ */
+struct logical_volume *lv_cache_create(struct logical_volume *pool,
+ struct logical_volume *origin)
+{
+ const struct segment_type *segtype;
+ struct cmd_context *cmd = pool->vg->cmd;
+ struct logical_volume *cache_lv;
+ struct lv_segment *seg;
+
+ if (!lv_is_cache_pool(pool)) {
+ log_error(INTERNAL_ERROR
+ "%s is not a cache_pool LV", pool->name);
+ return NULL;
+ }
+
+ if (lv_is_cache_type(origin)) {
+ /*
+ * FIXME: We can layer caches, insert_layer_for_lv() would
+ * have to do a better job renaming the LVs in the stack
+ * first so that there isn't a name collision with <name>_corig.
+ * The origin under the origin would become *_corig_corig
+ * before renaming the origin above to *_corig.
+ */
+ log_error(INTERNAL_ERROR
+ "The origin, %s, cannot be of cache type",
+ origin->name);
+ return NULL;
+ }
+
+ if (!(segtype = get_segtype_from_string(cmd, "cache")))
+ return_NULL;
+
+ cache_lv = origin;
+ if (!(origin = insert_layer_for_lv(cmd, cache_lv, CACHE, "_corig")))
+ return_NULL;
+
+ seg = first_seg(cache_lv);
+ seg->segtype = segtype;
+
+ if (!attach_pool_lv(seg, pool, NULL, NULL))
+ return_0;
+
+ return cache_lv;
+}
+
+/*
+ * lv_cache_remove
+ * @cache_lv
+ *
+ * Given a cache LV, remove the cache layer. This will unlink
+ * the origin and cache_pool, remove the cache LV layer, and promote
+ * the origin to a usable non-cached LV of the same name as the
+ * given cache_lv.
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+int lv_cache_remove(struct logical_volume *cache_lv)
+{
+ struct cmd_context *cmd = cache_lv->vg->cmd;
+ char *policy_name;
+ uint64_t dirty_blocks;
+ struct segment_type *segtype;
+ struct lv_segment *cache_seg = first_seg(cache_lv);
+ struct logical_volume *origin_lv;
+ struct logical_volume *cache_pool_lv;
+
+ if (!lv_is_cache(cache_lv))
+ return_0;
+
+ /*
+ * FIXME:
+ * Before the link can be broken, we must ensure that the
+ * cache has been flushed. This may already be the case
+ * if the cache mode is writethrough (or the cleaner
+ * policy is in place from a previous half-finished attempt
+ * to remove the cache_pool). It could take a long time to
+ * flush the cache - it should probably be done in the background.
+ *
+ * Also, if we do perform the flush in the background and we
+ * happen to also be removing the cache/origin LV, then we
+ * could check if the cleaner policy is in place and simply
+ * remove the cache_pool then without waiting for the flush to
+ * complete.
+ */
+ if (!lv_cache_policy_info(cache_lv, &policy_name, NULL, NULL))
+ return_0;
+
+ if (strcmp(policy_name, "cleaner")) {
+ /* We must swap in the cleaner to flush the cache */
+ log_error("Flushing cache for %s", cache_lv->name);
+
+ /*
+ * Is there are clean way to free the memory for the name
+ * and argv when changing the policy?
+ */
+ cache_seg->policy_name = (char *)"cleaner";
+ cache_seg->policy_argc = 0;
+ cache_seg->policy_argv = NULL;
+
+ /* update the kernel to put the cleaner policy in place */
+ if (!vg_write(cache_lv->vg))
+ return_0;
+ if (!suspend_lv(cmd, cache_lv))
+ return_0;
+ if (!vg_commit(cache_lv->vg))
+ return_0;
+ if (!resume_lv(cmd, cache_lv))
+ return_0;
+
+ //FIXME: use polling to do this...
+ do {
+ if (!lv_cache_block_info(cache_lv, NULL,
+ &dirty_blocks, NULL, NULL))
+ return_0;
+ log_error("%" PRIu64 " blocks must still be flushed.",
+ dirty_blocks);
+ if (dirty_blocks)
+ sleep(5);
+ } while (dirty_blocks);
+ }
+
+ cache_pool_lv = first_seg(cache_lv)->pool_lv;
+ if (!detach_pool_lv(first_seg(cache_lv)))
+ return_0;
+
+ origin_lv = seg_lv(first_seg(cache_lv), 0);
+ lv_set_visible(origin_lv);
+
+//FIXME: We should be able to use 'remove_layer_from_lv', but
+// there is a call to 'lv_empty' in there that recursively
+// deletes everything down the tree - including the origin_lv
+// that we are trying to preserve!
+// if (!remove_layer_from_lv(cache_lv, origin_lv))
+// return_0;
+
+ if (!remove_seg_from_segs_using_this_lv(origin_lv, first_seg(cache_lv)))
+ return_0;
+ if (!move_lv_segments(cache_lv, origin_lv, 0, 0))
+ return_0;
+
+ cache_lv->status &= ~CACHE;
+
+ segtype = get_segtype_from_string(cmd, "error");
+ if (!lv_add_virtual_segment(origin_lv, 0,
+ cache_lv->le_count, segtype, NULL))
+ return_0;
+
+ if (!vg_write(cache_lv->vg))
+ return_0;
+
+ /*
+ * suspend_lv on this cache LV will suspend all of the components:
+ * - the top-level cache LV
+ * - the origin
+ * - the cache_pool and all of its sub-LVs
+ */
+ if (!suspend_lv(cmd, cache_lv))
+ return_0;
+
+ if (!vg_commit(cache_lv->vg))
+ return_0;
+
+ /*
+ * resume_lv on this (former) cache LV will resume all
+ * but the cache_pool LV. It must be resumed seperately.
+ */
+ if (!resume_lv(cmd, cache_lv))
+ return_0;
+ if (!resume_lv(cmd, cache_pool_lv))
+ return_0;
+
+ if (!activate_lv(cmd, origin_lv))
+ return_0;
+ if (!deactivate_lv(cmd, origin_lv))
+ return_0;
+ if (!lv_remove(origin_lv))
+ return_0;
+
+ return 1;
+}
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 97f05fc..d8eef2d 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -1016,9 +1016,14 @@ int lv_raid_reshape(struct logical_volume *lv,
int lv_raid_replace(struct logical_volume *lv, struct dm_list *remove_pvs,
struct dm_list *allocate_pvs);
int lv_raid_remove_missing(struct logical_volume *lv);
-
/* -- metadata/raid_manip.c */
+/* ++ metadata/cache_manip.c */
+struct logical_volume *lv_cache_create(struct logical_volume *pool,
+ struct logical_volume *origin);
+int lv_cache_remove(struct logical_volume *cache_lv);
+/* -- metadata/cache_manip.c */
+
struct cmd_vg *cmd_vg_add(struct dm_pool *mem, struct dm_list *cmd_vgs,
const char *vg_name, const char *vgid,
uint32_t flags);
--
1.7.7.6
More information about the lvm-devel
mailing list