Re: [RFC PATCH v3] mm: retry page faults under per-VMA lock when mmap_lock is not required
Barry Song <[email protected]> Tue, 4 Aug 2026 06:48:27 +0800
| Newsgroups | org.kvack.linux-mm,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CAGsJ_4x3HiRP7QU=N-oPiWuxuTG1VvzCCdHPqr3Trdk_8WMUGw@mail.gmail.com> |
On Sun, Jul 12, 2026 at 9:28=E2=80=AFPM Hongru Zhang <[email protected]= om> wrote: > > > On Tue, Jul 07, 2026 at 05:52:31PM +0100, Lorenzo Stoakes wrote: > > > +cc Vlata, the only one from the MEMORY MAPPING - LOCKING people excl= uded, > > > and Willy as he's been heavily involved. But see below you need to cc= - way > > > more. > > > > Ugh, I hadn't seen this. > > > > No. > > > > I've been looking into this problem, and as usual it has turned into a > > yak-shaving exercise. I think I'm five yaks deep at this point: > > > > - Need to start by simplifying filemap_fault > > https://lore.kernel.org/linux-mm/20260625195040.2508362-1-willy@infr= adead.org/ > > Hi Matthew, > > Thanks for looking at this. > > I understand your concern about adding more complexity to an already > complicated fault path. > > However, I tested the RFC patch [1] on Android workloads and observed > lock-wait regressions. The common pattern is that filemap_fault() can per= form > file-backed I/O while holding either mmap_lock or a per-VMA lock. The tra= ces > show three representative classes of lock-wait regressions: GUP faults, > kernel uaccess faults, and per-VMA-lock faults blocking fork / copy_mm(). > > 1) GUP faults under mmap_lock > > APP: com.xs.fm.lite > lock type: mmap_lock > holder: Thread-77 > faulted file: libbytehook.so > lock-held filemap fault time: 95.606ms > blocked writer: NetDownload#15 (blocked 218.971ms) > > Holder stack: > filemap_fault+0x0 > __do_fault+0xdc > do_pte_missing+0x2c8 > handle_mm_fault+0x4c8 > __get_user_pages+0x618 > __gup_longterm_locked+0xac > pin_user_pages_remote+0x88 > process_vm_rw+0x2cc > __arm64_sys_process_vm_readv+0x28 > invoke_syscall+0x58 > el0_svc_common+0x80 > do_el0_svc+0x1c > el0_svc+0x48 > el0t_64_sync_handler+0x70 > el0t_64_sync+0x1bc > > Blocked writer stack: > vm_mmap_pgoff+0x168 > ksys_mmap_pgoff+0xa4 > __arm64_sys_mmap+0x34 > invoke_syscall+0x58 > el0_svc_common+0x80 > do_el0_svc+0x1c > el0_svc+0x48 > el0t_64_sync_handler+0x70 > el0t_64_sync+0x1bc > > 2) kernel uaccess faults under mmap_lock > > APP: com.xingin.xhs > lock type: mmap_lock > holder: Thread-2531 > faulted file: libtiny.so > lock-held filemap fault time: 172.375ms > blocked writer count: 5 > writer wait range: 152.766ms - 172.006ms > representative blocked writer: com.xingin.xhs (main thread, blocked 172= .006ms) > > Holder stack: > filemap_fault+0x0 > __do_fault+0xdc > do_pte_missing+0x2c8 > handle_mm_fault+0x4c8 > do_page_fault+0x39c > do_translation_fault+0x4c > do_mem_abort+0x54 > el1_abort+0x3c > el1h_64_sync_handler+0x80 > el1h_64_sync+0x7c > __arch_copy_from_user+0x1b4 > copy_page_from_iter+0xd0 > pipe_write+0x1ec > vfs_write+0x368 > ksys_write+0x78 > __arm64_sys_write+0x1c > invoke_syscall+0x58 > el0_svc_common+0x80 > do_el0_svc+0x1c > el0_svc+0x48 > el0t_64_sync_handler+0x70 > el0t_64_sync+0x1bc > > Blocked writer stack: > vm_mmap_pgoff+0x168 > ksys_mmap_pgoff+0xa4 > __arm64_sys_mmap+0x34 > invoke_syscall+0x58 > el0_svc_common+0x80 > do_el0_svc+0x1c > el0_svc+0x48 > el0t_64_sync_handler+0x70 > el0t_64_sync+0x1bc > > 3) filemap faults under per-VMA lock blocking fork / copy_mm() > > Other testing also reported similar per-VMA-lock blocking data [2], where > filemap faults under a VMA read lock can block fork / copy_mm(). One exam= ple > from my trace is: > > APP: com.xingin.xhs > lock type: per-VMA lock > holder: xylog_thread_po > faulted file: 2026-07-07-11-51-46.203.log > lock-held filemap fault time: 10.518ms > blocked writer: com.xingin.xhs (blocked 1.583ms) > > Holder stack: > filemap_fault+0x0 > __do_fault+0xdc > do_pte_missing+0x2c8 > handle_mm_fault+0x4c8 > do_page_fault+0x30c > do_translation_fault+0x4c > do_mem_abort+0x54 > el0_da+0x54 > el0t_64_sync_handler+0x50 > el0t_64_sync+0x1bc > > Blocked writer stack: > copy_mm+0x2a4 > copy_process+0x4ec > kernel_clone+0xb0 > __arm64_sys_clone+0x60 > invoke_syscall+0x58 > el0_svc_common+0x80 > do_el0_svc+0x1c > el0_svc+0x48 > el0t_64_sync_handler+0x70 > el0t_64_sync+0x1bc > Thanks, Hongru. It seems these stacks clearly expose paths such as GUP and copy_from/to_user() where I/O may be performed after Matthew's approach is adopted. I am putting together a list of paths that would perform I/O under mmap_lock, along with possible ways to address them. Performing I/O while holding mmap_lock may result in unpredictable and potentially long mmap_lock hold times, so we need to address these issues at least. 1. GUP doesn't support vma lock Maybe this can be addressed by Rik van Riel's patchset? I haven't looked into it in detail yet, so I'm not entirely sure. mm: use per-VMA lock in __access_remote_vm for improved monitoring reliabil= ity https://lore.kernel.org/linux-mm/[email protected]/ 2. copy_from/to_user doesn't support vma lock Maybe this can be addressed by the topic currently under discussion? mm: use VMA lock for kernel faults on user addresses https://lore.kernel.org/linux-mm/[email protected]/ 3. first PF before retry might have been mmap_lock: Maybe this can be addressed by `vma_start_read_unlocked()`, as we discussed here: mm: Unconditional per-VMA locks and cleanups https://lore.kernel.org/linux-mm/CAJuCfpEF6SjKhRW33AuboAuUbQz5zv+QKr2eD=3D5= [email protected]/ 4. The last one is the fork regression, which is unrelated to I/O under mmap_lock. - No approach yet. Perhaps Android could enforce some rules to prevent apps from calling fork() in the future? Thanks Barry