mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-03 05:18:29 +03:00
Fix contiguous allocations with linear.
This commit is contained in:
parent
fece730645
commit
0888dc43cf
@ -1,5 +1,6 @@
|
|||||||
Version 2.01.11 -
|
Version 2.01.11 -
|
||||||
==============================
|
==============================
|
||||||
|
Fix contiguous allocation policy with linear.
|
||||||
Cope with missing format1 PVs again.
|
Cope with missing format1 PVs again.
|
||||||
Remove lists of free PV segments.
|
Remove lists of free PV segments.
|
||||||
Simplify pv_maps code and remove slow bitset algorithm.
|
Simplify pv_maps code and remove slow bitset algorithm.
|
||||||
|
@ -103,6 +103,14 @@ static inline int list_end(struct list *head, struct list *elem)
|
|||||||
return elem->n == head;
|
return elem->n == head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return last element of the list or NULL if empty
|
||||||
|
*/
|
||||||
|
static inline struct list *list_last(struct list *head)
|
||||||
|
{
|
||||||
|
return (list_empty(head) ? NULL : head->p);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the previous element of the list, or NULL if we've reached the start.
|
* Return the previous element of the list, or NULL if we've reached the start.
|
||||||
*/
|
*/
|
||||||
|
@ -196,9 +196,8 @@ static int _alloc_parallel(struct logical_volume *lv,
|
|||||||
uint32_t mirrors, struct segment_type *segtype)
|
uint32_t mirrors, struct segment_type *segtype)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
struct list *pvmh;
|
|
||||||
struct pv_area **areas;
|
struct pv_area **areas;
|
||||||
unsigned int pv_count = 0, ix;
|
unsigned int pv_count, ix;
|
||||||
struct pv_map *pvm;
|
struct pv_map *pvm;
|
||||||
size_t len;
|
size_t len;
|
||||||
uint32_t area_count;
|
uint32_t area_count;
|
||||||
@ -213,8 +212,7 @@ static int _alloc_parallel(struct logical_volume *lv,
|
|||||||
else
|
else
|
||||||
area_count = mirrors;
|
area_count = mirrors;
|
||||||
|
|
||||||
list_iterate(pvmh, pvms)
|
pv_count = list_size(pvms);
|
||||||
pv_count++;
|
|
||||||
|
|
||||||
/* allocate an array of pv_areas, one candidate per pv */
|
/* allocate an array of pv_areas, one candidate per pv */
|
||||||
len = sizeof(*areas) * pv_count;
|
len = sizeof(*areas) * pv_count;
|
||||||
@ -226,9 +224,7 @@ static int _alloc_parallel(struct logical_volume *lv,
|
|||||||
while (allocated != lv->le_count) {
|
while (allocated != lv->le_count) {
|
||||||
|
|
||||||
ix = 0;
|
ix = 0;
|
||||||
list_iterate(pvmh, pvms) {
|
list_iterate_items(pvm, pvms) {
|
||||||
pvm = list_item(pvmh, struct pv_map);
|
|
||||||
|
|
||||||
if (list_empty(&pvm->areas))
|
if (list_empty(&pvm->areas))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -341,39 +337,54 @@ static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
|
|||||||
* can complete the allocation.
|
* can complete the allocation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: subsequent lvextends may not be contiguous.
|
|
||||||
*/
|
|
||||||
static int _alloc_contiguous(struct logical_volume *lv,
|
static int _alloc_contiguous(struct logical_volume *lv,
|
||||||
struct list *pvms, uint32_t allocated)
|
struct list *pvms, uint32_t allocated)
|
||||||
{
|
{
|
||||||
struct list *tmp1;
|
|
||||||
struct pv_map *pvm;
|
struct pv_map *pvm;
|
||||||
struct pv_area *pva;
|
struct pv_area *pva;
|
||||||
|
struct lv_segment *prev_lvseg;
|
||||||
|
struct pv_segment *prev_pvseg = NULL;
|
||||||
|
uint32_t largest = 0;
|
||||||
|
|
||||||
list_iterate(tmp1, pvms) {
|
/* So far the only case is exactly one area */
|
||||||
pvm = list_item(tmp1, struct pv_map);
|
if ((prev_lvseg = list_item(list_last(&lv->segments), struct lv_segment)) &&
|
||||||
|
(prev_lvseg->area_count == 1) &&
|
||||||
|
(prev_lvseg->area[0].type == AREA_PV))
|
||||||
|
prev_pvseg = prev_lvseg->area[0].u.pv.pvseg;
|
||||||
|
|
||||||
if (list_empty(&pvm->areas))
|
list_iterate_items(pvm, pvms) {
|
||||||
|
if (prev_pvseg && (prev_pvseg->pv != pvm->pv))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* first item in the list is the biggest */
|
list_iterate_items(pva, &pvm->areas) {
|
||||||
pva = list_item(pvm->areas.n, struct pv_area);
|
if (prev_pvseg &&
|
||||||
if (pva->count < lv->le_count)
|
(prev_pvseg->pe + prev_pvseg->len != pva->start))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!_alloc_linear_area(lv, &allocated, pvm, pva)) {
|
if (pva->count > largest)
|
||||||
stack;
|
largest = pva->count;
|
||||||
return 0;
|
|
||||||
|
/* first item in the list is the biggest */
|
||||||
|
if (pva->count < lv->le_count - allocated)
|
||||||
|
goto next_pv;
|
||||||
|
|
||||||
|
if (!_alloc_linear_area(lv, &allocated, pvm, pva)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
next_pv:
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
if (allocated != lv->le_count) {
|
if (allocated != lv->le_count) {
|
||||||
log_error("Insufficient allocatable extents (%u) "
|
log_error("Insufficient allocatable extents (%u) "
|
||||||
"for logical volume %s: %u required",
|
"for logical volume %s: %u required",
|
||||||
allocated, lv->name, lv->le_count);
|
largest, lv->name, lv->le_count - allocated);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,15 +398,12 @@ static int _alloc_mirrored(struct logical_volume *lv,
|
|||||||
struct physical_volume *mirrored_pv,
|
struct physical_volume *mirrored_pv,
|
||||||
uint32_t mirrored_pe)
|
uint32_t mirrored_pe)
|
||||||
{
|
{
|
||||||
struct list *tmp1;
|
|
||||||
struct pv_map *pvm;
|
struct pv_map *pvm;
|
||||||
struct pv_area *pva;
|
struct pv_area *pva;
|
||||||
uint32_t max_found = 0;
|
uint32_t max_found = 0;
|
||||||
|
|
||||||
/* Try each PV in turn */
|
/* Try each PV in turn */
|
||||||
list_iterate(tmp1, pvms) {
|
list_iterate_items(pvm, pvms) {
|
||||||
pvm = list_item(tmp1, struct pv_map);
|
|
||||||
|
|
||||||
if (list_empty(&pvm->areas))
|
if (list_empty(&pvm->areas))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -432,15 +440,11 @@ static int _alloc_mirrored(struct logical_volume *lv,
|
|||||||
static int _alloc_next_free(struct logical_volume *lv,
|
static int _alloc_next_free(struct logical_volume *lv,
|
||||||
struct list *pvms, uint32_t allocated)
|
struct list *pvms, uint32_t allocated)
|
||||||
{
|
{
|
||||||
struct list *tmp1, *tmp2;
|
|
||||||
struct pv_map *pvm;
|
struct pv_map *pvm;
|
||||||
struct pv_area *pva;
|
struct pv_area *pva;
|
||||||
|
|
||||||
list_iterate(tmp1, pvms) {
|
list_iterate_items(pvm, pvms) {
|
||||||
pvm = list_item(tmp1, struct pv_map);
|
list_iterate_items(pva, &pvm->areas) {
|
||||||
|
|
||||||
list_iterate(tmp2, &pvm->areas) {
|
|
||||||
pva = list_item(tmp2, struct pv_area);
|
|
||||||
if (!_alloc_linear_area(lv, &allocated, pvm, pva) ||
|
if (!_alloc_linear_area(lv, &allocated, pvm, pva) ||
|
||||||
(allocated == lv->le_count))
|
(allocated == lv->le_count))
|
||||||
goto done;
|
goto done;
|
||||||
@ -560,7 +564,7 @@ static int _allocate(struct logical_volume *lv,
|
|||||||
* Iterate through the new segments, updating pe
|
* Iterate through the new segments, updating pe
|
||||||
* counts in pv's.
|
* counts in pv's.
|
||||||
*/
|
*/
|
||||||
for (segh = lv->segments.p; segh != old_tail; segh = segh->p) {
|
list_uniterate(segh, old_tail, &lv->segments) {
|
||||||
seg = list_item(segh, struct lv_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
_get_extents(seg);
|
_get_extents(seg);
|
||||||
seg->status = status;
|
seg->status = status;
|
||||||
@ -581,14 +585,11 @@ static int _allocate(struct logical_volume *lv,
|
|||||||
static char *_generate_lv_name(struct volume_group *vg, const char *format,
|
static char *_generate_lv_name(struct volume_group *vg, const char *format,
|
||||||
char *buffer, size_t len)
|
char *buffer, size_t len)
|
||||||
{
|
{
|
||||||
struct list *lvh;
|
struct lv_list *lvl;
|
||||||
struct logical_volume *lv;
|
|
||||||
int high = -1, i;
|
int high = -1, i;
|
||||||
|
|
||||||
list_iterate(lvh, &vg->lvs) {
|
list_iterate_items(lvl, &vg->lvs) {
|
||||||
lv = (list_item(lvh, struct lv_list)->lv);
|
if (sscanf(lvl->lv->name, format, &i) != 1)
|
||||||
|
|
||||||
if (sscanf(lv->name, format, &i) != 1)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (i > high)
|
if (i > high)
|
||||||
@ -822,14 +823,12 @@ uint32_t find_free_lvnum(struct logical_volume *lv)
|
|||||||
{
|
{
|
||||||
int lvnum_used[MAX_RESTRICTED_LVS + 1];
|
int lvnum_used[MAX_RESTRICTED_LVS + 1];
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
struct list *lvh;
|
|
||||||
struct lv_list *lvl;
|
struct lv_list *lvl;
|
||||||
int lvnum;
|
int lvnum;
|
||||||
|
|
||||||
memset(&lvnum_used, 0, sizeof(lvnum_used));
|
memset(&lvnum_used, 0, sizeof(lvnum_used));
|
||||||
|
|
||||||
list_iterate(lvh, &lv->vg->lvs) {
|
list_iterate_items(lvl, &lv->vg->lvs) {
|
||||||
lvl = list_item(lvh, struct lv_list);
|
|
||||||
lvnum = lvnum_from_lvid(&lvl->lv->lvid);
|
lvnum = lvnum_from_lvid(&lvl->lv->lvid);
|
||||||
if (lvnum <= MAX_RESTRICTED_LVS)
|
if (lvnum <= MAX_RESTRICTED_LVS)
|
||||||
lvnum_used[lvnum] = 1;
|
lvnum_used[lvnum] = 1;
|
||||||
|
@ -103,6 +103,14 @@ static inline int list_end(struct list *head, struct list *elem)
|
|||||||
return elem->n == head;
|
return elem->n == head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return last element of the list or NULL if empty
|
||||||
|
*/
|
||||||
|
static inline struct list *list_last(struct list *head)
|
||||||
|
{
|
||||||
|
return (list_empty(head) ? NULL : head->p);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the previous element of the list, or NULL if we've reached the start.
|
* Return the previous element of the list, or NULL if we've reached the start.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user