diff options
Diffstat (limited to 'fs/mpage.c')
| -rw-r--r-- | fs/mpage.c | 129 | 
1 files changed, 63 insertions, 66 deletions
diff --git a/fs/mpage.c b/fs/mpage.c index fd56ca2ea55..5f9ed622274 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -13,7 +13,7 @@   */  #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/export.h>  #include <linux/mm.h>  #include <linux/kdev_t.h>  #include <linux/gfp.h> @@ -27,6 +27,7 @@  #include <linux/writeback.h>  #include <linux/backing-dev.h>  #include <linux/pagevec.h> +#include <linux/cleancache.h>  /*   * I/O completion handler for multipage BIOs. @@ -40,54 +41,22 @@   * status of that page is hard.  See end_buffer_async_read() for the details.   * There is no point in duplicating all that complexity.   */ -static void mpage_end_io_read(struct bio *bio, int err) +static void mpage_end_io(struct bio *bio, int err)  { -	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); -	struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; +	struct bio_vec *bv; +	int i; -	do { -		struct page *page = bvec->bv_page; - -		if (--bvec >= bio->bi_io_vec) -			prefetchw(&bvec->bv_page->flags); - -		if (uptodate) { -			SetPageUptodate(page); -		} else { -			ClearPageUptodate(page); -			SetPageError(page); -		} -		unlock_page(page); -	} while (bvec >= bio->bi_io_vec); -	bio_put(bio); -} - -static void mpage_end_io_write(struct bio *bio, int err) -{ -	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); -	struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - -	do { -		struct page *page = bvec->bv_page; - -		if (--bvec >= bio->bi_io_vec) -			prefetchw(&bvec->bv_page->flags); +	bio_for_each_segment_all(bv, bio, i) { +		struct page *page = bv->bv_page; +		page_endio(page, bio_data_dir(bio), err); +	} -		if (!uptodate){ -			SetPageError(page); -			if (page->mapping) -				set_bit(AS_EIO, &page->mapping->flags); -		} -		end_page_writeback(page); -	} while (bvec >= bio->bi_io_vec);  	bio_put(bio);  }  static struct bio *mpage_bio_submit(int rw, struct bio *bio)  { -	bio->bi_end_io = mpage_end_io_read; -	if (rw == WRITE) -		bio->bi_end_io = mpage_end_io_write; +	bio->bi_end_io = mpage_end_io;  	submit_bio(rw, bio);  	return NULL;  } @@ -108,7 +77,7 @@ mpage_alloc(struct block_device *bdev,  	if (bio) {  		bio->bi_bdev = bdev; -		bio->bi_sector = first_sector; +		bio->bi_iter.bi_sector = first_sector;  	}  	return bio;  } @@ -286,6 +255,12 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,  		SetPageMappedToDisk(page);  	} +	if (fully_mapped && blocks_per_page == 1 && !PageUptodate(page) && +	    cleancache_get_page(page) == 0) { +		SetPageUptodate(page); +		goto confused; +	} +  	/*  	 * This page will go to BIO.  Do we need to send this BIO off first?  	 */ @@ -294,6 +269,11 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,  alloc_new:  	if (bio == NULL) { +		if (first_hole == blocks_per_page) { +			if (!bdev_read_page(bdev, blocks[0] << (blkbits - 9), +								page)) +				goto out; +		}  		bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),  			  	min_t(int, nr_pages, bio_get_nr_vecs(bdev)),  				GFP_KERNEL); @@ -448,6 +428,35 @@ struct mpage_data {  	unsigned use_writepage;  }; +/* + * We have our BIO, so we can now mark the buffers clean.  Make + * sure to only clean buffers which we know we'll be writing. + */ +static void clean_buffers(struct page *page, unsigned first_unmapped) +{ +	unsigned buffer_counter = 0; +	struct buffer_head *bh, *head; +	if (!page_has_buffers(page)) +		return; +	head = page_buffers(page); +	bh = head; + +	do { +		if (buffer_counter++ == first_unmapped) +			break; +		clear_buffer_dirty(bh); +		bh = bh->b_this_page; +	} while (bh != head); + +	/* +	 * we cannot drop the bh if the page is not uptodate or a concurrent +	 * readpage would fail to serialize with the bh and it would read from +	 * disk before we reach the platter. +	 */ +	if (buffer_heads_over_limit && PageUptodate(page)) +		try_to_free_buffers(page); +} +  static int __mpage_writepage(struct page *page, struct writeback_control *wbc,  		      void *data)  { @@ -583,6 +592,13 @@ page_is_mapped:  alloc_new:  	if (bio == NULL) { +		if (first_unmapped == blocks_per_page) { +			if (!bdev_write_page(bdev, blocks[0] << (blkbits - 9), +								page, wbc)) { +				clean_buffers(page, first_unmapped); +				goto out; +			} +		}  		bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),  				bio_get_nr_vecs(bdev), GFP_NOFS|__GFP_HIGH);  		if (bio == NULL) @@ -600,30 +616,7 @@ alloc_new:  		goto alloc_new;  	} -	/* -	 * OK, we have our BIO, so we can now mark the buffers clean.  Make -	 * sure to only clean buffers which we know we'll be writing. -	 */ -	if (page_has_buffers(page)) { -		struct buffer_head *head = page_buffers(page); -		struct buffer_head *bh = head; -		unsigned buffer_counter = 0; - -		do { -			if (buffer_counter++ == first_unmapped) -				break; -			clear_buffer_dirty(bh); -			bh = bh->b_this_page; -		} while (bh != head); - -		/* -		 * we cannot drop the bh if the page is not uptodate -		 * or a concurrent readpage would fail to serialize with the bh -		 * and it would read from disk before we reach the platter. -		 */ -		if (buffer_heads_over_limit && PageUptodate(page)) -			try_to_free_buffers(page); -	} +	clean_buffers(page, first_unmapped);  	BUG_ON(PageWriteback(page));  	set_page_writeback(page); @@ -681,8 +674,11 @@ int  mpage_writepages(struct address_space *mapping,  		struct writeback_control *wbc, get_block_t get_block)  { +	struct blk_plug plug;  	int ret; +	blk_start_plug(&plug); +  	if (!get_block)  		ret = generic_writepages(mapping, wbc);  	else { @@ -697,6 +693,7 @@ mpage_writepages(struct address_space *mapping,  		if (mpd.bio)  			mpage_bio_submit(WRITE, mpd.bio);  	} +	blk_finish_plug(&plug);  	return ret;  }  EXPORT_SYMBOL(mpage_writepages);  | 
