From: Jan Kara <jack@suse.cz>
To: <linux-mm@kvack.org>
Cc: Hugh Dickins <hughd@google.com>,
David Howells <dhowells@redhat.com>,
linux-afs@lists.infradead.org,
Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>,
linux-nilfs@vger.kernel.org, Bob Peterson <rpeterso@redhat.com>,
cluster-devel@redhat.com, Jaegeuk Kim <jaegeuk@kernel.org>,
linux-f2fs-devel@lists.sourceforge.net, tytso@mit.edu,
linux-ext4@vger.kernel.org, Ilya Dryomov <idryomov@gmail.com>,
"Yan, Zheng" <zyan@redhat.com>,
ceph-devel@vger.kernel.org, linux-btrfs@vger.kernel.org,
David Sterba <dsterba@suse.com>,
"Darrick J . Wong" <darrick.wong@oracle.com>,
linux-xfs@vger.kernel.org,
Nadia Yvette Chambers <nyc@holomorphy.com>,
Jan Kara <jack@suse.cz>
Subject: [PATCH 07/35] mm: Implement find_get_pages_range()
Date: Thu, 1 Jun 2017 11:32:17 +0200 [thread overview]
Message-ID: <20170601093245.29238-8-jack@suse.cz> (raw)
In-Reply-To: <20170601093245.29238-1-jack@suse.cz>
Implement a variant of find_get_pages() that stops iterating at given
index. This may be substantial performance gain if the mapping is
sparse. See following commit for details. Furthermore lots of users of
this function (through pagevec_lookup()) actually want a range lookup
and all of them are currently open-coding this.
Also create corresponding pagevec_lookup_range() function.
Signed-off-by: Jan Kara <jack@suse.cz>
---
include/linux/pagemap.h | 12 ++++++++++--
include/linux/pagevec.h | 13 +++++++++++--
mm/filemap.c | 42 ++++++++++++++++++++++++++++++------------
mm/swap.c | 22 ++++++++++++++--------
4 files changed, 65 insertions(+), 24 deletions(-)
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 86de6f9c8607..2bb5e636a8c8 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -336,8 +336,16 @@ struct page *find_lock_entry(struct address_space *mapping, pgoff_t offset);
unsigned find_get_entries(struct address_space *mapping, pgoff_t start,
unsigned int nr_entries, struct page **entries,
pgoff_t *indices);
-unsigned find_get_pages(struct address_space *mapping, pgoff_t *start,
- unsigned int nr_pages, struct page **pages);
+unsigned find_get_pages_range(struct address_space *mapping, pgoff_t *start,
+ pgoff_t end, unsigned int nr_pages,
+ struct page **pages);
+static inline unsigned find_get_pages(struct address_space *mapping,
+ pgoff_t *start, unsigned int nr_pages,
+ struct page **pages)
+{
+ return find_get_pages_range(mapping, start, (pgoff_t)-1, nr_pages,
+ pages);
+}
unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t start,
unsigned int nr_pages, struct page **pages);
unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
diff --git a/include/linux/pagevec.h b/include/linux/pagevec.h
index c395a5bb58b2..7df056910437 100644
--- a/include/linux/pagevec.h
+++ b/include/linux/pagevec.h
@@ -27,8 +27,17 @@ unsigned pagevec_lookup_entries(struct pagevec *pvec,
pgoff_t start, unsigned nr_entries,
pgoff_t *indices);
void pagevec_remove_exceptionals(struct pagevec *pvec);
-unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
- pgoff_t *start, unsigned nr_pages);
+unsigned pagevec_lookup_range(struct pagevec *pvec,
+ struct address_space *mapping,
+ pgoff_t *start, pgoff_t end, unsigned nr_pages);
+static inline unsigned pagevec_lookup(struct pagevec *pvec,
+ struct address_space *mapping,
+ pgoff_t *start, unsigned nr_pages)
+{
+ return pagevec_lookup_range(pvec, mapping, start, (pgoff_t)-1,
+ nr_pages);
+}
+
unsigned pagevec_lookup_tag(struct pagevec *pvec,
struct address_space *mapping, pgoff_t *index, int tag,
unsigned nr_pages);
diff --git a/mm/filemap.c b/mm/filemap.c
index 10d926a423e2..2693f87a7968 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1438,24 +1438,29 @@ unsigned find_get_entries(struct address_space *mapping,
}
/**
- * find_get_pages - gang pagecache lookup
+ * find_get_pages_range - gang pagecache lookup
* @mapping: The address_space to search
* @start: The starting page index
+ * @end: The final page index (inclusive)
* @nr_pages: The maximum number of pages
* @pages: Where the resulting pages are placed
*
- * find_get_pages() will search for and return a group of up to
- * @nr_pages pages in the mapping. The pages are placed at @pages.
- * find_get_pages() takes a reference against the returned pages.
+ * find_get_pages_range() will search for and return a group of up to @nr_pages
+ * pages in the mapping starting at index @start and up to index @end
+ * (inclusive). The pages are placed at @pages. find_get_pages_range() takes
+ * a reference against the returned pages.
*
* The search returns a group of mapping-contiguous pages with ascending
* indexes. There may be holes in the indices due to not-present pages.
* We also update @start to index the next page for the traversal.
*
- * find_get_pages() returns the number of pages which were found.
+ * find_get_pages_range() returns the number of pages which were found. If this
+ * number is smaller than @nr_pages, the end of specified range has been
+ * reached.
*/
-unsigned find_get_pages(struct address_space *mapping, pgoff_t *start,
- unsigned int nr_pages, struct page **pages)
+unsigned find_get_pages_range(struct address_space *mapping, pgoff_t *start,
+ pgoff_t end, unsigned int nr_pages,
+ struct page **pages)
{
struct radix_tree_iter iter;
void **slot;
@@ -1467,6 +1472,9 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t *start,
rcu_read_lock();
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, *start) {
struct page *head, *page;
+
+ if (iter.index > end)
+ break;
repeat:
page = radix_tree_deref_slot(slot);
if (unlikely(!page))
@@ -1502,15 +1510,25 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t *start,
}
pages[ret] = page;
- if (++ret == nr_pages)
- break;
+ if (++ret == nr_pages) {
+ *start = pages[ret - 1]->index + 1;
+ goto out;
+ }
}
+ /*
+ * We come here when there is no page beyond @end. We take care to not
+ * overflow the index @start as it confuses some of the callers. This
+ * breaks the iteration when there is page at index -1 but that is
+ * already broken anyway.
+ */
+ if (end == (pgoff_t)-1)
+ *start = (pgoff_t)-1;
+ else
+ *start = end + 1;
+out:
rcu_read_unlock();
- if (ret)
- *start = pages[ret - 1]->index + 1;
-
return ret;
}
diff --git a/mm/swap.c b/mm/swap.c
index 368d627cf279..804c9867af96 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -940,29 +940,35 @@ void pagevec_remove_exceptionals(struct pagevec *pvec)
}
/**
- * pagevec_lookup - gang pagecache lookup
+ * pagevec_lookup_range - gang pagecache lookup
* @pvec: Where the resulting pages are placed
* @mapping: The address_space to search
* @start: The starting page index
+ * @end: The final page index
* @nr_pages: The maximum number of pages
*
- * pagevec_lookup() will search for and return a group of up to @nr_pages pages
- * in the mapping. The pages are placed in @pvec. pagevec_lookup() takes a
+ * pagevec_lookup_range() will search for and return a group of up to @nr_pages
+ * pages in the mapping starting from index @start and upto index @end
+ * (inclusive). The pages are placed in @pvec. pagevec_lookup() takes a
* reference against the pages in @pvec.
*
* The search returns a group of mapping-contiguous pages with ascending
* indexes. There may be holes in the indices due to not-present pages. We
* also update @start to index the next page for the traversal.
*
- * pagevec_lookup() returns the number of pages which were found.
+ * pagevec_lookup_range() returns the number of pages which were found. If this
+ * number is smaller than @nr_pages, the end of specified range has been
+ * reached.
*/
-unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
- pgoff_t *start, unsigned nr_pages)
+unsigned pagevec_lookup_range(struct pagevec *pvec,
+ struct address_space *mapping, pgoff_t *start, pgoff_t end,
+ unsigned nr_pages)
{
- pvec->nr = find_get_pages(mapping, start, nr_pages, pvec->pages);
+ pvec->nr = find_get_pages_range(mapping, start, end, nr_pages,
+ pvec->pages);
return pagevec_count(pvec);
}
-EXPORT_SYMBOL(pagevec_lookup);
+EXPORT_SYMBOL(pagevec_lookup_range);
unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
pgoff_t *index, int tag, unsigned nr_pages)
--
2.12.3
next prev parent reply other threads:[~2017-06-01 9:33 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-06-01 9:32 [PATCH 00/35 v1] pagevec API cleanups Jan Kara
2017-06-01 9:32 ` [PATCH 01/35] fscache: Remove unused ->now_uncached callback Jan Kara
2017-06-01 9:32 ` [PATCH 02/35] ext4: Fix SEEK_HOLE Jan Kara
2017-06-01 9:32 ` [PATCH 03/35] ext4: Fix off-by-in in loop termination in ext4_find_unwritten_pgoff() Jan Kara
2017-06-01 9:32 ` [PATCH 04/35] dax: Fix inefficiency in dax_writeback_mapping_range() Jan Kara
2017-06-01 9:32 ` [PATCH 05/35] mm: Fix THP handling in invalidate_mapping_pages() Jan Kara
2017-06-01 9:32 ` [PATCH 06/35] mm: Make pagevec_lookup() update index Jan Kara
2017-06-01 9:32 ` Jan Kara [this message]
2017-06-01 9:32 ` [PATCH 08/35] fs: Fix performance regression in clean_bdev_aliases() Jan Kara
2017-06-01 9:32 ` [PATCH 09/35] ext4: Use pagevec_lookup_range() in ext4_find_unwritten_pgoff() Jan Kara
2017-06-01 9:32 ` [PATCH 10/35] ext4: Use pagevec_lookup_range() in writeback code Jan Kara
2017-06-01 9:32 ` [PATCH 11/35] hugetlbfs: Use pagevec_lookup_range() in remove_inode_hugepages() Jan Kara
2017-06-01 9:32 ` [PATCH 12/35] xfs: Use pagevec_lookup_range() in xfs_find_get_desired_pgoff() Jan Kara
2017-06-01 9:32 ` [PATCH 13/35] mm: Remove nr_pages argument from pagevec_lookup{,_range}() Jan Kara
2017-06-01 9:32 ` [PATCH 14/35] mm: Implement find_get_pages_range_tag() Jan Kara
2017-06-01 9:32 ` [PATCH 15/35] btrfs: Use pagevec_lookup_range_tag() Jan Kara
2017-06-01 9:32 ` [PATCH 16/35] ceph: " Jan Kara
2017-06-01 9:32 ` [PATCH 17/35] ext4: " Jan Kara
2017-06-01 9:32 ` [PATCH 18/35] f2fs: " Jan Kara
2017-06-01 9:32 ` [PATCH 19/35] f2fs: Simplify page iteration loops Jan Kara
2017-06-01 13:00 ` kbuild test robot
2017-06-01 9:32 ` [PATCH 20/35] f2fs: Use find_get_pages_tag() for looking up single page Jan Kara
2017-06-01 9:32 ` [PATCH 21/35] gfs2: Use pagevec_lookup_range_tag() Jan Kara
2017-06-01 9:32 ` [PATCH 22/35] nilfs2: " Jan Kara
2017-06-01 9:32 ` [PATCH 23/35] mm: Use pagevec_lookup_range_tag() in __filemap_fdatawait_range() Jan Kara
2017-06-01 9:32 ` [PATCH 24/35] mm: Use pagevec_lookup_range_tag() in write_cache_pages() Jan Kara
2017-06-01 9:32 ` [PATCH 25/35] mm: Remove nr_pages argument from pagevec_lookup_{,range}_tag() Jan Kara
2017-06-01 9:32 ` [PATCH 26/35] afs: Use find_get_pages_range_tag() Jan Kara
2017-06-01 9:32 ` [PATCH 27/35] shmem: Use pagevec_lookup() in shmem_unlock_mapping() Jan Kara
2017-06-01 9:32 ` [PATCH 28/35] shmem: Use pagevec_lookup_entries() Jan Kara
2017-06-01 9:32 ` [PATCH 29/35] mm: Make pagevec_lookup_entries() update index Jan Kara
2017-06-01 9:32 ` [PATCH 30/35] mm: Implement find_get_entries_range() Jan Kara
2017-06-01 9:32 ` [PATCH 31/35] shmem: Convert to pagevec_lookup_entries_range() Jan Kara
2017-06-01 13:55 ` kbuild test robot
2017-06-01 9:32 ` [PATCH 32/35] mm: Convert truncate code " Jan Kara
2017-06-01 9:32 ` [PATCH 33/35] mm: Remove nr_entries argument from pagevec_lookup_entries{,_range}() Jan Kara
2017-06-01 9:32 ` [PATCH 34/35] mm: Make find_get_entries_tag() update index Jan Kara
2017-06-01 9:32 ` [PATCH 35/35] mm: Implement find_get_entries_range_tag() Jan Kara
2017-06-01 10:26 ` [PATCH 01/35] fscache: Remove unused ->now_uncached callback David Howells
2017-06-01 11:34 ` Jan Kara
2017-06-19 13:12 ` Jan Kara
2017-06-01 11:36 ` [Cluster-devel] [PATCH 00/35 v1] pagevec API cleanups Christoph Hellwig
2017-06-01 12:05 ` Jan Kara
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170601093245.29238-8-jack@suse.cz \
--to=jack@suse.cz \
--cc=ceph-devel@vger.kernel.org \
--cc=cluster-devel@redhat.com \
--cc=darrick.wong@oracle.com \
--cc=dhowells@redhat.com \
--cc=dsterba@suse.com \
--cc=hughd@google.com \
--cc=idryomov@gmail.com \
--cc=jaegeuk@kernel.org \
--cc=konishi.ryusuke@lab.ntt.co.jp \
--cc=linux-afs@lists.infradead.org \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-mm@kvack.org \
--cc=linux-nilfs@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
--cc=nyc@holomorphy.com \
--cc=rpeterso@redhat.com \
--cc=tytso@mit.edu \
--cc=zyan@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).