diff mbox series

[RFC] find_get_heads_contig

Message ID 20201021012630.GG20115@casper.infradead.org (mailing list archive)
State New, archived
Headers show
Series [RFC] find_get_heads_contig | expand

Commit Message

Matthew Wilcox Oct. 21, 2020, 1:26 a.m. UTC
I was going to convert find_get_pages_contig() to only return head pages,
but I want to change the API to take a pagevec like the other find_*
functions have or will have.  And it'd be nice if the name of the function
reminded callers that it only returns head pages.  So comments on this?

Comments

Kent Overstreet Oct. 21, 2020, 4:19 a.m. UTC | #1
On Wed, Oct 21, 2020 at 02:26:30AM +0100, Matthew Wilcox wrote:
> I was going to convert find_get_pages_contig() to only return head pages,
> but I want to change the API to take a pagevec like the other find_*
> functions have or will have.  And it'd be nice if the name of the function
> reminded callers that it only returns head pages.  So comments on this?

Perfect, looks like exactly what we need - at some point I can change my
vectorized pagecache stuff to use this.

Reviewed-by: Kent Overstreet <kent.overstreet@gmail.com>

> 
> diff --git a/mm/filemap.c b/mm/filemap.c
> index 31ba06409dfa..b7dd2523fe79 100644
> --- a/mm/filemap.c
> +++ b/mm/filemap.c
> @@ -2093,6 +2093,58 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
>  }
>  EXPORT_SYMBOL(find_get_pages_contig);
>  
> +/**
> + * find_get_heads_contig - Return head pages for a contiguous byte range.
> + * @mapping: The address_space to search.
> + * @start: The starting page index.
> + * @end: The final page index (inclusive).
> + * @pvec: Where the resulting pages are placed.
> + *
> + * find_get_heads_contig() will return a batch of head pages from
> + * @mapping.  Pages are returned with an incremented refcount.  Only the
> + * head page of a THP is returned.  In contrast to find_get_entries(),
> + * pages which are partially outside the range are returned.  The head
> + * pages have ascending indices.  The indices may not be consecutive,
> + * but the bytes represented by the pages are contiguous.  If there is
> + * no page at @start, no pages will be returned.
> + *
> + * Return: The number of pages which were found.
> + */
> +unsigned find_get_heads_contig(struct address_space *mapping, pgoff_t start,
> +		pgoff_t end, struct pagevec *pvec)
> +{
> +	XA_STATE(xas, &mapping->i_pages, start);
> +	struct page *page;
> +
> +	rcu_read_lock();
> +	for (page = xas_load(&xas); page; page = xas_next(&xas)) {
> +		if (xas.xa_index > end)
> +			break;
> +		if (xas_retry(&xas, page) || xa_is_sibling(page))
> +			continue;
> +		if (xa_is_value(page))
> +			break;
> +
> +		if (!page_cache_get_speculative(page))
> +			goto retry;
> +
> +		/* Has the page moved or been split? */
> +		if (unlikely(page != xas_reload(&xas)))
> +			goto put_page;
> +
> +		if (!pagevec_add(pvec, page))
> +			break;
> +		continue;
> +put_page:
> +		put_page(page);
> +retry:
> +		xas_reset(&xas);
> +	}
> +	rcu_read_unlock();
> +	return pagevec_count(pvec);
> +}
> +EXPORT_SYMBOL(find_get_heads_contig);
> +
>  /**
>   * find_get_pages_range_tag - Find and return head pages matching @tag.
>   * @mapping:	the address_space to search
diff mbox series

Patch

diff --git a/mm/filemap.c b/mm/filemap.c
index 31ba06409dfa..b7dd2523fe79 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2093,6 +2093,58 @@  unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
 }
 EXPORT_SYMBOL(find_get_pages_contig);
 
+/**
+ * find_get_heads_contig - Return head pages for a contiguous byte range.
+ * @mapping: The address_space to search.
+ * @start: The starting page index.
+ * @end: The final page index (inclusive).
+ * @pvec: Where the resulting pages are placed.
+ *
+ * find_get_heads_contig() will return a batch of head pages from
+ * @mapping.  Pages are returned with an incremented refcount.  Only the
+ * head page of a THP is returned.  In contrast to find_get_entries(),
+ * pages which are partially outside the range are returned.  The head
+ * pages have ascending indices.  The indices may not be consecutive,
+ * but the bytes represented by the pages are contiguous.  If there is
+ * no page at @start, no pages will be returned.
+ *
+ * Return: The number of pages which were found.
+ */
+unsigned find_get_heads_contig(struct address_space *mapping, pgoff_t start,
+		pgoff_t end, struct pagevec *pvec)
+{
+	XA_STATE(xas, &mapping->i_pages, start);
+	struct page *page;
+
+	rcu_read_lock();
+	for (page = xas_load(&xas); page; page = xas_next(&xas)) {
+		if (xas.xa_index > end)
+			break;
+		if (xas_retry(&xas, page) || xa_is_sibling(page))
+			continue;
+		if (xa_is_value(page))
+			break;
+
+		if (!page_cache_get_speculative(page))
+			goto retry;
+
+		/* Has the page moved or been split? */
+		if (unlikely(page != xas_reload(&xas)))
+			goto put_page;
+
+		if (!pagevec_add(pvec, page))
+			break;
+		continue;
+put_page:
+		put_page(page);
+retry:
+		xas_reset(&xas);
+	}
+	rcu_read_unlock();
+	return pagevec_count(pvec);
+}
+EXPORT_SYMBOL(find_get_heads_contig);
+
 /**
  * find_get_pages_range_tag - Find and return head pages matching @tag.
  * @mapping:	the address_space to search