From 7d68b080284df8fadaa3197e6e0fc9f9668bc684 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 12 Feb 2002 16:31:31 +0000 Subject: [PATCH] o First changes to add snapshot support. I'm taking a different route from LVM1 here in that snapshots are a seperate entity from the logical volumes, I think of them as an application of an LV (or two lvs rather). As such there is a list of snapshots held against the vg, and there is *not* a SNAPSHOT, or SHAPSHOT_ORG flag in lv->status. --- lib/Makefile.in | 3 +- lib/format1/disk-rep.h | 2 +- lib/format1/format1.c | 2 +- lib/format1/import-export.c | 16 +++--- lib/metadata/metadata.h | 33 ++++++++++++ lib/metadata/snapshot_manip.c | 96 +++++++++++++++++++++++++++++++++++ 6 files changed, 141 insertions(+), 11 deletions(-) create mode 100644 lib/metadata/snapshot_manip.c diff --git a/lib/Makefile.in b/lib/Makefile.in index c35c2a72a..109d29b84 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -40,13 +40,14 @@ SOURCES=\ format_text/import.c \ label/label.c \ label/uuid-map.c \ - locking/locking.c \ locking/file_locking.c \ + locking/locking.c \ log/log.c \ metadata/lv_manip.c \ metadata/merge.c \ metadata/metadata.c \ metadata/pv_map.c \ + metadata/snapshot_manip.c \ misc/lvm-file.c \ mm/dbg_malloc.c \ mm/pool.c \ diff --git a/lib/format1/disk-rep.h b/lib/format1/disk-rep.h index fa42d7716..7db71d7fe 100644 --- a/lib/format1/disk-rep.h +++ b/lib/format1/disk-rep.h @@ -216,7 +216,7 @@ int import_lv(struct pool *mem, struct logical_volume *lv, void export_lv(struct lv_disk *lvd, struct volume_group *vg, struct logical_volume *lv, const char *dev_dir); -int import_extents(struct pool *mem, struct volume_group *vg, +int import_extents(struct pool *mem, struct volume_group *vg, struct list *pvds); int export_extents(struct disk_list *dl, int lv_num, struct logical_volume *lv, diff --git a/lib/format1/format1.c b/lib/format1/format1.c index 1cfe297d3..1b8de6441 100644 --- a/lib/format1/format1.c +++ b/lib/format1/format1.c @@ -29,7 +29,7 @@ static int _check_vgs(struct list *pvs, int *partial) * If there are exported and unexported PVs, ignore exported ones. * 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); diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c index 8cec06fb1..4e049cbce 100644 --- a/lib/format1/import-export.c +++ b/lib/format1/import-export.c @@ -58,10 +58,10 @@ int import_pv(struct pool *mem, struct device *dev, if (vg && strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id))) log_very_verbose("System ID %s on %s differs from %s for " - "volume group", pvd->system_id, + "volume group", pvd->system_id, dev_name(pv->dev), vg->system_id); - - /* + + /* * If exported, we still need to flag in pv->status too because * we don't always have a struct volume_group when we need this. */ @@ -89,7 +89,7 @@ int _system_id(char *s, const char *prefix) return 0; } - if (lvm_snprintf(s, NAME_LEN, "%s%s%lu", + if (lvm_snprintf(s, NAME_LEN, "%s%s%lu", prefix, uts.nodename, time(NULL)) < 0) { log_error("Generated system_id too long"); return 0; @@ -120,14 +120,14 @@ int export_pv(struct pool *mem, struct volume_group *vg, strncpy(pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name)); /* Preserve existing system_id if it exists */ - if (vg && *vg->system_id) + if (vg && *vg->system_id) strncpy(pvd->system_id, vg->system_id, sizeof(pvd->system_id)); /* Is VG already exported or being exported? */ if (vg && (vg->status & EXPORTED_VG)) { /* Does system_id need setting? */ - if (!*vg->system_id || - strncmp(vg->system_id, EXPORTED_TAG, + if (!*vg->system_id || + strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) { if (!_system_id(pvd->system_id, EXPORTED_TAG)) { stack; @@ -160,7 +160,7 @@ int export_pv(struct pool *mem, struct volume_group *vg, } /* Update internal system_id if we changed it */ - if (vg && + if (vg && (!*vg->system_id || strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id)))) strncpy(vg->system_id, pvd->system_id, NAME_LEN); diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index e650863b8..45f46ab88 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -94,6 +94,10 @@ struct volume_group { /* logical volumes */ uint32_t lv_count; struct list lvs; + + /* snapshots */ + uint32_t snapshot_count; + struct list snapshots; }; struct stripe_segment { @@ -128,6 +132,14 @@ struct logical_volume { struct list segments; }; +struct snapshot { + int persistent; /* boolean */ + uint32_t chunk_size; /* in 512 byte sectors */ + + struct logical_volume *origin; + struct logical_volume *cow; +}; + struct name_list { struct list list; char *name; @@ -143,6 +155,12 @@ struct lv_list { struct logical_volume *lv; }; +struct snapshot_list { + struct list list; + + struct snapshot *snapshot; +}; + struct format_instance { struct cmd_context *cmd; struct format_handler *ops; @@ -315,4 +333,19 @@ int lv_check_segments(struct logical_volume *lv); int lv_merge_segments(struct logical_volume *lv); +/* + * Useful functions for managing snapshots. + */ +int lv_is_origin(struct volume_group *vg, struct logical_volume *lv); +int lv_is_cow(struct volume_group *vg, struct logical_volume *lv); + +int vg_add_snapshot(struct volume_group *vg, + struct logical_volume *origin, + struct logical_volume *cow, + int persistent, + uint32_t chunk_size); + +int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow); + + #endif diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c new file mode 100644 index 000000000..ab681c156 --- /dev/null +++ b/lib/metadata/snapshot_manip.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2002 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. + */ + +#include "log.h" +#include "metadata.h" +#include "toolcontext.h" + +int lv_is_origin(struct volume_group *vg, struct logical_volume *lv) +{ + struct list *slh; + struct snapshot *s; + + list_iterate (slh, &vg->snapshots) { + s = list_item(slh, struct snapshot_list)->snapshot; + if (s->origin == lv) + return 1; + } + + return 0; +} + +int lv_is_cow(struct volume_group *vg, struct logical_volume *lv) +{ + struct list *slh; + struct snapshot *s; + + list_iterate (slh, &vg->snapshots) { + s = list_item(slh, struct snapshot_list)->snapshot; + if (s->cow == lv) + return 1; + } + + return 0; +} + +int vg_add_snapshot(struct volume_group *vg, + struct logical_volume *origin, + struct logical_volume *cow, + int persistent, + uint32_t chunk_size) +{ + struct snapshot *s; + struct snapshot_list *sl; + struct pool *mem = vg->cmd->mem; + + /* + * Is the cow device already being used ? + */ + if (lv_is_cow(vg, cow)) { + log_err("'%s' is already in use as a snapshot.", cow->name); + return 0; + } + + if (!(s = pool_alloc(mem, sizeof(*s)))) { + stack; + return 0; + } + + s->persistent = persistent; + s->chunk_size = chunk_size; + s->origin = origin; + s->cow = cow; + + if (!(sl = pool_alloc(mem, sizeof(*sl)))) { + stack; + pool_free(mem, s); + return 0; + } + + sl->snapshot = s; + list_add(&vg->snapshots, &sl->list); + + return 1; +} + +int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow) +{ + struct list *slh; + struct snapshot_list *sl; + + list_iterate (slh, &vg->snapshots) { + sl = list_item(slh, struct snapshot_list); + + if (sl->snapshot->cow == cow) { + list_del(slh); + return 1; + } + } + + /* fail */ + log_err("Asked to remove an unknow snapshot."); + return 0; +}