1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

Internal snapshot code restructuring.

This commit is contained in:
Alasdair Kergon 2005-04-07 12:39:44 +00:00
parent 3a6edbed16
commit 072893aabd
25 changed files with 307 additions and 421 deletions

View File

@ -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;

View File

@ -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",

View File

@ -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))

View File

@ -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;

View File

@ -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;

View File

@ -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)) {

View File

@ -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)) {

View File

@ -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, "}");

View File

@ -54,6 +54,7 @@ static struct flag _lv_flags[] = {
{LOCKED, "LOCKED"},
{MIRRORED, NULL},
{VIRTUAL, NULL},
{SNAPSHOT, NULL},
{0, NULL}
};

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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))) {

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;