Re: [PATCH v2 07/11] mm: add find_get_entries_tag()
From: Dave Chinner <david@fromorbit.com>
Date: 2015-11-16 22:42:22
Also in:
linux-fsdevel, linux-mm, linux-xfs, lkml, nvdimm
On Fri, Nov 13, 2015 at 05:06:46PM -0700, Ross Zwisler wrote:
quoted hunk ↗ jump to hunk
Add find_get_entries_tag() to the family of functions that include find_get_entries(), find_get_pages() and find_get_pages_tag(). This is needed for DAX dirty page handling because we need a list of both page offsets and radix tree entries ('indices' and 'entries' in this function) that are marked with the PAGECACHE_TAG_TOWRITE tag. Signed-off-by: Ross Zwisler <redacted> --- include/linux/pagemap.h | 3 +++ mm/filemap.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+)diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index a6c78e0..6fea3be 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h@@ -354,6 +354,9 @@ 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, int tag, unsigned int nr_pages, struct page **pages); +unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start, + int tag, unsigned int nr_entries, + struct page **entries, pgoff_t *indices); struct page *grab_cache_page_write_begin(struct address_space *mapping, pgoff_t index, unsigned flags);diff --git a/mm/filemap.c b/mm/filemap.c index d5e94fd..89ab448 100644 --- a/mm/filemap.c +++ b/mm/filemap.c@@ -1454,6 +1454,67 @@ repeat: } EXPORT_SYMBOL(find_get_pages_tag); +/** + * find_get_entries_tag - find and return entries that match @tag + * @mapping: the address_space to search + * @start: the starting page cache index + * @tag: the tag index + * @nr_entries: the maximum number of entries + * @entries: where the resulting entries are placed + * @indices: the cache indices corresponding to the entries in @entries + * + * Like find_get_entries, except we only return entries which are tagged with + * @tag. + */ +unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start, + int tag, unsigned int nr_entries, + struct page **entries, pgoff_t *indices) +{ + void **slot; + unsigned int ret = 0; + struct radix_tree_iter iter; + + if (!nr_entries) + return 0; + + rcu_read_lock(); +restart: + radix_tree_for_each_tagged(slot, &mapping->page_tree, + &iter, start, tag) { + struct page *page; +repeat: + page = radix_tree_deref_slot(slot); + if (unlikely(!page)) + continue; + if (radix_tree_exception(page)) { + if (radix_tree_deref_retry(page)) + goto restart;
That restart condition looks wrong. ret can be non-zero, but we start looking from the original start index again, resulting in duplicates being added to the return arrays... Cheers, Dave. -- Dave Chinner david@fromorbit.com -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>