summaryrefslogtreecommitdiffstats
path: root/lib/metadata/snapshot_manip.c
diff options
context:
space:
mode:
authorMike Snitzer <snitzer@redhat.com>2010-02-17 22:59:46 +0000
committerMike Snitzer <snitzer@redhat.com>2010-02-17 22:59:46 +0000
commita5ec3e3827b9b35da222575349a6a1be99958e14 (patch)
tree33fe8853a843bd968c32a05eb43f7ff1eb60638c /lib/metadata/snapshot_manip.c
parent943c443426ce063177d5a4973155e7f072d3b12f (diff)
downloadlvm2-a5ec3e3827b9b35da222575349a6a1be99958e14.tar.gz
lvm2-a5ec3e3827b9b35da222575349a6a1be99958e14.tar.xz
lvm2-a5ec3e3827b9b35da222575349a6a1be99958e14.zip
Refactor snapshot-merge deptree and device removal to support info-by-uuid
Add a merging snapshot to the deptree, using the "error" target, rather than avoid adding it entirely. This allows proper cleanup of the -cow device without having to rename the -cow to use the origin's name as a prefix. Move the preloading of the origin LV, after a merge, from lv_remove_single() to vg_remove_snapshot(). Having vg_remove_snapshot() preload the origin allows the -cow device to be released so that it can be removed via deactivate_lv(). lv_remove_single()'s deactivate_lv() reliably removes the -cow device because the associated snapshot LV, that is to be removed when a snapshot-merge completes, is always added to the deptree (and kernel -- via "error" target). Now when the snapshot LV is removed both the -cow and -real devices get removed using uuid rather than device name. This paves the way for us to switch over to info-by-uuid queries. Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'lib/metadata/snapshot_manip.c')
-rw-r--r--lib/metadata/snapshot_manip.c37
1 files changed, 32 insertions, 5 deletions
diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c
index 19effe38..f7218c26 100644
--- a/lib/metadata/snapshot_manip.c
+++ b/lib/metadata/snapshot_manip.c
@@ -15,6 +15,7 @@
#include "lib.h"
#include "metadata.h"
+#include "locking.h"
#include "toolcontext.h"
#include "lv_alloc.h"
@@ -58,9 +59,9 @@ int lv_is_merging_origin(const struct logical_volume *origin)
struct lv_segment *find_merging_cow(const struct logical_volume *origin)
{
- /* FIXME: eliminate this wrapper and just use find_cow()?
- * - find_merging_cow() adds to code clarity in caller
- */
+ if (!lv_is_merging_origin(origin))
+ return NULL;
+
return find_cow(origin);
}
@@ -170,12 +171,22 @@ int vg_add_snapshot(struct logical_volume *origin,
int vg_remove_snapshot(struct logical_volume *cow)
{
+ int preload_origin = 0;
struct logical_volume *origin = origin_from_cow(cow);
dm_list_del(&cow->snapshot->origin_list);
origin->origin_count--;
- if (find_merging_cow(origin) == find_cow(cow))
- clear_snapshot_merge(origin_from_cow(cow));
+ if (find_merging_cow(origin) == find_cow(cow)) {
+ clear_snapshot_merge(origin);
+ /*
+ * preload origin to:
+ * - allow proper release of -cow
+ * - avoid allocations with other devices suspended
+ * when transitioning from "snapshot-merge" to
+ * "snapshot-origin after a merge completes.
+ */
+ preload_origin = 1;
+ }
if (!lv_remove(cow->snapshot->lv)) {
log_error("Failed to remove internal snapshot LV %s",
@@ -186,5 +197,21 @@ int vg_remove_snapshot(struct logical_volume *cow)
cow->snapshot = NULL;
lv_set_visible(cow);
+ if (preload_origin) {
+ if (!vg_write(origin->vg))
+ return_0;
+ if (!suspend_lv(origin->vg->cmd, origin)) {
+ log_error("Failed to refresh %s without snapshot.",
+ origin->name);
+ return 0;
+ }
+ if (!vg_commit(origin->vg))
+ return_0;
+ if (!resume_lv(origin->vg->cmd, origin)) {
+ log_error("Failed to resume %s.", origin->name);
+ return 0;
+ }
+ }
+
return 1;
}