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

[lvm-devel] [LVM2 PATCH] (3/5) Allocate mirror log first



This patch allows log allocation first to fix the problems that
lvconvert from linear to mirror and lvconvert from corelog to disklog
may allocate log from the same PV as mirror images.

What is the problem?
  - Different (stronger) constraint should be applied to log area.
    i.e. log must avoid all parallel areas, not only the ones
    corresponding to the current LE.
    In other words, _find_parallel_space() should use ah->parallel_areas
    as whole for log allocation constraint. Whereas the part of it
    (parallel_pvs) is used for the other allocation.

To fix it, this patch tries log allocation first and then others.

As a result of this change,
"--alloc anywhere" for mirror with log on the same device also starts
working. (It currently doesn't.)

Moving auto variables initialization after "restart" label
is not necessary but for avoiding future problem.


Thanks,
-- 
Jun'ichi Nomura, NEC Corporation of America

This patch allows log allocation first to fix the problems that
lvconvert from linear to mirror and lvconvert from corelog to disklog
may allocate log from the same PV as mirror images.

What is the problem?
  - Different (stronger) constraint should be applied to log area.
    i.e. log must avoid all parallel areas, not only the ones
    corresponding to the current LE.
    In other words, _find_parallel_space() should use ah->parallel_areas
    as whole for log allocation constraint. Whereas the part of it
    (parallel_pvs) is used for the other allocation.

To fix it, this patch tries log allocation first and then others.

As a result of this change,
"--alloc anywhere" for mirror with log on the same device also starts
working. (It currently doesn't.)

Moving auto variables initialization after "restart" label
is not necessary but for avoiding future problem.


Index: LVM2.02.17/lib/metadata/lv_manip.c
===================================================================
--- LVM2.02.17.orig/lib/metadata/lv_manip.c	2007-01-06 01:27:08.000000000 -0500
+++ LVM2.02.17/lib/metadata/lv_manip.c	2007-01-06 01:33:40.000000000 -0500
@@ -644,8 +644,7 @@ static int _alloc_log_area(struct alloc_
  * The part used is removed from the pv_map so it can't be allocated twice.
  */
 static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
-				struct pv_area **areas,
-				uint32_t *ix, struct pv_area *log_area)
+				struct pv_area **areas, uint32_t *ix)
 {
 	uint32_t area_len, remaining;
 	uint32_t s;
@@ -675,9 +674,6 @@ static int _alloc_parallel_area(struct a
 	ah->total_area_len += area_len;
 	*ix += area_len * ah->area_multiple;
 
-	if (log_area)
-		_allocate_log_area(ah, log_area);
-
 	return 1;
 }
 
@@ -898,15 +894,25 @@ static int _find_parallel_space(struct a
 	struct pv_map *pvm;
 	struct pv_area *pva;
 	struct pv_list *pvl;
-	unsigned already_found_one = 0;
-	unsigned contiguous = 0, cling = 0, preferred_count = 0;
+	unsigned already_found_one;
+	unsigned contiguous, cling, preferred_count;
 	unsigned ix;
-	unsigned ix_offset = 0;	/* Offset for non-preferred allocations */
+	unsigned ix_offset;	/* Offset for non-preferred allocations */
 	uint32_t max_parallel;	/* Maximum extents to allocate */
 	uint32_t next_le;
 	struct seg_pvs *spvs;
 	struct list *parallel_pvs;
 	uint32_t free_pes;
+	uint32_t needed_areas;
+
+      restart: /* when log allocation is done first */
+	contiguous = cling = 0;
+	ix_offset = preferred_count = 0;
+
+	if (allocating_log(ah))
+		needed_areas = ah->log_count;
+	else
+		needed_areas = ah->area_count;
 
 	/* Is there enough total space? */
 	free_pes = pv_maps_size(pvms);
@@ -917,10 +923,8 @@ static int _find_parallel_space(struct a
 		return 0;
 	}
 
-	/* FIXME Select log PV appropriately if there isn't one yet */
-
 	/* Are there any preceding segments we must follow on from? */
-	if (prev_lvseg) {
+	if (!allocating_log(ah) && prev_lvseg) {
 		ix_offset = prev_lvseg->area_count;
 		if ((alloc == ALLOC_CONTIGUOUS))
 			contiguous = 1;
@@ -945,7 +949,7 @@ static int _find_parallel_space(struct a
 		 * If there are existing parallel PVs, avoid them and reduce
 		 * the maximum we can allocate in one go accordingly.
 		 */
-		if (ah->parallel_areas) {
+		if (!allocating_log(ah) && ah->parallel_areas) {
 			next_le = (prev_lvseg ? prev_lvseg->le + prev_lvseg->len : 0) + *allocated / ah->area_multiple;
 			list_iterate_items(spvs, ah->parallel_areas) {
 				if (next_le >= spvs->le + spvs->len)
@@ -975,10 +979,19 @@ static int _find_parallel_space(struct a
 					continue;	/* Next PV */
 
 				/* Avoid PVs used by existing parallel areas */
-				if (parallel_pvs)
+				if (parallel_pvs) {
 					list_iterate_items(pvl, parallel_pvs)
 						if (pvm->pv == pvl->pv)
 							goto next_pv;
+				} else if (allocating_log(ah) &&
+					   ah->parallel_areas) {
+					list_iterate_items(spvs,
+							   ah->parallel_areas)
+						list_iterate_items(pvl,
+								   &spvs->pvs)
+							if (pvm->pv == pvl->pv)
+								goto next_pv;
+				}
 			}
 
 			already_found_one = 0;
@@ -1008,9 +1021,19 @@ static int _find_parallel_space(struct a
 				}
 
 				/* Is it big enough on its own? */
-				if (pva->count * ah->area_multiple <
+				/*
+				 * The condition is read as:
+				 * 1) Take any sized area for log
+				 * 2) Take the area if it's large enough
+				 * 3) Take the area if split is allowed
+				 *    and it's the first one found
+				 *        or ALLOC_ANYWHERE
+				 * Otherwise, skip this PV.
+				 */
+				if (!allocating_log(ah) &&
+				    pva->count * ah->area_multiple <
 				    max_parallel - *allocated &&
-				    ((!can_split && !ah->log_count) ||
+				    (!can_split ||
 				     (already_found_one &&
 				      !(alloc == ALLOC_ANYWHERE))))
 					goto next_pv;
@@ -1033,10 +1056,7 @@ static int _find_parallel_space(struct a
 		if ((contiguous || cling) && (preferred_count < ix_offset))
 			break;
 
-		/* Only allocate log_area the first time around */
-		if (ix + ix_offset < ah->area_count +
-			    ((ah->log_count && !ah->log_area.len) ?
-				ah->log_count : 0))
+		if (ix + ix_offset < needed_areas)
 			/* FIXME With ALLOC_ANYWHERE, need to split areas */
 			break;
 
@@ -1046,12 +1066,15 @@ static int _find_parallel_space(struct a
 			      _comp_area);
 
 		/* First time around, use smallest area as log_area */
-		/* FIXME decide which PV to use at top of function instead */
-		if (!_alloc_parallel_area(ah, max_parallel, areas,
-					  allocated,
-					  (ah->log_count && !ah->log_area.len) ?
-						*(areas + ix_offset + ix - 1) :
-						NULL)) {
+		if (allocating_log(ah)) {
+			if (!_alloc_log_area(ah, *(areas + ix_offset + ix - 1))) {
+				stack;
+				return 0;
+			}
+			/* log_area is allocated, restart for remainder */
+			goto restart;
+		} else if (!_alloc_parallel_area(ah, max_parallel, areas,
+						 allocated)) {
 			stack;
 			return 0;
 		}

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