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
>

Reply via email to