From 072893aabd31b78b23b8235fe5f99146a40c7543 Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Thu, 7 Apr 2005 12:39:44 +0000 Subject: [PATCH] Internal snapshot code restructuring. --- lib/activate/dev_manager.c | 69 ++++++++------ lib/display/display.c | 82 +++++++---------- lib/format1/format1.c | 1 - lib/format1/import-export.c | 48 ++++------ lib/format1/import-extents.c | 2 + lib/format_pool/format_pool.c | 1 - lib/format_pool/import_export.c | 9 +- lib/format_text/export.c | 86 ------------------ lib/format_text/flags.c | 1 + lib/format_text/import_vsn1.c | 40 +++++---- lib/metadata/lv_alloc.h | 3 + lib/metadata/lv_manip.c | 38 +++++++- lib/metadata/metadata.c | 2 - lib/metadata/metadata.h | 38 +++----- lib/metadata/snapshot_manip.c | 155 +++++++++----------------------- lib/report/report.c | 21 ++--- lib/snapshot/snapshot.c | 4 +- tools/lvcreate.c | 6 +- tools/lvresize.c | 6 +- tools/pvmove.c | 5 +- tools/toollib.c | 3 + tools/vgchange.c | 2 +- tools/vgconvert.c | 2 + tools/vgreduce.c | 34 ++++--- tools/vgsplit.c | 70 +++++++++------ 25 files changed, 307 insertions(+), 421 deletions(-) diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index 80b284021..0481132a8 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -875,22 +875,23 @@ static int _populate_snapshot(struct dev_manager *dm, { char *origin, *cow; char params[PATH_MAX * 2 + 32]; - struct snapshot *s; + struct lv_segment *snap_seg; struct dev_layer *dlo, *dlc; char devbufo[10], devbufc[10]; uint64_t size; - if (!(s = find_cow(dl->lv))) { + if (!(snap_seg = find_cow(dl->lv))) { log_error("Couldn't find snapshot for '%s'.", dl->lv->name); return 0; } - if (!(origin = _build_dlid(dm->mem, s->origin->lvid.s, "real"))) { + if (!(origin = _build_dlid(dm->mem, snap_seg->origin->lvid.s, + "real"))) { stack; return 0; } - if (!(cow = _build_dlid(dm->mem, s->cow->lvid.s, "cow"))) { + if (!(cow = _build_dlid(dm->mem, snap_seg->cow->lvid.s, "cow"))) { stack; return 0; } @@ -909,24 +910,24 @@ static int _populate_snapshot(struct dev_manager *dm, if (!dm_format_dev(devbufo, sizeof(devbufo), dlo->info.major, dlo->info.minor)) { log_error("Couldn't create origin device parameters for '%s'.", - s->origin->name); + snap_seg->origin->name); return 0; } if (!dm_format_dev(devbufc, sizeof(devbufc), dlc->info.major, dlc->info.minor)) { log_error("Couldn't create cow device parameters for '%s'.", - s->cow->name); + snap_seg->cow->name); return 0; } if (lvm_snprintf(params, sizeof(params), "%s %s P %d", - devbufo, devbufc, s->chunk_size) == -1) { + devbufo, devbufc, snap_seg->chunk_size) == -1) { stack; return 0; } - size = (uint64_t) s->le_count * s->origin->vg->extent_size; + size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size; log_debug("Adding target: 0 %" PRIu64 " snapshot %s", size, params); if (!dm_task_add_target(dmt, UINT64_C(0), size, "snapshot", params)) { @@ -1274,7 +1275,7 @@ static int _expand_origin_real(struct dev_manager *dm, static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv) { struct logical_volume *active; - struct snapshot *s; + struct lv_segment *snap_seg; struct list *sh; /* @@ -1283,7 +1284,7 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv) */ list_iterate(sh, &dm->active_list) { active = list_item(sh, struct lv_list)->lv; - if ((s = find_cow(active)) && (s->origin == lv)) + if ((snap_seg = find_cow(active)) && (snap_seg->origin == lv)) return _expand_origin_real(dm, lv); } @@ -1294,7 +1295,7 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv) } static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv, - struct snapshot *s) + struct lv_segment *snap_seg) { /* * snapshot(org, cow) @@ -1331,13 +1332,15 @@ static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv, /* add the dependency on the real origin device */ if (!str_list_add(dm->mem, &dl->pre_create, - _build_dlid(dm->mem, s->origin->lvid.s, "real"))) { + _build_dlid(dm->mem, snap_seg->origin->lvid.s, + "real"))) { stack; return 0; } /* add the dependency on the visible origin device */ - if (!str_list_add(dm->mem, &dl->pre_suspend, s->origin->lvid.s)) { + if (!str_list_add(dm->mem, &dl->pre_suspend, + snap_seg->origin->lvid.s)) { stack; return 0; } @@ -1350,13 +1353,13 @@ static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv, */ static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv) { - struct snapshot *s; + struct lv_segment *snap_seg; /* * FIXME: this doesn't cope with recursive snapshots yet. */ - if ((s = find_cow(lv))) - return _expand_snapshot(dm, lv, s); + if ((snap_seg = find_cow(lv))) + return _expand_snapshot(dm, lv, snap_seg); else if (lv_is_origin(lv)) return _expand_origin(dm, lv); @@ -1445,6 +1448,8 @@ static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag) list_iterate(lvh, lvs) { lv = list_item(lvh, struct lv_list)->lv; + if (lv->status & SNAPSHOT) + continue; if (!(dl = _lookup(dm, lv->lvid.s, NULL))) { stack; @@ -1606,14 +1611,16 @@ 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 *lvt; + struct logical_volume *lv; /* * Build layers for complete vg. */ list_iterate(lvh, &vg->lvs) { - lvt = list_item(lvh, struct lv_list)->lv; - if (!_expand_lv(dm, lvt)) { + lv = list_item(lvh, struct lv_list)->lv; + if (lv->status & SNAPSHOT) + continue; + if (!_expand_lv(dm, lv)) { stack; return 0; } @@ -1915,12 +1922,14 @@ static int _add_lvs(struct pool *mem, struct list *head, struct logical_volume *origin) { struct logical_volume *lv; - struct snapshot *s; + struct lv_segment *snap_seg; struct list *lvh; list_iterate(lvh, &origin->vg->lvs) { lv = list_item(lvh, struct lv_list)->lv; - if ((s = find_cow(lv)) && s->origin == origin) + if (lv->status & SNAPSHOT) + continue; + if ((snap_seg = find_cow(lv)) && snap_seg->origin == origin) if (!_add_lv(mem, head, lv)) return 0; } @@ -1945,7 +1954,7 @@ static void _remove_lv(struct list *head, struct logical_volume *lv) static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv) { struct logical_volume *active, *old_origin; - struct snapshot *s; + struct lv_segment *snap_seg; struct list *sh, *active_head; active_head = &dm->active_list; @@ -1953,22 +1962,23 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv) /* Remove any snapshots with given origin */ list_iterate(sh, active_head) { active = list_item(sh, struct lv_list)->lv; - if ((s = find_cow(active)) && s->origin == lv) { + if ((snap_seg = find_cow(active)) && snap_seg->origin == lv) { _remove_lv(active_head, active); } } _remove_lv(active_head, lv); - if (!(s = find_cow(lv))) + if (!(snap_seg = find_cow(lv))) return 1; - old_origin = s->origin; + 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; - if ((s = find_cow(active)) && s->origin == old_origin) { + if ((snap_seg = find_cow(active)) && + snap_seg->origin == old_origin) { return 1; } } @@ -1980,7 +1990,7 @@ static int _remove_suspended_lvs(struct dev_manager *dm, struct logical_volume *lv) { struct logical_volume *suspended; - struct snapshot *s; + struct lv_segment *snap_seg; struct list *sh, *suspend_head; suspend_head = &dm->suspend_list; @@ -1988,7 +1998,8 @@ static int _remove_suspended_lvs(struct dev_manager *dm, /* Remove from list any snapshots with given origin */ list_iterate(sh, suspend_head) { suspended = list_item(sh, struct lv_list)->lv; - if ((s = find_cow(suspended)) && s->origin == lv) { + if ((snap_seg = find_cow(suspended)) && + snap_seg->origin == lv) { _remove_lv(suspend_head, suspended); } } @@ -2074,6 +2085,8 @@ static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg) list_iterate(lvh, &vg->lvs) { lv = list_item(lvh, struct lv_list)->lv; + if (lv->status & SNAPSHOT) + continue; if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) { stack; diff --git a/lib/display/display.c b/lib/display/display.c index 3be412cc6..f5d3df057 100644 --- a/lib/display/display.c +++ b/lib/display/display.c @@ -337,10 +337,9 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv, void *handle) { struct lvinfo info; - int inkernel, snap_active; + int inkernel, snap_active = 0; char uuid[64]; - struct snapshot *snap = NULL; - struct list *slh, *snaplist; + struct lv_segment *snap_seg = NULL; float snap_percent; /* fused, fsize; */ if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) { @@ -364,27 +363,30 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv, if (lv_is_origin(lv)) { log_print("LV snapshot status source of"); - snaplist = find_snapshots(lv); - list_iterate(slh, snaplist) { - snap = list_item(slh, struct snapshot_list)->snapshot; - snap_active = lv_snapshot_percent(snap->cow, - &snap_percent); - if (!snap_active || snap_percent < 0 || - snap_percent >= 100) snap_active = 0; + list_iterate_items_gen(snap_seg, &lv->snapshot_segs, + origin_list) { + if (inkernel && + (snap_active = lv_snapshot_percent(snap_seg->cow, + &snap_percent))) + if (snap_percent < 0 || snap_percent >= 100) + snap_active = 0; log_print(" %s%s/%s [%s]", lv->vg->cmd->dev_dir, lv->vg->name, - snap->cow->name, + snap_seg->cow->name, (snap_active > 0) ? "active" : "INACTIVE"); } - snap = NULL; - } else if ((snap = find_cow(lv))) { - snap_active = lv_snapshot_percent(lv, &snap_percent); - if (!snap_active || snap_percent < 0 || snap_percent >= 100) - snap_active = 0; + snap_seg = NULL; + } else if ((snap_seg = find_cow(lv))) { + if (inkernel && + (snap_active = lv_snapshot_percent(snap_seg->cow, + &snap_percent))) + if (snap_percent < 0 || snap_percent >= 100) + snap_active = 0; + log_print("LV snapshot status %s destination for %s%s/%s", (snap_active > 0) ? "active" : "INACTIVE", lv->vg->cmd->dev_dir, lv->vg->name, - snap->origin->name); + snap_seg->origin->name); } if (inkernel && info.suspended) @@ -402,15 +404,24 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv, log_print("LV Size %s", display_size(cmd, - snap ? snap->origin->size : lv->size, + snap_seg ? snap_seg->origin->size : lv->size, SIZE_SHORT)); log_print("Current LE %u", - snap ? snap->origin->le_count : lv->le_count); + snap_seg ? snap_seg->origin->le_count : lv->le_count); -/********** FIXME allocation - log_print("Allocated LE %u", lv->allocated_le); -**********/ + if (snap_seg) { + log_print("COW-table size %s", + display_size(cmd, (uint64_t) lv->size, SIZE_SHORT)); + log_print("COW-table LE %u", lv->le_count); + + if (snap_active) + log_print("Allocated to snapshot %.2f%% ", snap_percent); + + log_print("Snapshot chunk size %s", + display_size(cmd, (uint64_t) snap_seg->chunk_size, + SIZE_SHORT)); + } log_print("Segments %u", list_size(&lv->segments)); @@ -418,31 +429,6 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv, log_print("Stripe size (KByte) %u", lv->stripesize / 2); ***********/ - if (snap) { - if (snap_percent == -1) - snap_percent = 100; - - log_print("Snapshot chunk size %s", - display_size(cmd, (uint64_t) snap->chunk_size, - SIZE_SHORT)); - -/* - size = display_size(lv->size, SIZE_SHORT); - sscanf(size, "%f", &fsize); - fused = fsize * snap_percent / 100; -*/ - log_print("Allocated to snapshot %.2f%% ", /* [%.2f/%s]", */ - snap_percent); /*, fused, size); */ - /* dbg_free(size); */ - } - -/********** FIXME Snapshot - size = ??? - log_print("Allocated to COW-table %s", size); - dbg_free(size); - } -******************/ - log_print("Allocation %s", get_alloc_string(lv->alloc)); log_print("Read ahead sectors %u", lv->read_ahead); @@ -550,7 +536,7 @@ void vgdisplay_full(struct volume_group *vg) vg->status & SHARED ? "yes" : "no"); } log_print("MAX LV %u", vg->max_lv); - log_print("Cur LV %u", vg->lv_count); + log_print("Cur LV %u", vg->lv_count + vg->snapshot_count); log_print("Open LV %u", lvs_in_vg_opened(vg)); /****** FIXME Max LV Size log_print ( "MAX LV Size %s", diff --git a/lib/format1/format1.c b/lib/format1/format1.c index ff4a00cb1..8bc887092 100644 --- a/lib/format1/format1.c +++ b/lib/format1/format1.c @@ -148,7 +148,6 @@ static struct volume_group *_build_vg(struct format_instance *fid, vg->seqno = 0; list_init(&vg->pvs); list_init(&vg->lvs); - list_init(&vg->snapshots); list_init(&vg->tags); if (!_check_vgs(pvs, &partial)) diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c index 99bddd265..0fdb3e9f0 100644 --- a/lib/format1/import-export.c +++ b/lib/format1/import-export.c @@ -323,6 +323,8 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd) lv->size = lvd->lv_size; lv->le_count = lvd->lv_allocated_le; + lv->snapshot = NULL; + list_init(&lv->snapshot_segs); list_init(&lv->segments); list_init(&lv->tags); @@ -495,7 +497,7 @@ 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, *sh; + struct list *lvh; struct lv_list *ll; struct lvd_list *lvdl; size_t len; @@ -524,6 +526,9 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg, list_iterate(lvh, &vg->lvs) { ll = list_item(lvh, struct lv_list); + if (ll->lv->status & SNAPSHOT) + continue; + if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) { stack; goto out; @@ -532,7 +537,6 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg, _export_lv(&lvdl->lvd, vg, ll->lv, dev_dir); lv_num = lvnum_from_lvid(&ll->lv->lvid); - lvdl->lvd.lv_number = lv_num; if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) { @@ -545,37 +549,20 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg, goto out; } + if (lv_is_origin(ll->lv)) + lvdl->lvd.lv_access |= LV_SNAPSHOT_ORG; + + if (lv_is_cow(ll->lv)) { + lvdl->lvd.lv_access |= LV_SNAPSHOT; + lvdl->lvd.lv_chunk_size = ll->lv->snapshot->chunk_size; + lvdl->lvd.lv_snapshot_minor = + lvnum_from_lvid(&ll->lv->snapshot->origin->lvid); + } + list_add(&dl->lvds, &lvdl->list); dl->pvd.lv_cur++; } - /* - * Now we need to run through the snapshots, exporting - * the SNAPSHOT_ORG flags etc. - */ - list_iterate(sh, &vg->snapshots) { - struct lv_disk *org, *cow; - struct snapshot *s = list_item(sh, - struct snapshot_list)->snapshot; - - if (!(org = hash_lookup(lvd_hash, s->origin->name))) { - log_err("Couldn't find snapshot origin '%s'.", - s->origin->name); - goto out; - } - - if (!(cow = hash_lookup(lvd_hash, s->cow->name))) { - log_err("Couldn't find snapshot cow store '%s'.", - s->cow->name); - goto out; - } - - org->lv_access |= LV_SNAPSHOT_ORG; - cow->lv_access |= LV_SNAPSHOT; - cow->lv_snapshot_minor = org->lv_number; - cow->lv_chunk_size = s->chunk_size; - } - r = 1; out: @@ -646,7 +633,8 @@ int import_snapshots(struct pool *mem, struct volume_group *vg, continue; /* insert the snapshot */ - if (!vg_add_snapshot(org, cow, NULL, org->le_count, + if (!vg_add_snapshot(vg->fid, NULL, org, cow, NULL, + org->le_count, lvd->lv_chunk_size)) { log_err("Couldn't add snapshot."); return 0; diff --git a/lib/format1/import-extents.c b/lib/format1/import-extents.c index cc644d61e..6ce0d7f53 100644 --- a/lib/format1/import-extents.c +++ b/lib/format1/import-extents.c @@ -60,6 +60,8 @@ static struct hash_table *_create_lv_maps(struct pool *mem, list_iterate(llh, &vg->lvs) { ll = list_item(llh, struct lv_list); + if (ll->lv->status & SNAPSHOT) + continue; if (!(lvm = pool_alloc(mem, sizeof(*lvm)))) { stack; diff --git a/lib/format_pool/format_pool.c b/lib/format_pool/format_pool.c index dc7ff858c..b23df7d83 100644 --- a/lib/format_pool/format_pool.c +++ b/lib/format_pool/format_pool.c @@ -132,7 +132,6 @@ static struct volume_group *_build_vg_from_pds(struct format_instance vg->system_id = NULL; list_init(&vg->pvs); list_init(&vg->lvs); - list_init(&vg->snapshots); list_init(&vg->tags); if (!import_pool_vg(vg, smem, pds)) { diff --git a/lib/format_pool/import_export.c b/lib/format_pool/import_export.c index eddc690a3..52284082c 100644 --- a/lib/format_pool/import_export.c +++ b/lib/format_pool/import_export.c @@ -82,6 +82,8 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls) lv->name = NULL; lv->le_count = 0; lv->read_ahead = 0; + lv->snapshot = NULL; + list_init(&lv->snapshot_segs); list_init(&lv->segments); list_init(&lv->tags); @@ -112,6 +114,8 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls) } else { lv->minor = -1; } + lv->snapshot = NULL; + list_init(&lv->snapshot_segs); list_init(&lv->segments); list_init(&lv->tags); } @@ -288,8 +292,11 @@ int import_pool_segments(struct list *lvs, struct pool *mem, list_iterate(lvhs, lvs) { lvl = list_item(lvhs, struct lv_list); - lv = lvl->lv; + + if (lv->status & SNAPSHOT) + continue; + for (i = 0; i < subpools; i++) { if (usp[i].striping) { if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) { diff --git a/lib/format_text/export.c b/lib/format_text/export.c index fb1c46061..a94cbe0cf 100644 --- a/lib/format_text/export.c +++ b/lib/format_text/export.c @@ -477,87 +477,6 @@ static int _count_segments(struct logical_volume *lv) return r; } -static int _print_snapshot(struct formatter *f, struct snapshot *snap, - unsigned int count) -{ - char buffer[256]; - struct lv_segment seg; - - f->nl(f); - - outf(f, "snapshot%u {", count); - _inc_indent(f); - - if (!id_write_format(&snap->lvid.id[1], buffer, sizeof(buffer))) { - stack; - return 0; - } - - outf(f, "id = \"%s\"", buffer); - - seg.status = LVM_READ | LVM_WRITE | VISIBLE_LV; - if (!print_flags(seg.status, LV_FLAGS, buffer, sizeof(buffer))) { - stack; - return 0; - } - - outf(f, "status = %s", buffer); - outf(f, "segment_count = 1"); - - f->nl(f); - - if (!(seg.segtype = get_segtype_from_string(snap->origin->vg->cmd, - "snapshot"))) { - stack; - return 0; - } - - seg.le = 0; - seg.len = snap->le_count; - seg.origin = snap->origin; - seg.cow = snap->cow; - seg.chunk_size = snap->chunk_size; - - /* FIXME Dummy values */ - list_init(&seg.list); - seg.lv = snap->cow; - seg.stripe_size = 0; - seg.area_count = 0; - seg.area_len = 0; - seg.extents_copied = 0; - - /* Can't tag a snapshot independently of its origin */ - list_init(&seg.tags); - - if (!_print_segment(f, snap->origin->vg, 1, &seg)) { - stack; - return 0; - } - - _dec_indent(f); - outf(f, "}"); - - return 1; -} - -static int _print_snapshots(struct formatter *f, struct volume_group *vg) -{ - struct list *sh; - struct snapshot *s; - unsigned int count = 0; - - list_iterate(sh, &vg->snapshots) { - s = list_item(sh, struct snapshot_list)->snapshot; - - if (!_print_snapshot(f, s, count++)) { - stack; - return 0; - } - } - - return 1; -} - static int _print_lvs(struct formatter *f, struct volume_group *vg) { struct list *lvh; @@ -629,11 +548,6 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg) outf(f, "}"); } - if (!_print_snapshots(f, vg)) { - stack; - return 0; - } - _dec_indent(f); outf(f, "}"); diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c index 282f0c55f..04354c2eb 100644 --- a/lib/format_text/flags.c +++ b/lib/format_text/flags.c @@ -54,6 +54,7 @@ static struct flag _lv_flags[] = { {LOCKED, "LOCKED"}, {MIRRORED, NULL}, {VIRTUAL, NULL}, + {SNAPSHOT, NULL}, {0, NULL} }; diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c index dc8d0e30e..74a88fed3 100644 --- a/lib/format_text/import_vsn1.c +++ b/lib/format_text/import_vsn1.c @@ -508,6 +508,8 @@ static int _read_lvnames(struct format_instance *fid, struct pool *mem, if (!_read_int32(lvn, "read_ahead", &lv->read_ahead)) lv->read_ahead = 0; + lv->snapshot = NULL; + list_init(&lv->snapshot_segs); list_init(&lv->segments); list_init(&lv->tags); @@ -561,24 +563,29 @@ static int _read_lvsegs(struct format_instance *fid, struct pool *mem, lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size; - /* Skip this for now for snapshots */ - if (!(lv->status & SNAPSHOT)) { - lv->minor = -1; - if ((lv->status & FIXED_MINOR) && - !_read_int32(lvn, "minor", &lv->minor)) { - log_error("Couldn't read minor number for logical " - "volume %s.", lv->name); - return 0; - } - lv->major = -1; - if ((lv->status & FIXED_MINOR) && - !_read_int32(lvn, "major", &lv->major)) { - log_error("Couldn't read major number for logical " - "volume %s.", lv->name); - } - } else { + /* + * FIXME We now have 2 LVs for each snapshot. The real one was + * created by vg_add_snapshot from the segment text_import. + */ + if (lv->status & SNAPSHOT) { vg->lv_count--; list_del(&lvl->list); + return 1; + } + + lv->minor = -1; + if ((lv->status & FIXED_MINOR) && + !_read_int32(lvn, "minor", &lv->minor)) { + log_error("Couldn't read minor number for logical " + "volume %s.", lv->name); + return 0; + } + + lv->major = -1; + if ((lv->status & FIXED_MINOR) && + !_read_int32(lvn, "major", &lv->major)) { + log_error("Couldn't read major number for logical " + "volume %s.", lv->name); } return 1; @@ -736,7 +743,6 @@ static struct volume_group *_read_vg(struct format_instance *fid, } list_init(&vg->lvs); - list_init(&vg->snapshots); list_init(&vg->tags); /* Optional tags */ diff --git a/lib/metadata/lv_alloc.h b/lib/metadata/lv_alloc.h index 087e4feb7..2fa62e0b9 100644 --- a/lib/metadata/lv_alloc.h +++ b/lib/metadata/lv_alloc.h @@ -17,4 +17,7 @@ #include "pool.h" struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas); +struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv, + uint32_t allocated); + #endif diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 57e7485be..ce6dbffcd 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -440,6 +440,34 @@ static int _alloc_virtual(struct logical_volume *lv, return 1; } +struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv, + uint32_t allocated) +{ + struct lv_segment *seg; + + if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 0))) { + log_err("Couldn't allocate new zero segment."); + return NULL; + } + + seg->lv = lv; + seg->segtype = get_segtype_from_string(lv->vg->cmd, "snapshot"); + if (!seg->segtype) { + log_error("Failed to find snapshot segtype"); + return NULL; + } + seg->status = 0u; + seg->le = allocated; + seg->len = lv->le_count - allocated; + seg->area_len = seg->len; + seg->stripe_size = 0; + seg->extents_copied = 0u; + list_add(&lv->segments, &seg->list); + lv->status |= VIRTUAL; + + return seg; +} + /* * Chooses a correct allocation policy. */ @@ -546,6 +574,7 @@ struct logical_volume *lv_create_empty(struct format_instance *fi, union lvid *lvid, uint32_t status, alloc_policy_t alloc, + int import, struct volume_group *vg) { struct cmd_context *cmd = vg->cmd; @@ -566,7 +595,8 @@ struct logical_volume *lv_create_empty(struct format_instance *fi, return NULL; } - log_verbose("Creating logical volume %s", name); + if (!import) + log_verbose("Creating logical volume %s", name); if (!(ll = pool_zalloc(cmd->mem, sizeof(*ll))) || !(ll->lv = pool_zalloc(cmd->mem, sizeof(*ll->lv)))) { @@ -593,6 +623,8 @@ struct logical_volume *lv_create_empty(struct format_instance *fi, lv->minor = -1; lv->size = UINT64_C(0); lv->le_count = 0; + lv->snapshot = NULL; + list_init(&lv->snapshot_segs); list_init(&lv->segments); list_init(&lv->tags); @@ -606,7 +638,9 @@ struct logical_volume *lv_create_empty(struct format_instance *fi, return NULL; } - vg->lv_count++; + if (!import) + vg->lv_count++; + list_add(&vg->lvs, &ll->list); return lv; diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 2af54c07b..03e77b123 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -221,7 +221,6 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name, list_init(&vg->lvs); vg->snapshot_count = 0; - list_init(&vg->snapshots); list_init(&vg->tags); @@ -617,7 +616,6 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd) } list_init(&vg->pvs); list_init(&vg->lvs); - list_init(&vg->snapshots); list_init(&vg->tags); vg->cmd = cmd; if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) { diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index dd39f5561..66ecd9f86 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -50,7 +50,7 @@ #define VISIBLE_LV 0x00000040 /* LV */ #define FIXED_MINOR 0x00000080 /* LV */ /* FIXME Remove when metadata restructuring is completed */ -#define SNAPSHOT 0x00001000 /* LV - tmp internal use only */ +#define SNAPSHOT 0x00001000 /* LV - internal use only */ #define PVMOVE 0x00002000 /* VG LV SEG */ #define LOCKED 0x00004000 /* LV */ #define MIRRORED 0x00008000 /* LV - internal use only */ @@ -191,11 +191,8 @@ struct volume_group { /* logical volumes */ uint32_t lv_count; - struct list lvs; - - /* snapshots */ uint32_t snapshot_count; - struct list snapshots; + struct list lvs; struct list tags; }; @@ -217,7 +214,8 @@ struct lv_segment { uint32_t area_len; struct logical_volume *origin; struct logical_volume *cow; - uint32_t chunk_size; + struct list origin_list; + uint32_t chunk_size; /* In sectors */ uint32_t extents_copied; struct list tags; @@ -253,20 +251,14 @@ struct logical_volume { uint64_t size; uint32_t le_count; + uint32_t origin_count; + struct list snapshot_segs; + struct lv_segment *snapshot; + struct list segments; struct list tags; }; -struct snapshot { - union lvid lvid; - - uint32_t chunk_size; /* in 512 byte sectors */ - uint32_t le_count; - - struct logical_volume *origin; - struct logical_volume *cow; -}; - struct name_list { struct list list; char *name; @@ -290,12 +282,6 @@ struct lv_list { struct logical_volume *lv; }; -struct snapshot_list { - struct list list; - - struct snapshot *snapshot; -}; - struct mda_list { struct list list; struct device_area mda; @@ -424,6 +410,7 @@ struct logical_volume *lv_create_empty(struct format_instance *fi, union lvid *lvid, uint32_t status, alloc_policy_t alloc, + int import, struct volume_group *vg); int lv_reduce(struct format_instance *fi, @@ -503,11 +490,10 @@ int lv_is_cow(const struct logical_volume *lv); int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv); -struct snapshot *find_cow(const struct logical_volume *lv); -struct snapshot *find_origin(const struct logical_volume *lv); -struct list *find_snapshots(const struct logical_volume *lv); +struct lv_segment *find_cow(const struct logical_volume *lv); -int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow, +int vg_add_snapshot(struct format_instance *fid, const char *name, + struct logical_volume *origin, struct logical_volume *cow, union lvid *lvid, uint32_t extent_count, uint32_t chunk_size); diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c index cd9ebfbae..32bfb2cfd 100644 --- a/lib/metadata/snapshot_manip.c +++ b/lib/metadata/snapshot_manip.c @@ -16,101 +16,31 @@ #include "lib.h" #include "metadata.h" #include "toolcontext.h" +#include "lv_alloc.h" int lv_is_origin(const struct logical_volume *lv) { - struct list *slh; - struct snapshot *s; - - list_iterate(slh, &lv->vg->snapshots) { - s = list_item(slh, struct snapshot_list)->snapshot; - if (s->origin == lv) - return 1; - } - - return 0; + return lv->origin_count ? 1 : 0; } int lv_is_cow(const struct logical_volume *lv) { - struct list *slh; - struct snapshot *s; - - list_iterate(slh, &lv->vg->snapshots) { - s = list_item(slh, struct snapshot_list)->snapshot; - if (s->cow == lv) - return 1; - } - - return 0; + return lv->snapshot ? 1 : 0; } -struct snapshot *find_origin(const struct logical_volume *lv) +/* Given a cow LV, return the snapshot lv_segment that uses it */ +struct lv_segment *find_cow(const struct logical_volume *lv) { - struct list *slh; - struct snapshot *s; - - list_iterate(slh, &lv->vg->snapshots) { - s = list_item(slh, struct snapshot_list)->snapshot; - if (s->origin == lv) - return s; - } - - return NULL; + return lv->snapshot; } -struct snapshot *find_cow(const struct logical_volume *lv) +int vg_add_snapshot(struct format_instance *fid, const char *name, + struct logical_volume *origin, + struct logical_volume *cow, union lvid *lvid, + uint32_t extent_count, uint32_t chunk_size) { - struct list *slh; - struct snapshot *s; - - list_iterate(slh, &lv->vg->snapshots) { - s = list_item(slh, struct snapshot_list)->snapshot; - if (s->cow == lv) - return s; - } - - return NULL; -} - -struct list *find_snapshots(const struct logical_volume *lv) -{ - struct list *slh; - struct list *snaplist; - struct snapshot *s; - struct snapshot_list *newsl; - struct pool *mem = lv->vg->cmd->mem; - - if (!(snaplist = pool_alloc(mem, sizeof(*snaplist)))) { - log_error("snapshot name list allocation failed"); - return NULL; - } - - list_init(snaplist); - - list_iterate(slh, &lv->vg->snapshots) { - s = list_item(slh, struct snapshot_list)->snapshot; - if (!(s->origin == lv)) - continue; - if (!(newsl = pool_alloc(mem, sizeof(*newsl)))) { - log_error("snapshot_list structure allocation failed"); - pool_free(mem, snaplist); - return NULL; - } - newsl->snapshot = s; - list_add(snaplist, &newsl->list); - } - - return snaplist; -} - -int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow, - union lvid *lvid, uint32_t extent_count, - uint32_t chunk_size) -{ - struct snapshot *s; - struct snapshot_list *sl; - struct pool *mem = origin->vg->cmd->mem; + struct logical_volume *snap; + struct lv_segment *seg; /* * Is the cow device already being used ? @@ -120,54 +50,53 @@ int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow, return 0; } - if (!(s = pool_alloc(mem, sizeof(*s)))) { + if (!(snap = lv_create_empty(fid, name, name ? NULL : "snapshot%d", + lvid, LVM_READ | LVM_WRITE | VISIBLE_LV, + ALLOC_INHERIT, 1, origin->vg))) { stack; return 0; } - s->chunk_size = chunk_size; - s->le_count = extent_count; - s->origin = origin; - s->cow = cow; + snap->le_count = extent_count; - if (lvid) - s->lvid = *lvid; - else if (!lvid_create(&s->lvid, &origin->vg->id)) { - log_error("Random UUID creation failed for snapshot %s.", - cow->name); - return 0; - } - - if (!(sl = pool_alloc(mem, sizeof(*sl)))) { + if (!(seg = alloc_snapshot_seg(snap, 0))) { stack; - pool_free(mem, s); return 0; } + seg->chunk_size = chunk_size; + seg->origin = origin; + seg->cow = cow; + seg->lv->status |= SNAPSHOT; + + origin->origin_count++; + origin->vg->snapshot_count++; + origin->vg->lv_count--; + cow->snapshot = seg; + cow->status &= ~VISIBLE_LV; - sl->snapshot = s; - list_add(&origin->vg->snapshots, &sl->list); - origin->vg->snapshot_count++; + + list_add(&origin->snapshot_segs, &seg->origin_list); return 1; } int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow) { - struct list *slh; - struct snapshot_list *sl; + list_del(&cow->snapshot->origin_list); + cow->snapshot->origin->origin_count--; - list_iterate(slh, &vg->snapshots) { - sl = list_item(slh, struct snapshot_list); - - if (sl->snapshot->cow == cow) { - list_del(slh); - vg->snapshot_count--; - return 1; - } + if (!lv_remove(vg, cow->snapshot->lv)) { + log_error("Failed to remove internal snapshot LV %s", + cow->snapshot->lv->name); + return 0; } - /* fail */ - log_err("Asked to remove an unknown snapshot."); - return 0; + cow->snapshot = NULL; + + vg->snapshot_count--; + vg->lv_count++; + cow->status |= VISIBLE_LV; + + return 1; } diff --git a/lib/report/report.c b/lib/report/report.c index af5068289..f6e0de329 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -324,7 +324,7 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field, const struct logical_volume *lv = (const struct logical_volume *) data; struct lvinfo info; char *repstr; - struct snapshot *snap; + struct lv_segment *snap_seg; float snap_percent; if (!(repstr = pool_zalloc(rh->mem, 7))) { @@ -373,8 +373,8 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field, repstr[5] = '-'; /* Snapshot dropped? */ - if ((snap = find_cow(lv)) && - (!lv_snapshot_percent(snap->cow, &snap_percent) || + if ((snap_seg = find_cow(lv)) && + (!lv_snapshot_percent(snap_seg->cow, &snap_percent) || snap_percent < 0 || snap_percent >= 100)) { repstr[0] = toupper(repstr[0]); if (info.suspended) @@ -478,10 +478,10 @@ static int _origin_disp(struct report_handle *rh, struct field *field, const void *data) { const struct logical_volume *lv = (const struct logical_volume *) data; - struct snapshot *snap; + struct lv_segment *snap_seg; - if ((snap = find_cow(lv))) - return _string_disp(rh, field, &snap->origin->name); + if ((snap_seg = find_cow(lv))) + return _string_disp(rh, field, &snap_seg->origin->name); field->report_string = ""; field->sort_value = (const void *) field->report_string; @@ -762,7 +762,7 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field, const void *data) { const struct logical_volume *lv = (const struct logical_volume *) data; - struct snapshot *snap; + struct lv_segment *snap_seg; struct lvinfo info; float snap_percent; uint64_t *sortval; @@ -773,15 +773,16 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field, return 0; } - if (!(snap = find_cow(lv)) || - (lv_info(snap->cow, &info, 0) && !info.exists)) { + if (!(snap_seg = find_cow(lv)) || + (lv_info(snap_seg->cow, &info, 0) && !info.exists)) { field->report_string = ""; *sortval = UINT64_C(0); field->sort_value = sortval; return 1; } - if (!lv_snapshot_percent(snap->cow, &snap_percent) || snap_percent < 0) { + if (!lv_snapshot_percent(snap_seg->cow, &snap_percent) + || snap_percent < 0) { field->report_string = "100.00"; *sortval = UINT64_C(100); field->sort_value = sortval; diff --git a/lib/snapshot/snapshot.c b/lib/snapshot/snapshot.c index 65b73c10f..cbfbe6084 100644 --- a/lib/snapshot/snapshot.c +++ b/lib/snapshot/snapshot.c @@ -70,8 +70,8 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn, return 0; } - if (!vg_add_snapshot(org, cow, &seg->lv->lvid, seg->len, - chunk_size)) { + if (!vg_add_snapshot(seg->lv->vg->fid, seg->lv->name, org, cow, + &seg->lv->lvid, seg->len, chunk_size)) { stack; return 0; } diff --git a/tools/lvcreate.c b/tools/lvcreate.c index b5ac6d20c..90b3fd9bb 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -513,7 +513,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) } if (!(lv = lv_create_empty(vg->fid, lp->lv_name, "lvol%d", NULL, - status, lp->alloc, vg))) { + status, lp->alloc, 0, vg))) { stack; return 0; } @@ -609,8 +609,8 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) return 0; } - if (!vg_add_snapshot(org, lv, NULL, org->le_count, - lp->chunk_size)) { + if (!vg_add_snapshot(vg->fid, NULL, org, lv, NULL, + org->le_count, lp->chunk_size)) { log_err("Couldn't create snapshot."); return 0; } diff --git a/tools/lvresize.c b/tools/lvresize.c index c788c988e..80b3ba801 100644 --- a/tools/lvresize.c +++ b/tools/lvresize.c @@ -115,7 +115,7 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp) { struct volume_group *vg; struct logical_volume *lv; - struct snapshot *snap; + struct lv_segment *snap_seg; struct lvinfo info; uint32_t stripesize_extents = 0; uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0; @@ -472,8 +472,8 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp) backup(vg); /* If snapshot, must suspend all associated devices */ - if ((snap = find_cow(lv))) - lock_lvid = snap->origin->lvid.s; + if ((snap_seg = find_cow(lv))) + lock_lvid = snap_seg->origin->lvid.s; else lock_lvid = lv->lvid.s; diff --git a/tools/pvmove.c b/tools/pvmove.c index 0727301a4..0fc689332 100644 --- a/tools/pvmove.c +++ b/tools/pvmove.c @@ -143,7 +143,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, /* FIXME Pass 'alloc' down to lv_extend */ if (!(lv_mirr = lv_create_empty(vg->fid, NULL, "pvmove%d", NULL, LVM_READ | LVM_WRITE, - ALLOC_CONTIGUOUS, vg))) { + ALLOC_CONTIGUOUS, 0, vg))) { log_error("Creation of temporary pvmove LV failed"); return NULL; } @@ -160,7 +160,8 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, /* Find segments to be moved and set up mirrors */ list_iterate_items(lvl, &vg->lvs) { lv = lvl->lv; - if ((lv == lv_mirr) || (lv_name && strcmp(lv->name, lv_name))) + if ((lv == lv_mirr) || + (lv_name && strcmp(lv->name, lv_name))) continue; if (lv_is_origin(lv) || lv_is_cow(lv)) { log_print("Skipping snapshot-related LV %s", lv->name); diff --git a/tools/toollib.c b/tools/toollib.c index d2d174745..8fb2dbef8 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -60,6 +60,9 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, } list_iterate_items(lvl, &vg->lvs) { + if (lvl->lv->status & SNAPSHOT) + continue; + /* Should we process this LV? */ if (process_all) process_lv = 1; diff --git a/tools/vgchange.c b/tools/vgchange.c index d1d21c256..2b7c36e3d 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -27,7 +27,7 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd, lv = lvl->lv; /* Only request activation of snapshot origin devices */ - if (lv_is_cow(lv)) + if ((lv->status & SNAPSHOT) || lv_is_cow(lv)) continue; /* Can't deactive a pvmove LV */ diff --git a/tools/vgconvert.c b/tools/vgconvert.c index d55bb406f..e50aac242 100644 --- a/tools/vgconvert.c +++ b/tools/vgconvert.c @@ -92,6 +92,8 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name, if (cmd->fmt->features & FMT_RESTRICTED_LVIDS) { list_iterate_items(lvl, &vg->lvs) { lv = lvl->lv; + if (lv->status & SNAPSHOT) + continue; if (lvnum_from_lvid(&lv->lvid) < MAX_RESTRICTED_LVS) continue; if (lv_info(lv, &info, 0) && info.exists) { diff --git a/tools/vgreduce.c b/tools/vgreduce.c index ceb49db5d..80de5525c 100644 --- a/tools/vgreduce.c +++ b/tools/vgreduce.c @@ -49,9 +49,9 @@ static int _remove_pv(struct volume_group *vg, struct pv_list *pvl) static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv, int *list_unsafe) { - struct snapshot *snap; - struct snapshot_list *snl; - struct list *snaplist; + struct lv_segment *snap_seg; + struct list *snh, *snht; + struct logical_volume *cow; log_verbose("%s/%s has missing extents: removing (including " "dependencies)", lv->vg->name, lv->name); @@ -65,36 +65,34 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv, log_error("Failed to deactivate LV %s", lv->name); return 0; } - } else if ((snap = find_cow(lv))) { + } else if ((snap_seg = find_cow(lv))) { log_verbose("Deactivating (if active) logical volume %s " - "(origin of %s)", snap->origin->name, lv->name); + "(origin of %s)", snap_seg->origin->name, lv->name); - if (!deactivate_lv(cmd, snap->origin->lvid.s)) { + if (!deactivate_lv(cmd, snap_seg->origin->lvid.s)) { log_error("Failed to deactivate LV %s", - snap->origin->name); + snap_seg->origin->name); return 0; } /* Use the origin LV */ - lv = snap->origin; + lv = snap_seg->origin; } /* Remove snapshot dependencies */ - if (!(snaplist = find_snapshots(lv))) { - stack; - return 0; - } - /* List may be empty */ - list_iterate_items(snl, snaplist) { + list_iterate_safe(snh, snht, &lv->snapshot_segs) { + snap_seg = list_struct_base(snh, struct lv_segment, + origin_list); + cow = snap_seg->cow; + *list_unsafe = 1; /* May remove caller's lvht! */ - snap = snl->snapshot; - if (!vg_remove_snapshot(lv->vg, snap->cow)) { + if (!vg_remove_snapshot(lv->vg, cow)) { stack; return 0; } - log_verbose("Removing LV %s from VG %s", snap->cow->name, + log_verbose("Removing LV %s from VG %s", cow->name, lv->vg->name); - if (!lv_remove(lv->vg, snap->cow)) { + if (!lv_remove(lv->vg, cow)) { stack; return 0; } diff --git a/tools/vgsplit.c b/tools/vgsplit.c index 2ff4e93dd..741075c1f 100644 --- a/tools/vgsplit.c +++ b/tools/vgsplit.c @@ -44,6 +44,19 @@ static int _move_pv(struct volume_group *vg_from, struct volume_group *vg_to, return 1; } +/* FIXME Why not (lv->vg == vg) ? */ +static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv) +{ + struct lv_list *lvl; + + list_iterate_items(lvl, &vg->lvs) + if (lv == lvl->lv) + return 1; + + return 0; +} + + static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) { struct list *lvh, *lvht; @@ -56,6 +69,9 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) list_iterate_safe(lvh, lvht, &vg_from->lvs) { lv = list_item(lvh, struct lv_list)->lv; + if ((lv->status & SNAPSHOT)) + continue; + /* Ensure all the PVs used by this LV remain in the same */ /* VG as each other */ vg_with = NULL; @@ -89,8 +105,9 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) dev_name(pv->dev)); return 0; } - } + } + if (vg_with == vg_from) continue; @@ -107,39 +124,38 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) return 1; } -static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv) -{ - struct lv_list *lvl; - - list_iterate_items(lvl, &vg->lvs) - if (lv == lvl->lv) - return 1; - - return 0; -} - static int _move_snapshots(struct volume_group *vg_from, struct volume_group *vg_to) { - struct list *slh, *slth; - struct snapshot *snap; - int cow_from, origin_from; + struct list *lvh, *lvht; + struct logical_volume *lv; + struct lv_segment *seg; + int cow_from = 0; + int origin_from = 0; - list_iterate_safe(slh, slth, &vg_from->snapshots) { - snap = list_item(slh, struct snapshot_list)->snapshot; - cow_from = _lv_is_in_vg(vg_from, snap->cow); - origin_from = _lv_is_in_vg(vg_from, snap->origin); - if (cow_from && origin_from) - return 1; - if ((!cow_from && origin_from) || (cow_from && !origin_from)) { - log_error("Snapshot %s split", snap->cow->name); - return 0; + list_iterate_safe(lvh, lvht, &vg_from->lvs) { + lv = list_item(lvh, struct lv_list)->lv; + + if (!(lv->status & SNAPSHOT)) + continue; + + list_iterate_items(seg, &lv->segments) { + cow_from = _lv_is_in_vg(vg_from, seg->cow); + origin_from = _lv_is_in_vg(vg_from, seg->origin); } + if (cow_from && origin_from) + continue; + if ((!cow_from && origin_from) || (cow_from && !origin_from)) { + log_error("Snapshot %s split", seg->cow->name); + return 0; + } + + /* Move this snapshot */ + list_del(lvh); + list_add(&vg_to->lvs, lvh); + vg_from->snapshot_count--; vg_to->snapshot_count++; - - list_del(slh); - list_add(&vg_to->snapshots, slh); } return 1;