mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-03 05:18:29 +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,
|
int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||||
struct physical_volume *pv, const char *dev_dir);
|
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);
|
int export_uuids(struct disk_list *dl, struct volume_group *vg);
|
||||||
|
|
||||||
void export_numbers(struct list *pvds, 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;
|
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 volume_group *vg = pool_alloc(mem, sizeof(*vg));
|
||||||
struct disk_list *dl;
|
struct disk_list *dl;
|
||||||
int partial;
|
int partial;
|
||||||
@ -96,8 +98,10 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
|
|||||||
|
|
||||||
memset(vg, 0, sizeof(*vg));
|
memset(vg, 0, sizeof(*vg));
|
||||||
|
|
||||||
|
vg->cmd = cmd;
|
||||||
list_init(&vg->pvs);
|
list_init(&vg->pvs);
|
||||||
list_init(&vg->lvs);
|
list_init(&vg->lvs);
|
||||||
|
list_init(&vg->snapshots);
|
||||||
|
|
||||||
if (!_check_vgs(pvs, &partial))
|
if (!_check_vgs(pvs, &partial))
|
||||||
goto bad;
|
goto bad;
|
||||||
@ -116,6 +120,9 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
|
|||||||
if (!import_extents(mem, vg, pvs))
|
if (!import_extents(mem, vg, pvs))
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
|
if (!import_snapshots(mem, vg, pvs))
|
||||||
|
goto bad;
|
||||||
|
|
||||||
return vg;
|
return vg;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
@ -145,13 +152,11 @@ static struct volume_group *_vg_read(struct format_instance *fi,
|
|||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(vg = _build_vg(fi->cmd->mem, &pvs))) {
|
if (!(vg = _build_vg(fi->cmd, &pvs))) {
|
||||||
stack;
|
stack;
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
vg->cmd = fi->cmd;
|
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
pool_destroy(mem);
|
pool_destroy(mem);
|
||||||
return vg;
|
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)
|
if (lvd->lv_access & LV_WRITE)
|
||||||
lv->status |= LVM_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)
|
if (lvd->lv_badblock)
|
||||||
lv->status |= BADBLOCK_ON;
|
lv->status |= BADBLOCK_ON;
|
||||||
|
|
||||||
@ -336,12 +330,6 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
|||||||
if (lv->status & LVM_WRITE)
|
if (lv->status & LVM_WRITE)
|
||||||
lvd->lv_access |= LV_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)
|
if (lv->status & SPINDOWN_LV)
|
||||||
lvd->lv_status |= LV_SPINDOWN;
|
lvd->lv_status |= LV_SPINDOWN;
|
||||||
|
|
||||||
@ -478,13 +466,21 @@ int import_lvs(struct pool *mem, struct volume_group *vg,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: tidy */
|
||||||
int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||||
struct physical_volume *pv, const char *dev_dir)
|
struct physical_volume *pv, const char *dev_dir)
|
||||||
{
|
{
|
||||||
struct list *lvh;
|
int r = 0;
|
||||||
|
struct list *lvh, *sh;
|
||||||
struct lv_list *ll;
|
struct lv_list *ll;
|
||||||
struct lvd_list *lvdl;
|
struct lvd_list *lvdl;
|
||||||
int lv_num = 0, len;
|
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
|
* 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;
|
len = sizeof(struct pe_disk) * dl->pvd.pe_total;
|
||||||
if (!(dl->extents = pool_alloc(dl->mem, len))) {
|
if (!(dl->extents = pool_alloc(dl->mem, len))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
goto out;
|
||||||
}
|
}
|
||||||
memset(dl->extents, 0, len);
|
memset(dl->extents, 0, len);
|
||||||
|
|
||||||
|
|
||||||
list_iterate (lvh, &vg->lvs) {
|
list_iterate (lvh, &vg->lvs) {
|
||||||
ll = list_item(lvh, struct lv_list);
|
ll = list_item(lvh, struct lv_list);
|
||||||
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
|
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
|
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;
|
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)) {
|
if (!export_extents(dl, lv_num + 1, ll->lv, pv)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add(&dl->lvds, &lvdl->list);
|
list_add(&dl->lvds, &lvdl->list);
|
||||||
dl->pvd.lv_cur++;
|
dl->pvd.lv_cur++;
|
||||||
lv_num++;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int export_uuids(struct disk_list *dl, struct volume_group *vg)
|
int export_uuids(struct disk_list *dl, struct volume_group *vg)
|
||||||
{
|
{
|
||||||
struct uuid_list *ul;
|
struct uuid_list *ul;
|
||||||
|
@ -41,8 +41,6 @@ static struct flag _lv_flags[] = {
|
|||||||
{ALLOC_SIMPLE, "ALLOC_SIMPLE"},
|
{ALLOC_SIMPLE, "ALLOC_SIMPLE"},
|
||||||
{ALLOC_STRICT, "ALLOC_STRICT"},
|
{ALLOC_STRICT, "ALLOC_STRICT"},
|
||||||
{ALLOC_CONTIGUOUS, "ALLOC_CONTIGUOUS"},
|
{ALLOC_CONTIGUOUS, "ALLOC_CONTIGUOUS"},
|
||||||
{SNAPSHOT, "SNASHOT"},
|
|
||||||
{SNAPSHOT_ORG, "SNAPSHOT_ORIGIN"},
|
|
||||||
{FIXED_MINOR, "FIXED_MINOR"},
|
{FIXED_MINOR, "FIXED_MINOR"},
|
||||||
{0, NULL}
|
{0, NULL}
|
||||||
};
|
};
|
||||||
|
@ -50,9 +50,6 @@
|
|||||||
#define ALLOC_STRICT 0x00002000 /* LV */
|
#define ALLOC_STRICT 0x00002000 /* LV */
|
||||||
#define ALLOC_CONTIGUOUS 0x00004000 /* LV */
|
#define ALLOC_CONTIGUOUS 0x00004000 /* LV */
|
||||||
|
|
||||||
#define SNAPSHOT 0x00010000 /* LV */
|
|
||||||
#define SNAPSHOT_ORG 0x00020000 /* LV */
|
|
||||||
|
|
||||||
|
|
||||||
struct physical_volume {
|
struct physical_volume {
|
||||||
struct id id;
|
struct id id;
|
||||||
|
@ -91,6 +91,6 @@ int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* fail */
|
/* fail */
|
||||||
log_err("Asked to remove an unknow snapshot.");
|
log_err("Asked to remove an unknown snapshot.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -67,13 +67,13 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv)
|
|||||||
return EINVALID_CMD_LINE;
|
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",
|
log_error("Can't change logical volume \"%s\" under snapshot",
|
||||||
lv->name);
|
lv->name);
|
||||||
return ECMD_FAILED;
|
return ECMD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lv->status & SNAPSHOT) {
|
if (lv_is_cow(lv->vg, lv)) {
|
||||||
log_error("Can't change snapshot logical volume \"%s\"",
|
log_error("Can't change snapshot logical volume \"%s\"",
|
||||||
lv->name);
|
lv->name);
|
||||||
return ECMD_FAILED;
|
return ECMD_FAILED;
|
||||||
|
@ -44,7 +44,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv)
|
|||||||
return ECMD_FAILED;
|
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",
|
log_error("Can't remove logical volume \"%s\" under snapshot",
|
||||||
lv->name);
|
lv->name);
|
||||||
return ECMD_FAILED;
|
return ECMD_FAILED;
|
||||||
|
@ -70,9 +70,9 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv)
|
|||||||
} else
|
} else
|
||||||
active_str = "inactive ";
|
active_str = "inactive ";
|
||||||
|
|
||||||
if (lv->status & SNAPSHOT_ORG)
|
if (lv_is_origin(lv->vg, lv))
|
||||||
snapshot_str = "Original";
|
snapshot_str = "Original";
|
||||||
else if (lv->status & SNAPSHOT)
|
else if (lv_is_cow(lv->vg, lv))
|
||||||
snapshot_str = "Snapshot";
|
snapshot_str = "Snapshot";
|
||||||
else
|
else
|
||||||
snapshot_str = " ";
|
snapshot_str = " ";
|
||||||
|
Loading…
Reference in New Issue
Block a user