mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-11-02 23:54:33 +01:00
mm: add new readahead_control API
Filesystems which implement the upcoming ->readahead method will get their pages by calling readahead_page() or readahead_page_batch(). These functions support large pages, even though none of the filesystems to be converted do yet. Signed-off-by: Matthew Wilcox (Oracle) <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: William Kucharski <[email protected]> Cc: Chao Yu <[email protected]> Cc: Cong Wang <[email protected]> Cc: Darrick J. Wong <[email protected]> Cc: Dave Chinner <[email protected]> Cc: Eric Biggers <[email protected]> Cc: Gao Xiang <[email protected]> Cc: Jaegeuk Kim <[email protected]> Cc: John Hubbard <[email protected]> Cc: Joseph Qi <[email protected]> Cc: Junxiao Bi <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Zi Yan <[email protected]> Cc: Johannes Thumshirn <[email protected]> Cc: Miklos Szeredi <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
1 parent
ad4ae1c732
commit
042124cc64
1 file changed
+140
@@ -642,6 +642,146 @@ static inline int add_to_page_cache(struct page *page,
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct readahead_control - Describes a readahead request.
|
||||
*
|
||||
* A readahead request is for consecutive pages. Filesystems which
|
||||
* implement the ->readahead method should call readahead_page() or
|
||||
* readahead_page_batch() in a loop and attempt to start I/O against
|
||||
* each page in the request.
|
||||
*
|
||||
* Most of the fields in this struct are private and should be accessed
|
||||
* by the functions below.
|
||||
*
|
||||
* @file: The file, used primarily by network filesystems for authentication.
|
||||
* May be NULL if invoked internally by the filesystem.
|
||||
* @mapping: Readahead this filesystem object.
|
||||
*/
|
||||
struct readahead_control {
|
||||
struct file *file;
|
||||
struct address_space *mapping;
|
||||
/* private: use the readahead_* accessors instead */
|
||||
pgoff_t _index;
|
||||
unsigned int _nr_pages;
|
||||
unsigned int _batch_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* readahead_page - Get the next page to read.
|
||||
* @rac: The current readahead request.
|
||||
*
|
||||
* Context: The page is locked and has an elevated refcount. The caller
|
||||
* should decreases the refcount once the page has been submitted for I/O
|
||||
* and unlock the page once all I/O to that page has completed.
|
||||
* Return: A pointer to the next page, or %NULL if we are done.
|
||||
*/
|
||||
static inline struct page *readahead_page(struct readahead_control *rac)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
BUG_ON(rac->_batch_count > rac->_nr_pages);
|
||||
rac->_nr_pages -= rac->_batch_count;
|
||||
rac->_index += rac->_batch_count;
|
||||
|
||||
if (!rac->_nr_pages) {
|
||||
rac->_batch_count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
page = xa_load(&rac->mapping->i_pages, rac->_index);
|
||||
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
||||
rac->_batch_count = hpage_nr_pages(page);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
static inline unsigned int __readahead_batch(struct readahead_control *rac,
|
||||
struct page **array, unsigned int array_sz)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
XA_STATE(xas, &rac->mapping->i_pages, 0);
|
||||
struct page *page;
|
||||
|
||||
BUG_ON(rac->_batch_count > rac->_nr_pages);
|
||||
rac->_nr_pages -= rac->_batch_count;
|
||||
rac->_index += rac->_batch_count;
|
||||
rac->_batch_count = 0;
|
||||
|
||||
xas_set(&xas, rac->_index);
|
||||
rcu_read_lock();
|
||||
xas_for_each(&xas, page, rac->_index + rac->_nr_pages - 1) {
|
||||
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
||||
VM_BUG_ON_PAGE(PageTail(page), page);
|
||||
array[i++] = page;
|
||||
rac->_batch_count += hpage_nr_pages(page);
|
||||
|
||||
/*
|
||||
* The page cache isn't using multi-index entries yet,
|
||||
* so the xas cursor needs to be manually moved to the
|
||||
* next index. This can be removed once the page cache
|
||||
* is converted.
|
||||
*/
|
||||
if (PageHead(page))
|
||||
xas_set(&xas, rac->_index + rac->_batch_count);
|
||||
|
||||
if (i == array_sz)
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* readahead_page_batch - Get a batch of pages to read.
|
||||
* @rac: The current readahead request.
|
||||
* @array: An array of pointers to struct page.
|
||||
*
|
||||
* Context: The pages are locked and have an elevated refcount. The caller
|
||||
* should decreases the refcount once the page has been submitted for I/O
|
||||
* and unlock the page once all I/O to that page has completed.
|
||||
* Return: The number of pages placed in the array. 0 indicates the request
|
||||
* is complete.
|
||||
*/
|
||||
#define readahead_page_batch(rac, array) \
|
||||
__readahead_batch(rac, array, ARRAY_SIZE(array))
|
||||
|
||||
/**
|
||||
* readahead_pos - The byte offset into the file of this readahead request.
|
||||
* @rac: The readahead request.
|
||||
*/
|
||||
static inline loff_t readahead_pos(struct readahead_control *rac)
|
||||
{
|
||||
return (loff_t)rac->_index * PAGE_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* readahead_length - The number of bytes in this readahead request.
|
||||
* @rac: The readahead request.
|
||||
*/
|
||||
static inline loff_t readahead_length(struct readahead_control *rac)
|
||||
{
|
||||
return (loff_t)rac->_nr_pages * PAGE_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* readahead_index - The index of the first page in this readahead request.
|
||||
* @rac: The readahead request.
|
||||
*/
|
||||
static inline pgoff_t readahead_index(struct readahead_control *rac)
|
||||
{
|
||||
return rac->_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* readahead_count - The number of pages in this readahead request.
|
||||
* @rac: The readahead request.
|
||||
*/
|
||||
static inline unsigned int readahead_count(struct readahead_control *rac)
|
||||
{
|
||||
return rac->_nr_pages;
|
||||
}
|
||||
|
||||
static inline unsigned long dir_pages(struct inode *inode)
|
||||
{
|
||||
return (unsigned long)(inode->i_size + PAGE_SIZE - 1) >>
|
||||
|
||||
Reference in new issue
Block a user