On Tue, Sep 16, 2025 at 03:11:54PM +0100, Lorenzo Stoakes wrote:

> +/* What action should be taken after an .mmap_prepare call is complete? */
> +enum mmap_action_type {
> +     MMAP_NOTHING,           /* Mapping is complete, no further action. */
> +     MMAP_REMAP_PFN,         /* Remap PFN range. */

Seems like it would be a bit tider to include MMAP_IO_REMAP_PFN here
instead of having the is_io_remap bool.

> @@ -1155,15 +1155,18 @@ int __compat_vma_mmap_prepare(const struct 
> file_operations *f_op,
>               .vm_file = vma->vm_file,
>               .vm_flags = vma->vm_flags,
>               .page_prot = vma->vm_page_prot,
> +
> +             .action.type = MMAP_NOTHING, /* Default */
>       };
>       int err;
>  
>       err = f_op->mmap_prepare(&desc);
>       if (err)
>               return err;
> -     set_vma_from_desc(vma, &desc);
>  
> -     return 0;
> +     mmap_action_prepare(&desc.action, &desc);
> +     set_vma_from_desc(vma, &desc);
> +     return mmap_action_complete(&desc.action, vma);
>  }
>  EXPORT_SYMBOL(__compat_vma_mmap_prepare);

A function called prepare that now calls complete has become a bit oddly named??

> +int mmap_action_complete(struct mmap_action *action,
> +                      struct vm_area_struct *vma)
> +{
> +     int err = 0;
> +
> +     switch (action->type) {
> +     case MMAP_NOTHING:
> +             break;
> +     case MMAP_REMAP_PFN:
> +             VM_WARN_ON_ONCE((vma->vm_flags & VM_REMAP_FLAGS) !=
> +                             VM_REMAP_FLAGS);

This is checked in remap_pfn_range_complete() IIRC? Probably not
needed here as well then.

> +             if (action->remap.is_io_remap)
> +                     err = io_remap_pfn_range_complete(vma, 
> action->remap.start,
> +                             action->remap.start_pfn, action->remap.size,
> +                             action->remap.pgprot);
> +             else
> +                     err = remap_pfn_range_complete(vma, action->remap.start,
> +                             action->remap.start_pfn, action->remap.size,
> +                             action->remap.pgprot);
> +             break;
> +     }
> +
> +     /*
> +      * If an error occurs, unmap the VMA altogether and return an error. We
> +      * only clear the newly allocated VMA, since this function is only
> +      * invoked if we do NOT merge, so we only clean up the VMA we created.
> +      */
> +     if (err) {
> +             const size_t len = vma_pages(vma) << PAGE_SHIFT;
> +
> +             do_munmap(current->mm, vma->vm_start, len, NULL);
> +
> +             if (action->error_hook) {
> +                     /* We may want to filter the error. */
> +                     err = action->error_hook(err);
> +
> +                     /* The caller should not clear the error. */
> +                     VM_WARN_ON_ONCE(!err);
> +             }
> +             return err;
> +     }
> +
> +     if (action->success_hook)
> +             err = action->success_hook(vma);
> +
> +     return err;

I would write this as

        if (action->success_hook)
                return action->success_hook(vma);

        return 0;

Just for emphasis this is the success path.

> +int mmap_action_complete(struct mmap_action *action,
> +                     struct vm_area_struct *vma)
> +{
> +     int err = 0;
> +
> +     switch (action->type) {
> +     case MMAP_NOTHING:
> +             break;
> +     case MMAP_REMAP_PFN:
> +             WARN_ON_ONCE(1); /* nommu cannot handle this. */
> +
> +             break;
> +     }
> +
> +     /*
> +      * If an error occurs, unmap the VMA altogether and return an error. We
> +      * only clear the newly allocated VMA, since this function is only
> +      * invoked if we do NOT merge, so we only clean up the VMA we created.
> +      */
> +     if (err) {
> +             const size_t len = vma_pages(vma) << PAGE_SHIFT;
> +
> +             do_munmap(current->mm, vma->vm_start, len, NULL);
> +
> +             if (action->error_hook) {
> +                     /* We may want to filter the error. */
> +                     err = action->error_hook(err);
> +
> +                     /* The caller should not clear the error. */
> +                     VM_WARN_ON_ONCE(!err);
> +             }
> +             return err;
> +     }

err is never !0 here, so this should go to a later patch/series.

Also seems like this cleanup wants to be in a function that is not
protected by #ifdef nommu since the code is identical on both branches.

> +     if (action->success_hook)
> +             err = action->success_hook(vma);
> +
> +     return 0;

return err, though prefer to match above, and probably this sequence
should be pulled into the same shared function as above too.

Jason

Reply via email to