summaryrefslogtreecommitdiff
path: root/fs/netfs/read_collect.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/netfs/read_collect.c')
-rw-r--r--fs/netfs/read_collect.c26
1 files changed, 14 insertions, 12 deletions
diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c
index e70eb4ea21c0..eae415efae24 100644
--- a/fs/netfs/read_collect.c
+++ b/fs/netfs/read_collect.c
@@ -249,9 +249,9 @@ donation_changed:
/* Deal with the trickiest case: that this subreq is in the middle of a
* folio, not touching either edge, but finishes first. In such a
- * case, we donate to the previous subreq, if there is one, so that the
- * donation is only handled when that completes - and remove this
- * subreq from the list.
+ * case, we donate to the previous subreq, if there is one and if it is
+ * contiguous, so that the donation is only handled when that completes
+ * - and remove this subreq from the list.
*
* If the previous subreq finished first, we will have acquired their
* donation and should be able to unlock folios and/or donate nextwards.
@@ -260,14 +260,16 @@ donation_changed:
!prev_donated &&
!list_is_first(&subreq->rreq_link, &rreq->subrequests)) {
prev = list_prev_entry(subreq, rreq_link);
- WRITE_ONCE(prev->next_donated, prev->next_donated + subreq->len);
- subreq->start += subreq->len;
- subreq->len = 0;
- subreq->transferred = 0;
- trace_netfs_donate(rreq, subreq, prev, subreq->len,
- netfs_trace_donate_to_prev);
- trace_netfs_sreq(subreq, netfs_sreq_trace_donate_to_prev);
- goto remove_subreq_locked;
+ if (subreq->start == prev->start + prev->len) {
+ WRITE_ONCE(prev->next_donated, prev->next_donated + subreq->len);
+ subreq->start += subreq->len;
+ subreq->len = 0;
+ subreq->transferred = 0;
+ trace_netfs_donate(rreq, subreq, prev, subreq->len,
+ netfs_trace_donate_to_prev);
+ trace_netfs_sreq(subreq, netfs_sreq_trace_donate_to_prev);
+ goto remove_subreq_locked;
+ }
}
/* If we can't donate down the chain, donate up the chain instead. */
@@ -282,7 +284,7 @@ donation_changed:
netfs_trace_donate_to_deferred_next);
} else {
next = list_next_entry(subreq, rreq_link);
- WRITE_ONCE(next->prev_donated, excess);
+ WRITE_ONCE(next->prev_donated, next->prev_donated + excess);
trace_netfs_donate(rreq, subreq, next, excess,
netfs_trace_donate_to_next);
}