hailo_pci: find_vma() called without mmap_lock in hailo_vdma_buffer_map()— kernel warning storm and hard crash under sustained inference

Bug report

Summary

hailo_vdma_buffer_map() in the PCIe driver (linux/vdma/memory.c) calls
find_vma(current->mm, ...) without holding mmap_read_lock. Walking
the VMA tree unlocked races against concurrent address-space changes in the
calling process (ordinary mmap/munmap traffic from numpy/OpenCV allocators
in our case). When the race lands, the kernel emits a rwsem.h:80 lock
assertion warning on every subsequent buffer-map ioctl (~40/s in our
pipeline) and dies within about a minute. This hard-crashed our Raspberry
Pi 5 four times in one day, always during multi-model inference.

The same file already takes mmap_read_lock correctly elsewhere
(hailo_vdma_launch_transfer path, memory.c ~line 684 in 4.23.0), so this
one call site appears to be an oversight.

Environment

  • Driver: hailort-pcie-driver 4.23.0 (Raspberry Pi OS apt package)
  • HailoRT: 4.23.0, firmware 4.23.0
  • Hardware: Hailo-8 (1e60:2864) on Raspberry Pi 5 Model B Rev 1.1
    (Raspberry Pi AI HAT)
  • Kernel: 6.18.34+rpt-rpi-2712 (Debian 1:6.18.34-1+rpt1, PREEMPT, arm64)
  • Workload: three HEFs on one VDevice (scrfd_10g, arcface_mobilefacenet,
    yolov8m_pose), ROUND_ROBIN scheduler, Python InferModel API,
    ~40 inferences/s aggregate

Kernel trace (first of ~2,100 identical warnings in 48 s, then hard crash)

------------[ cut here ]------------
WARNING: CPU: 1 PID: 2128 at include/linux/rwsem.h:80 find_vma+0x6c/0x80
CPU: 1 UID: 1000 PID: 2128 Comm: python3 Tainted: G           O        6.18.34+rpt-rpi-2712 #1 PREEMPT  Debian 1:6.18.34-1+rpt1
Tainted: [O]=OOT_MODULE
Hardware name: Raspberry Pi 5 Model B Rev 1.1 (DT)
pc : find_vma+0x6c/0x80
lr : hailo_vdma_buffer_map+0x8c/0x620 [hailo_pci]
Call trace:
 find_vma+0x6c/0x80 (P)
 hailo_vdma_buffer_map+0x8c/0x620 [hailo_pci]
 hailo_vdma_buffer_map_ioctl+0xdc/0x350 [hailo_pci]
 hailo_vdma_ioctl+0xcc/0x260 [hailo_pci]
 hailo_pcie_fops_unlockedioctl+0x17c/0x610 [hailo_pci]
 __arm64_sys_ioctl+0xb4/0x120

Once the first warning appears, every subsequent buffer-map ioctl warns
(storms of 2,647 and 2,119 traces observed on two separate crashes), and
the machine locks up CPU-by-CPU and hard-resets within ~50–70 s. Full
journalctl captures of two crashes are available on request.

Reproduction

Sustained inference with per-call buffer registration (fresh
create_bindings() + set_buffer() with newly allocated numpy arrays
every call) on 3 concurrent models, while the same process continuously
allocates/frees large buffers (anonymous mmap/munmap churn — numpy and
OpenCV do this naturally). On our system this crashed the kernel within
~30–90 minutes, four times out of four runs, reproducibly correlated with
the moments inference load and allocation churn rose together.

A minimal stressor (3 models, per-call bindings, plus a thread doing
4 MB mmap/munmap cycles) reproduces the preconditions; with the patch
below the identical workload runs for hours with zero warnings.

Fix (tested)

Take mmap_read_lock around the find_vma() call and the subsequent vma
uses (is_dmabuf_vma() / create_fd_from_vma()), matching the locking
idiom already used elsewhere in the same file:

--- a/linux/vdma/memory.c
+++ b/linux/vdma/memory.c
@@ -167,11 +167,16 @@
     }

     if (HAILO_DMA_DMABUF_BUFFER != buffer_type) {
+        mmap_read_lock(current->mm);
         vma = find_vma(current->mm, addr_or_fd);
         if (IS_ENABLED(HAILO_SUPPORT_MMIO_DMA_MAPPING)) {
             if (NULL == vma) {
                 dev_err(dev, "no vma for virt_addr/size = 0x%08lx/0x%08zx\n", addr_or_fd, size);
                 ret = -EFAULT;
+                mmap_read_unlock(current->mm);
                 goto cleanup;
             }
         }
@@ -182,12 +187,14 @@
             ret = create_fd_from_vma(dev, vma);
             if (ret < 0) {
                 dev_err(dev, "Failed creating fd from vma in given dmabuf\n");
+                mmap_read_unlock(current->mm);
                 goto cleanup;
             }
             // Save original dmabuf user address in dmabuf_from_pointer_addr and override addr_or_fd with fd
             dmabuf_from_pointer_addr = addr_or_fd;
             addr_or_fd = ret;
         }
+        mmap_read_unlock(current->mm);
     }

     // TODO: is MMIO DMA MAPPINGS STILL needed after dmabuf

Note: when HAILO_SUPPORT_MMIO_DMA_MAPPING is defined, the
vma->vm_flags dereference and map_mmio_address(..., vma, ...) call
further down would also need to move inside the locked region; in the
default build they are compiled out, so the diff above covers the paths
that execute.

With this patch applied on 4.23.0 and the module rebuilt, the previously
crashing workloads (both the real pipeline and the stressor) have run
clean — no warnings, no crashes.

Happy to provide full journal logs or test a candidate fix.