forked from mirrors/linux
		
	filemap: prepare find and delete operations for huge pages
For now, we would have HPAGE_PMD_NR entries in radix tree for every huge page. That's suboptimal and it will be changed to use Matthew's multi-order entries later. 'add' operation is not changed, because we don't need it to implement hugetmpfs: shmem uses its own implementation. Link: http://lkml.kernel.org/r/1466021202-61880-25-git-send-email-kirill.shutemov@linux.intel.com Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									c78c66d1dd
								
							
						
					
					
						commit
						83929372f6
					
				
					 1 changed files with 122 additions and 56 deletions
				
			
		
							
								
								
									
										150
									
								
								mm/filemap.c
									
									
									
									
									
								
							
							
						
						
									
										150
									
								
								mm/filemap.c
									
									
									
									
									
								
							| 
						 | 
					@ -114,14 +114,14 @@ static void page_cache_tree_delete(struct address_space *mapping,
 | 
				
			||||||
				   struct page *page, void *shadow)
 | 
									   struct page *page, void *shadow)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct radix_tree_node *node;
 | 
						struct radix_tree_node *node;
 | 
				
			||||||
 | 
						int i, nr = PageHuge(page) ? 1 : hpage_nr_pages(page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	VM_BUG_ON(!PageLocked(page));
 | 
						VM_BUG_ON_PAGE(!PageLocked(page), page);
 | 
				
			||||||
 | 
						VM_BUG_ON_PAGE(PageTail(page), page);
 | 
				
			||||||
	node = radix_tree_replace_clear_tags(&mapping->page_tree, page->index,
 | 
						VM_BUG_ON_PAGE(nr != 1 && shadow, page);
 | 
				
			||||||
								shadow);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (shadow) {
 | 
						if (shadow) {
 | 
				
			||||||
		mapping->nrexceptional++;
 | 
							mapping->nrexceptional += nr;
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Make sure the nrexceptional update is committed before
 | 
							 * Make sure the nrexceptional update is committed before
 | 
				
			||||||
		 * the nrpages update so that final truncate racing
 | 
							 * the nrpages update so that final truncate racing
 | 
				
			||||||
| 
						 | 
					@ -130,31 +130,38 @@ static void page_cache_tree_delete(struct address_space *mapping,
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		smp_wmb();
 | 
							smp_wmb();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mapping->nrpages--;
 | 
						mapping->nrpages -= nr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!node)
 | 
						for (i = 0; i < nr; i++) {
 | 
				
			||||||
 | 
							node = radix_tree_replace_clear_tags(&mapping->page_tree,
 | 
				
			||||||
 | 
									page->index + i, shadow);
 | 
				
			||||||
 | 
							if (!node) {
 | 
				
			||||||
 | 
								VM_BUG_ON_PAGE(nr != 1, page);
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		workingset_node_pages_dec(node);
 | 
							workingset_node_pages_dec(node);
 | 
				
			||||||
		if (shadow)
 | 
							if (shadow)
 | 
				
			||||||
			workingset_node_shadows_inc(node);
 | 
								workingset_node_shadows_inc(node);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			if (__radix_tree_delete_node(&mapping->page_tree, node))
 | 
								if (__radix_tree_delete_node(&mapping->page_tree, node))
 | 
				
			||||||
			return;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
	 * Track node that only contains shadow entries. DAX mappings contain
 | 
							 * Track node that only contains shadow entries. DAX mappings
 | 
				
			||||||
	 * no shadow entries and may contain other exceptional entries so skip
 | 
							 * contain no shadow entries and may contain other exceptional
 | 
				
			||||||
	 * those.
 | 
							 * entries so skip those.
 | 
				
			||||||
		 *
 | 
							 *
 | 
				
			||||||
	 * Avoid acquiring the list_lru lock if already tracked.  The
 | 
							 * Avoid acquiring the list_lru lock if already tracked.
 | 
				
			||||||
	 * list_empty() test is safe as node->private_list is
 | 
							 * The list_empty() test is safe as node->private_list is
 | 
				
			||||||
		 * protected by mapping->tree_lock.
 | 
							 * protected by mapping->tree_lock.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (!dax_mapping(mapping) && !workingset_node_pages(node) &&
 | 
							if (!dax_mapping(mapping) && !workingset_node_pages(node) &&
 | 
				
			||||||
				list_empty(&node->private_list)) {
 | 
									list_empty(&node->private_list)) {
 | 
				
			||||||
			node->private_data = mapping;
 | 
								node->private_data = mapping;
 | 
				
			||||||
		list_lru_add(&workingset_shadow_nodes, &node->private_list);
 | 
								list_lru_add(&workingset_shadow_nodes,
 | 
				
			||||||
 | 
										&node->private_list);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -166,6 +173,7 @@ static void page_cache_tree_delete(struct address_space *mapping,
 | 
				
			||||||
void __delete_from_page_cache(struct page *page, void *shadow)
 | 
					void __delete_from_page_cache(struct page *page, void *shadow)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct address_space *mapping = page->mapping;
 | 
						struct address_space *mapping = page->mapping;
 | 
				
			||||||
 | 
						int nr = hpage_nr_pages(page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trace_mm_filemap_delete_from_page_cache(page);
 | 
						trace_mm_filemap_delete_from_page_cache(page);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -178,6 +186,7 @@ void __delete_from_page_cache(struct page *page, void *shadow)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		cleancache_invalidate_page(mapping, page);
 | 
							cleancache_invalidate_page(mapping, page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						VM_BUG_ON_PAGE(PageTail(page), page);
 | 
				
			||||||
	VM_BUG_ON_PAGE(page_mapped(page), page);
 | 
						VM_BUG_ON_PAGE(page_mapped(page), page);
 | 
				
			||||||
	if (!IS_ENABLED(CONFIG_DEBUG_VM) && unlikely(page_mapped(page))) {
 | 
						if (!IS_ENABLED(CONFIG_DEBUG_VM) && unlikely(page_mapped(page))) {
 | 
				
			||||||
		int mapcount;
 | 
							int mapcount;
 | 
				
			||||||
| 
						 | 
					@ -209,9 +218,9 @@ void __delete_from_page_cache(struct page *page, void *shadow)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* hugetlb pages do not participate in page cache accounting. */
 | 
						/* hugetlb pages do not participate in page cache accounting. */
 | 
				
			||||||
	if (!PageHuge(page))
 | 
						if (!PageHuge(page))
 | 
				
			||||||
		__dec_zone_page_state(page, NR_FILE_PAGES);
 | 
							__mod_zone_page_state(page_zone(page), NR_FILE_PAGES, -nr);
 | 
				
			||||||
	if (PageSwapBacked(page))
 | 
						if (PageSwapBacked(page))
 | 
				
			||||||
		__dec_zone_page_state(page, NR_SHMEM);
 | 
							__mod_zone_page_state(page_zone(page), NR_SHMEM, -nr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * At this point page must be either written or cleaned by truncate.
 | 
						 * At this point page must be either written or cleaned by truncate.
 | 
				
			||||||
| 
						 | 
					@ -235,9 +244,8 @@ void __delete_from_page_cache(struct page *page, void *shadow)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void delete_from_page_cache(struct page *page)
 | 
					void delete_from_page_cache(struct page *page)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct address_space *mapping = page->mapping;
 | 
						struct address_space *mapping = page_mapping(page);
 | 
				
			||||||
	unsigned long flags;
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	void (*freepage)(struct page *);
 | 
						void (*freepage)(struct page *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BUG_ON(!PageLocked(page));
 | 
						BUG_ON(!PageLocked(page));
 | 
				
			||||||
| 
						 | 
					@ -250,8 +258,14 @@ void delete_from_page_cache(struct page *page)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (freepage)
 | 
						if (freepage)
 | 
				
			||||||
		freepage(page);
 | 
							freepage(page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (PageTransHuge(page) && !PageHuge(page)) {
 | 
				
			||||||
 | 
							page_ref_sub(page, HPAGE_PMD_NR);
 | 
				
			||||||
 | 
							VM_BUG_ON_PAGE(page_count(page) <= 0, page);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		put_page(page);
 | 
							put_page(page);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(delete_from_page_cache);
 | 
					EXPORT_SYMBOL(delete_from_page_cache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int filemap_check_errors(struct address_space *mapping)
 | 
					static int filemap_check_errors(struct address_space *mapping)
 | 
				
			||||||
| 
						 | 
					@ -1053,7 +1067,7 @@ EXPORT_SYMBOL(page_cache_prev_hole);
 | 
				
			||||||
struct page *find_get_entry(struct address_space *mapping, pgoff_t offset)
 | 
					struct page *find_get_entry(struct address_space *mapping, pgoff_t offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void **pagep;
 | 
						void **pagep;
 | 
				
			||||||
	struct page *page;
 | 
						struct page *head, *page;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
repeat:
 | 
					repeat:
 | 
				
			||||||
| 
						 | 
					@ -1073,16 +1087,24 @@ struct page *find_get_entry(struct address_space *mapping, pgoff_t offset)
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (!page_cache_get_speculative(page))
 | 
					
 | 
				
			||||||
 | 
							head = compound_head(page);
 | 
				
			||||||
 | 
							if (!page_cache_get_speculative(head))
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* The page was split under us? */
 | 
				
			||||||
 | 
							if (compound_head(page) != head) {
 | 
				
			||||||
 | 
								put_page(head);
 | 
				
			||||||
 | 
								goto repeat;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Has the page moved?
 | 
							 * Has the page moved?
 | 
				
			||||||
		 * This is part of the lockless pagecache protocol. See
 | 
							 * This is part of the lockless pagecache protocol. See
 | 
				
			||||||
		 * include/linux/pagemap.h for details.
 | 
							 * include/linux/pagemap.h for details.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (unlikely(page != *pagep)) {
 | 
							if (unlikely(page != *pagep)) {
 | 
				
			||||||
			put_page(page);
 | 
								put_page(head);
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1118,12 +1140,12 @@ struct page *find_lock_entry(struct address_space *mapping, pgoff_t offset)
 | 
				
			||||||
	if (page && !radix_tree_exception(page)) {
 | 
						if (page && !radix_tree_exception(page)) {
 | 
				
			||||||
		lock_page(page);
 | 
							lock_page(page);
 | 
				
			||||||
		/* Has the page been truncated? */
 | 
							/* Has the page been truncated? */
 | 
				
			||||||
		if (unlikely(page->mapping != mapping)) {
 | 
							if (unlikely(page_mapping(page) != mapping)) {
 | 
				
			||||||
			unlock_page(page);
 | 
								unlock_page(page);
 | 
				
			||||||
			put_page(page);
 | 
								put_page(page);
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		VM_BUG_ON_PAGE(page->index != offset, page);
 | 
							VM_BUG_ON_PAGE(page_to_pgoff(page) != offset, page);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return page;
 | 
						return page;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1255,7 +1277,7 @@ unsigned find_get_entries(struct address_space *mapping,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
 | 
						radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
 | 
				
			||||||
		struct page *page;
 | 
							struct page *head, *page;
 | 
				
			||||||
repeat:
 | 
					repeat:
 | 
				
			||||||
		page = radix_tree_deref_slot(slot);
 | 
							page = radix_tree_deref_slot(slot);
 | 
				
			||||||
		if (unlikely(!page))
 | 
							if (unlikely(!page))
 | 
				
			||||||
| 
						 | 
					@ -1272,12 +1294,20 @@ unsigned find_get_entries(struct address_space *mapping,
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			goto export;
 | 
								goto export;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (!page_cache_get_speculative(page))
 | 
					
 | 
				
			||||||
 | 
							head = compound_head(page);
 | 
				
			||||||
 | 
							if (!page_cache_get_speculative(head))
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* The page was split under us? */
 | 
				
			||||||
 | 
							if (compound_head(page) != head) {
 | 
				
			||||||
 | 
								put_page(head);
 | 
				
			||||||
 | 
								goto repeat;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Has the page moved? */
 | 
							/* Has the page moved? */
 | 
				
			||||||
		if (unlikely(page != *slot)) {
 | 
							if (unlikely(page != *slot)) {
 | 
				
			||||||
			put_page(page);
 | 
								put_page(head);
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
export:
 | 
					export:
 | 
				
			||||||
| 
						 | 
					@ -1318,7 +1348,7 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
 | 
						radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
 | 
				
			||||||
		struct page *page;
 | 
							struct page *head, *page;
 | 
				
			||||||
repeat:
 | 
					repeat:
 | 
				
			||||||
		page = radix_tree_deref_slot(slot);
 | 
							page = radix_tree_deref_slot(slot);
 | 
				
			||||||
		if (unlikely(!page))
 | 
							if (unlikely(!page))
 | 
				
			||||||
| 
						 | 
					@ -1337,12 +1367,19 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!page_cache_get_speculative(page))
 | 
							head = compound_head(page);
 | 
				
			||||||
 | 
							if (!page_cache_get_speculative(head))
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* The page was split under us? */
 | 
				
			||||||
 | 
							if (compound_head(page) != head) {
 | 
				
			||||||
 | 
								put_page(head);
 | 
				
			||||||
 | 
								goto repeat;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Has the page moved? */
 | 
							/* Has the page moved? */
 | 
				
			||||||
		if (unlikely(page != *slot)) {
 | 
							if (unlikely(page != *slot)) {
 | 
				
			||||||
			put_page(page);
 | 
								put_page(head);
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1379,7 +1416,7 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	radix_tree_for_each_contig(slot, &mapping->page_tree, &iter, index) {
 | 
						radix_tree_for_each_contig(slot, &mapping->page_tree, &iter, index) {
 | 
				
			||||||
		struct page *page;
 | 
							struct page *head, *page;
 | 
				
			||||||
repeat:
 | 
					repeat:
 | 
				
			||||||
		page = radix_tree_deref_slot(slot);
 | 
							page = radix_tree_deref_slot(slot);
 | 
				
			||||||
		/* The hole, there no reason to continue */
 | 
							/* The hole, there no reason to continue */
 | 
				
			||||||
| 
						 | 
					@ -1399,12 +1436,19 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!page_cache_get_speculative(page))
 | 
							head = compound_head(page);
 | 
				
			||||||
 | 
							if (!page_cache_get_speculative(head))
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* The page was split under us? */
 | 
				
			||||||
 | 
							if (compound_head(page) != head) {
 | 
				
			||||||
 | 
								put_page(head);
 | 
				
			||||||
 | 
								goto repeat;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Has the page moved? */
 | 
							/* Has the page moved? */
 | 
				
			||||||
		if (unlikely(page != *slot)) {
 | 
							if (unlikely(page != *slot)) {
 | 
				
			||||||
			put_page(page);
 | 
								put_page(head);
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1413,7 +1457,7 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
 | 
				
			||||||
		 * otherwise we can get both false positives and false
 | 
							 * otherwise we can get both false positives and false
 | 
				
			||||||
		 * negatives, which is just confusing to the caller.
 | 
							 * negatives, which is just confusing to the caller.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (page->mapping == NULL || page->index != iter.index) {
 | 
							if (page->mapping == NULL || page_to_pgoff(page) != iter.index) {
 | 
				
			||||||
			put_page(page);
 | 
								put_page(page);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1451,7 +1495,7 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	radix_tree_for_each_tagged(slot, &mapping->page_tree,
 | 
						radix_tree_for_each_tagged(slot, &mapping->page_tree,
 | 
				
			||||||
				   &iter, *index, tag) {
 | 
									   &iter, *index, tag) {
 | 
				
			||||||
		struct page *page;
 | 
							struct page *head, *page;
 | 
				
			||||||
repeat:
 | 
					repeat:
 | 
				
			||||||
		page = radix_tree_deref_slot(slot);
 | 
							page = radix_tree_deref_slot(slot);
 | 
				
			||||||
		if (unlikely(!page))
 | 
							if (unlikely(!page))
 | 
				
			||||||
| 
						 | 
					@ -1476,12 +1520,19 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!page_cache_get_speculative(page))
 | 
							head = compound_head(page);
 | 
				
			||||||
 | 
							if (!page_cache_get_speculative(head))
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* The page was split under us? */
 | 
				
			||||||
 | 
							if (compound_head(page) != head) {
 | 
				
			||||||
 | 
								put_page(head);
 | 
				
			||||||
 | 
								goto repeat;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Has the page moved? */
 | 
							/* Has the page moved? */
 | 
				
			||||||
		if (unlikely(page != *slot)) {
 | 
							if (unlikely(page != *slot)) {
 | 
				
			||||||
			put_page(page);
 | 
								put_page(head);
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1525,7 +1576,7 @@ unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start,
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	radix_tree_for_each_tagged(slot, &mapping->page_tree,
 | 
						radix_tree_for_each_tagged(slot, &mapping->page_tree,
 | 
				
			||||||
				   &iter, start, tag) {
 | 
									   &iter, start, tag) {
 | 
				
			||||||
		struct page *page;
 | 
							struct page *head, *page;
 | 
				
			||||||
repeat:
 | 
					repeat:
 | 
				
			||||||
		page = radix_tree_deref_slot(slot);
 | 
							page = radix_tree_deref_slot(slot);
 | 
				
			||||||
		if (unlikely(!page))
 | 
							if (unlikely(!page))
 | 
				
			||||||
| 
						 | 
					@ -1543,12 +1594,20 @@ unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start,
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			goto export;
 | 
								goto export;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (!page_cache_get_speculative(page))
 | 
					
 | 
				
			||||||
 | 
							head = compound_head(page);
 | 
				
			||||||
 | 
							if (!page_cache_get_speculative(head))
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* The page was split under us? */
 | 
				
			||||||
 | 
							if (compound_head(page) != head) {
 | 
				
			||||||
 | 
								put_page(head);
 | 
				
			||||||
 | 
								goto repeat;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Has the page moved? */
 | 
							/* Has the page moved? */
 | 
				
			||||||
		if (unlikely(page != *slot)) {
 | 
							if (unlikely(page != *slot)) {
 | 
				
			||||||
			put_page(page);
 | 
								put_page(head);
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
export:
 | 
					export:
 | 
				
			||||||
| 
						 | 
					@ -2137,7 +2196,7 @@ void filemap_map_pages(struct fault_env *fe,
 | 
				
			||||||
	struct address_space *mapping = file->f_mapping;
 | 
						struct address_space *mapping = file->f_mapping;
 | 
				
			||||||
	pgoff_t last_pgoff = start_pgoff;
 | 
						pgoff_t last_pgoff = start_pgoff;
 | 
				
			||||||
	loff_t size;
 | 
						loff_t size;
 | 
				
			||||||
	struct page *page;
 | 
						struct page *head, *page;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	radix_tree_for_each_slot(slot, &mapping->page_tree, &iter,
 | 
						radix_tree_for_each_slot(slot, &mapping->page_tree, &iter,
 | 
				
			||||||
| 
						 | 
					@ -2156,12 +2215,19 @@ void filemap_map_pages(struct fault_env *fe,
 | 
				
			||||||
			goto next;
 | 
								goto next;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!page_cache_get_speculative(page))
 | 
							head = compound_head(page);
 | 
				
			||||||
 | 
							if (!page_cache_get_speculative(head))
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* The page was split under us? */
 | 
				
			||||||
 | 
							if (compound_head(page) != head) {
 | 
				
			||||||
 | 
								put_page(head);
 | 
				
			||||||
 | 
								goto repeat;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Has the page moved? */
 | 
							/* Has the page moved? */
 | 
				
			||||||
		if (unlikely(page != *slot)) {
 | 
							if (unlikely(page != *slot)) {
 | 
				
			||||||
			put_page(page);
 | 
								put_page(head);
 | 
				
			||||||
			goto repeat;
 | 
								goto repeat;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue