On Tue, Sep 16, 2025 at 03:11:54PM +0100, Lorenzo Stoakes wrote: > Some drivers/filesystems need to perform additional tasks after the VMA is > set up. This is typically in the form of pre-population. > > The forms of pre-population most likely to be performed are a PFN remap > or the insertion of normal folios and PFNs into a mixed map. > > We start by implementing the PFN remap functionality, ensuring that we > perform the appropriate actions at the appropriate time - that is setting > flags at the point of .mmap_prepare, and performing the actual remap at the > point at which the VMA is fully established. > > This prevents the driver from doing anything too crazy with a VMA at any > stage, and we retain complete control over how the mm functionality is > applied. > > Unfortunately callers still do often require some kind of custom action, > so we add an optional success/error _hook to allow the caller to do > something after the action has succeeded or failed.
Do we have any idea for rules regarding ->mmap_prepare() and ->*_hook()? It feels spooky to e.g grab locks in mmap_prepare, and hold them across core mmap(). And I guess it might be needed? > > This is done at the point when the VMA has already been established, so > the harm that can be done is limited. > > The error hook can be used to filter errors if necessary. > > If any error arises on these final actions, we simply unmap the VMA > altogether. > > Also update the stacked filesystem compatibility layer to utilise the > action behaviour, and update the VMA tests accordingly. > > Signed-off-by: Lorenzo Stoakes <[email protected]> <snip> > diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h > index 31b27086586d..aa1e2003f366 100644 > --- a/include/linux/mm_types.h > +++ b/include/linux/mm_types.h > @@ -775,6 +775,49 @@ struct pfnmap_track_ctx { > }; > #endif > > +/* 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; > + bool is_io_remap; > + } 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); Do we need two hooks? It might be more ergonomic to simply have a: int (*finish)(int err); int random_driver_finish(int err) { if (err) pr_err("ahhhhhhhhh\n"); mutex_unlock(&big_lock); return err; } It's also unclear to me if/why we need the capability to switch error codes, but I might've missed some discussion on this. -- Pedro
