diff --git a/lib/format1/disk-rep.h b/lib/format1/disk-rep.h index 7db71d7fe..63390708d 100644 --- a/lib/format1/disk-rep.h +++ b/lib/format1/disk-rep.h @@ -230,6 +230,9 @@ int import_lvs(struct pool *mem, struct volume_group *vg, int export_lvs(struct disk_list *dl, struct volume_group *vg, struct physical_volume *pv, const char *dev_dir); +int import_snapshots(struct pool *mem, struct volume_group *vg, + struct list *pvds); + int export_uuids(struct disk_list *dl, struct volume_group *vg); void export_numbers(struct list *pvds, struct volume_group *vg); diff --git a/lib/format1/format1.c b/lib/format1/format1.c index 1b8de6441..f7c9ce5cd 100644 --- a/lib/format1/format1.c +++ b/lib/format1/format1.c @@ -82,8 +82,10 @@ static int _check_vgs(struct list *pvs, int *partial) return 1; } -static struct volume_group *_build_vg(struct pool *mem, struct list *pvs) +static struct volume_group *_build_vg(struct cmd_context *cmd, + struct list *pvs) { + struct pool *mem = cmd->mem; struct volume_group *vg = pool_alloc(mem, sizeof(*vg)); struct disk_list *dl; int partial; @@ -96,8 +98,10 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs) memset(vg, 0, sizeof(*vg)); + vg->cmd = cmd; list_init(&vg->pvs); list_init(&vg->lvs); + list_init(&vg->snapshots); if (!_check_vgs(pvs, &partial)) goto bad; @@ -116,6 +120,9 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs) if (!import_extents(mem, vg, pvs)) goto bad; + if (!import_snapshots(mem, vg, pvs)) + goto bad; + return vg; bad: @@ -145,13 +152,11 @@ static struct volume_group *_vg_read(struct format_instance *fi, goto bad; } - if (!(vg = _build_vg(fi->cmd->mem, &pvs))) { + if (!(vg = _build_vg(fi->cmd, &pvs))) { stack; goto bad; } - vg->cmd = fi->cmd; - bad: pool_destroy(mem); return vg; diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c index 4e049cbce..d58f3c0e3 100644 --- a/lib/format1/import-export.c +++ b/lib/format1/import-export.c @@ -293,12 +293,6 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd) if (lvd->lv_access & LV_WRITE) lv->status |= LVM_WRITE; - if (lvd->lv_access & LV_SNAPSHOT) - lv->status |= SNAPSHOT; - - if (lvd->lv_access & LV_SNAPSHOT_ORG) - lv->status |= SNAPSHOT_ORG; - if (lvd->lv_badblock) lv->status |= BADBLOCK_ON; @@ -336,12 +330,6 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg, if (lv->status & LVM_WRITE) lvd->lv_access |= LV_WRITE; - if (lv->status & SNAPSHOT) - lvd->lv_access |= LV_SNAPSHOT; - - if (lv->status & SNAPSHOT_ORG) - lvd->lv_access |= LV_SNAPSHOT_ORG; - if (lv->status & SPINDOWN_LV) lvd->lv_status |= LV_SPINDOWN; @@ -478,13 +466,21 @@ int import_lvs(struct pool *mem, struct volume_group *vg, return 1; } +/* FIXME: tidy */ int export_lvs(struct disk_list *dl, struct volume_group *vg, struct physical_volume *pv, const char *dev_dir) { - struct list *lvh; + int r = 0; + struct list *lvh, *sh; struct lv_list *ll; struct lvd_list *lvdl; int lv_num = 0, len; + struct hash_table *lvd_hash; + + if (!(lvd_hash = hash_create(32))) { + stack; + return 0; + } /* * setup the pv's extents array @@ -492,32 +488,146 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg, len = sizeof(struct pe_disk) * dl->pvd.pe_total; if (!(dl->extents = pool_alloc(dl->mem, len))) { stack; - return 0; + goto out; } memset(dl->extents, 0, len); - - list_iterate(lvh, &vg->lvs) { + list_iterate (lvh, &vg->lvs) { ll = list_item(lvh, struct lv_list); if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) { stack; - return 0; + goto out; } export_lv(&lvdl->lvd, vg, ll->lv, dev_dir); + + /* this isn't a real dev, more of an index for + * snapshots to refer to, *HACK* */ + lvdl->lvd.lv_dev = MKDEV(0, lv_num); lvdl->lvd.lv_number = lv_num; + + if (!hash_insert(lvd_hash, lvdl->lvd.lv_name, &lvdl->lvd)) { + stack; + goto out; + } + if (!export_extents(dl, lv_num + 1, ll->lv, pv)) { stack; - return 0; + goto out; } list_add(&dl->lvds, &lvdl->list); dl->pvd.lv_cur++; lv_num++; } + + /* + * 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))) { + stack; + goto out; + } + + if (!(cow = hash_lookup(lvd_hash, s->cow->name))) { + stack; + goto out; + } + + org->lv_access |= LV_SNAPSHOT_ORG; + cow->lv_access |= LV_SNAPSHOT; + cow->lv_snapshot_minor = MINOR(org->lv_dev); + } + + r = 1; + + out: + hash_destroy(lvd_hash); + return r; +} + +/* + * FIXME: More inefficient code. + */ +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 lv_disk *lvd; + int minor; + struct logical_volume *org, *cow; + + /* build an array of minor->lv* */ + 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); + + minor = MINOR(lvd->lv_dev); + + if (minor > MAX_LV) { + log_err("Logical volume minor number " + "out of bounds."); + return 0; + } + + if (!lvs[minor] && + !(lvs[minor] = find_lv(vg, lvd->lv_name))) { + log_err("Couldn't find logical volume '%s'.", + lvd->lv_name); + return 0; + } + } + } + + /* + * 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); + + if (!(lvd->lv_status & LV_SNAPSHOT)) + continue; + + minor = MINOR(lvd->lv_dev); + cow = lvs[minor]; + if (!(org = lvs[lvd->lv_snapshot_minor])) { + log_err("Couldn't find origin logical volume " + "for snapshot '%s'.", lvd->lv_name); + return 0; + } + + /* we may have already added this snapshot */ + if (lv_is_cow(vg, cow)) + continue; + + /* insert the snapshot */ + if (!vg_add_snapshot(vg, org, cow, 1, + lvd->lv_chunk_size)) { + log_err("Couldn't add snapshot."); + return 0; + } + } + } + return 1; } + + int export_uuids(struct disk_list *dl, struct volume_group *vg) { struct uuid_list *ul; diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c index b31491d35..7956a3439 100644 --- a/lib/format_text/flags.c +++ b/lib/format_text/flags.c @@ -41,8 +41,6 @@ static struct flag _lv_flags[] = { {ALLOC_SIMPLE, "ALLOC_SIMPLE"}, {ALLOC_STRICT, "ALLOC_STRICT"}, {ALLOC_CONTIGUOUS, "ALLOC_CONTIGUOUS"}, - {SNAPSHOT, "SNASHOT"}, - {SNAPSHOT_ORG, "SNAPSHOT_ORIGIN"}, {FIXED_MINOR, "FIXED_MINOR"}, {0, NULL} }; diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index 45f46ab88..8cf6cd04e 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -50,9 +50,6 @@ #define ALLOC_STRICT 0x00002000 /* LV */ #define ALLOC_CONTIGUOUS 0x00004000 /* LV */ -#define SNAPSHOT 0x00010000 /* LV */ -#define SNAPSHOT_ORG 0x00020000 /* LV */ - struct physical_volume { struct id id; diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c index ab681c156..42a29c997 100644 --- a/lib/metadata/snapshot_manip.c +++ b/lib/metadata/snapshot_manip.c @@ -91,6 +91,6 @@ int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow) } /* fail */ - log_err("Asked to remove an unknow snapshot."); + log_err("Asked to remove an unknown snapshot."); return 0; } diff --git a/tools/lvchange.c b/tools/lvchange.c index bc688dbb1..7a5a1b349 100644 --- a/tools/lvchange.c +++ b/tools/lvchange.c @@ -67,13 +67,13 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv) return EINVALID_CMD_LINE; } - if (lv->status & SNAPSHOT_ORG) { + if (lv_is_origin(lv->vg, lv)) { log_error("Can't change logical volume \"%s\" under snapshot", lv->name); return ECMD_FAILED; } - if (lv->status & SNAPSHOT) { + if (lv_is_cow(lv->vg, lv)) { log_error("Can't change snapshot logical volume \"%s\"", lv->name); return ECMD_FAILED; diff --git a/tools/lvremove.c b/tools/lvremove.c index 718d9b1d6..5569e7835 100644 --- a/tools/lvremove.c +++ b/tools/lvremove.c @@ -44,7 +44,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv) return ECMD_FAILED; } - if (lv->status & SNAPSHOT_ORG) { + if (lv_is_origin(lv->vg, lv)) { log_error("Can't remove logical volume \"%s\" under snapshot", lv->name); return ECMD_FAILED; diff --git a/tools/lvscan.c b/tools/lvscan.c index 953303a0b..0cd47d9f9 100644 --- a/tools/lvscan.c +++ b/tools/lvscan.c @@ -70,9 +70,9 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv) } else active_str = "inactive "; - if (lv->status & SNAPSHOT_ORG) + if (lv_is_origin(lv->vg, lv)) snapshot_str = "Original"; - else if (lv->status & SNAPSHOT) + else if (lv_is_cow(lv->vg, lv)) snapshot_str = "Snapshot"; else snapshot_str = " ";