On Wed, Jan 31, 2024 at 1:41 PM Liam R. Howlett <Liam.Howlett@xxxxxxxxxx> wrote: > > * Lokesh Gidra <lokeshgidra@xxxxxxxxxx> [240130 21:49]: > > On Mon, Jan 29, 2024 at 6:58 PM Liam R. Howlett <Liam.Howlett@xxxxxxxxxx> wrote: > > > > > > * Lokesh Gidra <lokeshgidra@xxxxxxxxxx> [240129 19:28]: > > > > On Mon, Jan 29, 2024 at 12:53 PM Suren Baghdasaryan <surenb@xxxxxxxxxx> wrote: > > > > > > > > > > ... > > > > > > > > Your suggestion is definitely simpler and easier to follow, but due to > > > > the overflow situation that Suren pointed out, I would still need to > > > > keep the locking/boolean dance, no? IIUC, even if I were to return > > > > EAGAIN to the userspace, there is no guarantee that subsequent ioctls > > > > on the same vma will succeed due to the same overflow, until someone > > > > acquires and releases mmap_lock in write-mode. > > > > Also, sometimes it seems insufficient whether we managed to lock vma > > > > or not. For instance, lock_vma_under_rcu() checks if anon_vma (for > > > > anonymous vma) exists. If not then it bails out. > > > > So it seems to me that we have to provide some fall back in > > > > userfaultfd operations which executes with mmap_lock in read-mode. > > > > > > Fair enough, what if we didn't use the sequence number and just locked > > > the vma directly? > > > > Looks good to me, unless someone else has any objections. > > > > > > /* This will wait on the vma lock, so once we return it's locked */ > > > void vma_aquire_read_lock(struct vm_area_struct *vma) > > > { > > > mmap_assert_locked(vma->vm_mm); > > > down_read(&vma->vm_lock->lock); > > > } > > > > > > struct vm_area_struct *lock_vma(struct mm_struct *mm, > > > unsigned long addr)) /* or some better name.. */ > > > { > > > struct vm_area_struct *vma; > > > > > > vma = lock_vma_under_rcu(mm, addr); > > > if (vma) > > > return vma; > > > > > > mmap_read_lock(mm); > > > /* mm sequence cannot change, no mm writers anyways. > > > * find_mergeable_anon_vma is only a concern in the page fault > > > * path > > > * start/end won't change under the mmap_lock > > > * vma won't become detached as we have the mmap_lock in read > > > * We are now sure no writes will change the VMA > > > * So let's make sure no other context is isolating the vma > > > */ > > > vma = lookup_vma(mm, addr); > > > if (vma) > > We can take care of anon_vma as well here right? I can take a bool > > parameter ('prepare_anon' or something) and then: > > > > if (vma) { > > if (prepare_anon && vma_is_anonymous(vma)) && > > !anon_vma_prepare(vma)) { > > vma = ERR_PTR(-ENOMEM); > > goto out_unlock; > > } > > > vma_aquire_read_lock(vma); > > } > > out_unlock: > > > mmap_read_unlock(mm); > > > return vma; > > > } > > Do you need this? I didn't think this was happening in the code as > written? If you need it I would suggest making it happen always and > ditch the flag until a user needs this variant, but document what's > going on in here or even have a better name. I think yes, you do need this. I can see calls to anon_vma_prepare() under mmap_read_lock() protection in both mfill_atomic_hugetlb() and in mfill_atomic(). This means, just like in the pagefault path, we modify vma->anon_vma under mmap_read_lock protection which guarantees that adjacent VMAs won't change. This is important because __anon_vma_prepare() uses find_mergeable_anon_vma() that needs the neighboring VMAs to be stable. Per-VMA lock guarantees stability of the VMA we locked but not of its neighbors, therefore holding per-VMA lock while calling anon_vma_prepare() is not enough. The solution Lokesh suggests would call anon_vma_prepare() under mmap_read_lock and therefore would avoid the issue. > > Thanks, > Liam