Re: [RFC PATCH v3] mm: retry page faults under per-VMA lock when mmap_lock is not required
From: Suren Baghdasaryan
Date: Wed Aug 05 2026 - 12:56:11 EST
On Mon, Aug 3, 2026 at 3:48 PM Barry Song <baohua@xxxxxxxxxx> wrote:
>
> On Sun, Jul 12, 2026 at 9:28 PM Hongru Zhang <zhanghongru06@xxxxxxxxx> 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 excluded,
> > > > 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@xxxxxxxxxxxxx/
> >
> > 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 perform
> > file-backed I/O while holding either mmap_lock or a per-VMA lock. The traces
> > 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 example
> > 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 reliability
>
> https://lore.kernel.org/linux-mm/20260724222934.1463812-1-riel@xxxxxxxxxxx/
>
> 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/20260802074018.73887-1-baohua@xxxxxxxxxx/
>
> 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=52Qd_POL18Kg@xxxxxxxxxxxxxx/
>
> 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?
That would be quite hard, as you might know. We have to support
existing apps which might be using fork() and forcing developers to
change their apps is difficult and sometimes impossible (app is using
a 3rd party library that calls fork() and the library vendor does not
exist anymore).
>
> Thanks
> Barry