Skip to content

Commit fe27d18

Browse files
committed
Merge tag 'folio-5.18f' of git://git.infradead.org/users/willy/pagecache
Pull folio fixes from Matthew Wilcox: "Two folio fixes for 5.18. Darrick and Brian have done amazing work debugging the race I created in the folio BIO iterator. The readahead problem was deterministic, so easy to fix. - Fix a race when we were calling folio_next() in the BIO folio iter without holding a reference, meaning the folio could be split or freed, and we'd jump to the next page instead of the intended next folio. - Fix readahead creating single-page folios instead of the intended large folios when doing reads that are not a power of two in size" * tag 'folio-5.18f' of git://git.infradead.org/users/willy/pagecache: mm/readahead: Fix readahead with large folios block: Do not call folio_next() on an unreferenced folio
2 parents f47c960 + b9ff43d commit fe27d18

File tree

2 files changed

+13
-7
lines changed

2 files changed

+13
-7
lines changed

include/linux/bio.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ struct folio_iter {
269269
size_t offset;
270270
size_t length;
271271
/* private: for use by the iterator */
272+
struct folio *_next;
272273
size_t _seg_count;
273274
int _i;
274275
};
@@ -283,16 +284,18 @@ static inline void bio_first_folio(struct folio_iter *fi, struct bio *bio,
283284
PAGE_SIZE * (bvec->bv_page - &fi->folio->page);
284285
fi->_seg_count = bvec->bv_len;
285286
fi->length = min(folio_size(fi->folio) - fi->offset, fi->_seg_count);
287+
fi->_next = folio_next(fi->folio);
286288
fi->_i = i;
287289
}
288290

289291
static inline void bio_next_folio(struct folio_iter *fi, struct bio *bio)
290292
{
291293
fi->_seg_count -= fi->length;
292294
if (fi->_seg_count) {
293-
fi->folio = folio_next(fi->folio);
295+
fi->folio = fi->_next;
294296
fi->offset = 0;
295297
fi->length = min(folio_size(fi->folio), fi->_seg_count);
298+
fi->_next = folio_next(fi->folio);
296299
} else if (fi->_i + 1 < bio->bi_vcnt) {
297300
bio_first_folio(fi, bio, fi->_i + 1);
298301
} else {

mm/readahead.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,8 @@ static inline int ra_alloc_folio(struct readahead_control *ractl, pgoff_t index,
474474

475475
if (!folio)
476476
return -ENOMEM;
477-
if (mark - index < (1UL << order))
477+
mark = round_up(mark, 1UL << order);
478+
if (index == mark)
478479
folio_set_readahead(folio);
479480
err = filemap_add_folio(ractl->mapping, folio, index, gfp);
480481
if (err)
@@ -555,8 +556,9 @@ static void ondemand_readahead(struct readahead_control *ractl,
555556
struct file_ra_state *ra = ractl->ra;
556557
unsigned long max_pages = ra->ra_pages;
557558
unsigned long add_pages;
558-
unsigned long index = readahead_index(ractl);
559-
pgoff_t prev_index;
559+
pgoff_t index = readahead_index(ractl);
560+
pgoff_t expected, prev_index;
561+
unsigned int order = folio ? folio_order(folio) : 0;
560562

561563
/*
562564
* If the request exceeds the readahead window, allow the read to
@@ -575,8 +577,9 @@ static void ondemand_readahead(struct readahead_control *ractl,
575577
* It's the expected callback index, assume sequential access.
576578
* Ramp up sizes, and push forward the readahead window.
577579
*/
578-
if ((index == (ra->start + ra->size - ra->async_size) ||
579-
index == (ra->start + ra->size))) {
580+
expected = round_up(ra->start + ra->size - ra->async_size,
581+
1UL << order);
582+
if (index == expected || index == (ra->start + ra->size)) {
580583
ra->start += ra->size;
581584
ra->size = get_next_ra_size(ra, max_pages);
582585
ra->async_size = ra->size;
@@ -662,7 +665,7 @@ static void ondemand_readahead(struct readahead_control *ractl,
662665
}
663666

664667
ractl->_index = ra->start;
665-
page_cache_ra_order(ractl, ra, folio ? folio_order(folio) : 0);
668+
page_cache_ra_order(ractl, ra, order);
666669
}
667670

668671
void page_cache_sync_ra(struct readahead_control *ractl,

0 commit comments

Comments
 (0)