mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
block: Do not call folio_next() on an unreferenced folio
It is unsafe to call folio_next() on a folio unless you hold a reference on it that prevents it from being split or freed. After returning from the iterator, iomap calls folio_end_writeback() which may drop the last reference to the page, or allow the page to be split. If that happens, the iterator will not advance far enough through the bio_vec, leading to assertion failures like the BUG() in folio_end_writeback() that checks we're not trying to end writeback on a page not currently under writeback. Other assertion failures were also seen, but they're all explained by this one bug. Fix the bug by remembering where the next folio starts before returning from the iterator. There are other ways of fixing this bug, but this seems the simplest. Reported-by: Darrick J. Wong <djwong@kernel.org> Tested-by: Darrick J. Wong <djwong@kernel.org> Reported-by: Brian Foster <bfoster@redhat.com> Tested-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
This commit is contained in:
parent
a7391ad357
commit
170f37d6aa
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user