mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
o First pass at format1 snapshot support.
This commit is contained in:
parent
7d68b08028
commit
0a9f8bcf97
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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}
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 = " ";
|
||||
|
Loading…
Reference in New Issue
Block a user