Skip to content

Commit

Permalink
block, direct-io: fix OOM by converting to bio_for_each_page_all()
Browse files Browse the repository at this point in the history
There has been an occasional out-of-memory problem with multipage bvecs.

Fix the bug by converting bio_for_each_segment_all() to
bio_for_each_page_all(), both in bio_check_pages_dirty() and
dio_bio_complete().

To reproduce the OOM, run xfstests/generic/113 infinitely:

while [ 1 ] ; do
	./check generic/113
done

TODO: audit other uses of bio_for_each_segment_all()

Signed-off-by: Ming Lin <mlin@minggr.net>
[dpark: add more description into commit message]
Signed-off-by: Dongsu Park <dongsu.park@profitbricks.com>
  • Loading branch information
Ming Lin authored and Dongsu Park committed Dec 29, 2014
1 parent 3ac9061 commit 25fdad5
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 9 deletions.
10 changes: 5 additions & 5 deletions block/bio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1661,16 +1661,16 @@ static void bio_dirty_fn(struct work_struct *work)

void bio_check_pages_dirty(struct bio *bio)
{
struct bio_vec *bvec;
struct bio_vec bvec;
struct bvec_iter iter;
int nr_clean_pages = 0;
int i;

bio_for_each_segment_all(bvec, bio, i) {
struct page *page = bvec->bv_page;
bio_for_each_page_all(bvec, bio, iter) {
struct page *page = bvec.bv_page;

if (PageDirty(page) || PageCompound(page)) {
page_cache_release(page);
bvec->bv_page = NULL;
bvec.bv_page = NULL;
} else {
nr_clean_pages++;
}
Expand Down
8 changes: 4 additions & 4 deletions fs/direct-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,17 +457,17 @@ static struct bio *dio_await_one(struct dio *dio)
static int dio_bio_complete(struct dio *dio, struct bio *bio)
{
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct bio_vec *bvec;
unsigned i;
struct bio_vec bvec;
struct bvec_iter iter;

if (!uptodate)
dio->io_error = -EIO;

if (dio->is_async && dio->rw == READ) {
bio_check_pages_dirty(bio); /* transfers ownership */
} else {
bio_for_each_segment_all(bvec, bio, i) {
struct page *page = bvec->bv_page;
bio_for_each_page_all(bvec, bio, iter) {
struct page *page = bvec.bv_page;

if (dio->rw == READ && !PageCompound(page))
set_page_dirty_lock(page);
Expand Down

0 comments on commit 25fdad5

Please sign in to comment.