Commit 2c684234 authored by Matthew Wilcox (Oracle)'s avatar Matthew Wilcox (Oracle) Committed by Linus Torvalds

mm: add page_cache_readahead_unbounded

ext4 and f2fs have duplicated the guts of the readahead code so they can
read past i_size.  Instead, separate out the guts of the readahead code
so they can call it directly.
Signed-off-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Tested-by: default avatarEric Biggers <ebiggers@google.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarWilliam Kucharski <william.kucharski@oracle.com>
Reviewed-by: default avatarEric Biggers <ebiggers@google.com>
Cc: Chao Yu <yuchao0@huawei.com>
Cc: Cong Wang <xiyou.wangcong@gmail.com>
Cc: Darrick J. Wong <darrick.wong@oracle.com>
Cc: Dave Chinner <dchinner@redhat.com>
Cc: Gao Xiang <gaoxiang25@huawei.com>
Cc: Jaegeuk Kim <jaegeuk@kernel.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Cc: Miklos Szeredi <mszeredi@redhat.com>
Link: http://lkml.kernel.org/r/20200414150233.24495-14-willy@infradead.orgSigned-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b0f31d78
...@@ -342,37 +342,6 @@ static int ext4_get_verity_descriptor(struct inode *inode, void *buf, ...@@ -342,37 +342,6 @@ static int ext4_get_verity_descriptor(struct inode *inode, void *buf,
return desc_size; return desc_size;
} }
/*
* Prefetch some pages from the file's Merkle tree.
*
* This is basically a stripped-down version of __do_page_cache_readahead()
* which works on pages past i_size.
*/
static void ext4_merkle_tree_readahead(struct address_space *mapping,
pgoff_t start_index, unsigned long count)
{
LIST_HEAD(pages);
unsigned int nr_pages = 0;
struct page *page;
pgoff_t index;
struct blk_plug plug;
for (index = start_index; index < start_index + count; index++) {
page = xa_load(&mapping->i_pages, index);
if (!page || xa_is_value(page)) {
page = __page_cache_alloc(readahead_gfp_mask(mapping));
if (!page)
break;
page->index = index;
list_add(&page->lru, &pages);
nr_pages++;
}
}
blk_start_plug(&plug);
ext4_mpage_readpages(mapping, &pages, NULL, nr_pages, true);
blk_finish_plug(&plug);
}
static struct page *ext4_read_merkle_tree_page(struct inode *inode, static struct page *ext4_read_merkle_tree_page(struct inode *inode,
pgoff_t index, pgoff_t index,
unsigned long num_ra_pages) unsigned long num_ra_pages)
...@@ -386,8 +355,8 @@ static struct page *ext4_read_merkle_tree_page(struct inode *inode, ...@@ -386,8 +355,8 @@ static struct page *ext4_read_merkle_tree_page(struct inode *inode,
if (page) if (page)
put_page(page); put_page(page);
else if (num_ra_pages > 1) else if (num_ra_pages > 1)
ext4_merkle_tree_readahead(inode->i_mapping, index, page_cache_readahead_unbounded(inode->i_mapping, NULL,
num_ra_pages); index, num_ra_pages, 0);
page = read_mapping_page(inode->i_mapping, index, NULL); page = read_mapping_page(inode->i_mapping, index, NULL);
} }
return page; return page;
......
...@@ -2177,7 +2177,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret, ...@@ -2177,7 +2177,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
* use ->readpage() or do the necessary surgery to decouple ->readpages() * use ->readpage() or do the necessary surgery to decouple ->readpages()
* from read-ahead. * from read-ahead.
*/ */
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,
unsigned nr_pages, bool is_readahead) unsigned nr_pages, bool is_readahead)
{ {
......
...@@ -3373,9 +3373,6 @@ int f2fs_reserve_new_block(struct dnode_of_data *dn); ...@@ -3373,9 +3373,6 @@ int f2fs_reserve_new_block(struct dnode_of_data *dn);
int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index); int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index);
int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from); int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from);
int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index); int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index);
int f2fs_mpage_readpages(struct address_space *mapping,
struct list_head *pages, struct page *page,
unsigned nr_pages, bool is_readahead);
struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index, struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
int op_flags, bool for_write); int op_flags, bool for_write);
struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index); struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index);
......
...@@ -222,37 +222,6 @@ static int f2fs_get_verity_descriptor(struct inode *inode, void *buf, ...@@ -222,37 +222,6 @@ static int f2fs_get_verity_descriptor(struct inode *inode, void *buf,
return size; return size;
} }
/*
* Prefetch some pages from the file's Merkle tree.
*
* This is basically a stripped-down version of __do_page_cache_readahead()
* which works on pages past i_size.
*/
static void f2fs_merkle_tree_readahead(struct address_space *mapping,
pgoff_t start_index, unsigned long count)
{
LIST_HEAD(pages);
unsigned int nr_pages = 0;
struct page *page;
pgoff_t index;
struct blk_plug plug;
for (index = start_index; index < start_index + count; index++) {
page = xa_load(&mapping->i_pages, index);
if (!page || xa_is_value(page)) {
page = __page_cache_alloc(readahead_gfp_mask(mapping));
if (!page)
break;
page->index = index;
list_add(&page->lru, &pages);
nr_pages++;
}
}
blk_start_plug(&plug);
f2fs_mpage_readpages(mapping, &pages, NULL, nr_pages, true);
blk_finish_plug(&plug);
}
static struct page *f2fs_read_merkle_tree_page(struct inode *inode, static struct page *f2fs_read_merkle_tree_page(struct inode *inode,
pgoff_t index, pgoff_t index,
unsigned long num_ra_pages) unsigned long num_ra_pages)
...@@ -266,8 +235,8 @@ static struct page *f2fs_read_merkle_tree_page(struct inode *inode, ...@@ -266,8 +235,8 @@ static struct page *f2fs_read_merkle_tree_page(struct inode *inode,
if (page) if (page)
put_page(page); put_page(page);
else if (num_ra_pages > 1) else if (num_ra_pages > 1)
f2fs_merkle_tree_readahead(inode->i_mapping, index, page_cache_readahead_unbounded(inode->i_mapping, NULL,
num_ra_pages); index, num_ra_pages, 0);
page = read_mapping_page(inode->i_mapping, index, NULL); page = read_mapping_page(inode->i_mapping, index, NULL);
} }
return page; return page;
......
...@@ -625,6 +625,9 @@ void page_cache_sync_readahead(struct address_space *, struct file_ra_state *, ...@@ -625,6 +625,9 @@ void page_cache_sync_readahead(struct address_space *, struct file_ra_state *,
void page_cache_async_readahead(struct address_space *, struct file_ra_state *, void page_cache_async_readahead(struct address_space *, struct file_ra_state *,
struct file *, struct page *, pgoff_t index, struct file *, struct page *, pgoff_t index,
unsigned long req_count); unsigned long req_count);
void page_cache_readahead_unbounded(struct address_space *, struct file *,
pgoff_t index, unsigned long nr_to_read,
unsigned long lookahead_count);
/* /*
* Like add_to_page_cache_locked, but used to add newly allocated pages: * Like add_to_page_cache_locked, but used to add newly allocated pages:
......
...@@ -156,37 +156,34 @@ static void read_pages(struct readahead_control *rac, struct list_head *pages, ...@@ -156,37 +156,34 @@ static void read_pages(struct readahead_control *rac, struct list_head *pages,
rac->_index++; rac->_index++;
} }
/* /**
* __do_page_cache_readahead() actually reads a chunk of disk. It allocates * page_cache_readahead_unbounded - Start unchecked readahead.
* the pages first, then submits them for I/O. This avoids the very bad * @mapping: File address space.
* behaviour which would occur if page allocations are causing VM writeback. * @file: This instance of the open file; used for authentication.
* We really don't want to intermingle reads and writes like that. * @index: First page index to read.
* @nr_to_read: The number of pages to read.
* @lookahead_size: Where to start the next readahead.
*
* This function is for filesystems to call when they want to start
* readahead beyond a file's stated i_size. This is almost certainly
* not the function you want to call. Use page_cache_async_readahead()
* or page_cache_sync_readahead() instead.
*
* Context: File is referenced by caller. Mutexes may be held by caller.
* May sleep, but will not reenter filesystem to reclaim memory.
*/ */
void __do_page_cache_readahead(struct address_space *mapping, void page_cache_readahead_unbounded(struct address_space *mapping,
struct file *filp, pgoff_t index, unsigned long nr_to_read, struct file *file, pgoff_t index, unsigned long nr_to_read,
unsigned long lookahead_size) unsigned long lookahead_size)
{ {
struct inode *inode = mapping->host;
LIST_HEAD(page_pool); LIST_HEAD(page_pool);
loff_t isize = i_size_read(inode);
gfp_t gfp_mask = readahead_gfp_mask(mapping); gfp_t gfp_mask = readahead_gfp_mask(mapping);
struct readahead_control rac = { struct readahead_control rac = {
.mapping = mapping, .mapping = mapping,
.file = filp, .file = file,
._index = index, ._index = index,
}; };
unsigned long i; unsigned long i;
pgoff_t end_index; /* The last page we want to read */
if (isize == 0)
return;
end_index = (isize - 1) >> PAGE_SHIFT;
if (index > end_index)
return;
/* Don't read past the page containing the last byte of the file */
if (nr_to_read > end_index - index)
nr_to_read = end_index - index + 1;
/* /*
* Preallocate as many pages as we will need. * Preallocate as many pages as we will need.
...@@ -230,6 +227,35 @@ void __do_page_cache_readahead(struct address_space *mapping, ...@@ -230,6 +227,35 @@ void __do_page_cache_readahead(struct address_space *mapping,
*/ */
read_pages(&rac, &page_pool, false); read_pages(&rac, &page_pool, false);
} }
EXPORT_SYMBOL_GPL(page_cache_readahead_unbounded);
/*
* __do_page_cache_readahead() actually reads a chunk of disk. It allocates
* the pages first, then submits them for I/O. This avoids the very bad
* behaviour which would occur if page allocations are causing VM writeback.
* We really don't want to intermingle reads and writes like that.
*/
void __do_page_cache_readahead(struct address_space *mapping,
struct file *file, pgoff_t index, unsigned long nr_to_read,
unsigned long lookahead_size)
{
struct inode *inode = mapping->host;
loff_t isize = i_size_read(inode);
pgoff_t end_index; /* The last page we want to read */
if (isize == 0)
return;
end_index = (isize - 1) >> PAGE_SHIFT;
if (index > end_index)
return;
/* Don't read past the page containing the last byte of the file */
if (nr_to_read > end_index - index)
nr_to_read = end_index - index + 1;
page_cache_readahead_unbounded(mapping, file, index, nr_to_read,
lookahead_size);
}
/* /*
* Chunk the readahead into 2 megabyte units, so that we don't pin too much * Chunk the readahead into 2 megabyte units, so that we don't pin too much
......
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