On Sat, Oct 3, 2026 at 6:35 PM Lorenzo Stoakes (ARM) <[email protected]> wrote: > > Describe the newly introduced discontiguous kernel page mapping mechanism, > detailing how to use it sensibly and how the API looks. > > Explicitly detail the various discontiguous actions available and how to > use them. > > Signed-off-by: Lorenzo Stoakes (ARM) <[email protected]>
Reviewed-by: Suren Baghdasaryan <[email protected]> > --- > Documentation/filesystems/mmap_prepare.rst | 81 > ++++++++++++++++++++++++++++++ > 1 file changed, 81 insertions(+) > > diff --git a/Documentation/filesystems/mmap_prepare.rst > b/Documentation/filesystems/mmap_prepare.rst > index 82c99c95ad85..ddb4434d919a 100644 > --- a/Documentation/filesystems/mmap_prepare.rst > +++ b/Documentation/filesystems/mmap_prepare.rst > @@ -164,5 +164,86 @@ pointer. These are: > sufficient entries in the page array to cover the entire range of the > described VMA. > > +* mmap_action_map_discontig_kernel_pages() - Maps a discontiguous range of > + `struct page` pointers over the VMA. They must span from the start of the > VMA, > + but may terminate prior to the end (leaving the remainder unmapped). > + > **NOTE:** The ``action`` field should never normally be manipulated directly, > rather you ought to use one of these helpers. > + > +Discontiguous Actions > +===================== > + > +Some actions can be performed across discontiguous ranges. > + > +Map kernel pages > +---------------- > + > +To map kernel pages discontiguously, you must provide hooks using ``struct > +discontig_kernel_page_ops``: > + > +.. code-block:: C > + > + struct discontig_kernel_page_ops { > + int (*init)(void *vm_private_data, void **private); > + int (*get)(struct discontig_kernel_page_state *state); > + }; > + > +The ``init`` hook is optional and allows state to be established before the > +operation starts, for instance taking a reference count. Nothing is invoked > +after the operation, so ``init`` must not leave locks held, and state that > must > +be released once the mapping goes away should be released in > +``vm_ops->close``. > + > +The ``init`` hook, if provided, is invoked prior to the operation starting. > It > +may update what is pointed to by ``vm_private_data`` and/or ``private``. If > an > +error is returned, then the operation is aborted. The ``private`` field can > be > +reassigned. > + > +**NOTE:** The operation may sleep between invocations of ``get``, so locks > +needed to stabilise state must be taken and released within each hook. > + > +The ``get`` handler is the key means through which the operation is > +executed. The current state of the operation is provided through ``struct > +discontig_kernel_page_state``: > + > +.. code-block:: C > + > + struct discontig_kernel_page_state { > + /* Map state. */ > + unsigned long start; /* Start address of VMA. */ > + unsigned long end; /* End address of VMA. */ > + unsigned long addr; /* The current address to be mapped. > */ > + pgoff_t pgoff; /* The current pgoff to be mapped. */ > + unsigned long nr_pages_mapped; /* The number of pages mapped. */ > + unsigned long nr_pages_remain; /* The number of pages remaining. */ > + > + /* User-defined state. */ > + void *vm_private_data; /* VMA private data. */ > + void *private; /* Mapping private data. */ > + > + /* Users should not touch these, use discontig_kernel_map_*() > helpers. */ > + ... internal fields ... > + }; > + > +With ``private`` being an additional user-controllable state variable, > +initialised via ``mmap_action_map_discontig_kernel_pages()``, and > +``vm_private_data`` being equal to the ``desc->private_data`` field set in > +the ``mmap_prepare()`` hook. > + > +In the ``get`` hook, the user must choose how to map kernel pages: > + > +* ``discontig_kernel_map_abort()`` - Call this to abort the operation, > whatever > + has been mapped so far will be retained, the rest of the mapping will > SIGBUS > + if accessed. > +* ``discontig_kernel_map_page()`` - Maps a single page, correctly handling > + compound pages (if the compound page is bigger than the remaining pages in > the > + VMA, then only those pages that fit will be mapped). For a compound page, > the > + head page must be passed. > +* ``discontig_kernel_map_page_range()`` - Map an array of pages of a > specified > + size. As with a compound page, if more pages are specified than remain in > + the VMA then only those that fit will be mapped. > + > +If an error arises after ``init`` succeeded, the core unmaps the VMA, > invoking > +``vm_ops->close`` if set, which is therefore the place to release any state > +that ``init`` established. > > -- > 2.55.0 >
