diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 7256ce1e0b20..35db9f655a90 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -1305,8 +1305,7 @@ static inline bool vma_can_userfault(struct vm_area_struct *vma, unsigned long vm_flags) { if (vm_flags & VM_UFFD_MINOR) { - /* FIXME: Add minor fault interception for shmem. */ - if (!is_vm_hugetlb_page(vma)) + if (!(is_vm_hugetlb_page(vma) || vma_is_shmem(vma))) return false; } diff --git a/mm/memory.c b/mm/memory.c index 37e14b073b68..2a633f7284bb 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3899,9 +3899,11 @@ static vm_fault_t do_read_fault(struct vm_fault *vmf) * something). */ if (vma->vm_ops->map_pages && fault_around_bytes >> PAGE_SHIFT > 1) { - ret = do_fault_around(vmf); - if (ret) - return ret; + if (likely(!userfaultfd_minor(vmf->vma))) { + ret = do_fault_around(vmf); + if (ret) + return ret; + } } ret = __do_fault(vmf); diff --git a/mm/shmem.c b/mm/shmem.c index c22a2d82b302..87e736f5ebd3 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1739,7 +1739,7 @@ unlock: * vm. If we swap it in we mark it dirty since we also free the swap * entry since a page cannot live in both the swap and page cache. * - * vmf and fault_type are only supplied by shmem_fault: + * vma, vmf, and fault_type are only supplied by shmem_fault: * otherwise they are NULL. */ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, @@ -1773,6 +1773,16 @@ repeat: charge_mm = vma ? vma->vm_mm : current->mm; page = find_lock_entry(mapping, index); + + if (page && vma && userfaultfd_minor(vma)) { + if (!xa_is_value(page)) { + unlock_page(page); + put_page(page); + } + *fault_type = handle_userfault(vmf, VM_UFFD_MINOR); + return 0; + } + if (xa_is_value(page)) { error = shmem_swapin_page(inode, index, &page, sgp, gfp, vma, fault_type);