| From: NeilBrown <neilb@suse.de> |
| Subject: mm: improve cleanup when ->readpages doesn't process all pages |
| |
| If ->readpages doesn't process all the pages, then it is best to act as |
| though they weren't requested so that a subsequent readahead can try |
| again. |
| |
| So: |
| - remove any 'ahead' pages from the page cache so they can be loaded |
| with ->readahead() rather then multiple ->read()s |
| - update the file_ra_state to reflect the reads that were actually |
| submitted. |
| |
| This allows ->readpages() to abort early due e.g. to congestion, which |
| will then allow us to remove the inode_read_congested() test from |
| page_Cache_async_ra(). |
| |
| Link: https://lkml.kernel.org/r/164549983736.9187.16755913785880819183.stgit@noble.brown |
| Signed-off-by: NeilBrown <neilb@suse.de> |
| Cc: Anna Schumaker <Anna.Schumaker@Netapp.com> |
| Cc: Chao Yu <chao@kernel.org> |
| Cc: Darrick J. Wong <djwong@kernel.org> |
| Cc: Ilya Dryomov <idryomov@gmail.com> |
| Cc: Jaegeuk Kim <jaegeuk@kernel.org> |
| Cc: Jan Kara <jack@suse.cz> |
| Cc: Jeff Layton <jlayton@kernel.org> |
| Cc: Jens Axboe <axboe@kernel.dk> |
| Cc: Lars Ellenberg <lars.ellenberg@linbit.com> |
| Cc: Miklos Szeredi <miklos@szeredi.hu> |
| Cc: Paolo Valente <paolo.valente@linaro.org> |
| Cc: Philipp Reisner <philipp.reisner@linbit.com> |
| Cc: Ryusuke Konishi <konishi.ryusuke@gmail.com> |
| Cc: Trond Myklebust <trond.myklebust@hammerspace.com> |
| Cc: Wu Fengguang <fengguang.wu@intel.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| mm/readahead.c | 19 +++++++++++++++++-- |
| 1 file changed, 17 insertions(+), 2 deletions(-) |
| |
| --- a/mm/readahead.c~mm-improve-cleanup-when-readpages-doesnt-process-all-pages |
| +++ a/mm/readahead.c |
| @@ -104,7 +104,13 @@ |
| * for necessary resources (e.g. memory or indexing information) to |
| * become available. Pages in the final ``async_size`` may be |
| * considered less urgent and failure to read them is more acceptable. |
| - * They will eventually be read individually using ->readpage(). |
| + * In this case it is best to use delete_from_page_cache() to remove the |
| + * pages from the page cache as is automatically done for pages that |
| + * were not fetched with readahead_page(). This will allow a |
| + * subsequent synchronous read ahead request to try them again. If they |
| + * are left in the page cache, then they will be read individually using |
| + * ->readpage(). |
| + * |
| */ |
| |
| #include <linux/kernel.h> |
| @@ -226,8 +232,17 @@ static void read_pages(struct readahead_ |
| |
| if (aops->readahead) { |
| aops->readahead(rac); |
| - /* Clean up the remaining pages */ |
| + /* |
| + * Clean up the remaining pages. The sizes in ->ra |
| + * maybe be used to size next read-ahead, so make sure |
| + * they accurately reflect what happened. |
| + */ |
| while ((page = readahead_page(rac))) { |
| + rac->ra->size -= 1; |
| + if (rac->ra->async_size > 0) { |
| + rac->ra->async_size -= 1; |
| + delete_from_page_cache(page); |
| + } |
| unlock_page(page); |
| put_page(page); |
| } |
| _ |