Re: [PATCH v4 09/38] drivers/usb/mon: update to use mmap_prepare + map kernel pages

From: Suren Baghdasaryan

Date: Sun Oct 04 2026 - 13:22:19 EST


On Sat, Oct 3, 2026 at 6:36 PM Lorenzo Stoakes (ARM) <ljs@xxxxxxxxxx> wrote:
>
> Replace the deprecated .mmap hook with its replacement .mmap_prepare. As
> part of this change, additionally take the approach of mapping pages upon
> mmap rather than providing a fault handler.
>
> The page span cannot be mutated when an mmap mapping is in place, so this
> is safe to do in advance (the MON_IOCT_RING_SIZE ioctl operation exits
> -EBUSY if it's attempted, gated by the rp->mmap_active reference count).
>
> Utilise the newly introduced mmap_action_map_discontig_kernel_pages() to do
> this, which allows for iteration over pages in mon_bin_discontig_get().
>
> mon_bin_discontig_init() increments the rp->mmap_active reference count to
> stabilise page spans. Should an error arise the core unmaps the VMA and
> mon_bin_vma_close() drops the reference again.
>
> The vm_ops->close hook implemented in mon_bin_vma_close() will ensure
> correct reference count arithmetic upon unmap (with mon_bin_vma_open()
> accounting for splitting).
>
> The existing semantics are all retained, including not mapping past the
> range of available pages, with a SIGBUS being raised in a userland process
> that attempts to access past this point.
>
> Ultimately insert_page() is invoked to insert each page, which increments
> the reference count on each mapped page. This mimics what was being done
> previously, only we pre-map the entire range rather than doing so on
> demand.
>
> The existing fault handler did nothing that required demand paging, and was
> presumably implemented this way for historical reasons.
>
> One behavioural difference: pages are no longer faulted in on demand, so a
> page discarded with MADV_DONTNEED is not repopulated and a subsequent
> access raises SIGBUS, as with other pre-populated kernel mappings.
>
> Acked-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Lorenzo Stoakes (ARM) <ljs@xxxxxxxxxx>

Reviewed-by: Suren Baghdasaryan <surenb@xxxxxxxxxx>


> ---
> drivers/usb/mon/mon_bin.c | 82 ++++++++++++++++++++++++++++++-----------------
> 1 file changed, 53 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
> index 687f6a8981f3..9d00b21a8153 100644
> --- a/drivers/usb/mon/mon_bin.c
> +++ b/drivers/usb/mon/mon_bin.c
> @@ -1219,6 +1219,15 @@ mon_bin_poll(struct file *file, struct poll_table_struct *wait)
> return mask;
> }
>
> +static void __mon_bin_vma_open(struct mon_reader_bin *rp)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&rp->b_lock, flags);
> + rp->mmap_active++;
> + spin_unlock_irqrestore(&rp->b_lock, flags);
> +}
> +
> /*
> * open and close: just keep track of how many times the device is
> * mapped, to use the proper memory allocation function.
> @@ -1226,64 +1235,79 @@ mon_bin_poll(struct file *file, struct poll_table_struct *wait)
> static void mon_bin_vma_open(struct vm_area_struct *vma)
> {
> struct mon_reader_bin *rp = vma->vm_private_data;
> - unsigned long flags;
>
> - spin_lock_irqsave(&rp->b_lock, flags);
> - rp->mmap_active++;
> - spin_unlock_irqrestore(&rp->b_lock, flags);
> + __mon_bin_vma_open(rp);
> }
>
> -static void mon_bin_vma_close(struct vm_area_struct *vma)
> +static void __mon_bin_vma_close(struct mon_reader_bin *rp)
> {
> unsigned long flags;
>
> - struct mon_reader_bin *rp = vma->vm_private_data;
> spin_lock_irqsave(&rp->b_lock, flags);
> rp->mmap_active--;
> spin_unlock_irqrestore(&rp->b_lock, flags);
> }
>
> -/*
> - * Map ring pages to user space.
> - */
> -static vm_fault_t mon_bin_vma_fault(struct vm_fault *vmf)
> +static void mon_bin_vma_close(struct vm_area_struct *vma)
> {
> - struct mon_reader_bin *rp = vmf->vma->vm_private_data;
> + struct mon_reader_bin *rp = vma->vm_private_data;
> +
> + __mon_bin_vma_close(rp);
> +}
> +
> +static const struct vm_operations_struct mon_bin_vm_ops = {
> + .open = mon_bin_vma_open,
> + .close = mon_bin_vma_close,
> +};
> +
> +static int mon_bin_discontig_init(void *vm_private_data, void **private)
> +{
> + struct mon_reader_bin *rp = vm_private_data;
> +
> + /* Dropped by mon_bin_vma_close() on unmap, including on error. */
> + __mon_bin_vma_open(rp);
> + return 0;
> +}
> +
> +static int mon_bin_discontig_get(struct discontig_kernel_page_state *state)
> +{
> + struct mon_reader_bin *rp = state->vm_private_data;
> unsigned long offset, chunk_idx;
> - struct page *pageptr;
> unsigned long flags;
>
> spin_lock_irqsave(&rp->b_lock, flags);
> - offset = vmf->pgoff << PAGE_SHIFT;
> +
> + offset = state->pgoff << PAGE_SHIFT;
> if (offset >= rp->b_size) {
> spin_unlock_irqrestore(&rp->b_lock, flags);
> - return VM_FAULT_SIGBUS;
> + discontig_kernel_map_abort(state);
> + return 0;
> }
> chunk_idx = offset / CHUNK_SIZE;
> - pageptr = rp->b_vec[chunk_idx].pg;
> - get_page(pageptr);
> - vmf->page = pageptr;
> + discontig_kernel_map_page(state, rp->b_vec[chunk_idx].pg);
> +
> spin_unlock_irqrestore(&rp->b_lock, flags);
> return 0;
> }
>
> -static const struct vm_operations_struct mon_bin_vm_ops = {
> - .open = mon_bin_vma_open,
> - .close = mon_bin_vma_close,
> - .fault = mon_bin_vma_fault,
> +static const struct discontig_kernel_page_ops mon_discontig_ops = {
> + .init = mon_bin_discontig_init,
> + .get = mon_bin_discontig_get,
> };
>
> -static int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
> +static int mon_bin_mmap_prepare(struct vm_area_desc *desc)
> {
> - /* don't do anything here: "fault" will set up page table entries */
> - vma->vm_ops = &mon_bin_vm_ops;
> + const struct file *filp = desc->file;
>
> - if (vma->vm_flags & VM_WRITE)
> + if (vma_desc_test(desc, VMA_WRITE_BIT))
> return -EPERM;
>
> - vm_flags_mod(vma, VM_DONTEXPAND | VM_DONTDUMP, VM_MAYWRITE);
> - vma->vm_private_data = filp->private_data;
> - mon_bin_vma_open(vma);
> + desc->vm_ops = &mon_bin_vm_ops;
> + vma_desc_clear_flags(desc, VMA_MAYWRITE_BIT);
> + vma_desc_set_flags(desc, VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT);
> + desc->private_data = filp->private_data;
> +
> + mmap_action_map_discontig_kernel_pages(desc, NULL, &mon_discontig_ops);
> return 0;
> }
>
> @@ -1298,7 +1322,7 @@ static const struct file_operations mon_fops_binary = {
> .compat_ioctl = mon_bin_compat_ioctl,
> #endif
> .release = mon_bin_release,
> - .mmap = mon_bin_mmap,
> + .mmap_prepare = mon_bin_mmap_prepare,
> };
>
> static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp)
>
> --
> 2.55.0
>