diff options
author | Alasdair Kergon <agk@redhat.com> | 2003-04-24 22:23:24 +0000 |
---|---|---|
committer | Alasdair Kergon <agk@redhat.com> | 2003-04-24 22:23:24 +0000 |
commit | b8c919b402cf781c87d2978fe920ae179f4a3a2b (patch) | |
tree | c8adf53075747abddc31a11da5cec40e5a29737f /lib/metadata | |
parent | 098102afc0fdda302a48c00d3a59316c521d1f5e (diff) | |
download | lvm2-b8c919b402cf781c87d2978fe920ae179f4a3a2b.tar.gz |
o Metadata area struct change.
o Support physical extent restrictions on PV lists for allocations
e.g. lvcreate -l 200 vg1 /dev/sda1:100-199:300-399
Diffstat (limited to 'lib/metadata')
-rw-r--r-- | lib/metadata/lv_manip.c | 196 | ||||
-rw-r--r-- | lib/metadata/merge.c | 15 | ||||
-rw-r--r-- | lib/metadata/metadata.c | 19 | ||||
-rw-r--r-- | lib/metadata/metadata.h | 48 | ||||
-rw-r--r-- | lib/metadata/pv_map.c | 92 | ||||
-rw-r--r-- | lib/metadata/pv_map.h | 2 |
6 files changed, 266 insertions, 106 deletions
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 120ea4aee..9dfb48692 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -6,6 +6,7 @@ #include "lib.h" #include "metadata.h" +#include "locking.h" #include "pv_map.h" #include "lvm-string.h" #include "toolcontext.h" @@ -19,9 +20,12 @@ static void _get_extents(struct lv_segment *seg) unsigned int s, count; struct physical_volume *pv; - for (s = 0; s < seg->stripes; s++) { - pv = seg->area[s].pv; - count = seg->len / seg->stripes; + for (s = 0; s < seg->area_count; s++) { + if (seg->area[s].type != AREA_PV) + continue; + + pv = seg->area[s].u.pv.pv; + count = seg->area_len; pv->pe_alloc_count += count; } } @@ -31,11 +35,14 @@ static void _put_extents(struct lv_segment *seg) unsigned int s, count; struct physical_volume *pv; - for (s = 0; s < seg->stripes; s++) { - pv = seg->area[s].pv; + for (s = 0; s < seg->area_count; s++) { + if (seg->area[s].type != AREA_PV) + continue; + + pv = seg->area[s].u.pv.pv; if (pv) { - count = seg->len / seg->stripes; + count = seg->area_len; assert(pv->pe_alloc_count >= count); pv->pe_alloc_count -= count; } @@ -60,13 +67,13 @@ static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes, struct pv_area **areas, uint32_t *ix) { uint32_t count = lv->le_count - *ix; - uint32_t per_area = count / stripes; + uint32_t area_len = count / stripes; uint32_t smallest = areas[stripes - 1]->count; uint32_t s; struct lv_segment *seg; - if (smallest < per_area) - per_area = smallest; + if (smallest < area_len) + area_len = smallest; if (!(seg = _alloc_segment(lv->vg->cmd->mem, stripes))) { log_err("Couldn't allocate new stripe segment."); @@ -76,15 +83,17 @@ static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes, seg->lv = lv; seg->type = SEG_STRIPED; seg->le = *ix; - seg->len = per_area * stripes; - seg->stripes = stripes; + seg->len = area_len * stripes; + seg->area_len = area_len; + seg->area_count = stripes; seg->stripe_size = stripe_size; for (s = 0; s < stripes; s++) { struct pv_area *pva = areas[s]; - seg->area[s].pv = pva->map->pv; - seg->area[s].pe = pva->start; - consume_pv_area(pva, per_area); + seg->area[s].type = AREA_PV; + seg->area[s].u.pv.pv = pva->map->pvl->pv; + seg->area[s].u.pv.pe = pva->start; + consume_pv_area(pva, area_len); } list_add(&lv->segments, &seg->list); @@ -188,10 +197,12 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix, seg->type = SEG_STRIPED; seg->le = *ix; seg->len = count; + seg->area_len = count; seg->stripe_size = 0; - seg->stripes = 1; - seg->area[0].pv = map->pv; - seg->area[0].pe = pva->start; + seg->area_count = 1; + seg->area[0].type = AREA_PV; + seg->area[0].u.pv.pv = map->pvl->pv; + seg->area[0].u.pv.pe = pva->start; list_add(&lv->segments, &seg->list); @@ -281,7 +292,7 @@ static int _alloc_next_free(struct logical_volume *lv, * Chooses a correct allocation policy. */ static int _allocate(struct volume_group *vg, struct logical_volume *lv, - struct list *acceptable_pvs, uint32_t allocated, + struct list *allocatable_pvs, uint32_t allocated, uint32_t stripes, uint32_t stripe_size) { int r = 0; @@ -296,7 +307,7 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv, /* * Build the sets of available areas on the pv's. */ - if (!(pvms = create_pv_maps(scratch, vg, acceptable_pvs))) + if (!(pvms = create_pv_maps(scratch, vg, allocatable_pvs))) goto out; if (stripes > 1) @@ -359,46 +370,23 @@ static char *_generate_lv_name(struct volume_group *vg, return buffer; } -struct logical_volume *lv_create(struct format_instance *fi, - const char *name, - uint32_t status, - alloc_policy_t alloc, - uint32_t stripes, - uint32_t stripe_size, - uint32_t extents, - struct volume_group *vg, - struct list *acceptable_pvs) +struct logical_volume *lv_create_empty(struct format_instance *fi, + const char *name, + uint32_t status, + alloc_policy_t alloc, + struct volume_group *vg) { struct cmd_context *cmd = vg->cmd; struct lv_list *ll = NULL; struct logical_volume *lv; char dname[32]; - if (!extents) { - log_error("Unable to create logical volume %s with no extents", - name); - return NULL; - } - - if (vg->free_count < extents) { - log_error("Insufficient free extents (%u) in volume group %s: " - "%u required", vg->free_count, vg->name, extents); - return NULL; - } - if (vg->max_lv == vg->lv_count) { log_error("Maximum number of logical volumes (%u) reached " "in volume group %s", vg->max_lv, vg->name); return NULL; } - if (stripes > list_size(acceptable_pvs)) { - log_error("Number of stripes (%u) must not exceed " - "number of physical volumes (%d)", stripes, - list_size(acceptable_pvs)); - return NULL; - } - if (!name && !(name = _generate_lv_name(vg, dname, sizeof(dname)))) { log_error("Failed to generate unique name for the new " "logical volume"); @@ -409,17 +397,20 @@ struct logical_volume *lv_create(struct format_instance *fi, if (!(ll = pool_zalloc(cmd->mem, sizeof(*ll))) || !(ll->lv = pool_zalloc(cmd->mem, sizeof(*ll->lv)))) { - stack; + log_error("lv_list allocation failed"); + if (ll) + pool_free(cmd->mem, ll); return NULL; } lv = ll->lv; - lv->vg = vg; if (!(lv->name = pool_strdup(cmd->mem, name))) { - stack; - goto bad; + log_error("lv name strdup failed"); + if (ll) + pool_free(cmd->mem, ll); + return NULL; } lv->status = status; @@ -427,30 +418,73 @@ struct logical_volume *lv_create(struct format_instance *fi, lv->read_ahead = 0; lv->major = -1; lv->minor = -1; - lv->size = (uint64_t) extents *vg->extent_size; - lv->le_count = extents; + lv->size = UINT64_C(0); + lv->le_count = 0; list_init(&lv->segments); - if (!_allocate(vg, lv, acceptable_pvs, 0u, stripes, stripe_size)) { - stack; - goto bad; - } - if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) { stack; - goto bad; + if (ll) + pool_free(cmd->mem, ll); + return NULL; } vg->lv_count++; list_add(&vg->lvs, &ll->list); return lv; +} - bad: - if (ll) - pool_free(cmd->mem, ll); +struct logical_volume *lv_create(struct format_instance *fi, + const char *name, + uint32_t status, + alloc_policy_t alloc, + uint32_t stripes, + uint32_t stripe_size, + uint32_t extents, + struct volume_group *vg, + struct list *allocatable_pvs) +{ + struct logical_volume *lv; - return NULL; + if (!extents) { + log_error("Unable to create logical volume %s with no extents", + name); + return NULL; + } + + if (vg->free_count < extents) { + log_error("Insufficient free extents (%u) in volume group %s: " + "%u required", vg->free_count, vg->name, extents); + return NULL; + } + + if (stripes > list_size(allocatable_pvs)) { + log_error("Number of stripes (%u) must not exceed " + "number of physical volumes (%d)", stripes, + list_size(allocatable_pvs)); + return NULL; + } + + if (!(lv = lv_create_empty(fi, name, status, alloc, vg))) { + stack; + return NULL; + } + + lv->size = (uint64_t) extents *vg->extent_size; + lv->le_count = extents; + + if (!_allocate(vg, lv, allocatable_pvs, 0u, stripes, stripe_size)) { + stack; + return NULL; + } + + if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) { + stack; + return NULL; + } + + return lv; } int lv_reduce(struct format_instance *fi, @@ -493,7 +527,7 @@ int lv_reduce(struct format_instance *fi, int lv_extend(struct format_instance *fi, struct logical_volume *lv, uint32_t stripes, uint32_t stripe_size, - uint32_t extents, struct list *acceptable_pvs) + uint32_t extents, struct list *allocatable_pvs) { uint32_t old_le_count = lv->le_count; uint64_t old_size = lv->size; @@ -501,10 +535,11 @@ int lv_extend(struct format_instance *fi, lv->le_count += extents; lv->size += (uint64_t) extents *lv->vg->extent_size; - if (!_allocate(lv->vg, lv, acceptable_pvs, old_le_count, + if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count, stripes, stripe_size)) { lv->le_count = old_le_count; lv->size = old_size; + stack; return 0; } @@ -544,3 +579,34 @@ int lv_remove(struct volume_group *vg, struct logical_volume *lv) return 1; } + +/* Lock a list of LVs */ +int lock_lvs(struct cmd_context *cmd, struct list *lvs, int flags) +{ + struct list *lvh; + struct logical_volume *lv; + + list_iterate(lvh, lvs) { + lv = list_item(lvh, struct lv_list)->lv; + if (!lock_vol(cmd, lv->lvid.s, flags)) { + log_error("Failed to lock %s", lv->name); + return 0; + } + } + + return 1; +} + +/* Unlock list of LVs */ +int unlock_lvs(struct cmd_context *cmd, struct list *lvs) +{ + struct list *lvh; + struct logical_volume *lv; + + list_iterate(lvh, lvs) { + lv = list_item(lvh, struct lv_list)->lv; + unlock_lv(cmd, lv->lvid.s); + } + + return 1; +} diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c index 17db74c83..ba4afe549 100644 --- a/lib/metadata/merge.c +++ b/lib/metadata/merge.c @@ -20,15 +20,20 @@ static int _merge(struct lv_segment *first, struct lv_segment *second) if (!first || (first->type != SEG_STRIPED) || (first->type != second->type) || - (first->stripes != second->stripes) || + (first->area_count != second->area_count) || (first->stripe_size != second->stripe_size)) return 0; - for (s = 0; s < first->stripes; s++) { - width = first->len / first->stripes; + for (s = 0; s < first->area_count; s++) { + width = first->area_len; - if ((first->area[s].pv != second->area[s].pv) || - (first->area[s].pe + width != second->area[s].pe)) + /* FIXME Relax this to first type != second type ? */ + if (first->area[s].type != AREA_PV || + second->area[s].type != AREA_PV) + return 0; + + if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) || + (first->area[s].u.pv.pe + width != second->area[s].u.pv.pe)) return 0; } diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 592dedb4b..d3de78245 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -23,7 +23,7 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg, log_verbose("Adding physical volume '%s' to volume group '%s'", pv_name, vg->name); - if (!(pvl = pool_alloc(mem, sizeof(*pvl)))) { + if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) { log_error("pv_list allocation for '%s' failed", pv_name); return 0; } @@ -401,6 +401,21 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev) return NULL; } +/* Find segment at a given logical extent in an LV */ +struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le) +{ + struct list *segh; + struct lv_segment *seg; + + list_iterate(segh, &lv->segments) { + seg = list_item(segh, struct lv_segment); + if (le >= seg->le && le < seg->le + seg->len) + return seg; + } + + return NULL; +} + int vg_remove(struct volume_group *vg) { struct list *mdah; @@ -707,7 +722,7 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name, *label_sector = label->sector; if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) { - log_error("pv_list allocation for '%s' failed", pv_name); + log_error("pv allocation for '%s' failed", pv_name); return 0; } diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index 7c0c836d9..a872b097f 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -58,9 +58,14 @@ typedef enum { typedef enum { SEG_STRIPED, SEG_SNAPSHOT, - SEG_MIRROR + SEG_MIRRORED } segment_type_t; +typedef enum { + AREA_PV, + AREA_LV +} area_type_t; + struct cmd_context; struct format_handler; struct labeller; @@ -175,15 +180,25 @@ struct lv_segment { /* FIXME Fields depend on segment type */ uint32_t stripe_size; - uint32_t stripes; + uint32_t area_count; + uint32_t area_len; struct logical_volume *origin; struct logical_volume *cow; uint32_t chunk_size; /* There will be one area for each stripe */ struct { - struct physical_volume *pv; - uint32_t pe; + area_type_t type; + union { + struct { + struct physical_volume *pv; + uint32_t pe; + } pv; + struct { + struct logical_volume *lv; + uint32_t le; + } lv; + } u; } area[0]; }; @@ -220,10 +235,17 @@ struct name_list { char *name; }; +struct alloc_area { + struct list list; + uint32_t start; /* PEs */ + uint32_t count; /* PEs */ +}; + struct pv_list { struct list list; struct physical_volume *pv; - struct list *mdas; + struct list *mdas; /* Metadata areas */ + struct list *alloc_areas; /* Areas we may allocate from */ }; struct lv_list { @@ -357,8 +379,15 @@ struct logical_volume *lv_create(struct format_instance *fi, uint32_t stripe_size, uint32_t extents, struct volume_group *vg, - struct list *acceptable_pvs); + struct list *allocatable_pvs); + +struct logical_volume *lv_create_empty(struct format_instance *fi, + const char *name, + uint32_t status, + alloc_policy_t alloc, + struct volume_group *vg); +/* Manipulate LVs */ int lv_reduce(struct format_instance *fi, struct logical_volume *lv, uint32_t extents); @@ -368,6 +397,10 @@ int lv_extend(struct format_instance *fi, uint32_t stripe_size, uint32_t extents, struct list *allocatable_pvs); +/* Lock list of LVs */ +int lock_lvs(struct cmd_context *cmd, struct list *lvs, int flags); +int unlock_lvs(struct cmd_context *cmd, struct list *lvs); + /* lv must be part of vg->lvs */ int lv_remove(struct volume_group *vg, struct logical_volume *lv); @@ -398,6 +431,9 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, struct physical_volume *find_pv(struct volume_group *vg, struct device *dev); struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name); +/* Find LV segment containing given LE */ +struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le); + /* * Remove a dev_dir if present. */ diff --git a/lib/metadata/pv_map.c b/lib/metadata/pv_map.c index eb6bae000..cee992e26 100644 --- a/lib/metadata/pv_map.c +++ b/lib/metadata/pv_map.c @@ -11,13 +11,13 @@ static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps) { struct list *tmp; - struct physical_volume *pv; struct pv_map *pvm; + struct pv_list *pvl; list_iterate(tmp, pvs) { - pv = list_item(tmp, struct pv_list)->pv; + pvl = list_item(tmp, struct pv_list); - if (!(pv->status & ALLOCATABLE_PV)) + if (!(pvl->pv->status & ALLOCATABLE_PV)) continue; if (!(pvm = pool_zalloc(mem, sizeof(*pvm)))) { @@ -25,9 +25,9 @@ static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps) return 0; } - pvm->pv = pv; + pvm->pvl = pvl; if (!(pvm->allocated_extents = - bitset_create(mem, pv->pe_count))) { + bitset_create(mem, pvl->pv->pe_count))) { stack; return 0; } @@ -39,8 +39,8 @@ static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps) return 1; } -static int _set_allocated(struct hash_table *hash, - struct physical_volume *pv, uint32_t pe) +static int _set_allocd(struct hash_table *hash, + struct physical_volume *pv, uint32_t pe) { struct pv_map *pvm; @@ -82,7 +82,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps) /* populate the hash table */ list_iterate(pvmh, maps) { pvm = list_item(pvmh, struct pv_map); - if (!hash_insert(hash, dev_name(pvm->pv->dev), pvm)) { + if (!hash_insert(hash, dev_name(pvm->pvl->pv->dev), pvm)) { stack; goto out; } @@ -95,13 +95,14 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps) list_iterate(segh, &lv->segments) { seg = list_item(segh, struct lv_segment); - for (s = 0; s < seg->stripes; s++) { - for (pe = 0; pe < (seg->len / seg->stripes); - pe++) { - if (!_set_allocated(hash, - seg->area[s].pv, - seg->area[s].pe - + pe)) { + for (s = 0u; s < seg->area_count; s++) { + for (pe = 0u; pe < seg->area_len; pe++) { + if (seg->area[s].type != AREA_PV) + continue; + if (!_set_allocd(hash, + seg->area[s].u.pv.pv, + seg->area[s].u.pv.pe + + pe)) { stack; goto out; } @@ -140,22 +141,22 @@ static void _insert_area(struct list *head, struct pv_area *a) } static int _create_single_area(struct pool *mem, struct pv_map *pvm, - uint32_t *extent) + uint32_t end, uint32_t *extent) { - uint32_t e = *extent, b, count = pvm->pv->pe_count; + uint32_t e = *extent, b; struct pv_area *pva; - while (e < count && bit(pvm->allocated_extents, e)) + while (e <= end && bit(pvm->allocated_extents, e)) e++; - if (e == count) { + if (e > end) { *extent = e; return 1; } b = e++; - while (e < count && !bit(pvm->allocated_extents, e)) + while (e <= end && !bit(pvm->allocated_extents, e)) e++; if (!(pva = pool_zalloc(mem, sizeof(*pva)))) { @@ -163,6 +164,8 @@ static int _create_single_area(struct pool *mem, struct pv_map *pvm, return 0; } + log_debug("Allowing allocation on %s start PE %" PRIu32 " length %" + PRIu32, dev_name(pvm->pvl->pv->dev), b, e - b); pva->map = pvm; pva->start = b; pva->count = e - b; @@ -172,12 +175,18 @@ static int _create_single_area(struct pool *mem, struct pv_map *pvm, return 1; } -static int _create_areas(struct pool *mem, struct pv_map *pvm) +static int _create_areas(struct pool *mem, struct pv_map *pvm, uint32_t start, + uint32_t count) { - uint32_t pe = 0; + uint32_t pe, end; - while (pe < pvm->pv->pe_count) - if (!_create_single_area(mem, pvm, &pe)) { + end = start + count - 1; + if (end > pvm->pvl->pv->pe_count - 1) + end = pvm->pvl->pv->pe_count - 1; + + pe = start; + while (pe <= end) + if (!_create_single_area(mem, pvm, end, &pe)) { stack; return 0; } @@ -185,7 +194,36 @@ static int _create_areas(struct pool *mem, struct pv_map *pvm) return 1; } -static int _create_all_areas(struct pool *mem, struct list *maps) +static int _create_allocatable_areas(struct pool *mem, struct pv_map *pvm) +{ + struct list *alloc_areas, *aah; + struct alloc_area *aa; + + alloc_areas = pvm->pvl->alloc_areas; + + if (alloc_areas) { + list_iterate(aah, alloc_areas) { + aa = list_item(aah, struct alloc_area); + if (!_create_areas(mem, pvm, aa->start, aa->count)) { + stack; + return 0; + } + + } + } else { + /* Use whole PV */ + if (!_create_areas(mem, pvm, UINT32_C(0), + pvm->pvl->pv->pe_count)) { + stack; + return 0; + } + } + + return 1; +} + +static int _create_all_areas(struct pool *mem, struct list *maps, + struct list *pvs) { struct list *tmp; struct pv_map *pvm; @@ -193,7 +231,7 @@ static int _create_all_areas(struct pool *mem, struct list *maps) list_iterate(tmp, maps) { pvm = list_item(tmp, struct pv_map); - if (!_create_areas(mem, pvm)) { + if (!_create_allocatable_areas(mem, pvm)) { stack; return 0; } @@ -226,7 +264,7 @@ struct list *create_pv_maps(struct pool *mem, struct volume_group *vg, goto bad; } - if (!_create_all_areas(mem, maps)) { + if (!_create_all_areas(mem, maps, pvs)) { log_error("Couldn't create area maps in %s", vg->name); goto bad; } diff --git a/lib/metadata/pv_map.h b/lib/metadata/pv_map.h index 86e0d7624..7a00bb3d6 100644 --- a/lib/metadata/pv_map.h +++ b/lib/metadata/pv_map.h @@ -28,7 +28,7 @@ struct pv_area { }; struct pv_map { - struct physical_volume *pv; + struct pv_list *pvl; bitset_t allocated_extents; struct list areas; |