diff options
Diffstat (limited to 'lib/metadata/lv_manip.c')
-rw-r--r-- | lib/metadata/lv_manip.c | 196 |
1 files changed, 131 insertions, 65 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; +} |