[lvm-devel] [PATCH] fix bugs in temporary mirror layer handling

Jonathan Brassow jbrassow at redhat.com
Mon Mar 21 21:29:06 UTC 2011


ack

  brassow

On Mar 19, 2011, at 6:33 PM, Petr Rockai wrote:

> Hi,
>
> while working on vgreduce --removemissing --force, I have uncovered
> about half a dozen bugs in handling mirror image removal with  
> temporary
> layers present in the mirror stack.
>
> In some cases, we could end up with a mirrored LV without a MIRRORED
> flag. In other cases, the code could wind up removing wrong number of
> mirrors. In yet other cases, we could remove the right number of
> mirrors, but fail to respect the removal preferences (i.e. keep an  
> image
> that was requested to be removed while removing an image that was
> requested to be kept). Under some circumstances, remove_mirror_images
> could also get stuck in an infinite loop.
>
> I think the proposed version of remove_mirror_images should get  
> through
> all of these above cases correctly. I have tried to explain specific
> problems in the comments in the code.
>
> The patch did not break any tests from the test suite for me. It is a
> prerequisite for vgreduce --removemissing --force, but it also fixes  
> the
> above bugs when triggered in plain lvconvert and in lvconvert -- 
> repair.
>
> Index: lib/metadata/mirror.c
> ===================================================================
> RCS file: /cvs/lvm2/LVM2/lib/metadata/mirror.c,v
> retrieving revision 1.144
> diff -u -p -r1.144 mirror.c
> --- lib/metadata/mirror.c	11 Mar 2011 14:56:56 -0000	1.144
> +++ lib/metadata/mirror.c	19 Mar 2011 23:08:58 -0000
> @@ -779,7 +779,7 @@ static int _remove_mirror_images(struct
> 				 int (*is_removable)(struct logical_volume *, void *),
> 				 void *removable_baton,
> 				 unsigned remove_log, unsigned collapse,
> -				 uint32_t *removed)
> +				 uint32_t *removed, int preferred_only)
> {
> 	uint32_t m;
> 	int32_t s;
> @@ -791,12 +791,13 @@ static int _remove_mirror_images(struct
> 	uint32_t new_area_count = mirrored_seg->area_count;
> 	struct lv_list *lvl;
> 	struct dm_list tmp_orphan_lvs;
> +	int orig_removed = num_removed;
>
> 	if (removed)
> 		*removed = 0;
>
> -	log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
> -			 PRIu32 " image(s)%s.",
> +	log_very_verbose("Reducing mirror set %s from %" PRIu32 " to %"
> +			 PRIu32 " image(s)%s.", lv->name,
> 			 old_area_count, old_area_count - num_removed,
> 			 remove_log ? " and no log volume" : "");
>
> @@ -805,12 +806,14 @@ static int _remove_mirror_images(struct
> 		return 0;
> 	}
>
> +	num_removed = 0;
> +
> 	/* Move removable_pvs to end of array */
> 	for (s = mirrored_seg->area_count - 1;
> -	     s >= 0 && old_area_count - new_area_count < num_removed;
> +	     s >= 0 && old_area_count - new_area_count < orig_removed;
> 	     s--) {
> 		sub_lv = seg_lv(mirrored_seg, s);
> -		if (!is_temporary_mirror_layer(sub_lv) &&
> +		if (!(is_temporary_mirror_layer(sub_lv) &&  
> lv_mirror_count(sub_lv) != 1) &&
> 		    is_removable(sub_lv, removable_baton)) {
> 			/*
> 			 * Check if the user is trying to pull the
> @@ -825,9 +828,13 @@ static int _remove_mirror_images(struct
> 			if (!shift_mirror_images(mirrored_seg, s))
> 				return_0;
> 			new_area_count--;
> +			num_removed ++;
> 		}
> 	}
>
> +	if (!preferred_only)
> +		num_removed = orig_removed;
> +
> 	/*
> 	 * If removable_pvs were specified, then they have been shifted
> 	 * to the end to ensure they are removed.  The remaining balance
> @@ -864,12 +871,19 @@ static int _remove_mirror_images(struct
> 		detached_log_lv = detach_mirror_log(mirrored_seg);
> 		if (!remove_layer_from_lv(lv, temp_layer_lv))
> 			return_0;
> -		lv->status &= ~MIRRORED;
> -		lv->status &= ~MIRROR_NOTSYNCED;
> 		if (collapse && !_merge_mirror_images(lv, &tmp_orphan_lvs)) {
> 			log_error("Failed to add mirror images");
> 			return 0;
> 		}
> +                /*
> +                 * No longer a mirror? Even though new_area_count  
> was 1,
> +                 * _merge_mirror_images may have resulted into lv  
> being still a
> +                 * mirror. Fix up the flags if we only have one  
> image left.
> +                 */
> +                if (lv_mirror_count(lv) == 1) {
> +                    lv->status &= ~MIRRORED;
> +                    lv->status &= ~MIRROR_NOTSYNCED;
> +                }
> 		mirrored_seg = first_seg(lv);
> 		if (remove_log && !detached_log_lv)
> 			detached_log_lv = detach_mirror_log(mirrored_seg);
> @@ -1035,7 +1049,7 @@ static int _remove_mirror_images(struct
> 		*removed = old_area_count - new_area_count;
>
> 	log_very_verbose("%" PRIu32 " image(s) removed from %s",
> -			 old_area_count - num_removed, lv->name);
> +			 old_area_count - new_area_count, lv->name);
>
> 	return 1;
> }
> @@ -1051,6 +1065,9 @@ int remove_mirror_images(struct logical_
> 	uint32_t existing_mirrors = lv_mirror_count(lv);
> 	struct logical_volume *next_lv = lv;
>
> +	int preferred_only = 1;
> +	int retries = 0;
> +
> 	num_removed = existing_mirrors - num_mirrors;
>
> 	/* num_removed can be 0 if the function is called just to remove  
> log */
> @@ -1062,17 +1079,33 @@ int remove_mirror_images(struct logical_
>
> 		if (!_remove_mirror_images(next_lv, removed_once,
> 					   is_removable, removable_baton,
> -					   remove_log, 0, &r))
> +					   remove_log, 0, &r, preferred_only))
> 			return_0;
>
> -		if (r < removed_once) {
> +		if (r < removed_once || !removed_once) {
> 			/* Some mirrors are removed from the temporary mirror,
> 			 * but the temporary layer still exists.
> 			 * Down the stack and retry for remainder. */
> 			next_lv = find_temporary_mirror(next_lv);
> +			if (!next_lv) {
> +				preferred_only = 0;
> +				next_lv = lv;
> +			}
> 		}
>
> 		num_removed -= r;
> +
> +		/*
> +		 * if there are still images to be removed, try again; this is
> +		 * required since some temporary layers may have been reduced
> +		 * to 1, at which point they are made removable, just like
> +		 * normal images
> +		 */
> +		if (!next_lv && !preferred_only && !retries && num_removed) {
> +			++ retries;
> +			preferred_only = 1;
> +		}
> +
> 	} while (next_lv && num_removed);
>
> 	if (num_removed) {
> @@ -1126,7 +1159,7 @@ int collapse_mirrored_lv(struct logical_
>
> 		if (!_remove_mirror_images(mirror_seg->lv,
> 					   mirror_seg->area_count - 1,
> -					   _no_removable_images, NULL, 0, 1, NULL)) {
> +					   _no_removable_images, NULL, 0, 1, NULL, 0)) {
> 			log_error("Failed to release mirror images");
> 			return 0;
> 		}
> @@ -1252,7 +1285,7 @@ int reconfigure_mirror_images(struct lv_
>
> 	r = _remove_mirror_images(mirrored_seg->lv, old_num_mirrors -  
> num_mirrors,
> 				  is_mirror_image_removable, removable_pvs,
> -				  remove_log, 0, NULL);
> +				  remove_log, 0, NULL, 0);
> 	if (!r)
> 		/* Unable to remove bad devices */
> 		return 0;
>
> Yours,
>   Petr
>
> -- 
> id' Ash = Ash; id' Dust = Dust; id' _ = undefined
> --
> lvm-devel mailing list
> lvm-devel at redhat.com
> https://www.redhat.com/mailman/listinfo/lvm-devel




More information about the lvm-devel mailing list