Blame SOURCES/lvm2-2_02_187-Fix-rounding-writes-up-to-sector-size.patch

f507f1
From 12041b03584bb2fa36f797ece4b0f9a41760a303 Mon Sep 17 00:00:00 2001
f507f1
From: David Teigland <teigland@redhat.com>
f507f1
Date: Wed, 24 Jul 2019 11:32:13 -0500
f507f1
Subject: [PATCH 2/4] Fix rounding writes up to sector size
f507f1
f507f1
Do this at two levels, although one would be enough to
f507f1
fix the problem seen recently:
f507f1
f507f1
- Ignore any reported sector size other than 512 of 4096.
f507f1
  If either sector size (physical or logical) is reported
f507f1
  as 512, then use 512.  If neither are reported as 512,
f507f1
  and one or the other is reported as 4096, then use 4096.
f507f1
  If neither is reported as either 512 or 4096, then use 512.
f507f1
f507f1
- When rounding up a limited write in bcache to be a multiple
f507f1
  of the sector size, check that the resulting write size is
f507f1
  not larger than the bcache block itself.  (This shouldn't
f507f1
  happen if the sector size is 512 or 4096.)
f507f1
f507f1
(cherry picked from commit 7550665ba49ac7d497d5b212e14b69298ef01361)
f507f1
f507f1
Conflicts:
f507f1
	lib/device/dev-io.c
f507f1
f507f1
(cherry picked from commit 44c460954be5c63cf5338bd9151344fe2626565f)
f507f1
---
f507f1
 lib/device/bcache.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++--
f507f1
 1 file changed, 87 insertions(+), 2 deletions(-)
f507f1
f507f1
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
f507f1
index b64707e..77d1543 100644
f507f1
--- a/lib/device/bcache.c
f507f1
+++ b/lib/device/bcache.c
f507f1
@@ -169,6 +169,7 @@ static bool _async_issue(struct io_engine *ioe, enum dir d, int fd,
f507f1
 	sector_t offset;
f507f1
 	sector_t nbytes;
f507f1
 	sector_t limit_nbytes;
f507f1
+	sector_t orig_nbytes;
f507f1
 	sector_t extra_nbytes = 0;
f507f1
 
f507f1
 	if (((uintptr_t) data) & e->page_mask) {
f507f1
@@ -191,11 +192,41 @@ static bool _async_issue(struct io_engine *ioe, enum dir d, int fd,
f507f1
 			return false;
f507f1
 		}
f507f1
 
f507f1
+		/*
f507f1
+		 * If the bcache block offset+len goes beyond where lvm is
f507f1
+		 * intending to write, then reduce the len being written
f507f1
+		 * (which is the bcache block size) so we don't write past
f507f1
+		 * the limit set by lvm.  If after applying the limit, the
f507f1
+		 * resulting size is not a multiple of the sector size (512
f507f1
+		 * or 4096) then extend the reduced size to be a multiple of
f507f1
+		 * the sector size (we don't want to write partial sectors.)
f507f1
+		 */
f507f1
 		if (offset + nbytes > _last_byte_offset) {
f507f1
 			limit_nbytes = _last_byte_offset - offset;
f507f1
-			if (limit_nbytes % _last_byte_sector_size)
f507f1
+
f507f1
+			if (limit_nbytes % _last_byte_sector_size) {
f507f1
 				extra_nbytes = _last_byte_sector_size - (limit_nbytes % _last_byte_sector_size);
f507f1
 
f507f1
+				/*
f507f1
+				 * adding extra_nbytes to the reduced nbytes (limit_nbytes)
f507f1
+				 * should make the final write size a multiple of the
f507f1
+				 * sector size.  This should never result in a final size
f507f1
+				 * larger than the bcache block size (as long as the bcache
f507f1
+				 * block size is a multiple of the sector size).
f507f1
+				 */
f507f1
+				if (limit_nbytes + extra_nbytes > nbytes) {
f507f1
+					log_warn("Skip extending write at %llu len %llu limit %llu extra %llu sector_size %llu",
f507f1
+						 (unsigned long long)offset,
f507f1
+						 (unsigned long long)nbytes,
f507f1
+						 (unsigned long long)limit_nbytes,
f507f1
+						 (unsigned long long)extra_nbytes,
f507f1
+						 (unsigned long long)_last_byte_sector_size);
f507f1
+					extra_nbytes = 0;
f507f1
+				}
f507f1
+			}
f507f1
+
f507f1
+			orig_nbytes = nbytes;
f507f1
+
f507f1
 			if (extra_nbytes) {
f507f1
 				log_debug("Limit write at %llu len %llu to len %llu rounded to %llu",
f507f1
 					  (unsigned long long)offset,
f507f1
@@ -210,6 +241,22 @@ static bool _async_issue(struct io_engine *ioe, enum dir d, int fd,
f507f1
 					  (unsigned long long)limit_nbytes);
f507f1
 				nbytes = limit_nbytes;
f507f1
 			}
f507f1
+
f507f1
+			/*
f507f1
+			 * This shouldn't happen, the reduced+extended
f507f1
+			 * nbytes value should never be larger than the
f507f1
+			 * bcache block size.
f507f1
+			 */
f507f1
+			if (nbytes > orig_nbytes) {
f507f1
+				log_error("Invalid adjusted write at %llu len %llu adjusted %llu limit %llu extra %llu sector_size %llu",
f507f1
+					  (unsigned long long)offset,
f507f1
+					  (unsigned long long)orig_nbytes,
f507f1
+					  (unsigned long long)nbytes,
f507f1
+					  (unsigned long long)limit_nbytes,
f507f1
+					  (unsigned long long)extra_nbytes,
f507f1
+					  (unsigned long long)_last_byte_sector_size);
f507f1
+				return false;
f507f1
+			}
f507f1
 		}
f507f1
 	}
f507f1
 
f507f1
@@ -403,6 +450,7 @@ static bool _sync_issue(struct io_engine *ioe, enum dir d, int fd,
f507f1
 		uint64_t nbytes = len;
f507f1
 		sector_t limit_nbytes = 0;
f507f1
 		sector_t extra_nbytes = 0;
f507f1
+		sector_t orig_nbytes = 0;
f507f1
 
f507f1
 		if (offset > _last_byte_offset) {
f507f1
 			log_error("Limit write at %llu len %llu beyond last byte %llu",
f507f1
@@ -415,9 +463,30 @@ static bool _sync_issue(struct io_engine *ioe, enum dir d, int fd,
f507f1
 
f507f1
 		if (offset + nbytes > _last_byte_offset) {
f507f1
 			limit_nbytes = _last_byte_offset - offset;
f507f1
-			if (limit_nbytes % _last_byte_sector_size)
f507f1
+
f507f1
+			if (limit_nbytes % _last_byte_sector_size) {
f507f1
 				extra_nbytes = _last_byte_sector_size - (limit_nbytes % _last_byte_sector_size);
f507f1
 
f507f1
+				/*
f507f1
+				 * adding extra_nbytes to the reduced nbytes (limit_nbytes)
f507f1
+				 * should make the final write size a multiple of the
f507f1
+				 * sector size.  This should never result in a final size
f507f1
+				 * larger than the bcache block size (as long as the bcache
f507f1
+				 * block size is a multiple of the sector size).
f507f1
+				 */
f507f1
+				if (limit_nbytes + extra_nbytes > nbytes) {
f507f1
+					log_warn("Skip extending write at %llu len %llu limit %llu extra %llu sector_size %llu",
f507f1
+						 (unsigned long long)offset,
f507f1
+						 (unsigned long long)nbytes,
f507f1
+						 (unsigned long long)limit_nbytes,
f507f1
+						 (unsigned long long)extra_nbytes,
f507f1
+						 (unsigned long long)_last_byte_sector_size);
f507f1
+					extra_nbytes = 0;
f507f1
+				}
f507f1
+			}
f507f1
+
f507f1
+			orig_nbytes = nbytes;
f507f1
+
f507f1
 			if (extra_nbytes) {
f507f1
 				log_debug("Limit write at %llu len %llu to len %llu rounded to %llu",
f507f1
 					  (unsigned long long)offset,
f507f1
@@ -432,6 +501,22 @@ static bool _sync_issue(struct io_engine *ioe, enum dir d, int fd,
f507f1
 					  (unsigned long long)limit_nbytes);
f507f1
 				nbytes = limit_nbytes;
f507f1
 			}
f507f1
+
f507f1
+			/*
f507f1
+			 * This shouldn't happen, the reduced+extended
f507f1
+			 * nbytes value should never be larger than the
f507f1
+			 * bcache block size.
f507f1
+			 */
f507f1
+			if (nbytes > orig_nbytes) {
f507f1
+				log_error("Invalid adjusted write at %llu len %llu adjusted %llu limit %llu extra %llu sector_size %llu",
f507f1
+					  (unsigned long long)offset,
f507f1
+					  (unsigned long long)orig_nbytes,
f507f1
+					  (unsigned long long)nbytes,
f507f1
+					  (unsigned long long)limit_nbytes,
f507f1
+					  (unsigned long long)extra_nbytes,
f507f1
+					  (unsigned long long)_last_byte_sector_size);
f507f1
+				return false;
f507f1
+			}
f507f1
 		}
f507f1
 
f507f1
 		where = offset;
f507f1
-- 
f507f1
1.8.3.1
f507f1