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];
};
@@ -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;
/* 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;
- 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;
+ }
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;
/* 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 (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;
}