All of lore.kernel.org
 help / color / mirror / Atom feed
* [LVM2 PATCH v2] incorrect calculation of snapshot space (fwd)
@ 2013-11-29 23:15 Mikulas Patocka
  2013-12-02  9:45 ` Zdenek Kabelac
  0 siblings, 1 reply; 2+ messages in thread
From: Mikulas Patocka @ 2013-11-29 23:15 UTC (permalink / raw)
  To: lvm-devel

Hi

This is the patch for incorrect calculation of snapshot space in lvm2. 
This is the updated that checks target driver version.

We need to get this into RHEL6.5 z-stream as soon as possible because this 
bug is a regression introduced in RHEL6.5.

I created this bug for the issue: 
https://bugzilla.redhat.com/show_bug.cgi?id=1035871

The bug can be tested with this script:
#!/bin/sh
VG=vg1
lvremove -f $VG/origin
set -e
lvcreate -L 2143289344b -n origin $VG
lvcreate -n snap -c 8k -L 2304M -s $VG/origin
dd if=/dev/zero of=/dev/$VG/snap bs=1M count=2044 oflag=direct


The bug happens when these two conditions are met
* origin size is divisible by (chunk_size/16) - so that the last metadata 
  area is filled completely
* the miscalculated snapshot metadata size is divisible by extent size - 
  so that there is no padding to extent boundary which would otherwise 
  save us

Mikulas
---
 lib/metadata/snapshot_manip.c |   52 +++++++++++++++++++++++++++++++++---------
 1 file changed, 41 insertions(+), 11 deletions(-)

Index: LVM2.2.02.104/lib/metadata/snapshot_manip.c
===================================================================
--- LVM2.2.02.104.orig/lib/metadata/snapshot_manip.c	2013-11-28 19:11:00.000000000 +0100
+++ LVM2.2.02.104/lib/metadata/snapshot_manip.c	2013-11-30 00:08:29.000000000 +0100
@@ -31,7 +31,35 @@ int lv_is_cow(const struct logical_volum
 	return (!lv_is_origin(lv) && lv->snapshot) ? 1 : 0;
 }
 
-static uint64_t _cow_max_size(uint64_t origin_size, uint32_t chunk_size)
+/*
+ * Some kernels have a bug that they may leak space in the snapshot on crash.
+ * If the kernel is buggy, we add some extra space.
+ */
+static uint64_t _cow_extra_chunks(struct cmd_context *cmd, uint64_t n_chunks)
+{
+	static int space_leak_bug_fixed = -1;
+	if (space_leak_bug_fixed < 0) {
+		uint32_t maj, min, patchlevel;
+		if (!target_version("snapshot", &maj, &min, &patchlevel) &&
+		    (!module_present(cmd, "snapshot") ||
+		     !target_version("snapshot", &maj, &min, &patchlevel))) {
+			space_leak_bug_fixed = 0;
+			goto x;
+		}
+		space_leak_bug_fixed =
+			(maj > 1 ||
+			(maj == 1 && (min >= 12 ||
+				     (min == 10 && patchlevel >= 2))));
+x:;
+	}
+
+	if (space_leak_bug_fixed)
+		return 0;
+
+	return (n_chunks + 63) / 64;
+}
+
+static uint64_t _cow_max_size(struct cmd_context *cmd, uint64_t origin_size, uint32_t chunk_size)
 {
 	/* Snapshot disk layout:
 	 *    COW is divided into chunks
@@ -40,21 +68,23 @@ static uint64_t _cow_max_size(uint64_t o
 	 *        3rd. chunk is the 1st. data chunk
 	 */
 
-	/* Size of metadata for snapshot in sectors */
-	uint64_t mdata_size = ((origin_size + chunk_size - 1) / chunk_size * 16 + 511) >> SECTOR_SHIFT;
+	uint64_t origin_chunks = (origin_size + chunk_size - 1) / chunk_size;
+
+	uint64_t chunks_per_metadata_area = (uint64_t)chunk_size << (SECTOR_SHIFT - 4);
 
-	/* Sum all chunks - header + metadata size + origin size (aligned on chunk boundary) */
-	uint64_t size = chunk_size +
-		((mdata_size + chunk_size - 1) & ~(uint64_t)(chunk_size - 1)) +
-		((origin_size + chunk_size - 1) & ~(uint64_t)(chunk_size - 1));
+	/*
+	 * Note: if origin_chunks is divisible by chunks_per_metadata_area, we
+	 * need one extra metadata chunk as a terminator.
+	 */
+	uint64_t metadata_chunks = (origin_chunks + chunks_per_metadata_area) / chunks_per_metadata_area;
 
-	/* Does not overflow since size is in sectors (9 bits) */
-	return size;
+	uint64_t n_chunks = 1 + origin_chunks + metadata_chunks;
+	return (n_chunks + _cow_extra_chunks(cmd, n_chunks)) * chunk_size;
 }
 
 uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size)
 {
-	uint64_t size = _cow_max_size(origin->size, chunk_size);
+	uint64_t size = _cow_max_size(origin->vg->cmd, origin->size, chunk_size);
 	uint32_t extent_size = origin->vg->extent_size;
 	uint64_t max_size = (uint64_t) MAX_EXTENT_COUNT * extent_size;
 
@@ -70,7 +100,7 @@ uint32_t cow_max_extents(const struct lo
 int lv_is_cow_covering_origin(const struct logical_volume *lv)
 {
 	return lv_is_cow(lv) &&
-		(lv->size >= _cow_max_size(origin_from_cow(lv)->size, find_snapshot(lv)->chunk_size));
+		(lv->size >= _cow_max_size(lv->vg->cmd, origin_from_cow(lv)->size, find_snapshot(lv)->chunk_size));
 }
 
 int lv_is_visible(const struct logical_volume *lv)



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2013-12-02  9:45 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-11-29 23:15 [LVM2 PATCH v2] incorrect calculation of snapshot space (fwd) Mikulas Patocka
2013-12-02  9:45 ` Zdenek Kabelac

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.