From 99df4f892de1af867714e4597ad2e761a7b0f366 Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Wed, 1 Jun 2005 16:51:55 +0000 Subject: [PATCH] Basic support for mirrors. --- WHATS_NEW | 11 + lib/activate/activate.c | 19 +- lib/activate/dev_manager.c | 209 +++--- lib/cache/lvmcache.c | 25 +- lib/commands/toolcontext.c | 4 +- lib/config/defaults.h | 4 +- lib/datastruct/list.h | 27 + lib/device/dev-cache.c | 16 +- lib/display/display.c | 23 +- lib/filters/filter-persistent.c | 6 +- lib/filters/filter-regex.c | 4 +- lib/format1/disk-rep.c | 28 +- lib/format1/format1.c | 9 +- lib/format1/import-export.c | 72 +- lib/format1/import-extents.c | 20 +- lib/format1/vg_number.c | 4 +- lib/format_pool/disk_rep.c | 26 +- lib/format_pool/format_pool.c | 8 +- lib/format_pool/import_export.c | 30 +- lib/format_text/archive.c | 23 +- lib/format_text/export.c | 146 ++-- lib/format_text/flags.c | 1 + lib/format_text/format-text.c | 106 ++- lib/format_text/import_vsn1.c | 12 +- lib/format_text/layout.h | 1 + lib/format_text/text_label.c | 12 +- lib/label/label.c | 13 +- lib/locking/locking.c | 39 +- lib/locking/locking_types.h | 1 + lib/metadata/lv_alloc.h | 34 +- lib/metadata/lv_manip.c | 1177 +++++++++++++++++++------------ lib/metadata/merge.c | 82 ++- lib/metadata/metadata.c | 136 ++-- lib/metadata/metadata.h | 15 +- lib/metadata/mirror.c | 99 ++- lib/metadata/pv_alloc.h | 2 +- lib/metadata/pv_manip.c | 60 +- lib/metadata/segtype.h | 4 + lib/metadata/snapshot_manip.c | 2 +- lib/mirror/mirrored.c | 75 +- lib/mm/dbg_malloc.c | 3 + lib/report/columns.h | 2 + lib/report/report.c | 57 +- lib/striped/striped.c | 12 +- libdm/datastruct/list.h | 27 + tools/args.h | 2 + tools/commands.h | 8 +- tools/lvchange.c | 6 + tools/lvcreate.c | 188 ++++- tools/lvremove.c | 6 + tools/toollib.c | 8 +- tools/vgchange.c | 4 +- tools/vgreduce.c | 4 +- tools/vgsplit.c | 4 +- 54 files changed, 1752 insertions(+), 1164 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index f8707c349..6ac23cf9a 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,16 @@ Version 2.01.11 - ============================== + Allow the creation of mirrors with contiguous extents. + Always perform sanity checks against metadata before committing it to disk. + Split lv_extend into two steps: choosing extents + allocation to LV(s). + Add mirror log region size to metadata. + Use list_iterate_items throughout and add list*back macros. + Introduce seg_ macros to access areas. + Add segtype_is_ macros. + Support tiny metadata areas for pool conversions. + Mirror activation handles disk log as well as core. + Activation code recognises mirror log dependency. + Add mirror_log and regionsize fields to report. Fix non-orphan pvchange -u. Fix vgmerge to handle duplicate LVIDs. Move archiver code from tools into library. diff --git a/lib/activate/activate.c b/lib/activate/activate.c index 8ff3b8a3a..ef265d73f 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -517,17 +517,15 @@ static int _lv_suspend_lv(struct logical_volume *lv) */ int lvs_in_vg_activated(struct volume_group *vg) { - struct list *lvh; - struct logical_volume *lv; + struct lv_list *lvl; int count = 0; if (!activation()) return 0; - list_iterate(lvh, &vg->lvs) { - lv = list_item(lvh, struct lv_list)->lv; - if (lv->status & VISIBLE_LV) - count += (_lv_active(lv) == 1); + list_iterate_items(lvl, &vg->lvs) { + if (lvl->lv->status & VISIBLE_LV) + count += (_lv_active(lvl->lv) == 1); } return count; @@ -535,17 +533,16 @@ int lvs_in_vg_activated(struct volume_group *vg) int lvs_in_vg_opened(struct volume_group *vg) { - struct list *lvh; + struct lv_list *lvl; struct logical_volume *lv; int count = 0; if (!activation()) return 0; - list_iterate(lvh, &vg->lvs) { - lv = list_item(lvh, struct lv_list)->lv; - if (lv->status & VISIBLE_LV) - count += (_lv_open_count(lv) > 0); + list_iterate_items(lvl, &vg->lvs) { + if (lvl->lv->status & VISIBLE_LV) + count += (_lv_open_count(lvl->lv) > 0); } return count; diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index 2ccdd4451..2a06bb7ac 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -732,9 +732,38 @@ int compose_log_line(struct dev_manager *dm, struct lv_segment *seg, uint32_t region_size) { int tw; + char devbuf[10]; + char *name; + struct dev_layer *dl; - tw = lvm_snprintf(params, paramsize, "core 1 %u %u ", - region_size, areas); + if (!seg->log_lv) + tw = lvm_snprintf(params, paramsize, "core 1 %u %u ", + region_size, areas); + else { + if (!(name = build_dm_name(dm->mem, seg->log_lv->vg->name, + seg->log_lv->name, NULL))) { + stack; + return 0; + } + + if (!(dl = hash_lookup(dm->layers, seg->log_lv->lvid.s))) { + log_error("device layer %s missing from hash", + seg->log_lv->lvid.s); + return 0; + } + + if (!dm_format_dev(devbuf, sizeof(devbuf), dl->info.major, + dl->info.minor)) { + log_error("Failed to format device number as dm " + "target (%u,%u)", + dl->info.major, dl->info.minor); + return 0; + } + + /* FIXME add sync parm? */ + tw = lvm_snprintf(params, paramsize, "disk 2 %s %u %u ", + devbuf, region_size, areas); + } if (tw < 0) { stack; @@ -759,29 +788,26 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, for (s = start_area; s < areas; s++, *pos += tw) { trailing_space = (areas - s - 1) ? " " : ""; - if ((seg->area[s].type == AREA_PV && - (!seg->area[s].u.pv.pvseg || - !seg->area[s].u.pv.pvseg->pv || - !seg->area[s].u.pv.pvseg->pv->dev)) || - (seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv)) + if ((seg_type(seg, s) == AREA_PV && + (!seg_pvseg(seg, s) || + !seg_pv(seg, s) || + !seg_dev(seg, s))) || + (seg_type(seg, s) == AREA_LV && !seg_lv(seg, s))) tw = lvm_snprintf(params + *pos, paramsize - *pos, "%s 0%s", dm->stripe_filler, trailing_space); - else if (seg->area[s].type == AREA_PV) + else if (seg_type(seg, s) == AREA_PV) tw = lvm_snprintf(params + *pos, paramsize - *pos, "%s %" PRIu64 "%s", - dev_name(seg->area[s].u.pv.pvseg-> - pv->dev), - (seg->area[s].u.pv.pvseg->pv-> - pe_start + - (esize * seg->area[s].u.pv.pvseg-> - pe)), + dev_name(seg_dev(seg, s)), + (seg_pv(seg, s)->pe_start + + (esize * seg_pe(seg, s))), trailing_space); else { if (!(dl = hash_lookup(dm->layers, - seg->area[s].u.lv.lv->lvid.s))) { + seg_lv(seg, s)->lvid.s))) { log_error("device layer %s missing from hash", - seg->area[s].u.lv.lv->lvid.s); + seg_lv(seg, s)->lvid.s); return 0; } if (!dm_format_dev @@ -794,7 +820,7 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, } tw = lvm_snprintf(params + *pos, paramsize - *pos, "%s %" PRIu64 "%s", devbuf, - esize * seg->area[s].u.lv.le, + esize * seg_le(seg, s), trailing_space); } @@ -842,14 +868,12 @@ static int _emit_target(struct dev_manager *dm, struct dm_task *dmt, static int _populate_vanilla(struct dev_manager *dm, struct dm_task *dmt, struct dev_layer *dl) { - struct list *segh; struct lv_segment *seg; struct logical_volume *lv = dl->lv; dm->pvmove_mirror_count = 0u; - list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct lv_segment); + list_iterate_items(seg, &lv->segments) { if (!_emit_target(dm, dmt, seg)) { log_error("Unable to build table for '%s'", lv->name); return 0; @@ -1201,7 +1225,6 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv, * only one layer. */ struct dev_layer *dl, *dlr; - struct list *segh; struct lv_segment *seg; uint32_t s; @@ -1219,14 +1242,22 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv, _set_flag(dl, TOPLEVEL); /* Add dependencies for any LVs that segments refer to */ - list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct lv_segment); + list_iterate_items(seg, &lv->segments) { + if (seg->log_lv && + !str_list_add(dm->mem, &dl->pre_create, + _build_dlid(dm->mem, seg->log_lv->lvid.s, + NULL))) { + stack; + return 0; + } + // FIXME Check we don't want NOPROPAGATE here + for (s = 0; s < seg->area_count; s++) { - if (seg->area[s].type != AREA_LV) + if (seg_type(seg, s) != AREA_LV) continue; if (!str_list_add(dm->mem, &dl->pre_create, _build_dlid(dm->mem, - seg->area[s].u.lv.lv-> + seg_lv(seg, s)-> lvid.s, NULL))) { stack; return 0; @@ -1300,14 +1331,14 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv) { struct logical_volume *active; struct lv_segment *snap_seg; - struct list *sh; + struct lv_list *lvl; /* * We only need to create an origin layer if one of our * snapshots is in the active list */ - list_iterate(sh, &dm->active_list) { - active = list_item(sh, struct lv_list)->lv; + list_iterate_items(lvl, &dm->active_list) { + active = lvl->lv; if ((snap_seg = find_cow(active)) && (snap_seg->origin == lv)) return _expand_origin_real(dm, lv); } @@ -1411,12 +1442,12 @@ static void _clear_marks(struct dev_manager *dm, int flag) static int _trace_layer_marks(struct dev_manager *dm, struct dev_layer *dl, int flag) { - struct list *sh; + struct str_list *strl; const char *dlid; struct dev_layer *dep; - list_iterate(sh, &dl->pre_create) { - dlid = list_item(sh, struct str_list)->str; + list_iterate_items(strl, &dl->pre_create) { + dlid = strl->str; if (!(dep = hash_lookup(dm->layers, dlid))) { log_error("Couldn't find device layer '%s'.", dlid); @@ -1466,16 +1497,14 @@ static int _trace_all_marks(struct dev_manager *dm, int flag) */ static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag) { - struct list *lvh; - struct logical_volume *lv; + struct lv_list *lvl; struct dev_layer *dl; - list_iterate(lvh, lvs) { - lv = list_item(lvh, struct lv_list)->lv; - if (lv->status & SNAPSHOT) + list_iterate_items(lvl, lvs) { + if (lvl->lv->status & SNAPSHOT) continue; - if (!(dl = _lookup(dm, lv->lvid.s, NULL))) { + if (!(dl = _lookup(dm, lvl->lv->lvid.s, NULL))) { stack; return 0; } @@ -1493,12 +1522,12 @@ static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag) static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl) { - struct list *sh; + struct str_list *strl; struct dev_layer *dep; const char *dlid; - list_iterate(sh, &dl->pre_suspend) { - dlid = list_item(sh, struct str_list)->str; + list_iterate_items(strl, &dl->pre_suspend) { + dlid = strl->str; if (!(dep = hash_lookup(dm->layers, dlid))) { log_debug("_suspend_parents couldn't find device " @@ -1527,12 +1556,12 @@ static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl) static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl) { - struct list *sh; + struct str_list *strl; struct dev_layer *dep; const char *dlid; - list_iterate(sh, &dl->pre_create) { - dlid = list_item(sh, struct str_list)->str; + list_iterate_items(strl, &dl->pre_create) { + dlid = strl->str; if (!(dep = hash_lookup(dm->layers, dlid))) { log_debug("_resume_with_deps couldn't find device " @@ -1565,7 +1594,7 @@ static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl) */ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl) { - struct list *sh; + struct str_list *strl; struct dev_layer *dep; const char *dlid; char *newname, *suffix; @@ -1577,8 +1606,8 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl) return 0; } - list_iterate(sh, &dl->pre_create) { - dlid = list_item(sh, struct str_list)->str; + list_iterate_items(strl, &dl->pre_create) { + dlid = strl->str; if (!(dep = hash_lookup(dm->layers, dlid))) { log_error("Couldn't find device layer '%s'.", dlid); @@ -1634,17 +1663,15 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl) static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg) { - struct list *lvh; - struct logical_volume *lv; + struct lv_list *lvl; /* * Build layers for complete vg. */ - list_iterate(lvh, &vg->lvs) { - lv = list_item(lvh, struct lv_list)->lv; - if (lv->status & SNAPSHOT) + list_iterate_items(lvl, &vg->lvs) { + if (lvl->lv->status & SNAPSHOT) continue; - if (!_expand_lv(dm, lv)) { + if (!_expand_lv(dm, lvl->lv)) { stack; return 0; } @@ -1684,15 +1711,15 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm) { struct hash_node *hn; struct dev_layer *dl; - struct list *sh; + struct str_list *strl; const char *dlid; struct dev_layer *dep; hash_iterate(hn, dm->layers) { dl = hash_get_data(dm->layers, hn); - list_iterate(sh, &dl->pre_suspend) { - dlid = list_item(sh, struct str_list)->str; + list_iterate_items(strl, &dl->pre_suspend) { + dlid = strl->str; if (!(dep = hash_lookup(dm->layers, dlid))) { log_debug("_populate_pre_suspend_lists: " @@ -1707,8 +1734,8 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm) } } - list_iterate(sh, &dl->pre_create) { - dlid = list_item(sh, struct str_list)->str; + list_iterate_items(strl, &dl->pre_create) { + dlid = strl->str; if (!(dep = hash_lookup(dm->layers, dlid))) { log_debug("_populate_pre_suspend_lists: " @@ -1733,6 +1760,7 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm) static int _remove_old_layers(struct dev_manager *dm) { int change; + struct dl_list *dll; struct list *rh, *n; struct dev_layer *dl; @@ -1755,10 +1783,8 @@ static int _remove_old_layers(struct dev_manager *dm) } while (change); if (!list_empty(&dm->remove_list)) { - list_iterate(rh, &dm->remove_list) { - dl = list_item(rh, struct dl_list)->dl; - log_error("Couldn't deactivate device %s", dl->name); - } + list_iterate_items(dll, &dm->remove_list) + log_error("Couldn't deactivate device %s", dll->dl->name); return 0; } @@ -1945,16 +1971,14 @@ static int _add_lv(struct pool *mem, static int _add_lvs(struct pool *mem, struct list *head, struct logical_volume *origin) { - struct logical_volume *lv; struct lv_segment *snap_seg; - struct list *lvh; + struct lv_list *lvl; - list_iterate(lvh, &origin->vg->lvs) { - lv = list_item(lvh, struct lv_list)->lv; - if (lv->status & SNAPSHOT) + list_iterate_items(lvl, &origin->vg->lvs) { + if (lvl->lv->status & SNAPSHOT) continue; - if ((snap_seg = find_cow(lv)) && snap_seg->origin == origin) - if (!_add_lv(mem, head, lv)) + if ((snap_seg = find_cow(lvl->lv)) && snap_seg->origin == origin) + if (!_add_lv(mem, head, lvl->lv)) return 0; } @@ -1963,13 +1987,11 @@ static int _add_lvs(struct pool *mem, static void _remove_lv(struct list *head, struct logical_volume *lv) { - struct list *lvh; struct lv_list *lvl; - list_iterate(lvh, head) { - lvl = list_item(lvh, struct lv_list); + list_iterate_items(lvl, head) { if (lvl->lv == lv) { - list_del(lvh); + list_del(&lvl->list); break; } } @@ -1979,13 +2001,14 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv) { struct logical_volume *active, *old_origin; struct lv_segment *snap_seg; - struct list *sh, *active_head; + struct list *active_head; + struct lv_list *lvl; active_head = &dm->active_list; /* Remove any snapshots with given origin */ - list_iterate(sh, active_head) { - active = list_item(sh, struct lv_list)->lv; + list_iterate_items(lvl, active_head) { + active = lvl->lv; if ((snap_seg = find_cow(active)) && snap_seg->origin == lv) { _remove_lv(active_head, active); } @@ -1999,8 +2022,8 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv) old_origin = snap_seg->origin; /* Was this the last active snapshot with this origin? */ - list_iterate(sh, active_head) { - active = list_item(sh, struct lv_list)->lv; + list_iterate_items(lvl, active_head) { + active = lvl->lv; if ((snap_seg = find_cow(active)) && snap_seg->origin == old_origin) { return 1; @@ -2015,13 +2038,14 @@ static int _remove_suspended_lvs(struct dev_manager *dm, { struct logical_volume *suspended; struct lv_segment *snap_seg; - struct list *sh, *suspend_head; + struct list *suspend_head; + struct lv_list *lvl; suspend_head = &dm->suspend_list; /* Remove from list any snapshots with given origin */ - list_iterate(sh, suspend_head) { - suspended = list_item(sh, struct lv_list)->lv; + list_iterate_items(lvl, suspend_head) { + suspended = lvl->lv; if ((snap_seg = find_cow(suspended)) && snap_seg->origin == lv) { _remove_lv(suspend_head, suspended); @@ -2036,13 +2060,13 @@ static int _remove_suspended_lvs(struct dev_manager *dm, static int _targets_present(struct dev_manager *dm, struct list *lvs) { struct logical_volume *lv; - struct list *lvh, *segh; + struct lv_list *lvl; struct segment_type *segtype; struct lv_segment *seg; int snapshots = 0, mirrors = 0; - list_iterate(lvh, lvs) { - lv = list_item(lvh, struct lv_list)->lv; + list_iterate_items(lvl, lvs) { + lv = lvl->lv; if (!snapshots) if (lv_is_cow(lv) || lv_is_origin(lv)) @@ -2053,8 +2077,7 @@ static int _targets_present(struct dev_manager *dm, struct list *lvs) mirrors = 1; if (lv->status & VIRTUAL) { - list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct lv_segment); + list_iterate_items(seg, &lv->segments) { if (seg->segtype->ops->target_present && !seg->segtype->ops->target_present()) { log_error("Can't expand LV: %s target " @@ -2103,16 +2126,14 @@ static int _targets_present(struct dev_manager *dm, struct list *lvs) static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg) { char *dlid; - struct list *lvh; - struct logical_volume *lv; + struct lv_list *lvl; struct dev_layer *dl; - list_iterate(lvh, &vg->lvs) { - lv = list_item(lvh, struct lv_list)->lv; - if (lv->status & SNAPSHOT) + list_iterate_items(lvl, &vg->lvs) { + if (lvl->lv->status & SNAPSHOT) continue; - if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) { + if (!(dlid = _build_dlid(dm->mem, lvl->lv->lvid.s, NULL))) { stack; return 0; } @@ -2121,16 +2142,16 @@ static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg) pool_free(dm->mem, dlid); if (dl) { - log_debug("Found active lv %s%s", lv->name, + log_debug("Found active lv %s%s", lvl->lv->name, dl->info.suspended ? " (suspended)" : ""); - if (!_add_lv(dm->mem, &dm->active_list, lv)) { + if (!_add_lv(dm->mem, &dm->active_list, lvl->lv)) { stack; return 0; } if (dl->info.suspended) { - if (!_add_lv(dm->mem, &dm->suspend_list, lv)) { + if (!_add_lv(dm->mem, &dm->suspend_list, lvl->lv)) { stack; return 0; } diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c index 3173f4641..17084a54b 100644 --- a/lib/cache/lvmcache.c +++ b/lib/cache/lvmcache.c @@ -104,8 +104,9 @@ struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname) const struct format_type *fmt_from_vgname(const char *vgname) { struct lvmcache_vginfo *vginfo; + struct lvmcache_info *info; struct label *label; - struct list *ih, *devh, *tmp; + struct list *devh, *tmp; struct list devs; struct device_list *devl; @@ -115,9 +116,9 @@ const struct format_type *fmt_from_vgname(const char *vgname) /* This function is normally called before reading metadata so * we check cached labels here. Unfortunately vginfo is volatile. */ list_init(&devs); - list_iterate(ih, &vginfo->infos) { - devl = malloc(sizeof(*devl)); - devl->dev = list_item(ih, struct lvmcache_info)->dev; + list_iterate_items(info, &vginfo->infos) { + devl = dbg_malloc(sizeof(*devl)); + devl->dev = info->dev; list_add(&devs, &devl->list); } @@ -125,7 +126,7 @@ const struct format_type *fmt_from_vgname(const char *vgname) devl = list_item(devh, struct device_list); label_read(devl->dev, &label); list_del(&devl->list); - free(devl); + dbg_free(devl); } return vginfo->fmt; @@ -186,7 +187,6 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan) struct label *label; struct dev_iter *iter; struct device *dev; - struct list *fmth; struct format_type *fmt; static int _scanning_in_progress = 0; @@ -221,8 +221,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan) _has_scanned = 1; /* Perform any format-specific scanning e.g. text files */ - list_iterate(fmth, &cmd->formats) { - fmt = list_item(fmth, struct format_type); + list_iterate_items(fmt, &cmd->formats) { if (fmt->ops->scan && !fmt->ops->scan(fmt)) goto out; } @@ -431,18 +430,16 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname) int lvmcache_update_vg(struct volume_group *vg) { - struct list *pvh; - struct physical_volume *pv; + struct pv_list *pvl; struct lvmcache_info *info; char pvid_s[ID_LEN + 1]; int vgid_updated = 0; pvid_s[sizeof(pvid_s) - 1] = '\0'; - list_iterate(pvh, &vg->pvs) { - pv = list_item(pvh, struct pv_list)->pv; - strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1); - /* FIXME Could pv->dev->pvid ever be different? */ + list_iterate_items(pvl, &vg->pvs) { + strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1); + /* FIXME Could pvl->pv->dev->pvid ever be different? */ if ((info = info_from_pvid(pvid_s))) { lvmcache_update_vgname(info, vg->name); if (!vgid_updated) { diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c index 02bdefa33..023d8c49b 100644 --- a/lib/commands/toolcontext.c +++ b/lib/commands/toolcontext.c @@ -622,7 +622,6 @@ static int _init_formats(struct cmd_context *cmd) const char *format; struct format_type *fmt; - struct list *fmth; #ifdef HAVE_LIBDL const struct config_node *cn; @@ -689,8 +688,7 @@ static int _init_formats(struct cmd_context *cmd) format = find_config_str(cmd->cft->root, "global/format", DEFAULT_FORMAT); - list_iterate(fmth, &cmd->formats) { - fmt = list_item(fmth, struct format_type); + list_iterate_items(fmt, &cmd->formats) { if (!strcasecmp(fmt->name, format) || (fmt->alias && !strcasecmp(fmt->alias, format))) { cmd->default_settings.fmt = fmt; diff --git a/lib/config/defaults.h b/lib/config/defaults.h index c4dcb815b..aa6c47011 100644 --- a/lib/config/defaults.h +++ b/lib/config/defaults.h @@ -91,13 +91,13 @@ #define DEFAULT_REP_HEADINGS 1 #define DEFAULT_REP_SEPARATOR " " -#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,copy_percent" +#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,mirror_log,copy_percent" #define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free" #define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free" #define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size" #define DEFAULT_PVSEGS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size" -#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,lv_uuid" +#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,mirror_log,lv_uuid" #define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid" #define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid" #define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize" diff --git a/lib/datastruct/list.h b/lib/datastruct/list.h index b43b26ca0..e2fbc76c1 100644 --- a/lib/datastruct/list.h +++ b/lib/datastruct/list.h @@ -103,6 +103,14 @@ static inline int list_end(struct list *head, struct list *elem) return elem->n == head; } +/* + * Return first element of the list or NULL if empty + */ +static inline struct list *list_first(struct list *head) +{ + return (list_empty(head) ? NULL : head->n); +} + /* * Return last element of the list or NULL if empty */ @@ -194,6 +202,25 @@ static inline struct list *list_next(struct list *head, struct list *elem) */ #define list_iterate_items(v, head) list_iterate_items_gen(v, (head), list) +/* + * Walk a list backwards, setting 'v' in turn to the containing structure + * of each item. + * The containing structure should be the same type as 'v'. + * The 'struct list' variable within the containing structure is 'field'. + */ +#define list_iterate_back_items_gen(v, head, field) \ + for (v = list_struct_base((head)->p, typeof(*v), field); \ + &v->field != (head); \ + v = list_struct_base(v->field.p, typeof(*v), field)) + +/* + * Walk a list backwards, setting 'v' in turn to the containing structure + * of each item. + * The containing structure should be the same type as 'v'. + * The list should be 'struct list list' within the containing structure. + */ +#define list_iterate_back_items(v, head) list_iterate_back_items_gen(v, (head), list) + /* * Return the number of elements in a list by walking it. */ diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c index d585d3c74..383f95f48 100644 --- a/lib/device/dev-cache.c +++ b/lib/device/dev-cache.c @@ -196,7 +196,7 @@ static int _compare_paths(const char *path0, const char *path1) static int _add_alias(struct device *dev, const char *path) { struct str_list *sl = _alloc(sizeof(*sl)); - struct list *ah; + struct str_list *strl; const char *oldpath; int prefer_old = 1; @@ -206,8 +206,8 @@ static int _add_alias(struct device *dev, const char *path) } /* Is name already there? */ - list_iterate(ah, &dev->aliases) { - if (!strcmp(list_item(ah, struct str_list)->str, path)) { + list_iterate_items(strl, &dev->aliases) { + if (!strcmp(strl->str, path)) { log_debug("%s: Already in device cache", path); return 1; } @@ -414,20 +414,16 @@ static int _insert(const char *path, int rec) static void _full_scan(int dev_scan) { - struct list *dh; + struct dir_list *dl; if (_cache.has_scanned && !dev_scan) return; - list_iterate(dh, &_cache.dirs) { - struct dir_list *dl = list_item(dh, struct dir_list); + list_iterate_items(dl, &_cache.dirs) _insert_dir(dl->dir); - }; - list_iterate(dh, &_cache.files) { - struct dir_list *dl = list_item(dh, struct dir_list); + list_iterate_items(dl, &_cache.files) _insert_file(dl->dir); - }; _cache.has_scanned = 1; init_full_scan_done(1); diff --git a/lib/display/display.c b/lib/display/display.c index 11726e44f..c87195102 100644 --- a/lib/display/display.c +++ b/lib/display/display.c @@ -449,29 +449,28 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv, void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre) { - switch (seg->area[s].type) { + switch (seg_type(seg, s)) { case AREA_PV: /* FIXME Re-check the conditions for 'Missing' */ log_print("%sPhysical volume\t%s", pre, - seg->area[s].u.pv.pvseg->pv ? - dev_name(seg->area[s].u.pv.pvseg->pv->dev) : + seg_pv(seg, s) ? + dev_name(seg_dev(seg, s)) : "Missing"); - if (seg->area[s].u.pv.pvseg->pv) + if (seg_pv(seg, s)) log_print("%sPhysical extents\t%d to %d", pre, - seg->area[s].u.pv.pvseg->pe, - seg->area[s].u.pv.pvseg->pe + - seg->area_len - 1); + seg_pe(seg, s), + seg_pe(seg, s) + seg->area_len - 1); break; case AREA_LV: log_print("%sLogical volume\t%s", pre, - seg->area[s].u.lv.lv ? - seg->area[s].u.lv.lv->name : "Missing"); + seg_lv(seg, s) ? + seg_lv(seg, s)->name : "Missing"); - if (seg->area[s].u.lv.lv) + if (seg_lv(seg, s)) log_print("%sLogical extents\t%d to %d", pre, - seg->area[s].u.lv.le, - seg->area[s].u.lv.le + seg->area_len - 1); + seg_le(seg, s), + seg_le(seg, s) + seg->area_len - 1); } } diff --git a/lib/filters/filter-persistent.c b/lib/filters/filter-persistent.c index 0666156b8..4ab229501 100644 --- a/lib/filters/filter-persistent.c +++ b/lib/filters/filter-persistent.c @@ -204,16 +204,14 @@ static int _lookup_p(struct dev_filter *f, struct device *dev) struct pfilter *pf = (struct pfilter *) f->private; void *l = hash_lookup(pf->devices, dev_name(dev)); struct str_list *sl; - struct list *ah; if (!l) { l = pf->real->passes_filter(pf->real, dev) ? PF_GOOD_DEVICE : PF_BAD_DEVICE; - list_iterate(ah, &dev->aliases) { - sl = list_item(ah, struct str_list); + list_iterate_items(sl, &dev->aliases) hash_insert(pf->devices, sl->str, l); - } + } else if (l == PF_BAD_DEVICE) log_debug("%s: Skipping (cached)", dev_name(dev)); diff --git a/lib/filters/filter-regex.c b/lib/filters/filter-regex.c index ed6da849d..db8e07f8a 100644 --- a/lib/filters/filter-regex.c +++ b/lib/filters/filter-regex.c @@ -158,13 +158,11 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val) static int _accept_p(struct dev_filter *f, struct device *dev) { - struct list *ah; int m, first = 1, rejected = 0; struct rfilter *rf = (struct rfilter *) f->private; struct str_list *sl; - list_iterate(ah, &dev->aliases) { - sl = list_item(ah, struct str_list); + list_iterate_items(sl, &dev->aliases) { m = matcher_run(rf->engine, sl->str); if (m >= 0) { diff --git a/lib/format1/disk-rep.c b/lib/format1/disk-rep.c index 834e5c86b..9418ff98b 100644 --- a/lib/format1/disk-rep.c +++ b/lib/format1/disk-rep.c @@ -424,11 +424,11 @@ struct disk_list *read_disk(const struct format_type *fmt, struct device *dev, static void _add_pv_to_list(struct list *head, struct disk_list *data) { - struct list *pvdh; struct pv_disk *pvd; + struct disk_list *diskl; - list_iterate(pvdh, head) { - pvd = &list_item(pvdh, struct disk_list)->pvd; + list_iterate_items(diskl, head) { + pvd = &diskl->pvd; if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid, sizeof(pvd->pv_uuid))) { if (MAJOR(data->dev->dev) != md_major()) { @@ -439,7 +439,7 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data) } log_very_verbose("Duplicate PV %s - using md %s", pvd->pv_uuid, dev_name(data->dev)); - list_del(pvdh); + list_del(&diskl->list); break; } } @@ -458,14 +458,14 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name, struct dev_iter *iter; struct device *dev; struct disk_list *data = NULL; - struct list *vgih; struct lvmcache_vginfo *vginfo; + struct lvmcache_info *info; /* Fast path if we already saw this VG and cached the list of PVs */ if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) && vginfo->infos.n) { - list_iterate(vgih, &vginfo->infos) { - dev = list_item(vgih, struct lvmcache_info)->dev; + list_iterate_items(info, &vginfo->infos) { + dev = info->dev; if (dev && !(data = read_disk(fmt, dev, mem, vg_name))) break; _add_pv_to_list(head, data); @@ -518,18 +518,16 @@ static int _write_vgd(struct disk_list *data) static int _write_uuids(struct disk_list *data) { struct uuid_list *ul; - struct list *uh; uint64_t pos = data->pvd.pv_uuidlist_on_disk.base; uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size; - list_iterate(uh, &data->uuids) { + list_iterate_items(ul, &data->uuids) { if (pos >= end) { log_error("Too many uuids to fit on %s", dev_name(data->dev)); return 0; } - ul = list_item(uh, struct uuid_list); if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid)) fail; @@ -552,7 +550,7 @@ static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk) static int _write_lvs(struct disk_list *data) { - struct list *lvh; + struct lvd_list *ll; uint64_t pos, offset; pos = data->pvd.lv_on_disk.base; @@ -563,9 +561,7 @@ static int _write_lvs(struct disk_list *data) return 0; } - list_iterate(lvh, &data->lvds) { - struct lvd_list *ll = list_item(lvh, struct lvd_list); - + list_iterate_items(ll, &data->lvds) { offset = sizeof(struct lv_disk) * ll->lvd.lv_number; if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) { log_error("lv_number %d too large", ll->lvd.lv_number); @@ -704,11 +700,9 @@ static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data) */ int write_disks(const struct format_type *fmt, struct list *pvs) { - struct list *pvh; struct disk_list *dl; - list_iterate(pvh, pvs) { - dl = list_item(pvh, struct disk_list); + list_iterate_items(dl, pvs) { if (!(_write_all_pvd(fmt, dl))) fail; diff --git a/lib/format1/format1.c b/lib/format1/format1.c index 8bc887092..45f715830 100644 --- a/lib/format1/format1.c +++ b/lib/format1/format1.c @@ -46,9 +46,7 @@ static int _check_vgs(struct list *pvs, int *partial) * This means an active VG won't be affected if disks are inserted * bearing an exported VG with the same name. */ - list_iterate(pvh, pvs) { - dl = list_item(pvh, struct disk_list); - + list_iterate_items(dl, pvs) { if (first_time) { exported = dl->pvd.pv_status & VG_EXPORTED; first_time = 0; @@ -246,13 +244,10 @@ static int _flatten_vg(struct format_instance *fid, struct pool *mem, struct list *pvds, const char *dev_dir, struct dev_filter *filter) { - struct list *pvh; struct pv_list *pvl; struct disk_list *data; - list_iterate(pvh, &vg->pvs) { - pvl = list_item(pvh, struct pv_list); - + list_iterate_items(pvl, &vg->pvs) { if (!(data = _flatten_pv(fid, mem, vg, pvl->pv, dev_dir))) { stack; return 0; diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c index 2e38104af..d1360e0b9 100644 --- a/lib/format1/import-export.c +++ b/lib/format1/import-export.c @@ -87,7 +87,7 @@ int import_pv(struct pool *mem, struct device *dev, pv->pe_size = pvd->pe_size; pv->pe_start = pvd->pe_start; pv->pe_count = pvd->pe_total; - pv->pe_alloc_count = pvd->pe_allocated; + pv->pe_alloc_count = 0; list_init(&pv->tags); list_init(&pv->segments); @@ -382,14 +382,11 @@ static void _export_lv(struct lv_disk *lvd, struct volume_group *vg, int export_extents(struct disk_list *dl, uint32_t lv_num, struct logical_volume *lv, struct physical_volume *pv) { - struct list *segh; struct pe_disk *ped; struct lv_segment *seg; uint32_t pe, s; - list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct lv_segment); - + list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) { log_error("Segment type %s in LV %s: " @@ -397,17 +394,16 @@ int export_extents(struct disk_list *dl, uint32_t lv_num, seg->segtype->name, lv->name); return 0; } - if (seg->area[s].type != AREA_PV) { + if (seg_type(seg, s) != AREA_PV) { log_error("LV stripe found in LV %s: " "unsupported by format1", lv->name); return 0; } - if (seg->area[s].u.pv.pvseg->pv != pv) + if (seg_pv(seg, s) != pv) continue; /* not our pv */ for (pe = 0; pe < (seg->len / seg->area_count); pe++) { - ped = &dl->extents[pe + - seg->area[s].u.pv.pvseg->pe]; + ped = &dl->extents[pe + seg_pe(seg, s)]; ped->lv_num = lv_num; ped->le_num = (seg->le / seg->area_count) + pe + s * (lv->le_count / seg->area_count); @@ -422,15 +418,11 @@ int import_pvs(const struct format_type *fmt, struct pool *mem, struct volume_group *vg, struct list *pvds, struct list *results, int *count) { - struct list *pvdh; struct disk_list *dl; struct pv_list *pvl; *count = 0; - list_iterate(pvdh, pvds) { - - dl = list_item(pvdh, struct disk_list); - + list_iterate_items(dl, pvds) { if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) || !(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) { stack; @@ -481,12 +473,9 @@ int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds) struct disk_list *dl; struct lvd_list *ll; struct lv_disk *lvd; - struct list *pvdh, *lvdh; - list_iterate(pvdh, pvds) { - dl = list_item(pvdh, struct disk_list); - list_iterate(lvdh, &dl->lvds) { - ll = list_item(lvdh, struct lvd_list); + list_iterate_items(dl, pvds) { + list_iterate_items(ll, &dl->lvds) { lvd = &ll->lvd; if (!find_lv(vg, lvd->lv_name) && @@ -505,7 +494,6 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg, struct physical_volume *pv, const char *dev_dir) { int r = 0; - struct list *lvh; struct lv_list *ll; struct lvd_list *lvdl; size_t len; @@ -532,8 +520,7 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg, } memset(dl->extents, 0, len); - list_iterate(lvh, &vg->lvs) { - ll = list_item(lvh, struct lv_list); + list_iterate_items(ll, &vg->lvs) { if (ll->lv->status & SNAPSHOT) continue; @@ -585,19 +572,17 @@ int import_snapshots(struct pool *mem, struct volume_group *vg, struct list *pvds) { struct logical_volume *lvs[MAX_LV]; - struct list *pvdh, *lvdh; struct disk_list *dl; + struct lvd_list *ll; struct lv_disk *lvd; int lvnum; struct logical_volume *org, *cow; /* build an index of lv numbers */ memset(lvs, 0, sizeof(lvs)); - list_iterate(pvdh, pvds) { - dl = list_item(pvdh, struct disk_list); - - list_iterate(lvdh, &dl->lvds) { - lvd = &(list_item(lvdh, struct lvd_list)->lvd); + list_iterate_items(dl, pvds) { + list_iterate_items(ll, &dl->lvds) { + lvd = &ll->lvd; lvnum = lvd->lv_number; @@ -619,11 +604,9 @@ int import_snapshots(struct pool *mem, struct volume_group *vg, /* * Now iterate through yet again adding the snapshots. */ - list_iterate(pvdh, pvds) { - dl = list_item(pvdh, struct disk_list); - - list_iterate(lvdh, &dl->lvds) { - lvd = &(list_item(lvdh, struct lvd_list)->lvd); + list_iterate_items(dl, pvds) { + list_iterate_items(ll, &dl->lvds) { + lvd = &ll->lvd; if (!(lvd->lv_access & LV_SNAPSHOT)) continue; @@ -657,10 +640,8 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg) { struct uuid_list *ul; struct pv_list *pvl; - struct list *pvh; - list_iterate(pvh, &vg->pvs) { - pvl = list_item(pvh, struct pv_list); + list_iterate_items(pvl, &vg->pvs) { if (!(ul = pool_alloc(dl->mem, sizeof(*ul)))) { stack; return 0; @@ -680,14 +661,11 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg) */ void export_numbers(struct list *pvds, struct volume_group *vg) { - struct list *pvdh; struct disk_list *dl; int pv_num = 1; - list_iterate(pvdh, pvds) { - dl = list_item(pvdh, struct disk_list); + list_iterate_items(dl, pvds) dl->pvd.pv_number = pv_num++; - } } /* @@ -695,26 +673,20 @@ void export_numbers(struct list *pvds, struct volume_group *vg) */ void export_pv_act(struct list *pvds) { - struct list *pvdh; struct disk_list *dl; int act = 0; - list_iterate(pvdh, pvds) { - dl = list_item(pvdh, struct disk_list); + list_iterate_items(dl, pvds) if (dl->pvd.pv_status & PV_ACTIVE) act++; - } - list_iterate(pvdh, pvds) { - dl = list_item(pvdh, struct disk_list); + list_iterate_items(dl, pvds) dl->vgd.pv_act = act; - } } int export_vg_number(struct format_instance *fid, struct list *pvds, const char *vg_name, struct dev_filter *filter) { - struct list *pvdh; struct disk_list *dl; int vg_num; @@ -723,10 +695,8 @@ int export_vg_number(struct format_instance *fid, struct list *pvds, return 0; } - list_iterate(pvdh, pvds) { - dl = list_item(pvdh, struct disk_list); + list_iterate_items(dl, pvds) dl->vgd.vg_number = vg_num; - } return 1; } diff --git a/lib/format1/import-extents.c b/lib/format1/import-extents.c index 20913a5df..cf74fa09f 100644 --- a/lib/format1/import-extents.c +++ b/lib/format1/import-extents.c @@ -48,7 +48,6 @@ static struct hash_table *_create_lv_maps(struct pool *mem, struct volume_group *vg) { struct hash_table *maps = hash_create(32); - struct list *llh; struct lv_list *ll; struct lv_map *lvm; @@ -58,8 +57,7 @@ static struct hash_table *_create_lv_maps(struct pool *mem, return NULL; } - list_iterate(llh, &vg->lvs) { - ll = list_item(llh, struct lv_list); + list_iterate_items(ll, &vg->lvs) { if (ll->lv->status & SNAPSHOT) continue; @@ -91,13 +89,12 @@ static struct hash_table *_create_lv_maps(struct pool *mem, static int _fill_lv_array(struct lv_map **lvs, struct hash_table *maps, struct disk_list *dl) { - struct list *lvh; + struct lvd_list *ll; struct lv_map *lvm; memset(lvs, 0, sizeof(*lvs) * MAX_LV); - list_iterate(lvh, &dl->lvds) { - struct lvd_list *ll = list_item(lvh, struct lvd_list); + list_iterate_items(ll, &dl->lvds) { if (!(lvm = hash_lookup(maps, strrchr(ll->lvd.lv_name, '/') + 1))) { log_err("Physical volume (%s) contains an " @@ -118,15 +115,13 @@ static int _fill_lv_array(struct lv_map **lvs, static int _fill_maps(struct hash_table *maps, struct volume_group *vg, struct list *pvds) { - struct list *pvdh; struct disk_list *dl; struct physical_volume *pv; struct lv_map *lvms[MAX_LV], *lvm; struct pe_disk *e; uint32_t i, lv_num, le; - list_iterate(pvdh, pvds) { - dl = list_item(pvdh, struct disk_list); + list_iterate_items(dl, pvds) { pv = find_pv(vg, dl->dev); e = dl->extents; @@ -226,7 +221,7 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm) lvm->map[le + len].pe == lvm->map[le].pe + len)); if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le, - len, 0, 0, 1, len, 0, 0))) { + len, 0, 0, NULL, 1, len, 0, 0, 0))) { log_error("Failed to allocate linear segment."); return 0; } @@ -300,8 +295,9 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm) if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, lvm->stripes * le, lvm->stripes * area_len, - 0, lvm->stripe_size, lvm->stripes, - area_len, 0, 0))) { + 0, lvm->stripe_size, NULL, + lvm->stripes, + area_len, 0, 0, 0))) { log_error("Failed to allocate striped segment."); return 0; } diff --git a/lib/format1/vg_number.c b/lib/format1/vg_number.c index c149aa9be..bab07d027 100644 --- a/lib/format1/vg_number.c +++ b/lib/format1/vg_number.c @@ -27,7 +27,6 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter, const char *candidate_vg, int *result) { - struct list *pvh; struct list all_pvs; struct disk_list *dl; struct pool *mem = pool_create("lvm1 vg_number", 10 * 1024); @@ -47,8 +46,7 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter, memset(numbers, 0, sizeof(numbers)); - list_iterate(pvh, &all_pvs) { - dl = list_item(pvh, struct disk_list); + list_iterate_items(dl, &all_pvs) { if (!*dl->pvd.vg_name || !strcmp(dl->pvd.vg_name, candidate_vg)) continue; diff --git a/lib/format_pool/disk_rep.c b/lib/format_pool/disk_rep.c index f6513808d..3c8dbebe7 100644 --- a/lib/format_pool/disk_rep.c +++ b/lib/format_pool/disk_rep.c @@ -57,12 +57,9 @@ static int __read_pool_disk(const struct format_type *fmt, struct device *dev, static void _add_pl_to_list(struct list *head, struct pool_list *data) { - struct list *pvdh; struct pool_list *pl; - list_iterate(pvdh, head) { - pl = list_item(pvdh, struct pool_list); - + list_iterate_items(pl, head) { if (id_equal(&data->pv_uuid, &pl->pv_uuid)) { char uuid[ID_LEN + 7]; @@ -76,7 +73,7 @@ static void _add_pl_to_list(struct list *head, struct pool_list *data) } log_very_verbose("Duplicate PV %s - using md %s", uuid, dev_name(data->dev)); - list_del(pvdh); + list_del(&pl->list); break; } } @@ -247,11 +244,9 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem, struct lvmcache_vginfo *vginfo, struct list *head, uint32_t *devcount) { - - struct list *vgih = NULL; - struct device *dev; - struct pool_list *pl = NULL; - struct pool *tmpmem = NULL; + struct lvmcache_info *info; + struct pool_list *pl; + struct pool *tmpmem; uint32_t sp_count = 0; uint32_t *sp_devs = NULL; @@ -264,16 +259,16 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem, return 0; } - list_iterate(vgih, &vginfo->infos) { - dev = list_item(vgih, struct lvmcache_info)->dev; - if (dev && - !(pl = read_pool_disk(fmt, dev, mem, vginfo->vgname))) + list_iterate_items(info, &vginfo->infos) { + if (info->dev && + !(pl = read_pool_disk(fmt, info->dev, mem, vginfo->vgname))) break; /* * We need to keep track of the total expected number * of devices per subpool */ if (!sp_count) { + /* FIXME pl left uninitialised if !info->dev */ sp_count = pl->pd.pl_subpools; if (!(sp_devs = pool_zalloc(tmpmem, @@ -298,9 +293,8 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem, } *devcount = 0; - for (i = 0; i < sp_count; i++) { + for (i = 0; i < sp_count; i++) *devcount += sp_devs[i]; - } pool_destroy(tmpmem); diff --git a/lib/format_pool/format_pool.c b/lib/format_pool/format_pool.c index b23df7d83..e2831617f 100644 --- a/lib/format_pool/format_pool.c +++ b/lib/format_pool/format_pool.c @@ -33,8 +33,6 @@ static struct user_subpool *_build_usp(struct list *pls, struct pool *mem, int *sps) { - - struct list *plhs; struct pool_list *pl; struct user_subpool *usp = NULL, *cur_sp = NULL; struct user_device *cur_dev = NULL; @@ -43,9 +41,7 @@ static struct user_subpool *_build_usp(struct list *pls, struct pool *mem, * FIXME: Need to do some checks here - I'm tempted to add a * user_pool structure and build the entire thing to check against. */ - list_iterate(plhs, pls) { - pl = list_item(plhs, struct pool_list); - + list_iterate_items(pl, pls) { *sps = pl->pd.pl_subpools; if (!usp && (!(usp = pool_zalloc(mem, sizeof(*usp) * (*sps))))) { log_error("Unable to allocate %d subpool structures", @@ -72,13 +68,13 @@ static struct user_subpool *_build_usp(struct list *pls, struct pool *mem, "structures", pl->pd.pl_sp_devs); return 0; } + cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid]; cur_dev->sp_id = cur_sp->id; cur_dev->devid = pl->pd.pl_sp_id; cur_dev->blocks = pl->pd.pl_blocks; cur_dev->pv = pl->pv; cur_dev->initialized = 1; - } return usp; diff --git a/lib/format_pool/import_export.c b/lib/format_pool/import_export.c index dd3152661..34a78b399 100644 --- a/lib/format_pool/import_export.c +++ b/lib/format_pool/import_export.c @@ -30,12 +30,9 @@ int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls) { - struct list *plhs; struct pool_list *pl; - list_iterate(plhs, pls) { - pl = list_item(plhs, struct pool_list); - + list_iterate_items(pl, pls) { vg->extent_count += ((pl->pd.pl_blocks) / POOL_PE_SIZE); @@ -61,7 +58,6 @@ int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls) int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls) { struct pool_list *pl; - struct list *plhs; struct lv_list *lvl = pool_zalloc(mem, sizeof(*lvl)); struct logical_volume *lv; @@ -88,9 +84,7 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls) list_init(&lv->segments); list_init(&lv->tags); - list_iterate(plhs, pls) { - pl = list_item(plhs, struct pool_list); - + list_iterate_items(pl, pls) { lv->size += pl->pd.pl_blocks; if (lv->name) @@ -134,11 +128,8 @@ int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg, { struct pv_list *pvl; struct pool_list *pl; - struct list *plhs; - - list_iterate(plhs, pls) { - pl = list_item(plhs, struct pool_list); + list_iterate_items(pl, pls) { if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) { log_error("Unable to allocate pv list structure"); return 0; @@ -180,7 +171,7 @@ int import_pool_pv(const struct format_type *fmt, struct pool *mem, pv->pe_size = POOL_PE_SIZE; pv->pe_start = POOL_PE_START; pv->pe_count = pv->size / POOL_PE_SIZE; - pv->pe_alloc_count = pv->pe_count; + pv->pe_alloc_count = 0; list_init(&pv->tags); list_init(&pv->segments); @@ -230,8 +221,8 @@ static int _add_stripe_seg(struct pool *mem, if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur, area_len * usp->num_devs, 0, - usp->striping, usp->num_devs, area_len, - 0, 0))) { + usp->striping, NULL, usp->num_devs, + area_len, 0, 0, 0))) { log_error("Unable to allocate striped lv_segment structure"); return 0; } @@ -271,7 +262,8 @@ static int _add_linear_seg(struct pool *mem, if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur, area_len, 0, usp->striping, - 1, area_len, POOL_PE_SIZE, 0))) { + NULL, 1, area_len, + POOL_PE_SIZE, 0, 0))) { log_error("Unable to allocate linear lv_segment " "structure"); return 0; @@ -295,15 +287,12 @@ static int _add_linear_seg(struct pool *mem, int import_pool_segments(struct list *lvs, struct pool *mem, struct user_subpool *usp, int subpools) { - - struct list *lvhs; struct lv_list *lvl; struct logical_volume *lv; uint32_t le_cur = 0; int i; - list_iterate(lvhs, lvs) { - lvl = list_item(lvhs, struct lv_list); + list_iterate_items(lvl, lvs) { lv = lvl->lv; if (lv->status & SNAPSHOT) @@ -325,5 +314,4 @@ int import_pool_segments(struct list *lvs, struct pool *mem, } return 1; - } diff --git a/lib/format_text/archive.c b/lib/format_text/archive.c index 3f1b09f19..ea2e7db8c 100644 --- a/lib/format_text/archive.c +++ b/lib/format_text/archive.c @@ -91,7 +91,6 @@ static int _split_vg(const char *filename, char *vgname, size_t vg_size, static void _insert_file(struct list *head, struct archive_file *b) { - struct list *bh; struct archive_file *bf = NULL; if (list_empty(head)) { @@ -99,11 +98,9 @@ static void _insert_file(struct list *head, struct archive_file *b) return; } - /* index increases through list */ - list_iterate(bh, head) { - bf = list_item(bh, struct archive_file); - - if (bf->index > b->index) { + /* index reduces through list */ + list_iterate_items(bf, head) { + if (b->index > bf->index) { list_add(&bf->list, &b->list); return; } @@ -200,7 +197,6 @@ static struct list *_scan_archive(struct pool *mem, static void _remove_expired(struct list *archives, uint32_t archives_size, uint32_t retain_days, uint32_t min_archive) { - struct list *bh; struct archive_file *bf; struct stat sb; time_t retain_time; @@ -214,9 +210,7 @@ static void _remove_expired(struct list *archives, uint32_t archives_size, retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY; /* Assume list is ordered oldest first (by index) */ - list_iterate(bh, archives) { - bf = list_item(bh, struct archive_file); - + list_iterate_items(bf, archives) { /* Get the mtime of the file and unlink if too old */ if (stat(bf->path, &sb)) { log_sys_error("stat", bf->path); @@ -280,7 +274,7 @@ int archive_vg(struct volume_group *vg, if (list_empty(archives)) ix = 0; else { - last = list_item(archives->p, struct archive_file); + last = list_item(list_first(archives), struct archive_file); ix = last->index + 1; } @@ -345,7 +339,7 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af) int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname) { - struct list *archives, *ah; + struct list *archives; struct archive_file *af; if (!(archives = _scan_archive(cmd->mem, vgname, dir))) { @@ -356,11 +350,8 @@ int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname) if (list_empty(archives)) log_print("No archives found in %s.", dir); - list_iterate(ah, archives) { - af = list_item(ah, struct archive_file); - + list_iterate_back_items(af, archives) _display_archive(cmd, af); - } pool_free(cmd->mem, archives); diff --git a/lib/format_text/export.c b/lib/format_text/export.c index 310c03f26..f84682b6d 100644 --- a/lib/format_text/export.c +++ b/lib/format_text/export.c @@ -330,7 +330,7 @@ static inline const char *_get_pv_name(struct formatter *f, static int _print_pvs(struct formatter *f, struct volume_group *vg) { - struct list *pvh; + struct pv_list *pvl; struct physical_volume *pv; char buffer[4096]; const char *name; @@ -338,8 +338,8 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg) outf(f, "physical_volumes {"); _inc_indent(f); - list_iterate(pvh, &vg->pvs) { - pv = list_item(pvh, struct pv_list)->pv; + list_iterate_items(pvl, &vg->pvs) { + pv = pvl->pv; if (!(name = _get_pv_name(f, pv))) { stack; @@ -442,22 +442,21 @@ int out_areas(struct formatter *f, const struct lv_segment *seg, _inc_indent(f); for (s = 0; s < seg->area_count; s++) { - switch (seg->area[s].type) { + switch (seg_type(seg, s)) { case AREA_PV: - if (!(name = _get_pv_name(f, seg->area[s].u.pv.pvseg-> - pv))) { + if (!(name = _get_pv_name(f, seg_pv(seg, s)))) { stack; return 0; } outf(f, "\"%s\", %u%s", name, - seg->area[s].u.pv.pvseg->pe, + seg_pe(seg, s), (s == seg->area_count - 1) ? "" : ","); break; case AREA_LV: outf(f, "\"%s\", %u%s", - seg->area[s].u.lv.lv->name, - seg->area[s].u.lv.le, + seg_lv(seg, s)->name, + seg_le(seg, s), (s == seg->area_count - 1) ? "" : ","); } } @@ -467,24 +466,68 @@ int out_areas(struct formatter *f, const struct lv_segment *seg, return 1; } -static int _count_segments(struct logical_volume *lv) +static int _print_lv(struct formatter *f, struct logical_volume *lv) { - int r = 0; - struct list *segh; + struct lv_segment *seg; + char buffer[4096]; + int seg_count; - list_iterate(segh, &lv->segments) - r++; + f->nl(f); + outf(f, "%s {", lv->name); + _inc_indent(f); - return r; + /* FIXME: Write full lvid */ + if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) { + stack; + return 0; + } + + outf(f, "id = \"%s\"", buffer); + + if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) { + stack; + return 0; + } + outf(f, "status = %s", buffer); + + if (!list_empty(&lv->tags)) { + if (!print_tags(&lv->tags, buffer, sizeof(buffer))) { + stack; + return 0; + } + outf(f, "tags = %s", buffer); + } + + if (lv->alloc != ALLOC_INHERIT) + outf(f, "allocation_policy = \"%s\"", + get_alloc_string(lv->alloc)); + + if (lv->read_ahead) + outf(f, "read_ahead = %u", lv->read_ahead); + if (lv->major >= 0) + outf(f, "major = %d", lv->major); + if (lv->minor >= 0) + outf(f, "minor = %d", lv->minor); + outf(f, "segment_count = %u", list_size(&lv->segments)); + f->nl(f); + + seg_count = 1; + list_iterate_items(seg, &lv->segments) { + if (!_print_segment(f, lv->vg, seg_count++, seg)) { + stack; + return 0; + } + } + + _dec_indent(f); + outf(f, "}"); + + return 1; } static int _print_lvs(struct formatter *f, struct volume_group *vg) { - struct list *lvh; - struct logical_volume *lv; - struct lv_segment *seg; - char buffer[4096]; - int seg_count; + struct lv_list *lvl; /* * Don't bother with an lv section if there are no lvs. @@ -495,58 +538,25 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg) outf(f, "logical_volumes {"); _inc_indent(f); - list_iterate(lvh, &vg->lvs) { - lv = list_item(lvh, struct lv_list)->lv; - - f->nl(f); - outf(f, "%s {", lv->name); - _inc_indent(f); - - /* FIXME: Write full lvid */ - if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) { + /* + * Write visible LVs first + */ + list_iterate_items(lvl, &vg->lvs) { + if (!(lvl->lv->status & VISIBLE_LV)) + continue; + if (!_print_lv(f, lvl->lv)) { stack; return 0; } + } - outf(f, "id = \"%s\"", buffer); - - if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) { + list_iterate_items(lvl, &vg->lvs) { + if ((lvl->lv->status & VISIBLE_LV)) + continue; + if (!_print_lv(f, lvl->lv)) { stack; return 0; } - outf(f, "status = %s", buffer); - - if (!list_empty(&lv->tags)) { - if (!print_tags(&lv->tags, buffer, sizeof(buffer))) { - stack; - return 0; - } - outf(f, "tags = %s", buffer); - } - - if (lv->alloc != ALLOC_INHERIT) - outf(f, "allocation_policy = \"%s\"", - get_alloc_string(lv->alloc)); - - if (lv->read_ahead) - outf(f, "read_ahead = %u", lv->read_ahead); - if (lv->major >= 0) - outf(f, "major = %d", lv->major); - if (lv->minor >= 0) - outf(f, "minor = %d", lv->minor); - outf(f, "segment_count = %u", _count_segments(lv)); - f->nl(f); - - seg_count = 1; - list_iterate_items(seg, &lv->segments) { - if (!_print_segment(f, vg, seg_count++, seg)) { - stack; - return 0; - } - } - - _dec_indent(f); - outf(f, "}"); } _dec_indent(f); @@ -563,7 +573,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg) static int _build_pv_names(struct formatter *f, struct volume_group *vg) { int count = 0; - struct list *pvh; + struct pv_list *pvl; struct physical_volume *pv; char buffer[32], *name; @@ -577,8 +587,8 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg) goto bad; } - list_iterate(pvh, &vg->pvs) { - pv = list_item(pvh, struct pv_list)->pv; + list_iterate_items(pvl, &vg->pvs) { + pv = pvl->pv; /* FIXME But skip if there's already an LV called pv%d ! */ if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) { diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c index 04354c2eb..2acd17068 100644 --- a/lib/format_text/flags.c +++ b/lib/format_text/flags.c @@ -52,6 +52,7 @@ static struct flag _lv_flags[] = { {VISIBLE_LV, "VISIBLE"}, {PVMOVE, "PVMOVE"}, {LOCKED, "LOCKED"}, + {MIRROR_LOG, NULL}, {MIRRORED, NULL}, {VIRTUAL, NULL}, {SNAPSHOT, NULL}, diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c index 4d0f3d0b9..9dfb5dbf3 100644 --- a/lib/format_text/format-text.c +++ b/lib/format_text/format-text.c @@ -341,8 +341,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg, struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct raw_locn *rlocn; struct mda_header *mdah; - struct physical_volume *pv; - struct list *pvh; + struct pv_list *pvl; int r = 0; uint32_t new_wrap = 0, old_wrap = 0; @@ -351,9 +350,8 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg, int found = 0; /* Ignore any mda on a PV outside the VG. vgsplit relies on this */ - list_iterate(pvh, &vg->pvs) { - pv = list_item(pvh, struct pv_list)->pv; - if (pv->dev == mdac->area.dev) { + list_iterate_items(pvl, &vg->pvs) { + if (pvl->pv->dev == mdac->area.dev) { found = 1; break; } @@ -446,15 +444,13 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid, struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct mda_header *mdah; struct raw_locn *rlocn; - struct physical_volume *pv; - struct list *pvh; + struct pv_list *pvl; int r = 0; int found = 0; /* Ignore any mda on a PV outside the VG. vgsplit relies on this */ - list_iterate(pvh, &vg->pvs) { - pv = list_item(pvh, struct pv_list)->pv; - if (pv->dev == mdac->area.dev) { + list_iterate_items(pvl, &vg->pvs) { + if (pvl->pv->dev == mdac->area.dev) { found = 1; break; } @@ -518,14 +514,12 @@ static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg, struct metadata_area *mda) { struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; - struct physical_volume *pv; - struct list *pvh; + struct pv_list *pvl; int found = 0; /* Ignore any mda on a PV outside the VG. vgsplit relies on this */ - list_iterate(pvh, &vg->pvs) { - pv = list_item(pvh, struct pv_list)->pv; - if (pv->dev == mdac->area.dev) { + list_iterate_items(pvl, &vg->pvs) { + if (pvl->pv->dev == mdac->area.dev) { found = 1; break; } @@ -784,7 +778,7 @@ static int _scan_file(const struct format_type *fmt) { struct dirent *dirent; struct dir_list *dl; - struct list *dlh, *dir_list; + struct list *dir_list; char *tmp; DIR *d; struct volume_group *vg; @@ -794,8 +788,7 @@ static int _scan_file(const struct format_type *fmt) dir_list = &((struct mda_lists *) fmt->private)->dirs; - list_iterate(dlh, dir_list) { - dl = list_item(dlh, struct dir_list); + list_iterate_items(dl, dir_list) { if (!(d = opendir(dl->dir))) { log_sys_error("opendir", dl->dir); continue; @@ -883,7 +876,7 @@ int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area, static int _scan_raw(const struct format_type *fmt) { struct raw_list *rl; - struct list *rlh, *raw_list; + struct list *raw_list; char vgnamebuf[NAME_LEN + 2]; struct volume_group *vg; struct format_instance fid; @@ -893,9 +886,7 @@ static int _scan_raw(const struct format_type *fmt) fid.fmt = fmt; list_init(&fid.metadata_areas); - list_iterate(rlh, raw_list) { - rl = list_item(rlh, struct raw_list); - + list_iterate_items(rl, raw_list) { /* FIXME We're reading mdah twice here... */ if (vgname_from_mda(fmt, &rl->dev_area, vgnamebuf, sizeof(vgnamebuf))) { @@ -925,6 +916,7 @@ static int _mda_setup(const struct format_type *fmt, uint64_t start1, mda_size1; /* First area - start of disk */ uint64_t start2, mda_size2; /* Second area - end of disk */ uint64_t wipe_size = 8 << SECTOR_SHIFT; + size_t pagesize = getpagesize(); if (!pvmetadatacopies) { /* Space available for PEs */ @@ -952,10 +944,21 @@ static int _mda_setup(const struct format_type *fmt, /* Place mda straight after label area at start of disk */ start1 = LABEL_SCAN_SIZE; + /* Unless the space available is tiny, round to PAGE_SIZE boundary */ + if ((!pe_start && !pe_end) || + ((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) { + mda_adjustment = start1 % pagesize; + if (mda_adjustment) { + start1 += (pagesize - mda_adjustment); + pv->size -= ((pagesize - mda_adjustment) >> + SECTOR_SHIFT); + } + } + /* Ensure it's not going to be bigger than the disk! */ - if (mda_size1 > disk_size) { - log_print("Warning: metadata area fills disk %s", - dev_name(pv->dev)); + if (start1 + mda_size1 > disk_size) { + log_print("Warning: metadata area fills disk leaving no " + "space for data on %s.", dev_name(pv->dev)); /* Leave some free space for rounding */ /* Avoid empty data area as could cause tools problems */ mda_size1 = disk_size - start1 - alignment * 2; @@ -1048,7 +1051,6 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv, struct label *label; struct lvmcache_info *info; struct mda_context *mdac; - struct list *mdash; struct metadata_area *mda; char buf[MDA_HEADER_SIZE]; struct mda_header *mdah = (struct mda_header *) buf; @@ -1076,8 +1078,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv, del_mdas(&info->mdas); else list_init(&info->mdas); - list_iterate(mdash, mdas) { - mda = list_item(mdash, struct metadata_area); + list_iterate_items(mda, mdas) { mdac = mda->metadata_locn; log_debug("Creating metadata area on %s at sector %" PRIu64 " size %" PRIu64 " sectors", @@ -1100,8 +1101,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv, /* Set pe_start to first aligned sector after any metadata * areas that begin before pe_start */ pv->pe_start = PE_ALIGN; - list_iterate(mdash, &info->mdas) { - mda = list_item(mdash, struct metadata_area); + list_iterate_items(mda, &info->mdas) { mdac = (struct mda_context *) mda->metadata_locn; if (pv->dev == mdac->area.dev && (mdac->area.start < (pv->pe_start << SECTOR_SHIFT)) && @@ -1125,8 +1125,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv, return 0; } - list_iterate(mdash, &info->mdas) { - mda = list_item(mdash, struct metadata_area); + list_iterate_items(mda, &info->mdas) { mdac = mda->metadata_locn; memset(&buf, 0, sizeof(buf)); mdah->size = mdac->area.size; @@ -1152,14 +1151,13 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv, static int _add_raw(struct list *raw_list, struct device_area *dev_area) { struct raw_list *rl; - struct list *rlh; /* Already present? */ - list_iterate(rlh, raw_list) { - rl = list_item(rlh, struct raw_list); + list_iterate_items(rl, raw_list) { /* FIXME Check size/overlap consistency too */ if (rl->dev_area.dev == dev_area->dev && - rl->dev_area.start == dev_area->start) return 1; + rl->dev_area.start == dev_area->start) + return 1; } if (!(rl = dbg_malloc(sizeof(struct raw_list)))) { @@ -1180,7 +1178,6 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name, struct lvmcache_info *info; struct metadata_area *mda, *mda_new; struct mda_context *mdac, *mdac_new; - struct list *mdah, *dah; struct data_area_list *da; if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) { @@ -1227,17 +1224,15 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name, list_size(&info->das), dev_name(dev)); return 0; } - list_iterate(dah, &info->das) { - da = list_item(dah, struct data_area_list); + + list_iterate_items(da, &info->das) pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT; - } if (!mdas) return 1; /* Add copy of mdas to supplied list */ - list_iterate(mdah, &info->mdas) { - mda = list_item(mdah, struct metadata_area); + list_iterate_items(mda, &info->mdas) { mdac = (struct mda_context *) mda->metadata_locn; if (!(mda_new = pool_alloc(fmt->cmd->mem, sizeof(*mda_new)))) { log_error("metadata_area allocation failed"); @@ -1327,7 +1322,7 @@ static int _pv_setup(const struct format_type *fmt, { struct metadata_area *mda, *mda_new, *mda2; struct mda_context *mdac, *mdac_new, *mdac2; - struct list *pvmdas, *pvmdash, *mdash; + struct list *pvmdas; struct lvmcache_info *info; int found; uint64_t pe_end = 0; @@ -1342,8 +1337,7 @@ static int _pv_setup(const struct format_type *fmt, /* Iterate through all mdas on this PV */ if ((info = info_from_pvid(pv->dev->pvid))) { pvmdas = &info->mdas; - list_iterate(pvmdash, pvmdas) { - mda = list_item(pvmdash, struct metadata_area); + list_iterate_items(mda, pvmdas) { mdac = (struct mda_context *) mda->metadata_locn; @@ -1351,10 +1345,7 @@ static int _pv_setup(const struct format_type *fmt, /* Ensure it isn't already on list */ found = 0; - list_iterate(mdash, mdas) { - mda2 = - list_item(mdash, - struct metadata_area); + list_iterate_items(mda2, mdas) { if (mda2->ops != &_metadata_text_raw_ops) continue; mdac2 = @@ -1416,9 +1407,10 @@ static struct format_instance *_create_text_instance(const struct format_type struct mda_context *mdac, *mdac_new; struct dir_list *dl; struct raw_list *rl; - struct list *dlh, *dir_list, *rlh, *raw_list, *mdas, *mdash, *infoh; + struct list *dir_list, *raw_list, *mdas; char path[PATH_MAX]; struct lvmcache_vginfo *vginfo; + struct lvmcache_info *info; if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) { log_error("Couldn't allocate format instance object."); @@ -1440,8 +1432,7 @@ static struct format_instance *_create_text_instance(const struct format_type } else { dir_list = &((struct mda_lists *) fmt->private)->dirs; - list_iterate(dlh, dir_list) { - dl = list_item(dlh, struct dir_list); + list_iterate_items(dl, dir_list) { if (lvm_snprintf(path, PATH_MAX, "%s/%s", dl->dir, vgname) < 0) { log_error("Name too long %s/%s", dl->dir, @@ -1461,9 +1452,7 @@ static struct format_instance *_create_text_instance(const struct format_type raw_list = &((struct mda_lists *) fmt->private)->raws; - list_iterate(rlh, raw_list) { - rl = list_item(rlh, struct raw_list); - + list_iterate_items(rl, raw_list) { /* FIXME Cache this; rescan below if some missing */ if (!_raw_holds_vgname(fid, &rl->dev_area, vgname)) continue; @@ -1491,10 +1480,9 @@ static struct format_instance *_create_text_instance(const struct format_type stack; goto out; } - list_iterate(infoh, &vginfo->infos) { - mdas = &(list_item(infoh, struct lvmcache_info)->mdas); - list_iterate(mdash, mdas) { - mda = list_item(mdash, struct metadata_area); + list_iterate_items(info, &vginfo->infos) { + mdas = &info->mdas; + list_iterate_items(mda, mdas) { mdac = (struct mda_context *) mda->metadata_locn; diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c index ec130594f..5da5fc6d3 100644 --- a/lib/format_text/import_vsn1.c +++ b/lib/format_text/import_vsn1.c @@ -223,12 +223,9 @@ static int _read_pv(struct format_instance *fid, struct pool *mem, static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg) { - struct list *segh; struct lv_segment *comp; - list_iterate(segh, &lv->segments) { - comp = list_item(segh, struct lv_segment); - + list_iterate_items(comp, &lv->segments) { if (comp->le > seg->le) { list_add(&comp->list, &seg->list); return; @@ -291,8 +288,8 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, } if (!(seg = alloc_lv_segment(mem, segtype, lv, start_extent, - extent_count, 0, 0, area_count, - extent_count, 0, 0))) { + extent_count, 0, 0, NULL, area_count, + extent_count, 0, 0, 0))) { log_error("Segment allocation failed"); return 0; } @@ -369,7 +366,6 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn, /* * Adjust extent counts in the pv and vg. */ - pv->pe_alloc_count += seg->area_len; seg->lv->vg->free_count -= seg->area_len; } else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) { set_lv_segment_area_lv(seg, s, lv1, cv->next->v.i); @@ -436,7 +432,7 @@ static int _read_segments(struct pool *mem, struct volume_group *vg, /* * Check there are no gaps or overlaps in the lv. */ - if (!lv_check_segments(lv)) { + if (!check_lv_segments(lv)) { stack; return 0; } diff --git a/lib/format_text/layout.h b/lib/format_text/layout.h index a60be8a93..2f7ec8bc5 100644 --- a/lib/format_text/layout.h +++ b/lib/format_text/layout.h @@ -81,5 +81,6 @@ struct mda_context { #define FMTT_VERSION 1 #define MDA_HEADER_SIZE 512 #define LVM2_LABEL "LVM2 001" +#define MDA_SIZE_MIN (8 * getpagesize()) #endif diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c index 3cecf4bdb..bc43766e1 100644 --- a/lib/format_text/text_label.c +++ b/lib/format_text/text_label.c @@ -39,7 +39,6 @@ static int _write(struct label *label, char *buf) struct pv_header *pvhdr; struct lvmcache_info *info; struct disk_locn *pvh_dlocn_xl; - struct list *mdash, *dash; struct metadata_area *mda; struct mda_context *mdac; struct data_area_list *da; @@ -57,9 +56,7 @@ static int _write(struct label *label, char *buf) pvh_dlocn_xl = &pvhdr->disk_areas_xl[0]; /* List of data areas (holding PEs) */ - list_iterate(dash, &info->das) { - da = list_item(dash, struct data_area_list); - + list_iterate_items(da, &info->das) { pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset); pvh_dlocn_xl->size = xlate64(da->disk_locn.size); pvh_dlocn_xl++; @@ -71,8 +68,7 @@ static int _write(struct label *label, char *buf) pvh_dlocn_xl++; /* List of metadata area header locations */ - list_iterate(mdash, &info->mdas) { - mda = list_item(mdash, struct metadata_area); + list_iterate_items(mda, &info->mdas) { mdac = (struct mda_context *) mda->metadata_locn; if (mdac->area.dev != info->dev) @@ -198,7 +194,6 @@ static int _read(struct labeller *l, struct device *dev, char *buf, struct lvmcache_info *info; struct disk_locn *dlocn_xl; uint64_t offset; - struct list *mdah; struct metadata_area *mda; char vgnamebuf[NAME_LEN + 2]; struct mda_context *mdac; @@ -235,8 +230,7 @@ static int _read(struct labeller *l, struct device *dev, char *buf, dlocn_xl++; } - list_iterate(mdah, &info->mdas) { - mda = list_item(mdah, struct metadata_area); + list_iterate_items(mda, &info->mdas) { mdac = (struct mda_context *) mda->metadata_locn; if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf, sizeof(vgnamebuf))) { diff --git a/lib/label/label.c b/lib/label/label.c index beda8e970..b5faa20eb 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -98,14 +98,11 @@ int label_register_handler(const char *name, struct labeller *handler) struct labeller *label_get_handler(const char *name) { - struct list *lih; struct labeller_i *li; - list_iterate(lih, &_labellers) { - li = list_item(lih, struct labeller_i); + list_iterate_items(li, &_labellers) if (!strcmp(li->name, name)) return li->l; - } return NULL; } @@ -113,7 +110,6 @@ struct labeller *label_get_handler(const char *name) static struct labeller *_find_labeller(struct device *dev, char *buf, uint64_t *label_sector) { - struct list *lih; struct labeller_i *li; struct labeller *r = NULL; struct label_header *lh; @@ -166,8 +162,7 @@ static struct labeller *_find_labeller(struct device *dev, char *buf, continue; } - list_iterate(lih, &_labellers) { - li = list_item(lih, struct labeller_i); + list_iterate_items(li, &_labellers) { if (li->l->ops->can_handle(li->l, (char *) lh, sector)) { log_very_verbose("%s: %s label detected", dev_name(dev), li->name); @@ -208,7 +203,6 @@ int label_remove(struct device *dev) int r = 1; uint64_t sector; int wipe; - struct list *lih; struct labeller_i *li; struct label_header *lh; @@ -244,8 +238,7 @@ int label_remove(struct device *dev) if (xlate64(lh->sector_xl) == sector) wipe = 1; } else { - list_iterate(lih, &_labellers) { - li = list_item(lih, struct labeller_i); + list_iterate_items(li, &_labellers) { if (li->l->ops->can_handle(li->l, (char *) lh, sector)) { wipe = 1; diff --git a/lib/locking/locking.c b/lib/locking/locking.c index b3cbaf228..0e90aa3a8 100644 --- a/lib/locking/locking.c +++ b/lib/locking/locking.c @@ -265,13 +265,10 @@ int lock_vol(struct cmd_context *cmd, const char *vol, int flags) /* Unlock list of LVs */ int resume_lvs(struct cmd_context *cmd, struct list *lvs) { - struct list *lvh; - struct logical_volume *lv; + struct lv_list *lvl; - list_iterate(lvh, lvs) { - lv = list_item(lvh, struct lv_list)->lv; - resume_lv(cmd, lv->lvid.s); - } + list_iterate_items(lvl, lvs) + resume_lv(cmd, lvl->lv->lvid.s); return 1; } @@ -280,15 +277,14 @@ int resume_lvs(struct cmd_context *cmd, struct list *lvs) int suspend_lvs(struct cmd_context *cmd, struct list *lvs) { struct list *lvh; - struct logical_volume *lv; + struct lv_list *lvl; - list_iterate(lvh, lvs) { - lv = list_item(lvh, struct lv_list)->lv; - if (!suspend_lv(cmd, lv->lvid.s)) { - log_error("Failed to suspend %s", lv->name); - list_uniterate(lvh, lvs, lvh) { - lv = list_item(lvh, struct lv_list)->lv; - resume_lv(cmd, lv->lvid.s); + list_iterate_items(lvl, lvs) { + if (!suspend_lv(cmd, lvl->lv->lvid.s)) { + log_error("Failed to suspend %s", lvl->lv->name); + list_uniterate(lvh, lvs, &lvl->list) { + lvl = list_item(lvh, struct lv_list); + resume_lv(cmd, lvl->lv->lvid.s); } return 0; @@ -302,15 +298,14 @@ int suspend_lvs(struct cmd_context *cmd, struct list *lvs) int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs) { struct list *lvh; - struct logical_volume *lv; + struct lv_list *lvl; - list_iterate(lvh, lvs) { - lv = list_item(lvh, struct lv_list)->lv; - if (!activate_lv_excl(cmd, lv->lvid.s)) { - log_error("Failed to activate %s", lv->name); - list_uniterate(lvh, lvs, lvh) { - lv = list_item(lvh, struct lv_list)->lv; - activate_lv(cmd, lv->lvid.s); + list_iterate_items(lvl, lvs) { + if (!activate_lv_excl(cmd, lvl->lv->lvid.s)) { + log_error("Failed to activate %s", lvl->lv->name); + list_uniterate(lvh, lvs, &lvl->list) { + lvl = list_item(lvh, struct lv_list); + activate_lv(cmd, lvl->lv->lvid.s); } return 0; diff --git a/lib/locking/locking_types.h b/lib/locking/locking_types.h index 4bc0803e6..2d5a0ba5b 100644 --- a/lib/locking/locking_types.h +++ b/lib/locking/locking_types.h @@ -41,4 +41,5 @@ int init_no_locking(struct locking_type *locking, struct config_tree *cf); int init_file_locking(struct locking_type *locking, struct config_tree *cf); int init_external_locking(struct locking_type *locking, struct config_tree *cf); + int init_cluster_locking(struct locking_type *locking, struct config_tree *cf); diff --git a/lib/metadata/lv_alloc.h b/lib/metadata/lv_alloc.h index 4607b802c..cb0a5a4bb 100644 --- a/lib/metadata/lv_alloc.h +++ b/lib/metadata/lv_alloc.h @@ -22,17 +22,49 @@ struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t le, uint32_t len, uint32_t status, uint32_t stripe_size, + struct logical_volume *log_lv, uint32_t area_count, uint32_t area_len, uint32_t chunk_size, + uint32_t region_size, uint32_t extents_copied); struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv, - uint32_t allocated); + uint32_t status, uint32_t old_le_count); int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num, struct physical_volume *pv, uint32_t pe); void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num, struct logical_volume *lv, uint32_t le); +struct alloc_handle; +struct alloc_handle *allocate_extents(struct volume_group *vg, + struct logical_volume *lv, + struct segment_type *segtype, + uint32_t stripes, + uint32_t mirrors, uint32_t log_count, + uint32_t extents, + struct physical_volume *mirrored_pv, + uint32_t mirrored_pe, + uint32_t status, + struct list *allocatable_pvs, + alloc_policy_t alloc); + +int lv_add_segment(struct alloc_handle *ah, + uint32_t first_area, uint32_t num_areas, + struct logical_volume *lv, + struct segment_type *segtype, + uint32_t stripe_size, + struct physical_volume *mirrored_pv, + uint32_t mirrored_pe, + uint32_t status, + uint32_t region_size, + struct logical_volume *log_lv); + +int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv); +int lv_add_virtual_segment(struct logical_volume *lv, uint32_t status, + uint32_t extents, struct segment_type *segtype); + +void alloc_destroy(struct alloc_handle *ah); + #endif diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 37ceccc7e..47bd3c9fc 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -25,52 +25,45 @@ #include "segtype.h" /* - * These functions adjust the pe counts in pv's - * after we've added or removed segments. + * Find first unused LV number. */ -static void _get_extents(struct lv_segment *seg) +uint32_t find_free_lvnum(struct logical_volume *lv) { - unsigned int s, count; - struct physical_volume *pv; + int lvnum_used[MAX_RESTRICTED_LVS + 1]; + uint32_t i = 0; + struct lv_list *lvl; + int lvnum; - for (s = 0; s < seg->area_count; s++) { - if (seg->area[s].type != AREA_PV) - continue; + memset(&lvnum_used, 0, sizeof(lvnum_used)); - pv = seg->area[s].u.pv.pvseg->pv; - count = seg->area_len; - pv->pe_alloc_count += count; - } -} - -static void _put_extents(struct lv_segment *seg) -{ - unsigned int s, count; - struct physical_volume *pv; - - for (s = 0; s < seg->area_count; s++) { - if (seg->area[s].type != AREA_PV) - continue; - - pv = seg->area[s].u.pv.pvseg->pv; - - if (pv) { - count = seg->area_len; - assert(pv->pe_alloc_count >= count); - pv->pe_alloc_count -= count; - } + list_iterate_items(lvl, &lv->vg->lvs) { + lvnum = lvnum_from_lvid(&lvl->lv->lvid); + if (lvnum <= MAX_RESTRICTED_LVS) + lvnum_used[lvnum] = 1; } + + while (lvnum_used[i]) + i++; + + /* FIXME What if none are free? */ + + return i; } +/* + * All lv_segments get created here. + */ struct lv_segment *alloc_lv_segment(struct pool *mem, struct segment_type *segtype, struct logical_volume *lv, uint32_t le, uint32_t len, uint32_t status, uint32_t stripe_size, + struct logical_volume *log_lv, uint32_t area_count, uint32_t area_len, uint32_t chunk_size, + uint32_t region_size, uint32_t extents_copied) { struct lv_segment *seg; @@ -90,18 +83,53 @@ struct lv_segment *alloc_lv_segment(struct pool *mem, seg->area_count = area_count; seg->area_len = area_len; seg->chunk_size = chunk_size; + seg->region_size = region_size; seg->extents_copied = extents_copied; + seg->log_lv = log_lv; list_init(&seg->tags); + if (log_lv) + log_lv->status |= MIRROR_LOG; + return seg; } +struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv, + uint32_t status, uint32_t old_le_count) +{ + struct lv_segment *seg; + struct segment_type *segtype; + + segtype = get_segtype_from_string(lv->vg->cmd, "snapshot"); + if (!segtype) { + log_error("Failed to find snapshot segtype"); + return NULL; + } + + if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, old_le_count, + lv->le_count - old_le_count, status, 0, + NULL, 0, lv->le_count - old_le_count, + 0, 0, 0))) { + log_error("Couldn't allocate new snapshot segment."); + return NULL; + } + + list_add(&lv->segments, &seg->list); + lv->status |= VIRTUAL; + + return seg; +} + +/* + * Link part of a PV to an LV segment. + */ int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num, struct physical_volume *pv, uint32_t pe) { seg->area[area_num].type = AREA_PV; + pv->pe_alloc_count += seg->area_len; - if (!(seg->area[area_num].u.pv.pvseg = + if (!(seg_pvseg(seg, area_num) = assign_peg_to_lvseg(pv, pe, seg->area_len, seg, area_num))) { stack; return 0; @@ -110,63 +138,240 @@ int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num, return 1; } +/* + * Link one LV segment to another. Assumes sizes already match. + */ void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num, struct logical_volume *lv, uint32_t le) { seg->area[area_num].type = AREA_LV; - seg->area[area_num].u.lv.lv = lv; - seg->area[area_num].u.lv.le = le; -} - -static void _shrink_lv_segment(struct lv_segment *seg) -{ - uint32_t s; - - for (s = 0; s < seg->area_count; s++) { - if (seg->area[s].type != AREA_PV) - continue; - release_pv_segment(seg->area[s].u.pv.pvseg, seg->area_len); - } + seg_lv(seg, area_num) = lv; + seg_le(seg, area_num) = le; } /* - * The heart of the allocation code. This function takes a list of - * pv_area and allocates them to the lv. If the lv doesn't need - * the complete area then the area is split, otherwise the area - * is unlinked from the pv_map. + * Reduce the size of an lv_segment. New size can be zero. */ -static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count, - uint32_t stripe_size, - struct segment_type *segtype, - struct pv_area **areas, uint32_t *ix, - struct physical_volume *mirrored_pv, - uint32_t mirrored_pe) +static int _lv_segment_reduce(struct lv_segment *seg, uint32_t reduction) { - uint32_t area_len, smallest, remaining; - uint32_t s; - uint32_t extra_areas = 0; - struct lv_segment *seg; - struct pv_area *pva; - int striped = 0; + uint32_t area_reduction, s; - /* Striped or mirrored? */ - if (seg_is_striped(seg)) - striped = 1; + /* Caller must ensure exact divisibility */ + if (seg_is_striped(seg)) { + if (reduction % seg->area_count) { + log_error("Segment extent reduction %" PRIu32 + "not divisible by #stripes %" PRIu32, + reduction, seg->area_count); + return 0; + } + area_reduction = (reduction / seg->area_count); + } else + area_reduction = reduction; + + seg->len -= reduction; + seg->area_len -= area_reduction; + seg->lv->vg->free_count += area_reduction * seg->area_count; + + for (s = 0; s < seg->area_count; s++) { + if (seg_type(seg, s) != AREA_PV) + continue; + release_pv_segment(seg_pvseg(seg, s), area_reduction); + } + + return 1; +} + +/* + * Entry point for all LV reductions in size. + */ +int lv_reduce(struct logical_volume *lv, uint32_t extents) +{ + struct lv_segment *seg; + uint32_t count = extents; + uint32_t reduction; + + list_iterate_back_items(seg, &lv->segments) { + if (!count) + break; + + if (seg->len <= count) { + /* remove this segment completely */ + /* FIXME Check this is safe */ + if (seg->log_lv && !lv_remove(seg->log_lv)) { + stack; + return 0; + } + list_del(&seg->list); + reduction = seg->len; + } else + reduction = count; + + if (!_lv_segment_reduce(seg, reduction)) { + stack; + return 0; + } + count -= reduction; + } + + lv->le_count -= extents; + lv->size = (uint64_t) lv->le_count * lv->vg->extent_size; + + if (lv->le_count && lv->vg->fid->fmt->ops->lv_setup && + !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) { + stack; + return 0; + } + + return 1; +} + +/* + * Completely remove an LV. + */ +int lv_remove(struct logical_volume *lv) +{ + struct lv_list *lvl; + + if (!lv_reduce(lv, lv->le_count)) { + stack; + return 0; + } + + /* find the lv list */ + if (!(lvl = find_lv_in_vg(lv->vg, lv->name))) { + stack; + return 0; + } + + list_del(&lvl->list); + + lv->vg->lv_count--; + + return 1; +} + +/* + * A set of contiguous physical extents allocated + */ +struct alloced_area { + struct list list; + + struct physical_volume *pv; + uint32_t pe; + uint32_t len; +}; + +/* + * Details of an allocation attempt + */ +struct alloc_handle { + struct pool *mem; + + alloc_policy_t alloc; /* Overall policy */ + uint32_t area_count; /* Number of parallel areas */ + uint32_t area_multiple; /* seg->len = area_len * area_multiple */ + uint32_t log_count; /* Number of parallel 1-extent logs */ + + struct alloced_area log_area; /* Extent used for log */ + struct list alloced_areas[0]; /* Lists of areas in each stripe */ +}; + +/* + * Preparation for a specific allocation attempt + */ +static struct alloc_handle *_alloc_init(struct pool *mem, + struct segment_type *segtype, + alloc_policy_t alloc, + uint32_t mirrors, + uint32_t stripes, + uint32_t log_count, + struct physical_volume *mirrored_pv) +{ + struct alloc_handle *ah; + uint32_t s, area_count; + + if (stripes > 1 && mirrors > 1) { + log_error("striped mirrors are not supported yet"); + return NULL; + } + + if ((stripes > 1 || mirrors > 1) && mirrored_pv) { + log_error("Can't mix striping or mirroring with " + "creation of a mirrored PV yet"); + return NULL; + } + + if (log_count && (stripes > 1 || mirrored_pv)) { + log_error("Can't mix striping or pvmove with " + "a mirror log yet."); + return NULL; + } + + if (segtype_is_virtual(segtype)) + area_count = 0; + else if (mirrors > 1) + area_count = mirrors; + else if (mirrored_pv) + area_count = 1; + else + area_count = stripes; + + if (!(ah = pool_zalloc(mem, sizeof(*ah) + sizeof(ah->alloced_areas[0]) * area_count))) { + log_error("allocation handle allocation failed"); + return NULL; + } + + if (segtype_is_virtual(segtype)) + return ah; + + if (!(ah->mem = pool_create("allocation", 1024))) { + log_error("allocation pool creation failed"); + return NULL; + } + + ah->area_count = area_count; + ah->log_count = log_count; + ah->alloc = alloc; + ah->area_multiple = segtype_is_striped(segtype) ? ah->area_count : 1; + + list_init(&ah->alloced_areas[0]); + + for (s = 0; s < ah->area_count; s++) + list_init(&ah->alloced_areas[s]); + + return ah; +} + +void alloc_destroy(struct alloc_handle *ah) +{ + if (ah->mem) + pool_destroy(ah->mem); +} + +static int _setup_alloced_segment(struct logical_volume *lv, uint32_t status, + uint32_t area_count, + uint32_t stripe_size, + struct segment_type *segtype, + struct alloced_area *aa, + struct physical_volume *mirrored_pv, + uint32_t mirrored_pe, + uint32_t region_size, + struct logical_volume *log_lv) +{ + uint32_t s, extents, area_multiple, extra_areas = 0; + struct lv_segment *seg; if (mirrored_pv) extra_areas = 1; - remaining = lv->le_count - *ix; - area_len = remaining / (striped ? area_count : 1); - smallest = areas[area_count - 1]->count; + area_multiple = segtype_is_striped(segtype) ? area_count : 1; - if (area_len > smallest) - area_len = smallest; - - if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, *ix, - area_len * (striped ? area_count : 1), - 0u, stripe_size, area_count + extra_areas, - area_len, 0u, 0u))) { + if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, + lv->le_count, + aa[0].len * area_multiple, + status, stripe_size, log_lv, + area_count + extra_areas, + aa[0].len, 0u, region_size, 0u))) { log_error("Couldn't allocate new LV segment."); return 0; } @@ -179,24 +384,102 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count, } for (s = 0; s < area_count; s++) { - pva = areas[s]; - if (!set_lv_segment_area_pv(seg, s + extra_areas, pva->map->pv, - pva->start)) { + if (!set_lv_segment_area_pv(seg, s + extra_areas, aa[s].pv, + aa[s].pe)) { stack; return 0; } - consume_pv_area(pva, area_len); } list_add(&lv->segments, &seg->list); - *ix += seg->len; - if (!striped) + extents = aa[0].len * area_multiple; + lv->le_count += extents; + lv->size += (uint64_t) extents *lv->vg->extent_size; + + lv->vg->free_count -= aa[0].len * area_count; + + if (segtype_is_mirrored(segtype)) lv->status |= MIRRORED; return 1; } +static int _setup_alloced_segments(struct logical_volume *lv, + struct list *alloced_areas, + uint32_t area_count, + uint32_t status, + uint32_t stripe_size, + struct segment_type *segtype, + struct physical_volume *mirrored_pv, + uint32_t mirrored_pe, + uint32_t region_size, + struct logical_volume *log_lv) +{ + struct alloced_area *aa; + + list_iterate_items(aa, &alloced_areas[0]) { + if (!_setup_alloced_segment(lv, status, area_count, + stripe_size, segtype, aa, + mirrored_pv, mirrored_pe, + region_size, log_lv)) { + stack; + return 0; + } + } + + return 1; +} + +/* + * This function takes a list of pv_areas and adds them to allocated_areas. + * If the complete area is not needed then it gets split. + * The part used is removed from the pv_map so it can't be allocated twice. + */ +static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed, + struct pv_area **areas, + uint32_t *ix, struct pv_area *log_area) +{ + uint32_t area_len, smallest, remaining; + uint32_t s; + struct alloced_area *aa; + + remaining = needed - *ix; + area_len = remaining / ah->area_multiple; + + smallest = areas[ah->area_count - 1]->count; + + if (area_len > smallest) + area_len = smallest; + + if (!(aa = pool_alloc(ah->mem, sizeof(*aa) * + (ah->area_count + (log_area ? 1 : 0))))) { + log_error("alloced_area allocation failed"); + return 0; + } + + for (s = 0; s < ah->area_count; s++) { + aa[s].pv = areas[s]->map->pv; + aa[s].pe = areas[s]->start; + aa[s].len = area_len; + list_add(&ah->alloced_areas[s], &aa[s].list); + } + + for (s = 0; s < ah->area_count; s++) + consume_pv_area(areas[s], area_len); + + if (log_area) { + ah->log_area.pv = log_area->map->pv; + ah->log_area.pe = log_area->start; + ah->log_area.len = 1; /* FIXME Calculate & check this */ + consume_pv_area(log_area, ah->log_area.len); + } + + *ix += area_len * ah->area_multiple; + + return 1; +} + static int _comp_area(const void *l, const void *r) { const struct pv_area *lhs = *((const struct pv_area **) l); @@ -211,97 +494,244 @@ static int _comp_area(const void *l, const void *r) return 0; } -static int _alloc_parallel(struct logical_volume *lv, alloc_policy_t alloc, - struct list *pvms, uint32_t allocated, - uint32_t stripes, uint32_t stripe_size, - uint32_t mirrors, struct segment_type *segtype, - struct physical_volume *mirrored_pv, - uint32_t mirrored_pe) +/* + * Is pva contiguous to any existing areas or on the same PV? + */ +static int _check_contiguous(struct lv_segment *prev_lvseg, + struct physical_volume *pv, struct pv_area *pva, + struct pv_area **areas) +{ + struct pv_segment *prev_pvseg; + uint32_t s; + + for (s = 0; s < prev_lvseg->area_count; s++) { + if (seg_type(prev_lvseg, s) != AREA_PV) + continue; /* FIXME Broken */ + + if (!(prev_pvseg = seg_pvseg(prev_lvseg, s))) + continue; /* FIXME Broken */ + + if ((prev_pvseg->pv != pv)) + continue; + + if (prev_pvseg->pe + prev_pvseg->len == pva->start) { + areas[s] = pva; + return 1; + } + } + + return 0; +} + +/* + * Choose sets of parallel areas to use, respecting any constraints. + */ +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) { - int r = 0; - struct pv_area **areas, *pva; - unsigned int pv_count, ix; struct pv_map *pvm; - uint32_t area_count, largest = 0; + struct pv_area *pva; + unsigned already_found_one = 0; + unsigned contiguous = 0, contiguous_count = 0; + unsigned ix; + unsigned ix_offset = 0; /* Offset for non-contiguous allocations */ - if (stripes > 1 && mirrors > 1) { - log_error("striped mirrors are not supported yet"); - return 0; + /* FIXME Do calculations on free extent counts before selecting space */ + /* FIXME Select log PV appropriately if there isn't one yet */ + + if ((alloc == ALLOC_CONTIGUOUS)) { + contiguous = 1; + if (prev_lvseg) + ix_offset = prev_lvseg->area_count; + else + ix_offset = ah->area_count; } - if ((stripes > 1 || mirrors > 1) && mirrored_pv) { - log_error("Can't mix striping or mirroring with " - "creation of a mirrored PV yet"); - return 0; - } - - if (stripes > 1) - area_count = stripes; - else if (mirrored_pv) - area_count = 1; - else - area_count = mirrors; - - pv_count = list_size(pvms); - - /* allocate an array of pv_areas, one candidate per pv */ - if (!(areas = dbg_malloc(sizeof(*areas) * pv_count))) { - log_err("Couldn't allocate areas array."); - return 0; - } - - while (allocated != lv->le_count) { + /* FIXME This algorithm needs a lot of cleaning up! */ + /* FIXME anywhere doesn't find all space yet */ + /* ix_offset holds the number of allocations that must be contiguous */ + /* ix holds the number of areas found on other PVs */ + do { ix = 0; - /* Put the largest area on each PV into areas array */ + + /* + * Put the smallest area of each PV that is at least the + * size we need into areas array. If there isn't one + * that fits completely and we're allowed more than one + * LV segment, then take the largest remaining instead. + */ list_iterate_items(pvm, pvms) { if (list_empty(&pvm->areas)) - continue; + continue; /* Next PV */ + /* Don't allocate onto the log pv */ + if ((alloc != ALLOC_ANYWHERE) && ah->log_count && + (pvm->pv == ah->log_area.pv)) + continue; /* Next PV */ + + already_found_one = 0; + /* First area in each list is the largest */ list_iterate_items(pva, &pvm->areas) { - if (pva->count > largest) - largest = pva->count; - - if (mirrored_pv) { - if (pva->count < lv->le_count - allocated) - goto next_pv; + if (contiguous) { + if (prev_lvseg && + _check_contiguous(prev_lvseg, + pvm->pv, + pva, areas)) { + contiguous_count++; + break; /* Next PV */ + } + continue; } - areas[ix++] = pva; - if (mirrored_pv) - goto try_it; + /* Is it big enough on its own? */ + if ((pva->count < needed - *allocated) && + ((!can_split && !ah->log_count) || + (already_found_one && + !(alloc == ALLOC_ANYWHERE)))) + break; /* Next PV */ + + if (!already_found_one || + alloc == ALLOC_ANYWHERE) { + ix++; + already_found_one = 1; + } + + areas[ix + ix_offset -1] = pva; + + break; /* Next PV */ } - next_pv: - ; + if (ix >= areas_size) + break; } - try_it: - if (ix < area_count) + if (contiguous && (contiguous_count < ix_offset)) + break; + + if (ix + ix_offset < ah->area_count + ah->log_count) + /* FIXME With ALLOC_ANYWHERE, need to split areas */ break; /* sort the areas so we allocate from the biggest */ if (ix > 1) - qsort(areas, ix, sizeof(*areas), _comp_area); + qsort(areas + ix_offset, ix, sizeof(*areas), + _comp_area); - if (!_alloc_parallel_area(lv, area_count, stripe_size, segtype, - areas, &allocated, mirrored_pv, mirrored_pe)) { + if (!_alloc_parallel_area(ah, needed, areas, + allocated, + ah->log_count ? + *(areas + ix_offset + ix - 1) : + NULL)) { stack; - goto out; + return 0; } - if (mirrored_pv) - break; + } while (*allocated != needed && can_split); + + return 1; +} + +/* + * Allocate several segments, each the same size, in parallel. + * If mirrored_pv and mirrored_pe are supplied, it is used as + * the first area, and additional areas are allocated parallel to it. + */ +static int _allocate(struct alloc_handle *ah, + struct volume_group *vg, + struct logical_volume *lv, uint32_t status, + uint32_t new_extents, + struct list *allocatable_pvs, + uint32_t stripes, uint32_t mirrors, + struct segment_type *segtype, + struct physical_volume *mirrored_pv, + uint32_t mirrored_pe) +{ + struct pv_area **areas; + uint32_t allocated = lv ? lv->le_count : 0; + uint32_t old_allocated; + struct lv_segment *prev_lvseg = NULL; + unsigned can_split = 1; /* Are we allowed more than one segment? */ + int r = 0; + struct list *pvms; + uint32_t areas_size; + + if (allocated >= new_extents) { + log_error("_allocate called with no work to do!"); + return 1; } - if (allocated != lv->le_count) { - if (mirrored_pv) - log_error("Insufficient contiguous allocatable extents " - "(%u) for logical volume %s: %u required", - largest, lv->name, lv->le_count - allocated); - else - log_error("Insufficient allocatable extents suitable " - "for parallel use for logical volume %s: " - "%u more required", lv->name, - lv->le_count - allocated); + if (mirrored_pv || (ah->alloc == ALLOC_CONTIGUOUS) || ah->log_count) + can_split = 0; + + if (lv && !list_empty(&lv->segments)) + prev_lvseg = list_item(list_last(&lv->segments), + struct lv_segment); + /* + * Build the sets of available areas on the pv's. + */ + if (!(pvms = create_pv_maps(ah->mem, vg, allocatable_pvs))) { + stack; + return 0; + } + + areas_size = list_size(pvms); + if (areas_size < ah->area_count + ah->log_count) { + if (ah->alloc != ALLOC_ANYWHERE) { + log_error("Not enough PVs with free space available " + "for parallel allocation."); + log_error("Consider --alloc anywhere if desperate."); + return 0; + } + areas_size = ah->area_count + ah->log_count; + } + + /* Allocate an array of pv_areas to hold the largest space on each PV */ + if (!(areas = dbg_malloc(sizeof(*areas) * areas_size))) { + log_err("Couldn't allocate areas array."); + return 0; + } + + old_allocated = allocated; + if (!_find_parallel_space(ah, ALLOC_CONTIGUOUS, pvms, areas, + areas_size, can_split, + prev_lvseg, &allocated, new_extents)) { + stack; + goto out; + } + + if ((allocated == new_extents) || (ah->alloc == ALLOC_CONTIGUOUS) || + (!can_split && (allocated != old_allocated))) + goto finished; + + old_allocated = allocated; + if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas, + areas_size, can_split, + prev_lvseg, &allocated, new_extents)) { + stack; + goto out; + } + + if ((allocated == new_extents) || (ah->alloc == ALLOC_NORMAL) || + (!can_split && (allocated != old_allocated))) + goto finished; + + if (!_find_parallel_space(ah, ALLOC_ANYWHERE, pvms, areas, + areas_size, can_split, + prev_lvseg, &allocated, new_extents)) { + stack; + goto out; + } + + finished: + if (allocated != new_extents) { + log_error("Insufficient suitable %sallocatable extents " + "for logical volume %s: %u more required", + can_split ? "" : "contiguous ", + lv ? lv->name : "", + (new_extents - allocated) * ah->area_count + / ah->area_multiple); goto out; } @@ -312,183 +742,197 @@ static int _alloc_parallel(struct logical_volume *lv, alloc_policy_t alloc, return r; } -/* - * For contiguous, only one area per pv is allowed, so we search - * for the biggest area, or the first area that can complete - * the allocation. If there is an existing segment, new space must - * be contiguous to it. - */ -static int _alloc_next_free(struct logical_volume *lv, alloc_policy_t alloc, - struct list *pvms, uint32_t allocated, - struct segment_type *segtype) -{ - struct pv_map *pvm; - struct pv_area *pva; - uint32_t prev_allocated = allocated; - struct lv_segment *prev_lvseg; - struct pv_segment *prev_pvseg = NULL; - uint32_t largest = 0; - int contiguous = 0; - - /* So far the only case is exactly one area */ - if ((alloc == ALLOC_CONTIGUOUS)) - contiguous = 1; - - if (contiguous && - (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; - - list_iterate_items(pvm, pvms) { - if (prev_pvseg && (prev_pvseg->pv != pvm->pv)) - continue; - - list_iterate_items(pva, &pvm->areas) { - if (prev_pvseg && - (prev_pvseg->pe + prev_pvseg->len != pva->start)) - continue; - - if (pva->count > largest) - largest = pva->count; - - /* first item in the list is the biggest */ - if (contiguous && - pva->count < lv->le_count - allocated) - goto next_pv; - - if (!_alloc_parallel_area(lv, 1, 0, segtype, &pva, - &allocated, NULL, 0)) { - stack; - return 0; - } - - if (contiguous || (allocated == lv->le_count)) - goto out; - } - - next_pv: - ; - } - - out: - if (allocated != lv->le_count) { - log_error("Insufficient %sallocatable extents (%u) " - "for logical volume %s: %u required", - contiguous ? "contiguous " : "", - contiguous ? largest : allocated - prev_allocated, - lv->name, lv->le_count - prev_allocated); - return 0; - } - - return 1; -} - -static int _alloc_virtual(struct logical_volume *lv, - uint32_t allocated, struct segment_type *segtype) +int lv_add_virtual_segment(struct logical_volume *lv, uint32_t status, + uint32_t extents, struct segment_type *segtype) { struct lv_segment *seg; - if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, allocated, - lv->le_count - allocated, 0, 0, 0, - lv->le_count - allocated, 0, 0))) { + if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, + lv->le_count, extents, status, 0, + NULL, 0, extents, 0, 0, 0))) { log_error("Couldn't allocate new zero segment."); return 0; } list_add(&lv->segments, &seg->list); + + lv->le_count += extents; + lv->size += (uint64_t) extents *lv->vg->extent_size; + lv->status |= VIRTUAL; return 1; } -struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv, - uint32_t allocated) +/* + * Entry point for all extent allocations. + */ +struct alloc_handle *allocate_extents(struct volume_group *vg, + struct logical_volume *lv, + struct segment_type *segtype, + uint32_t stripes, + uint32_t mirrors, uint32_t log_count, + uint32_t extents, + struct physical_volume *mirrored_pv, + uint32_t mirrored_pe, + uint32_t status, + struct list *allocatable_pvs, + alloc_policy_t alloc) { - struct lv_segment *seg; - struct segment_type *segtype; + struct alloc_handle *ah; - segtype = get_segtype_from_string(lv->vg->cmd, "snapshot"); - if (!segtype) { - log_error("Failed to find snapshot segtype"); + if (segtype_is_virtual(segtype)) { + log_error("allocate_extents does not handle virtual segments"); return NULL; } - if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, allocated, - lv->le_count - allocated, 0, 0, 0, - lv->le_count - allocated, 0, 0))) { - log_error("Couldn't allocate new snapshot segment."); + if (vg->fid->fmt->ops->segtype_supported && + !vg->fid->fmt->ops->segtype_supported(vg->fid, segtype)) { + log_error("Metadata format (%s) does not support required " + "LV segment type (%s).", vg->fid->fmt->name, + segtype->name); + log_error("Consider changing the metadata format by running " + "vgconvert."); return NULL; } - list_add(&lv->segments, &seg->list); - lv->status |= VIRTUAL; + if (alloc == ALLOC_INHERIT) + alloc = vg->alloc; - return seg; + if (!(ah = _alloc_init(vg->cmd->mem, segtype, alloc, mirrors, + stripes, log_count, mirrored_pv))) { + stack; + return NULL; + } + + if (!segtype_is_virtual(segtype) && + !_allocate(ah, vg, lv, status, (lv ? lv->le_count : 0) + extents, + allocatable_pvs, + stripes, mirrors, segtype, mirrored_pv, mirrored_pe)) { + stack; + alloc_destroy(ah); + return NULL; + } + + return ah; } /* - * Chooses a correct allocation policy. + * Add new segments to an LV from supplied list of areas. */ -static int _allocate(struct logical_volume *lv, - struct list *allocatable_pvs, uint32_t allocated, - alloc_policy_t alloc, struct segment_type *segtype, - uint32_t stripes, uint32_t stripe_size, uint32_t mirrors, - struct physical_volume *mirrored_pv, uint32_t mirrored_pe, - uint32_t status) +int lv_add_segment(struct alloc_handle *ah, + uint32_t first_area, uint32_t num_areas, + struct logical_volume *lv, + struct segment_type *segtype, + uint32_t stripe_size, + struct physical_volume *mirrored_pv, + uint32_t mirrored_pe, + uint32_t status, + uint32_t region_size, + struct logical_volume *log_lv) { - int r = 0; - struct pool *scratch; - struct list *pvms, *old_tail = lv->segments.p, *segh; - struct lv_segment *seg; + if (segtype_is_virtual(segtype)) { + log_error("lv_add_segment cannot handle virtual segments"); + return 0; + } - if (segtype->flags & SEG_VIRTUAL) - return _alloc_virtual(lv, allocated, segtype); - - if (!(scratch = pool_create("allocation", 1024))) { + if (!_setup_alloced_segments(lv, &ah->alloced_areas[first_area], + num_areas, status, + stripe_size, segtype, + mirrored_pv, mirrored_pe, + region_size, log_lv)) { stack; return 0; } - if (alloc == ALLOC_INHERIT) - alloc = lv->vg->alloc; + if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) { + log_err("Couldn't merge segments after extending " + "logical volume."); + return 0; + } - /* - * Build the sets of available areas on the pv's. - */ - if (!(pvms = create_pv_maps(scratch, lv->vg, allocatable_pvs))) + if (lv->vg->fid->fmt->ops->lv_setup && + !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) { + stack; + return 0; + } + + return 1; +} + +/* + * Turn an empty LV into a mirror log. + */ +int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv) +{ + struct lv_segment *seg; + + if (list_size(&log_lv->segments)) { + log_error("Log segments can only be added to an empty LV"); + return 0; + } + + if (!(seg = alloc_lv_segment(log_lv->vg->cmd->mem, + get_segtype_from_string(log_lv->vg->cmd, + "striped"), + log_lv, 0, ah->log_area.len, MIRROR_LOG, + 0, NULL, 1, ah->log_area.len, 0, 0, 0))) { + log_error("Couldn't allocate new mirror log segment."); + return 0; + } + + if (!set_lv_segment_area_pv(seg, 0, ah->log_area.pv, ah->log_area.pe)) { + stack; + return 0; + } + + list_add(&log_lv->segments, &seg->list); + log_lv->le_count += ah->log_area.len; + log_lv->size += (uint64_t) log_lv->le_count *log_lv->vg->extent_size; + + log_lv->vg->free_count--; + + if (log_lv->vg->fid->fmt->ops->lv_setup && + !log_lv->vg->fid->fmt->ops->lv_setup(log_lv->vg->fid, log_lv)) { + stack; + return 0; + } + + return 1; +} + +/* + * Entry point for single-step LV allocation + extension. + */ +int lv_extend(struct logical_volume *lv, + struct segment_type *segtype, + uint32_t stripes, uint32_t stripe_size, + uint32_t mirrors, uint32_t extents, + struct physical_volume *mirrored_pv, uint32_t mirrored_pe, + uint32_t status, struct list *allocatable_pvs, + alloc_policy_t alloc) +{ + int r = 1; + struct alloc_handle *ah; + + if (segtype_is_virtual(segtype)) + return lv_add_virtual_segment(lv, status, extents, segtype); + + if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0, + extents, mirrored_pv, mirrored_pe, status, + allocatable_pvs, alloc))) { + stack; + return 0; + } + + if (!lv_add_segment(ah, 0, ah->area_count, lv, segtype, stripe_size, + mirrored_pv, mirrored_pe, status, 0, NULL)) { + stack; goto out; - - if (stripes > 1 || mirrors > 1 || mirrored_pv) - r = _alloc_parallel(lv, alloc, pvms, allocated, stripes, - stripe_size, mirrors, segtype, - mirrored_pv, mirrored_pe); - else - r = _alloc_next_free(lv, alloc, pvms, allocated, segtype); - - if (r) { - lv->vg->free_count -= lv->le_count - allocated; - - /* - * Iterate through the new segments, updating pe - * counts in pv's. - */ - list_uniterate(segh, old_tail, &lv->segments) { - seg = list_item(segh, struct lv_segment); - _get_extents(seg); - seg->status = status; - } - } else { - /* - * Put the segment list back how we found it. - */ - old_tail->n = &lv->segments; - lv->segments.p = old_tail; } out: - pool_destroy(scratch); + alloc_destroy(ah); return r; } @@ -512,6 +956,9 @@ static char *_generate_lv_name(struct volume_group *vg, const char *format, return buffer; } +/* + * Create a new empty LV. + */ struct logical_volume *lv_create_empty(struct format_instance *fi, const char *name, const char *name_format, @@ -589,163 +1036,3 @@ struct logical_volume *lv_create_empty(struct format_instance *fi, return lv; } - -/* - * Entry point for all extent allocations - */ -int lv_extend(struct logical_volume *lv, - struct segment_type *segtype, - uint32_t stripes, uint32_t stripe_size, - uint32_t mirrors, uint32_t extents, - struct physical_volume *mirrored_pv, uint32_t mirrored_pe, - uint32_t status, struct list *allocatable_pvs, - alloc_policy_t alloc) -{ - uint32_t old_le_count = lv->le_count; - uint64_t old_size = lv->size; - - lv->le_count += extents; - lv->size += (uint64_t) extents *lv->vg->extent_size; - - if (lv->vg->fid->fmt->ops->segtype_supported && - !lv->vg->fid->fmt->ops->segtype_supported(lv->vg->fid, segtype)) { - log_error("Metadata format (%s) does not support required " - "LV segment type (%s).", lv->vg->fid->fmt->name, - segtype->name); - log_error("Consider changing the metadata format by running " - "vgconvert."); - return 0; - } - - if (!_allocate(lv, allocatable_pvs, old_le_count, alloc, - segtype, stripes, stripe_size, mirrors, mirrored_pv, - mirrored_pe, status)) { - lv->le_count = old_le_count; - lv->size = old_size; - stack; - return 0; - } - - if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) { - log_err("Couldn't merge segments after extending " - "logical volume."); - return 0; - } - - if (lv->vg->fid->fmt->ops->lv_setup && - !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) { - stack; - return 0; - } - - return 1; -} - -static int _lv_segment_reduce(struct lv_segment *seg, uint32_t reduction) -{ - _put_extents(seg); - seg->len -= reduction; - - /* Caller must ensure exact divisibility */ - if (seg_is_striped(seg)) { - if (reduction % seg->area_count) { - log_error("Segment extent reduction %" PRIu32 - "not divisible by #stripes %" PRIu32, - reduction, seg->area_count); - return 0; - } - seg->area_len -= (reduction / seg->area_count); - } else - seg->area_len -= reduction; - - _shrink_lv_segment(seg); - _get_extents(seg); - - return 1; -} - -/* - * Entry point for all extent reductions - */ -int lv_reduce(struct logical_volume *lv, uint32_t extents) -{ - struct list *segh; - struct lv_segment *seg; - uint32_t count = extents; - uint32_t reduction; - - list_uniterate(segh, &lv->segments, &lv->segments) { - seg = list_item(segh, struct lv_segment); - - if (!count) - break; - - if (seg->len <= count) { - /* remove this segment completely */ - list_del(segh); - reduction = seg->len; - } else - reduction = count; - - if (!_lv_segment_reduce(seg, reduction)) { - stack; - return 0; - } - count -= reduction; - } - - lv->le_count -= extents; - lv->size = (uint64_t) lv->le_count * lv->vg->extent_size; - lv->vg->free_count += extents; - - if (lv->le_count && lv->vg->fid->fmt->ops->lv_setup && - !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) { - stack; - return 0; - } - - return 1; -} - -int lv_remove(struct logical_volume *lv) -{ - struct lv_list *lvl; - - if (!lv_reduce(lv, lv->le_count)) { - stack; - return 0; - } - - /* find the lv list */ - if (!(lvl = find_lv_in_vg(lv->vg, lv->name))) { - stack; - return 0; - } - - list_del(&lvl->list); - - lv->vg->lv_count--; - - return 1; -} - -uint32_t find_free_lvnum(struct logical_volume *lv) -{ - int lvnum_used[MAX_RESTRICTED_LVS + 1]; - uint32_t i = 0; - struct lv_list *lvl; - int lvnum; - - memset(&lvnum_used, 0, sizeof(lvnum_used)); - - list_iterate_items(lvl, &lv->vg->lvs) { - lvnum = lvnum_from_lvid(&lvl->lv->lvid); - if (lvnum <= MAX_RESTRICTED_LVS) - lvnum_used[lvnum] = 1; - } - - while (lvnum_used[i]) - i++; - - return i; -} diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c index ba4032063..9ac10fba4 100644 --- a/lib/metadata/merge.c +++ b/lib/metadata/merge.c @@ -58,11 +58,13 @@ int lv_merge_segments(struct logical_volume *lv) /* * Verify that an LV's segments are consecutive, complete and don't overlap. */ -int lv_check_segments(struct logical_volume *lv) +int check_lv_segments(struct logical_volume *lv) { struct lv_segment *seg; uint32_t le = 0; unsigned seg_count = 0; + int r = 1; + uint32_t area_multiplier, s; list_iterate_items(seg, &lv->segments) { seg_count++; @@ -70,13 +72,58 @@ int lv_check_segments(struct logical_volume *lv) log_error("LV %s invalid: segment %u should begin at " "LE %" PRIu32 " (found %" PRIu32 ").", lv->name, seg_count, le, seg->le); - return 0; + r = 0; + } + + area_multiplier = segtype_is_striped(seg->segtype) ? + seg->area_count : 1; + + if (seg->area_len * area_multiplier != seg->len) { + log_error("LV %s: segment %u has inconsistent " + "area_len %u", + lv->name, seg_count, seg->area_len); + r = 0; + } + + for (s = 0; s < seg->area_count; s++) { + if (seg_type(seg, s) == AREA_PV) { + if (!seg_pvseg(seg, s) || + seg_pvseg(seg, s)->lvseg != seg || + seg_pvseg(seg, s)->lv_area != s) { + log_error("LV %s: segment %u has " + "inconsistent PV area %u", + lv->name, seg_count, s); + r = 0; + } + } else { + if (!seg_lv(seg, s) || + seg_lv(seg, s)->vg != lv->vg || + seg_lv(seg, s) == lv) { + log_error("LV %s: segment %u has " + "inconsistent LV area %u", + lv->name, seg_count, s); + r = 0; + } + if (seg_le(seg, s) != le) { + log_error("LV %s: segment %u has " + "inconsistent LV area %u " + "size", + lv->name, seg_count, s); + r = 0; + } + } } le += seg->len; } - return 1; + if (le != lv->le_count) { + log_error("LV %s: inconsistent LE count %u != %u", + lv->name, le, lv->le_count); + r = 0; + } + + return r; } /* @@ -101,8 +148,9 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg, if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->segtype, seg->lv, seg->le, seg->len, seg->status, seg->stripe_size, + seg->log_lv, seg->area_count, seg->area_len, - seg->chunk_size, + seg->chunk_size, seg->region_size, seg->extents_copied))) { log_error("Couldn't allocate cloned LV segment."); return 0; @@ -128,24 +176,24 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg, /* Adjust the PV mapping */ for (s = 0; s < seg->area_count; s++) { - split_seg->area[s].type = seg->area[s].type; + seg_type(split_seg, s) = seg_type(seg, s); /* Split area at the offset */ - switch (seg->area[s].type) { + switch (seg_type(seg, s)) { case AREA_LV: - split_seg->area[s].u.lv.lv = seg->area[s].u.lv.lv; - split_seg->area[s].u.lv.le = - seg->area[s].u.lv.le + seg->area_len; + seg_lv(split_seg, s) = seg_lv(seg, s); + seg_le(split_seg, s) = + seg_le(seg, s) + seg->area_len; log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name, - seg->le, s, le, seg->area[s].u.lv.lv->name, - split_seg->area[s].u.lv.le); + seg->le, s, le, seg_lv(seg, s)->name, + seg_le(split_seg, s)); break; case AREA_PV: - if (!assign_peg_to_lvseg(seg->area[s].u.pv.pvseg->pv, - seg->area[s].u.pv.pvseg->pe + + if (!assign_peg_to_lvseg(seg_pv(seg, s), + seg_pe(seg, s) + seg->area_len, - seg->area[s].u.pv.pvseg->len - + seg_pvseg(seg, s)->len - seg->area_len, split_seg, s)) { stack; @@ -153,13 +201,13 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg, } log_debug("Split %s:%u[%u] at %u: %s PE %u", lv->name, seg->le, s, le, - dev_name(seg->area[s].u.pv.pvseg->pv->dev), - split_seg->area[s].u.pv.pvseg->pe); + dev_name(seg_dev(seg, s)), + seg_pe(split_seg, s)); break; default: log_error("Unrecognised segment type %u", - seg->area[s].type); + seg_type(seg, s)); return 0; } } diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 60fc1ec69..5f999702a 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -139,7 +139,6 @@ int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name, const char *id, struct physical_volume *pv) { struct volume_group *vg; - struct list *pvh; struct pv_list *pvl; int consistent = 0; @@ -153,8 +152,7 @@ int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name, log_error("Warning: Volume group %s is not consistent", vg_name); - list_iterate(pvh, &vg->pvs) { - pvl = list_item(pvh, struct pv_list); + list_iterate_items(pvl, &vg->pvs) { if (id_equal(&pvl->pv->id, (const struct id *) id)) { if (!_copy_pv(pv, pvl->pv)) { stack; @@ -171,19 +169,17 @@ int vg_rename(struct cmd_context *cmd, struct volume_group *vg, const char *new_name) { struct pool *mem = cmd->mem; - struct physical_volume *pv; - struct list *pvh; + struct pv_list *pvl; if (!(vg->name = pool_strdup(mem, new_name))) { log_error("vg->name allocation failed for '%s'", new_name); return 0; } - list_iterate(pvh, &vg->pvs) { - pv = list_item(pvh, struct pv_list)->pv; - if (!(pv->vg_name = pool_strdup(mem, new_name))) { + list_iterate_items(pvl, &vg->pvs) { + if (!(pvl->pv->vg_name = pool_strdup(mem, new_name))) { log_error("pv->vg_name allocation failed for '%s'", - dev_name(pv->dev)); + dev_name(pvl->pv->dev)); return 0; } } @@ -441,10 +437,10 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg, /* foreach area */ for (s = 0; s < seg->area_count; s++) { - switch (seg->area[s].type) { + switch (seg_type(seg, s)) { case AREA_PV: if (!_recalc_extents - (&seg->area[s].u.pv.pvseg->pe, + (&seg_pe(seg, s), lv->name, " pvseg start", old_size, new_size)) { @@ -452,7 +448,7 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg, return 0; } if (!_recalc_extents - (&seg->area[s].u.pv.pvseg->len, + (&seg_pvseg(seg, s)->len, lv->name, " pvseg length", old_size, new_size)) { @@ -462,7 +458,7 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg, break; case AREA_LV: if (!_recalc_extents - (&seg->area[s].u.lv.le, lv->name, + (&seg_le(seg, s), lv->name, " area start", old_size, new_size)) { stack; @@ -471,7 +467,7 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg, break; default: log_error("Unrecognised segment type " - "%u", seg->area[s].type); + "%u", seg_type(seg, s)); return 0; } } @@ -563,26 +559,22 @@ struct physical_volume *pv_create(const struct format_type *fmt, struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name) { - struct list *pvh; struct pv_list *pvl; - list_iterate(pvh, &vg->pvs) { - pvl = list_item(pvh, struct pv_list); + list_iterate_items(pvl, &vg->pvs) if (pvl->pv->dev == dev_cache_get(pv_name, vg->cmd->filter)) return pvl; - } return NULL; } int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv) { - struct list *pvh; + struct pv_list *pvl; - list_iterate(pvh, &vg->pvs) { - if (pv == list_item(pvh, struct pv_list)->pv) + list_iterate_items(pvl, &vg->pvs) + if (pv == pvl->pv) return 1; - } return 0; } @@ -590,21 +582,17 @@ int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv) struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg, struct id *id) { - struct list *pvh; struct pv_list *pvl; - list_iterate(pvh, &vg->pvs) { - pvl = list_item(pvh, struct pv_list); + list_iterate_items(pvl, &vg->pvs) if (id_equal(&pvl->pv->id, id)) return pvl->pv; - } return NULL; } struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name) { - struct list *lvh; struct lv_list *lvl; const char *ptr; @@ -614,11 +602,9 @@ struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name) else ptr = lv_name; - list_iterate(lvh, &vg->lvs) { - lvl = list_item(lvh, struct lv_list); + list_iterate_items(lvl, &vg->lvs) if (!strcmp(lvl->lv->name, ptr)) return lvl; - } return NULL; } @@ -643,15 +629,12 @@ struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name) struct physical_volume *find_pv(struct volume_group *vg, struct device *dev) { - struct list *pvh; - struct physical_volume *pv; + struct pv_list *pvl; - list_iterate(pvh, &vg->pvs) { - pv = list_item(pvh, struct pv_list)->pv; + list_iterate_items(pvl, &vg->pvs) + if (dev == pvl->pv->dev) + return pvl->pv; - if (dev == pv->dev) - return pv; - } return NULL; } @@ -676,14 +659,11 @@ struct physical_volume *find_pv_by_name(struct cmd_context *cmd, /* 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); + list_iterate_items(seg, &lv->segments) if (le >= seg->le && le < seg->le + seg->len) return seg; - } return NULL; } @@ -693,23 +673,20 @@ struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe) { struct pv_segment *peg; - list_iterate_items(peg, &pv->segments) { + list_iterate_items(peg, &pv->segments) if (pe >= peg->pe && pe < peg->pe + peg->len) return peg; - } return NULL; } int vg_remove(struct volume_group *vg) { - struct list *mdah; struct metadata_area *mda; /* FIXME Improve recovery situation? */ /* Remove each copy of the metadata */ - list_iterate(mdah, &vg->fid->metadata_areas) { - mda = list_item(mdah, struct metadata_area); + list_iterate_items(mda, &vg->fid->metadata_areas) { if (mda->ops->vg_remove && !mda->ops->vg_remove(vg->fid, vg, mda)) { stack; @@ -726,8 +703,9 @@ int vg_remove(struct volume_group *vg) */ int vg_write(struct volume_group *vg) { - struct list *mdah, *mdah2; + struct list *mdah; struct metadata_area *mda; + struct lv_list *lvl; if (!check_pv_segments(vg)) { log_error("Internal error: PV segments corrupted in %s.", @@ -735,6 +713,14 @@ int vg_write(struct volume_group *vg) return 0; } + list_iterate_items(lvl, &vg->lvs) { + if (!check_lv_segments(lvl->lv)) { + log_error("Internal error: LV segments corrupted in %s.", + lvl->lv->name); + return 0; + } + } + if (vg->status & PARTIAL_VG) { log_error("Cannot change metadata for partial volume group %s", vg->name); @@ -749,14 +735,13 @@ int vg_write(struct volume_group *vg) vg->seqno++; /* Write to each copy of the metadata area */ - list_iterate(mdah, &vg->fid->metadata_areas) { - mda = list_item(mdah, struct metadata_area); + list_iterate_items(mda, &vg->fid->metadata_areas) { if (!mda->ops->vg_write) { log_error("Format does not support writing volume" "group metadata areas"); /* Revert */ - list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) { - mda = list_item(mdah2, struct metadata_area); + list_uniterate(mdah, &vg->fid->metadata_areas, &mda->list) { + mda = list_item(mdah, struct metadata_area); if (mda->ops->vg_revert && !mda->ops->vg_revert(vg->fid, vg, mda)) { @@ -768,8 +753,9 @@ int vg_write(struct volume_group *vg) if (!mda->ops->vg_write(vg->fid, vg, mda)) { stack; /* Revert */ - list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) { - mda = list_item(mdah2, struct metadata_area); + list_uniterate(mdah, &vg->fid->metadata_areas, &mda->list) { + mda = list_item(mdah, struct metadata_area); + if (mda->ops->vg_revert && !mda->ops->vg_revert(vg->fid, vg, mda)) { stack; @@ -780,14 +766,12 @@ int vg_write(struct volume_group *vg) } /* Now pre-commit each copy of the new metadata */ - list_iterate(mdah, &vg->fid->metadata_areas) { - mda = list_item(mdah, struct metadata_area); + list_iterate_items(mda, &vg->fid->metadata_areas) { if (mda->ops->vg_precommit && !mda->ops->vg_precommit(vg->fid, vg, mda)) { stack; /* Revert */ - list_iterate(mdah2, &vg->fid->metadata_areas) { - mda = list_item(mdah2, struct metadata_area); + list_iterate_items(mda, &vg->fid->metadata_areas) { if (mda->ops->vg_revert && !mda->ops->vg_revert(vg->fid, vg, mda)) { stack; @@ -803,14 +787,12 @@ int vg_write(struct volume_group *vg) /* Commit pending changes */ int vg_commit(struct volume_group *vg) { - struct list *mdah; struct metadata_area *mda; int cache_updated = 0; int failed = 0; /* Commit to each copy of the metadata area */ - list_iterate(mdah, &vg->fid->metadata_areas) { - mda = list_item(mdah, struct metadata_area); + list_iterate_items(mda, &vg->fid->metadata_areas) { failed = 0; if (mda->ops->vg_commit && !mda->ops->vg_commit(vg->fid, vg, mda)) { @@ -822,7 +804,6 @@ int vg_commit(struct volume_group *vg) lvmcache_update_vg(vg); cache_updated = 1; } - } /* If at least one mda commit succeeded, it was committed */ @@ -832,11 +813,9 @@ int vg_commit(struct volume_group *vg) /* Don't commit any pending changes */ int vg_revert(struct volume_group *vg) { - struct list *mdah; struct metadata_area *mda; - list_iterate(mdah, &vg->fid->metadata_areas) { - mda = list_item(mdah, struct metadata_area); + list_iterate_items(mda, &vg->fid->metadata_areas) { if (mda->ops->vg_revert && !mda->ops->vg_revert(vg->fid, vg, mda)) { stack; @@ -850,8 +829,7 @@ int vg_revert(struct volume_group *vg) static struct volume_group *_vg_read_orphans(struct cmd_context *cmd) { struct lvmcache_vginfo *vginfo; - struct list *ih; - struct device *dev; + struct lvmcache_info *info; struct pv_list *pvl; struct volume_group *vg; struct physical_volume *pv; @@ -874,9 +852,8 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd) return NULL; } - list_iterate(ih, &vginfo->infos) { - dev = list_item(ih, struct lvmcache_info)->dev; - if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL, 1))) { + list_iterate_items(info, &vginfo->infos) { + if (!(pv = pv_read(cmd, dev_name(info->dev), NULL, NULL, 1))) { continue; } if (!(pvl = pool_zalloc(cmd->mem, sizeof(*pvl)))) { @@ -905,7 +882,6 @@ static struct volume_group *_vg_read(struct cmd_context *cmd, struct format_instance *fid; const struct format_type *fmt; struct volume_group *vg, *correct_vg = NULL; - struct list *mdah; struct metadata_area *mda; int inconsistent = 0; @@ -949,8 +925,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd, } /* Ensure contents of all metadata areas match - else do recovery */ - list_iterate(mdah, &fid->metadata_areas) { - mda = list_item(mdah, struct metadata_area); + list_iterate_items(mda, &fid->metadata_areas) { if ((precommitted && !(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) || (!precommitted && @@ -993,8 +968,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd, } /* Ensure contents of all metadata areas match - else recover */ - list_iterate(mdah, &fid->metadata_areas) { - mda = list_item(mdah, struct metadata_area); + list_iterate_items(mda, &fid->metadata_areas) { if ((precommitted && !(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) || @@ -1088,9 +1062,10 @@ struct volume_group *vg_read_precommitted(struct cmd_context *cmd, struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid) { const char *vgname; - struct list *vgnames, *slh; + struct list *vgnames; struct volume_group *vg; struct lvmcache_vginfo *vginfo; + struct str_list *strl; int consistent = 0; /* Is corresponding vgname already cached? */ @@ -1121,8 +1096,8 @@ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid) return NULL; } - list_iterate(slh, vgnames) { - vgname = list_item(slh, struct str_list)->str; + list_iterate_items(strl, vgnames) { + vgname = strl->str; if (!vgname || !*vgname) continue; // FIXME Unnecessary? consistent = 0; @@ -1228,10 +1203,11 @@ struct list *get_vgs(struct cmd_context *cmd, int full_scan) struct list *get_pvs(struct cmd_context *cmd) { + struct str_list *strl; struct list *results; const char *vgname; struct list *pvh, *tmp; - struct list *vgnames, *slh; + struct list *vgnames; struct volume_group *vg; int consistent = 0; int old_partial; @@ -1258,8 +1234,8 @@ struct list *get_pvs(struct cmd_context *cmd) old_pvmove = pvmove_mode(); init_partial(1); init_pvmove(1); - list_iterate(slh, vgnames) { - vgname = list_item(slh, struct str_list)->str; + list_iterate_items(strl, vgnames) { + vgname = strl->str; if (!vgname) continue; /* FIXME Unnecessary? */ consistent = 0; diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index a6f90248d..a5914dcf7 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -55,6 +55,7 @@ #define LOCKED 0x00004000 /* LV */ #define MIRRORED 0x00008000 /* LV - internal use only */ #define VIRTUAL 0x00010000 /* LV - internal use only */ +#define MIRROR_LOG 0x00020000 /* LV */ #define LVM_READ 0x00000100 /* LV VG */ #define LVM_WRITE 0x00000200 /* LV VG */ @@ -228,8 +229,10 @@ struct lv_segment { struct logical_volume *origin; struct logical_volume *cow; struct list origin_list; - uint32_t chunk_size; /* In sectors */ + uint32_t chunk_size; /* For snapshots - in sectors */ + uint32_t region_size; /* For mirrors - in sectors */ uint32_t extents_copied; + struct logical_volume *log_lv; struct list tags; @@ -248,6 +251,14 @@ struct lv_segment { } area[0]; }; +#define seg_type(seg, s) (seg)->area[(s)].type +#define seg_pvseg(seg, s) (seg)->area[(s)].u.pv.pvseg +#define seg_pv(seg, s) (seg)->area[(s)].u.pv.pvseg->pv +#define seg_dev(seg, s) (seg)->area[(s)].u.pv.pvseg->pv->dev +#define seg_pe(seg, s) (seg)->area[(s)].u.pv.pvseg->pe +#define seg_lv(seg, s) (seg)->area[(s)].u.lv.lv +#define seg_le(seg, s) (seg)->area[(s)].u.lv.le + struct logical_volume { union lvid lvid; char *name; @@ -492,7 +503,7 @@ const char *strip_dir(const char *vg_name, const char *dir); /* * Checks that an lv has no gaps or overlapping segments. */ -int lv_check_segments(struct logical_volume *lv); +int check_lv_segments(struct logical_volume *lv); /* * Sometimes (eg, after an lvextend), it is possible to merge two diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c index 76a0e0725..7bdaf2c4c 100644 --- a/lib/metadata/mirror.c +++ b/lib/metadata/mirror.c @@ -33,7 +33,6 @@ int insert_pvmove_mirrors(struct cmd_context *cmd, alloc_policy_t alloc, struct list *lvs_changed) { - struct list *segh; struct lv_segment *seg; struct lv_list *lvl; struct pv_list *pvl; @@ -59,16 +58,15 @@ int insert_pvmove_mirrors(struct cmd_context *cmd, } /* Split LV segments to match PE ranges */ - list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct lv_segment); + list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { - if (seg->area[s].type != AREA_PV || - seg->area[s].u.pv.pvseg->pv->dev != pvl->pv->dev) + if (seg_type(seg, s) != AREA_PV || + seg_dev(seg, s) != pvl->pv->dev) continue; /* Do these PEs need moving? */ list_iterate_items(per, pvl->pe_ranges) { - pe_start = seg->area[s].u.pv.pvseg->pe; + pe_start = seg_pe(seg, s); pe_end = pe_start + seg->area_len - 1; per_end = per->start + per->count - 1; @@ -104,14 +102,13 @@ int insert_pvmove_mirrors(struct cmd_context *cmd, } /* Work through all segments on the supplied PV */ - list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct lv_segment); + list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { - if (seg->area[s].type != AREA_PV || - seg->area[s].u.pv.pvseg->pv->dev != pvl->pv->dev) + if (seg_type(seg, s) != AREA_PV || + seg_dev(seg, s) != pvl->pv->dev) continue; - pe_start = seg->area[s].u.pv.pvseg->pe; + pe_start = seg_pe(seg, s); /* Do these PEs need moving? */ list_iterate_items(per, pvl->pe_ranges) { @@ -123,9 +120,8 @@ int insert_pvmove_mirrors(struct cmd_context *cmd, log_debug("Matched PE range %u-%u against " "%s %u len %u", per->start, per_end, - dev_name(seg->area[s].u.pv.pvseg-> - pv->dev), - seg->area[s].u.pv.pvseg->pe, + dev_name(seg_dev(seg, s)), + seg_pe(seg, s), seg->area_len); /* First time, add LV to list of LVs affected */ @@ -141,16 +137,16 @@ int insert_pvmove_mirrors(struct cmd_context *cmd, log_very_verbose("Moving %s:%u-%u of %s/%s", dev_name(pvl->pv->dev), - seg->area[s].u.pv.pvseg->pe, - seg->area[s].u.pv.pvseg->pe + + seg_pe(seg, s), + seg_pe(seg, s) + seg->area_len - 1, lv->vg->name, lv->name); start_le = lv_mirr->le_count; if (!lv_extend(lv_mirr, segtype, 1, seg->area_len, 0u, seg->area_len, - seg->area[s].u.pv.pvseg->pv, - seg->area[s].u.pv.pvseg->pe, + seg_pv(seg, s), + seg_pe(seg, s), PVMOVE, allocatable_pvs, alloc)) { log_error("Unable to allocate " @@ -178,29 +174,27 @@ int insert_pvmove_mirrors(struct cmd_context *cmd, int remove_pvmove_mirrors(struct volume_group *vg, struct logical_volume *lv_mirr) { - struct list *lvh, *segh; + struct lv_list *lvl; struct logical_volume *lv1; struct lv_segment *seg, *mir_seg; uint32_t s, c; /* Loop through all LVs except the temporary mirror */ - list_iterate(lvh, &vg->lvs) { - lv1 = list_item(lvh, struct lv_list)->lv; + list_iterate_items(lvl, &vg->lvs) { + lv1 = lvl->lv; if (lv1 == lv_mirr) continue; /* Find all segments that point at the temporary mirror */ - list_iterate(segh, &lv1->segments) { - seg = list_item(segh, struct lv_segment); + list_iterate_items(seg, &lv1->segments) { for (s = 0; s < seg->area_count; s++) { - if (seg->area[s].type != AREA_LV || - seg->area[s].u.lv.lv != lv_mirr) + if (seg_type(seg, s) != AREA_LV || + seg_lv(seg, s) != lv_mirr) continue; /* Find the mirror segment pointed at */ if (!(mir_seg = find_seg_by_le(lv_mirr, - seg->area[s]. - u.lv.le))) { + seg_le(seg, s)))) { /* FIXME Error message */ log_error("No segment found with LE"); return 0; @@ -210,7 +204,7 @@ int remove_pvmove_mirrors(struct volume_group *vg, /* FIXME Improve error mesg & remove restrcn */ if (!seg_is_mirrored(mir_seg) || !(mir_seg->status & PVMOVE) || - mir_seg->le != seg->area[s].u.lv.le || + mir_seg->le != seg_le(seg, s) || mir_seg->area_count != 2 || mir_seg->area_len != seg->area_len) { log_error("Incompatible segments"); @@ -227,8 +221,8 @@ int remove_pvmove_mirrors(struct volume_group *vg, c = 0; if (!set_lv_segment_area_pv(seg, s, - mir_seg->area[c].u.pv.pvseg->pv, - mir_seg->area[c].u.pv.pvseg->pe)) { + seg_pv(mir_seg, c), + seg_pe(mir_seg, c))) { stack; return 0; } @@ -258,16 +252,14 @@ int remove_pvmove_mirrors(struct volume_group *vg, const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr) { - struct list *segh; struct lv_segment *seg; - list_iterate(segh, &lv_mirr->segments) { - seg = list_item(segh, struct lv_segment); + list_iterate_items(seg, &lv_mirr->segments) { if (!seg_is_mirrored(seg)) continue; if (seg->area[0].type != AREA_PV) continue; - return dev_name(seg->area[0].u.pv.pvseg->pv->dev); + return dev_name(seg_dev(seg, 0)); } return NULL; @@ -275,16 +267,14 @@ const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr) const char *get_pvmove_pvname_from_lv(struct logical_volume *lv) { - struct list *segh; struct lv_segment *seg; uint32_t s; - list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct lv_segment); + list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { - if (seg->area[s].type != AREA_LV) + if (seg_type(seg, s) != AREA_LV) continue; - return get_pvmove_pvname_from_lv_mirr(seg->area[s].u.lv.lv); + return get_pvmove_pvname_from_lv_mirr(seg_lv(seg, s)); } } @@ -295,23 +285,22 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg, struct device *dev, uint32_t lv_type) { - struct list *lvh, *segh; + struct lv_list *lvl; struct logical_volume *lv; struct lv_segment *seg; /* Loop through all LVs */ - list_iterate(lvh, &vg->lvs) { - lv = list_item(lvh, struct lv_list)->lv; + list_iterate_items(lvl, &vg->lvs) { + lv = lvl->lv; if (!(lv->status & lv_type)) continue; /* Check segment origins point to pvname */ - list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct lv_segment); + list_iterate_items(seg, &lv->segments) { if (seg->area[0].type != AREA_PV) continue; - if (seg->area[0].u.pv.pvseg->pv->dev != dev) + if (seg_dev(seg, 0) != dev) continue; return lv; } @@ -338,9 +327,9 @@ struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd, struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv) { - struct list *lvh, *segh, *lvs; + struct list *lvs; struct logical_volume *lv1; - struct lv_list *lvl; + struct lv_list *lvl, *lvl1; struct lv_segment *seg; uint32_t s; @@ -352,17 +341,16 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg, list_init(lvs); /* Loop through all LVs except the one supplied */ - list_iterate(lvh, &vg->lvs) { - lv1 = list_item(lvh, struct lv_list)->lv; + list_iterate_items(lvl1, &vg->lvs) { + lv1 = lvl1->lv; if (lv1 == lv) continue; /* Find whether any segment points at the supplied LV */ - list_iterate(segh, &lv1->segments) { - seg = list_item(segh, struct lv_segment); + list_iterate_items(seg, &lv1->segments) { for (s = 0; s < seg->area_count; s++) { - if (seg->area[s].type != AREA_LV || - seg->area[s].u.lv.lv != lv) + if (seg_type(seg, s) != AREA_LV || + seg_lv(seg, s) != lv) continue; if (!(lvl = pool_alloc(cmd->mem, sizeof(*lvl)))) { log_error("lv_list alloc failed"); @@ -383,12 +371,9 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg, float copy_percent(struct logical_volume *lv_mirr) { uint32_t numerator = 0u, denominator = 0u; - struct list *segh; struct lv_segment *seg; - list_iterate(segh, &lv_mirr->segments) { - seg = list_item(segh, struct lv_segment); - + list_iterate_items(seg, &lv_mirr->segments) { denominator += seg->area_len; if (seg_is_mirrored(seg)) diff --git a/lib/metadata/pv_alloc.h b/lib/metadata/pv_alloc.h index ff2b76a4c..8b4134b16 100644 --- a/lib/metadata/pv_alloc.h +++ b/lib/metadata/pv_alloc.h @@ -22,7 +22,7 @@ struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv, uint32_t pe, struct lv_segment *seg, uint32_t area_num); int pv_split_segment(struct physical_volume *pv, uint32_t pe); -int release_pv_segment(struct pv_segment *peg, uint32_t new_area_len); +int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction); int check_pv_segments(struct volume_group *vg); void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2); diff --git a/lib/metadata/pv_manip.c b/lib/metadata/pv_manip.c index 64499aa71..2e9a2d6b5 100644 --- a/lib/metadata/pv_manip.c +++ b/lib/metadata/pv_manip.c @@ -165,9 +165,11 @@ struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv, return peg; } -int release_pv_segment(struct pv_segment *peg, uint32_t new_area_len) +int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction) { - if (new_area_len == 0) { + peg->pv->pe_alloc_count -= area_reduction; + + if (!peg->lvseg->area_len) { peg->lvseg = NULL; peg->lv_area = 0; @@ -176,7 +178,7 @@ int release_pv_segment(struct pv_segment *peg, uint32_t new_area_len) return 1; } - if (!pv_split_segment(peg->pv, peg->pe + new_area_len)) { + if (!pv_split_segment(peg->pv, peg->pe + peg->lvseg->area_len)) { stack; return 0; } @@ -203,13 +205,16 @@ int check_pv_segments(struct volume_group *vg) struct pv_list *pvl; struct pv_segment *peg; unsigned s, segno; - uint32_t start_pe; + uint32_t start_pe, alloced; + uint32_t pv_count = 0, free_count = 0, extent_count = 0; int ret = 1; list_iterate_items(pvl, &vg->pvs) { pv = pvl->pv; segno = 0; start_pe = 0; + alloced = 0; + pv_count++; list_iterate_items(peg, &pv->segments) { s = peg->lv_area; @@ -221,30 +226,63 @@ int check_pv_segments(struct volume_group *vg) peg->lvseg ? peg->lvseg->le : 0, s); /* FIXME Add details here on failure instead */ if (start_pe != peg->pe) { - log_debug("Gap in pvsegs: %u, %u", + log_error("Gap in pvsegs: %u, %u", start_pe, peg->pe); ret = 0; } if (peg->lvseg) { - if (peg->lvseg->area[s].type != AREA_PV) { - log_debug("Wrong lvseg area type"); + if (seg_type(peg->lvseg, s) != AREA_PV) { + log_error("Wrong lvseg area type"); ret = 0; } - if (peg->lvseg->area[s].u.pv.pvseg != peg) { - log_debug("Inconsistent pvseg pointers"); + if (seg_pvseg(peg->lvseg, s) != peg) { + log_error("Inconsistent pvseg pointers"); ret = 0; } if (peg->lvseg->area_len != peg->len) { - log_debug("Inconsistent length: %u %u", + log_error("Inconsistent length: %u %u", peg->len, peg->lvseg->area_len); ret = 0; } + alloced += peg->len; } start_pe += peg->len; } + + if (start_pe != pv->pe_count) { + log_error("PV segment pe_count mismatch: %u != %u", + start_pe, pv->pe_count); + ret = 0; + } + + if (alloced != pv->pe_alloc_count) { + log_error("PV segment pe_alloc_count mismatch: " + "%u != %u", alloced, pv->pe_alloc_count); + ret = 0; + } + + extent_count += start_pe; + free_count += (start_pe - alloced); + } + + if (pv_count != vg->pv_count) { + log_error("PV segment VG pv_count mismatch: %u != %u", + pv_count, vg->pv_count); + ret = 0; + } + + if (free_count != vg->free_count) { + log_error("PV segment VG free_count mismatch: %u != %u", + free_count, vg->free_count); + ret = 0; + } + + if (extent_count != vg->extent_count) { + log_error("PV segment VG extent_count mismatch: %u != %u", + extent_count, vg->extent_count); + ret = 0; } return ret; } - diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h index 67388b833..83cbb8600 100644 --- a/lib/metadata/segtype.h +++ b/lib/metadata/segtype.h @@ -39,6 +39,10 @@ struct dev_manager; #define seg_is_virtual(seg) ((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0) #define seg_can_split(seg) ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0) +#define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0) +#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0) +#define segtype_is_virtual(segtype) ((segtype)->flags & SEG_VIRTUAL ? 1 : 0) + struct segment_type { struct list list; struct cmd_context *cmd; diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c index d0133b548..266b3d401 100644 --- a/lib/metadata/snapshot_manip.c +++ b/lib/metadata/snapshot_manip.c @@ -59,7 +59,7 @@ int vg_add_snapshot(struct format_instance *fid, const char *name, snap->le_count = extent_count; - if (!(seg = alloc_snapshot_seg(snap, 0))) { + if (!(seg = alloc_snapshot_seg(snap, 0, 0))) { stack; return 0; } diff --git a/lib/mirror/mirrored.c b/lib/mirror/mirrored.c index cf76d6db7..3fe7992d1 100644 --- a/lib/mirror/mirrored.c +++ b/lib/mirror/mirrored.c @@ -35,7 +35,7 @@ enum { }; struct mirror_state { - uint32_t region_size; + uint32_t default_region_size; }; static const char *_name(const struct lv_segment *seg) @@ -45,14 +45,25 @@ static const char *_name(const struct lv_segment *seg) static void _display(const struct lv_segment *seg) { + const char *size; + log_print(" Mirrors\t\t%u", seg->area_count); log_print(" Mirror size\t\t%u", seg->area_len); + if (seg->log_lv) + log_print(" Mirror log volume\t%s", seg->log_lv->name); + + if (seg->region_size) { + size = display_size(seg->lv->vg->cmd, + (uint64_t) seg->region_size, + SIZE_SHORT); + log_print(" Mirror region size\t%s", size); + } + log_print(" Mirror original:"); display_stripe(seg, 0, " "); log_print(" Mirror destination:"); display_stripe(seg, 1, " "); log_print(" "); - } static int _text_import_area_count(struct config_node *sn, uint32_t *area_count) @@ -70,6 +81,7 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn, struct hash_table *pv_hash) { const struct config_node *cn; + char *logname = NULL; if (find_config_node(sn, "extents_moved")) { if (get_config_uint32(sn, "extents_moved", @@ -82,6 +94,35 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn, } } + if (find_config_node(sn, "region_size")) { + if (!get_config_uint32(sn, "region_size", + &seg->region_size)) { + log_error("Couldn't read 'region_size' for " + "segment '%s'.", sn->key); + return 0; + } + } + + if ((cn = find_config_node(sn, "mirror_log"))) { + if (!cn->v || !cn->v->v.str) { + log_error("Mirror log type must be a string."); + return 0; + } + logname = cn->v->v.str; + if (!(seg->log_lv = find_lv(seg->lv->vg, logname))) { + log_error("Unrecognised mirror log in segment %s.", + sn->key); + return 0; + } + seg->log_lv->status |= MIRROR_LOG; + } + + if (logname && !seg->region_size) { + log_error("Missing region size for mirror log for segment " + "'%s'.", sn->key); + return 0; + } + if (!(cn = find_config_node(sn, "mirrors"))) { log_error("Couldn't find mirrors array for segment " "'%s'.", sn->key); @@ -96,7 +137,11 @@ static int _text_export(const struct lv_segment *seg, struct formatter *f) outf(f, "mirror_count = %u", seg->area_count); if (seg->status & PVMOVE) out_size(f, (uint64_t) seg->extents_copied * seg->lv->vg->extent_size, - "extents_moved = %u", seg->extents_copied); + "extents_moved = %" PRIu32, seg->extents_copied); + if (seg->log_lv) + outf(f, "mirror_log = \"%s\"", seg->log_lv->name); + if (seg->region_size) + outf(f, "region_size = %" PRIu32, seg->region_size); return out_areas(f, seg, "mirror"); } @@ -112,7 +157,7 @@ static struct mirror_state *_init_target(struct pool *mem, return NULL; } - mirr_state->region_size = 2 * + mirr_state->default_region_size = 2 * find_config_int(cft->root, "activation/mirror_region_size", DEFAULT_MIRROR_REGION_SIZE); @@ -156,15 +201,23 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem, } else { *target = "mirror"; - /* Find largest power of 2 region size unit we can use */ - region_max = (1 << (ffs(seg->area_len) - 1)) * + if (!(seg->status & PVMOVE)) { + if (!seg->region_size) { + log_error("Missing region size for mirror segment."); + return 0; + } + region_size = seg->region_size; + } else { + /* Find largest power of 2 region size unit we can use */ + region_max = (1 << (ffs(seg->area_len) - 1)) * seg->lv->vg->extent_size; - region_size = mirr_state->region_size; - if (region_max < region_size) { - region_size = region_max; - log_verbose("Using reduced mirror region size of %u sectors", - region_size); + region_size = mirr_state->default_region_size; + if (region_max < region_size) { + region_size = region_max; + log_verbose("Using reduced mirror region size of %u sectors", + region_size); + } } if ((ret = compose_log_line(dm, seg, params, paramsize, pos, diff --git a/lib/mm/dbg_malloc.c b/lib/mm/dbg_malloc.c index 79bb49ced..b2fc38aff 100644 --- a/lib/mm/dbg_malloc.c +++ b/lib/mm/dbg_malloc.c @@ -112,6 +112,9 @@ void *malloc_aux(size_t s, const char *file, int line) if (_mem_stats.bytes > _mem_stats.mbytes) _mem_stats.mbytes = _mem_stats.bytes; + /* log_debug("Allocated: %u %u %u", nb->id, _mem_stats.blocks_allocated, + _mem_stats.bytes); */ + return nb + 1; } diff --git a/lib/report/columns.h b/lib/report/columns.h index bf55c5d69..ef86d34bd 100644 --- a/lib/report/columns.h +++ b/lib/report/columns.h @@ -32,6 +32,7 @@ FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent") FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent") FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv") FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags") +FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log") FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt") FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid") @@ -67,6 +68,7 @@ FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype") FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes") FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize") FIELD(SEGS, seg, NUM, "Chunk", chunk_size, 5, size32, "chunksize") +FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize") FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start") FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size") FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags") diff --git a/lib/report/report.c b/lib/report/report.c index 3eb854005..c947d7229 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -154,14 +154,14 @@ static int _devices_disp(struct report_handle *rh, struct field *field, } for (s = 0; s < seg->area_count; s++) { - switch (seg->area[s].type) { + switch (seg_type(seg, s)) { case AREA_LV: - name = seg->area[s].u.lv.lv->name; - extent = seg->area[s].u.lv.le; + name = seg_lv(seg, s)->name; + extent = seg_le(seg, s); break; case AREA_PV: - name = dev_name(seg->area[s].u.pv.pvseg->pv->dev); - extent = seg->area[s].u.pv.pvseg->pe; + name = dev_name(seg_dev(seg, s)); + extent = seg_pe(seg, s); break; default: name = "unknown"; @@ -337,6 +337,8 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field, repstr[0] = 'p'; else if (lv->status & MIRRORED) repstr[0] = 'm'; + else if (lv->status & MIRROR_LOG) + repstr[0] = 'l'; else if (lv->status & VIRTUAL) repstr[0] = 'v'; else if (lv_is_origin(lv)) @@ -490,19 +492,35 @@ static int _origin_disp(struct report_handle *rh, struct field *field, return 1; } +static int _loglv_disp(struct report_handle *rh, struct field *field, + const void *data) +{ + const struct logical_volume *lv = (const struct logical_volume *) data; + struct lv_segment *seg; + + list_iterate_items(seg, &lv->segments) { + if (!seg_is_mirrored(seg) || !seg->log_lv) + continue; + return _string_disp(rh, field, &seg->log_lv->name); + } + + field->report_string = ""; + field->sort_value = (const void *) field->report_string; + + return 1; +} + static int _movepv_disp(struct report_handle *rh, struct field *field, const void *data) { const struct logical_volume *lv = (const struct logical_volume *) data; const char *name; - struct list *segh; struct lv_segment *seg; - list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct lv_segment); + list_iterate_items(seg, &lv->segments) { if (!(seg->status & PVMOVE)) continue; - name = dev_name(seg->area[0].u.pv.pvseg->pv->dev); + name = dev_name(seg_dev(seg, 0)); return _string_disp(rh, field, &name); } @@ -917,12 +935,9 @@ static int _field_match(struct report_handle *rh, const char *field, size_t len) static int _add_sort_key(struct report_handle *rh, uint32_t field_num, uint32_t flags) { - struct list *fh; struct field_properties *fp, *found = NULL; - list_iterate(fh, &rh->field_props) { - fp = list_item(fh, struct field_properties); - + list_iterate_items(fp, &rh->field_props) { if (fp->field_num == field_num) { found = fp; break; @@ -1138,7 +1153,6 @@ int report_object(void *handle, struct volume_group *vg, struct lv_segment *seg, struct pv_segment *pvseg) { struct report_handle *rh = handle; - struct list *fh; struct field_properties *fp; struct row *row; struct field *field; @@ -1168,9 +1182,7 @@ int report_object(void *handle, struct volume_group *vg, list_add(&rh->rows, &row->list); /* For each field to be displayed, call its report_fn */ - list_iterate(fh, &rh->field_props) { - fp = list_item(fh, struct field_properties); - + list_iterate_items(fp, &rh->field_props) { skip = 0; if (!(field = pool_zalloc(rh->mem, sizeof(*field)))) { @@ -1231,7 +1243,6 @@ int report_object(void *handle, struct volume_group *vg, static int _report_headings(void *handle) { struct report_handle *rh = handle; - struct list *fh; struct field_properties *fp; const char *heading; char buf[1024]; @@ -1250,8 +1261,7 @@ static int _report_headings(void *handle) } /* First heading line */ - list_iterate(fh, &rh->field_props) { - fp = list_item(fh, struct field_properties); + list_iterate_items(fp, &rh->field_props) { if (fp->flags & FLD_HIDDEN) continue; @@ -1268,7 +1278,7 @@ static int _report_headings(void *handle) } else if (!pool_grow_object(rh->mem, heading, strlen(heading))) goto bad; - if (!list_end(&rh->field_props, fh)) + if (!list_end(&rh->field_props, &fp->list)) if (!pool_grow_object(rh->mem, rh->separator, strlen(rh->separator))) goto bad; @@ -1336,7 +1346,6 @@ static int _row_compare(const void *a, const void *b) static int _sort_rows(struct report_handle *rh) { struct row *(*rows)[]; - struct list *rowh; uint32_t count = 0; struct row *row; @@ -1346,10 +1355,8 @@ static int _sort_rows(struct report_handle *rh) return 0; } - list_iterate(rowh, &rh->rows) { - row = list_item(rowh, struct row); + list_iterate_items(row, &rh->rows) (*rows)[count++] = row; - } qsort(rows, count, sizeof(**rows), _row_compare); diff --git a/lib/striped/striped.c b/lib/striped/striped.c index dd95454df..a6c1be90a 100644 --- a/lib/striped/striped.c +++ b/lib/striped/striped.c @@ -119,10 +119,10 @@ static int _segments_compatible(struct lv_segment *first, width = first->area_len; - if ((first->area[s].u.pv.pvseg->pv != - second->area[s].u.pv.pvseg->pv) || - (first->area[s].u.pv.pvseg->pe + width != - second->area[s].u.pv.pvseg->pe)) + if ((seg_pv(first, s) != + seg_pv(second, s)) || + (seg_pe(first, s) + width != + seg_pe(second, s))) return 0; } @@ -144,8 +144,8 @@ static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2) for (s = 0; s < seg1->area_count; s++) if (seg1->area[s].type == AREA_PV) - merge_pv_segments(seg1->area[s].u.pv.pvseg, - seg2->area[s].u.pv.pvseg); + merge_pv_segments(seg_pvseg(seg1, s), + seg_pvseg(seg2, s)); return 1; } diff --git a/libdm/datastruct/list.h b/libdm/datastruct/list.h index b43b26ca0..e2fbc76c1 100644 --- a/libdm/datastruct/list.h +++ b/libdm/datastruct/list.h @@ -103,6 +103,14 @@ static inline int list_end(struct list *head, struct list *elem) return elem->n == head; } +/* + * Return first element of the list or NULL if empty + */ +static inline struct list *list_first(struct list *head) +{ + return (list_empty(head) ? NULL : head->n); +} + /* * Return last element of the list or NULL if empty */ @@ -194,6 +202,25 @@ static inline struct list *list_next(struct list *head, struct list *elem) */ #define list_iterate_items(v, head) list_iterate_items_gen(v, (head), list) +/* + * Walk a list backwards, setting 'v' in turn to the containing structure + * of each item. + * The containing structure should be the same type as 'v'. + * The 'struct list' variable within the containing structure is 'field'. + */ +#define list_iterate_back_items_gen(v, head, field) \ + for (v = list_struct_base((head)->p, typeof(*v), field); \ + &v->field != (head); \ + v = list_struct_base(v->field.p, typeof(*v), field)) + +/* + * Walk a list backwards, setting 'v' in turn to the containing structure + * of each item. + * The containing structure should be the same type as 'v'. + * The list should be 'struct list list' within the containing structure. + */ +#define list_iterate_back_items(v, head) list_iterate_back_items_gen(v, (head), list) + /* * Return the number of elements in a list by walking it. */ diff --git a/tools/args.h b/tools/args.h index e88a66188..80b5b9a3d 100644 --- a/tools/args.h +++ b/tools/args.h @@ -85,6 +85,7 @@ arg(size_ARG, 'L', "size", size_mb_arg) arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign) arg(persistent_ARG, 'M', "persistent", yes_no_arg) arg(major_ARG, 'j', "major", major_arg) +arg(mirrors_ARG, 'm', "mirrors", int_arg) arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg) arg(maps_ARG, 'm', "maps", NULL) arg(name_ARG, 'n', "name", string_arg) @@ -100,6 +101,7 @@ arg(physicalvolume_ARG, 'P', "physicalvolume", NULL) arg(readahead_ARG, 'r', "readahead", int_arg) arg(resizefs_ARG, 'r', "resizefs", NULL) arg(reset_ARG, 'R', "reset", NULL) +arg(regionsize_ARG, 'R', "regionsize", size_mb_arg) arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg) arg(stdin_ARG, 's', "stdin", NULL) arg(snapshot_ARG, 's', "snapshot", NULL) diff --git a/tools/commands.h b/tools/commands.h index 22931f01b..46ac265ed 100644 --- a/tools/commands.h +++ b/tools/commands.h @@ -91,9 +91,11 @@ xx(lvcreate, "\t{-l|--extents LogicalExtentsNumber |\n" "\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n" "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n" + "\t[-m|--mirrors Mirrors]\n" "\t[-n|--name LogicalVolumeName]\n" "\t[-p|--permission {r|rw}]\n" "\t[-r|--readahead ReadAheadSectors]\n" + "\t[-R|--regionsize MirrorLogRegionSize]\n" "\t[-t|--test]\n" "\t[--type VolumeType]\n" "\t[-v|--verbose]\n" @@ -122,9 +124,9 @@ xx(lvcreate, "\tOriginalLogicalVolume[Path] [PhysicalVolumePath...]\n\n", addtag_ARG, alloc_ARG, autobackup_ARG, chunksize_ARG, contiguous_ARG, - extents_ARG, major_ARG, minor_ARG, name_ARG, permission_ARG, - persistent_ARG, readahead_ARG, size_ARG, snapshot_ARG, stripes_ARG, - stripesize_ARG, test_ARG, type_ARG, zero_ARG) + extents_ARG, major_ARG, minor_ARG, mirrors_ARG, name_ARG, permission_ARG, + persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG, snapshot_ARG, + stripes_ARG, stripesize_ARG, test_ARG, type_ARG, zero_ARG) xx(lvdisplay, "Display information about a logical volume", diff --git a/tools/lvchange.c b/tools/lvchange.c index d268134e2..75251be2c 100644 --- a/tools/lvchange.c +++ b/tools/lvchange.c @@ -405,6 +405,12 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv, return ECMD_FAILED; } + /* FIXME Test for VISIBLE instead? */ + if (lv->status & MIRROR_LOG) { + log_error("Unable to change mirror log LV %s directly", lv->name); + return ECMD_FAILED; + } + /* access permission change */ if (arg_count(cmd, permission_ARG)) { if (!archive(lv->vg)) diff --git a/tools/lvcreate.c b/tools/lvcreate.c index f2d65a97b..7bd361119 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -14,6 +14,7 @@ */ #include "tools.h" +#include "lv_alloc.h" #include @@ -31,6 +32,7 @@ struct lvcreate_params { uint32_t stripes; uint32_t stripe_size; uint32_t chunk_size; + uint32_t region_size; uint32_t mirrors; @@ -228,6 +230,38 @@ static int _read_stripe_params(struct lvcreate_params *lp, return 1; } +static int _read_mirror_params(struct lvcreate_params *lp, + struct cmd_context *cmd, + int *pargc, char ***pargv) +{ + int argc = *pargc; + + if (argc && (unsigned) argc < lp->mirrors) { + log_error("Too few physical volumes on " + "command line for %d-way mirroring", lp->mirrors); + return 0; + } + + if (arg_count(cmd, regionsize_ARG)) { + if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) { + log_error("Negative regionsize is invalid"); + return 0; + } + lp->region_size = 2 * arg_uint_value(cmd, regionsize_ARG, 0); + } else + lp->region_size = 2 * find_config_int(cmd->cft->root, + "activation/mirror_region_size", + DEFAULT_MIRROR_REGION_SIZE); + + if (lp->region_size & (lp->region_size - 1)) { + log_error("Region size (%" PRIu32 ") must be a power of 2", + lp->region_size); + return 0; + } + + return 1; +} + static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd, int argc, char **argv) { @@ -249,6 +283,18 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd, if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp)) lp->snapshot = 1; + lp->mirrors = 1; + + /* Default to 2 mirrored areas if --type mirror */ + if (seg_is_mirrored(lp)) + lp->mirrors = 2; + + if (arg_count(cmd, mirrors_ARG)) { + lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1; + if (lp->mirrors == 1) + log_print("Redundant mirrors argument: default is 0"); + } + if (lp->snapshot) { if (arg_count(cmd, zero_ARG)) { log_error("-Z is incompatible with snapshots"); @@ -272,6 +318,25 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd, } } + if (lp->mirrors > 1) { + if (lp->snapshot) { + log_error("mirrors and snapshots are currently " + "incompatible"); + return 0; + } + + if (lp->stripes > 1) { + log_error("mirrors and stripes are currently " + "incompatible"); + return 0; + } + + if (!(lp->segtype = get_segtype_from_string(cmd, "mirror"))) { + stack; + return 0; + } + } + if (activation() && lp->segtype->ops->target_present && !lp->segtype->ops->target_present()) { log_error("%s: Required device-mapper target(s) not " @@ -281,8 +346,11 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd, if (!_read_name_params(lp, cmd, &argc, &argv) || !_read_size_params(lp, cmd, &argc, &argv) || - !_read_stripe_params(lp, cmd, &argc, &argv)) + !_read_stripe_params(lp, cmd, &argc, &argv) || + !_read_mirror_params(lp, cmd, &argc, &argv)) { + stack; return 0; + } /* * Should we zero the lv. @@ -392,14 +460,15 @@ static int _zero_lv(struct cmd_context *cmd, struct logical_volume *lv) static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) { - uint32_t size_rest; + uint32_t size_rest, region_max; uint32_t status = 0; uint64_t tmp_size; struct volume_group *vg; - struct logical_volume *lv, *org = NULL; + struct logical_volume *lv, *org = NULL, *log_lv = NULL; struct list *pvh; const char *tag; int consistent = 1; + struct alloc_handle *ah = NULL; status |= lp->permission | VISIBLE_LV; @@ -505,30 +574,98 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) return 0; } - if (lp->stripes > list_size(pvh)) { + if (lp->stripes > list_size(pvh) && lp->alloc != ALLOC_ANYWHERE) { log_error("Number of stripes (%u) must not exceed " "number of physical volumes (%d)", lp->stripes, list_size(pvh)); return 0; } - if (!(lv = lv_create_empty(vg->fid, lp->lv_name, "lvol%d", NULL, - status, lp->alloc, 0, vg))) { - stack; + if (lp->mirrors > 1 && !activation()) { + log_error("Can't create mirror without using " + "device-mapper kernel driver."); return 0; } /* The snapshot segment gets created later */ - if (lp->snapshot) - if (!(lp->segtype = get_segtype_from_string(cmd, "striped"))) { + if (lp->snapshot && + !(lp->segtype = get_segtype_from_string(cmd, "striped"))) { + stack; + return 0; + } + + if (!archive(vg)) + return 0; + + if (lp->mirrors > 1) { + /* FIXME Adjust lp->region_size if necessary */ + region_max = (1 << (ffs(lp->extents) - 1)) * vg->extent_size; + + if (region_max < lp->region_size) { + lp->region_size = region_max; + log_print("Using reduced mirror region size of %" PRIu32 + " sectors", lp->region_size); + } + + /* FIXME Calculate how many extents needed for the log */ + + if (!(log_lv = lv_create_empty(vg->fid, NULL, "mirrorlog%d", NULL, + VISIBLE_LV | LVM_READ | LVM_WRITE, + lp->alloc, 0, vg))) { stack; return 0; } - if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size, - lp->mirrors, lp->extents, NULL, 0u, 0u, pvh, lp->alloc)) { + if (!(ah = allocate_extents(vg, NULL, lp->segtype, lp->stripes, + lp->mirrors, 1, lp->extents, + NULL, 0, 0, pvh, lp->alloc))) { + stack; + return 0; + } + + if (!lv_add_log_segment(ah, log_lv)) { + stack; + goto error; + } + + /* store mirror log on disk(s) */ + if (!vg_write(vg)) { + stack; + goto error; + } + + backup(vg); + + if (!vg_commit(vg)) { + stack; + goto error; + } + + if (!activate_lv(cmd, log_lv->lvid.s)) { + log_error("Aborting. Failed to activate mirror log. " + "Remove new LVs and retry."); + goto error; + } + + if (activation() && !_zero_lv(cmd, log_lv)) { + log_error("Aborting. Failed to wipe mirror log. " + "Remove new LV and retry."); + goto error; + } + + if (!deactivate_lv(cmd, log_lv->lvid.s)) { + log_error("Aborting. Failed to deactivate mirror log. " + "Remove new LV and retry."); + goto error; + } + + log_lv->status &= ~VISIBLE_LV; + } + + if (!(lv = lv_create_empty(vg->fid, lp->lv_name, "lvol%d", NULL, + status, lp->alloc, 0, vg))) { stack; - return 0; + goto error; } if (lp->read_ahead) { @@ -547,24 +684,38 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) if (arg_count(cmd, addtag_ARG)) { if (!(tag = arg_str_value(cmd, addtag_ARG, NULL))) { log_error("Failed to get tag"); - return 0; + goto error; } if (!(lv->vg->fid->fmt->features & FMT_TAGS)) { log_error("Volume group %s does not support tags", lv->vg->name); - return 0; + goto error; } if (!str_list_add(cmd->mem, &lv->tags, tag)) { log_error("Failed to add tag %s to %s/%s", tag, lv->vg->name, lv->name); - return 0; + goto error; } } - if (!archive(vg)) + if (lp->mirrors > 1) { + if (!lv_add_segment(ah, 0, lp->mirrors, lv, lp->segtype, + lp->stripe_size, NULL, 0, 0, + lp->region_size, log_lv)) { + log_error("Aborting. Failed to add mirror segment. " + "Remove new LV and retry."); + goto error; + } + + alloc_destroy(ah); + ah = NULL; + } else if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size, + lp->mirrors, lp->extents, NULL, 0u, 0u, pvh, lp->alloc)) { + stack; return 0; + } /* store vg on disk(s) */ if (!vg_write(vg)) { @@ -642,6 +793,11 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) */ return 1; + +error: + if (ah) + alloc_destroy(ah); + return 0; } int lvcreate(struct cmd_context *cmd, int argc, char **argv) diff --git a/tools/lvremove.c b/tools/lvremove.c index 94c22c3b9..e5069a1fa 100644 --- a/tools/lvremove.c +++ b/tools/lvremove.c @@ -34,6 +34,12 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, return ECMD_FAILED; } + if (lv->status & MIRROR_LOG) { + log_error("Can't remove logical volume %s used as mirror log", + lv->name); + return ECMD_FAILED; + } + if (lv->status & LOCKED) { log_error("Can't remove locked LV %s", lv->name); return ECMD_FAILED; diff --git a/tools/toollib.c b/tools/toollib.c index 8882c72e8..4c7cf160b 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -110,9 +110,9 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv, int ret = 0; int consistent; - struct list *slh, *tags_arg; + struct list *tags_arg; struct list *vgnames; /* VGs to process */ - struct str_list *sll; + struct str_list *sll, *strl; struct volume_group *vg; struct list tags, lvnames; struct list arg_lvnames; /* Cmdline vgname or vgname/lvname */ @@ -228,8 +228,8 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv, } } - list_iterate(slh, vgnames) { - vgname = list_item(slh, struct str_list)->str; + list_iterate_items(strl, vgnames) { + vgname = strl->str; if (!vgname || !*vgname) continue; /* FIXME Unnecessary? */ if (!lock_vol(cmd, vgname, lock_type)) { diff --git a/tools/vgchange.c b/tools/vgchange.c index d30e32b6c..efc23e274 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -30,10 +30,10 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd, if ((lv->status & SNAPSHOT) || lv_is_cow(lv)) continue; - /* Can't deactive a pvmove LV */ + /* Can't deactive a pvmove or log LV */ /* FIXME There needs to be a controlled way of doing this */ if (((activate == CHANGE_AN) || (activate == CHANGE_ALN)) && - (lv->status & PVMOVE)) + ((lv->status & PVMOVE) || (lv->status & MIRROR_LOG))) continue; if (activate == CHANGE_AN) { diff --git a/tools/vgreduce.c b/tools/vgreduce.c index db1afec93..64b797d39 100644 --- a/tools/vgreduce.c +++ b/tools/vgreduce.c @@ -129,12 +129,12 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg) /* Are any segments of this LV on missing PVs? */ list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { - if (seg->area[s].type != AREA_PV) + if (seg_type(seg, s) != AREA_PV) continue; /* FIXME Also check for segs on deleted LVs */ - pv = seg->area[s].u.pv.pvseg->pv; + pv = seg_pv(seg, s); if (!pv || !pv->dev) { if (!_remove_lv(cmd, lv, &list_unsafe)) { stack; diff --git a/tools/vgsplit.c b/tools/vgsplit.c index 4762ebd57..cf19ba1c9 100644 --- a/tools/vgsplit.c +++ b/tools/vgsplit.c @@ -78,10 +78,10 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) list_iterate_items(seg, &lv->segments) { for (s = 0; s < seg->area_count; s++) { /* FIXME Check AREA_LV too */ - if (seg->area[s].type != AREA_PV) + if (seg_type(seg, s) != AREA_PV) continue; - pv = seg->area[s].u.pv.pvseg->pv; + pv = seg_pv(seg, s); if (vg_with) { if (!pv_is_in_vg(vg_with, pv)) { log_error("Logical Volume %s "