summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorAlasdair Kergon <agk@redhat.com>2005-06-01 16:51:55 +0000
committerAlasdair Kergon <agk@redhat.com>2005-06-01 16:51:55 +0000
commit60f13f01d2af1cb1b05c20b11285c7c6c15acd6b (patch)
tree32895b7e9cb063b88bd00c568dc59f949cc716f2 /lib
parent8e6230ddd981539221bc82ed71ed9f2308148e2c (diff)
downloadlvm2-60f13f01d2af1cb1b05c20b11285c7c6c15acd6b.tar.gz
lvm2-60f13f01d2af1cb1b05c20b11285c7c6c15acd6b.tar.xz
lvm2-60f13f01d2af1cb1b05c20b11285c7c6c15acd6b.zip
Basic support for mirrors.
Diffstat (limited to 'lib')
-rw-r--r--lib/activate/activate.c19
-rw-r--r--lib/activate/dev_manager.c209
-rw-r--r--lib/cache/lvmcache.c25
-rw-r--r--lib/commands/toolcontext.c4
-rw-r--r--lib/config/defaults.h4
-rw-r--r--lib/datastruct/list.h27
-rw-r--r--lib/device/dev-cache.c16
-rw-r--r--lib/display/display.c23
-rw-r--r--lib/filters/filter-persistent.c6
-rw-r--r--lib/filters/filter-regex.c4
-rw-r--r--lib/format1/disk-rep.c28
-rw-r--r--lib/format1/format1.c9
-rw-r--r--lib/format1/import-export.c72
-rw-r--r--lib/format1/import-extents.c20
-rw-r--r--lib/format1/vg_number.c4
-rw-r--r--lib/format_pool/disk_rep.c26
-rw-r--r--lib/format_pool/format_pool.c8
-rw-r--r--lib/format_pool/import_export.c30
-rw-r--r--lib/format_text/archive.c23
-rw-r--r--lib/format_text/export.c146
-rw-r--r--lib/format_text/flags.c1
-rw-r--r--lib/format_text/format-text.c106
-rw-r--r--lib/format_text/import_vsn1.c12
-rw-r--r--lib/format_text/layout.h1
-rw-r--r--lib/format_text/text_label.c12
-rw-r--r--lib/label/label.c13
-rw-r--r--lib/locking/locking.c43
-rw-r--r--lib/locking/locking_types.h1
-rw-r--r--lib/metadata/lv_alloc.h34
-rw-r--r--lib/metadata/lv_manip.c1123
-rw-r--r--lib/metadata/merge.c82
-rw-r--r--lib/metadata/metadata.c136
-rw-r--r--lib/metadata/metadata.h15
-rw-r--r--lib/metadata/mirror.c99
-rw-r--r--lib/metadata/pv_alloc.h2
-rw-r--r--lib/metadata/pv_manip.c60
-rw-r--r--lib/metadata/segtype.h4
-rw-r--r--lib/metadata/snapshot_manip.c2
-rw-r--r--lib/mirror/mirrored.c75
-rw-r--r--lib/mm/dbg_malloc.c3
-rw-r--r--lib/report/columns.h2
-rw-r--r--lib/report/report.c57
-rw-r--r--lib/striped/striped.c12
43 files changed, 1488 insertions, 1110 deletions
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 8ff3b8a3..ef265d73 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 2ccdd445..2a06bb7a 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 3173f464..17084a54 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 02bdefa3..023d8c49 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 c4dcb815..aa6c4701 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 b43b26ca..e2fbc76c 100644
--- a/lib/datastruct/list.h
+++ b/lib/datastruct/list.h
@@ -104,6 +104,14 @@ static inline int list_end(struct list *head, struct list *elem)
}
/*
+ * 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
*/
static inline struct list *list_last(struct list *head)
@@ -195,6 +203,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.
*/
static inline unsigned int list_size(const struct list *head)
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index d585d3c7..383f95f4 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 11726e44..c8719510 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 0666156b..4ab22950 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 ed6da849..db8e07f8 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 834e5c86..9418ff98 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 8bc88709..45f71583 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 2e38104a..d1360e0b 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 20913a5d..cf74fa09 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 c149aa9b..bab07d02 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 f6513808..3c8dbebe 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 b23df7d8..e2831617 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 dd315266..34a78b39 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 3f1b09f1..ea2e7db8 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 310c03f2..f84682b6 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 04354c2e..2acd1706 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 4d0f3d0b..9dfb5dbf 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 ec130594..5da5fc6d 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 a60be8a9..2f7ec8bc 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 3cecf4bd..bc43766e 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 beda8e97..b5faa20e 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 b3cbaf22..0e90aa3a 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;
-
- 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);
+ struct lv_list *lvl;
+
+ 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;
-
- 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);
+ struct lv_list *lvl;
+
+ 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 4bc0803e..2d5a0ba5 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 4607b802..cb0a5a4b 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 37ceccc7..47bd3c9f 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;
+ list_iterate_items(lvl, &lv->vg->lvs) {
+ lvnum = lvnum_from_lvid(&lvl->lv->lvid);
+ if (lvnum <= MAX_RESTRICTED_LVS)
+ lvnum_used[lvnum] = 1;
}
-}
-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;
+ while (lvnum_used[i])
+ i++;
- pv = seg->area[s].u.pv.pvseg->pv;
+ /* FIXME What if none are free? */
- if (pv) {
- count = seg->area_len;
- assert(pv->pe_alloc_count >= count);
- pv->pe_alloc_count -= count;
- }
- }
+ 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;
+ seg_lv(seg, area_num) = lv;
+ seg_le(seg, area_num) = le;
}
-static void _shrink_lv_segment(struct lv_segment *seg)
+/*
+ * Reduce the size of an lv_segment. New size can be zero.
+ */
+static int _lv_segment_reduce(struct lv_segment *seg, uint32_t reduction)
{
- uint32_t s;
+ uint32_t area_reduction, s;
+
+ /* 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->area[s].type != AREA_PV)
+ if (seg_type(seg, s) != AREA_PV)
continue;
- release_pv_segment(seg->area[s].u.pv.pvseg, seg->area_len);
+ release_pv_segment(seg_pvseg(seg, s), area_reduction);
}
+
+ return 1;
}
/*
- * 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.
+ * Entry point for all LV reductions in size.
*/
-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)
+int lv_reduce(struct logical_volume *lv, uint32_t extents)
{
- 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 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 */
- /* Striped or mirrored? */
- if (seg_is_striped(seg))
- striped = 1;
+ 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;
-
- if (area_len > smallest)
- area_len = smallest;
+ area_multiple = segtype_is_striped(segtype) ? area_count : 1;
- 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,284 +494,445 @@ 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)
{
- 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_segment *prev_pvseg;
+ uint32_t s;
- if (stripes > 1 && mirrors > 1) {
- log_error("striped mirrors are not supported yet");
- return 0;
- }
+ for (s = 0; s < prev_lvseg->area_count; s++) {
+ if (seg_type(prev_lvseg, s) != AREA_PV)
+ continue; /* FIXME Broken */
- 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 (!(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;
+ }
}
- if (stripes > 1)
- area_count = stripes;
- else if (mirrored_pv)
- area_count = 1;
- else
- area_count = mirrors;
+ return 0;
+}
- pv_count = list_size(pvms);
+/*
+ * 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)
+{
+ struct pv_map *pvm;
+ 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 */
- /* 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;
+ /* 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;
}
- 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 (contiguous) {
+ if (prev_lvseg &&
+ _check_contiguous(prev_lvseg,
+ pvm->pv,
+ pva, areas)) {
+ contiguous_count++;
+ break; /* Next PV */
+ }
+ continue;
+ }
- if (mirrored_pv) {
- if (pva->count < lv->le_count - allocated)
- goto next_pv;
+ /* 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++] = pva;
- if (mirrored_pv)
- goto try_it;
+ 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);
-
- if (!_alloc_parallel_area(lv, area_count, stripe_size, segtype,
- areas, &allocated, mirrored_pv, mirrored_pe)) {
+ qsort(areas + ix_offset, ix, sizeof(*areas),
+ _comp_area);
+
+ 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);
- 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);
- goto out;
- }
-
- r = 1;
-
- out:
- dbg_free(areas);
- return r;
+ return 1;
}
/*
- * 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.
+ * 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 _alloc_next_free(struct logical_volume *lv, alloc_policy_t alloc,
- struct list *pvms, uint32_t allocated,
- struct segment_type *segtype)
+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_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;
+ 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 (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;
+ if (allocated >= new_extents) {
+ log_error("_allocate called with no work to do!");
+ return 1;
+ }
- list_iterate_items(pvm, pvms) {
- if (prev_pvseg && (prev_pvseg->pv != pvm->pv))
- continue;
+ if (mirrored_pv || (ah->alloc == ALLOC_CONTIGUOUS) || ah->log_count)
+ can_split = 0;
- list_iterate_items(pva, &pvm->areas) {
- if (prev_pvseg &&
- (prev_pvseg->pe + prev_pvseg->len != pva->start))
- continue;
+ 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;
+ }
- if (pva->count > largest)
- largest = pva->count;
+ 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;
+ }
- /* first item in the list is the biggest */
- if (contiguous &&
- pva->count < lv->le_count - allocated)
- goto next_pv;
+ /* 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;
+ }
- if (!_alloc_parallel_area(lv, 1, 0, segtype, &pva,
- &allocated, NULL, 0)) {
- stack;
- 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 (contiguous || (allocated == lv->le_count))
- goto out;
- }
+ if ((allocated == new_extents) || (ah->alloc == ALLOC_CONTIGUOUS) ||
+ (!can_split && (allocated != old_allocated)))
+ goto finished;
- next_pv:
- ;
+ old_allocated = allocated;
+ if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas,
+ areas_size, can_split,
+ prev_lvseg, &allocated, new_extents)) {
+ stack;
+ goto out;
}
- 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;
+ 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;
}
- return 1;
+ 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;
+ }
+
+ r = 1;
+
+ out:
+ dbg_free(areas);
+ return r;
}
-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)
+{
+ if (segtype_is_virtual(segtype)) {
+ log_error("lv_add_segment cannot handle virtual segments");
+ return 0;
+ }
+
+ 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 ((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;
+}
+
+/*
+ * Turn an empty LV into a mirror log.
+ */
+int lv_add_log_segment(struct alloc_handle *ah, 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->flags & SEG_VIRTUAL)
- return _alloc_virtual(lv, allocated, segtype);
+ 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;
- if (!(scratch = pool_create("allocation", 1024))) {
+ 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;
}
- if (alloc == ALLOC_INHERIT)
- alloc = lv->vg->alloc;
+ return 1;
+}
- /*
- * Build the sets of available areas on the pv's.
- */
- if (!(pvms = create_pv_maps(scratch, lv->vg, allocatable_pvs)))
- goto out;
+/*
+ * 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 (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 (segtype_is_virtual(segtype))
+ return lv_add_virtual_segment(lv, status, extents, segtype);
- if (r) {
- lv->vg->free_count -= lv->le_count - allocated;
+ if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0,
+ extents, mirrored_pv, mirrored_pe, status,
+ allocatable_pvs, alloc))) {
+ stack;
+ return 0;
+ }
- /*
- * 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;
+ if (!lv_add_segment(ah, 0, ah->area_count, lv, segtype, stripe_size,
+ mirrored_pv, mirrored_pe, status, 0, NULL)) {
+ stack;
+ goto out;
}
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 ba403206..9ac10fba 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 60fc1ec6..5f999702 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 a6f90248..a5914dcf 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 76a0e072..7bdaf2c4 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 ff2b76a4..8b4134b1 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 64499aa7..2e9a2d6b 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 67388b83..83cbb860 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 d0133b54..266b3d40 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 cf76d6db..3fe7992d 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 79bb49ce..b2fc38af 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 bf55c5d6..ef86d34b 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 3eb85400..c947d722 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 dd95454d..a6c1be90 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;
}