[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [lvm-devel] [PATCH 2/11] Add upward link from underlying LV to stacked seg



Attached is a revised version of the patch in the subject,
including a fix posted as "12/14" fix-upward-link.patch.
Other patches in the patchset won't be affected.

Changes since the last post:
  * Modified the picture in the patch header
  * Add reference count to 'struct seg_list'
  * Add validation checks in check_lv_segments()
  * Don't add link from mimage to mirror LV in mirror fixup code
  * Add _remove_mirror_log() to properly unlink mirror seg
    from log_lv->segs_using_this_lv, instead of just setting
    seg->log_lv = NULL
  * Change _lv_split_segment() to use set_lv_segment_area_lv()
    instead of directly modifying seg_lv(seg, s)
  * Add error messages in find_mirror_seg()
  * Add error messages in seg_using_lv()
  * Rename lv_{add,remove}_user_seg() and seg_using_lv()

Following issues may need more discussion:

  - Namings of functions to add/remove seg to/from
    lv->segs_using_this_lv.
    For now, I just changed them to descriptive names
      - add_seg_to_segs_using_this_lv()
      - remove_seg_from_segs_using_this_lv()

  - About seg_using_lv().
    Maybe adding is_top_of_the_stack(lv) is better if we would
    like to check it in future.
    For now, seg_using_lv() is really a specialized function
    to check if it has one and only segment and to get it.
    So I didn't change it except for additional error message
    and renaming to a descriptive name to characterize its
    specialty.

  - Duplication check of lv->segs_using_this_lv.
    In theory, it's possible that a LV has multiple references
    from a single segment. (e.g. multiple areas refer the same LV)
    So I added reference count to 'struct seg_list' and the
    validator matches it with actual references as well as checking
    duplications of entries.

Thanks,
-- 
Jun'ichi Nomura, NEC Corporation of America
Add upward link from underlying LV to LV segments using the LV.

Stacking is done like this:
   +-------------------+---------------------+
   |        LV0        |         LV2        ...
   +-------------------+---------------------+
   |SEG01|SEG02| SEG03 |         ....        |
   +-------------------------------+---------+
   |              LV1              | ...
   +-------------------------------+
   |  SEG11  |SEG12| SEG13 |  ...  | ...
   +-------------------------------+

(This figure might be over simplified.
 The point is they are stacked as lv-seg-lv-seg-...
 and the direct relationship is between lv and seg.)

Downward links:
  - lv-to-seg (e.g. LV0 -> SEG0x, LV1 -> SEG1x) => lv->segments 
  - seg-to-lv (e.g. SEG0x -> LV1)               => seg_lv(seg, s)
    [where s is the index of the segment area]
Upward links:
  - lv-to-seg (e.g. LV1 -> SEG0x)               => N/A
  - seg-to-lv (e.g. SEG0x -> LV0, SEG1x -> LV1) => seg->lv

This patch adds lv-to-seg upward link, lv->segs_using_this_lv.

The patch also replaces seg->mirror_seg with this.
mirror_seg was seg-to-seg link, i.e. with the above example, SEG1x -> SEG0x.
However, it's been used only when LV0 has 1 segment.
So the conversion is straight-forward.

For segment areas, the linking/unlinkg of the LV to the seg is
automatically done with set_lv_segment_area_lv()/release_lv_segment_area().
For other relation ships (e.g. log_lv), the linking/unlinking should done
explicitly using add_seg_to_segs_using_this_lv()/remove_seg_from_segs_using_this_lv().

find_parent_for_layer() is removed.

Changes since rev.1 (posted Jan. 11, 2008):
  * Add reference count to 'struct seg_list'
  * Add validation checks in check_lv_segments()
  * Don't add link from mimage to mirror LV in mirror fixup code
  * Add _remove_mirror_log() to properly unlink mirror seg from log_lv
  * Change _lv_split_segment() to use set_lv_segment_area_lv()
  * Add error messages in find_mirror_seg()
  * Add error messages in seg_using_lv() [now get_only_segment_using_this_lv()]
  * Rename lv_{add,remove}_user_seg() and seg_using_lv()

Index: LVM2.work/lib/metadata/metadata-exported.h
===================================================================
--- LVM2.work.orig/lib/metadata/metadata-exported.h
+++ LVM2.work/lib/metadata/metadata-exported.h
@@ -242,7 +242,6 @@ struct lv_segment {
 	uint32_t region_size;	/* For mirrors - in sectors */
 	uint32_t extents_copied;
 	struct logical_volume *log_lv;
-	struct lv_segment *mirror_seg;
 
 	struct list tags;
 
@@ -274,6 +273,7 @@ struct logical_volume {
 
 	struct list segments;
 	struct list tags;
+	struct list segs_using_this_lv;
 };
 
 struct pe_range {
@@ -411,8 +411,6 @@ int remove_layers_for_segments_all(struc
 				   struct list *lvs_changed);
 int split_parent_segments_for_layer(struct cmd_context *cmd,
 				    struct logical_volume *layer_lv);
-struct logical_volume *find_parent_for_layer(struct logical_volume *lv,
-					     struct logical_volume *layer_lv);
 int remove_layer_from_lv(struct logical_volume *lv,
 			 struct logical_volume *layer_lv);
 struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
@@ -463,6 +461,7 @@ int vg_check_status(const struct volume_
 /*
 * Mirroring functions
 */
+struct lv_segment *find_mirror_seg(struct lv_segment *seg);
 int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
 		   uint32_t mirrors, uint32_t stripes,
 		   uint32_t region_size, uint32_t log_count,
Index: LVM2.work/lib/metadata/metadata.h
===================================================================
--- LVM2.work.orig/lib/metadata/metadata.h
+++ LVM2.work/lib/metadata/metadata.h
@@ -158,6 +158,12 @@ struct peg_list {
 	struct pv_segment *peg;
 };
 
+struct seg_list {
+	struct list list;
+	unsigned count;
+	struct lv_segment *seg;
+};
+
 /*
  * Ownership of objects passes to caller.
  */
@@ -293,13 +299,20 @@ int lv_merge_segments(struct logical_vol
 int lv_split_segment(struct logical_volume *lv, uint32_t le);
 
 /*
+ * Add/remove upward link from underlying LV to the segment using it
+ * FIXME: ridiculously long name
+ */
+int add_seg_to_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg);
+int remove_seg_from_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg);
+struct lv_segment *get_only_segment_using_this_lv(struct logical_volume *lv);
+
+/*
  * Mirroring functions
  */
 
 /*
  * Given mirror image or mirror log segment, find corresponding mirror segment 
  */
-struct lv_segment *find_mirror_seg(struct lv_segment *seg);
 int fixup_imported_mirrors(struct volume_group *vg);
 
 /*
Index: LVM2.work/lib/metadata/lv_manip.c
===================================================================
--- LVM2.work.orig/lib/metadata/lv_manip.c
+++ LVM2.work/lib/metadata/lv_manip.c
@@ -31,6 +31,69 @@ struct lv_names {
 	const char *new;
 };
 
+int add_seg_to_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg)
+{
+	struct seg_list *sl;
+
+	list_iterate_items(sl, &lv->segs_using_this_lv) {
+		if (sl->seg == seg) {
+			sl->count++;
+			return 1;
+		}
+	}
+
+	if (!(sl = dm_pool_zalloc(lv->vg->cmd->mem, sizeof(*sl)))) {
+		log_error("Failed to allocate segment list");
+		return 0;
+	}
+
+	sl->count = 1;
+	sl->seg = seg;
+	list_add(&lv->segs_using_this_lv, &sl->list);
+
+	return 1;
+}
+
+int remove_seg_from_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg)
+{
+	struct seg_list *sl;
+
+	list_iterate_items(sl, &lv->segs_using_this_lv) {
+		if (sl->seg != seg)
+			continue;
+		if (sl->count > 1)
+			sl->count--;
+		else
+			list_del(&sl->list);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * This is a function specialized for the common case where there is
+ * only one segment which uses the LV.
+ * e.g. the LV is a layer inserted by insert_layer_for_lv().
+ *
+ * In general, walk through lv->segs_using_this_lv.
+ */
+struct lv_segment *get_only_segment_using_this_lv(struct logical_volume *lv)
+{
+	struct seg_list *sl;
+
+	if (list_size(&lv->segs_using_this_lv) != 1) {
+		log_error("%s is expected to have only one segment using it, "
+			  "while it has %d", lv->name,
+			  list_size(&lv->segs_using_this_lv));
+		return NULL;
+	}
+
+	sl = list_item(list_first(&lv->segs_using_this_lv), struct seg_list);
+
+	return sl->seg;
+}
+
 /*
  * PVs used by a segment of an LV
  */
@@ -127,12 +190,12 @@ struct lv_segment *alloc_lv_segment(stru
 	seg->region_size = region_size;
 	seg->extents_copied = extents_copied;
 	seg->log_lv = log_lv;
-	seg->mirror_seg = NULL;
 	list_init(&seg->tags);
 
 	if (log_lv) {
 		log_lv->status |= MIRROR_LOG;
-		first_seg(log_lv)->mirror_seg = seg;
+		if (!add_seg_to_segs_using_this_lv(log_lv, seg))
+			return_NULL;
 	}
 
 	return seg;
@@ -183,6 +246,7 @@ void release_lv_segment_area(struct lv_s
 	}
 
 	if (area_reduction == seg->area_len) {
+		remove_seg_from_segs_using_this_lv(seg_lv(seg, s), seg);
 		seg_lv(seg, s) = NULL;
 		seg_le(seg, s) = 0;
 		seg_type(seg, s) = AREA_UNASSIGNED;
@@ -223,7 +287,8 @@ int move_lv_segment_area(struct lv_segme
 					seg_from->area_len);
 		release_lv_segment_area(seg_to, area_to, seg_to->area_len);
 
-		set_lv_segment_area_lv(seg_to, area_to, lv, le, 0);
+		if (!set_lv_segment_area_lv(seg_to, area_to, lv, le, 0))
+			return_0;
 
 		break;
 
@@ -254,14 +319,19 @@ int set_lv_segment_area_pv(struct lv_seg
 /*
  * Link one LV segment to another.  Assumes sizes already match.
  */
-void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
-			    struct logical_volume *lv, uint32_t le,
-			    uint32_t flags)
+int set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
+			   struct logical_volume *lv, uint32_t le,
+			   uint32_t flags)
 {
 	seg->areas[area_num].type = AREA_LV;
 	seg_lv(seg, area_num) = lv;
 	seg_le(seg, area_num) = le;
 	lv->status |= flags;
+
+	if (!add_seg_to_segs_using_this_lv(lv, seg))
+		return_0;
+
+	return 1;
 }
 
 /*
@@ -1399,14 +1469,13 @@ int lv_add_mirror_lvs(struct logical_vol
 		return 0;
 	}
 
-	for (m = 0; m < old_area_count; m++) {
+	for (m = 0; m < old_area_count; m++)
 		seg_lv(seg, m)->status |= status;
-		first_seg(seg_lv(seg, m))->mirror_seg = seg;
-	}
 
 	for (m = old_area_count; m < new_area_count; m++) {
-		set_lv_segment_area_lv(seg, m, sub_lvs[m - old_area_count], 0, status);
-		first_seg(sub_lvs[m - old_area_count])->mirror_seg = seg;
+		if (!set_lv_segment_area_lv(seg, m, sub_lvs[m - old_area_count],
+					    0, status))
+			return_0;
 		sub_lvs[m - old_area_count]->status &= ~VISIBLE_LV;
 	}
 
@@ -1780,6 +1849,7 @@ struct logical_volume *lv_create_empty(c
 	list_init(&lv->snapshot_segs);
 	list_init(&lv->segments);
 	list_init(&lv->tags);
+	list_init(&lv->segs_using_this_lv);
 
 	if (lvid)
 		lv->lvid = *lvid;
@@ -2212,53 +2282,29 @@ static int _move_lv_segments(struct logi
 	return 1;
 }
 
-/*
- * Find a parent LV for the layer_lv in the lv
- */
-struct logical_volume *find_parent_for_layer(struct logical_volume *lv,
-                                            struct logical_volume *layer_lv)
-{
-	struct logical_volume *parent;
-	struct lv_segment *seg;
-	uint32_t s;
-
-	list_iterate_items(seg, &lv->segments) {
-		for (s = 0; s < seg->area_count; s++) {
-			if (seg_type(seg, s) != AREA_LV)
-				continue;
-			if (seg_lv(seg, s) == layer_lv)
-				return lv;
-			parent = find_parent_for_layer(seg_lv(seg, s),
-						       layer_lv);
-			if (parent)
-				return parent;
-		}
-	}
-	return NULL;
-}
-
 /* Remove a layer from the LV */
 int remove_layer_from_lv(struct logical_volume *lv,
 			 struct logical_volume *layer_lv)
 {
 	struct logical_volume *parent;
+	struct lv_segment *parent_seg;
 	struct segment_type *segtype;
 
-	parent = find_parent_for_layer(lv, layer_lv);
-	if (!parent) {
+	if (!(parent_seg = get_only_segment_using_this_lv(layer_lv))) {
 		log_error("Failed to find layer %s in %s",
 		layer_lv->name, lv->name);
 		return 0;
 	}
+	parent = parent_seg->lv;
 
 	/*
 	 * Before removal, the layer should be cleaned up,
 	 * i.e. additional segments and areas should have been removed.
 	 */
 	if (list_size(&parent->segments) != 1 ||
-	    first_seg(parent)->area_count != 1 ||
-	    seg_type(first_seg(parent), 0) != AREA_LV ||
-	    layer_lv != seg_lv(first_seg(parent), 0) ||
+	    parent_seg->area_count != 1 ||
+	    seg_type(parent_seg, 0) != AREA_LV ||
+	    layer_lv != seg_lv(parent_seg, 0) ||
 	    parent->le_count != layer_lv->le_count)
 		return_0;
 
@@ -2328,7 +2374,8 @@ struct logical_volume *insert_layer_for_
 		return_NULL;
 
 	/* map the new segment to the original underlying are */
-	set_lv_segment_area_lv(mapseg, 0, layer_lv, 0, 0);
+	if (!set_lv_segment_area_lv(mapseg, 0, layer_lv, 0, 0))
+		return_NULL;
 
 	/* add the new segment to the layer LV */
 	list_add(&lv_where->segments, &mapseg->list);
@@ -2379,7 +2426,8 @@ static int _extend_layer_lv_for_segment(
 	layer_lv->size += seg->area_len * layer_lv->vg->extent_size;
 
 	/* map the original area to the new segment */
-	set_lv_segment_area_lv(seg, s, layer_lv, mapseg->le, 0);
+	if (!set_lv_segment_area_lv(seg, s, layer_lv, mapseg->le, 0))
+		return_0;
 
 	return 1;
 }
Index: LVM2.work/lib/metadata/merge.c
===================================================================
--- LVM2.work.orig/lib/metadata/merge.c
+++ LVM2.work/lib/metadata/merge.c
@@ -62,9 +62,10 @@ int check_lv_segments(struct logical_vol
 {
 	struct lv_segment *seg, *seg2;
 	uint32_t le = 0;
-	unsigned seg_count = 0;
+	unsigned seg_count = 0, seg_found;
 	int r = 1;
 	uint32_t area_multiplier, s;
+	struct seg_list *sl;
 
 	list_iterate_items(seg, &lv->segments) {
 		seg_count++;
@@ -101,7 +102,7 @@ int check_lv_segments(struct logical_vol
 			}
 
 			if (!(seg2 = first_seg(seg->log_lv)) ||
-			    seg2->mirror_seg != seg) {
+			    find_mirror_seg(seg2) != seg) {
 				log_error("LV %s: segment %u log LV does not "
 					  "point back to mirror segment",
 					   lv->name, seg_count);
@@ -110,8 +111,8 @@ int check_lv_segments(struct logical_vol
 		}
 
 		if (complete_vg && seg->status & MIRROR_IMAGE) {
-			if (!seg->mirror_seg ||
-			    !seg_is_mirrored(seg->mirror_seg)) {
+			if (!find_mirror_seg(seg) ||
+			    !seg_is_mirrored(find_mirror_seg(seg))) {
 				log_error("LV %s: segment %u mirror image "
 					  "is not mirrored",
 					  lv->name, seg_count);
@@ -157,7 +158,7 @@ int check_lv_segments(struct logical_vol
 				    (seg_lv(seg, s)->status & MIRROR_IMAGE) &&
 				    (!(seg2 = find_seg_by_le(seg_lv(seg, s),
 							    seg_le(seg, s))) ||
-				     seg2->mirror_seg != seg)) {
+				     find_mirror_seg(seg2) != seg)) {
 					log_error("LV %s: segment %u mirror "
 						  "image %u missing mirror ptr",
 						  lv->name, seg_count, s);
@@ -173,12 +174,57 @@ int check_lv_segments(struct logical_vol
 					r = 0;
 				}
  */
+				seg_found = 0;
+				list_iterate_items(sl, &seg_lv(seg, s)->segs_using_this_lv)
+					if (sl->seg == seg)
+						seg_found++;
+				if (!seg_found) {
+					log_error("LV %s segment %d uses LV %s,"
+						  " but missing ptr from %s to %s",
+						  lv->name, seg_count,
+						  seg_lv(seg, s)->name,
+						  seg_lv(seg, s)->name, lv->name);
+					r = 0;
+				} else if (seg_found > 1) {
+					log_error("LV %s has duplicated links "
+						  "to LV %s segment %d",
+						  seg_lv(seg, s)->name,
+						  lv->name, seg_count);
+					r = 0;
+				}
 			}
 		}
 
 		le += seg->len;
 	}
 
+	list_iterate_items(sl, &lv->segs_using_this_lv) {
+		seg = sl->seg;
+		seg_found = 0;
+		for (s = 0; s < seg->area_count; s++) {
+			if (seg_type(seg, s) != AREA_LV)
+				continue;
+			if (lv == seg_lv(seg, s))
+				seg_found++;
+		}
+		if (seg->log_lv == lv)
+			seg_found++;
+		if (!seg_found) {
+			log_error("LV %s is used by LV %s:%" PRIu32 ", "
+				  "but missing ptr from %s to %s",
+				  lv->name, seg->lv->name, seg->le,
+				  seg->lv->name, lv->name);
+			r = 0;
+		} else if (seg_found != sl->count) {
+			log_error("Reference count mismatch: LV %s has %d "
+				  "links to LV %s:%" PRIu32
+				  ", which has %d links",
+				  lv->name, sl->count,
+				  seg->lv->name, seg->le, seg_found);
+			r = 0;
+		}
+	}
+
 	if (le != lv->le_count) {
 		log_error("LV %s: inconsistent LE count %u != %u",
 			  lv->name, le, lv->le_count);
@@ -243,9 +289,9 @@ static int _lv_split_segment(struct logi
 		/* Split area at the offset */
 		switch (seg_type(seg, s)) {
 		case AREA_LV:
-			seg_lv(split_seg, s) = seg_lv(seg, s);
-			seg_le(split_seg, s) =
-			    seg_le(seg, s) + seg->area_len;
+			if (!set_lv_segment_area_lv(split_seg, s, seg_lv(seg, s),
+						    seg_le(seg, s) + seg->area_len, 0))
+				return_0;
 			log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name,
 				  seg->le, s, le, seg_lv(seg, s)->name,
 				  seg_le(split_seg, s));
Index: LVM2.work/lib/metadata/mirror.c
===================================================================
--- LVM2.work.orig/lib/metadata/mirror.c
+++ LVM2.work/lib/metadata/mirror.c
@@ -76,7 +76,22 @@ uint32_t lv_mirror_count(const struct lo
 
 struct lv_segment *find_mirror_seg(struct lv_segment *seg)
 {
-	return seg->mirror_seg;
+	struct lv_segment *mirror_seg;
+
+	mirror_seg = get_only_segment_using_this_lv(seg->lv);
+
+	if (!mirror_seg) {
+		log_error("Failed to find mirror_seg for %s", seg->lv->name);
+		return NULL;
+	}
+
+	if (!seg_is_mirrored(mirror_seg)) {
+		log_error("%s on %s is not a mirror segments",
+			  mirror_seg->lv->name, seg->lv->name);
+		return NULL;
+	}
+
+	return mirror_seg;
 }
 
 /*
@@ -155,6 +170,20 @@ static int _merge_mirror_images(struct l
 				 MIRROR_IMAGE, first_seg(lv)->region_size);
 }
 
+/* Unlink the relationship between the segment and its log_lv */
+static void _remove_mirror_log(struct lv_segment *mirrored_seg)
+{
+	struct logical_volume *log_lv;
+
+	if (!mirrored_seg->log_lv)
+		return;
+
+	log_lv = mirrored_seg->log_lv;
+	mirrored_seg->log_lv = NULL;
+	log_lv->status &= ~MIRROR_LOG;
+	remove_seg_from_segs_using_this_lv(log_lv, mirrored_seg);
+}
+
 /*
  * Remove num_removed images from mirrored_seg
  */
@@ -244,6 +273,7 @@ static int _remove_mirror_images(struct 
 		}
 		lvl->lv = seg_lv(mirrored_seg, m);
 		list_add(&tmp_orphan_lvs, &lvl->list);
+		release_lv_segment_area(mirrored_seg, m, mirrored_seg->area_len);
 	}
 	mirrored_seg->area_count = new_area_count;
 
@@ -254,7 +284,7 @@ static int _remove_mirror_images(struct 
 	/* If no more mirrors, remove mirror layer */
 	if (new_area_count == 1) {
 		lv1 = seg_lv(mirrored_seg, 0);
-		mirrored_seg->log_lv = NULL;
+		_remove_mirror_log(mirrored_seg);
 		if (!remove_layer_from_lv(lv, lv1))
 			return_0;
 		lv->status &= ~MIRRORED;
@@ -265,12 +295,10 @@ static int _remove_mirror_images(struct 
 			return 0;
 		}
 	} else if (remove_log)
-		mirrored_seg->log_lv = NULL;
+		_remove_mirror_log(mirrored_seg);
 
-	if (remove_log && log_lv) {
-		log_lv->status &= ~MIRROR_LOG;
+	if (remove_log && log_lv)
 		log_lv->status |= VISIBLE_LV;
-	}
 
 	/*
 	 * To successfully remove these unwanted LVs we need to
@@ -395,18 +423,25 @@ static struct logical_volume *_find_tmp_
  */
 int collapse_mirrored_lv(struct logical_volume *lv)
 {
-	struct logical_volume *tmp_lv, *parent_lv;
+	struct logical_volume *tmp_lv;
+	struct lv_segment *mirror_seg;
 
 	while ((tmp_lv = _find_tmp_mirror(lv))) {
-		parent_lv = find_parent_for_layer(lv, tmp_lv);
-		if (!_mirrored_lv_in_sync(parent_lv)) {
+		mirror_seg = find_mirror_seg(first_seg(tmp_lv));
+		if (!mirror_seg) {
+			log_error("Failed to find mirrored LV for %s",
+				  tmp_lv->name);
+			return 0;
+		}
+
+		if (!_mirrored_lv_in_sync(mirror_seg->lv)) {
 			log_verbose("Not collapsing %s: out-of-sync",
-				    parent_lv->name);
+				    mirror_seg->lv->name);
 			return 1;
 		}
 
-		if (!_remove_mirror_images(parent_lv,
-					   first_seg(parent_lv)->area_count - 1,
+		if (!_remove_mirror_images(mirror_seg->lv,
+					   mirror_seg->area_count - 1,
 					   NULL, 1, 1)) {
 			log_error("Failed to release mirror images");
 			return 0;
@@ -801,7 +836,6 @@ int fixup_imported_mirrors(struct volume
 {
 	struct lv_list *lvl;
 	struct lv_segment *seg;
-	uint32_t s;
 
 	list_iterate_items(lvl, &vg->lvs) {
 		list_iterate_items(seg, &lvl->lv->segments) {
@@ -809,12 +843,8 @@ int fixup_imported_mirrors(struct volume
 			    get_segtype_from_string(vg->cmd, "mirror"))
 				continue;
 
-			if (seg->log_lv)
-				first_seg(seg->log_lv)->mirror_seg = seg;
-			for (s = 0; s < seg->area_count; s++)
-				if (seg_type(seg, s) == AREA_LV)
-					first_seg(seg_lv(seg, s))->mirror_seg
-					    = seg;
+			if (seg->log_lv && !add_seg_to_segs_using_this_lv(seg->log_lv, seg))
+				return_0;
 		}
 	}
 
@@ -1103,7 +1133,7 @@ static void _add_mirror_log(struct logic
 {
 	first_seg(lv)->log_lv = log_lv;
 	log_lv->status |= MIRROR_LOG;
-	first_seg(log_lv)->mirror_seg = first_seg(lv);
+	add_seg_to_segs_using_this_lv(log_lv, first_seg(lv));
 }
 
 int add_mirror_log(struct cmd_context *cmd,
Index: LVM2.work/lib/report/report.c
===================================================================
--- LVM2.work.orig/lib/report/report.c
+++ LVM2.work/lib/report/report.c
@@ -275,13 +275,12 @@ static int _lvkmin_disp(struct dm_report
 static int _lv_mimage_in_sync(const struct logical_volume *lv)
 {
 	float percent;
-	struct lv_segment *seg = first_seg(lv);
+	struct lv_segment *mirror_seg = find_mirror_seg(first_seg(lv));
 
-	if (!(lv->status & MIRROR_IMAGE) || !seg->mirror_seg)
+	if (!(lv->status & MIRROR_IMAGE) || !mirror_seg)
 		return_0;
 
-	if (!lv_mirror_percent(lv->vg->cmd, seg->mirror_seg->lv, 0,
-			       &percent, NULL))
+	if (!lv_mirror_percent(lv->vg->cmd, mirror_seg->lv, 0, &percent, NULL))
 		return_0;
 
 	if (percent >= 100.0)
Index: LVM2.work/tools/vgreduce.c
===================================================================
--- LVM2.work.orig/tools/vgreduce.c
+++ LVM2.work/tools/vgreduce.c
@@ -50,7 +50,7 @@ static int _remove_pv(struct volume_grou
 static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
 		      int *list_unsafe, struct list *lvs_changed)
 {
-	struct lv_segment *snap_seg, *mirror_seg;
+	struct lv_segment *snap_seg;
 	struct list *snh, *snht;
 	struct logical_volume *cow;
 	struct lv_list *lvl;
@@ -117,9 +117,8 @@ static int _remove_lv(struct cmd_context
 	 * Clean-up is currently done by caller (_make_vg_consistent()).
 	 */
 	if ((lv_info(cmd, lv, &info, 0, 0) && info.exists)
-	    || first_seg(lv)->mirror_seg) {
+	    || find_mirror_seg(first_seg(lv))) {
 		extents = lv->le_count;
-		mirror_seg = first_seg(lv)->mirror_seg;
 		if (!lv_empty(lv)) {
 			stack;
 			return 0;
@@ -130,10 +129,6 @@ static int _remove_lv(struct cmd_context
 			stack;
 			return 0;
 		}
-		if (mirror_seg) {
-			first_seg(lv)->status |= MIRROR_IMAGE;
-			first_seg(lv)->mirror_seg = mirror_seg;
-		}
 
 		if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
 			log_error("lv_list alloc failed");
Index: LVM2.work/lib/format_text/import_vsn1.c
===================================================================
--- LVM2.work.orig/lib/format_text/import_vsn1.c
+++ LVM2.work/lib/format_text/import_vsn1.c
@@ -408,8 +408,10 @@ int text_import_areas(struct lv_segment 
 				return 0;
 			}
 		} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
-			set_lv_segment_area_lv(seg, s, lv1, (uint32_t) cv->next->v.i,
-					       flags);
+			if (!set_lv_segment_area_lv(seg, s, lv1,
+						    (uint32_t) cv->next->v.i,
+						    flags))
+				return_0;
 		} else {
 			log_error("Couldn't find volume '%s' "
 				  "for segment '%s'.",
@@ -562,6 +564,7 @@ static int _read_lvnames(struct format_i
 	list_init(&lv->snapshot_segs);
 	list_init(&lv->segments);
 	list_init(&lv->tags);
+	list_init(&lv->segs_using_this_lv);
 
 	/* Optional tags */
 	if ((cn = find_config_node(lvn, "tags")) &&
Index: LVM2.work/lib/metadata/lv_alloc.h
===================================================================
--- LVM2.work.orig/lib/metadata/lv_alloc.h
+++ LVM2.work/lib/metadata/lv_alloc.h
@@ -33,9 +33,9 @@ struct lv_segment *alloc_snapshot_seg(st
 
 int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
 			   struct physical_volume *pv, uint32_t pe);
-void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
-			    struct logical_volume *lv, uint32_t le,
-			    uint32_t flags);
+int set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
+			   struct logical_volume *lv, uint32_t le,
+			   uint32_t flags);
 int move_lv_segment_area(struct lv_segment *seg_to, uint32_t area_to,
 			 struct lv_segment *seg_from, uint32_t area_from);
 void release_lv_segment_area(struct lv_segment *seg, uint32_t s,
Index: LVM2.work/lib/format1/import-export.c
===================================================================
--- LVM2.work.orig/lib/format1/import-export.c
+++ LVM2.work/lib/format1/import-export.c
@@ -361,6 +361,7 @@ int import_lv(struct dm_pool *mem, struc
 	list_init(&lv->snapshot_segs);
 	list_init(&lv->segments);
 	list_init(&lv->tags);
+	list_init(&lv->segs_using_this_lv);
 
 	return 1;
 }
Index: LVM2.work/lib/format_pool/import_export.c
===================================================================
--- LVM2.work.orig/lib/format_pool/import_export.c
+++ LVM2.work/lib/format_pool/import_export.c
@@ -83,6 +83,7 @@ int import_pool_lvs(struct volume_group 
 	list_init(&lv->snapshot_segs);
 	list_init(&lv->segments);
 	list_init(&lv->tags);
+	list_init(&lv->segs_using_this_lv);
 
 	list_iterate_items(pl, pls) {
 		lv->size += pl->pd.pl_blocks;

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]