Commit 74c8164e authored by Jens Axboe's avatar Jens Axboe Committed by Linus Torvalds

mpage: mpage_readpages() should submit IO as read-ahead

a_ops->readpages() is only ever used for read-ahead, yet we don't flag
the IO being submitted as such.  Fix that up.  Any file system that uses
mpage_readpages() as its ->readpages() implementation will now get this
right.

Since we're passing in whether the IO is read-ahead or not, we don't
need to pass in the 'gfp' separately, as it is dependent on the IO being
read-ahead.  Kill off that member.

Add some documentation notes on ->readpages() being purely for
read-ahead.

Link: http://lkml.kernel.org/r/20180621010725.17813-3-axboe@kernel.dkSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
Reviewed-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Chris Mason <clm@fb.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 357c1206
...@@ -1421,6 +1421,11 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -1421,6 +1421,11 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
/* /*
* This function was originally taken from fs/mpage.c, and customized for f2fs. * This function was originally taken from fs/mpage.c, and customized for f2fs.
* Major change was from block_size == page_size in f2fs by default. * Major change was from block_size == page_size in f2fs by default.
*
* Note that the aops->readpages() function is ONLY used for read-ahead. If
* this function ever deviates from doing just read-ahead, it should either
* use ->readpage() or do the necessary surgery to decouple ->readpages()
* readom read-ahead.
*/ */
static int f2fs_mpage_readpages(struct address_space *mapping, static int f2fs_mpage_readpages(struct address_space *mapping,
struct list_head *pages, struct page *page, struct list_head *pages, struct page *page,
......
...@@ -137,11 +137,11 @@ struct mpage_readpage_args { ...@@ -137,11 +137,11 @@ struct mpage_readpage_args {
struct bio *bio; struct bio *bio;
struct page *page; struct page *page;
unsigned int nr_pages; unsigned int nr_pages;
bool is_readahead;
sector_t last_block_in_bio; sector_t last_block_in_bio;
struct buffer_head map_bh; struct buffer_head map_bh;
unsigned long first_logical_block; unsigned long first_logical_block;
get_block_t *get_block; get_block_t *get_block;
gfp_t gfp;
}; };
/* /*
...@@ -170,8 +170,18 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args) ...@@ -170,8 +170,18 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
struct block_device *bdev = NULL; struct block_device *bdev = NULL;
int length; int length;
int fully_mapped = 1; int fully_mapped = 1;
int op_flags;
unsigned nblocks; unsigned nblocks;
unsigned relative_block; unsigned relative_block;
gfp_t gfp;
if (args->is_readahead) {
op_flags = REQ_RAHEAD;
gfp = readahead_gfp_mask(page->mapping);
} else {
op_flags = 0;
gfp = mapping_gfp_constraint(page->mapping, GFP_KERNEL);
}
if (page_has_buffers(page)) if (page_has_buffers(page))
goto confused; goto confused;
...@@ -284,7 +294,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args) ...@@ -284,7 +294,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
* This page will go to BIO. Do we need to send this BIO off first? * This page will go to BIO. Do we need to send this BIO off first?
*/ */
if (args->bio && (args->last_block_in_bio != blocks[0] - 1)) if (args->bio && (args->last_block_in_bio != blocks[0] - 1))
args->bio = mpage_bio_submit(REQ_OP_READ, 0, args->bio); args->bio = mpage_bio_submit(REQ_OP_READ, op_flags, args->bio);
alloc_new: alloc_new:
if (args->bio == NULL) { if (args->bio == NULL) {
...@@ -296,14 +306,14 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args) ...@@ -296,14 +306,14 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
args->bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9), args->bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),
min_t(int, args->nr_pages, min_t(int, args->nr_pages,
BIO_MAX_PAGES), BIO_MAX_PAGES),
args->gfp); gfp);
if (args->bio == NULL) if (args->bio == NULL)
goto confused; goto confused;
} }
length = first_hole << blkbits; length = first_hole << blkbits;
if (bio_add_page(args->bio, page, length, 0) < length) { if (bio_add_page(args->bio, page, length, 0) < length) {
args->bio = mpage_bio_submit(REQ_OP_READ, 0, args->bio); args->bio = mpage_bio_submit(REQ_OP_READ, op_flags, args->bio);
goto alloc_new; goto alloc_new;
} }
...@@ -311,7 +321,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args) ...@@ -311,7 +321,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
nblocks = map_bh->b_size >> blkbits; nblocks = map_bh->b_size >> blkbits;
if ((buffer_boundary(map_bh) && relative_block == nblocks) || if ((buffer_boundary(map_bh) && relative_block == nblocks) ||
(first_hole != blocks_per_page)) (first_hole != blocks_per_page))
args->bio = mpage_bio_submit(REQ_OP_READ, 0, args->bio); args->bio = mpage_bio_submit(REQ_OP_READ, op_flags, args->bio);
else else
args->last_block_in_bio = blocks[blocks_per_page - 1]; args->last_block_in_bio = blocks[blocks_per_page - 1];
out: out:
...@@ -319,7 +329,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args) ...@@ -319,7 +329,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
confused: confused:
if (args->bio) if (args->bio)
args->bio = mpage_bio_submit(REQ_OP_READ, 0, args->bio); args->bio = mpage_bio_submit(REQ_OP_READ, op_flags, args->bio);
if (!PageUptodate(page)) if (!PageUptodate(page))
block_read_full_page(page, args->get_block); block_read_full_page(page, args->get_block);
else else
...@@ -377,7 +387,7 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages, ...@@ -377,7 +387,7 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages,
{ {
struct mpage_readpage_args args = { struct mpage_readpage_args args = {
.get_block = get_block, .get_block = get_block,
.gfp = readahead_gfp_mask(mapping), .is_readahead = true,
}; };
unsigned page_idx; unsigned page_idx;
...@@ -388,7 +398,7 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages, ...@@ -388,7 +398,7 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages,
list_del(&page->lru); list_del(&page->lru);
if (!add_to_page_cache_lru(page, mapping, if (!add_to_page_cache_lru(page, mapping,
page->index, page->index,
args.gfp)) { readahead_gfp_mask(mapping))) {
args.page = page; args.page = page;
args.nr_pages = nr_pages - page_idx; args.nr_pages = nr_pages - page_idx;
args.bio = do_mpage_readpage(&args); args.bio = do_mpage_readpage(&args);
...@@ -397,7 +407,7 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages, ...@@ -397,7 +407,7 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages,
} }
BUG_ON(!list_empty(pages)); BUG_ON(!list_empty(pages));
if (args.bio) if (args.bio)
mpage_bio_submit(REQ_OP_READ, 0, args.bio); mpage_bio_submit(REQ_OP_READ, REQ_RAHEAD, args.bio);
return 0; return 0;
} }
EXPORT_SYMBOL(mpage_readpages); EXPORT_SYMBOL(mpage_readpages);
...@@ -411,7 +421,6 @@ int mpage_readpage(struct page *page, get_block_t get_block) ...@@ -411,7 +421,6 @@ int mpage_readpage(struct page *page, get_block_t get_block)
.page = page, .page = page,
.nr_pages = 1, .nr_pages = 1,
.get_block = get_block, .get_block = get_block,
.gfp = mapping_gfp_constraint(page->mapping, GFP_KERNEL),
}; };
args.bio = do_mpage_readpage(&args); args.bio = do_mpage_readpage(&args);
......
...@@ -344,6 +344,10 @@ struct address_space_operations { ...@@ -344,6 +344,10 @@ struct address_space_operations {
/* Set a page dirty. Return true if this dirtied it */ /* Set a page dirty. Return true if this dirtied it */
int (*set_page_dirty)(struct page *page); int (*set_page_dirty)(struct page *page);
/*
* Reads in the requested pages. Unlike ->readpage(), this is
* PURELY used for read-ahead!.
*/
int (*readpages)(struct file *filp, struct address_space *mapping, int (*readpages)(struct file *filp, struct address_space *mapping,
struct list_head *pages, unsigned nr_pages); struct list_head *pages, unsigned nr_pages);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment