78 lines
3.1 KiB
Diff
78 lines
3.1 KiB
Diff
From 0623d1f6690209880885deae614e8368488598c2 Mon Sep 17 00:00:00 2001
|
|
From: Dominique Martinet <asmadeus@codewreck.org>
|
|
Date: Wed, 13 Aug 2025 15:04:55 +0900
|
|
Subject: iov_iter: iterate_folioq: fix handling of offset >= folio size
|
|
|
|
It's apparently possible to get an iov advanced all the way up to the end
|
|
of the current page we're looking at, e.g.
|
|
|
|
(gdb) p *iter
|
|
$24 = {iter_type = 4 '\004', nofault = false, data_source = false, iov_offset = 4096, {__ubuf_iovec = {
|
|
iov_base = 0xffff88800f5bc000, iov_len = 655}, {{__iov = 0xffff88800f5bc000, kvec = 0xffff88800f5bc000,
|
|
bvec = 0xffff88800f5bc000, folioq = 0xffff88800f5bc000, xarray = 0xffff88800f5bc000,
|
|
ubuf = 0xffff88800f5bc000}, count = 655}}, {nr_segs = 2, folioq_slot = 2 '\002', xarray_start = 2}}
|
|
|
|
Where iov_offset is 4k with 4k-sized folios
|
|
|
|
This should have been fine because we're only in the 2nd slot and there's
|
|
another one after this, but iterate_folioq should not try to map a folio
|
|
that skips the whole size, and more importantly part here does not end up
|
|
zero (because 'PAGE_SIZE - skip % PAGE_SIZE' ends up PAGE_SIZE and not
|
|
zero..), so skip forward to the "advance to next folio" code
|
|
|
|
Link: https://lkml.kernel.org/r/20250813-iot_iter_folio-v3-0-a0ffad2b665a@codewreck.org
|
|
Link: https://lkml.kernel.org/r/20250813-iot_iter_folio-v3-1-a0ffad2b665a@codewreck.org
|
|
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
|
|
Fixes: db0aa2e9566f ("mm: Define struct folio_queue and ITER_FOLIOQ to handle a sequence of folios")
|
|
Reported-by: Maximilian Bosch <maximilian@mbosch.me>
|
|
Reported-by: Ryan Lahfa <ryan@lahfa.xyz>
|
|
Reported-by: Christian Theune <ct@flyingcircus.io>
|
|
Reported-by: Arnout Engelen <arnout@bzzt.net>
|
|
Link: https://lkml.kernel.org/r/D4LHHUNLG79Y.12PI0X6BEHRHW@mbosch.me/
|
|
Acked-by: David Howells <dhowells@redhat.com>
|
|
Cc: Al Viro <viro@zeniv.linux.org.uk>
|
|
Cc: Christian Brauner <brauner@kernel.org>
|
|
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
|
|
Cc: <stable@vger.kernel.org> [6.12+]
|
|
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
|
---
|
|
include/linux/iov_iter.h | 20 +++++++++++---------
|
|
1 file changed, 11 insertions(+), 9 deletions(-)
|
|
|
|
--- a/include/linux/iov_iter.h
|
|
+++ b/include/linux/iov_iter.h
|
|
@@ -160,7 +160,7 @@ size_t iterate_folioq(struct iov_iter *i
|
|
|
|
do {
|
|
struct folio *folio = folioq_folio(folioq, slot);
|
|
- size_t part, remain, consumed;
|
|
+ size_t part, remain = 0, consumed;
|
|
size_t fsize;
|
|
void *base;
|
|
|
|
@@ -168,14 +168,16 @@ size_t iterate_folioq(struct iov_iter *i
|
|
break;
|
|
|
|
fsize = folioq_folio_size(folioq, slot);
|
|
- base = kmap_local_folio(folio, skip);
|
|
- part = umin(len, PAGE_SIZE - skip % PAGE_SIZE);
|
|
- remain = step(base, progress, part, priv, priv2);
|
|
- kunmap_local(base);
|
|
- consumed = part - remain;
|
|
- len -= consumed;
|
|
- progress += consumed;
|
|
- skip += consumed;
|
|
+ if (skip < fsize) {
|
|
+ base = kmap_local_folio(folio, skip);
|
|
+ part = umin(len, PAGE_SIZE - skip % PAGE_SIZE);
|
|
+ remain = step(base, progress, part, priv, priv2);
|
|
+ kunmap_local(base);
|
|
+ consumed = part - remain;
|
|
+ len -= consumed;
|
|
+ progress += consumed;
|
|
+ skip += consumed;
|
|
+ }
|
|
if (skip >= fsize) {
|
|
skip = 0;
|
|
slot++;
|