Re: [PATCH v4 09/14] mm: add ability to take further action in vm_area_desc

Lorenzo Stoakes
2025-09-18T06:10:06Z

On Wed, Sep 17, 2025 at 06:37:37PM -0300, Jason Gunthorpe wrote:
> On Wed, Sep 17, 2025 at 08:11:11PM +0100, Lorenzo Stoakes wrote:
> > +static int mmap_action_finish(struct mmap_action *action,
> > + const struct vm_area_struct *vma, int err)
> > +{
> > + /*
> > + * 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)
> > + return action->success_hook(vma);
>
> I thought you were going to use a single hook function as was
> suggested?
>
> return action->finish_hook(vma, err);

Err, no? I said no to this suggestion from Pedro? I don't like it.

In practice I've found callers need to EITHER do something on success or
filter errors. I think it's more expressive this way.

I also think you make it more likely that a driver will get things wrong if
they intend only to do something on success and you have an 'err'
parameter.

>
> > +int mmap_action_complete(struct mmap_action *action,
> > + struct vm_area_struct *vma)
> > +{
> > + switch (action->type) {
> > + case MMAP_NOTHING:
> > + break;
> > + case MMAP_REMAP_PFN:
> > + case MMAP_IO_REMAP_PFN:
> > + WARN_ON_ONCE(1); /* nommu cannot handle this. */
>
> This should be:
>
> if (WARN_ON_ONCE(true))
> err = -EINVAL
>
> To abort the thing and try to recover.

'Try to recover'... how exactly...

It'd be a serious programmatic kernel bug so I'm not sure going out of our way
to error out here is brilliantly valuable. You might even mask the bug this way,
because the mmap() will just fail instad of nuking the process on fault.

But fine, let me send a fix-patch...

>
> > diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
> > index 07167446dcf4..22ed38e8714e 100644
> > --- a/tools/testing/vma/vma_internal.h
> > +++ b/tools/testing/vma/vma_internal.h
> > @@ -274,6 +274,49 @@ struct mm_struct {
> >
> > struct vm_area_struct;
> >
> > +
> > +/* 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. */
> > +};
> > +
> > +/*
> > + * Describes an action an mmap_prepare hook can instruct to be taken to complete
> > + * the mapping of a VMA. Specified in vm_area_desc.
> > + */
> > +struct mmap_action {
> > + union {
> > + /* Remap range. */
> > + struct {
> > + unsigned long start;
> > + unsigned long start_pfn;
> > + unsigned long size;
> > + pgprot_t pgprot;
> > + } remap;
> > + };
> > + enum mmap_action_type type;
> > +
> > + /*
> > + * If specified, this hook is invoked after the selected action has been
> > + * successfully completed. Note that the VMA write lock still held.
> > + *
> > + * The absolute minimum ought to be done here.
> > + *
> > + * Returns 0 on success, or an error code.
> > + */
> > + int (*success_hook)(const struct vm_area_struct *vma);
> > +
> > + /*
> > + * If specified, this hook is invoked when an error occurred when
> > + * attempting the selection action.
> > + *
> > + * The hook can return an error code in order to filter the error, but
> > + * it is not valid to clear the error here.
> > + */
> > + int (*error_hook)(int err);
> > +};
>
> I didn't try to understand what vma_internal.h is for, but should this
> block be an exact copy of the normal one? ie MMAP_IO_REMAP_PFN is missing?

Right. Of course. I'll include that in the fix-patch...

>
> Jason