mirror of
git://sourceware.org/git/lvm2.git
synced 2025-04-01 18:50:41 +03:00
Various lvconvert/polldaemon-related fixes from NEC. See lvm-devel
for original patches & explanations.
This commit is contained in:
parent
d473b7bca8
commit
06b103c8d4
@ -60,6 +60,7 @@ static struct flag _lv_flags[] = {
|
||||
{VIRTUAL, NULL},
|
||||
{SNAPSHOT, NULL},
|
||||
{ACTIVATE_EXCL, NULL},
|
||||
{CONVERTING, NULL},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
|
@ -86,6 +86,22 @@ static int _check_version(struct config_tree *cft)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _is_converting(struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
if (lv->status & MIRRORED) {
|
||||
seg = first_seg(lv);
|
||||
/* Can't use is_temporary_mirror() because the metadata for
|
||||
* seg_lv may not be read in and flags may not be set yet. */
|
||||
if (seg_type(seg, 0) == AREA_LV &&
|
||||
strstr(seg_lv(seg, 0)->name, MIRROR_SYNC_LAYER))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _read_id(struct id *id, struct config_node *cn, const char *path)
|
||||
{
|
||||
struct config_value *cv;
|
||||
@ -343,6 +359,9 @@ static int _read_segment(struct dm_pool *mem, struct volume_group *vg,
|
||||
if (seg_is_virtual(seg))
|
||||
lv->status |= VIRTUAL;
|
||||
|
||||
if (_is_converting(lv))
|
||||
lv->status |= CONVERTING;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@ struct pv_segment;
|
||||
#define MIRROR_NOTSYNCED 0x00080000U /* LV */
|
||||
//#define ACTIVATE_EXCL 0x00100000U /* LV - internal use only */
|
||||
//#define PRECOMMITTED 0x00200000U /* VG - internal use only */
|
||||
#define CONVERTING 0x00400000U /* LV */
|
||||
|
||||
#define LVM_READ 0x00000100U /* LV VG */
|
||||
#define LVM_WRITE 0x00000200U /* LV VG */
|
||||
|
@ -134,13 +134,34 @@ static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *l
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _merge_mirror_images(struct logical_volume *lv,
|
||||
const struct list *mimages)
|
||||
{
|
||||
uint32_t addition = list_size(mimages);
|
||||
struct logical_volume **img_lvs;
|
||||
struct lv_list *lvl;
|
||||
int i = 0;
|
||||
|
||||
if (!addition)
|
||||
return 1;
|
||||
|
||||
if (!(img_lvs = alloca(sizeof(*img_lvs) * addition)))
|
||||
return_0;
|
||||
|
||||
list_iterate_items(lvl, mimages)
|
||||
img_lvs[i++] = lvl->lv;
|
||||
|
||||
return lv_add_mirror_lvs(lv, img_lvs, addition,
|
||||
MIRROR_IMAGE, first_seg(lv)->region_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove num_removed images from mirrored_seg
|
||||
*/
|
||||
static int _remove_mirror_images(struct logical_volume *lv,
|
||||
uint32_t num_removed,
|
||||
struct list *removable_pvs,
|
||||
unsigned remove_log, struct list *orphan_lvs)
|
||||
unsigned remove_log, unsigned collapse)
|
||||
{
|
||||
uint32_t m;
|
||||
uint32_t s, s1;
|
||||
@ -162,9 +183,16 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
old_area_count, old_area_count - num_removed,
|
||||
remove_log ? " and no log volume" : "");
|
||||
|
||||
if (collapse &&
|
||||
(removable_pvs || (old_area_count - num_removed != 1))) {
|
||||
log_error("Incompatible parameters to _remove_mirror_images");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move removable_pvs to end of array */
|
||||
if (removable_pvs) {
|
||||
for (s = 0; s < mirrored_seg->area_count; s++) {
|
||||
for (s = 0; s < mirrored_seg->area_count &&
|
||||
old_area_count - new_area_count < num_removed; s++) {
|
||||
all_pvs_removable = 1;
|
||||
sub_lv = seg_lv(mirrored_seg, s);
|
||||
list_iterate_items(seg, &sub_lv->segments) {
|
||||
@ -197,11 +225,8 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
mirrored_seg->areas[new_area_count] = mirrored_seg->areas[s];
|
||||
mirrored_seg->areas[s] = area;
|
||||
}
|
||||
/* Found enough matches? */
|
||||
if (old_area_count - new_area_count == num_removed)
|
||||
break;
|
||||
}
|
||||
if (old_area_count == new_area_count) {
|
||||
if (num_removed && old_area_count == new_area_count) {
|
||||
log_error("No mirror images found using specified PVs.");
|
||||
return 0;
|
||||
}
|
||||
@ -235,7 +260,12 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
lv->status &= ~MIRRORED;
|
||||
lv->status &= ~MIRROR_NOTSYNCED;
|
||||
remove_log = 1;
|
||||
}
|
||||
if (collapse && !_merge_mirror_images(lv, &tmp_orphan_lvs)) {
|
||||
log_error("Failed to add mirror images");
|
||||
return 0;
|
||||
}
|
||||
} else if (remove_log)
|
||||
mirrored_seg->log_lv = NULL;
|
||||
|
||||
if (remove_log && log_lv) {
|
||||
log_lv->status &= ~MIRROR_LOG;
|
||||
@ -272,11 +302,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
}
|
||||
|
||||
/* Save or delete the 'orphan' LVs */
|
||||
if (orphan_lvs) {
|
||||
*orphan_lvs = tmp_orphan_lvs;
|
||||
orphan_lvs->n->p = orphan_lvs;
|
||||
orphan_lvs->p->n = orphan_lvs;
|
||||
} else {
|
||||
if (!collapse) {
|
||||
list_iterate_items(lvl, &tmp_orphan_lvs)
|
||||
if (!_delete_lv(lv, lvl->lv))
|
||||
return 0;
|
||||
@ -302,18 +328,19 @@ int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors,
|
||||
|
||||
num_removed = existing_mirrors - num_mirrors;
|
||||
|
||||
while (num_removed) {
|
||||
/* num_removed can be 0 if the function is called just to remove log */
|
||||
do {
|
||||
if (num_removed < first_seg(lv)->area_count)
|
||||
removed_once = num_removed;
|
||||
else
|
||||
removed_once = first_seg(lv)->area_count - 1;
|
||||
|
||||
if (!_remove_mirror_images(lv, removed_once,
|
||||
removable_pvs, remove_log, NULL))
|
||||
removable_pvs, remove_log, 0))
|
||||
return_0;
|
||||
|
||||
num_removed -= removed_once;
|
||||
}
|
||||
} while (num_removed);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -334,27 +361,6 @@ static int _mirrored_lv_in_sync(struct logical_volume *lv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _merge_mirror_images(struct logical_volume *lv,
|
||||
const struct list *mimages)
|
||||
{
|
||||
uint32_t addition = list_size(mimages);
|
||||
struct logical_volume **img_lvs;
|
||||
struct lv_list *lvl;
|
||||
int i = 0;
|
||||
|
||||
if (!addition)
|
||||
return 1;
|
||||
|
||||
if (!(img_lvs = alloca(sizeof(*img_lvs) * addition)))
|
||||
return_0;
|
||||
|
||||
list_iterate_items(lvl, mimages)
|
||||
img_lvs[i++] = lvl->lv;
|
||||
|
||||
return lv_add_mirror_lvs(lv, img_lvs, addition,
|
||||
MIRROR_IMAGE, first_seg(lv)->region_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a temporary LV for resyncing added mirror image.
|
||||
* Add other mirror legs to lvs list.
|
||||
@ -390,7 +396,6 @@ static struct logical_volume *_find_tmp_mirror(struct logical_volume *lv)
|
||||
int collapse_mirrored_lv(struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *tmp_lv, *parent_lv;
|
||||
struct list lvlist;
|
||||
|
||||
while ((tmp_lv = _find_tmp_mirror(lv))) {
|
||||
parent_lv = find_parent_for_layer(lv, tmp_lv);
|
||||
@ -400,18 +405,12 @@ int collapse_mirrored_lv(struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
list_init(&lvlist);
|
||||
if (!_remove_mirror_images(parent_lv,
|
||||
first_seg(parent_lv)->area_count - 1,
|
||||
NULL, 1, &lvlist)) {
|
||||
NULL, 1, 1)) {
|
||||
log_error("Failed to release mirror images");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_merge_mirror_images(parent_lv, &lvlist)) {
|
||||
log_error("Failed to add mirror images");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -1277,6 +1276,13 @@ int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For corelog mirror, activation code depends on
|
||||
* the global mirror_in_sync status. As we are adding
|
||||
* a new mirror, it should be set as 'out-of-sync'
|
||||
* so that the sync starts. */
|
||||
if (!log_count)
|
||||
init_mirror_in_sync(0);
|
||||
|
||||
if (flags & MIRROR_BY_SEG) {
|
||||
if (log_count) {
|
||||
log_error("Persistent log is not supported on "
|
||||
|
@ -33,6 +33,7 @@ FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin", "For snapshots, the ori
|
||||
FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent", "For snapshots, the percentage full if LV is active.")
|
||||
FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent", "For mirrors and pvmove, current percentage in-sync.")
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv", "For pvmove, Source PV of temporary LV created by pvmove")
|
||||
FIELD(LVS, lv, STR, "Convert", lvid, 7, convertlv, "convert_lv", "For lvconvert, Name of temporary LV created by lvconvert")
|
||||
FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags", "Tags, if any.")
|
||||
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log", "For mirrors, the LV holding the synchronisation log.")
|
||||
FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules", "Kernel device-mapper modules required for this LV.")
|
||||
|
@ -272,7 +272,7 @@ static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute((u
|
||||
return dm_report_field_uint64(rh, field, &_minusone);
|
||||
}
|
||||
|
||||
static int _lv_mimage_in_sync(struct logical_volume *lv)
|
||||
static int _lv_mimage_in_sync(const struct logical_volume *lv)
|
||||
{
|
||||
float percent;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
@ -306,6 +306,8 @@ static int _lvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_
|
||||
|
||||
if (lv->status & PVMOVE)
|
||||
repstr[0] = 'p';
|
||||
else if (lv->status & CONVERTING)
|
||||
repstr[0] = 'c';
|
||||
else if (lv->status & MIRRORED) {
|
||||
if (lv->status & MIRROR_NOTSYNCED)
|
||||
repstr[0] = 'M';
|
||||
@ -548,6 +550,32 @@ static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((u
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute((unused)))
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *name = NULL;
|
||||
struct lv_segment *seg;
|
||||
|
||||
if (lv->status & CONVERTING) {
|
||||
if (lv->status & MIRRORED) {
|
||||
seg = first_seg(lv);
|
||||
|
||||
/* Temporary mirror is always area_num == 0 */
|
||||
if (seg_type(seg, 0) == AREA_LV &&
|
||||
is_temporary_mirror_layer(seg_lv(seg, 0)))
|
||||
name = seg_lv(seg, 0)->name;
|
||||
}
|
||||
}
|
||||
|
||||
if (name)
|
||||
return dm_report_field_string(rh, field, &name);
|
||||
|
||||
dm_report_field_set_value(field, "", NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _size32_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
|
@ -47,7 +47,8 @@ The lv_attr bits are:
|
||||
.RS
|
||||
.IP 1 3
|
||||
Volume type: (m)irrored, (M)irrored without initial sync, (o)rigin, (p)vmove, (s)napshot,
|
||||
invalid (S)napshot, (v)irtual, mirror (i)mage, mirror (I)mage out-of-sync
|
||||
invalid (S)napshot, (v)irtual, mirror (i)mage, mirror (I)mage out-of-sync,
|
||||
under (c)onversion
|
||||
.IP 2 3
|
||||
Permissions: (w)riteable, (r)ead-only
|
||||
.IP 3 3
|
||||
@ -82,6 +83,7 @@ All sizes are output in these units: (h)uman-readable, (s)ectors, (b)ytes,
|
||||
of 1000 (S.I.) instead of 1024. Can also specify custom (u)nits e.g.
|
||||
\-\-units 3M
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR lvdisplay (8),
|
||||
.BR pvs (8),
|
||||
.BR vgs (8)
|
||||
|
@ -58,6 +58,7 @@ All sizes are output in these units: (h)uman-readable, (s)ectors, (b)ytes,
|
||||
of 1000 (S.I.) instead of 1024. Can also specify custom (u)nits e.g.
|
||||
\-\-units 3M
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR pvdisplay (8),
|
||||
.BR lvs (8),
|
||||
.BR vgs (8)
|
||||
|
@ -71,6 +71,7 @@ All sizes are output in these units: (h)uman-readable, (s)ectors, (b)ytes,
|
||||
of 1000 (S.I.) instead of 1024. Can also specify custom (u)nits e.g.
|
||||
\-\-units 3M
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR vgdisplay (8),
|
||||
.BR pvs (8),
|
||||
.BR lvs (8)
|
||||
|
@ -106,6 +106,8 @@ static int lvchange_availability(struct cmd_context *cmd,
|
||||
{
|
||||
int activate;
|
||||
const char *pvname;
|
||||
char *lv_full_name;
|
||||
uint32_t len;
|
||||
|
||||
activate = arg_uint_value(cmd, available_ARG, 0);
|
||||
|
||||
@ -158,6 +160,18 @@ static int lvchange_availability(struct cmd_context *cmd,
|
||||
pvname);
|
||||
pvmove_poll(cmd, pvname, 1);
|
||||
}
|
||||
|
||||
if (lv->status & CONVERTING) {
|
||||
len = strlen(lv->vg->name) + strlen(lv->name) + 2;
|
||||
if (!(lv_full_name = alloca(len)))
|
||||
return_0;
|
||||
if (!dm_snprintf(lv_full_name, len, "%s/%s",
|
||||
lv->vg->name, lv->name))
|
||||
return_0;
|
||||
log_verbose("Spawning background lvconvert process for %s",
|
||||
lv->name);
|
||||
lvconvert_poll(cmd, lv_full_name, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -270,6 +270,8 @@ static int _finish_lvconvert_mirror(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->status &= ~CONVERTING;
|
||||
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
|
||||
if (!vg_write(vg))
|
||||
@ -307,8 +309,8 @@ static struct poll_functions _lvconvert_mirror_fns = {
|
||||
.finish_copy = _finish_lvconvert_mirror,
|
||||
};
|
||||
|
||||
static int _lvconvert_poll(struct cmd_context *cmd, const char *lv_name,
|
||||
unsigned background)
|
||||
int lvconvert_poll(struct cmd_context *cmd, const char *lv_name,
|
||||
unsigned background)
|
||||
{
|
||||
return poll_daemon(cmd, lv_name, background, 0, &_lvconvert_mirror_fns,
|
||||
"Converted");
|
||||
@ -370,7 +372,8 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
existing_mirrors = lv_mirror_count(lv);
|
||||
|
||||
/* If called with no argument, try collapsing the resync layers */
|
||||
if (!arg_count(cmd, mirrors_ARG) && !arg_count(cmd, mirrorlog_ARG)) {
|
||||
if (!arg_count(cmd, mirrors_ARG) && !arg_count(cmd, mirrorlog_ARG) &&
|
||||
!arg_count(cmd, corelog_ARG)) {
|
||||
lp->wait_daemon = 1;
|
||||
return 1;
|
||||
}
|
||||
@ -496,7 +499,8 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
lp->pvh, lp->alloc))
|
||||
return_0;
|
||||
} else if (seg->log_lv && corelog) {
|
||||
if (!remove_mirror_log(cmd, lv, lp->pvh))
|
||||
if (!remove_mirror_log(cmd, lv,
|
||||
lp->pv_count ? lp->pvh : NULL))
|
||||
return_0;
|
||||
} else {
|
||||
/* No change */
|
||||
@ -511,25 +515,46 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
"without initial resync");
|
||||
return 0;
|
||||
}
|
||||
/* FIXME: can't have multiple mlogs. force corelog. */
|
||||
corelog = 1;
|
||||
if (!_insert_lvconvert_layer(cmd, lv)) {
|
||||
/*
|
||||
* Log addition/removal should be done before the layer
|
||||
* insertion to make the end result consistent with
|
||||
* linear-to-mirror conversion.
|
||||
*/
|
||||
if (!seg->log_lv && !corelog) {
|
||||
if (!add_mirror_log(cmd, lv, 1,
|
||||
adjusted_mirror_region_size(
|
||||
lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size),
|
||||
lp->pvh, lp->alloc))
|
||||
return_0;
|
||||
} else if (seg->log_lv && corelog) {
|
||||
if (!remove_mirror_log(cmd, lv,
|
||||
lp->pv_count ? lp->pvh : NULL))
|
||||
return_0;
|
||||
}
|
||||
/* Insert a temporary layer for syncing,
|
||||
* only if the original lv is using disk log. */
|
||||
if (seg->log_lv && !_insert_lvconvert_layer(cmd, lv)) {
|
||||
log_error("Failed to insert resync layer");
|
||||
return 0;
|
||||
}
|
||||
/* FIXME: can't have multiple mlogs. force corelog. */
|
||||
if (!lv_add_mirrors(cmd, lv, lp->mirrors - existing_mirrors, 1,
|
||||
adjusted_mirror_region_size(
|
||||
lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size),
|
||||
corelog ? 0U : 1U, lp->pvh, lp->alloc,
|
||||
0U, lp->pvh, lp->alloc,
|
||||
MIRROR_BY_LV))
|
||||
return_0;
|
||||
lv->status |= CONVERTING;
|
||||
lp->wait_daemon = 1;
|
||||
} else {
|
||||
/* Reduce number of mirrors */
|
||||
if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors,
|
||||
0, lp->pv_count ? lp->pvh : NULL, 0))
|
||||
corelog ? 1U : 0U,
|
||||
lp->pv_count ? lp->pvh : NULL, 0))
|
||||
return_0;
|
||||
}
|
||||
|
||||
@ -681,6 +706,7 @@ int lvconvert(struct cmd_context * cmd, int argc, char **argv)
|
||||
struct lv_list *lvl;
|
||||
struct lvconvert_params lp;
|
||||
int ret = ECMD_FAILED;
|
||||
struct lvinfo info;
|
||||
|
||||
if (!_read_params(&lp, cmd, argc, argv)) {
|
||||
stack;
|
||||
@ -714,8 +740,14 @@ int lvconvert(struct cmd_context * cmd, int argc, char **argv)
|
||||
error:
|
||||
unlock_vg(cmd, lp.vg_name);
|
||||
|
||||
if (lp.wait_daemon)
|
||||
ret = _lvconvert_poll(cmd, lp.lv_name_full,
|
||||
arg_count(cmd, background_ARG) ? 1U : 0);
|
||||
if (ret == ECMD_PROCESSED && lp.wait_daemon) {
|
||||
if (!lv_info(cmd, lvl->lv, &info, 1, 0) || !info.exists) {
|
||||
log_print("Conversion starts after activation");
|
||||
return ret;
|
||||
}
|
||||
ret = lvconvert_poll(cmd, lp.lv_name_full,
|
||||
arg_count(cmd, background_ARG) ? 1U : 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -165,5 +165,6 @@ int arg_count_increment(struct cmd_context *cmd, int a);
|
||||
const char *command_name(struct cmd_context *cmd);
|
||||
|
||||
int pvmove_poll(struct cmd_context *cmd, const char *pv, unsigned background);
|
||||
int lvconvert_poll(struct cmd_context *cmd, const char *lv_name, unsigned background);
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user