mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-03 05:18:29 +03:00
Internal snapshot code restructuring.
This commit is contained in:
parent
3a6edbed16
commit
072893aabd
@ -875,22 +875,23 @@ static int _populate_snapshot(struct dev_manager *dm,
|
|||||||
{
|
{
|
||||||
char *origin, *cow;
|
char *origin, *cow;
|
||||||
char params[PATH_MAX * 2 + 32];
|
char params[PATH_MAX * 2 + 32];
|
||||||
struct snapshot *s;
|
struct lv_segment *snap_seg;
|
||||||
struct dev_layer *dlo, *dlc;
|
struct dev_layer *dlo, *dlc;
|
||||||
char devbufo[10], devbufc[10];
|
char devbufo[10], devbufc[10];
|
||||||
uint64_t size;
|
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);
|
log_error("Couldn't find snapshot for '%s'.", dl->lv->name);
|
||||||
return 0;
|
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;
|
stack;
|
||||||
return 0;
|
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;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -909,24 +910,24 @@ static int _populate_snapshot(struct dev_manager *dm,
|
|||||||
if (!dm_format_dev(devbufo, sizeof(devbufo), dlo->info.major,
|
if (!dm_format_dev(devbufo, sizeof(devbufo), dlo->info.major,
|
||||||
dlo->info.minor)) {
|
dlo->info.minor)) {
|
||||||
log_error("Couldn't create origin device parameters for '%s'.",
|
log_error("Couldn't create origin device parameters for '%s'.",
|
||||||
s->origin->name);
|
snap_seg->origin->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dm_format_dev(devbufc, sizeof(devbufc), dlc->info.major,
|
if (!dm_format_dev(devbufc, sizeof(devbufc), dlc->info.major,
|
||||||
dlc->info.minor)) {
|
dlc->info.minor)) {
|
||||||
log_error("Couldn't create cow device parameters for '%s'.",
|
log_error("Couldn't create cow device parameters for '%s'.",
|
||||||
s->cow->name);
|
snap_seg->cow->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lvm_snprintf(params, sizeof(params), "%s %s P %d",
|
if (lvm_snprintf(params, sizeof(params), "%s %s P %d",
|
||||||
devbufo, devbufc, s->chunk_size) == -1) {
|
devbufo, devbufc, snap_seg->chunk_size) == -1) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
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);
|
log_debug("Adding target: 0 %" PRIu64 " snapshot %s", size, params);
|
||||||
if (!dm_task_add_target(dmt, UINT64_C(0), size, "snapshot", 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)
|
static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct logical_volume *active;
|
struct logical_volume *active;
|
||||||
struct snapshot *s;
|
struct lv_segment *snap_seg;
|
||||||
struct list *sh;
|
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) {
|
list_iterate(sh, &dm->active_list) {
|
||||||
active = list_item(sh, struct lv_list)->lv;
|
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);
|
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,
|
static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
|
||||||
struct snapshot *s)
|
struct lv_segment *snap_seg)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* snapshot(org, cow)
|
* 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 */
|
/* add the dependency on the real origin device */
|
||||||
if (!str_list_add(dm->mem, &dl->pre_create,
|
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;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add the dependency on the visible origin device */
|
/* 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;
|
stack;
|
||||||
return 0;
|
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)
|
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.
|
* FIXME: this doesn't cope with recursive snapshots yet.
|
||||||
*/
|
*/
|
||||||
if ((s = find_cow(lv)))
|
if ((snap_seg = find_cow(lv)))
|
||||||
return _expand_snapshot(dm, lv, s);
|
return _expand_snapshot(dm, lv, snap_seg);
|
||||||
|
|
||||||
else if (lv_is_origin(lv))
|
else if (lv_is_origin(lv))
|
||||||
return _expand_origin(dm, 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) {
|
list_iterate(lvh, lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
|
if (lv->status & SNAPSHOT)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!(dl = _lookup(dm, lv->lvid.s, NULL))) {
|
if (!(dl = _lookup(dm, lv->lvid.s, NULL))) {
|
||||||
stack;
|
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)
|
static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg)
|
||||||
{
|
{
|
||||||
struct list *lvh;
|
struct list *lvh;
|
||||||
struct logical_volume *lvt;
|
struct logical_volume *lv;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build layers for complete vg.
|
* Build layers for complete vg.
|
||||||
*/
|
*/
|
||||||
list_iterate(lvh, &vg->lvs) {
|
list_iterate(lvh, &vg->lvs) {
|
||||||
lvt = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
if (!_expand_lv(dm, lvt)) {
|
if (lv->status & SNAPSHOT)
|
||||||
|
continue;
|
||||||
|
if (!_expand_lv(dm, lv)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1915,12 +1922,14 @@ static int _add_lvs(struct pool *mem,
|
|||||||
struct list *head, struct logical_volume *origin)
|
struct list *head, struct logical_volume *origin)
|
||||||
{
|
{
|
||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
struct snapshot *s;
|
struct lv_segment *snap_seg;
|
||||||
struct list *lvh;
|
struct list *lvh;
|
||||||
|
|
||||||
list_iterate(lvh, &origin->vg->lvs) {
|
list_iterate(lvh, &origin->vg->lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
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))
|
if (!_add_lv(mem, head, lv))
|
||||||
return 0;
|
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)
|
static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct logical_volume *active, *old_origin;
|
struct logical_volume *active, *old_origin;
|
||||||
struct snapshot *s;
|
struct lv_segment *snap_seg;
|
||||||
struct list *sh, *active_head;
|
struct list *sh, *active_head;
|
||||||
|
|
||||||
active_head = &dm->active_list;
|
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 */
|
/* Remove any snapshots with given origin */
|
||||||
list_iterate(sh, active_head) {
|
list_iterate(sh, active_head) {
|
||||||
active = list_item(sh, struct lv_list)->lv;
|
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, active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_remove_lv(active_head, lv);
|
_remove_lv(active_head, lv);
|
||||||
|
|
||||||
if (!(s = find_cow(lv)))
|
if (!(snap_seg = find_cow(lv)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
old_origin = s->origin;
|
old_origin = snap_seg->origin;
|
||||||
|
|
||||||
/* Was this the last active snapshot with this origin? */
|
/* Was this the last active snapshot with this origin? */
|
||||||
list_iterate(sh, active_head) {
|
list_iterate(sh, active_head) {
|
||||||
active = list_item(sh, struct lv_list)->lv;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1980,7 +1990,7 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
|
|||||||
struct logical_volume *lv)
|
struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct logical_volume *suspended;
|
struct logical_volume *suspended;
|
||||||
struct snapshot *s;
|
struct lv_segment *snap_seg;
|
||||||
struct list *sh, *suspend_head;
|
struct list *sh, *suspend_head;
|
||||||
|
|
||||||
suspend_head = &dm->suspend_list;
|
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 */
|
/* Remove from list any snapshots with given origin */
|
||||||
list_iterate(sh, suspend_head) {
|
list_iterate(sh, suspend_head) {
|
||||||
suspended = list_item(sh, struct lv_list)->lv;
|
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);
|
_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) {
|
list_iterate(lvh, &vg->lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
|
if (lv->status & SNAPSHOT)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) {
|
if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) {
|
||||||
stack;
|
stack;
|
||||||
|
@ -337,10 +337,9 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
|||||||
void *handle)
|
void *handle)
|
||||||
{
|
{
|
||||||
struct lvinfo info;
|
struct lvinfo info;
|
||||||
int inkernel, snap_active;
|
int inkernel, snap_active = 0;
|
||||||
char uuid[64];
|
char uuid[64];
|
||||||
struct snapshot *snap = NULL;
|
struct lv_segment *snap_seg = NULL;
|
||||||
struct list *slh, *snaplist;
|
|
||||||
float snap_percent; /* fused, fsize; */
|
float snap_percent; /* fused, fsize; */
|
||||||
|
|
||||||
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
|
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)) {
|
if (lv_is_origin(lv)) {
|
||||||
log_print("LV snapshot status source of");
|
log_print("LV snapshot status source of");
|
||||||
|
|
||||||
snaplist = find_snapshots(lv);
|
list_iterate_items_gen(snap_seg, &lv->snapshot_segs,
|
||||||
list_iterate(slh, snaplist) {
|
origin_list) {
|
||||||
snap = list_item(slh, struct snapshot_list)->snapshot;
|
if (inkernel &&
|
||||||
snap_active = lv_snapshot_percent(snap->cow,
|
(snap_active = lv_snapshot_percent(snap_seg->cow,
|
||||||
&snap_percent);
|
&snap_percent)))
|
||||||
if (!snap_active || snap_percent < 0 ||
|
if (snap_percent < 0 || snap_percent >= 100)
|
||||||
snap_percent >= 100) snap_active = 0;
|
snap_active = 0;
|
||||||
log_print(" %s%s/%s [%s]",
|
log_print(" %s%s/%s [%s]",
|
||||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||||
snap->cow->name,
|
snap_seg->cow->name,
|
||||||
(snap_active > 0) ? "active" : "INACTIVE");
|
(snap_active > 0) ? "active" : "INACTIVE");
|
||||||
}
|
}
|
||||||
snap = NULL;
|
snap_seg = NULL;
|
||||||
} else if ((snap = find_cow(lv))) {
|
} else if ((snap_seg = find_cow(lv))) {
|
||||||
snap_active = lv_snapshot_percent(lv, &snap_percent);
|
if (inkernel &&
|
||||||
if (!snap_active || snap_percent < 0 || snap_percent >= 100)
|
(snap_active = lv_snapshot_percent(snap_seg->cow,
|
||||||
|
&snap_percent)))
|
||||||
|
if (snap_percent < 0 || snap_percent >= 100)
|
||||||
snap_active = 0;
|
snap_active = 0;
|
||||||
|
|
||||||
log_print("LV snapshot status %s destination for %s%s/%s",
|
log_print("LV snapshot status %s destination for %s%s/%s",
|
||||||
(snap_active > 0) ? "active" : "INACTIVE",
|
(snap_active > 0) ? "active" : "INACTIVE",
|
||||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||||
snap->origin->name);
|
snap_seg->origin->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inkernel && info.suspended)
|
if (inkernel && info.suspended)
|
||||||
@ -402,15 +404,24 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
|||||||
|
|
||||||
log_print("LV Size %s",
|
log_print("LV Size %s",
|
||||||
display_size(cmd,
|
display_size(cmd,
|
||||||
snap ? snap->origin->size : lv->size,
|
snap_seg ? snap_seg->origin->size : lv->size,
|
||||||
SIZE_SHORT));
|
SIZE_SHORT));
|
||||||
|
|
||||||
log_print("Current LE %u",
|
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
|
if (snap_seg) {
|
||||||
log_print("Allocated LE %u", lv->allocated_le);
|
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));
|
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);
|
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("Allocation %s", get_alloc_string(lv->alloc));
|
||||||
log_print("Read ahead sectors %u", lv->read_ahead);
|
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");
|
vg->status & SHARED ? "yes" : "no");
|
||||||
}
|
}
|
||||||
log_print("MAX LV %u", vg->max_lv);
|
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));
|
log_print("Open LV %u", lvs_in_vg_opened(vg));
|
||||||
/****** FIXME Max LV Size
|
/****** FIXME Max LV Size
|
||||||
log_print ( "MAX LV Size %s",
|
log_print ( "MAX LV Size %s",
|
||||||
|
@ -148,7 +148,6 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
|||||||
vg->seqno = 0;
|
vg->seqno = 0;
|
||||||
list_init(&vg->pvs);
|
list_init(&vg->pvs);
|
||||||
list_init(&vg->lvs);
|
list_init(&vg->lvs);
|
||||||
list_init(&vg->snapshots);
|
|
||||||
list_init(&vg->tags);
|
list_init(&vg->tags);
|
||||||
|
|
||||||
if (!_check_vgs(pvs, &partial))
|
if (!_check_vgs(pvs, &partial))
|
||||||
|
@ -323,6 +323,8 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
|
|||||||
lv->size = lvd->lv_size;
|
lv->size = lvd->lv_size;
|
||||||
lv->le_count = lvd->lv_allocated_le;
|
lv->le_count = lvd->lv_allocated_le;
|
||||||
|
|
||||||
|
lv->snapshot = NULL;
|
||||||
|
list_init(&lv->snapshot_segs);
|
||||||
list_init(&lv->segments);
|
list_init(&lv->segments);
|
||||||
list_init(&lv->tags);
|
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)
|
struct physical_volume *pv, const char *dev_dir)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
struct list *lvh, *sh;
|
struct list *lvh;
|
||||||
struct lv_list *ll;
|
struct lv_list *ll;
|
||||||
struct lvd_list *lvdl;
|
struct lvd_list *lvdl;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -524,6 +526,9 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
|||||||
|
|
||||||
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 (ll->lv->status & SNAPSHOT)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
|
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
|
||||||
stack;
|
stack;
|
||||||
goto out;
|
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);
|
_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
|
||||||
|
|
||||||
lv_num = lvnum_from_lvid(&ll->lv->lvid);
|
lv_num = lvnum_from_lvid(&ll->lv->lvid);
|
||||||
|
|
||||||
lvdl->lvd.lv_number = lv_num;
|
lvdl->lvd.lv_number = lv_num;
|
||||||
|
|
||||||
if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) {
|
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;
|
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);
|
list_add(&dl->lvds, &lvdl->list);
|
||||||
dl->pvd.lv_cur++;
|
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;
|
r = 1;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -646,7 +633,8 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* insert the snapshot */
|
/* 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)) {
|
lvd->lv_chunk_size)) {
|
||||||
log_err("Couldn't add snapshot.");
|
log_err("Couldn't add snapshot.");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -60,6 +60,8 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
|
|||||||
|
|
||||||
list_iterate(llh, &vg->lvs) {
|
list_iterate(llh, &vg->lvs) {
|
||||||
ll = list_item(llh, struct lv_list);
|
ll = list_item(llh, struct lv_list);
|
||||||
|
if (ll->lv->status & SNAPSHOT)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!(lvm = pool_alloc(mem, sizeof(*lvm)))) {
|
if (!(lvm = pool_alloc(mem, sizeof(*lvm)))) {
|
||||||
stack;
|
stack;
|
||||||
|
@ -132,7 +132,6 @@ static struct volume_group *_build_vg_from_pds(struct format_instance
|
|||||||
vg->system_id = NULL;
|
vg->system_id = NULL;
|
||||||
list_init(&vg->pvs);
|
list_init(&vg->pvs);
|
||||||
list_init(&vg->lvs);
|
list_init(&vg->lvs);
|
||||||
list_init(&vg->snapshots);
|
|
||||||
list_init(&vg->tags);
|
list_init(&vg->tags);
|
||||||
|
|
||||||
if (!import_pool_vg(vg, smem, pds)) {
|
if (!import_pool_vg(vg, smem, pds)) {
|
||||||
|
@ -82,6 +82,8 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
|
|||||||
lv->name = NULL;
|
lv->name = NULL;
|
||||||
lv->le_count = 0;
|
lv->le_count = 0;
|
||||||
lv->read_ahead = 0;
|
lv->read_ahead = 0;
|
||||||
|
lv->snapshot = NULL;
|
||||||
|
list_init(&lv->snapshot_segs);
|
||||||
list_init(&lv->segments);
|
list_init(&lv->segments);
|
||||||
list_init(&lv->tags);
|
list_init(&lv->tags);
|
||||||
|
|
||||||
@ -112,6 +114,8 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
|
|||||||
} else {
|
} else {
|
||||||
lv->minor = -1;
|
lv->minor = -1;
|
||||||
}
|
}
|
||||||
|
lv->snapshot = NULL;
|
||||||
|
list_init(&lv->snapshot_segs);
|
||||||
list_init(&lv->segments);
|
list_init(&lv->segments);
|
||||||
list_init(&lv->tags);
|
list_init(&lv->tags);
|
||||||
}
|
}
|
||||||
@ -288,8 +292,11 @@ int import_pool_segments(struct list *lvs, struct pool *mem,
|
|||||||
|
|
||||||
list_iterate(lvhs, lvs) {
|
list_iterate(lvhs, lvs) {
|
||||||
lvl = list_item(lvhs, struct lv_list);
|
lvl = list_item(lvhs, struct lv_list);
|
||||||
|
|
||||||
lv = lvl->lv;
|
lv = lvl->lv;
|
||||||
|
|
||||||
|
if (lv->status & SNAPSHOT)
|
||||||
|
continue;
|
||||||
|
|
||||||
for (i = 0; i < subpools; i++) {
|
for (i = 0; i < subpools; i++) {
|
||||||
if (usp[i].striping) {
|
if (usp[i].striping) {
|
||||||
if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) {
|
if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) {
|
||||||
|
@ -477,87 +477,6 @@ static int _count_segments(struct logical_volume *lv)
|
|||||||
return r;
|
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)
|
static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||||
{
|
{
|
||||||
struct list *lvh;
|
struct list *lvh;
|
||||||
@ -629,11 +548,6 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
|||||||
outf(f, "}");
|
outf(f, "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_print_snapshots(f, vg)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
outf(f, "}");
|
outf(f, "}");
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ static struct flag _lv_flags[] = {
|
|||||||
{LOCKED, "LOCKED"},
|
{LOCKED, "LOCKED"},
|
||||||
{MIRRORED, NULL},
|
{MIRRORED, NULL},
|
||||||
{VIRTUAL, NULL},
|
{VIRTUAL, NULL},
|
||||||
|
{SNAPSHOT, NULL},
|
||||||
{0, NULL}
|
{0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -508,6 +508,8 @@ static int _read_lvnames(struct format_instance *fid, struct pool *mem,
|
|||||||
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
|
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
|
||||||
lv->read_ahead = 0;
|
lv->read_ahead = 0;
|
||||||
|
|
||||||
|
lv->snapshot = NULL;
|
||||||
|
list_init(&lv->snapshot_segs);
|
||||||
list_init(&lv->segments);
|
list_init(&lv->segments);
|
||||||
list_init(&lv->tags);
|
list_init(&lv->tags);
|
||||||
|
|
||||||
@ -561,8 +563,16 @@ static int _read_lvsegs(struct format_instance *fid, struct pool *mem,
|
|||||||
|
|
||||||
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
|
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
|
||||||
|
|
||||||
/* Skip this for now for snapshots */
|
/*
|
||||||
if (!(lv->status & SNAPSHOT)) {
|
* 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;
|
lv->minor = -1;
|
||||||
if ((lv->status & FIXED_MINOR) &&
|
if ((lv->status & FIXED_MINOR) &&
|
||||||
!_read_int32(lvn, "minor", &lv->minor)) {
|
!_read_int32(lvn, "minor", &lv->minor)) {
|
||||||
@ -570,16 +580,13 @@ static int _read_lvsegs(struct format_instance *fid, struct pool *mem,
|
|||||||
"volume %s.", lv->name);
|
"volume %s.", lv->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lv->major = -1;
|
lv->major = -1;
|
||||||
if ((lv->status & FIXED_MINOR) &&
|
if ((lv->status & FIXED_MINOR) &&
|
||||||
!_read_int32(lvn, "major", &lv->major)) {
|
!_read_int32(lvn, "major", &lv->major)) {
|
||||||
log_error("Couldn't read major number for logical "
|
log_error("Couldn't read major number for logical "
|
||||||
"volume %s.", lv->name);
|
"volume %s.", lv->name);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
vg->lv_count--;
|
|
||||||
list_del(&lvl->list);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -736,7 +743,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
list_init(&vg->lvs);
|
list_init(&vg->lvs);
|
||||||
list_init(&vg->snapshots);
|
|
||||||
list_init(&vg->tags);
|
list_init(&vg->tags);
|
||||||
|
|
||||||
/* Optional tags */
|
/* Optional tags */
|
||||||
|
@ -17,4 +17,7 @@
|
|||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
|
|
||||||
struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas);
|
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
|
#endif
|
||||||
|
@ -440,6 +440,34 @@ static int _alloc_virtual(struct logical_volume *lv,
|
|||||||
return 1;
|
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.
|
* Chooses a correct allocation policy.
|
||||||
*/
|
*/
|
||||||
@ -546,6 +574,7 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
|||||||
union lvid *lvid,
|
union lvid *lvid,
|
||||||
uint32_t status,
|
uint32_t status,
|
||||||
alloc_policy_t alloc,
|
alloc_policy_t alloc,
|
||||||
|
int import,
|
||||||
struct volume_group *vg)
|
struct volume_group *vg)
|
||||||
{
|
{
|
||||||
struct cmd_context *cmd = vg->cmd;
|
struct cmd_context *cmd = vg->cmd;
|
||||||
@ -566,6 +595,7 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!import)
|
||||||
log_verbose("Creating logical volume %s", name);
|
log_verbose("Creating logical volume %s", name);
|
||||||
|
|
||||||
if (!(ll = pool_zalloc(cmd->mem, sizeof(*ll))) ||
|
if (!(ll = pool_zalloc(cmd->mem, sizeof(*ll))) ||
|
||||||
@ -593,6 +623,8 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
|||||||
lv->minor = -1;
|
lv->minor = -1;
|
||||||
lv->size = UINT64_C(0);
|
lv->size = UINT64_C(0);
|
||||||
lv->le_count = 0;
|
lv->le_count = 0;
|
||||||
|
lv->snapshot = NULL;
|
||||||
|
list_init(&lv->snapshot_segs);
|
||||||
list_init(&lv->segments);
|
list_init(&lv->segments);
|
||||||
list_init(&lv->tags);
|
list_init(&lv->tags);
|
||||||
|
|
||||||
@ -606,7 +638,9 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!import)
|
||||||
vg->lv_count++;
|
vg->lv_count++;
|
||||||
|
|
||||||
list_add(&vg->lvs, &ll->list);
|
list_add(&vg->lvs, &ll->list);
|
||||||
|
|
||||||
return lv;
|
return lv;
|
||||||
|
@ -221,7 +221,6 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
|||||||
list_init(&vg->lvs);
|
list_init(&vg->lvs);
|
||||||
|
|
||||||
vg->snapshot_count = 0;
|
vg->snapshot_count = 0;
|
||||||
list_init(&vg->snapshots);
|
|
||||||
|
|
||||||
list_init(&vg->tags);
|
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->pvs);
|
||||||
list_init(&vg->lvs);
|
list_init(&vg->lvs);
|
||||||
list_init(&vg->snapshots);
|
|
||||||
list_init(&vg->tags);
|
list_init(&vg->tags);
|
||||||
vg->cmd = cmd;
|
vg->cmd = cmd;
|
||||||
if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) {
|
if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) {
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
#define VISIBLE_LV 0x00000040 /* LV */
|
#define VISIBLE_LV 0x00000040 /* LV */
|
||||||
#define FIXED_MINOR 0x00000080 /* LV */
|
#define FIXED_MINOR 0x00000080 /* LV */
|
||||||
/* FIXME Remove when metadata restructuring is completed */
|
/* 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 PVMOVE 0x00002000 /* VG LV SEG */
|
||||||
#define LOCKED 0x00004000 /* LV */
|
#define LOCKED 0x00004000 /* LV */
|
||||||
#define MIRRORED 0x00008000 /* LV - internal use only */
|
#define MIRRORED 0x00008000 /* LV - internal use only */
|
||||||
@ -191,11 +191,8 @@ struct volume_group {
|
|||||||
|
|
||||||
/* logical volumes */
|
/* logical volumes */
|
||||||
uint32_t lv_count;
|
uint32_t lv_count;
|
||||||
struct list lvs;
|
|
||||||
|
|
||||||
/* snapshots */
|
|
||||||
uint32_t snapshot_count;
|
uint32_t snapshot_count;
|
||||||
struct list snapshots;
|
struct list lvs;
|
||||||
|
|
||||||
struct list tags;
|
struct list tags;
|
||||||
};
|
};
|
||||||
@ -217,7 +214,8 @@ struct lv_segment {
|
|||||||
uint32_t area_len;
|
uint32_t area_len;
|
||||||
struct logical_volume *origin;
|
struct logical_volume *origin;
|
||||||
struct logical_volume *cow;
|
struct logical_volume *cow;
|
||||||
uint32_t chunk_size;
|
struct list origin_list;
|
||||||
|
uint32_t chunk_size; /* In sectors */
|
||||||
uint32_t extents_copied;
|
uint32_t extents_copied;
|
||||||
|
|
||||||
struct list tags;
|
struct list tags;
|
||||||
@ -253,20 +251,14 @@ struct logical_volume {
|
|||||||
uint64_t size;
|
uint64_t size;
|
||||||
uint32_t le_count;
|
uint32_t le_count;
|
||||||
|
|
||||||
|
uint32_t origin_count;
|
||||||
|
struct list snapshot_segs;
|
||||||
|
struct lv_segment *snapshot;
|
||||||
|
|
||||||
struct list segments;
|
struct list segments;
|
||||||
struct list tags;
|
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 name_list {
|
||||||
struct list list;
|
struct list list;
|
||||||
char *name;
|
char *name;
|
||||||
@ -290,12 +282,6 @@ struct lv_list {
|
|||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct snapshot_list {
|
|
||||||
struct list list;
|
|
||||||
|
|
||||||
struct snapshot *snapshot;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mda_list {
|
struct mda_list {
|
||||||
struct list list;
|
struct list list;
|
||||||
struct device_area mda;
|
struct device_area mda;
|
||||||
@ -424,6 +410,7 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
|||||||
union lvid *lvid,
|
union lvid *lvid,
|
||||||
uint32_t status,
|
uint32_t status,
|
||||||
alloc_policy_t alloc,
|
alloc_policy_t alloc,
|
||||||
|
int import,
|
||||||
struct volume_group *vg);
|
struct volume_group *vg);
|
||||||
|
|
||||||
int lv_reduce(struct format_instance *fi,
|
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);
|
int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv);
|
||||||
|
|
||||||
struct snapshot *find_cow(const struct logical_volume *lv);
|
struct lv_segment *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);
|
|
||||||
|
|
||||||
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,
|
union lvid *lvid, uint32_t extent_count,
|
||||||
uint32_t chunk_size);
|
uint32_t chunk_size);
|
||||||
|
|
||||||
|
@ -16,101 +16,31 @@
|
|||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
|
#include "lv_alloc.h"
|
||||||
|
|
||||||
int lv_is_origin(const struct logical_volume *lv)
|
int lv_is_origin(const struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct list *slh;
|
return lv->origin_count ? 1 : 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lv_is_cow(const struct logical_volume *lv)
|
int lv_is_cow(const struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct list *slh;
|
return lv->snapshot ? 1 : 0;
|
||||||
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;
|
/* Given a cow LV, return the snapshot lv_segment that uses it */
|
||||||
}
|
struct lv_segment *find_cow(const struct logical_volume *lv)
|
||||||
|
|
||||||
struct snapshot *find_origin(const struct logical_volume *lv)
|
|
||||||
{
|
{
|
||||||
struct list *slh;
|
return lv->snapshot;
|
||||||
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;
|
int vg_add_snapshot(struct format_instance *fid, const char *name,
|
||||||
}
|
struct logical_volume *origin,
|
||||||
|
struct logical_volume *cow, union lvid *lvid,
|
||||||
struct snapshot *find_cow(const struct logical_volume *lv)
|
uint32_t extent_count, uint32_t chunk_size)
|
||||||
{
|
{
|
||||||
struct list *slh;
|
struct logical_volume *snap;
|
||||||
struct snapshot *s;
|
struct lv_segment *seg;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Is the cow device already being used ?
|
* 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;
|
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;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->chunk_size = chunk_size;
|
snap->le_count = extent_count;
|
||||||
s->le_count = extent_count;
|
|
||||||
s->origin = origin;
|
|
||||||
s->cow = cow;
|
|
||||||
|
|
||||||
if (lvid)
|
if (!(seg = alloc_snapshot_seg(snap, 0))) {
|
||||||
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)))) {
|
|
||||||
stack;
|
stack;
|
||||||
pool_free(mem, s);
|
|
||||||
return 0;
|
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;
|
cow->status &= ~VISIBLE_LV;
|
||||||
sl->snapshot = s;
|
|
||||||
list_add(&origin->vg->snapshots, &sl->list);
|
list_add(&origin->snapshot_segs, &seg->origin_list);
|
||||||
origin->vg->snapshot_count++;
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow)
|
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow)
|
||||||
{
|
{
|
||||||
struct list *slh;
|
list_del(&cow->snapshot->origin_list);
|
||||||
struct snapshot_list *sl;
|
cow->snapshot->origin->origin_count--;
|
||||||
|
|
||||||
list_iterate(slh, &vg->snapshots) {
|
if (!lv_remove(vg, cow->snapshot->lv)) {
|
||||||
sl = list_item(slh, struct snapshot_list);
|
log_error("Failed to remove internal snapshot LV %s",
|
||||||
|
cow->snapshot->lv->name);
|
||||||
if (sl->snapshot->cow == cow) {
|
|
||||||
list_del(slh);
|
|
||||||
vg->snapshot_count--;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fail */
|
|
||||||
log_err("Asked to remove an unknown snapshot.");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cow->snapshot = NULL;
|
||||||
|
|
||||||
|
vg->snapshot_count--;
|
||||||
|
vg->lv_count++;
|
||||||
|
cow->status |= VISIBLE_LV;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
@ -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;
|
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||||
struct lvinfo info;
|
struct lvinfo info;
|
||||||
char *repstr;
|
char *repstr;
|
||||||
struct snapshot *snap;
|
struct lv_segment *snap_seg;
|
||||||
float snap_percent;
|
float snap_percent;
|
||||||
|
|
||||||
if (!(repstr = pool_zalloc(rh->mem, 7))) {
|
if (!(repstr = pool_zalloc(rh->mem, 7))) {
|
||||||
@ -373,8 +373,8 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
|
|||||||
repstr[5] = '-';
|
repstr[5] = '-';
|
||||||
|
|
||||||
/* Snapshot dropped? */
|
/* Snapshot dropped? */
|
||||||
if ((snap = find_cow(lv)) &&
|
if ((snap_seg = find_cow(lv)) &&
|
||||||
(!lv_snapshot_percent(snap->cow, &snap_percent) ||
|
(!lv_snapshot_percent(snap_seg->cow, &snap_percent) ||
|
||||||
snap_percent < 0 || snap_percent >= 100)) {
|
snap_percent < 0 || snap_percent >= 100)) {
|
||||||
repstr[0] = toupper(repstr[0]);
|
repstr[0] = toupper(repstr[0]);
|
||||||
if (info.suspended)
|
if (info.suspended)
|
||||||
@ -478,10 +478,10 @@ static int _origin_disp(struct report_handle *rh, struct field *field,
|
|||||||
const void *data)
|
const void *data)
|
||||||
{
|
{
|
||||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||||
struct snapshot *snap;
|
struct lv_segment *snap_seg;
|
||||||
|
|
||||||
if ((snap = find_cow(lv)))
|
if ((snap_seg = find_cow(lv)))
|
||||||
return _string_disp(rh, field, &snap->origin->name);
|
return _string_disp(rh, field, &snap_seg->origin->name);
|
||||||
|
|
||||||
field->report_string = "";
|
field->report_string = "";
|
||||||
field->sort_value = (const void *) 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 void *data)
|
||||||
{
|
{
|
||||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||||
struct snapshot *snap;
|
struct lv_segment *snap_seg;
|
||||||
struct lvinfo info;
|
struct lvinfo info;
|
||||||
float snap_percent;
|
float snap_percent;
|
||||||
uint64_t *sortval;
|
uint64_t *sortval;
|
||||||
@ -773,15 +773,16 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(snap = find_cow(lv)) ||
|
if (!(snap_seg = find_cow(lv)) ||
|
||||||
(lv_info(snap->cow, &info, 0) && !info.exists)) {
|
(lv_info(snap_seg->cow, &info, 0) && !info.exists)) {
|
||||||
field->report_string = "";
|
field->report_string = "";
|
||||||
*sortval = UINT64_C(0);
|
*sortval = UINT64_C(0);
|
||||||
field->sort_value = sortval;
|
field->sort_value = sortval;
|
||||||
return 1;
|
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";
|
field->report_string = "100.00";
|
||||||
*sortval = UINT64_C(100);
|
*sortval = UINT64_C(100);
|
||||||
field->sort_value = sortval;
|
field->sort_value = sortval;
|
||||||
|
@ -70,8 +70,8 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vg_add_snapshot(org, cow, &seg->lv->lvid, seg->len,
|
if (!vg_add_snapshot(seg->lv->vg->fid, seg->lv->name, org, cow,
|
||||||
chunk_size)) {
|
&seg->lv->lvid, seg->len, chunk_size)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
if (!(lv = lv_create_empty(vg->fid, lp->lv_name, "lvol%d", NULL,
|
||||||
status, lp->alloc, vg))) {
|
status, lp->alloc, 0, vg))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -609,8 +609,8 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vg_add_snapshot(org, lv, NULL, org->le_count,
|
if (!vg_add_snapshot(vg->fid, NULL, org, lv, NULL,
|
||||||
lp->chunk_size)) {
|
org->le_count, lp->chunk_size)) {
|
||||||
log_err("Couldn't create snapshot.");
|
log_err("Couldn't create snapshot.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
|||||||
{
|
{
|
||||||
struct volume_group *vg;
|
struct volume_group *vg;
|
||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
struct snapshot *snap;
|
struct lv_segment *snap_seg;
|
||||||
struct lvinfo info;
|
struct lvinfo info;
|
||||||
uint32_t stripesize_extents = 0;
|
uint32_t stripesize_extents = 0;
|
||||||
uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 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);
|
backup(vg);
|
||||||
|
|
||||||
/* If snapshot, must suspend all associated devices */
|
/* If snapshot, must suspend all associated devices */
|
||||||
if ((snap = find_cow(lv)))
|
if ((snap_seg = find_cow(lv)))
|
||||||
lock_lvid = snap->origin->lvid.s;
|
lock_lvid = snap_seg->origin->lvid.s;
|
||||||
else
|
else
|
||||||
lock_lvid = lv->lvid.s;
|
lock_lvid = lv->lvid.s;
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
|||||||
/* FIXME Pass 'alloc' down to lv_extend */
|
/* FIXME Pass 'alloc' down to lv_extend */
|
||||||
if (!(lv_mirr = lv_create_empty(vg->fid, NULL, "pvmove%d", NULL,
|
if (!(lv_mirr = lv_create_empty(vg->fid, NULL, "pvmove%d", NULL,
|
||||||
LVM_READ | LVM_WRITE,
|
LVM_READ | LVM_WRITE,
|
||||||
ALLOC_CONTIGUOUS, vg))) {
|
ALLOC_CONTIGUOUS, 0, vg))) {
|
||||||
log_error("Creation of temporary pvmove LV failed");
|
log_error("Creation of temporary pvmove LV failed");
|
||||||
return NULL;
|
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 */
|
/* Find segments to be moved and set up mirrors */
|
||||||
list_iterate_items(lvl, &vg->lvs) {
|
list_iterate_items(lvl, &vg->lvs) {
|
||||||
lv = lvl->lv;
|
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;
|
continue;
|
||||||
if (lv_is_origin(lv) || lv_is_cow(lv)) {
|
if (lv_is_origin(lv) || lv_is_cow(lv)) {
|
||||||
log_print("Skipping snapshot-related LV %s", lv->name);
|
log_print("Skipping snapshot-related LV %s", lv->name);
|
||||||
|
@ -60,6 +60,9 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
list_iterate_items(lvl, &vg->lvs) {
|
list_iterate_items(lvl, &vg->lvs) {
|
||||||
|
if (lvl->lv->status & SNAPSHOT)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Should we process this LV? */
|
/* Should we process this LV? */
|
||||||
if (process_all)
|
if (process_all)
|
||||||
process_lv = 1;
|
process_lv = 1;
|
||||||
|
@ -27,7 +27,7 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
|
|||||||
lv = lvl->lv;
|
lv = lvl->lv;
|
||||||
|
|
||||||
/* Only request activation of snapshot origin devices */
|
/* Only request activation of snapshot origin devices */
|
||||||
if (lv_is_cow(lv))
|
if ((lv->status & SNAPSHOT) || lv_is_cow(lv))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Can't deactive a pvmove LV */
|
/* Can't deactive a pvmove LV */
|
||||||
|
@ -92,6 +92,8 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
|
|||||||
if (cmd->fmt->features & FMT_RESTRICTED_LVIDS) {
|
if (cmd->fmt->features & FMT_RESTRICTED_LVIDS) {
|
||||||
list_iterate_items(lvl, &vg->lvs) {
|
list_iterate_items(lvl, &vg->lvs) {
|
||||||
lv = lvl->lv;
|
lv = lvl->lv;
|
||||||
|
if (lv->status & SNAPSHOT)
|
||||||
|
continue;
|
||||||
if (lvnum_from_lvid(&lv->lvid) < MAX_RESTRICTED_LVS)
|
if (lvnum_from_lvid(&lv->lvid) < MAX_RESTRICTED_LVS)
|
||||||
continue;
|
continue;
|
||||||
if (lv_info(lv, &info, 0) && info.exists) {
|
if (lv_info(lv, &info, 0) && info.exists) {
|
||||||
|
@ -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,
|
static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||||
int *list_unsafe)
|
int *list_unsafe)
|
||||||
{
|
{
|
||||||
struct snapshot *snap;
|
struct lv_segment *snap_seg;
|
||||||
struct snapshot_list *snl;
|
struct list *snh, *snht;
|
||||||
struct list *snaplist;
|
struct logical_volume *cow;
|
||||||
|
|
||||||
log_verbose("%s/%s has missing extents: removing (including "
|
log_verbose("%s/%s has missing extents: removing (including "
|
||||||
"dependencies)", lv->vg->name, lv->name);
|
"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);
|
log_error("Failed to deactivate LV %s", lv->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if ((snap = find_cow(lv))) {
|
} else if ((snap_seg = find_cow(lv))) {
|
||||||
log_verbose("Deactivating (if active) logical volume %s "
|
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",
|
log_error("Failed to deactivate LV %s",
|
||||||
snap->origin->name);
|
snap_seg->origin->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the origin LV */
|
/* Use the origin LV */
|
||||||
lv = snap->origin;
|
lv = snap_seg->origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove snapshot dependencies */
|
/* Remove snapshot dependencies */
|
||||||
if (!(snaplist = find_snapshots(lv))) {
|
list_iterate_safe(snh, snht, &lv->snapshot_segs) {
|
||||||
stack;
|
snap_seg = list_struct_base(snh, struct lv_segment,
|
||||||
return 0;
|
origin_list);
|
||||||
}
|
cow = snap_seg->cow;
|
||||||
/* List may be empty */
|
|
||||||
list_iterate_items(snl, snaplist) {
|
|
||||||
*list_unsafe = 1; /* May remove caller's lvht! */
|
*list_unsafe = 1; /* May remove caller's lvht! */
|
||||||
snap = snl->snapshot;
|
if (!vg_remove_snapshot(lv->vg, cow)) {
|
||||||
if (!vg_remove_snapshot(lv->vg, snap->cow)) {
|
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
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);
|
lv->vg->name);
|
||||||
if (!lv_remove(lv->vg, snap->cow)) {
|
if (!lv_remove(lv->vg, cow)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,19 @@ static int _move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
|
|||||||
return 1;
|
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)
|
static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
|
||||||
{
|
{
|
||||||
struct list *lvh, *lvht;
|
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) {
|
list_iterate_safe(lvh, lvht, &vg_from->lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
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 */
|
/* Ensure all the PVs used by this LV remain in the same */
|
||||||
/* VG as each other */
|
/* VG as each other */
|
||||||
vg_with = NULL;
|
vg_with = NULL;
|
||||||
@ -89,6 +105,7 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
|
|||||||
dev_name(pv->dev));
|
dev_name(pv->dev));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vg_with == vg_from)
|
if (vg_with == vg_from)
|
||||||
@ -107,39 +124,38 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
|
|||||||
return 1;
|
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,
|
static int _move_snapshots(struct volume_group *vg_from,
|
||||||
struct volume_group *vg_to)
|
struct volume_group *vg_to)
|
||||||
{
|
{
|
||||||
struct list *slh, *slth;
|
struct list *lvh, *lvht;
|
||||||
struct snapshot *snap;
|
struct logical_volume *lv;
|
||||||
int cow_from, origin_from;
|
struct lv_segment *seg;
|
||||||
|
int cow_from = 0;
|
||||||
|
int origin_from = 0;
|
||||||
|
|
||||||
list_iterate_safe(slh, slth, &vg_from->snapshots) {
|
list_iterate_safe(lvh, lvht, &vg_from->lvs) {
|
||||||
snap = list_item(slh, struct snapshot_list)->snapshot;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
cow_from = _lv_is_in_vg(vg_from, snap->cow);
|
|
||||||
origin_from = _lv_is_in_vg(vg_from, snap->origin);
|
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)
|
if (cow_from && origin_from)
|
||||||
return 1;
|
continue;
|
||||||
if ((!cow_from && origin_from) || (cow_from && !origin_from)) {
|
if ((!cow_from && origin_from) || (cow_from && !origin_from)) {
|
||||||
log_error("Snapshot %s split", snap->cow->name);
|
log_error("Snapshot %s split", seg->cow->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Move this snapshot */
|
||||||
|
list_del(lvh);
|
||||||
|
list_add(&vg_to->lvs, lvh);
|
||||||
|
|
||||||
vg_from->snapshot_count--;
|
vg_from->snapshot_count--;
|
||||||
vg_to->snapshot_count++;
|
vg_to->snapshot_count++;
|
||||||
|
|
||||||
list_del(slh);
|
|
||||||
list_add(&vg_to->snapshots, slh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user