summaryrefslogtreecommitdiff
path: root/fs/iomap/buffered-io.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/iomap/buffered-io.c')
-rw-r--r--fs/iomap/buffered-io.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index bc82083e420a..92a831cf4bf1 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -80,18 +80,27 @@ static void iomap_set_range_uptodate(struct folio *folio, size_t off,
{
struct iomap_folio_state *ifs = folio->private;
unsigned long flags;
- bool uptodate = true;
+ bool mark_uptodate = true;
if (folio_test_uptodate(folio))
return;
if (ifs) {
spin_lock_irqsave(&ifs->state_lock, flags);
- uptodate = ifs_set_range_uptodate(folio, ifs, off, len);
+ /*
+ * If a read with bytes pending is in progress, we must not call
+ * folio_mark_uptodate(). The read completion path
+ * (iomap_read_end()) will call folio_end_read(), which uses XOR
+ * semantics to set the uptodate bit. If we set it here, the XOR
+ * in folio_end_read() will clear it, leaving the folio not
+ * uptodate.
+ */
+ mark_uptodate = ifs_set_range_uptodate(folio, ifs, off, len) &&
+ !ifs->read_bytes_pending;
spin_unlock_irqrestore(&ifs->state_lock, flags);
}
- if (uptodate)
+ if (mark_uptodate)
folio_mark_uptodate(folio);
}
@@ -505,6 +514,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
loff_t length = iomap_length(iter);
struct folio *folio = ctx->cur_folio;
size_t folio_len = folio_size(folio);
+ struct iomap_folio_state *ifs;
size_t poff, plen;
loff_t pos_diff;
int ret;
@@ -516,7 +526,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
return iomap_iter_advance(iter, length);
}
- ifs_alloc(iter->inode, folio, iter->flags);
+ ifs = ifs_alloc(iter->inode, folio, iter->flags);
length = min_t(loff_t, length, folio_len - offset_in_folio(folio, pos));
while (length) {
@@ -551,11 +561,15 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
*bytes_submitted += plen;
/*
- * If the entire folio has been read in by the IO
- * helper, then the helper owns the folio and will end
- * the read on it.
+ * Hand off folio ownership to the IO helper when:
+ * 1) The entire folio has been submitted for IO, or
+ * 2) There is no ifs attached to the folio
+ *
+ * Case (2) occurs when 1 << i_blkbits matches the folio
+ * size but the underlying filesystem or block device
+ * uses a smaller granularity for IO.
*/
- if (*bytes_submitted == folio_len)
+ if (*bytes_submitted == folio_len || !ifs)
ctx->cur_folio = NULL;
}