Commit e8b3047f authored by Matthew Wilcox (Oracle)'s avatar Matthew Wilcox (Oracle) Committed by Liu Shixin
Browse files

mm: convert __do_fault() to use a folio

mainline inclusion
from mainline-v6.8-rc1
commit 01d1e0e6b7d99ebaf2e42d2205595080b7d0c271
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IAO6NS

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=01d1e0e6b7d99ebaf2e42d2205595080b7d0c271

--------------------------------

Convert vmf->page to a folio as soon as we're going to use it.  This fixes
a bug if the fault handler returns a tail page with hardware poison; tail
pages have an invalid page->index, so we would fail to unmap the page from
the page tables.  We actually have to unmap the entire folio (or
mapping_evict_folio() will fail), so use unmap_mapping_folio() instead.

This also saves various calls to compound_head() hidden in lock_page(),
put_page(), etc.

Link: https://lkml.kernel.org/r/20231108182809.602073-3-willy@infradead.org


Fixes: 793917d9 ("mm/readahead: Add large folio readahead")
Signed-off-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
Cc: Naoya Horiguchi <naoya.horiguchi@nec.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLiu Shixin <liushixin2@huawei.com>
parent 4ed482c3
Loading
Loading
Loading
Loading
+10 −10
Original line number Diff line number Diff line
@@ -4586,6 +4586,7 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
static vm_fault_t __do_fault(struct vm_fault *vmf)
{
	struct vm_area_struct *vma = vmf->vma;
	struct folio *folio;
	vm_fault_t ret;

	/*
@@ -4614,27 +4615,26 @@ static vm_fault_t __do_fault(struct vm_fault *vmf)
			    VM_FAULT_DONE_COW)))
		return ret;

	folio = page_folio(vmf->page);
	if (unlikely(PageHWPoison(vmf->page))) {
		struct page *page = vmf->page;
		vm_fault_t poisonret = VM_FAULT_HWPOISON;
		if (ret & VM_FAULT_LOCKED) {
			if (page_mapped(page))
				unmap_mapping_pages(page_mapping(page),
						    page->index, 1, false);
			/* Retry if a clean page was removed from the cache. */
			if (invalidate_inode_page(page))
			if (page_mapped(vmf->page))
				unmap_mapping_folio(folio);
			/* Retry if a clean folio was removed from the cache. */
			if (mapping_evict_folio(folio->mapping, folio))
				poisonret = VM_FAULT_NOPAGE;
			unlock_page(page);
			folio_unlock(folio);
		}
		put_page(page);
		folio_put(folio);
		vmf->page = NULL;
		return poisonret;
	}

	if (unlikely(!(ret & VM_FAULT_LOCKED)))
		lock_page(vmf->page);
		folio_lock(folio);
	else
		VM_BUG_ON_PAGE(!PageLocked(vmf->page), vmf->page);
		VM_BUG_ON_PAGE(!folio_test_locked(folio), vmf->page);

	return ret;
}