mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
Determine parallel PVs to avoid with ALLOC_NORMAL allocation. (untested)
This commit is contained in:
parent
e3195fecf1
commit
c27920b1ca
@ -1,5 +1,6 @@
|
||||
Version 2.02.02
|
||||
====================================
|
||||
Determine parallel PVs to avoid with ALLOC_NORMAL allocation.
|
||||
Fix lv_empty.
|
||||
|
||||
Version 2.02.01 - 23rd November 2005
|
||||
|
@ -24,6 +24,18 @@
|
||||
#include "display.h"
|
||||
#include "segtype.h"
|
||||
|
||||
/*
|
||||
* PVs used by a segment of an LV
|
||||
*/
|
||||
struct seg_pvs {
|
||||
struct list list;
|
||||
|
||||
struct list pvs; /* struct pv_list */
|
||||
|
||||
uint32_t le;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
/*
|
||||
* Find first unused LV number.
|
||||
*/
|
||||
@ -659,13 +671,11 @@ static int _check_contiguous(struct lv_segment *prev_lvseg,
|
||||
/*
|
||||
* Choose sets of parallel areas to use, respecting any constraints.
|
||||
*/
|
||||
/* FIXME Also accept existing areas new space must be parallel to */
|
||||
static int _find_segment_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
struct list *pvms, struct pv_area **areas,
|
||||
uint32_t areas_size, unsigned can_split,
|
||||
struct lv_segment *prev_lvseg,
|
||||
uint32_t *allocated, uint32_t needed,
|
||||
struct list *parallel_pvs)
|
||||
static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
struct list *pvms, struct pv_area **areas,
|
||||
uint32_t areas_size, unsigned can_split,
|
||||
struct lv_segment *prev_lvseg,
|
||||
uint32_t *allocated, uint32_t needed)
|
||||
{
|
||||
struct pv_map *pvm;
|
||||
struct pv_area *pva;
|
||||
@ -674,6 +684,10 @@ static int _find_segment_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
unsigned contiguous = 0, contiguous_count = 0;
|
||||
unsigned ix;
|
||||
unsigned ix_offset = 0; /* Offset for non-contiguous allocations */
|
||||
uint32_t max_parallel; /* Maximum extents to allocate */
|
||||
uint32_t next_le;
|
||||
struct seg_pvs *spvs;
|
||||
struct list *parallel_pvs;
|
||||
|
||||
/* FIXME Do calculations on free extent counts before selecting space */
|
||||
/* FIXME Select log PV appropriately if there isn't one yet */
|
||||
@ -691,6 +705,25 @@ static int _find_segment_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
do {
|
||||
ix = 0;
|
||||
|
||||
parallel_pvs = NULL;
|
||||
max_parallel = needed;
|
||||
|
||||
/*
|
||||
* If there are existing parallel PVs, avoid them and reduce
|
||||
* the maximum we can allocate in one go accordingly.
|
||||
*/
|
||||
if (ah->parallel_areas) {
|
||||
list_iterate_items(spvs, ah->parallel_areas) {
|
||||
next_le = (prev_lvseg ? prev_lvseg->le + prev_lvseg->len : 0) + *allocated;
|
||||
if (next_le >= spvs->le) {
|
||||
if (next_le + max_parallel > spvs->le + spvs->len)
|
||||
max_parallel = spvs->le + spvs->len - next_le;
|
||||
parallel_pvs = &spvs->pvs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the smallest area of each PV that is at least the
|
||||
* size we need into areas array. If there isn't one
|
||||
@ -729,7 +762,7 @@ static int _find_segment_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
}
|
||||
|
||||
/* Is it big enough on its own? */
|
||||
if ((pva->count < needed - *allocated) &&
|
||||
if ((pva->count < max_parallel - *allocated) &&
|
||||
((!can_split && !ah->log_count) ||
|
||||
(already_found_one &&
|
||||
!(alloc == ALLOC_ANYWHERE))))
|
||||
@ -767,7 +800,7 @@ static int _find_segment_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
|
||||
/* 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, needed, areas,
|
||||
if (!_alloc_parallel_area(ah, max_parallel, areas,
|
||||
allocated,
|
||||
(ah->log_count && !ah->log_area.len) ?
|
||||
*(areas + ix_offset + ix - 1) :
|
||||
@ -781,17 +814,6 @@ static int _find_segment_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
struct list *pvms, struct pv_area **areas,
|
||||
uint32_t areas_size, unsigned can_split,
|
||||
struct lv_segment *prev_lvseg,
|
||||
uint32_t *allocated, uint32_t needed)
|
||||
{
|
||||
return _find_segment_space(ah, alloc, pvms, areas, areas_size,
|
||||
can_split, prev_lvseg,
|
||||
allocated, needed, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate several segments, each the same size, in parallel.
|
||||
* If mirrored_pv and mirrored_pe are supplied, it is used as
|
||||
@ -1306,6 +1328,74 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
return lv;
|
||||
}
|
||||
|
||||
/* Recursively process each PV used by part of an LV */
|
||||
static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint32_t le, uint32_t len,
|
||||
int (*fn)(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs),
|
||||
struct seg_pvs *spvs)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
uint32_t remaining_seg_len, area_len, area_multiple;
|
||||
|
||||
if (!(seg = find_seg_by_le(lv, le))) {
|
||||
log_error("Failed to find segment for %s extent %" PRIu32,
|
||||
lv->name, le);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remaining logical length of segment */
|
||||
remaining_seg_len = seg->len - (le - seg->le);
|
||||
|
||||
if (len > remaining_seg_len)
|
||||
remaining_seg_len = len;
|
||||
|
||||
if (spvs->len > remaining_seg_len)
|
||||
spvs->len = remaining_seg_len;
|
||||
|
||||
area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
|
||||
area_len = remaining_seg_len / area_multiple;
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg_type(seg, s) == AREA_LV) {
|
||||
if (!_for_each_pv(cmd, seg_lv(seg, s),
|
||||
seg_le(seg, s) + (le - seg->le) / area_multiple,
|
||||
area_len, fn, spvs)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
} else if (seg_type(seg, s) == AREA_PV) {
|
||||
if (!fn(cmd, seg_pvseg(seg, s), spvs)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
|
||||
/* FIXME Don't add again if it's already on the list! */
|
||||
|
||||
if (!(pvl = dm_pool_alloc(cmd->mem, sizeof(*pvl)))) {
|
||||
log_error("pv_list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pvl->pv = peg->pv;
|
||||
|
||||
/* FIXME Use ordered list to facilitate comparison */
|
||||
list_add(&spvs->pvs, &pvl->list);
|
||||
|
||||
/* FIXME Add mirror logs, snapshot cow LVs etc. */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct list of segments of LVs showing which PVs they use.
|
||||
*/
|
||||
@ -1313,6 +1403,8 @@ struct list *build_parallel_areas_from_lv(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
struct list *parallel_areas;
|
||||
struct seg_pvs *spvs;
|
||||
uint32_t current_le = 0;
|
||||
|
||||
if (!(parallel_areas = dm_pool_alloc(cmd->mem, sizeof(*parallel_areas)))) {
|
||||
log_error("parallel_areas allocation failed");
|
||||
@ -1321,5 +1413,30 @@ struct list *build_parallel_areas_from_lv(struct cmd_context *cmd,
|
||||
|
||||
list_init(parallel_areas);
|
||||
|
||||
do {
|
||||
if (!(spvs = dm_pool_zalloc(cmd->mem, sizeof(*spvs)))) {
|
||||
log_error("allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(&spvs->pvs);
|
||||
|
||||
spvs->le = current_le;
|
||||
spvs->len = lv->le_count - current_le;
|
||||
|
||||
list_add(parallel_areas, &spvs->list);
|
||||
|
||||
/* Find next segment end */
|
||||
/* FIXME Unnecessary nesting! */
|
||||
if (!_for_each_pv(cmd, lv, current_le, lv->le_count, _add_pvs, spvs)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
current_le = spvs->le + spvs->len;
|
||||
} while (current_le < lv->le_count);
|
||||
|
||||
/* FIXME Merge adjacent segments with identical PV lists (avoids need for contiguous allocation attempts between successful allocations) */
|
||||
|
||||
return parallel_areas;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user