diff --git a/mm/filemap.c b/mm/filemap.c index 6f110b9e5d27be..4452361e885832 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -3354,11 +3354,12 @@ static vm_fault_t filemap_map_folio_range(struct vm_fault *vmf, struct file *file = vma->vm_file; struct page *page = folio_page(folio, start); unsigned int mmap_miss = READ_ONCE(file->f_ra.mmap_miss); - unsigned int ref_count = 0, count = 0; + unsigned int mapped = 0; + pte_t *pte = vmf->pte; do { if (PageHWPoison(page)) - continue; + goto map; if (mmap_miss > 0) mmap_miss--; @@ -3368,20 +3369,34 @@ static vm_fault_t filemap_map_folio_range(struct vm_fault *vmf, * handled in the specific fault path, and it'll prohibit the * fault-around logic. */ - if (!pte_none(*vmf->pte)) - continue; + if (!pte_none(pte[mapped])) + goto map; if (vmf->address == addr) ret = VM_FAULT_NOPAGE; - ref_count++; - do_set_pte(vmf, page, addr); - } while (vmf->pte++, page++, addr += PAGE_SIZE, ++count < nr_pages); + mapped++; + continue; - /* Restore the vmf->pte */ - vmf->pte -= nr_pages; +map: + if (mapped) { + do_set_pte_range(vmf, folio, addr, pte, start, mapped); + folio_ref_add(folio, mapped); + } + + /* advance 1 to jump over the HWPoison or !pte_none entry */ + mapped++; + start += mapped; + pte += mapped; + addr += mapped * PAGE_SIZE; + mapped = 0; + } while (page++, --nr_pages > 0); + + if (mapped) { + do_set_pte_range(vmf, folio, addr, pte, start, mapped); + folio_ref_add(folio, mapped); + } - folio_ref_add(folio, ref_count); WRITE_ONCE(file->f_ra.mmap_miss, mmap_miss); return ret;