Commit fe27d189 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents f47c960e b9ff43dd
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -269,6 +269,7 @@ struct folio_iter {
	size_t offset;
	size_t length;
	/* private: for use by the iterator */
	struct folio *_next;
	size_t _seg_count;
	int _i;
};
@@ -283,6 +284,7 @@ static inline void bio_first_folio(struct folio_iter *fi, struct bio *bio,
			PAGE_SIZE * (bvec->bv_page - &fi->folio->page);
	fi->_seg_count = bvec->bv_len;
	fi->length = min(folio_size(fi->folio) - fi->offset, fi->_seg_count);
	fi->_next = folio_next(fi->folio);
	fi->_i = i;
}

@@ -290,9 +292,10 @@ static inline void bio_next_folio(struct folio_iter *fi, struct bio *bio)
{
	fi->_seg_count -= fi->length;
	if (fi->_seg_count) {
		fi->folio = folio_next(fi->folio);
		fi->folio = fi->_next;
		fi->offset = 0;
		fi->length = min(folio_size(fi->folio), fi->_seg_count);
		fi->_next = folio_next(fi->folio);
	} else if (fi->_i + 1 < bio->bi_vcnt) {
		bio_first_folio(fi, bio, fi->_i + 1);
	} else {
+9 −6
Original line number Diff line number Diff line
@@ -474,7 +474,8 @@ static inline int ra_alloc_folio(struct readahead_control *ractl, pgoff_t index,

	if (!folio)
		return -ENOMEM;
	if (mark - index < (1UL << order))
	mark = round_up(mark, 1UL << order);
	if (index == mark)
		folio_set_readahead(folio);
	err = filemap_add_folio(ractl->mapping, folio, index, gfp);
	if (err)
@@ -555,8 +556,9 @@ static void ondemand_readahead(struct readahead_control *ractl,
	struct file_ra_state *ra = ractl->ra;
	unsigned long max_pages = ra->ra_pages;
	unsigned long add_pages;
	unsigned long index = readahead_index(ractl);
	pgoff_t prev_index;
	pgoff_t index = readahead_index(ractl);
	pgoff_t expected, prev_index;
	unsigned int order = folio ? folio_order(folio) : 0;

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

	ractl->_index = ra->start;
	page_cache_ra_order(ractl, ra, folio ? folio_order(folio) : 0);
	page_cache_ra_order(ractl, ra, order);
}

void page_cache_sync_ra(struct readahead_control *ractl,