Thread (24 messages) 24 messages, 5 authors, 2020-01-11

Re: [PATCH] block: fix splitting segments

From: Guenter Roeck <linux@roeck-us.net>
Date: 2020-01-07 23:06:36
Also in: lkml

On Wed, Jan 08, 2020 at 06:30:35AM +0800, Ming Lei wrote:
On Tue, Jan 07, 2020 at 10:11:45AM -0800, Guenter Roeck wrote:
quoted
On Tue, Jan 07, 2020 at 11:23:39PM +0800, Ming Lei wrote:
quoted
On Tue, Jan 07, 2020 at 04:47:08AM -0800, Guenter Roeck wrote:
quoted
Hi,

On Sun, Dec 29, 2019 at 10:32:30AM +0800, Ming Lei wrote:
quoted
There are two issues in get_max_segment_size():

1) the default segment boudary mask is bypassed, and some devices still
require segment to not cross the default 4G boundary

2) the segment start address isn't taken into account when checking
segment boundary limit

Fixes the two issues.

Fixes: dcebd755926b ("block: use bio_for_each_bvec() to compute multi-page bvec count")
Signed-off-by: Ming Lei <redacted>
This patch, pushed into mainline as "block: fix splitting segments on
boundary masks", results in the following crash when booting 'versatilepb'
in qemu from disk. Bisect log is attached. Detailed log is at
https://kerneltests.org/builders/qemu-arm-master/builds/1410/steps/qemubuildcommand/logs/stdio

Guenter

---
Crash:

kernel BUG at block/bio.c:1885!
Internal error: Oops - BUG: 0 [#1] ARM
Please apply the following debug patch, and post the log.
Here you are:

max_sectors 2560 max_segs 96 max_seg_size 65536 mask ffffffff
c738da80: 8c80/0 2416 28672, 0
         total sectors 56

(I replaced %p with %px).
Please try the following patch and see if it makes a difference.
If not, replace trace_printk with printk in previous debug patch,
and apply the debug patch only & post the log.
The patch below fixes the problem for me.

Tested-by: Guenter Roeck <linux@roeck-us.net>

Guenter
quoted hunk ↗ jump to hunk
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 347782a24a35..f152bdee9b05 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -159,12 +159,12 @@ static inline unsigned get_max_io_size(struct request_queue *q,
 
 static inline unsigned get_max_segment_size(const struct request_queue *q,
 					    struct page *start_page,
-					    unsigned long offset)
+					    unsigned long long offset)
 {
 	unsigned long mask = queue_segment_boundary(q);
 
 	offset = mask & (page_to_phys(start_page) + offset);
-	return min_t(unsigned long, mask - offset + 1,
+	return min_t(unsigned long long, mask - offset + 1,
 		     queue_max_segment_size(q));
 }
 
Thanks,
Ming
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help