[dm-devel] [PATCH 1 of 10] LVM: agk allocation changes

Jonathan Brassow jbrassow at redhat.com
Fri Feb 26 23:35:49 UTC 2010


Patch name: lvm-agk-allocation-changes.patch

agk's allocation changes...

Index: LVM2/lib/metadata/lv_alloc.h
===================================================================
--- LVM2.orig/lib/metadata/lv_alloc.h
+++ LVM2/lib/metadata/lv_alloc.h
@@ -58,8 +58,7 @@ int lv_add_segment(struct alloc_handle *
                    const struct segment_type *segtype,
                    uint32_t stripe_size,
                    uint64_t status,
-		   uint32_t region_size,
-                   struct logical_volume *log_lv);
+		   uint32_t region_size);
 
 int lv_add_mirror_areas(struct alloc_handle *ah,
 			struct logical_volume *lv, uint32_t le,
Index: LVM2/lib/metadata/lv_manip.c
===================================================================
--- LVM2.orig/lib/metadata/lv_manip.c
+++ LVM2/lib/metadata/lv_manip.c
@@ -507,16 +507,21 @@ struct alloc_handle {
 	struct dm_pool *mem;
 
 	alloc_policy_t alloc;		/* Overall policy */
+	uint32_t new_extents;		/* Number of new extents required */
 	uint32_t area_count;		/* Number of parallel areas */
 	uint32_t area_multiple;		/* seg->len = area_len * area_multiple */
-	uint32_t log_count;		/* Number of parallel 1-extent logs */
-	uint32_t log_region_size;	/* region size for log device */
+	uint32_t log_area_count;	/* Number of parallel logs */
+	uint32_t log_len;		/* Length of log */
+	uint32_t region_size;		/* Mirror region size */
 	uint32_t total_area_len;	/* Total number of parallel extents */
 
 	struct dm_list *parallel_areas;	/* PVs to avoid */
 
-	struct alloced_area log_area;	/* Extent used for log */
-	struct dm_list alloced_areas[0];	/* Lists of areas in each stripe */
+	/*
+	 * Contains area_count lists of areas allocated to data stripes
+	 * followed by log_area_count lists of areas allocated to log stripes.
+	 */
+	struct dm_list alloced_areas[0];
 };
 
 static uint32_t calc_area_multiple(const struct segment_type *segtype,
@@ -529,16 +534,40 @@ static uint32_t calc_area_multiple(const
 }
 
 /*
+ * Returns log device size in extents, algorithm from kernel code
+ */
+#define BYTE_SHIFT 3
+static uint32_t mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint32_t area_len)
+{
+	size_t area_size, bitset_size, log_size, region_count;
+
+	area_size = area_len * pe_size;
+	region_count = dm_div_up(area_size, region_size);
+
+	/* Work out how many "unsigned long"s we need to hold the bitset. */
+	bitset_size = dm_round_up(region_count, sizeof(uint32_t) << BYTE_SHIFT);
+	bitset_size >>= BYTE_SHIFT;
+
+	/* Log device holds both header and bitset. */
+	log_size = dm_round_up((MIRROR_LOG_OFFSET << SECTOR_SHIFT) + bitset_size, 1 << SECTOR_SHIFT);
+	log_size >>= SECTOR_SHIFT;
+
+	return dm_div_up(log_size, pe_size);
+}
+
+/*
  * Preparation for a specific allocation attempt
  */
 static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
 					struct dm_pool *mem,
 					const struct segment_type *segtype,
 					alloc_policy_t alloc,
+					uint32_t new_extents,
 					uint32_t mirrors,
 					uint32_t stripes,
-					uint32_t log_count,
-					uint32_t log_region_size,
+					uint32_t log_area_count,
+					uint32_t extent_size,
+					uint32_t region_size,
 					struct dm_list *parallel_areas)
 {
 	struct alloc_handle *ah;
@@ -549,7 +578,7 @@ static struct alloc_handle *_alloc_init(
 		return NULL;
 	}
 
-	if (log_count && stripes > 1) {
+	if (log_area_count && stripes > 1) {
 		log_error("Can't mix striping with a mirror log yet.");
 		return NULL;
 	}
@@ -561,7 +590,7 @@ static struct alloc_handle *_alloc_init(
 	else
 		area_count = stripes;
 
-	if (!(ah = dm_pool_zalloc(mem, sizeof(*ah) + sizeof(ah->alloced_areas[0]) * area_count))) {
+	if (!(ah = dm_pool_zalloc(mem, sizeof(*ah) + sizeof(ah->alloced_areas[0]) * (area_count + log_area_count)))) {
 		log_error("allocation handle allocation failed");
 		return NULL;
 	}
@@ -576,13 +605,16 @@ static struct alloc_handle *_alloc_init(
 		return NULL;
 	}
 
+	ah->new_extents = new_extents;
 	ah->area_count = area_count;
-	ah->log_count = log_count;
-	ah->log_region_size = log_region_size;
+	ah->log_area_count = log_area_count;
+	ah->region_size = region_size;
 	ah->alloc = alloc;
 	ah->area_multiple = calc_area_multiple(segtype, area_count);
 
-	for (s = 0; s < ah->area_count; s++)
+	ah->log_len = log_area_count ? mirror_log_extents(ah->region_size, extent_size, ah->new_extents / ah->area_multiple) : 0;
+
+	for (s = 0; s < ah->area_count + ah->log_area_count; s++)
 		dm_list_init(&ah->alloced_areas[s]);
 
 	ah->parallel_areas = parallel_areas;
@@ -644,15 +676,13 @@ static int _setup_alloced_segment(struct
 				  uint32_t stripe_size,
 				  const struct segment_type *segtype,
 				  struct alloced_area *aa,
-				  uint32_t region_size,
-				  struct logical_volume *log_lv __attribute((unused)))
+				  uint32_t region_size)
 {
 	uint32_t s, extents, area_multiple;
 	struct lv_segment *seg;
 
 	area_multiple = calc_area_multiple(segtype, area_count);
 
-	/* log_lv gets set up elsehere */
 	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
 				     lv->le_count,
 				     aa[0].len * area_multiple,
@@ -685,15 +715,14 @@ static int _setup_alloced_segments(struc
 				   uint64_t status,
 				   uint32_t stripe_size,
 				   const struct segment_type *segtype,
-				   uint32_t region_size,
-				   struct logical_volume *log_lv)
+				   uint32_t region_size)
 {
 	struct alloced_area *aa;
 
 	dm_list_iterate_items(aa, &alloced_areas[0]) {
 		if (!_setup_alloced_segment(lv, status, area_count,
 					    stripe_size, segtype, aa,
-					    region_size, log_lv))
+					    region_size))
 			return_0;
 	}
 
@@ -701,42 +730,21 @@ static int _setup_alloced_segments(struc
 }
 
 /*
- * Returns log device size in extents, algorithm from kernel code
- */
-#define BYTE_SHIFT 3
-static uint32_t mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint32_t area_len)
-{
-	size_t area_size, bitset_size, log_size, region_count;
-
-	area_size = area_len * pe_size;
-	region_count = dm_div_up(area_size, region_size);
-
-	/* Work out how many "unsigned long"s we need to hold the bitset. */
-	bitset_size = dm_round_up(region_count, sizeof(uint32_t) << BYTE_SHIFT);
-	bitset_size >>= BYTE_SHIFT;
-
-	/* Log device holds both header and bitset. */
-	log_size = dm_round_up((MIRROR_LOG_OFFSET << SECTOR_SHIFT) + bitset_size, 1 << SECTOR_SHIFT);
-	log_size >>= SECTOR_SHIFT;
-
-	return dm_div_up(log_size, pe_size);
-}
-
-/*
  * This function takes a list of pv_areas and adds them to allocated_areas.
  * If the complete area is not needed then it gets split.
  * 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,
-				uint32_t log_len)
+				struct pv_area **areas, uint32_t *allocated,
+				unsigned log_needs_allocating, uint32_t ix_log_offset)
 {
-	uint32_t area_len, remaining;
+	uint32_t area_len, len, remaining;
 	uint32_t s;
+	uint32_t ix_log_skip = 0; /* How many areas to skip in middle of array to reach log areas */
+	uint32_t total_area_count = ah->area_count + (log_needs_allocating ? ah->log_area_count : 0);
 	struct alloced_area *aa;
 
-	remaining = needed - *ix;
+	remaining = needed - *allocated;
 	area_len = remaining / ah->area_multiple;
 
 	/* Reduce area_len to the smallest of the areas */
@@ -744,32 +752,35 @@ static int _alloc_parallel_area(struct a
 		if (area_len > areas[s]->count)
 			area_len = areas[s]->count;
 
-	if (!(aa = dm_pool_alloc(ah->mem, sizeof(*aa) *
-			      (ah->area_count + (log_area ? 1 : 0))))) {
+	if (!(aa = dm_pool_alloc(ah->mem, sizeof(*aa) * total_area_count))) {
 		log_error("alloced_area allocation failed");
 		return 0;
 	}
 
-	for (s = 0; s < ah->area_count; s++) {
-		aa[s].pv = areas[s]->map->pv;
-		aa[s].pe = areas[s]->start;
-		aa[s].len = area_len;
-		dm_list_add(&ah->alloced_areas[s], &aa[s].list);
-	}
+	/*
+	 * Areas consists of area_count areas for data stripes, then
+	 * ix_log_skip areas to skip, then log_area_count areas to use for the
+	 * log, then some areas too small for the log.
+	 */
+	len = area_len;
+	for (s = 0; s < total_area_count; s++) {
+		if (s == ah->area_count) {
+			ix_log_skip = ix_log_offset - ah->area_count;
+			len = ah->log_len;
+		}
 
-	ah->total_area_len += area_len;
+		aa[s].pv = areas[s + ix_log_skip]->map->pv;
+		aa[s].pe = areas[s + ix_log_skip]->start;
+		aa[s].len = len;
 
-	for (s = 0; s < ah->area_count; s++)
-		consume_pv_area(areas[s], area_len);
+		consume_pv_area(areas[s + ix_log_skip], len);
 
-	if (log_area) {
-		ah->log_area.pv = log_area->map->pv;
-		ah->log_area.pe = log_area->start;
-		ah->log_area.len = log_len;
-		consume_pv_area(log_area, ah->log_area.len);
+		dm_list_add(&ah->alloced_areas[s], &aa[s].list);
 	}
 
-	*ix += area_len * ah->area_multiple;
+	ah->total_area_len += area_len;
+
+	*allocated += area_len * ah->area_multiple;
 
 	return 1;
 }
@@ -990,15 +1001,16 @@ static int _find_parallel_space(struct a
 	unsigned contiguous = 0, cling = 0, preferred_count = 0;
 	unsigned ix;
 	unsigned ix_offset = 0;	/* Offset for non-preferred allocations */
+	unsigned ix_log_offset; /* Offset to start of areas to use for log */
 	unsigned too_small_for_log_count; /* How many too small for log? */
 	uint32_t max_parallel;	/* Maximum extents to allocate */
 	uint32_t next_le;
 	struct seg_pvs *spvs;
 	struct dm_list *parallel_pvs;
 	uint32_t free_pes;
-	uint32_t log_len;
-	struct pv_area *log_area;
 	unsigned log_needs_allocating;
+	struct alloced_area *aa;
+	uint32_t s;
 
 	/* Is there enough total space? */
 	free_pes = pv_maps_size(pvms);
@@ -1062,9 +1074,11 @@ static int _find_parallel_space(struct a
 
 			if (alloc != ALLOC_ANYWHERE) {
 				/* Don't allocate onto the log pv */
-				if (ah->log_count &&
-				    pvm->pv == ah->log_area.pv)
-					continue;	/* Next PV */
+				if (ah->log_area_count)
+					dm_list_iterate_items(aa, &ah->alloced_areas[ah->area_count])
+						for (s = 0; s < ah->log_area_count; s++)
+							if (!aa[s].pv)
+								goto next_pv;
 
 				/* Avoid PVs used by existing parallel areas */
 				if (parallel_pvs)
@@ -1102,7 +1116,7 @@ static int _find_parallel_space(struct a
 				/* Is it big enough on its own? */
 				if (pva->count * ah->area_multiple <
 				    max_parallel - *allocated &&
-				    ((!can_split && !ah->log_count) ||
+				    ((!can_split && !ah->log_area_count) ||
 				     (already_found_one &&
 				      !(alloc == ALLOC_ANYWHERE))))
 					goto next_pv;
@@ -1123,11 +1137,11 @@ static int _find_parallel_space(struct a
 		if ((contiguous || cling) && (preferred_count < ix_offset))
 			break;
 
-		log_needs_allocating = (ah->log_count && !ah->log_area.len) ?
-				       1 : 0;
+		log_needs_allocating = (ah->log_area_count &&
+					dm_list_empty(&ah->alloced_areas[ah->area_count])) ?  1 : 0;
 
 		if (ix + ix_offset < ah->area_count +
-		   (log_needs_allocating ? ah->log_count : 0))
+		   (log_needs_allocating ? ah->log_area_count : 0))
 			break;
 
 		/* sort the areas so we allocate from the biggest */
@@ -1138,38 +1152,28 @@ static int _find_parallel_space(struct a
 		/*
 		 * First time around, if there's a log, allocate it on the
 		 * smallest device that has space for it.
-		 *
-		 * FIXME decide which PV to use at top of function instead
 		 */
-
 		too_small_for_log_count = 0;
+		ix_log_offset = 0;
 
-		if (!log_needs_allocating) {
-			log_len = 0;
-			log_area = NULL;
-		} else {
-			log_len = mirror_log_extents(ah->log_region_size,
-			    pv_pe_size((*areas)->map->pv),
-			    (max_parallel - *allocated) / ah->area_multiple);
-
+		/* FIXME This logic is due to its heritage and can be simplified! */
+		if (log_needs_allocating) {
 			/* How many areas are too small for the log? */
 			while (too_small_for_log_count < ix_offset + ix &&
 			       (*(areas + ix_offset + ix - 1 -
-				  too_small_for_log_count))->count < log_len)
+				  too_small_for_log_count))->count < ah->log_len)
 				too_small_for_log_count++;
-
-			log_area = *(areas + ix_offset + ix - 1 -
-				     too_small_for_log_count);
+			ix_log_offset = ix_offset + ix - too_small_for_log_count - ah->log_area_count;
 		}
 
 		if (ix + ix_offset < ah->area_count +
-		    (log_needs_allocating ? ah->log_count +
+		    (log_needs_allocating ? ah->log_area_count +
 					    too_small_for_log_count : 0))
 			/* FIXME With ALLOC_ANYWHERE, need to split areas */
 			break;
 
 		if (!_alloc_parallel_area(ah, max_parallel, areas, allocated,
-					  log_area, log_len))
+					  log_needs_allocating, ix_log_offset))
 			return_0;
 
 	} while (!contiguous && *allocated != needed && can_split);
@@ -1185,7 +1189,6 @@ static int _find_parallel_space(struct a
 static int _allocate(struct alloc_handle *ah,
 		     struct volume_group *vg,
 		     struct logical_volume *lv,
-		     uint32_t new_extents,
 		     unsigned can_split,
 		     struct dm_list *allocatable_pvs)
 {
@@ -1197,8 +1200,9 @@ static int _allocate(struct alloc_handle
 	struct dm_list *pvms;
 	uint32_t areas_size;
 	alloc_policy_t alloc;
+	struct alloced_area *aa;
 
-	if (allocated >= new_extents && !ah->log_count) {
+	if (allocated >= ah->new_extents && !ah->log_area_count) {
 		log_error("_allocate called with no work to do!");
 		return 1;
 	}
@@ -1219,14 +1223,14 @@ static int _allocate(struct alloc_handle
 		stack;
 
 	areas_size = dm_list_size(pvms);
-	if (areas_size && areas_size < (ah->area_count + ah->log_count)) {
+	if (areas_size && areas_size < (ah->area_count + ah->log_area_count)) {
 		if (ah->alloc != ALLOC_ANYWHERE) {
 			log_error("Not enough PVs with free space available "
 				  "for parallel allocation.");
 			log_error("Consider --alloc anywhere if desperate.");
 			return 0;
 		}
-		areas_size = ah->area_count + ah->log_count;
+		areas_size = ah->area_count + ah->log_area_count;
 	}
 
 	/* Upper bound if none of the PVs in prev_lvseg is in pvms */
@@ -1245,29 +1249,31 @@ static int _allocate(struct alloc_handle
 		old_allocated = allocated;
 		if (!_find_parallel_space(ah, alloc, pvms, areas,
 					  areas_size, can_split,
-					  prev_lvseg, &allocated, new_extents))
+					  prev_lvseg, &allocated, ah->new_extents))
 			goto_out;
-		if ((allocated == new_extents) || (ah->alloc == alloc) ||
+		if ((allocated == ah->new_extents) || (ah->alloc == alloc) ||
 		    (!can_split && (allocated != old_allocated)))
 			break;
 	}
 
-	if (allocated != new_extents) {
+	if (allocated != ah->new_extents) {
 		log_error("Insufficient suitable %sallocatable extents "
 			  "for logical volume %s: %u more required",
 			  can_split ? "" : "contiguous ",
 			  lv ? lv->name : "",
-			  (new_extents - allocated) * ah->area_count
+			  (ah->new_extents - allocated) * ah->area_count
 			  / ah->area_multiple);
 		goto out;
 	}
 
-	if (ah->log_count && !ah->log_area.len) {
-		log_error("Insufficient extents for log allocation "
-			  "for logical volume %s.",
-			  lv ? lv->name : "");
-		goto out;
-	}
+	if (ah->log_area_count)
+		dm_list_iterate_items(aa, &ah->alloced_areas[ah->area_count])
+			if (!aa[0].pv) {
+				log_error("Insufficient extents for log allocation "
+					  "for logical volume %s.",
+					  lv ? lv->name : "");
+				goto out;
+			}
 
 	r = 1;
 
@@ -1306,12 +1312,13 @@ struct alloc_handle *allocate_extents(st
 				      const struct segment_type *segtype,
 				      uint32_t stripes,
 				      uint32_t mirrors, uint32_t log_count,
-				      uint32_t log_region_size, uint32_t extents,
+				      uint32_t region_size, uint32_t extents,
 				      struct dm_list *allocatable_pvs,
 				      alloc_policy_t alloc,
 				      struct dm_list *parallel_areas)
 {
 	struct alloc_handle *ah;
+	uint32_t new_extents;
 
 	if (segtype_is_virtual(segtype)) {
 		log_error("allocate_extents does not handle virtual segments");
@@ -1331,13 +1338,15 @@ struct alloc_handle *allocate_extents(st
 	if (alloc == ALLOC_INHERIT)
 		alloc = vg->alloc;
 
-	if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc, mirrors,
-			       stripes, log_count, log_region_size, parallel_areas)))
+	new_extents = (lv ? lv->le_count : 0) + extents;
+	if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc,
+			       new_extents, mirrors, stripes, log_count,
+			       vg->extent_size, region_size,
+			       parallel_areas)))
 		return_NULL;
 
 	if (!segtype_is_virtual(segtype) &&
-	    !_allocate(ah, vg, lv, (lv ? lv->le_count : 0) + extents,
-		       1, allocatable_pvs)) {
+	    !_allocate(ah, vg, lv, 1, allocatable_pvs)) {
 		alloc_destroy(ah);
 		return_NULL;
 	}
@@ -1354,8 +1363,7 @@ int lv_add_segment(struct alloc_handle *
 		   const struct segment_type *segtype,
 		   uint32_t stripe_size,
 		   uint64_t status,
-		   uint32_t region_size,
-		   struct logical_volume *log_lv)
+		   uint32_t region_size)
 {
 	if (!segtype) {
 		log_error("Missing segtype in lv_add_segment().");
@@ -1367,10 +1375,15 @@ int lv_add_segment(struct alloc_handle *
 		return 0;
 	}
 
+	if ((status & MIRROR_LOG) && dm_list_size(&lv->segments)) {
+		log_error("Log segments can only be added to an empty LV");
+		return 0;
+	}
+
 	if (!_setup_alloced_segments(lv, &ah->alloced_areas[first_area],
 				     num_areas, status,
 				     stripe_size, segtype,
-				     region_size, log_lv))
+				     region_size))
 		return_0;
 
 	if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) {
@@ -1546,34 +1559,11 @@ int lv_add_mirror_lvs(struct logical_vol
  */
 int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv)
 {
-	struct lv_segment *seg;
+	const char *segtype_name = ah->log_area_count > 1 ? "mirror" : "striped";
 
-	if (dm_list_size(&log_lv->segments)) {
-		log_error("Log segments can only be added to an empty LV");
-		return 0;
-	}
-
-	if (!(seg = alloc_lv_segment(log_lv->vg->cmd->mem,
-				     get_segtype_from_string(log_lv->vg->cmd,
-							     "striped"),
-				     log_lv, 0, ah->log_area.len, MIRROR_LOG,
-				     0, NULL, 1, ah->log_area.len, 0, 0, 0))) {
-		log_error("Couldn't allocate new mirror log segment.");
-		return 0;
-	}
-
-	if (!set_lv_segment_area_pv(seg, 0, ah->log_area.pv, ah->log_area.pe))
-		return_0;
-
-	dm_list_add(&log_lv->segments, &seg->list);
-	log_lv->le_count += ah->log_area.len;
-	log_lv->size += (uint64_t) log_lv->le_count * log_lv->vg->extent_size;
-
-	if (log_lv->vg->fid->fmt->ops->lv_setup &&
-	    !log_lv->vg->fid->fmt->ops->lv_setup(log_lv->vg->fid, log_lv))
-		return_0;
-
-	return 1;
+	return lv_add_segment(ah, ah->area_count, ah->log_area_count, log_lv,
+			      get_segtype_from_string(log_lv->vg->cmd, segtype_name),
+			      0, MIRROR_LOG, 0);
 }
 
 static int _lv_extend_mirror(struct alloc_handle *ah,
@@ -1595,7 +1585,7 @@ static int _lv_extend_mirror(struct allo
 		if (!lv_add_segment(ah, m++, 1, seg_lv(seg, s),
 				    get_segtype_from_string(lv->vg->cmd,
 							    "striped"),
-				    0, 0, 0, NULL)) {
+				    0, 0, 0)) {
 			log_error("Aborting. Failed to extend %s.",
 				  seg_lv(seg, s)->name);
 			return 0;
@@ -1633,7 +1623,7 @@ int lv_extend(struct logical_volume *lv,
 
 	if (mirrors < 2)
 		r = lv_add_segment(ah, 0, ah->area_count, lv, segtype,
-				   stripe_size, status, 0, NULL);
+				   stripe_size, status, 0);
 	else
 		r = _lv_extend_mirror(ah, lv, extents, 0);
 
Index: LVM2/lib/metadata/mirror.c
===================================================================
--- LVM2.orig/lib/metadata/mirror.c
+++ LVM2/lib/metadata/mirror.c
@@ -1202,7 +1202,7 @@ static int _create_mimage_lvs(struct all
 		if (!lv_add_segment(ah, m, 1, img_lvs[m],
 				    get_segtype_from_string(lv->vg->cmd,
 							    "striped"),
-				    0, 0, 0, NULL)) {
+				    0, 0, 0)) {
 			log_error("Aborting. Failed to add mirror image segment "
 				  "to %s. Remove new LV and retry.",
 				  img_lvs[m]->name);




More information about the dm-devel mailing list