Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

page cache: Convert find_get_pages_contig to XArray

There's no direct replacement for radix_tree_for_each_contig()
in the XArray API as it's an unusual thing to do. Instead,
open-code a loop using xas_next(). This removes the only user of
radix_tree_for_each_contig() so delete the iterator from the API and
the test suite code for it.

Signed-off-by: Matthew Wilcox <willy@infradead.org>

+22 -72
-1
.clang-format
··· 323 323 - 'protocol_for_each_card' 324 324 - 'protocol_for_each_dev' 325 325 - 'queue_for_each_hw_ctx' 326 - - 'radix_tree_for_each_contig' 327 326 - 'radix_tree_for_each_slot' 328 327 - 'radix_tree_for_each_tagged' 329 328 - 'rbtree_postorder_for_each_entry_safe'
-17
include/linux/radix-tree.h
··· 523 523 slot = radix_tree_next_slot(slot, iter, 0)) 524 524 525 525 /** 526 - * radix_tree_for_each_contig - iterate over contiguous slots 527 - * 528 - * @slot: the void** variable for pointer to slot 529 - * @root: the struct radix_tree_root pointer 530 - * @iter: the struct radix_tree_iter pointer 531 - * @start: iteration starting index 532 - * 533 - * @slot points to radix tree slot, @iter->index contains its index. 534 - */ 535 - #define radix_tree_for_each_contig(slot, root, iter, start) \ 536 - for (slot = radix_tree_iter_init(iter, start) ; \ 537 - slot || (slot = radix_tree_next_chunk(root, iter, \ 538 - RADIX_TREE_ITER_CONTIG)) ; \ 539 - slot = radix_tree_next_slot(slot, iter, \ 540 - RADIX_TREE_ITER_CONTIG)) 541 - 542 - /** 543 526 * radix_tree_for_each_tagged - iterate over tagged slots 544 527 * 545 528 * @slot: the void** variable for pointer to slot
+22 -31
mm/filemap.c
··· 1721 1721 unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index, 1722 1722 unsigned int nr_pages, struct page **pages) 1723 1723 { 1724 - struct radix_tree_iter iter; 1725 - void **slot; 1724 + XA_STATE(xas, &mapping->i_pages, index); 1725 + struct page *page; 1726 1726 unsigned int ret = 0; 1727 1727 1728 1728 if (unlikely(!nr_pages)) 1729 1729 return 0; 1730 1730 1731 1731 rcu_read_lock(); 1732 - radix_tree_for_each_contig(slot, &mapping->i_pages, &iter, index) { 1733 - struct page *head, *page; 1734 - repeat: 1735 - page = radix_tree_deref_slot(slot); 1736 - /* The hole, there no reason to continue */ 1737 - if (unlikely(!page)) 1732 + for (page = xas_load(&xas); page; page = xas_next(&xas)) { 1733 + struct page *head; 1734 + if (xas_retry(&xas, page)) 1735 + continue; 1736 + /* 1737 + * If the entry has been swapped out, we can stop looking. 1738 + * No current caller is looking for DAX entries. 1739 + */ 1740 + if (xa_is_value(page)) 1738 1741 break; 1739 - 1740 - if (radix_tree_exception(page)) { 1741 - if (radix_tree_deref_retry(page)) { 1742 - slot = radix_tree_iter_retry(&iter); 1743 - continue; 1744 - } 1745 - /* 1746 - * A shadow entry of a recently evicted page, 1747 - * or a swap entry from shmem/tmpfs. Stop 1748 - * looking for contiguous pages. 1749 - */ 1750 - break; 1751 - } 1752 1742 1753 1743 head = compound_head(page); 1754 1744 if (!page_cache_get_speculative(head)) 1755 - goto repeat; 1745 + goto retry; 1756 1746 1757 1747 /* The page was split under us? */ 1758 - if (compound_head(page) != head) { 1759 - put_page(head); 1760 - goto repeat; 1761 - } 1748 + if (compound_head(page) != head) 1749 + goto put_page; 1762 1750 1763 1751 /* Has the page moved? */ 1764 - if (unlikely(page != *slot)) { 1765 - put_page(head); 1766 - goto repeat; 1767 - } 1752 + if (unlikely(page != xas_reload(&xas))) 1753 + goto put_page; 1768 1754 1769 1755 /* 1770 1756 * must check mapping and index after taking the ref. 1771 1757 * otherwise we can get both false positives and false 1772 1758 * negatives, which is just confusing to the caller. 1773 1759 */ 1774 - if (page->mapping == NULL || page_to_pgoff(page) != iter.index) { 1760 + if (!page->mapping || page_to_pgoff(page) != xas.xa_index) { 1775 1761 put_page(page); 1776 1762 break; 1777 1763 } ··· 1765 1779 pages[ret] = page; 1766 1780 if (++ret == nr_pages) 1767 1781 break; 1782 + continue; 1783 + put_page: 1784 + put_page(head); 1785 + retry: 1786 + xas_reset(&xas); 1768 1787 } 1769 1788 rcu_read_unlock(); 1770 1789 return ret;
-23
tools/testing/radix-tree/regression3.c
··· 69 69 continue; 70 70 } 71 71 } 72 - radix_tree_delete(&root, 1); 73 - 74 - first = true; 75 - radix_tree_for_each_contig(slot, &root, &iter, 0) { 76 - printv(2, "contig %ld %p\n", iter.index, *slot); 77 - if (first) { 78 - radix_tree_insert(&root, 1, ptr); 79 - first = false; 80 - } 81 - if (radix_tree_deref_retry(*slot)) { 82 - printv(2, "retry at %ld\n", iter.index); 83 - slot = radix_tree_iter_retry(&iter); 84 - continue; 85 - } 86 - } 87 72 88 73 radix_tree_for_each_slot(slot, &root, &iter, 0) { 89 74 printv(2, "slot %ld %p\n", iter.index, *slot); 90 - if (!iter.index) { 91 - printv(2, "next at %ld\n", iter.index); 92 - slot = radix_tree_iter_resume(slot, &iter); 93 - } 94 - } 95 - 96 - radix_tree_for_each_contig(slot, &root, &iter, 0) { 97 - printv(2, "contig %ld %p\n", iter.index, *slot); 98 75 if (!iter.index) { 99 76 printv(2, "next at %ld\n", iter.index); 100 77 slot = radix_tree_iter_resume(slot, &iter);