[linux-lvm] [Patch 1/1] Fix mirror region_size calculation.

Jonathan Brassow jbrassow at redhat.com
Thu Nov 9 17:00:46 UTC 2006


This patch fixes 214604 and 214302 (http://bugzilla.redhat.com).

 brassow

region_size is a 32-bit value.  Sometimes, when computing the maximum
possible region_size for large volumes, 32-bits can be exceeded.  We
now cap the maximum region_size at 2^31 (the max power of 2 that can
be held in a 32-bit number).

Additionally, while waiting for a fix to allow for log devices
greater than 1 extent, we also adjust the minimum region_size.
By increasing the region_size, we can get by with log devices
that maintain a size of 1 extent for now.

Index: LVM2/lib/metadata/mirror.c
===================================================================
--- LVM2.orig/lib/metadata/mirror.c	2006-11-08 14:18:33.000000000 -0600
+++ LVM2/lib/metadata/mirror.c	2006-11-09 10:51:11.000000000 -0600
@@ -36,20 +36,44 @@ struct lv_segment *find_mirror_seg(struc
 }
 
 /*
- * Ensure region size is compatible with volume size.
+ * adjusted_mirror_region_size
+ * @extent_size: The size of an extent in sectors
+ * @extents: The number of extents in the LV
+ * @region_size: The current guess at an appropriate region size
+ *
+ * The maximum region size must be the largest power of 2 that
+ * evenly divides into the total size given by extent_size * extents.
+ *
+ * The suggested minumum region size should be a number where the
+ * number of regions is less than the number of bits in an extent.
+ *
+ * Returns: suggested region_size, or 0 on failure to find good region size
  */
 uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
 				     uint32_t region_size)
 {
-	uint32_t region_max;
+	uint32_t region_max, region_min;
 
-	region_max = (1 << (ffs((int)extents) - 1)) * extent_size;
+	region_max = ffs((int)extents) + ffs((int)extent_size) - 2;
+	/* cap region_max at the max power of 2 that can be held in 32 bits */
+	region_max = (region_max > 31) ? (1 << 31) : (1 << region_max);
+
+	/* Leave some extra room for the log header before the bits... */
+	for (region_min = region_size;
+	     (extents/region_min) > (1 << SECTOR_SHIFT);
+	     region_min *= 2);
 
 	if (region_max < region_size) {
 		region_size = region_max;
 		log_print("Using reduced mirror region size of %" PRIu32
 			  " sectors", region_max);
-		return region_max;
+	} else if (region_min > region_size) {
+		region_size = region_min;
+		if (region_size <= region_max)
+			log_print("Using minimum mirror region size of %" PRIu32
+				  " sectors", region_min);
+		else
+			region_size = 0;
 	}
 
 	return region_size;
Index: LVM2/tools/lvconvert.c
===================================================================
--- LVM2.orig/tools/lvconvert.c	2006-10-24 13:50:29.000000000 -0500
+++ LVM2/tools/lvconvert.c	2006-11-09 09:12:28.000000000 -0600
@@ -388,6 +388,11 @@ static int lvconvert_mirrors(struct cmd_
 								      lv->le_count,
 								      lp->region_size);
 
+			if (!lp->region_size) {
+				log_error("Failed to find valid region size");
+				return 0;
+			}
+
 			log_lv = NULL;
 			if (!arg_count(cmd, corelog_ARG) &&
 			    !(log_lv = create_mirror_log(cmd, lv->vg, ah,
Index: LVM2/tools/lvcreate.c
===================================================================
--- LVM2.orig/tools/lvcreate.c	2006-10-18 13:01:53.000000000 -0500
+++ LVM2/tools/lvcreate.c	2006-11-09 09:10:22.000000000 -0600
@@ -678,6 +678,11 @@ static int _lvcreate(struct cmd_context 
 							      lp->extents,
 							      lp->region_size);
 
+		if (!lp->region_size) {
+			log_error("Failed to find valid region size");
+			return 0;
+		}
+
 		init_mirror_in_sync(lp->nosync);
 
 		if (lp->nosync) {





More information about the linux-lvm mailing list