netfs: Fix netfs_read_gaps() to use separate sink folios

Fix netfs_read_gaps() to use separate folios rather than re-using a single
sink folio to discard the unwanted data so that cifs checksum checking sees
all the data that was fetched.

Fixes: 7f84a7b989 ("netfs: Make netfs_read_folio() handle streaming-write pages")
Reported-by: Frank Sorenson <sorenson@redhat.com>
Closes: https://lore.kernel.org/r/a385053c-1c4a-4060-a3bb-befa007ddb33@redhat.com/
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/3228134.1789399227@warthog.procyon.org.uk
Tested-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Paulo Alcantara <pc@manguebit.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Namjae Jeon <linkinjeon@kernel.org>
cc: netfs@lists.linux.dev
cc: linux-cifs@vger.kernel.org
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
David Howells 2026-09-14 16:20:27 +01:00 committed by Christian Brauner
parent 1f7745fb35
commit fc3ae66514
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2

View File

@ -482,15 +482,14 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
struct netfs_group *group = netfs_folio_group(folio);
struct netfs_folio *finfo = netfs_folio_info(folio);
struct netfs_inode *ctx = netfs_inode(mapping->host);
struct folio *sink = NULL;
struct bio_vec *bvec;
struct bio_vec *bvec = NULL;
unsigned int from = finfo->dirty_offset;
unsigned int to = from + finfo->dirty_len;
unsigned int off = 0, i = 0;
unsigned int off = 0;
size_t flen = folio_size(folio);
size_t nr_bvec = flen / PAGE_SIZE + 2;
size_t part;
int ret;
int ret, i = 0, sink_from = -1, sink_to = -1;
_enter("%lx", folio->index);
@ -515,24 +514,23 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
if (!bvec)
goto discard;
sink = folio_alloc(GFP_KERNEL, 0);
if (!sink) {
kfree(bvec);
goto discard;
}
trace_netfs_folio(folio, netfs_folio_trace_read_gaps);
rreq->direct_bv = bvec;
rreq->direct_bv_count = nr_bvec;
if (from > 0) {
bvec_set_folio(&bvec[i++], folio, from, 0);
off = from;
}
sink_from = i;
while (off < to) {
struct folio *sink = folio_alloc(GFP_KERNEL, 0);
if (!sink)
goto discard;
part = min_t(size_t, to - off, PAGE_SIZE);
bvec_set_folio(&bvec[i++], sink, part, 0);
bvec_set_folio(&bvec[i], sink, part, 0);
off += part;
sink_to = i;
i++;
}
if (to < flen)
bvec_set_folio(&bvec[i++], folio, flen - to, to);
@ -553,8 +551,10 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
folio_mark_uptodate(folio);
}
if (sink)
folio_put(sink);
if (sink_to >= 0)
for (; sink_from <= sink_to; sink_from++)
folio_put(bvec_folio(&bvec[sink_from]));
kfree(bvec);
folio_unlock(folio);
netfs_put_request(rreq, netfs_rreq_trace_put_return);
return ret < 0 ? ret : 0;
@ -563,6 +563,10 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
netfs_put_failed_request(rreq);
alloc_error:
folio_unlock(folio);
if (sink_to >= 0)
for (; sink_from <= sink_to; sink_from++)
folio_put(bvec_folio(&bvec[sink_from]));
kfree(bvec);
return ret;
}