mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-22 17:35:59 +03:00
Account for mirror transient status when doing lvconvert --repair.
This commit is contained in:
parent
078573dc2c
commit
954df8f3d7
@ -475,6 +475,28 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if percent set, else 0 on failure.
|
||||
*/
|
||||
int lv_check_transient(struct logical_volume *lv)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name)))
|
||||
return_0;
|
||||
|
||||
if (!(r = dev_manager_transient(dm, lv)))
|
||||
stack;
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if percent set, else 0 on failure.
|
||||
*/
|
||||
|
@ -78,6 +78,7 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||
int *activate_lv);
|
||||
|
||||
int lv_check_transient(struct logical_volume *lv);
|
||||
/*
|
||||
* Returns 1 if percent has been set, else 0.
|
||||
*/
|
||||
|
@ -543,6 +543,68 @@ static int _percent(struct dev_manager *dm, const char *name, const char *dlid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dev_manager_transient(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *type = NULL;
|
||||
char *params = NULL;
|
||||
char *dlid = NULL;
|
||||
const struct dm_list *segh = &lv->segments;
|
||||
struct lv_segment *seg = NULL;
|
||||
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, NULL)))
|
||||
return_0;
|
||||
|
||||
if (!(dmt = _setup_task(0, dlid, NULL, DM_DEVICE_STATUS, 0, 0)))
|
||||
return_0;
|
||||
|
||||
if (!dm_task_no_open_count(dmt))
|
||||
log_error("Failed to disable open_count");
|
||||
|
||||
if (!dm_task_run(dmt))
|
||||
goto_out;
|
||||
|
||||
if (!dm_task_get_info(dmt, &info) || !info.exists)
|
||||
goto_out;
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length, &type,
|
||||
¶ms);
|
||||
if (lv) {
|
||||
if (!(segh = dm_list_next(&lv->segments, segh))) {
|
||||
log_error("Number of segments in active LV %s "
|
||||
"does not match metadata", lv->name);
|
||||
goto out;
|
||||
}
|
||||
seg = dm_list_item(segh, struct lv_segment);
|
||||
}
|
||||
|
||||
if (!type || !params)
|
||||
continue;
|
||||
|
||||
if (seg->segtype->ops->check_transient_status &&
|
||||
!seg->segtype->ops->check_transient_status(seg, params))
|
||||
goto_out;
|
||||
|
||||
} while (next);
|
||||
|
||||
if (lv && (segh = dm_list_next(&lv->segments, segh))) {
|
||||
log_error("Number of segments in active LV %s does not "
|
||||
"match metadata", lv->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_manager implementation.
|
||||
*/
|
||||
|
@ -57,6 +57,7 @@ int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv,
|
||||
int *flush_required);
|
||||
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_transient(struct dev_manager *dm, struct logical_volume *lv);
|
||||
|
||||
int dev_manager_mknodes(const struct logical_volume *lv);
|
||||
|
||||
|
@ -754,7 +754,8 @@ int lv_split_mirror_images(struct logical_volume *lv, const char *split_lv_name,
|
||||
uint32_t split_count, struct dm_list *removable_pvs);
|
||||
int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint32_t mirrors, uint32_t log_count,
|
||||
struct dm_list *pvs, uint64_t status_mask);
|
||||
int (*is_removable)(struct logical_volume *, void *),
|
||||
void *removable_baton, uint64_t status_mask);
|
||||
|
||||
int is_temporary_mirror_layer(const struct logical_volume *lv);
|
||||
struct logical_volume * find_temporary_mirror(const struct logical_volume *lv);
|
||||
@ -769,7 +770,8 @@ int add_mirrors_to_segments(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct dm_list *allocatable_pvs, alloc_policy_t alloc);
|
||||
|
||||
int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors,
|
||||
struct dm_list *removable_pvs, unsigned remove_log);
|
||||
int (*is_removable)(struct logical_volume *, void *),
|
||||
void *removable_baton, unsigned remove_log);
|
||||
int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint32_t mirrors, uint32_t stripes, uint32_t stripe_size, uint32_t region_size,
|
||||
struct dm_list *allocatable_pvs, alloc_policy_t alloc,
|
||||
|
@ -2117,7 +2117,7 @@ static int _lv_mark_if_partial(struct logical_volume *lv)
|
||||
* propagated transitively, so LVs referencing other LVs are marked
|
||||
* partial as well, if any of their referenced LVs are marked partial.
|
||||
*/
|
||||
static int _vg_mark_partial_lvs(struct volume_group *vg)
|
||||
int vg_mark_partial_lvs(struct volume_group *vg)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
@ -2654,7 +2654,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
if (vg_missing_pv_count(correct_vg)) {
|
||||
log_verbose("There are %d physical volumes missing.",
|
||||
vg_missing_pv_count(correct_vg));
|
||||
_vg_mark_partial_lvs(correct_vg);
|
||||
vg_mark_partial_lvs(correct_vg);
|
||||
}
|
||||
*consistent = 1;
|
||||
return correct_vg;
|
||||
@ -2945,7 +2945,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
if (vg_missing_pv_count(correct_vg)) {
|
||||
log_verbose("There are %d physical volumes missing.",
|
||||
vg_missing_pv_count(correct_vg));
|
||||
_vg_mark_partial_lvs(correct_vg);
|
||||
vg_mark_partial_lvs(correct_vg);
|
||||
}
|
||||
|
||||
if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
|
||||
|
@ -383,5 +383,7 @@ struct id pv_vgid(const struct physical_volume *pv);
|
||||
struct physical_volume *pv_by_path(struct cmd_context *cmd, const char *pv_name);
|
||||
int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
|
||||
struct physical_volume *pv);
|
||||
int vg_mark_partial_lvs(struct volume_group *vg);
|
||||
int is_mirror_image_removable(struct logical_volume *mimage_lv, void *baton);
|
||||
|
||||
#endif
|
||||
|
@ -435,14 +435,17 @@ struct logical_volume *detach_mirror_log(struct lv_segment *mirrored_seg)
|
||||
}
|
||||
|
||||
/* Check if mirror image LV is removable with regard to given removable_pvs */
|
||||
static int _is_mirror_image_removable(struct logical_volume *mimage_lv,
|
||||
struct dm_list *removable_pvs)
|
||||
int is_mirror_image_removable(struct logical_volume *mimage_lv, void *baton)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct lv_segment *seg;
|
||||
int pv_found;
|
||||
struct pv_list *pvl;
|
||||
uint32_t s;
|
||||
struct dm_list *removable_pvs = baton;
|
||||
|
||||
if (!baton || dm_list_empty(removable_pvs))
|
||||
return 1;
|
||||
|
||||
dm_list_iterate_items(seg, &mimage_lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
@ -508,7 +511,7 @@ static int _move_removable_mimages_to_end(struct logical_volume *lv,
|
||||
sub_lv = seg_lv(mirrored_seg, i);
|
||||
|
||||
if (!is_temporary_mirror_layer(sub_lv) &&
|
||||
_is_mirror_image_removable(sub_lv, removable_pvs)) {
|
||||
is_mirror_image_removable(sub_lv, removable_pvs)) {
|
||||
if (!shift_mirror_images(mirrored_seg, i))
|
||||
return_0;
|
||||
count--;
|
||||
@ -754,13 +757,13 @@ static int _split_mirror_images(struct logical_volume *lv,
|
||||
*/
|
||||
static int _remove_mirror_images(struct logical_volume *lv,
|
||||
uint32_t num_removed,
|
||||
struct dm_list *removable_pvs,
|
||||
int (*is_removable)(struct logical_volume *, void *),
|
||||
void *removable_baton,
|
||||
unsigned remove_log, unsigned collapse,
|
||||
uint32_t *removed)
|
||||
{
|
||||
uint32_t m;
|
||||
int32_t s;
|
||||
int removable_pvs_specified;
|
||||
struct logical_volume *sub_lv;
|
||||
struct logical_volume *detached_log_lv = NULL;
|
||||
struct logical_volume *temp_layer_lv = NULL;
|
||||
@ -770,9 +773,6 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
struct lv_list *lvl;
|
||||
struct dm_list tmp_orphan_lvs;
|
||||
|
||||
removable_pvs_specified = (removable_pvs &&
|
||||
!dm_list_empty(removable_pvs)) ? 1 : 0;
|
||||
|
||||
if (removed)
|
||||
*removed = 0;
|
||||
|
||||
@ -781,38 +781,32 @@ 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_specified || (old_area_count - num_removed != 1))) {
|
||||
if (collapse && (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_specified) {
|
||||
for (s = mirrored_seg->area_count - 1;
|
||||
s >= 0 && old_area_count - new_area_count < num_removed;
|
||||
s--) {
|
||||
sub_lv = seg_lv(mirrored_seg, s);
|
||||
|
||||
if (!is_temporary_mirror_layer(sub_lv) &&
|
||||
_is_mirror_image_removable(sub_lv, removable_pvs)) {
|
||||
/*
|
||||
* Check if the user is trying to pull the
|
||||
* primary mirror image when the mirror is
|
||||
* not in-sync.
|
||||
*/
|
||||
if ((s == 0) && !_mirrored_lv_in_sync(lv) &&
|
||||
!(lv->status & PARTIAL_LV)) {
|
||||
log_error("Unable to remove primary mirror image while mirror is not in-sync");
|
||||
return_0;
|
||||
}
|
||||
if (!shift_mirror_images(mirrored_seg, s))
|
||||
return_0;
|
||||
new_area_count--;
|
||||
for (s = mirrored_seg->area_count - 1;
|
||||
s >= 0 && old_area_count - new_area_count < num_removed;
|
||||
s--) {
|
||||
sub_lv = seg_lv(mirrored_seg, s);
|
||||
if (!is_temporary_mirror_layer(sub_lv) &&
|
||||
is_removable(sub_lv, removable_baton)) {
|
||||
/*
|
||||
* Check if the user is trying to pull the
|
||||
* primary mirror image when the mirror is
|
||||
* not in-sync.
|
||||
*/
|
||||
if ((s == 0) && !_mirrored_lv_in_sync(lv) &&
|
||||
!(lv->status & PARTIAL_LV)) {
|
||||
log_error("Unable to remove primary mirror image while mirror is not in-sync");
|
||||
return_0;
|
||||
}
|
||||
if (!shift_mirror_images(mirrored_seg, s))
|
||||
return_0;
|
||||
new_area_count--;
|
||||
}
|
||||
if (num_removed && old_area_count == new_area_count)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -822,6 +816,9 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
*/
|
||||
new_area_count = old_area_count - num_removed;
|
||||
|
||||
if (num_removed && old_area_count == new_area_count)
|
||||
return 1;
|
||||
|
||||
/* Remove mimage LVs from the segment */
|
||||
dm_list_init(&tmp_orphan_lvs);
|
||||
for (m = new_area_count; m < mirrored_seg->area_count; m++) {
|
||||
@ -956,7 +953,8 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
* Remove the number of mirror images from the LV
|
||||
*/
|
||||
int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors,
|
||||
struct dm_list *removable_pvs, unsigned remove_log)
|
||||
int (*is_removable)(struct logical_volume *, void *),
|
||||
void *removable_baton, unsigned remove_log)
|
||||
{
|
||||
uint32_t num_removed, removed_once, r;
|
||||
uint32_t existing_mirrors = lv_mirror_count(lv);
|
||||
@ -972,7 +970,8 @@ int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors,
|
||||
removed_once = first_seg(next_lv)->area_count - 1;
|
||||
|
||||
if (!_remove_mirror_images(next_lv, removed_once,
|
||||
removable_pvs, remove_log, 0, &r))
|
||||
is_removable, removable_baton,
|
||||
remove_log, 0, &r))
|
||||
return_0;
|
||||
|
||||
if (r < removed_once) {
|
||||
@ -999,6 +998,11 @@ int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _no_removable_images(struct logical_volume *lv __attribute((unused)),
|
||||
void *baton __attribute((unused))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Collapsing temporary mirror layers.
|
||||
*
|
||||
@ -1031,7 +1035,7 @@ int collapse_mirrored_lv(struct logical_volume *lv)
|
||||
|
||||
if (!_remove_mirror_images(mirror_seg->lv,
|
||||
mirror_seg->area_count - 1,
|
||||
NULL, 1, 1, NULL)) {
|
||||
_no_removable_images, NULL, 1, 1, NULL)) {
|
||||
log_error("Failed to release mirror images");
|
||||
return 0;
|
||||
}
|
||||
@ -1156,7 +1160,8 @@ int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirr
|
||||
init_mirror_in_sync(in_sync);
|
||||
|
||||
r = _remove_mirror_images(mirrored_seg->lv, old_num_mirrors - num_mirrors,
|
||||
removable_pvs, remove_log, 0, NULL);
|
||||
is_mirror_image_removable, removable_pvs,
|
||||
remove_log, 0, NULL);
|
||||
if (!r)
|
||||
/* Unable to remove bad devices */
|
||||
return 0;
|
||||
@ -1549,7 +1554,7 @@ int remove_mirror_log(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if (!remove_mirror_images(lv, lv_mirror_count(lv),
|
||||
removable_pvs, 1U))
|
||||
is_mirror_image_removable, removable_pvs, 1U))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
@ -1929,7 +1934,9 @@ int lv_split_mirror_images(struct logical_volume *lv, const char *split_name,
|
||||
*/
|
||||
int lv_remove_mirrors(struct cmd_context *cmd __attribute((unused)),
|
||||
struct logical_volume *lv,
|
||||
uint32_t mirrors, uint32_t log_count, struct dm_list *pvs,
|
||||
uint32_t mirrors, uint32_t log_count,
|
||||
int (*is_removable)(struct logical_volume *, void *),
|
||||
void *removable_baton,
|
||||
uint64_t status_mask)
|
||||
{
|
||||
uint32_t new_mirrors;
|
||||
@ -1957,7 +1964,8 @@ int lv_remove_mirrors(struct cmd_context *cmd __attribute((unused)),
|
||||
if (seg_type(seg, 0) == AREA_LV &&
|
||||
seg_lv(seg, 0)->status & MIRROR_IMAGE)
|
||||
return remove_mirror_images(lv, new_mirrors + 1,
|
||||
pvs, log_count ? 1U : 0);
|
||||
is_removable, removable_baton,
|
||||
log_count ? 1U : 0);
|
||||
|
||||
/* MIRROR_BY_SEG */
|
||||
if (log_count) {
|
||||
|
@ -82,6 +82,7 @@ struct segtype_handler {
|
||||
struct dm_tree_node *node, uint64_t len,
|
||||
uint32_t *pvmove_mirror_count);
|
||||
int (*target_status_compatible) (const char *type);
|
||||
int (*check_transient_status) (struct lv_segment *seg, char *params);
|
||||
int (*target_percent) (void **target_state,
|
||||
percent_range_t *percent_range,
|
||||
struct dm_pool * mem,
|
||||
|
@ -239,6 +239,117 @@ static int _mirrored_target_percent(void **target_state,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _mirrored_transient_status(struct lv_segment *seg, char *params)
|
||||
{
|
||||
int i, j;
|
||||
struct logical_volume *lv = seg->lv;
|
||||
struct lvinfo info;
|
||||
char *p = NULL;
|
||||
char **args, **log_args;
|
||||
struct logical_volume **images;
|
||||
struct logical_volume *log;
|
||||
int num_devs, log_argc;
|
||||
int failed = 0;
|
||||
char *status;
|
||||
|
||||
log_error("Mirrored transient status: \"%s\"", params);
|
||||
|
||||
/* number of devices */
|
||||
if (!dm_split_words(params, 1, 0, &p))
|
||||
return_0;
|
||||
|
||||
if (!(num_devs = atoi(p)))
|
||||
return_0;
|
||||
|
||||
p += strlen(p) + 1;
|
||||
|
||||
if (num_devs > DEFAULT_MIRROR_MAX_IMAGES) {
|
||||
log_error("Unexpectedly many (%d) mirror images in %s.",
|
||||
num_devs, lv->name);
|
||||
return_0;
|
||||
}
|
||||
|
||||
args = alloca((num_devs + 5) * sizeof(char *));
|
||||
images = alloca(num_devs * sizeof(struct logical_volume *));
|
||||
|
||||
if (dm_split_words(p, num_devs + 4, 0, args) < num_devs + 4)
|
||||
return_0;
|
||||
|
||||
log_argc = atoi(args[3 + num_devs]);
|
||||
log_args = alloca(log_argc * sizeof(char *));
|
||||
|
||||
if (log_argc > 16) {
|
||||
log_error("Unexpectedly many (%d) log arguments in %s.",
|
||||
log_argc, lv->name);
|
||||
return_0;
|
||||
}
|
||||
|
||||
|
||||
if (dm_split_words(args[3 + num_devs] + strlen(args[3 + num_devs]) + 1,
|
||||
log_argc, 0, log_args) < log_argc)
|
||||
return_0;
|
||||
|
||||
if (num_devs != seg->area_count) {
|
||||
log_error("Active mirror has a wrong number of mirror images!");
|
||||
log_error("Metadata says %d, kernel says %d.", seg->area_count, num_devs);
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!strcmp(log_args[0], "disk")) {
|
||||
char buf[32];
|
||||
log = first_seg(lv)->log_lv;
|
||||
lv_info(lv->vg->cmd, log, &info, 0, 0);
|
||||
log_debug("Found mirror log at %d:%d", info.major, info.minor);
|
||||
sprintf(buf, "%d:%d", info.major, info.minor);
|
||||
if (strcmp(buf, log_args[1])) {
|
||||
log_error("Mirror log mismatch. Metadata says %s, kernel says %s.",
|
||||
buf, log_args[1]);
|
||||
return_0;
|
||||
}
|
||||
log_very_verbose("Status of log (%s): %s", buf, log_args[2]);
|
||||
if (log_args[2][0] != 'A') {
|
||||
log->status |= PARTIAL_LV;
|
||||
++failed;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_devs; ++i)
|
||||
images[i] = NULL;
|
||||
|
||||
for (i = 0; i < seg->area_count; ++i) {
|
||||
char buf[32];
|
||||
lv_info(lv->vg->cmd, seg_lv(seg, i), &info, 0, 0);
|
||||
log_debug("Found mirror leg at %d:%d", info.major, info.minor);
|
||||
sprintf(buf, "%d:%d", info.major, info.minor);
|
||||
for (j = 0; j < num_devs; ++j) {
|
||||
if (!strcmp(buf, args[j])) {
|
||||
log_debug("Match: metadata image %d matches kernel image %d", i, j);
|
||||
images[j] = seg_lv(seg, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status = args[2 + num_devs];
|
||||
|
||||
for (i = 0; i < num_devs; ++i) {
|
||||
if (!images[i]) {
|
||||
log_error("Failed to find image %d (%s).", i, args[i]);
|
||||
return_0;
|
||||
}
|
||||
log_very_verbose("Status of image %d: %c", i, status[i]);
|
||||
if (status[i] != 'A') {
|
||||
images[i]->status |= PARTIAL_LV;
|
||||
++failed;
|
||||
}
|
||||
}
|
||||
|
||||
/* update PARTIAL_LV flags across the VG */
|
||||
if (failed)
|
||||
vg_mark_partial_lvs(lv->vg);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _add_log(struct dm_pool *mem, struct lv_segment *seg,
|
||||
struct dm_tree_node *node, uint32_t area_count, uint32_t region_size)
|
||||
{
|
||||
@ -564,6 +675,7 @@ static struct segtype_handler _mirrored_ops = {
|
||||
.add_target_line = _mirrored_add_target_line,
|
||||
.target_percent = _mirrored_target_percent,
|
||||
.target_present = _mirrored_target_present,
|
||||
.check_transient_status = _mirrored_transient_status,
|
||||
#ifdef DMEVENTD
|
||||
.target_monitored = _target_monitored,
|
||||
.target_monitor_events = _target_monitor_events,
|
||||
|
@ -32,40 +32,49 @@ lvcreate -m 1 -L 1 -n mirror $vg
|
||||
lvchange -a n $vg/mirror
|
||||
|
||||
# Fail a leg of a mirror.
|
||||
disable_dev $dev1
|
||||
aux disable_dev $dev1
|
||||
lvchange --partial -a y $vg/mirror
|
||||
repair 'activation { mirror_image_fault_policy = "remove" }'
|
||||
check linear $vg mirror
|
||||
cleanup $dev1
|
||||
aux cleanup $dev1
|
||||
|
||||
# Fail a leg of a mirror.
|
||||
# Expected result: Mirror (leg replaced)
|
||||
disable_dev $dev1
|
||||
aux disable_dev $dev1
|
||||
repair 'activation { mirror_image_fault_policy = "replace" }'
|
||||
check mirror $vg mirror
|
||||
lvs | grep mirror_mlog
|
||||
cleanup $dev1
|
||||
aux cleanup $dev1
|
||||
|
||||
# Fail a leg of a mirror (use old name for policy specification)
|
||||
# Expected result: Mirror (leg replaced)
|
||||
disable_dev $dev1
|
||||
aux disable_dev $dev1
|
||||
repair 'activation { mirror_device_fault_policy = "replace" }'
|
||||
check mirror $vg mirror
|
||||
lvs | grep mirror_mlog
|
||||
cleanup $dev1
|
||||
aux cleanup $dev1
|
||||
|
||||
# Fail a leg of a mirror w/ no available spare
|
||||
# Expected result: 2-way with corelog
|
||||
disable_dev $dev2 $dev4
|
||||
aux disable_dev $dev2 $dev4
|
||||
repair 'activation { mirror_image_fault_policy = "replace" }'
|
||||
check mirror $vg mirror
|
||||
lvs | not grep mirror_mlog
|
||||
cleanup $dev2 $dev4
|
||||
aux cleanup $dev2 $dev4
|
||||
|
||||
# Fail the log device of a mirror w/ no available spare
|
||||
# Expected result: mirror w/ corelog
|
||||
disable_dev $dev3 $dev4
|
||||
lvconvert --repair --use-policies --config 'activation { mirror_image_fault_policy = "replace" }' $vg/mirror
|
||||
aux disable_dev $dev3 $dev4
|
||||
repair 'activation { mirror_image_fault_policy = "replace" }' $vg/mirror
|
||||
check mirror $vg mirror
|
||||
lvs | not grep mirror_mlog
|
||||
aux cleanup $dev3 $dev4
|
||||
|
||||
# Fail the log device with a remove policy
|
||||
# Expected result: mirror w/ corelog
|
||||
lvchange -a y $vg/mirror
|
||||
aux disable_dev $dev3 $dev4
|
||||
repair 'activation { mirror_log_fault_policy = "remove" }'
|
||||
check mirror $vg mirror core
|
||||
lvs | not grep mirror_mlog
|
||||
cleanup $dev3 $dev4
|
||||
|
26
test/t-lvconvert-repair-transient.sh
Normal file
26
test/t-lvconvert-repair-transient.sh
Normal file
@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
. ./test-utils.sh
|
||||
|
||||
prepare_vg 5
|
||||
|
||||
# fail multiple devices
|
||||
|
||||
lvcreate -m 3 --ig -L 1 -n 4way $vg
|
||||
disable_dev $dev2 $dev4
|
||||
mkfs.ext3 $DM_DEV_DIR/$vg/4way
|
||||
enable_dev $dev2 $dev4
|
||||
echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out
|
||||
lvs -a -o +devices | not grep unknown
|
||||
vgreduce --removemissing $vg
|
||||
check mirror $vg 4way
|
||||
lvchange -a n $vg/4way
|
@ -11,38 +11,59 @@
|
||||
|
||||
. ./test-utils.sh
|
||||
|
||||
prepare_vg 5
|
||||
|
||||
# fail multiple devices
|
||||
|
||||
lvcreate -m 3 --ig -L 1 -n 4way $vg
|
||||
aux prepare_vg 5
|
||||
lvcreate -m 3 --ig -L 1 -n 4way $vg $dev1 $dev2 $dev3 $dev4 $dev5:0
|
||||
disable_dev $dev2 $dev4
|
||||
echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out
|
||||
lvs -a -o +devices | not grep unknown
|
||||
vgreduce --removemissing $vg
|
||||
enable_dev $dev2 $dev4
|
||||
check mirror $vg 4way
|
||||
lvchange -a n $vg/4way
|
||||
|
||||
vgremove -ff $vg
|
||||
vgcreate -c n $vg $dev1 $dev2 $dev3 $dev4
|
||||
check mirror $vg 4way $dev5
|
||||
|
||||
aux prepare_vg 5
|
||||
lvcreate -m 2 --ig -L 1 -n 3way $vg
|
||||
disable_dev $dev1 $dev2
|
||||
echo n | lvconvert --repair $vg/3way
|
||||
check linear $vg 3way
|
||||
lvs -a -o +devices | not grep unknown
|
||||
lvs -a -o +devices | not grep mlog
|
||||
dmsetup ls | grep $PREFIX | not grep mlog
|
||||
vgreduce --removemissing $vg
|
||||
enable_dev $dev1 $dev2
|
||||
check linear $vg 3way
|
||||
lvchange -a n $vg/3way
|
||||
|
||||
# fail just log and get it removed
|
||||
|
||||
aux prepare_vg 5
|
||||
lvcreate -m 2 --ig -L 1 -n 3way $vg $dev1 $dev2 $dev3 $dev4:0
|
||||
disable_dev $dev4
|
||||
echo n | lvconvert --repair $vg/3way
|
||||
check mirror $vg 3way core
|
||||
lvs -a -o +devices | not grep unknown
|
||||
lvs -a -o +devices | not grep mlog
|
||||
dmsetup ls | grep $PREFIX | not grep mlog
|
||||
vgreduce --removemissing $vg
|
||||
enable_dev $dev4
|
||||
|
||||
aux prepare_vg 5
|
||||
lvcreate -m 1 --ig -L 1 -n 2way $vg $dev1 $dev2 $dev3:0
|
||||
disable_dev $dev3
|
||||
echo n | lvconvert --repair $vg/2way
|
||||
check mirror $vg 2way core
|
||||
lvs -a -o +devices | not grep unknown
|
||||
lvs -a -o +devices | not grep mlog
|
||||
vgreduce --removemissing $vg
|
||||
enable_dev $dev3
|
||||
|
||||
# fail single devices
|
||||
|
||||
vgremove -ff $vg
|
||||
vgcreate -c n $vg $dev1 $dev2 $dev3
|
||||
aux prepare_vg 5
|
||||
vgreduce $vg $dev4
|
||||
|
||||
lvcreate -m 1 --ig -L 1 -n mirror $vg
|
||||
|
||||
lvchange -a n $vg/mirror
|
||||
vgextend $vg $dev4
|
||||
disable_dev $dev1
|
||||
|
@ -373,6 +373,7 @@ prepare_lvmconf() {
|
||||
level = 9
|
||||
file = "$TESTDIR/debug.log"
|
||||
overwrite = 1
|
||||
activation = 1
|
||||
}
|
||||
backup {
|
||||
backup = 0
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "tools.h"
|
||||
#include "polldaemon.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "metadata.h"
|
||||
|
||||
struct lvconvert_params {
|
||||
int snapshot;
|
||||
@ -603,6 +604,12 @@ static struct dm_list *_failed_pv_list(struct volume_group *vg)
|
||||
return failed_pvs;
|
||||
}
|
||||
|
||||
static int _is_partial_lv(struct logical_volume *lv,
|
||||
void *baton __attribute((unused)))
|
||||
{
|
||||
return lv->status & PARTIAL_LV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk down the stacked mirror LV to the original mirror LV.
|
||||
*/
|
||||
@ -727,7 +734,7 @@ static int _lv_update_log_type(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
/* Reducing redundancy of the log */
|
||||
return remove_mirror_images(log_lv, log_count, operable_pvs, 1U);
|
||||
return remove_mirror_images(log_lv, log_count, is_mirror_image_removable, operable_pvs, 1U);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -913,6 +920,34 @@ static int _lvconvert_mirrors_parse_params(struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _reload_lv(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
|
||||
if (!vg_write(lv->vg))
|
||||
return_0;
|
||||
|
||||
if (!suspend_lv(cmd, lv)) {
|
||||
log_error("Failed to lock %s", lv->name);
|
||||
vg_revert(lv->vg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_commit(lv->vg)) {
|
||||
if (!resume_lv(cmd, lv))
|
||||
stack;
|
||||
return_0;
|
||||
}
|
||||
|
||||
log_very_verbose("Updating \"%s\" in kernel", lv->name);
|
||||
|
||||
if (!resume_lv(cmd, lv)) {
|
||||
log_error("Problem reactivating %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* _lvconvert_mirrors_aux
|
||||
*
|
||||
@ -1004,6 +1039,16 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is there already a convert in progress? We do not
|
||||
* currently allow more than one.
|
||||
*/
|
||||
if (find_temporary_mirror(lv) || (lv->status & CONVERTING)) {
|
||||
log_error("%s is already being converted. Unable to start another conversion.",
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Log addition/removal should be done before the layer
|
||||
* insertion to make the end result consistent with
|
||||
@ -1064,7 +1109,7 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
|
||||
nmc, operable_pvs))
|
||||
return 0;
|
||||
} else if (!lv_remove_mirrors(cmd, lv, nmc, nlc,
|
||||
operable_pvs, 0))
|
||||
is_mirror_image_removable, operable_pvs, 0))
|
||||
return_0;
|
||||
|
||||
goto out; /* Just in case someone puts code between */
|
||||
@ -1084,29 +1129,8 @@ out:
|
||||
|
||||
out_skip_log_convert:
|
||||
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
|
||||
if (!vg_write(lv->vg))
|
||||
return_0;
|
||||
|
||||
if (!suspend_lv(cmd, lv)) {
|
||||
log_error("Failed to lock %s", lv->name);
|
||||
vg_revert(lv->vg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!vg_commit(lv->vg)) {
|
||||
if (!resume_lv(cmd, lv))
|
||||
stack;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
log_very_verbose("Updating \"%s\" in kernel", lv->name);
|
||||
|
||||
if (!resume_lv(cmd, lv)) {
|
||||
log_error("Problem reactivating %s", lv->name);
|
||||
goto out;
|
||||
}
|
||||
if (!_reload_lv(cmd, lv))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -1139,6 +1163,8 @@ static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
|
||||
cmd->partial_activation = 1;
|
||||
lp->need_polling = 0;
|
||||
|
||||
lv_check_transient(lv); /* TODO check this in lib for all commands? */
|
||||
|
||||
if (!(lv->status & PARTIAL_LV)) {
|
||||
log_error("%s is consistent. Nothing to repair.", lv->name);
|
||||
return 1;
|
||||
@ -1195,11 +1221,13 @@ static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
|
||||
if (!_lv_update_log_type(cmd, lp, lv, failed_pvs, new_log_count))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Remove all failed_pvs
|
||||
*/
|
||||
if (!_lvconvert_mirrors_aux(cmd, lv, lp, failed_pvs,
|
||||
lp->mirrors, new_log_count))
|
||||
if (failed_mirrors) {
|
||||
if (!lv_remove_mirrors(cmd, lv, failed_mirrors, new_log_count,
|
||||
_is_partial_lv, NULL, 0))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_reload_lv(cmd, lv))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@ -1209,6 +1237,13 @@ static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
|
||||
if (replace_mirrors)
|
||||
lp->mirrors = old_mimage_count;
|
||||
|
||||
/*
|
||||
* It does not make sense to replace the log if the volume is no longer
|
||||
* a mirror.
|
||||
*/
|
||||
if (!replace_mirrors && lp->mirrors == 1)
|
||||
replace_log = 0;
|
||||
|
||||
log_count = replace_log ? old_log_count : new_log_count;
|
||||
|
||||
while (replace_mirrors || replace_log) {
|
||||
@ -1226,10 +1261,10 @@ static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
if (lp->mirrors != old_mimage_count)
|
||||
if (replace_mirrors && lp->mirrors != old_mimage_count)
|
||||
log_warn("WARNING: Failed to replace %d of %d images in volume %s",
|
||||
old_mimage_count - lp->mirrors, old_mimage_count, lv->name);
|
||||
if (log_count != old_log_count)
|
||||
if (replace_log && log_count != old_log_count)
|
||||
log_warn("WARNING: Failed to replace %d of %d logs in volume %s",
|
||||
old_log_count - log_count, old_log_count, lv->name);
|
||||
|
||||
|
@ -292,7 +292,7 @@ static int _detach_pvmove_mirror(struct cmd_context *cmd,
|
||||
|
||||
/* Update metadata to remove mirror segments and break dependencies */
|
||||
dm_list_init(&lvs_completed);
|
||||
if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, NULL, PVMOVE) ||
|
||||
if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, NULL, NULL, PVMOVE) ||
|
||||
!remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE,
|
||||
&lvs_completed)) {
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user