[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[lvm-devel] [PATCH] handle transient errors in lvconvert --repair



Hi,

this is a first iteration of the transient-error handling in
lvconvert. This works by marking LVs as partial even though there are no
PVs missing -- whenever a mirror marks a leg or log as failed (in the
status string). The downside of this approach is that we never figure
which PV is failing, but that would require kernel-level support for IO
error tracking.

Yours,
   Petr.

PS: The test is rather rudimentary. On one hand, testing log failures
seems impossible because that runs into kernel lockups. I will add more
test scenarios for leg failures later, and also for leg replacement.

diff -rN -u -p old-upstream/lib/activate/activate.c new-upstream/lib/activate/activate.c
--- old-upstream/lib/activate/activate.c	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/lib/activate/activate.c	2010-04-27 17:13:20.000000000 +0200
@@ -478,6 +478,28 @@ int lv_info_by_lvid(struct cmd_context *
 /*
  * 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.
+ */
 int lv_snapshot_percent(const struct logical_volume *lv, float *percent,
 			percent_range_t *percent_range)
 {
diff -rN -u -p old-upstream/lib/activate/activate.h new-upstream/lib/activate/activate.h
--- old-upstream/lib/activate/activate.h	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/lib/activate/activate.h	2010-04-27 17:13:20.000000000 +0200
@@ -78,6 +78,7 @@ int lv_info_by_lvid(struct cmd_context *
 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.
  */
diff -rN -u -p old-upstream/lib/activate/dev_manager.c new-upstream/lib/activate/dev_manager.c
--- old-upstream/lib/activate/dev_manager.c	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/lib/activate/dev_manager.c	2010-04-27 17:13:20.000000000 +0200
@@ -526,6 +526,68 @@ static int _percent(struct dev_manager *
 	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,
+					  &params);
+		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.
  */
diff -rN -u -p old-upstream/lib/activate/dev_manager.h new-upstream/lib/activate/dev_manager.h
--- old-upstream/lib/activate/dev_manager.h	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/lib/activate/dev_manager.h	2010-04-27 17:13:20.000000000 +0200
@@ -57,6 +57,7 @@ int dev_manager_activate(struct dev_mana
 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);
 
diff -rN -u -p old-upstream/lib/metadata/metadata.c new-upstream/lib/metadata/metadata.c
--- old-upstream/lib/metadata/metadata.c	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/lib/metadata/metadata.c	2010-04-27 17:13:20.000000000 +0200
@@ -2095,7 +2095,7 @@ static int _lv_mark_if_partial(struct lo
  * 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;
@@ -2632,7 +2632,7 @@ static struct volume_group *_vg_read(str
 		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;
@@ -2923,7 +2923,7 @@ static struct volume_group *_vg_read(str
 	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()) {
diff -rN -u -p old-upstream/lib/metadata/metadata-exported.h new-upstream/lib/metadata/metadata-exported.h
--- old-upstream/lib/metadata/metadata-exported.h	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/lib/metadata/metadata-exported.h	2010-04-27 17:13:20.000000000 +0200
@@ -687,7 +687,8 @@ int lv_split_mirror_images(struct logica
 			   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);
@@ -701,7 +702,8 @@ int add_mirrors_to_segments(struct cmd_c
 			    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,
diff -rN -u -p old-upstream/lib/metadata/metadata.h new-upstream/lib/metadata/metadata.h
--- old-upstream/lib/metadata/metadata.h	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/lib/metadata/metadata.h	2010-04-27 17:13:20.000000000 +0200
@@ -377,5 +377,7 @@ struct id pv_vgid(const struct physical_
 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
diff -rN -u -p old-upstream/lib/metadata/mirror.c new-upstream/lib/metadata/mirror.c
--- old-upstream/lib/metadata/mirror.c	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/lib/metadata/mirror.c	2010-04-27 17:13:20.000000000 +0200
@@ -427,14 +427,17 @@ struct logical_volume *detach_mirror_log
 }
 
 /* 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++) {
@@ -500,7 +503,7 @@ static int _move_removable_mimages_to_en
 			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--;
@@ -746,13 +749,13 @@ static int _split_mirror_images(struct l
  */
 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;
@@ -762,9 +765,6 @@ static int _remove_mirror_images(struct 
 	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;
 
@@ -773,40 +773,36 @@ static int _remove_mirror_images(struct 
 			 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 && (is_removable || (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;
-	} else
-		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);
@@ -942,7 +938,8 @@ static int _remove_mirror_images(struct 
  * 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);
@@ -958,7 +955,8 @@ int remove_mirror_images(struct logical_
 			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) {
@@ -1017,7 +1015,7 @@ int collapse_mirrored_lv(struct logical_
 
 		if (!_remove_mirror_images(mirror_seg->lv,
 					   mirror_seg->area_count - 1,
-					   NULL, 1, 1, NULL)) {
+					   NULL, NULL, 1, 1, NULL)) {
 			log_error("Failed to release mirror images");
 			return 0;
 		}
@@ -1142,7 +1140,8 @@ int reconfigure_mirror_images(struct lv_
 	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;
@@ -1535,7 +1534,7 @@ int remove_mirror_log(struct cmd_context
 	}
 
 	if (!remove_mirror_images(lv, lv_mirror_count(lv),
-				  removable_pvs, 1U))
+				  is_mirror_image_removable, removable_pvs, 1U))
 		return_0;
 
 	return 1;
@@ -1915,7 +1914,9 @@ int lv_split_mirror_images(struct logica
  */
 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;
@@ -1943,7 +1944,8 @@ int lv_remove_mirrors(struct cmd_context
 	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) {
diff -rN -u -p old-upstream/lib/metadata/segtype.h new-upstream/lib/metadata/segtype.h
--- old-upstream/lib/metadata/segtype.h	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/lib/metadata/segtype.h	2010-04-27 17:13:20.000000000 +0200
@@ -78,6 +78,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,
diff -rN -u -p old-upstream/lib/mirror/mirrored.c new-upstream/lib/mirror/mirrored.c
--- old-upstream/lib/mirror/mirrored.c	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/lib/mirror/mirrored.c	2010-04-27 17:13:20.000000000 +0200
@@ -239,6 +239,103 @@ static int _mirrored_target_percent(void
 	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;
+
+	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 (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 +661,7 @@ static struct segtype_handler _mirrored_
 	.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,
diff -rN -u -p old-upstream/libdm/regex/parse_rx.c new-upstream/libdm/regex/parse_rx.c
--- old-upstream/libdm/regex/parse_rx.c	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/libdm/regex/parse_rx.c	2010-04-27 17:13:20.000000000 +0200
@@ -555,25 +555,25 @@ static struct rx_node *_pass(struct dm_p
 	 */
 	switch (r->type) {
 	case CAT:
-		if (!(r->left = _pass(mem, r->left, changed)))
-			return_NULL;
+		/*if (!(r->left = _pass(mem, r->left, changed)))
+		  return_NULL;*/
 
 		if (!(r->right = _pass(mem, r->right, changed)))
 			return_NULL;
 
 		break;
 
-	case STAR:
+		/*case STAR:
 	case PLUS:
 	case QUEST:
 		if (!(r->left = _pass(mem, r->left, changed)))
 			return_NULL;
-		break;
+			break;*/
 
 	case OR:
 		/* It's important we optimise sub nodes first */
-		if (!(r->left = _pass(mem, r->left, changed)))
-			return_NULL;
+		/*if (!(r->left = _pass(mem, r->left, changed)))
+		  return_NULL;*/
 
 		if (!(r->right = _pass(mem, r->right, changed)))
 			return_NULL;
@@ -595,7 +595,7 @@ static struct rx_node *_pass(struct dm_p
 		}
 		break;
 
-	case CHARSET:
+	default:
 		break;
 	}
 
diff -rN -u -p old-upstream/old-tests/regex/Makefile.in new-upstream/old-tests/regex/Makefile.in
--- old-upstream/old-tests/regex/Makefile.in	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/old-tests/regex/Makefile.in	2010-04-27 17:13:20.000000000 +0200
@@ -28,7 +28,7 @@ include $(top_builddir)/make.tmpl
 
 INCLUDES += -I$(top_srcdir)/libdm
 DM_DEPS = $(top_builddir)/libdm/libdevmapper.so
-DM_LIBS = -ldevmapper $(LIBS)
+DM_LIBS = -static -ldevmapper $(LIBS) -L$(top_builddir)/libdm/ioctl/
 
 parse_t: parse_t.o $(DM_DEPS)
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ parse_t.o $(DM_LIBS)
diff -rN -u -p old-upstream/test/t-lvconvert-repair-transient.sh new-upstream/test/t-lvconvert-repair-transient.sh
--- old-upstream/test/t-lvconvert-repair-transient.sh	1970-01-01 01:00:00.000000000 +0100
+++ new-upstream/test/t-lvconvert-repair-transient.sh	2010-04-27 17:13:20.000000000 +0200
@@ -0,0 +1,38 @@
+#!/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
+
+lvcreate -m 2 --ig -L 1 -n 4way2 --mirrorlog disk $vg
+disable_dev $dev5
+mkfs.ext3 $DM_DEV_DIR/$vg/4way2
+enable_dev $dev5
+echo n | lvconvert --repair $vg/4way2 2>&1 | tee 4way2.out
+lvs -a -o +devices
+exit 1
+vgreduce --removemissing $vg
+check mirror $vg 4way2
+lvchange -a n $vg/4way2
+
diff -rN -u -p old-upstream/tools/lvconvert.c new-upstream/tools/lvconvert.c
--- old-upstream/tools/lvconvert.c	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/tools/lvconvert.c	2010-04-27 17:13:20.000000000 +0200
@@ -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,13 @@ static struct dm_list *_failed_pv_list(s
 	return failed_pvs;
 }
 
+static int _is_partial_lv(struct logical_volume *lv, void *unused)
+{
+	(void) unused;
+	log_error("_is_partial_lv: %s: %d", lv->name, lv->status & PARTIAL_LV ? 1 : 0);
+	return lv->status & PARTIAL_LV;
+}
+
 /*
  * Walk down the stacked mirror LV to the original mirror LV.
  */
@@ -727,7 +735,7 @@ static int _lv_update_log_type(struct cm
 	}
 
 	/* 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 +921,34 @@ static int _lvconvert_mirrors_parse_para
 	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
  *
@@ -1064,7 +1100,7 @@ static int _lvconvert_mirrors_aux(struct
 						    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 +1120,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 +1154,8 @@ static int _lvconvert_mirrors_repair(str
 	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,9 +1212,14 @@ static int _lvconvert_mirrors_repair(str
 	if (!_lv_update_log_type(cmd, lp, lv, failed_pvs, new_log_count))
 		return 0;
 
-	if (!_lvconvert_mirrors_aux(cmd, lv, lp, failed_pvs,
-				    lp->mirrors, new_log_count))
-		return 0;
+	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;
+	}
 
 	/*
 	 * Second phase - replace faulty devices
diff -rN -u -p old-upstream/tools/pvmove.c new-upstream/tools/pvmove.c
--- old-upstream/tools/pvmove.c	2010-04-27 17:13:20.000000000 +0200
+++ new-upstream/tools/pvmove.c	2010-04-27 17:13:20.000000000 +0200
@@ -292,7 +292,7 @@ static int _detach_pvmove_mirror(struct 
 
 	/* 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;

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]