From de5c82a0d991e4c02819b1f71c9a2ab8143e01bb Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Sun, 8 Oct 2006 12:01:13 +0000 Subject: [PATCH] add cling allocation policy --- WHATS_NEW | 1 + lib/display/display.c | 1 + lib/metadata/lv_manip.c | 88 ++++++++++++++++++++++++++++++++++++----- lib/metadata/metadata.h | 1 + lib/report/report.c | 2 + man/lvm.8 | 13 +++--- 6 files changed, 91 insertions(+), 15 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index 5c33d9d18..d9100d6bf 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.11 - ===================================== + Add cling allocation policy. Change _check_contiguous() to use _for_each_pv(). Extend _for_each_pv() to allow termination without error. Abstract _is_contiguous(). diff --git a/lib/display/display.c b/lib/display/display.c index a7743f2a5..5b9cd640d 100644 --- a/lib/display/display.c +++ b/lib/display/display.c @@ -30,6 +30,7 @@ static struct { } _policies[] = { { ALLOC_CONTIGUOUS, "contiguous"}, { + ALLOC_CLING, "cling"}, { ALLOC_NORMAL, "normal"}, { ALLOC_ANYWHERE, "anywhere"}, { ALLOC_INHERIT, "inherit"} diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 0077a1024..54de8bd7f 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -772,6 +772,17 @@ struct pv_match { int s; /* Area index of match */ }; +/* + * Is PV area on the same PV? + */ +static int _is_same_pv(struct pv_segment *pvseg, struct pv_area *pva) +{ + if (pvseg->pv != pva->map->pv) + return 0; + + return 1; +} + /* * Is PV area contiguous to PV segment? */ @@ -786,9 +797,9 @@ static int _is_contiguous(struct pv_segment *pvseg, struct pv_area *pva) return 1; } -static int _is_contiguous_condition(struct cmd_context *cmd, - struct pv_segment *pvseg, uint32_t s, - void *data) +static int _is_condition(struct cmd_context *cmd, + struct pv_segment *pvseg, uint32_t s, + void *data) { struct pv_match *pvmatch = data; @@ -803,6 +814,34 @@ static int _is_contiguous_condition(struct cmd_context *cmd, return 2; /* Finished */ } +/* + * Is pva on same PV as any existing areas? + */ +static int _check_cling(struct cmd_context *cmd, + struct lv_segment *prev_lvseg, struct pv_area *pva, + struct pv_area **areas, uint32_t areas_size) +{ + struct pv_match pvmatch; + int r; + + pvmatch.condition = _is_same_pv; + pvmatch.areas = areas; + pvmatch.areas_size = areas_size; + pvmatch.pva = pva; + + /* FIXME Cope with stacks by flattening */ + if (!(r = _for_each_pv(cmd, prev_lvseg->lv, + prev_lvseg->le + prev_lvseg->len - 1, 1, NULL, + 0, 0, -1, 1, + _is_condition, &pvmatch))) + stack; + + if (r != 2) + return 0; + + return 1; +} + /* * Is pva contiguous to any existing areas or on the same PV? */ @@ -822,7 +861,7 @@ static int _check_contiguous(struct cmd_context *cmd, if (!(r = _for_each_pv(cmd, prev_lvseg->lv, prev_lvseg->le + prev_lvseg->len - 1, 1, NULL, 0, 0, -1, 1, - _is_contiguous_condition, &pvmatch))) + _is_condition, &pvmatch))) stack; if (r != 2) @@ -844,9 +883,9 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, struct pv_area *pva; struct pv_list *pvl; unsigned already_found_one = 0; - unsigned contiguous = 0, contiguous_count = 0; + unsigned contiguous = 0, cling = 0, preferred_count = 0; unsigned ix; - unsigned ix_offset = 0; /* Offset for non-contiguous allocations */ + unsigned ix_offset = 0; /* Offset for non-preferred allocations */ uint32_t max_parallel; /* Maximum extents to allocate */ uint32_t next_le; struct seg_pvs *spvs; @@ -856,9 +895,14 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, /* FIXME Select log PV appropriately if there isn't one yet */ /* Are there any preceding segments we must follow on from? */ - if ((alloc == ALLOC_CONTIGUOUS) && prev_lvseg) { - contiguous = 1; + if (prev_lvseg) { ix_offset = prev_lvseg->area_count; + if ((alloc == ALLOC_CONTIGUOUS)) + contiguous = 1; + else if ((alloc == ALLOC_CLING)) + cling = 1; + else + ix_offset = 0; } /* FIXME This algorithm needs a lot of cleaning up! */ @@ -867,6 +911,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, /* ix holds the number of areas found on other PVs */ do { ix = 0; + preferred_count = 0; parallel_pvs = NULL; max_parallel = needed; @@ -920,12 +965,23 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, prev_lvseg, pva, areas, areas_size)) { - contiguous_count++; + preferred_count++; goto next_pv; } continue; } + if (cling) { + if (prev_lvseg && + _check_cling(ah->cmd, + prev_lvseg, + pva, areas, + areas_size)) { + preferred_count++; + } + goto next_pv; + } + /* Is it big enough on its own? */ if (pva->count * ah->area_multiple < max_parallel - *allocated && @@ -949,7 +1005,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, break; } - if (contiguous && (contiguous_count < ix_offset)) + if ((contiguous || cling) && (preferred_count < ix_offset)) break; /* Only allocate log_area the first time around */ @@ -1058,6 +1114,18 @@ static int _allocate(struct alloc_handle *ah, (!can_split && (allocated != old_allocated))) goto finished; + old_allocated = allocated; + if (!_find_parallel_space(ah, ALLOC_CLING, pvms, areas, + areas_size, can_split, + prev_lvseg, &allocated, new_extents)) { + stack; + goto out; + } + + if ((allocated == new_extents) || (ah->alloc == ALLOC_CLING) || + (!can_split && (allocated != old_allocated))) + goto finished; + old_allocated = allocated; if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas, areas_size, can_split, diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index cead646a9..ac177089d 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -82,6 +82,7 @@ typedef enum { ALLOC_INVALID = 0, ALLOC_INHERIT, ALLOC_CONTIGUOUS, + ALLOC_CLING, ALLOC_NORMAL, ALLOC_ANYWHERE } alloc_policy_t; diff --git a/lib/report/report.c b/lib/report/report.c index 6a21f2a79..7cddb223f 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -104,6 +104,8 @@ static char _alloc_policy_char(alloc_policy_t alloc) switch (alloc) { case ALLOC_CONTIGUOUS: return 'c'; + case ALLOC_CLING: + return 'C'; case ALLOC_NORMAL: return 'n'; case ALLOC_ANYWHERE: diff --git a/man/lvm.8 b/man/lvm.8 index 5b98a61cf..eb2483c5d 100644 --- a/man/lvm.8 +++ b/man/lvm.8 @@ -136,7 +136,7 @@ Characters allowed in tags are: A-Z a-z 0-9 _ + . - Delete the tag \fBtag\fP from a PV, VG or LV, if it's present. .TP \fB--alloc AllocationPolicy\fP -The allocation policy to use: \fBcontiguous\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP. +The allocation policy to use: \fBcontiguous\fP, \fBcling\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP. When a command needs to allocate physical extents from the volume group, the allocation policy controls how they are chosen. Each volume group and logical volume has an allocation policy. @@ -146,15 +146,18 @@ physical volume. The default for a logical volume is \fBinherit\fP which applies the same policy as for the volume group. These policies can be changed using \fBlvchange\fP (8) and \fBvgchange\fP (8) or over-ridden on the command line of any command that performs allocation. -The \fBcontiguous\fP policy requires that new extents are adjacent to -existing extents. If there are sufficient free extents to satisfy +The \fBcontiguous\fP policy requires that new extents be placed adjacent +to existing extents. +The \fBcling\fP policy places new extents on the same physical +volume as existing extents in the same stripe of the Logical Volume. +If there are sufficient free extents to satisfy an allocation request but \fBnormal\fP doesn't use them, \fBanywhere\fP will - even if that reduces performance by placing two stripes on the same physical volume. .IP N.B. The policies described above are not implemented fully yet. -In particular, \fBcontiguous\fP does not place new extents adjacent to existing -extents and \fBanywhere\fP is not implemented at all. +In particular, contiguous free space cannot be broken up to +satisfy allocation attempts. .SH ENVIRONMENT VARIABLES .TP \fBLVM_SYSTEM_DIR\fP