|
@@ -207,12 +207,21 @@ out:
|
|
* memory at once.
|
|
* memory at once.
|
|
*/
|
|
*/
|
|
int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
|
|
int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
|
|
- pgoff_t offset, unsigned long nr_to_read)
|
|
|
|
|
|
+ pgoff_t offset, unsigned long nr_to_read)
|
|
{
|
|
{
|
|
|
|
+ struct backing_dev_info *bdi = inode_to_bdi(mapping->host);
|
|
|
|
+ struct file_ra_state *ra = &filp->f_ra;
|
|
|
|
+ unsigned long max_pages;
|
|
|
|
+
|
|
if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages))
|
|
if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- nr_to_read = min(nr_to_read, inode_to_bdi(mapping->host)->ra_pages);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If the request exceeds the readahead window, allow the read to
|
|
|
|
+ * be up to the optimal hardware IO size
|
|
|
|
+ */
|
|
|
|
+ max_pages = max_t(unsigned long, bdi->io_pages, ra->ra_pages);
|
|
|
|
+ nr_to_read = min(nr_to_read, max_pages);
|
|
while (nr_to_read) {
|
|
while (nr_to_read) {
|
|
int err;
|
|
int err;
|
|
|
|
|
|
@@ -369,9 +378,17 @@ ondemand_readahead(struct address_space *mapping,
|
|
bool hit_readahead_marker, pgoff_t offset,
|
|
bool hit_readahead_marker, pgoff_t offset,
|
|
unsigned long req_size)
|
|
unsigned long req_size)
|
|
{
|
|
{
|
|
- unsigned long max = ra->ra_pages;
|
|
|
|
|
|
+ struct backing_dev_info *bdi = inode_to_bdi(mapping->host);
|
|
|
|
+ unsigned long max_pages = ra->ra_pages;
|
|
pgoff_t prev_offset;
|
|
pgoff_t prev_offset;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If the request exceeds the readahead window, allow the read to
|
|
|
|
+ * be up to the optimal hardware IO size
|
|
|
|
+ */
|
|
|
|
+ if (req_size > max_pages && bdi->io_pages > max_pages)
|
|
|
|
+ max_pages = min(req_size, bdi->io_pages);
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* start of file
|
|
* start of file
|
|
*/
|
|
*/
|
|
@@ -385,7 +402,7 @@ ondemand_readahead(struct address_space *mapping,
|
|
if ((offset == (ra->start + ra->size - ra->async_size) ||
|
|
if ((offset == (ra->start + ra->size - ra->async_size) ||
|
|
offset == (ra->start + ra->size))) {
|
|
offset == (ra->start + ra->size))) {
|
|
ra->start += ra->size;
|
|
ra->start += ra->size;
|
|
- ra->size = get_next_ra_size(ra, max);
|
|
|
|
|
|
+ ra->size = get_next_ra_size(ra, max_pages);
|
|
ra->async_size = ra->size;
|
|
ra->async_size = ra->size;
|
|
goto readit;
|
|
goto readit;
|
|
}
|
|
}
|
|
@@ -400,16 +417,16 @@ ondemand_readahead(struct address_space *mapping,
|
|
pgoff_t start;
|
|
pgoff_t start;
|
|
|
|
|
|
rcu_read_lock();
|
|
rcu_read_lock();
|
|
- start = page_cache_next_hole(mapping, offset + 1, max);
|
|
|
|
|
|
+ start = page_cache_next_hole(mapping, offset + 1, max_pages);
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
|
|
|
|
- if (!start || start - offset > max)
|
|
|
|
|
|
+ if (!start || start - offset > max_pages)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
ra->start = start;
|
|
ra->start = start;
|
|
ra->size = start - offset; /* old async_size */
|
|
ra->size = start - offset; /* old async_size */
|
|
ra->size += req_size;
|
|
ra->size += req_size;
|
|
- ra->size = get_next_ra_size(ra, max);
|
|
|
|
|
|
+ ra->size = get_next_ra_size(ra, max_pages);
|
|
ra->async_size = ra->size;
|
|
ra->async_size = ra->size;
|
|
goto readit;
|
|
goto readit;
|
|
}
|
|
}
|
|
@@ -417,7 +434,7 @@ ondemand_readahead(struct address_space *mapping,
|
|
/*
|
|
/*
|
|
* oversize read
|
|
* oversize read
|
|
*/
|
|
*/
|
|
- if (req_size > max)
|
|
|
|
|
|
+ if (req_size > max_pages)
|
|
goto initial_readahead;
|
|
goto initial_readahead;
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -433,7 +450,7 @@ ondemand_readahead(struct address_space *mapping,
|
|
* Query the page cache and look for the traces(cached history pages)
|
|
* Query the page cache and look for the traces(cached history pages)
|
|
* that a sequential stream would leave behind.
|
|
* that a sequential stream would leave behind.
|
|
*/
|
|
*/
|
|
- if (try_context_readahead(mapping, ra, offset, req_size, max))
|
|
|
|
|
|
+ if (try_context_readahead(mapping, ra, offset, req_size, max_pages))
|
|
goto readit;
|
|
goto readit;
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -444,7 +461,7 @@ ondemand_readahead(struct address_space *mapping,
|
|
|
|
|
|
initial_readahead:
|
|
initial_readahead:
|
|
ra->start = offset;
|
|
ra->start = offset;
|
|
- ra->size = get_init_ra_size(req_size, max);
|
|
|
|
|
|
+ ra->size = get_init_ra_size(req_size, max_pages);
|
|
ra->async_size = ra->size > req_size ? ra->size - req_size : ra->size;
|
|
ra->async_size = ra->size > req_size ? ra->size - req_size : ra->size;
|
|
|
|
|
|
readit:
|
|
readit:
|
|
@@ -454,7 +471,7 @@ readit:
|
|
* the resulted next readahead window into the current one.
|
|
* the resulted next readahead window into the current one.
|
|
*/
|
|
*/
|
|
if (offset == ra->start && ra->size == ra->async_size) {
|
|
if (offset == ra->start && ra->size == ra->async_size) {
|
|
- ra->async_size = get_next_ra_size(ra, max);
|
|
|
|
|
|
+ ra->async_size = get_next_ra_size(ra, max_pages);
|
|
ra->size += ra->async_size;
|
|
ra->size += ra->async_size;
|
|
}
|
|
}
|
|
|
|
|