ANDROID: mm: allow vmas with vm_ops to be speculatively handled

Right now only anonymous page faults are speculatively handled,
thus leaving out a large percentage of faults still requiring to
take mmap_sem. These were left out since there can be fault
handlers mainly in the fs layer which may use vma in unknown ways.
This patch enables speculative fault for ext4, f2fs and shmem. The
feature is disabled by default and enabled via allow_file_spec_access
kernel param.

Bug: 171954515
Change-Id: I0d23ebf299000e4ac5e2c71bc0b7fc9006e98da9
Signed-off-by: Vinayak Menon <vinmenon@codeaurora.org>
This commit is contained in:
Vinayak Menon
2021-03-18 15:20:17 +05:30
committed by Todd Kjos
parent 77e791866b
commit 35eacb5c87
10 changed files with 170 additions and 37 deletions

View File

@@ -2864,6 +2864,11 @@ static bool filemap_map_pmd(struct vm_fault *vmf, struct page *page)
}
if (pmd_none(*vmf->pmd)) {
if (vmf->flags & FAULT_FLAG_SPECULATIVE) {
unlock_page(page);
put_page(page);
return true;
}
vmf->ptl = pmd_lock(mm, vmf->pmd);
if (likely(pmd_none(*vmf->pmd))) {
mm_inc_nr_ptes(mm);
@@ -2942,6 +2947,14 @@ static inline struct page *next_map_page(struct address_space *mapping,
mapping, xas, end_pgoff);
}
#ifdef CONFIG_SPECULATIVE_PAGE_FAULT
bool filemap_allow_speculation(void)
{
return true;
}
EXPORT_SYMBOL_GPL(filemap_allow_speculation);
#endif
vm_fault_t filemap_map_pages(struct vm_fault *vmf,
pgoff_t start_pgoff, pgoff_t end_pgoff)
{
@@ -2961,12 +2974,22 @@ vm_fault_t filemap_map_pages(struct vm_fault *vmf,
goto out;
if (filemap_map_pmd(vmf, head)) {
if (pmd_none(*vmf->pmd) &&
vmf->flags & FAULT_FLAG_SPECULATIVE) {
ret = VM_FAULT_RETRY;
goto out;
}
ret = VM_FAULT_NOPAGE;
goto out;
}
addr = vma->vm_start + ((start_pgoff - vma->vm_pgoff) << PAGE_SHIFT);
vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd, addr, &vmf->ptl);
if (!pte_map_lock_addr(vmf, addr)) {
ret = VM_FAULT_RETRY;
goto out;
}
do {
page = find_subpage(head, xas.xa_index);
if (PageHWPoison(page))
@@ -3033,6 +3056,9 @@ const struct vm_operations_struct generic_file_vm_ops = {
.fault = filemap_fault,
.map_pages = filemap_map_pages,
.page_mkwrite = filemap_page_mkwrite,
#ifdef CONFIG_SPECULATIVE_PAGE_FAULT
.allow_speculation = filemap_allow_speculation,
#endif
};
/* This is used for a general mmap of a disk file */