* [PATCH 1/1] docs: wrap generated tables to contain small-screen overflow
From: Rito Rhymes @ 2026-03-21 13:38 UTC (permalink / raw)
To: Jonathan Corbet, Mauro Carvalho Chehab, linux-doc
Cc: Shuah Khan, linux-kernel, Rito Rhymes
In-Reply-To: <20260321133811.17854-1-rito@ritovision.com>
Some documentation tables exceed the fixed-width main content column.
On desktop this is usually acceptable because they can overflow the
800px body without harming readability, but on smaller screens the
same tables create page-wide horizontal scroll overflow that breaks the
layout.
Wrap generated HTML tables in a dedicated container. Above
Alabaster's existing 65em breakpoint, the wrapper uses
`display: contents` to preserve current desktop rendering. At and
below that width, it becomes a horizontal scroll container so table
overflow is contained locally instead of breaking page layout.
Signed-off-by: Rito Rhymes <rito@ritovision.com>
---
Documentation/conf.py | 1 +
Documentation/sphinx-static/custom.css | 16 ++++++++++++++
Documentation/sphinx/table_wrapper.py | 30 ++++++++++++++++++++++++++
3 files changed, 47 insertions(+)
create mode 100644 Documentation/sphinx/table_wrapper.py
diff --git a/Documentation/conf.py b/Documentation/conf.py
index 679861503..51756d779 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -159,6 +159,7 @@ extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.autosectionlabel",
"sphinx.ext.ifconfig",
+ "table_wrapper",
"translations",
]
# Since Sphinx version 3, the C function parser is more pedantic with regards
diff --git a/Documentation/sphinx-static/custom.css b/Documentation/sphinx-static/custom.css
index db24f4344..d7c8c4f18 100644
--- a/Documentation/sphinx-static/custom.css
+++ b/Documentation/sphinx-static/custom.css
@@ -23,6 +23,13 @@ div.document {
margin: 20px 10px 0 10px;
width: auto;
}
+/*
+ * Wrap generated tables in a container that preserves desktop overflow
+ * while allowing contained scrolling on smaller screens.
+ */
+div.body div.table-overflow {
+ display: contents;
+}
/* Size the logo appropriately */
img.logo {
@@ -96,6 +103,15 @@ input.kernel-toc-toggle { display: none; }
div.kerneltoc a { color: black; }
}
+@media screen and (max-width: 65em) {
+ div.body div.table-overflow {
+ display: block;
+ max-width: 100%;
+ overflow-x: auto;
+ overflow-y: hidden;
+ }
+}
+
/* Language selection menu */
div.admonition {
diff --git a/Documentation/sphinx/table_wrapper.py b/Documentation/sphinx/table_wrapper.py
new file mode 100644
index 000000000..dfe8c139b
--- /dev/null
+++ b/Documentation/sphinx/table_wrapper.py
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+"""Wrap generated HTML tables in a responsive overflow container."""
+
+from sphinx.writers.html5 import HTML5Translator
+
+__version__ = "1.0"
+
+
+class TableWrapperHTMLTranslator(HTML5Translator):
+ """Add a wrapper around tables so CSS can control overflow behavior."""
+
+ def visit_table(self, node):
+ self.body.append('<div class="table-overflow">\n')
+ super().visit_table(node)
+
+ def depart_table(self, node):
+ super().depart_table(node)
+ self.body.append("</div>\n")
+
+
+def setup(app):
+ for builder in ("html", "dirhtml", "singlehtml"):
+ app.set_translator(builder, TableWrapperHTMLTranslator, override=True)
+
+ return dict(
+ version=__version__,
+ parallel_read_safe=True,
+ parallel_write_safe=True,
+ )
--
2.51.0
^ permalink raw reply related
* [PATCH 0/1] docs: examples of pages affected by table overflow
From: Rito Rhymes @ 2026-03-21 13:38 UTC (permalink / raw)
To: Jonathan Corbet, Mauro Carvalho Chehab, linux-doc
Cc: Shuah Khan, linux-kernel, Rito Rhymes
Examples of affected pages this patch improves:
kernel-hacking/locking.html
arch/arc/features.html
arch/arm/memory.html
arch/arm/omap/dss.html
arch/mips/features.html
arch/nios2/features.html
arch/openrisc/features.html
arch/parisc/features.html
arch/powerpc/features.html
arch/riscv/features.html
arch/s390/features.html
arch/sparc/features.html
arch/x86/boot.html
arch/x86/zero-page.html
arch/x86/pat.html
arch/x86/amd-hfi.html
arch/x86/tsx_async_abort.html
arch/x86/features.html
driver-api/parport-lowlevel.html
Rito Rhymes (1):
docs: wrap generated tables to contain small-screen overflow
Documentation/conf.py | 1 +
Documentation/sphinx-static/custom.css | 16 ++++++++++++++
Documentation/sphinx/table_wrapper.py | 30 ++++++++++++++++++++++++++
3 files changed, 47 insertions(+)
create mode 100644 Documentation/sphinx/table_wrapper.py
--
2.51.0
^ permalink raw reply
* [PATCH] docs: rework footer with semantic markup and responsive layout
From: Rito Rhymes @ 2026-03-21 13:18 UTC (permalink / raw)
To: Jonathan Corbet, Mauro Carvalho Chehab, linux-doc
Cc: Shuah Khan, linux-kernel, Rito Rhymes
The current Alabaster footer uses a generic `div` container, is
hidden entirely at the theme's small-screen breakpoint, and does
not provide a responsive layout for narrower viewports.
Rework the Alabaster footer to use semantic markup while
preserving its existing content, including the copyright notice,
theme attribution, and Page source link. Structure it with a
responsive flexbox so those items remain visible and orderly on
smaller screens.
Scope the change to Alabaster so other supported themes remain
unaffected.
Signed-off-by: Rito Rhymes <rito@ritovision.com>
---
Documentation/conf.py | 6 ++++
Documentation/sphinx-static/custom.css | 25 ++++++++++++++++
Documentation/sphinx/templates/layout.html | 33 ++++++++++++++++++++++
3 files changed, 64 insertions(+)
create mode 100644 Documentation/sphinx/templates/layout.html
diff --git a/Documentation/conf.py b/Documentation/conf.py
index 679861503..7ad1db83e 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -432,6 +432,12 @@ if html_theme == "alabaster":
sys.stderr.write("Using %s theme\n" % html_theme)
+# Expose the active theme so local templates can avoid overriding
+# theme-specific markup for non-default HTML builds.
+html_context = {
+ "kernel_docs_theme": html_theme,
+}
+
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
diff --git a/Documentation/sphinx-static/custom.css b/Documentation/sphinx-static/custom.css
index db24f4344..dfe550adf 100644
--- a/Documentation/sphinx-static/custom.css
+++ b/Documentation/sphinx-static/custom.css
@@ -23,6 +23,31 @@ div.document {
margin: 20px 10px 0 10px;
width: auto;
}
+/*
+ * Use a semantic footer that stays visible on small screens and wraps
+ * its content as needed.
+ */
+footer.footer {
+ max-width: 65em;
+ margin: 20px auto 30px auto;
+ padding: 0 15px 0 10px;
+ box-sizing: border-box;
+ font-size: 14px;
+ color: #888;
+}
+
+footer.footer a {
+ color: inherit;
+}
+
+footer.footer div.footer-inner {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 0.35em 0.6em;
+ text-align: center;
+}
/* Size the logo appropriately */
img.logo {
diff --git a/Documentation/sphinx/templates/layout.html b/Documentation/sphinx/templates/layout.html
new file mode 100644
index 000000000..52727cabc
--- /dev/null
+++ b/Documentation/sphinx/templates/layout.html
@@ -0,0 +1,33 @@
+{# SPDX-License-Identifier: GPL-2.0 #}
+
+{%- extends "!layout.html" %}
+
+{%- block footer %}
+ {% if kernel_docs_theme == "alabaster" %}
+ <footer class="footer" role="contentinfo">
+ <div class="footer-inner">
+ {% if show_copyright %}
+ <span class="footer-item">©{{ copyright }}.</span>
+ {% endif %}
+ {% if show_sphinx %}
+ {% if show_copyright %}
+ <span class="footer-sep" aria-hidden="true">|</span>
+ {% endif %}
+ <span class="footer-item">
+ Powered by <a href="https://www.sphinx-doc.org/">Sphinx {{ sphinx_version }}</a>
+ & <a href="https://alabaster.readthedocs.io">Alabaster {{ alabaster_version }}</a>
+ </span>
+ {% endif %}
+ {%- if show_source and has_source and sourcename %}
+ {% if show_copyright or show_sphinx %}
+ <span class="footer-sep" aria-hidden="true">|</span>
+ {% endif %}
+ <a class="footer-item" href="{{ pathto('_sources/' + sourcename, resource=True)|e }}"
+ rel="nofollow">{{ _('Page source') }}</a>
+ {%- endif %}
+ </div>
+ </footer>
+ {% else %}
+ {{ super() }}
+ {% endif %}
+{%- endblock %}
--
2.51.0
^ permalink raw reply related
* [PATCH v2] docs: use logo.svg as favicon
From: Rito Rhymes @ 2026-03-21 12:55 UTC (permalink / raw)
To: Jonathan Corbet, linux-doc; +Cc: Shuah Khan, linux-kernel, Rito Rhymes
In-Reply-To: <20260321111217.2404-1-rito@ritovision.com>
Use the existing documentation logo as the HTML favicon.
This makes generated documentation pages use a matching browser tab
icon without introducing a separate favicon asset.
Signed-off-by: Rito Rhymes <rito@ritovision.com>
---
v2: add commit message body and missing Signed-off-by
Documentation/conf.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/conf.py b/Documentation/conf.py
index 679861503..9b822ab47 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -455,6 +455,7 @@ if html_theme == "alabaster":
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = "images/logo.svg"
+html_favicon = "images/logo.svg"
# Output file base name for HTML help builder.
htmlhelp_basename = "TheLinuxKerneldoc"
--
2.51.0
^ permalink raw reply related
* [PATCH] docs: set canonical base URL for HTML output
From: Rito Rhymes @ 2026-03-21 12:49 UTC (permalink / raw)
To: Jonathan Corbet, linux-doc; +Cc: Shuah Khan, linux-kernel, Rito Rhymes
Set the published docs URL as html_baseurl so generated HTML pages
advertise the correct canonical URL metadata.
This helps search engines and other consumers treat docs.kernel.org as
the canonical location for published documentation pages.
Signed-off-by: Rito Rhymes <rito@ritovision.com>
---
Documentation/conf.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/conf.py b/Documentation/conf.py
index 679861503..f517dfeaf 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -437,6 +437,9 @@ sys.stderr.write("Using %s theme\n" % html_theme)
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["sphinx-static"]
+# Canonical base URL for generated HTML pages.
+html_baseurl = "https://docs.kernel.org/"
+
# If true, Docutils "smart quotes" will be used to convert quotes and dashes
# to typographically correct entities. However, conversion of "--" to "—"
# is not always what we want, so enable only quotes.
--
2.51.0
^ permalink raw reply related
* [PATCH] docs: use logo.svg as favicon
From: Rito Rhymes @ 2026-03-21 11:12 UTC (permalink / raw)
To: Jonathan Corbet, linux-doc; +Cc: Shuah Khan, linux-kernel, Rito Rhymes
---
Documentation/conf.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/conf.py b/Documentation/conf.py
index 679861503..9b822ab47 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -455,6 +455,7 @@ if html_theme == "alabaster":
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = "images/logo.svg"
+html_favicon = "images/logo.svg"
# Output file base name for HTML help builder.
htmlhelp_basename = "TheLinuxKerneldoc"
--
2.51.0
^ permalink raw reply related
* Re: [PATCH v2 06/10] gpu: nova-core: convert PDISP registers to kernel register macro
From: Alexandre Courbot @ 2026-03-21 6:19 UTC (permalink / raw)
To: Joel Fernandes
Cc: Danilo Krummrich, Alice Ryhl, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Miguel Ojeda,
Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple,
Timur Tabi, Zhi Wang, Eliot Courtney, dri-devel, linux-kernel,
linux-riscv, linux-doc, rust-for-linux
In-Reply-To: <0231b5bc-03f0-4207-b0c4-fb6daf19d135@nvidia.com>
On Sat Mar 21, 2026 at 2:33 AM JST, Joel Fernandes wrote:
>
>
> On 3/20/2026 8:19 AM, Alexandre Courbot wrote:
>> Convert all PDISP registers to use the kernel's register macro and
>> update the code accordingly.
>>
>> Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>
>> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
>> ---
>> drivers/gpu/nova-core/fb.rs | 6 +++++-
>> drivers/gpu/nova-core/regs.rs | 12 ++++++++----
>> 2 files changed, 13 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs
>> index 6536d0035cb1..62fc90fa6a84 100644
>> --- a/drivers/gpu/nova-core/fb.rs
>> +++ b/drivers/gpu/nova-core/fb.rs
>> @@ -8,6 +8,7 @@
>> use kernel::{
>> device,
>> fmt,
>> + io::Io,
>> prelude::*,
>> ptr::{
>> Alignable,
>> @@ -189,7 +190,10 @@ pub(crate) fn new(chipset: Chipset, bar: &Bar0, gsp_fw: &GspFirmware) -> Result<
>> let base = fb.end - NV_PRAMIN_SIZE;
>>
>> if hal.supports_display(bar) {
>> - match regs::NV_PDISP_VGA_WORKSPACE_BASE::read(bar).vga_workspace_addr() {
>> + match bar
>> + .read(regs::NV_PDISP_VGA_WORKSPACE_BASE)
>> + .vga_workspace_addr()
>> + {
>> Some(addr) => {
>> if addr < base {
>> const VBIOS_WORKSPACE_SIZE: u64 = usize_as_u64(SZ_128K);
>> diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs
>> index 61a8dba22d88..b051d5568cd8 100644
>> --- a/drivers/gpu/nova-core/regs.rs
>> +++ b/drivers/gpu/nova-core/regs.rs
>> @@ -250,10 +250,14 @@ pub(crate) fn usable_fb_size(self) -> u64 {
>>
>> // PDISP
>>
>> -register!(NV_PDISP_VGA_WORKSPACE_BASE @ 0x00625f04 {
>> - 3:3 status_valid as bool, "Set if the `addr` field is valid";
>> - 31:8 addr as u32, "VGA workspace base address divided by 0x10000";
>> -});
>> +io::register! {
>> + pub(crate) NV_PDISP_VGA_WORKSPACE_BASE(u32) @ 0x00625f04 {
>> + /// VGA workspace base address divided by 0x10000.
>> + 31:8 addr;
>> + /// Set if the `addr` field is valid.
>> + 3:3 status_valid => bool;
>> + }
>> +}
>
> Shouldn't this re-ordering of bit ranges be a separate patch? Also, what did we
> conclude on the ordering issue? I remember this was discussed, but I am not sure
> what the conclusion was.
The conclusion was descending order for both bitfields and the bits
themselves. This is part of the contract for using the `register!`
macro, so I don't think it is out of place in this series (and
re-shuffling things again won't make this diff smaller or more readable,
so I don't think there is a benefit).
^ permalink raw reply
* Re: [PATCH v2 08/10] gpu: nova-core: convert falcon registers to kernel register macro
From: Alexandre Courbot @ 2026-03-21 6:16 UTC (permalink / raw)
To: John Hubbard
Cc: Joel Fernandes, Danilo Krummrich, Alice Ryhl, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Alistair Popple, Timur Tabi, Zhi Wang,
Eliot Courtney, dri-devel, linux-kernel, linux-riscv, linux-doc,
rust-for-linux
In-Reply-To: <ba3c5689-5e34-4097-8823-c37a48a4f358@nvidia.com>
On Sat Mar 21, 2026 at 4:52 AM JST, John Hubbard wrote:
> On 3/20/26 10:38 AM, Joel Fernandes wrote:
>> Hi Alex,
>>
>> On 3/20/2026 8:19 AM, Alexandre Courbot wrote:
>>> /// Reset the controller, select the falcon core, and wait for memory scrubbing to complete.
>>> @@ -616,9 +462,10 @@ pub(crate) fn reset(&self, bar: &Bar0) -> Result {
>>> self.hal.select_core(self, bar)?;
>>> self.hal.reset_wait_mem_scrubbing(bar)?;
>>>
>>> - regs::NV_PFALCON_FALCON_RM::default()
>>> - .set_value(bar.read(regs::NV_PMC_BOOT_0).into())
>>> - .write(bar, &E::ID);
>>> + bar.write(
>>> + WithBase::of::<E>(),
>>> + regs::NV_PFALCON_FALCON_RM::from(bar.read(regs::NV_PMC_BOOT_0).into_raw()),
>>> + );
>>>
>>
>> Overall, I think the series is good improvement but I still feel this part is a
>> step back in readability, and we should come up with something better. I don't
>> think there's any chance anyone can memorize this syntax.
>
> I must reluctantly (because I know this conversation has gone very
> long, across so many versions) agree. That .write() statement is just
> brutal, and we will be relying on AI in order to even figure it out,
> I fear.
>
> I'd hoped that there were other, simpler forms to express this,
> is that not the case here?
Is the problem only about this particular `write()` statement? If so
there are other ways to write it, which we definitely should do if we
consider the nasty thing it is doing: read PMC_BOOT_0, extract its raw
value, forcibly store it into PFALCON_FALCON_RM, and write that value
back into the instance belonging to engine `E`.
It's quite a mouthful. Using a temporary value would help. Maybe we can
also implement a `From<NV_PMC_BOOT_0> on `PFALCON_FALCON_RM`, as it is
clearly used with that intent here.
Future features like projections the macro to initialize bitfields (once
they are extracted) should also improve readability. Meanwhile, it is of
course fine to use variables to smoothen complex statements a bit,
although I'd say this is beyond the scope of this series which tries to
translate the code 1:1.
^ permalink raw reply
* Re: [PATCH 2/2] hwmon: add mpm369x driver
From: kernel test robot @ 2026-03-21 5:56 UTC (permalink / raw)
To: Yuxi Wang, linux, corbet, robh, krzk+dt, conor+dt
Cc: oe-kbuild-all, wyx137120466, linux-hwmon, linux-doc, linux-kernel,
devicetree
In-Reply-To: <0111019cffc12220-1800bb62-f2e0-4194-99a3-7d2ba03532c6-000000@us-west-1.amazonses.com>
Hi Yuxi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on groeck-staging/hwmon-next]
[also build test WARNING on robh/for-next next-20260320]
[cannot apply to linus/master v6.16-rc1]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yuxi-Wang/hwmon-add-mpm369x-driver/20260321-082055
base: https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next
patch link: https://lore.kernel.org/r/0111019cffc12220-1800bb62-f2e0-4194-99a3-7d2ba03532c6-000000%40us-west-1.amazonses.com
patch subject: [PATCH 2/2] hwmon: add mpm369x driver
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
docutils: docutils (Docutils 0.21.2, Python 3.13.5, on linux)
reproduce: (https://download.01.org/0day-ci/archive/20260321/202603210627.wqCkJ5al-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603210627.wqCkJ5al-lkp@intel.com/
All warnings (new ones prefixed by >>):
Runtime Survivability
===================== [docutils]
>> Documentation/hwmon/mpm369x.rst:4: WARNING: Title underline too short.
vim +4 Documentation/hwmon/mpm369x.rst
2
3 Kernel driver mpm369x
> 4 ====================
5
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v4 00/21] mm: expand mmap_prepare functionality and usage
From: Andrew Morton @ 2026-03-21 2:42 UTC (permalink / raw)
To: Lorenzo Stoakes (Oracle)
Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jann Horn,
Pedro Falcato, linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <cover.1774045440.git.ljs@kernel.org>
On Fri, 20 Mar 2026 22:39:26 +0000 "Lorenzo Stoakes (Oracle)" <ljs@kernel.org> wrote:
> This series expands the mmap_prepare functionality, which is intended to
> replace the deprecated f_op->mmap hook which has been the source of bugs
> and security issues for some time.
Thanks, I updated mm-unstable to this version. Here's how that altered
mm.git:
Documentation/filesystems/mmap_prepare.rst | 4
include/linux/mm.h | 3
mm/internal.h | 27 ++++-
mm/util.c | 87 +++++++++----------
mm/vma.c | 41 +-------
tools/testing/vma/include/dup.h | 44 +--------
tools/testing/vma/include/stubs.h | 3
7 files changed, 80 insertions(+), 129 deletions(-)
--- a/Documentation/filesystems/mmap_prepare.rst~b
+++ a/Documentation/filesystems/mmap_prepare.rst
@@ -123,8 +123,8 @@ When implementing mmap_prepare(), refere
as a ``VMA_xxx_BIT`` macro, e.g. ``VMA_READ_BIT``, ``VMA_WRITE_BIT`` etc.,
and use one of (where ``desc`` is a pointer to struct vm_area_desc):
-* ``vma_desc_test_flags(desc, ...)`` - Specify a comma-separated list of flags
- you wish to test for (whether _any_ are set), e.g. - ``vma_desc_test_flags(
+* ``vma_desc_test_any(desc, ...)`` - Specify a comma-separated list of flags
+ you wish to test for (whether _any_ are set), e.g. - ``vma_desc_test_any(
desc, VMA_WRITE_BIT, VMA_MAYWRITE_BIT)`` - returns ``true`` if either are set,
otherwise ``false``.
* ``vma_desc_set_flags(desc, ...)`` - Update the VMA descriptor flags to set
--- a/include/linux/mm.h~b
+++ a/include/linux/mm.h
@@ -4394,8 +4394,7 @@ static inline void mmap_action_map_kerne
int mmap_action_prepare(struct vm_area_desc *desc);
int mmap_action_complete(struct vm_area_struct *vma,
- struct mmap_action *action,
- bool rmap_lock_held);
+ struct mmap_action *action);
/* Look up the first VMA which exactly match the interval vm_start ... vm_end */
static inline struct vm_area_struct *find_exact_vma(struct mm_struct *mm,
--- a/mm/internal.h~b
+++ a/mm/internal.h
@@ -202,14 +202,6 @@ static inline void vma_close(struct vm_a
/* unmap_vmas is in mm/memory.c */
void unmap_vmas(struct mmu_gather *tlb, struct unmap_desc *unmap);
-static inline void unmap_vma_locked(struct vm_area_struct *vma)
-{
- const size_t len = vma_pages(vma) << PAGE_SHIFT;
-
- mmap_assert_write_locked(vma->vm_mm);
- do_munmap(vma->vm_mm, vma->vm_start, len, NULL);
-}
-
#ifdef CONFIG_MMU
static inline void get_anon_vma(struct anon_vma *anon_vma)
@@ -1826,6 +1818,25 @@ static inline int io_remap_pfn_range_pre
return 0;
}
+/*
+ * When we succeed an mmap action or just before we unmap a VMA on error, we
+ * need to ensure any rmap lock held is released. On unmap it's required to
+ * avoid a deadlock.
+ */
+static inline void maybe_rmap_unlock_action(struct vm_area_struct *vma,
+ struct mmap_action *action)
+{
+ struct file *file;
+
+ if (!action->hide_from_rmap_until_complete)
+ return;
+
+ VM_WARN_ON_ONCE(vma_is_anonymous(vma));
+ file = vma->vm_file;
+ i_mmap_unlock_write(file->f_mapping);
+ action->hide_from_rmap_until_complete = false;
+}
+
#ifdef CONFIG_MMU_NOTIFIER
static inline int clear_flush_young_ptes_notify(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep, unsigned int nr)
--- a/mm/util.c~b
+++ a/mm/util.c
@@ -1198,25 +1198,6 @@ void compat_set_desc_from_vma(struct vm_
}
EXPORT_SYMBOL(compat_set_desc_from_vma);
-static int __compat_vma_mapped(struct file *file, struct vm_area_struct *vma)
-{
- const struct vm_operations_struct *vm_ops = vma->vm_ops;
- void *vm_private_data = vma->vm_private_data;
- int err;
-
- if (!vm_ops || !vm_ops->mapped)
- return 0;
-
- err = vm_ops->mapped(vma->vm_start, vma->vm_end, vma->vm_pgoff, file,
- &vm_private_data);
- if (err)
- unmap_vma_locked(vma);
- else if (vm_private_data != vma->vm_private_data)
- vma->vm_private_data = vm_private_data;
-
- return err;
-}
-
/**
* __compat_vma_mmap() - Similar to compat_vma_mmap(), only it allows
* flexibility as to how the mmap_prepare callback is invoked, which is useful
@@ -1251,13 +1232,7 @@ int __compat_vma_mmap(struct vm_area_des
/* Update the VMA from the descriptor. */
compat_set_vma_from_desc(vma, desc);
/* Complete any specified mmap actions. */
- err = mmap_action_complete(vma, &desc->action,
- /*rmap_lock_held=*/false);
- if (err)
- return err;
-
- /* Invoke vm_ops->mapped callback. */
- return __compat_vma_mapped(desc->file, vma);
+ return mmap_action_complete(vma, &desc->action);
}
EXPORT_SYMBOL(__compat_vma_mmap);
@@ -1290,12 +1265,17 @@ EXPORT_SYMBOL(__compat_vma_mmap);
int compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
{
struct vm_area_desc desc;
+ struct mmap_action *action;
int err;
compat_set_desc_from_vma(&desc, file, vma);
err = vfs_mmap_prepare(file, &desc);
if (err)
return err;
+ action = &desc.action;
+
+ /* being invoked from .mmmap means we don't have to enforce this. */
+ action->hide_from_rmap_until_complete = false;
return __compat_vma_mmap(&desc, vma);
}
@@ -1399,25 +1379,47 @@ again:
}
}
+static int call_vma_mapped(struct vm_area_struct *vma)
+{
+ const struct vm_operations_struct *vm_ops = vma->vm_ops;
+ void *vm_private_data = vma->vm_private_data;
+ int err;
+
+ if (!vm_ops || !vm_ops->mapped)
+ return 0;
+
+ err = vm_ops->mapped(vma->vm_start, vma->vm_end, vma->vm_pgoff,
+ vma->vm_file, &vm_private_data);
+ if (err)
+ return err;
+
+ if (vm_private_data != vma->vm_private_data)
+ vma->vm_private_data = vm_private_data;
+ return 0;
+}
+
static int mmap_action_finish(struct vm_area_struct *vma,
- struct mmap_action *action, int err,
- bool rmap_lock_held)
+ struct mmap_action *action, int err)
{
- if (rmap_lock_held)
- i_mmap_unlock_write(vma->vm_file->f_mapping);
+ size_t len;
- if (!err) {
- if (action->success_hook)
- return action->success_hook(vma);
+ if (!err)
+ err = call_vma_mapped(vma);
+ if (!err && action->success_hook)
+ err = action->success_hook(vma);
+
+ /* do_munmap() might take rmap lock, so release if held. */
+ maybe_rmap_unlock_action(vma, action);
+ if (!err)
return 0;
- }
/*
* 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.
*/
- unmap_vma_locked(vma);
+ 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);
@@ -1459,16 +1461,13 @@ EXPORT_SYMBOL(mmap_action_prepare);
* mmap_action_complete - Execute VMA descriptor action.
* @vma: The VMA to perform the action upon.
* @action: The action to perform.
- * @rmap_lock_held: Is the file rmap lock held?
*
* Similar to mmap_action_prepare().
*
* Return: 0 on success, or error, at which point the VMA will be unmapped.
*/
int mmap_action_complete(struct vm_area_struct *vma,
- struct mmap_action *action,
- bool rmap_lock_held)
-
+ struct mmap_action *action)
{
int err = 0;
@@ -1489,8 +1488,7 @@ int mmap_action_complete(struct vm_area_
break;
}
- return mmap_action_finish(vma, action, err,
- rmap_lock_held);
+ return mmap_action_finish(vma, action, err);
}
EXPORT_SYMBOL(mmap_action_complete);
#else
@@ -1512,8 +1510,7 @@ int mmap_action_prepare(struct vm_area_d
EXPORT_SYMBOL(mmap_action_prepare);
int mmap_action_complete(struct vm_area_struct *vma,
- struct mmap_action *action,
- bool rmap_lock_held)
+ struct mmap_action *action)
{
int err = 0;
@@ -1523,14 +1520,14 @@ int mmap_action_complete(struct vm_area_
case MMAP_REMAP_PFN:
case MMAP_IO_REMAP_PFN:
case MMAP_SIMPLE_IO_REMAP:
- casr MMAP_MAP_KERNEL_PAGES:
+ case MMAP_MAP_KERNEL_PAGES:
WARN_ON_ONCE(1); /* nommu cannot handle this. */
err = -EINVAL;
break;
}
- return mmap_action_finish(vma, action, err, rmap_lock_held);
+ return mmap_action_finish(vma, action, err);
}
EXPORT_SYMBOL(mmap_action_complete);
#endif
--- a/mm/vma.c~b
+++ a/mm/vma.c
@@ -38,8 +38,6 @@ struct mmap_state {
/* Determine if we can check KSM flags early in mmap() logic. */
bool check_ksm_early :1;
- /* If we map new, hold the file rmap lock on mapping. */
- bool hold_file_rmap_lock :1;
/* If .mmap_prepare changed the file, we don't need to pin. */
bool file_doesnt_need_get :1;
};
@@ -2530,10 +2528,12 @@ static int __mmap_new_file_vma(struct mm
*
* @map: Mapping state.
* @vmap: Output pointer for the new VMA.
+ * @action: Any mmap_prepare action that is still to complete.
*
* Returns: Zero on success, or an error.
*/
-static int __mmap_new_vma(struct mmap_state *map, struct vm_area_struct **vmap)
+static int __mmap_new_vma(struct mmap_state *map, struct vm_area_struct **vmap,
+ struct mmap_action *action)
{
struct vma_iterator *vmi = map->vmi;
int error = 0;
@@ -2582,7 +2582,7 @@ static int __mmap_new_vma(struct mmap_st
vma_start_write(vma);
vma_iter_store_new(vmi, vma);
map->mm->map_count++;
- vma_link_file(vma, map->hold_file_rmap_lock);
+ vma_link_file(vma, action->hide_from_rmap_until_complete);
/*
* vma_merge_new_range() calls khugepaged_enter_vma() too, the below
@@ -2649,8 +2649,6 @@ static int call_action_prepare(struct mm
if (err)
return err;
- if (desc->action.hide_from_rmap_until_complete)
- map->hold_file_rmap_lock = true;
return 0;
}
@@ -2731,30 +2729,6 @@ static bool can_set_ksm_flags_early(stru
return false;
}
-static int call_mapped_hook(struct mmap_state *map,
- struct vm_area_struct *vma)
-{
- const struct vm_operations_struct *vm_ops = vma->vm_ops;
- void *vm_private_data = vma->vm_private_data;
- int err;
-
- if (!vm_ops || !vm_ops->mapped)
- return 0;
- err = vm_ops->mapped(vma->vm_start, vma->vm_end, vma->vm_pgoff,
- vma->vm_file, &vm_private_data);
- if (err) {
- if (map->hold_file_rmap_lock)
- i_mmap_unlock_write(vma->vm_file->f_mapping);
-
- unmap_vma_locked(vma);
- return err;
- }
- /* Update private data if changed. */
- if (vm_private_data != vma->vm_private_data)
- vma->vm_private_data = vm_private_data;
- return 0;
-}
-
static unsigned long __mmap_region(struct file *file, unsigned long addr,
unsigned long len, vma_flags_t vma_flags,
unsigned long pgoff, struct list_head *uf)
@@ -2794,7 +2768,7 @@ static unsigned long __mmap_region(struc
/* ...but if we can't, allocate a new VMA. */
if (!vma) {
- error = __mmap_new_vma(&map, &vma);
+ error = __mmap_new_vma(&map, &vma, &desc.action);
if (error)
goto unacct_error;
allocated_new = true;
@@ -2806,10 +2780,7 @@ static unsigned long __mmap_region(struc
__mmap_complete(&map, vma);
if (have_mmap_prepare && allocated_new) {
- error = mmap_action_complete(vma, &desc.action,
- map.hold_file_rmap_lock);
- if (!error)
- error = call_mapped_hook(&map, vma);
+ error = mmap_action_complete(vma, &desc.action);
if (error)
return error;
}
--- a/tools/testing/vma/include/dup.h~b
+++ a/tools/testing/vma/include/dup.h
@@ -1313,27 +1313,9 @@ static inline unsigned long vma_pages(co
return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
}
-static inline void unmap_vma_locked(struct vm_area_struct *vma)
-{
- const size_t len = vma_pages(vma) << PAGE_SHIFT;
-
- mmap_assert_write_locked(vma->vm_mm);
- do_munmap(vma->vm_mm, vma->vm_start, len, NULL);
-}
-
-static inline int __compat_vma_mapped(struct file *file, struct vm_area_struct *vma)
+static inline int vfs_mmap_prepare(struct file *file, struct vm_area_desc *desc)
{
- const struct vm_operations_struct *vm_ops = vma->vm_ops;
- int err;
-
- if (!vm_ops->mapped)
- return 0;
-
- err = vm_ops->mapped(vma->vm_start, vma->vm_end, vma->vm_pgoff, file,
- &vma->vm_private_data);
- if (err)
- unmap_vma_locked(vma);
- return err;
+ return file->f_op->mmap_prepare(desc);
}
static inline int __compat_vma_mmap(struct vm_area_desc *desc,
@@ -1348,35 +1330,27 @@ static inline int __compat_vma_mmap(stru
/* Update the VMA from the descriptor. */
compat_set_vma_from_desc(vma, desc);
/* Complete any specified mmap actions. */
- err = mmap_action_complete(vma, &desc->action,
- /*rmap_lock_held=*/false);
- if (err)
- return err;
-
- /* Invoke vm_ops->mapped callback. */
- return __compat_vma_mapped(desc->file, vma);
-}
-
-static inline int vfs_mmap_prepare(struct file *file, struct vm_area_desc *desc)
-{
- return file->f_op->mmap_prepare(desc);
+ return mmap_action_complete(vma, &desc->action);
}
-static inline int compat_vma_mmap(struct file *file,
- struct vm_area_struct *vma)
+static inline int compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
{
struct vm_area_desc desc;
+ struct mmap_action *action;
int err;
compat_set_desc_from_vma(&desc, file, vma);
err = vfs_mmap_prepare(file, &desc);
if (err)
return err;
+ action = &desc.action;
+
+ /* being invoked from .mmmap means we don't have to enforce this. */
+ action->hide_from_rmap_until_complete = false;
return __compat_vma_mmap(&desc, vma);
}
-
static inline void vma_iter_init(struct vma_iterator *vmi,
struct mm_struct *mm, unsigned long addr)
{
--- a/tools/testing/vma/include/stubs.h~b
+++ a/tools/testing/vma/include/stubs.h
@@ -87,8 +87,7 @@ static inline int mmap_action_prepare(st
}
static inline int mmap_action_complete(struct vm_area_struct *vma,
- struct mmap_action *action,
- bool rmap_lock_held)
+ struct mmap_action *action)
{
return 0;
}
_
^ permalink raw reply
* Re: Invalid link generation for equations
From: Bagas Sanjaya @ 2026-03-21 1:49 UTC (permalink / raw)
To: Randy Dunlap, Kevin Brodsky, linux-doc; +Cc: Jonathan Corbet, Shuah Khan
In-Reply-To: <07f4d4aa-aed1-451f-a129-d8112094a49a@infradead.org>
[-- Attachment #1: Type: text/plain, Size: 872 bytes --]
On Thu, Mar 19, 2026 at 08:10:42PM -0700, Randy Dunlap wrote:
>
>
> On 3/19/26 5:06 PM, Bagas Sanjaya wrote:
> > On Wed, Mar 18, 2026 at 01:56:24PM +0100, Kevin Brodsky wrote:
> >> Hi,
> >>
> >> I have noticed that links to equation images are not generated correctly
> >> on docs.kernel.org. For instance, Documentation/mm/memory-model.rst has:
> >>
> >> .. math::
> >>
> >> NR\_MEM\_SECTIONS = 2 ^ {(MAX\_PHYSMEM\_BITS - SECTION\_SIZE\_BITS)}
> >
> > I think we can just get rid of the math markup, no?
> >
>
> Why get rid of it?
> and does that assume that some specific package is installed?
>
> <snipped>...
>
> OTOH, if you are saying that it's readable when just using ASCII text,
> I'm OK with that also.
I think that's what I mean.
Thanks.
--
An old man doll... just what I always wanted! - Clara
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH V8 3/8] dax: add fsdev.c driver for fs-dax on character dax
From: John Groves @ 2026-03-21 0:44 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Miklos Szeredi, Dan Williams, Bernd Schubert, Alison Schofield,
John Groves, Jonathan Corbet, Shuah Khan, Vishal Verma,
Dave Jiang, Matthew Wilcox, Jan Kara, Alexander Viro,
David Hildenbrand, Christian Brauner, Darrick J . Wong,
Randy Dunlap, Jeff Layton, Amir Goldstein, Stefan Hajnoczi,
Joanne Koong, Josef Bacik, Bagas Sanjaya, Chen Linxuan,
James Morse, Fuad Tabba, Sean Christopherson, Shivank Garg,
Ackerley Tng, Gregory Price, Aravind Ramesh, Ajay Joshi,
venkataravis, linux-doc, linux-kernel, nvdimm, linux-cxl,
linux-fsdevel
In-Reply-To: <20260319122057.00004503@huawei.com>
On 26/03/19 12:20PM, Jonathan Cameron wrote:
> On Wed, 18 Mar 2026 20:28:37 -0500
> John Groves <john@groves.net> wrote:
>
> > The new fsdev driver provides pages/folios initialized compatibly with
> > fsdax - normal rather than devdax-style refcounting, and starting out
> > with order-0 folios.
> >
> > When fsdev binds to a daxdev, it is usually (always?) switching from the
> > devdax mode (device.c), which pre-initializes compound folios according
> > to its alignment. Fsdev uses fsdev_clear_folio_state() to switch the
> > folios into a fsdax-compatible state.
> >
> > A side effect of this is that raw mmap doesn't (can't?) work on an fsdev
> > dax instance. Accordingly, The fsdev driver does not provide raw mmap -
> > devices must be put in 'devdax' mode (drivers/dax/device.c) to get raw
> > mmap capability.
> >
> > In this commit is just the framework, which remaps pages/folios compatibly
> > with fsdax.
> >
> > Enabling dax changes:
> >
> > - bus.h: add DAXDRV_FSDEV_TYPE driver type
> > - bus.c: allow DAXDRV_FSDEV_TYPE drivers to bind to daxdevs
> > - dax.h: prototype inode_dax(), which fsdev needs
> >
> > Suggested-by: Dan Williams <dan.j.williams@intel.com>
> > Suggested-by: Gregory Price <gourry@gourry.net>
> > Signed-off-by: John Groves <john@groves.net>
>
> A few comments inline. I think some of the code here could be moved
> to a helper library used by both this and device.c
>
> > ---
> > MAINTAINERS | 8 ++
> > drivers/dax/Makefile | 6 +
> > drivers/dax/bus.c | 4 +
> > drivers/dax/bus.h | 1 +
> > drivers/dax/fsdev.c | 253 +++++++++++++++++++++++++++++++++++++++++++
> > fs/dax.c | 1 +
> > include/linux/dax.h | 3 +
> > 7 files changed, 276 insertions(+)
> > create mode 100644 drivers/dax/fsdev.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 96ea84948d76..e83cfcf7e932 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -7298,6 +7298,14 @@ L: linux-cxl@vger.kernel.org
> > S: Supported
> > F: drivers/dax/
> >
> > +DEVICE DIRECT ACCESS (DAX) [fsdev_dax]
> > +M: John Groves <jgroves@micron.com>
> > +M: John Groves <John@Groves.net>
> > +L: nvdimm@lists.linux.dev
> > +L: linux-cxl@vger.kernel.org
> > +S: Supported
> > +F: drivers/dax/fsdev.c
> > +
> > DEVICE FREQUENCY (DEVFREQ)
> > M: MyungJoo Ham <myungjoo.ham@samsung.com>
> > M: Kyungmin Park <kyungmin.park@samsung.com>
> > diff --git a/drivers/dax/Makefile b/drivers/dax/Makefile
> > index 5ed5c39857c8..3bae252fd1bf 100644
> > --- a/drivers/dax/Makefile
> > +++ b/drivers/dax/Makefile
> > @@ -5,10 +5,16 @@ obj-$(CONFIG_DEV_DAX_KMEM) += kmem.o
> > obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o
> > obj-$(CONFIG_DEV_DAX_CXL) += dax_cxl.o
> >
> > +# fsdev_dax: fs-dax compatible devdax driver (needs DEV_DAX and FS_DAX)
> > +ifeq ($(CONFIG_FS_DAX),y)
> > +obj-$(CONFIG_DEV_DAX) += fsdev_dax.o
> > +endif
>
> Why not throw in a new CONFIG_FSDAX_DEV and handle the dependencies
> in Kconfig?
At one point I had another config parameter, but I'm trying not to
gratuitously add them. The fsdev driver is pretty small, and including it
whenever FS_DAX is enabled felt reasonable to me. I'm willing to change it
if there's a consensus that way.
>
> > +
> > dax-y := super.o
> > dax-y += bus.o
> > device_dax-y := device.o
> > dax_pmem-y := pmem.o
> > dax_cxl-y := cxl.o
> > +fsdev_dax-y := fsdev.o
> >
> > obj-y += hmem/
>
> > diff --git a/drivers/dax/fsdev.c b/drivers/dax/fsdev.c
> > new file mode 100644
> > index 000000000000..e5b4396ce401
> > --- /dev/null
> > +++ b/drivers/dax/fsdev.c
>
> > +static int fsdev_dax_probe(struct dev_dax *dev_dax)
> > +{
> > + struct dax_device *dax_dev = dev_dax->dax_dev;
> > + struct device *dev = &dev_dax->dev;
> > + struct dev_pagemap *pgmap;
> > + u64 data_offset = 0;
>
> See below. I think you can useful reduce scope of this one.
As of now, I've reduced the scope, but in the very next commit it needs to
move back here. So meh...not sure that's worth it for one commit
>
> > + struct inode *inode;
> > + struct cdev *cdev;
> > + void *addr;
> > + int rc, i;
> > +
>
> There is a lot of duplication in here with dax/device.c
> Is any of it suitable for shared helpers?
I haven't addressed factoring out more duplicated code yet. Ideally I'd like
to do that after the initial merge, but I'm paying attention to whether
there's pressure to do it.
>
> > + if (static_dev_dax(dev_dax)) {
> > + if (dev_dax->nr_range > 1) {
> > + dev_warn(dev, "static pgmap / multi-range device conflict\n");
> > + return -EINVAL;
> > + }
> > +
> > + pgmap = dev_dax->pgmap;
> > + } else {
> > + size_t pgmap_size;
> > +
> > + if (dev_dax->pgmap) {
> > + dev_warn(dev, "dynamic-dax with pre-populated page map\n");
> > + return -EINVAL;
> > + }
> > +
> > + pgmap_size = struct_size(pgmap, ranges, dev_dax->nr_range - 1);
> > + pgmap = devm_kzalloc(dev, pgmap_size, GFP_KERNEL);
>
> Bonus space before GFP_KERNEL.
Excised, thanks
>
>
> > + if (!pgmap)
> > + return -ENOMEM;
> > +
> > + pgmap->nr_range = dev_dax->nr_range;
> > + dev_dax->pgmap = pgmap;
> > +
> > + for (i = 0; i < dev_dax->nr_range; i++) {
> > + struct range *range = &dev_dax->ranges[i].range;
> > +
> > + pgmap->ranges[i] = *range;
> > + }
> > + }
> > +
> > + for (i = 0; i < dev_dax->nr_range; i++) {
> > + struct range *range = &dev_dax->ranges[i].range;
> > +
> > + if (!devm_request_mem_region(dev, range->start,
> > + range_len(range), dev_name(dev))) {
> > + dev_warn(dev, "mapping%d: %#llx-%#llx could not reserve range\n",
> > + i, range->start, range->end);
> > + return -EBUSY;
> > + }
> > + }
>
> Everything above here is shared. Some sort of _init() or similar library function
> seems in order.
Taken under advisement. Will look at this soon.
>
> > +
> > + /*
> > + * FS-DAX compatible mode: Use MEMORY_DEVICE_FS_DAX type and
> > + * do NOT set vmemmap_shift. This leaves folios at order-0,
> > + * allowing fs-dax to dynamically create compound folios as needed
> > + * (similar to pmem behavior).
> > + */
> > + pgmap->type = MEMORY_DEVICE_FS_DAX;
> > + pgmap->ops = &fsdev_pagemap_ops;
> > + pgmap->owner = dev_dax;
> > +
> > + /*
> > + * CRITICAL DIFFERENCE from device.c:
> > + * We do NOT set vmemmap_shift here, even if align > PAGE_SIZE.
> > + * This ensures folios remain order-0 and are compatible with
> > + * fs-dax's folio management.
> > + */
> > +
> > + addr = devm_memremap_pages(dev, pgmap);
> > + if (IS_ERR(addr))
> > + return PTR_ERR(addr);
> > +
> > + /*
> > + * Clear any stale compound folio state left over from a previous
> > + * driver (e.g., device_dax with vmemmap_shift). Also register this
> > + * as a devm action so folio state is cleared on unbind, ensuring
> > + * clean pages for subsequent drivers (e.g., kmem for system-ram).
> > + */
> > + fsdev_clear_folio_state(dev_dax);
> > + rc = devm_add_action_or_reset(dev, fsdev_clear_folio_state_action,
> > + dev_dax);
> > + if (rc)
> > + return rc;
> > +
> > + /* Detect whether the data is at a non-zero offset into the memory */
> > + if (pgmap->range.start != dev_dax->ranges[0].range.start) {
> > + u64 phys = dev_dax->ranges[0].range.start;
> > + u64 pgmap_phys = dev_dax->pgmap[0].range.start;
> > +
> > + if (!WARN_ON(pgmap_phys > phys))
> > + data_offset = phys - pgmap_phys;
> > +
> > + pr_debug("%s: offset detected phys=%llx pgmap_phys=%llx offset=%llx\n",
> > + __func__, phys, pgmap_phys, data_offset);
>
> Might change later, but at least at this point you could pull declaration of data_offset
> into this scope.
done as of now, but it's used right after the closing brace of this block
in the very next commit.
>
> > + }
> > +
> > + inode = dax_inode(dax_dev);
> > + cdev = inode->i_cdev;
> > + cdev_init(cdev, &fsdev_fops);
> > + cdev->owner = dev->driver->owner;
> > + cdev_set_parent(cdev, &dev->kobj);
> > + rc = cdev_add(cdev, dev->devt, 1);
> > + if (rc)
> > + return rc;
> > +
> > + rc = devm_add_action_or_reset(dev, fsdev_cdev_del, cdev);
> > + if (rc)
> > + return rc;
> > +
> > + run_dax(dax_dev);
> > + return devm_add_action_or_reset(dev, fsdev_kill, dev_dax);
> > +}
>
> > diff --git a/include/linux/dax.h b/include/linux/dax.h
> > index bf103f317cac..996493f5c538 100644
> > --- a/include/linux/dax.h
> > +++ b/include/linux/dax.h
> > @@ -51,6 +51,7 @@ struct dax_holder_operations {
> >
> > #if IS_ENABLED(CONFIG_DAX)
> > struct dax_device *alloc_dax(void *private, const struct dax_operations *ops);
> > +
>
> Unrelated change. Tidy this up for v9.
Spurious blank line dropped - thanks
>
>
> > void *dax_holder(struct dax_device *dax_dev);
> > void put_dax(struct dax_device *dax_dev);
> > void kill_dax(struct dax_device *dax_dev);
> > @@ -151,8 +152,10 @@ static inline void fs_put_dax(struct dax_device *dax_dev, void *holder)
> > #endif /* CONFIG_BLOCK && CONFIG_FS_DAX */
> >
> > #if IS_ENABLED(CONFIG_FS_DAX)
> > +struct dax_device *inode_dax(struct inode *inode);
>
> Already in dax_private.h so why does it want to be here?
Indeed, thanks!
Regards,
John
^ permalink raw reply
* Re: [PATCH V8 2/8] dax: Factor out dax_folio_reset_order() helper
From: John Groves @ 2026-03-21 0:27 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Miklos Szeredi, Dan Williams, Bernd Schubert, Alison Schofield,
John Groves, Jonathan Corbet, Shuah Khan, Vishal Verma,
Dave Jiang, Matthew Wilcox, Jan Kara, Alexander Viro,
David Hildenbrand, Christian Brauner, Darrick J . Wong,
Randy Dunlap, Jeff Layton, Amir Goldstein, Stefan Hajnoczi,
Joanne Koong, Josef Bacik, Bagas Sanjaya, Chen Linxuan,
James Morse, Fuad Tabba, Sean Christopherson, Shivank Garg,
Ackerley Tng, Gregory Price, Aravind Ramesh, Ajay Joshi,
venkataravis, linux-doc, linux-kernel, nvdimm, linux-cxl,
linux-fsdevel, Ira Weiny
In-Reply-To: <20260319113055.00001182@huawei.com>
On 26/03/19 11:30AM, Jonathan Cameron wrote:
> On Wed, 18 Mar 2026 20:28:20 -0500
> John Groves <john@groves.net> wrote:
>
> > From: John Groves <John@Groves.net>
> >
> > Both fs/dax.c:dax_folio_put() and drivers/dax/fsdev.c:
> > fsdev_clear_folio_state() (the latter coming in the next commit after this
> > one) contain nearly identical code to reset a compound DAX folio back to
> > order-0 pages. Factor this out into a shared helper function.
> >
> > The new dax_folio_reset_order() function:
> > - Clears the folio's mapping and share count
> > - Resets compound folio state via folio_reset_order()
> > - Clears PageHead and compound_head for each sub-page
> > - Restores the pgmap pointer for each resulting order-0 folio
> > - Returns the original folio order (for callers that need to advance by
> > that many pages)
> >
> > This simplifies fsdev_clear_folio_state() from ~50 lines to ~15 lines while
> > maintaining the same functionality in both call sites.
> >
> > Suggested-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> > Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> > Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> > Signed-off-by: John Groves <john@groves.net>
>
> Comment below. I may well be needing more coffee, or failing wrt
> to background knowledge as I only occasionally dip into dax.
thanks!
>
>
> > ---
> > fs/dax.c | 60 +++++++++++++++++++++++++++++++++++++++-----------------
> > 1 file changed, 42 insertions(+), 18 deletions(-)
> >
> > diff --git a/fs/dax.c b/fs/dax.c
> > index 289e6254aa30..7d7bbfb32c41 100644
> > --- a/fs/dax.c
> > +++ b/fs/dax.c
> > @@ -378,6 +378,45 @@ static void dax_folio_make_shared(struct folio *folio)
> > folio->share = 1;
> > }
> >
> > +/**
> > + * dax_folio_reset_order - Reset a compound DAX folio to order-0 pages
> > + * @folio: The folio to reset
> > + *
> > + * Splits a compound folio back into individual order-0 pages,
> > + * clearing compound state and restoring pgmap pointers.
> > + *
> > + * Returns: the original folio order (0 if already order-0)
> > + */
> > +int dax_folio_reset_order(struct folio *folio)
> > +{
> > + struct dev_pagemap *pgmap = page_pgmap(&folio->page);
> > + int order = folio_order(folio);
> > + int i;
> > +
> > + folio->mapping = NULL;
> > + folio->share = 0;
>
> This is different from the code you are replacing..
>
> Just above the call to this in dax_folio_put()
>
> if (!dax_folio_is_shared(folio))
> // in here is the interesting bit...
> ref = 0;
> else
> //this is fine because either it's still > 0 and we return
> //or it is zero and you are writing that again.
> ref = --folio->share;
> if (ref)
> return ref;
>
> So the path that bothers me is if
> !dax_folio_is_shared() can return false with shared != 0
>
> /*
> * A DAX folio is considered shared if it has no mapping set and ->share (which
> * shares the ->index field) is non-zero. Note this may return false even if the
> * page is shared between multiple files but has not yet actually been mapped
> * into multiple address spaces.
> */
> static inline bool dax_folio_is_shared(struct folio *folio)
> {
> return !folio->mapping && folio->share;
> }
>
> So it can if !folio->mapping is false (i.e. folio->mapping is set)
>
> Now I have zero idea of whether this is a real path and have
> a long review queue so not looking into it for now.
> However if it's not then I'd expect some commentary in the patch description
> to say why it's not a problem. Maybe even a precursor patch adding
> the folio->share so there is a place to state clearly that it doesn't
> matter and why.
I believe it is correct, and I'm adding a clarifying comment above as follows:
/*
* DAX maintains the invariant that folio->share != 0 only when
* folio->mapping == NULL (enforced by dax_folio_make_shared()).
* Equivalently: folio->mapping != NULL implies folio->share == 0.
* Callers ensure share has been decremented to zero before calling
* here, so unconditionally clearing both fields is correct.
*/
folio->mapping = NULL;
folio->share = 0;
...
>
> > +
> > + if (!order) {
> > + folio->pgmap = pgmap;
> This is also different...
Here too, I think it is correct, and I'm adding a comment as follows:
if (!order) {
/*
* Restore pgmap explicitly even for order-0 folios. For the
* dax_folio_put() caller this is a no-op (same value), but
* fsdev_clear_folio_state() may call this on folios that were
* previously compound and need pgmap re-established.
*/
folio->pgmap = pgmap;
return 0;
}
...but if I'm missing anything I hope somebody will point it out!
>
> > + return 0;
> > + }
> > +
> > + folio_reset_order(folio);
> > +
> > + for (i = 0; i < (1UL << order); i++) {
>
> I'd take advantage of evolving conventions and do
>
> for (int i = 0; i < ...)
Done, thanks!
John
<snip>
^ permalink raw reply
* Re: [PATCH v14 2/2] MAINTAINERS: gpu: buddy: Update reviewer
From: Joel Fernandes @ 2026-03-21 0:06 UTC (permalink / raw)
To: Alexandre Courbot
Cc: linux-kernel@vger.kernel.org, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida,
Koen Koning, dri-devel@lists.freedesktop.org,
rust-for-linux@vger.kernel.org, Nikola Djukic, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula,
Joonas Lahtinen, Vivi Rodrigo, Tvrtko Ursulin, Rui Huang,
Matthew Auld, Matthew Brost, Lucas De Marchi,
Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng,
John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer,
Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh,
Philipp Stanner, Elle Rhumsaa, Alexey Ivanov, Eliot Courtney,
joel@joelfernandes.org, linux-doc@vger.kernel.org,
amd-gfx@lists.freedesktop.org, intel-gfx@lists.freedesktop.org,
intel-xe@lists.freedesktop.org, linux-fbdev@vger.kernel.org
In-Reply-To: <DH7LP20OY5TJ.3ICBGXWHA7LQV@nvidia.com>
> On Mar 20, 2026, at 8:16 AM, Alexandre Courbot <acourbot@nvidia.com> wrote:
>
> On Fri Mar 20, 2026 at 1:57 PM JST, Joel Fernandes wrote:
>> Christian Koenig mentioned he'd like to step down from the reviewer
>> role for the GPU buddy allocator. Joel Fernandes is stepping in as
>> reviewer with agreement from Matthew Auld and Arun Pravin.
>>
>> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
>
> This is missing the Acked-bys you collected on v13.
Thank you, would Danilo be willing to add it only apply so I do not need to resend? Acks are from Mathew, Arun and Christian.
^ permalink raw reply
* Re: [PATCH net-next v4 13/13] net/mlx5: Add a shared devlink instance for PFs on same chip
From: Adam Young @ 2026-03-20 23:16 UTC (permalink / raw)
To: Jiri Pirko, netdev
Cc: davem, edumazet, kuba, pabeni, horms, donald.hunter, corbet,
skhan, saeedm, leon, tariqt, mbloch, przemyslaw.kitszel, mschmidt,
andrew+netdev, rostedt, mhiramat, mathieu.desnoyers, chuck.lever,
matttbe, cjubran, daniel.zahka, linux-doc, linux-rdma,
linux-trace-kernel
In-Reply-To: <20260312100407.551173-14-jiri@resnulli.us>
This breaks on my system:
On 7.0.0 It boots fine. With net-next/main currently at this commit
commit 8737d7194d6d5947c3d7d8813895b44a25b84477 (net-next/main,
net-next/HEAD)
Author: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Fri Mar 13 17:28:36 2026 +0100
I get:
[ 21.859081] mlx5_core 0005:01:00.0: probe_one:2017:(pid 10):
mlx5_shd_init failed with error code -2
[ 21.863266] mlx5_core 0005:01:00.0: probe with driver mlx5_core
failed with error -2
[ 21.866360] mlx5_core 0005:01:00.1: probe_one:2017:(pid 10):
mlx5_shd_init failed with error code -2
[ 21.869937] mlx5_core 0005:01:00.1: probe with driver mlx5_core
failed with error -2
I am happy to help debug: what do you need from me?
On 3/12/26 06:04, Jiri Pirko wrote:
> From: Jiri Pirko <jiri@nvidia.com>
>
> Use the previously introduced shared devlink infrastructure to create
> a shared devlink instance for mlx5 PFs that reside on the same physical
> chip. The shared instance is identified by the chip's serial number
> extracted from PCI VPD (V3 keyword, with fallback to serial number
> for older devices).
>
> Each PF that probes calls mlx5_shd_init() which extracts the chip serial
> number and uses devlink_shd_get() to get or create the shared instance.
> When a PF is removed, mlx5_shd_uninit() calls devlink_shd_put()
> to release the reference. The shared instance is automatically destroyed
> when the last PF is removed.
>
> Make the PF devlink instances nested in this shared devlink instance,
> allowing userspace to identify which PFs belong to the same physical
> chip.
>
> Example:
>
> pci/0000:08:00.0: index 0
> nested_devlink:
> auxiliary/mlx5_core.eth.0
> devlink_index/1: index 1
> nested_devlink:
> pci/0000:08:00.0
> pci/0000:08:00.1
> auxiliary/mlx5_core.eth.0: index 2
> pci/0000:08:00.1: index 3
> nested_devlink:
> auxiliary/mlx5_core.eth.1
> auxiliary/mlx5_core.eth.1: index 4
>
> Signed-off-by: Jiri Pirko <jiri@nvidia.com>
> ---
> v2->v3:
> - removed "const" from "sn"
> - passing driver pointer to devlink_shd_get()
> ---
> .../net/ethernet/mellanox/mlx5/core/Makefile | 5 +-
> .../net/ethernet/mellanox/mlx5/core/main.c | 17 ++++++
> .../ethernet/mellanox/mlx5/core/sh_devlink.c | 61 +++++++++++++++++++
> .../ethernet/mellanox/mlx5/core/sh_devlink.h | 12 ++++
> include/linux/mlx5/driver.h | 1 +
> 5 files changed, 94 insertions(+), 2 deletions(-)
> create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
> create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.h
>
> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
> index 8ffa286a18f5..d39fe9c4a87c 100644
> --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
> +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
> @@ -16,8 +16,9 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
> transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
> fs_counters.o fs_ft_pool.o rl.o lag/debugfs.o lag/lag.o dev.o events.o wq.o lib/gid.o \
> lib/devcom.o lib/pci_vsc.o lib/dm.o lib/fs_ttc.o diag/fs_tracepoint.o \
> - diag/fw_tracer.o diag/crdump.o devlink.o diag/rsc_dump.o diag/reporter_vnic.o \
> - fw_reset.o qos.o lib/tout.o lib/aso.o wc.o fs_pool.o lib/nv_param.o
> + diag/fw_tracer.o diag/crdump.o devlink.o sh_devlink.o diag/rsc_dump.o \
> + diag/reporter_vnic.o fw_reset.o qos.o lib/tout.o lib/aso.o wc.o fs_pool.o \
> + lib/nv_param.o
>
> #
> # Netdev basic
> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
> index fdc3ba20912e..1c35c3fc3bb3 100644
> --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
> +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
> @@ -74,6 +74,7 @@
> #include "mlx5_irq.h"
> #include "hwmon.h"
> #include "lag/lag.h"
> +#include "sh_devlink.h"
>
> MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
> MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) core driver");
> @@ -1520,10 +1521,16 @@ int mlx5_init_one(struct mlx5_core_dev *dev)
> int err;
>
> devl_lock(devlink);
> + if (dev->shd) {
> + err = devl_nested_devlink_set(dev->shd, devlink);
> + if (err)
> + goto unlock;
> + }
> devl_register(devlink);
> err = mlx5_init_one_devl_locked(dev);
> if (err)
> devl_unregister(devlink);
> +unlock:
> devl_unlock(devlink);
> return err;
> }
> @@ -2005,6 +2012,13 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
> goto pci_init_err;
> }
>
> + err = mlx5_shd_init(dev);
> + if (err) {
> + mlx5_core_err(dev, "mlx5_shd_init failed with error code %d\n",
> + err);
> + goto shd_init_err;
> + }
> +
> err = mlx5_init_one(dev);
> if (err) {
> mlx5_core_err(dev, "mlx5_init_one failed with error code %d\n",
> @@ -2018,6 +2032,8 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
> return 0;
>
> err_init_one:
> + mlx5_shd_uninit(dev);
> +shd_init_err:
> mlx5_pci_close(dev);
> pci_init_err:
> mlx5_mdev_uninit(dev);
> @@ -2039,6 +2055,7 @@ static void remove_one(struct pci_dev *pdev)
> mlx5_drain_health_wq(dev);
> mlx5_sriov_disable(pdev, false);
> mlx5_uninit_one(dev);
> + mlx5_shd_uninit(dev);
> mlx5_pci_close(dev);
> mlx5_mdev_uninit(dev);
> mlx5_adev_idx_free(dev->priv.adev_idx);
> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
> new file mode 100644
> index 000000000000..bc33f95302df
> --- /dev/null
> +++ b/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
> @@ -0,0 +1,61 @@
> +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
> +/* Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
> +
> +#include <linux/mlx5/driver.h>
> +#include <net/devlink.h>
> +
> +#include "sh_devlink.h"
> +
> +static const struct devlink_ops mlx5_shd_ops = {
> +};
> +
> +int mlx5_shd_init(struct mlx5_core_dev *dev)
> +{
> + u8 *vpd_data __free(kfree) = NULL;
> + struct pci_dev *pdev = dev->pdev;
> + unsigned int vpd_size, kw_len;
> + struct devlink *devlink;
> + char *sn, *end;
> + int start;
> + int err;
> +
> + if (!mlx5_core_is_pf(dev))
> + return 0;
> +
> + vpd_data = pci_vpd_alloc(pdev, &vpd_size);
> + if (IS_ERR(vpd_data)) {
> + err = PTR_ERR(vpd_data);
> + return err == -ENODEV ? 0 : err;
> + }
> + start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, "V3", &kw_len);
> + if (start < 0) {
> + /* Fall-back to SN for older devices. */
> + start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size,
> + PCI_VPD_RO_KEYWORD_SERIALNO, &kw_len);
> + if (start < 0)
> + return -ENOENT;
> + }
> + sn = kstrndup(vpd_data + start, kw_len, GFP_KERNEL);
> + if (!sn)
> + return -ENOMEM;
> + /* Firmware may return spaces at the end of the string, strip it. */
> + end = strchrnul(sn, ' ');
> + *end = '\0';
> +
> + /* Get or create shared devlink instance */
> + devlink = devlink_shd_get(sn, &mlx5_shd_ops, 0, pdev->dev.driver);
> + kfree(sn);
> + if (!devlink)
> + return -ENOMEM;
> +
> + dev->shd = devlink;
> + return 0;
> +}
> +
> +void mlx5_shd_uninit(struct mlx5_core_dev *dev)
> +{
> + if (!dev->shd)
> + return;
> +
> + devlink_shd_put(dev->shd);
> +}
> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.h b/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.h
> new file mode 100644
> index 000000000000..8ab8d6940227
> --- /dev/null
> +++ b/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
> +/* Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
> +
> +#ifndef __MLX5_SH_DEVLINK_H__
> +#define __MLX5_SH_DEVLINK_H__
> +
> +#include <linux/mlx5/driver.h>
> +
> +int mlx5_shd_init(struct mlx5_core_dev *dev);
> +void mlx5_shd_uninit(struct mlx5_core_dev *dev);
> +
> +#endif /* __MLX5_SH_DEVLINK_H__ */
> diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
> index 04dcd09f7517..1268fcf35ec7 100644
> --- a/include/linux/mlx5/driver.h
> +++ b/include/linux/mlx5/driver.h
> @@ -798,6 +798,7 @@ struct mlx5_core_dev {
> enum mlx5_wc_state wc_state;
> /* sync write combining state */
> struct mutex wc_state_lock;
> + struct devlink *shd;
> };
>
> struct mlx5_db {
^ permalink raw reply
* [PATCH v4 21/21] mm: on remap assert that input range within the proposed VMA
From: Lorenzo Stoakes (Oracle) @ 2026-03-20 22:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jann Horn,
Pedro Falcato, linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <cover.1774045440.git.ljs@kernel.org>
Now we have range_in_vma_desc(), update remap_pfn_range_prepare() to check
whether the input range in contained within the specified VMA, so we can
fail at prepare time if an invalid range is specified.
This covers the I/O remap mmap actions also which ultimately call into
this function, and other mmap action types either already span the full
VMA or check this already.
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
---
mm/memory.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/mm/memory.c b/mm/memory.c
index 53ef8ef3d04a..68cc592ff0ba 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3142,6 +3142,9 @@ int remap_pfn_range_prepare(struct vm_area_desc *desc)
const bool is_cow = vma_desc_is_cow_mapping(desc);
int err;
+ if (!range_in_vma_desc(desc, start, end))
+ return -EFAULT;
+
err = get_remap_pgoff(is_cow, start, end, desc->start, desc->end, pfn,
&desc->pgoff);
if (err)
--
2.53.0
^ permalink raw reply related
* [PATCH v4 20/21] mm: add mmap_action_map_kernel_pages[_full]()
From: Lorenzo Stoakes (Oracle) @ 2026-03-20 22:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jann Horn,
Pedro Falcato, linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <cover.1774045440.git.ljs@kernel.org>
A user can invoke mmap_action_map_kernel_pages() to specify that the
mapping should map kernel pages starting from desc->start of a specified
number of pages specified in an array.
In order to implement this, adjust mmap_action_prepare() to be able to
return an error code, as it makes sense to assert that the specified
parameters are valid as quickly as possible as well as updating the VMA
flags to include VMA_MIXEDMAP_BIT as necessary.
This provides an mmap_prepare equivalent of vm_insert_pages(). We
additionally update the existing vm_insert_pages() code to use
range_in_vma() and add a new range_in_vma_desc() helper function for the
mmap_prepare case, sharing the code between the two in range_is_subset().
We add both mmap_action_map_kernel_pages() and
mmap_action_map_kernel_pages_full() to allow for both partial and full VMA
mappings.
We update the documentation to reflect the new features.
Finally, we update the VMA tests accordingly to reflect the changes.
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
---
Documentation/filesystems/mmap_prepare.rst | 8 ++
include/linux/mm.h | 95 +++++++++++++++++++++-
include/linux/mm_types.h | 7 ++
mm/memory.c | 42 +++++++++-
mm/util.c | 7 ++
tools/testing/vma/include/dup.h | 7 ++
6 files changed, 160 insertions(+), 6 deletions(-)
diff --git a/Documentation/filesystems/mmap_prepare.rst b/Documentation/filesystems/mmap_prepare.rst
index 14bb057be564..82c99c95ad85 100644
--- a/Documentation/filesystems/mmap_prepare.rst
+++ b/Documentation/filesystems/mmap_prepare.rst
@@ -156,5 +156,13 @@ pointer. These are:
* mmap_action_simple_ioremap() - Sets up an I/O remap from a specified
physical address and over a specified length.
+* mmap_action_map_kernel_pages() - Maps a specified array of `struct page`
+ pointers in the VMA from a specific offset.
+
+* mmap_action_map_kernel_pages_full() - Maps a specified array of `struct
+ page` pointers over the entire VMA. The caller must ensure there are
+ sufficient entries in the page array to cover the entire range of the
+ described VMA.
+
**NOTE:** The ``action`` field should never normally be manipulated directly,
rather you ought to use one of these helpers.
diff --git a/include/linux/mm.h b/include/linux/mm.h
index df8fa6e6402b..6f0a3edb24e1 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2912,7 +2912,7 @@ static inline bool folio_maybe_mapped_shared(struct folio *folio)
* The caller must add any reference (e.g., from folio_try_get()) it might be
* holding itself to the result.
*
- * Returns the expected folio refcount.
+ * Returns: the expected folio refcount.
*/
static inline int folio_expected_ref_count(const struct folio *folio)
{
@@ -4364,6 +4364,45 @@ static inline void mmap_action_simple_ioremap(struct vm_area_desc *desc,
action->type = MMAP_SIMPLE_IO_REMAP;
}
+/**
+ * mmap_action_map_kernel_pages - helper for mmap_prepare hook to specify that
+ * @num kernel pages contained in the @pages array should be mapped to userland
+ * starting at virtual address @start.
+ * @desc: The VMA descriptor for the VMA requiring kernel pags to be mapped.
+ * @start: The virtual address from which to map them.
+ * @pages: An array of struct page pointers describing the memory to map.
+ * @nr_pages: The number of entries in the @pages aray.
+ */
+static inline void mmap_action_map_kernel_pages(struct vm_area_desc *desc,
+ unsigned long start, struct page **pages,
+ unsigned long nr_pages)
+{
+ struct mmap_action *action = &desc->action;
+
+ action->type = MMAP_MAP_KERNEL_PAGES;
+ action->map_kernel.start = start;
+ action->map_kernel.pages = pages;
+ action->map_kernel.nr_pages = nr_pages;
+ action->map_kernel.pgoff = desc->pgoff;
+}
+
+/**
+ * mmap_action_map_kernel_pages_full - helper for mmap_prepare hook to specify that
+ * kernel pages contained in the @pages array should be mapped to userland
+ * from @desc->start to @desc->end.
+ * @desc: The VMA descriptor for the VMA requiring kernel pags to be mapped.
+ * @pages: An array of struct page pointers describing the memory to map.
+ *
+ * The caller must ensure that @pages contains sufficient entries to cover the
+ * entire range described by @desc.
+ */
+static inline void mmap_action_map_kernel_pages_full(struct vm_area_desc *desc,
+ struct page **pages)
+{
+ mmap_action_map_kernel_pages(desc, desc->start, pages,
+ vma_desc_pages(desc));
+}
+
int mmap_action_prepare(struct vm_area_desc *desc);
int mmap_action_complete(struct vm_area_struct *vma,
struct mmap_action *action);
@@ -4380,10 +4419,59 @@ static inline struct vm_area_struct *find_exact_vma(struct mm_struct *mm,
return vma;
}
+/**
+ * range_is_subset - Is the specified inner range a subset of the outer range?
+ * @outer_start: The start of the outer range.
+ * @outer_end: The exclusive end of the outer range.
+ * @inner_start: The start of the inner range.
+ * @inner_end: The exclusive end of the inner range.
+ *
+ * Returns: %true if [inner_start, inner_end) is a subset of [outer_start,
+ * outer_end), otherwise %false.
+ */
+static inline bool range_is_subset(unsigned long outer_start,
+ unsigned long outer_end,
+ unsigned long inner_start,
+ unsigned long inner_end)
+{
+ return outer_start <= inner_start && inner_end <= outer_end;
+}
+
+/**
+ * range_in_vma - is the specified [@start, @end) range a subset of the VMA?
+ * @vma: The VMA against which we want to check [@start, @end).
+ * @start: The start of the range we wish to check.
+ * @end: The exclusive end of the range we wish to check.
+ *
+ * Returns: %true if [@start, @end) is a subset of [@vma->vm_start,
+ * @vma->vm_end), %false otherwise.
+ */
static inline bool range_in_vma(const struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
- return (vma && vma->vm_start <= start && end <= vma->vm_end);
+ if (!vma)
+ return false;
+
+ return range_is_subset(vma->vm_start, vma->vm_end, start, end);
+}
+
+/**
+ * range_in_vma_desc - is the specified [@start, @end) range a subset of the VMA
+ * described by @desc, a VMA descriptor?
+ * @desc: The VMA descriptor against which we want to check [@start, @end).
+ * @start: The start of the range we wish to check.
+ * @end: The exclusive end of the range we wish to check.
+ *
+ * Returns: %true if [@start, @end) is a subset of [@desc->start, @desc->end),
+ * %false otherwise.
+ */
+static inline bool range_in_vma_desc(const struct vm_area_desc *desc,
+ unsigned long start, unsigned long end)
+{
+ if (!desc)
+ return false;
+
+ return range_is_subset(desc->start, desc->end, start, end);
}
#ifdef CONFIG_MMU
@@ -4427,6 +4515,9 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *);
int vm_insert_pages(struct vm_area_struct *vma, unsigned long addr,
struct page **pages, unsigned long *num);
+int map_kernel_pages_prepare(struct vm_area_desc *desc);
+int map_kernel_pages_complete(struct vm_area_struct *vma,
+ struct mmap_action *action);
int vm_map_pages(struct vm_area_struct *vma, struct page **pages,
unsigned long num);
int vm_map_pages_zero(struct vm_area_struct *vma, struct page **pages,
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index d60eefde1db8..f9face579072 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -815,6 +815,7 @@ enum mmap_action_type {
MMAP_REMAP_PFN, /* Remap PFN range. */
MMAP_IO_REMAP_PFN, /* I/O remap PFN range. */
MMAP_SIMPLE_IO_REMAP, /* I/O remap with guardrails. */
+ MMAP_MAP_KERNEL_PAGES, /* Map kernel page range from array. */
};
/*
@@ -833,6 +834,12 @@ struct mmap_action {
phys_addr_t start_phys_addr;
unsigned long size;
} simple_ioremap;
+ struct {
+ unsigned long start;
+ struct page **pages;
+ unsigned long nr_pages;
+ pgoff_t pgoff;
+ } map_kernel;
};
enum mmap_action_type type;
diff --git a/mm/memory.c b/mm/memory.c
index b3bcc21af20a..53ef8ef3d04a 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2484,13 +2484,14 @@ static int insert_pages(struct vm_area_struct *vma, unsigned long addr,
int vm_insert_pages(struct vm_area_struct *vma, unsigned long addr,
struct page **pages, unsigned long *num)
{
- const unsigned long end_addr = addr + (*num * PAGE_SIZE) - 1;
+ const unsigned long nr_pages = *num;
+ const unsigned long end = addr + PAGE_SIZE * nr_pages;
- if (addr < vma->vm_start || end_addr >= vma->vm_end)
+ if (!range_in_vma(vma, addr, end))
return -EFAULT;
if (!(vma->vm_flags & VM_MIXEDMAP)) {
- BUG_ON(mmap_read_trylock(vma->vm_mm));
- BUG_ON(vma->vm_flags & VM_PFNMAP);
+ VM_WARN_ON_ONCE(mmap_read_trylock(vma->vm_mm));
+ VM_WARN_ON_ONCE(vma->vm_flags & VM_PFNMAP);
vm_flags_set(vma, VM_MIXEDMAP);
}
/* Defer page refcount checking till we're about to map that page. */
@@ -2498,6 +2499,39 @@ int vm_insert_pages(struct vm_area_struct *vma, unsigned long addr,
}
EXPORT_SYMBOL(vm_insert_pages);
+int map_kernel_pages_prepare(struct vm_area_desc *desc)
+{
+ const struct mmap_action *action = &desc->action;
+ const unsigned long addr = action->map_kernel.start;
+ unsigned long nr_pages, end;
+
+ if (!vma_desc_test(desc, VMA_MIXEDMAP_BIT)) {
+ VM_WARN_ON_ONCE(mmap_read_trylock(desc->mm));
+ VM_WARN_ON_ONCE(vma_desc_test(desc, VMA_PFNMAP_BIT));
+ vma_desc_set_flags(desc, VMA_MIXEDMAP_BIT);
+ }
+
+ nr_pages = action->map_kernel.nr_pages;
+ end = addr + PAGE_SIZE * nr_pages;
+ if (!range_in_vma_desc(desc, addr, end))
+ return -EFAULT;
+
+ return 0;
+}
+EXPORT_SYMBOL(map_kernel_pages_prepare);
+
+int map_kernel_pages_complete(struct vm_area_struct *vma,
+ struct mmap_action *action)
+{
+ unsigned long nr_pages;
+
+ nr_pages = action->map_kernel.nr_pages;
+ return insert_pages(vma, action->map_kernel.start,
+ action->map_kernel.pages,
+ &nr_pages, vma->vm_page_prot);
+}
+EXPORT_SYMBOL(map_kernel_pages_complete);
+
/**
* vm_insert_page - insert single page into user vma
* @vma: user vma to map to
diff --git a/mm/util.c b/mm/util.c
index 5ae20876ef2c..f063fd4de1e8 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -1448,6 +1448,8 @@ int mmap_action_prepare(struct vm_area_desc *desc)
return io_remap_pfn_range_prepare(desc);
case MMAP_SIMPLE_IO_REMAP:
return simple_ioremap_prepare(desc);
+ case MMAP_MAP_KERNEL_PAGES:
+ return map_kernel_pages_prepare(desc);
}
WARN_ON_ONCE(1);
@@ -1475,6 +1477,9 @@ int mmap_action_complete(struct vm_area_struct *vma,
case MMAP_REMAP_PFN:
err = remap_pfn_range_complete(vma, action);
break;
+ case MMAP_MAP_KERNEL_PAGES:
+ err = map_kernel_pages_complete(vma, action);
+ break;
case MMAP_IO_REMAP_PFN:
case MMAP_SIMPLE_IO_REMAP:
/* Should have been delegated. */
@@ -1495,6 +1500,7 @@ int mmap_action_prepare(struct vm_area_desc *desc)
case MMAP_REMAP_PFN:
case MMAP_IO_REMAP_PFN:
case MMAP_SIMPLE_IO_REMAP:
+ case MMAP_MAP_KERNEL_PAGES:
WARN_ON_ONCE(1); /* nommu cannot handle these. */
break;
}
@@ -1514,6 +1520,7 @@ int mmap_action_complete(struct vm_area_struct *vma,
case MMAP_REMAP_PFN:
case MMAP_IO_REMAP_PFN:
case MMAP_SIMPLE_IO_REMAP:
+ case MMAP_MAP_KERNEL_PAGES:
WARN_ON_ONCE(1); /* nommu cannot handle this. */
err = -EINVAL;
diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
index f5f7c45f1808..60f0b15638d0 100644
--- a/tools/testing/vma/include/dup.h
+++ b/tools/testing/vma/include/dup.h
@@ -454,6 +454,7 @@ enum mmap_action_type {
MMAP_REMAP_PFN, /* Remap PFN range. */
MMAP_IO_REMAP_PFN, /* I/O remap PFN range. */
MMAP_SIMPLE_IO_REMAP, /* I/O remap with guardrails. */
+ MMAP_MAP_KERNEL_PAGES, /* Map kernel page range from an array. */
};
/*
@@ -472,6 +473,12 @@ struct mmap_action {
phys_addr_t start_phys_addr;
unsigned long size;
} simple_ioremap;
+ struct {
+ unsigned long start;
+ struct page **pages;
+ unsigned long nr_pages;
+ pgoff_t pgoff;
+ } map_kernel;
};
enum mmap_action_type type;
--
2.53.0
^ permalink raw reply related
* [PATCH v4 19/21] uio: replace deprecated mmap hook with mmap_prepare in uio_info
From: Lorenzo Stoakes (Oracle) @ 2026-03-20 22:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jann Horn,
Pedro Falcato, linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <cover.1774045440.git.ljs@kernel.org>
The f_op->mmap interface is deprecated, so update uio_info to use its
successor, mmap_prepare.
Therefore, replace the uio_info->mmap hook with a new
uio_info->mmap_prepare hook, and update its one user, target_core_user,
to both specify this new mmap_prepare hook and also to use the new
vm_ops->mapped() hook to continue to maintain a correct udev->kref
refcount.
Then update uio_mmap() to utilise the mmap_prepare compatibility layer to
invoke this callback from the uio mmap invocation.
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
---
drivers/target/target_core_user.c | 26 ++++++++++++++++++--------
drivers/uio/uio.c | 10 ++++++++--
include/linux/uio_driver.h | 4 ++--
3 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index af95531ddd35..edc2afd5f4ee 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -1860,6 +1860,17 @@ static struct page *tcmu_try_get_data_page(struct tcmu_dev *udev, uint32_t dpi)
return NULL;
}
+static int tcmu_vma_mapped(unsigned long start, unsigned long end, pgoff_t pgoff,
+ const struct file *file, void **vm_private_data)
+{
+ struct tcmu_dev *udev = *vm_private_data;
+
+ pr_debug("vma_mapped\n");
+
+ kref_get(&udev->kref);
+ return 0;
+}
+
static void tcmu_vma_open(struct vm_area_struct *vma)
{
struct tcmu_dev *udev = vma->vm_private_data;
@@ -1919,26 +1930,25 @@ static vm_fault_t tcmu_vma_fault(struct vm_fault *vmf)
}
static const struct vm_operations_struct tcmu_vm_ops = {
+ .mapped = tcmu_vma_mapped,
.open = tcmu_vma_open,
.close = tcmu_vma_close,
.fault = tcmu_vma_fault,
};
-static int tcmu_mmap(struct uio_info *info, struct vm_area_struct *vma)
+static int tcmu_mmap_prepare(struct uio_info *info, struct vm_area_desc *desc)
{
struct tcmu_dev *udev = container_of(info, struct tcmu_dev, uio_info);
- vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
- vma->vm_ops = &tcmu_vm_ops;
+ vma_desc_set_flags(desc, VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT);
+ desc->vm_ops = &tcmu_vm_ops;
- vma->vm_private_data = udev;
+ desc->private_data = udev;
/* Ensure the mmap is exactly the right size */
- if (vma_pages(vma) != udev->mmap_pages)
+ if (vma_desc_pages(desc) != udev->mmap_pages)
return -EINVAL;
- tcmu_vma_open(vma);
-
return 0;
}
@@ -2253,7 +2263,7 @@ static int tcmu_configure_device(struct se_device *dev)
info->irqcontrol = tcmu_irqcontrol;
info->irq = UIO_IRQ_CUSTOM;
- info->mmap = tcmu_mmap;
+ info->mmap_prepare = tcmu_mmap_prepare;
info->open = tcmu_open;
info->release = tcmu_release;
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 5a4998e2caf8..1e4ade78ed84 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -850,8 +850,14 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
goto out;
}
- if (idev->info->mmap) {
- ret = idev->info->mmap(idev->info, vma);
+ if (idev->info->mmap_prepare) {
+ struct vm_area_desc desc;
+
+ compat_set_desc_from_vma(&desc, filep, vma);
+ ret = idev->info->mmap_prepare(idev->info, &desc);
+ if (ret)
+ goto out;
+ ret = __compat_vma_mmap(&desc, vma);
goto out;
}
diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h
index 334641e20fb1..02eaac47ac44 100644
--- a/include/linux/uio_driver.h
+++ b/include/linux/uio_driver.h
@@ -97,7 +97,7 @@ struct uio_device {
* @irq_flags: flags for request_irq()
* @priv: optional private data
* @handler: the device's irq handler
- * @mmap: mmap operation for this uio device
+ * @mmap_prepare: mmap_prepare operation for this uio device
* @open: open operation for this uio device
* @release: release operation for this uio device
* @irqcontrol: disable/enable irqs when 0/1 is written to /dev/uioX
@@ -112,7 +112,7 @@ struct uio_info {
unsigned long irq_flags;
void *priv;
irqreturn_t (*handler)(int irq, struct uio_info *dev_info);
- int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);
+ int (*mmap_prepare)(struct uio_info *info, struct vm_area_desc *desc);
int (*open)(struct uio_info *info, struct inode *inode);
int (*release)(struct uio_info *info, struct inode *inode);
int (*irqcontrol)(struct uio_info *info, s32 irq_on);
--
2.53.0
^ permalink raw reply related
* [PATCH v4 18/21] drivers: hv: vmbus: replace deprecated mmap hook with mmap_prepare
From: Lorenzo Stoakes (Oracle) @ 2026-03-20 22:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jann Horn,
Pedro Falcato, linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <cover.1774045440.git.ljs@kernel.org>
The f_op->mmap interface is deprecated, so update the vmbus driver to use
its successor, mmap_prepare.
This updates all callbacks which referenced the function pointer
hv_mmap_ring_buffer to instead reference hv_mmap_prepare_ring_buffer,
utilising the newly introduced compat_set_desc_from_vma() and
__compat_vma_mmap() to be able to implement this change.
The UIO HV generic driver is the only user of hv_create_ring_sysfs(),
which is the only function which references
vmbus_channel->mmap_prepare_ring_buffer which, in turn, is the only
external interface to hv_mmap_prepare_ring_buffer.
This patch therefore updates this caller to use mmap_prepare instead,
which also previously used vm_iomap_memory(), so this change replaces it
with its mmap_prepare equivalent, mmap_action_simple_ioremap().
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
---
drivers/hv/hyperv_vmbus.h | 4 ++--
drivers/hv/vmbus_drv.c | 31 +++++++++++++++++++------------
drivers/uio/uio_hv_generic.c | 11 ++++++-----
include/linux/hyperv.h | 4 ++--
4 files changed, 29 insertions(+), 21 deletions(-)
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 7bd8f8486e85..31f576464f18 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -545,8 +545,8 @@ static inline int hv_debug_add_dev_dir(struct hv_device *dev)
/* Create and remove sysfs entry for memory mapped ring buffers for a channel */
int hv_create_ring_sysfs(struct vmbus_channel *channel,
- int (*hv_mmap_ring_buffer)(struct vmbus_channel *channel,
- struct vm_area_struct *vma));
+ int (*hv_mmap_prepare_ring_buffer)(struct vmbus_channel *channel,
+ struct vm_area_desc *desc));
int hv_remove_ring_sysfs(struct vmbus_channel *channel);
#endif /* _HYPERV_VMBUS_H */
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index bc4fc1951ae1..45625487ba36 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -1951,12 +1951,19 @@ static int hv_mmap_ring_buffer_wrapper(struct file *filp, struct kobject *kobj,
struct vm_area_struct *vma)
{
struct vmbus_channel *channel = container_of(kobj, struct vmbus_channel, kobj);
+ struct vm_area_desc desc;
+ int err;
/*
- * hv_(create|remove)_ring_sysfs implementation ensures that mmap_ring_buffer
- * is not NULL.
+ * hv_(create|remove)_ring_sysfs implementation ensures that
+ * mmap_prepare_ring_buffer is not NULL.
*/
- return channel->mmap_ring_buffer(channel, vma);
+ compat_set_desc_from_vma(&desc, filp, vma);
+ err = channel->mmap_prepare_ring_buffer(channel, &desc);
+ if (err)
+ return err;
+
+ return __compat_vma_mmap(&desc, vma);
}
static struct bin_attribute chan_attr_ring_buffer = {
@@ -2048,13 +2055,13 @@ static const struct kobj_type vmbus_chan_ktype = {
/**
* hv_create_ring_sysfs() - create "ring" sysfs entry corresponding to ring buffers for a channel.
* @channel: Pointer to vmbus_channel structure
- * @hv_mmap_ring_buffer: function pointer for initializing the function to be called on mmap of
+ * @hv_mmap_prepare_ring_buffer: function pointer for initializing the function to be called on mmap
* channel's "ring" sysfs node, which is for the ring buffer of that channel.
* Function pointer is of below type:
- * int (*hv_mmap_ring_buffer)(struct vmbus_channel *channel,
- * struct vm_area_struct *vma))
- * This has a pointer to the channel and a pointer to vm_area_struct,
- * used for mmap, as arguments.
+ * int (*hv_mmap_prepare_ring_buffer)(struct vmbus_channel *channel,
+ * struct vm_area_desc *desc))
+ * This has a pointer to the channel and a pointer to vm_area_desc,
+ * used for mmap_prepare, as arguments.
*
* Sysfs node for ring buffer of a channel is created along with other fields, however its
* visibility is disabled by default. Sysfs creation needs to be controlled when the use-case
@@ -2071,12 +2078,12 @@ static const struct kobj_type vmbus_chan_ktype = {
* Returns 0 on success or error code on failure.
*/
int hv_create_ring_sysfs(struct vmbus_channel *channel,
- int (*hv_mmap_ring_buffer)(struct vmbus_channel *channel,
- struct vm_area_struct *vma))
+ int (*hv_mmap_prepare_ring_buffer)(struct vmbus_channel *channel,
+ struct vm_area_desc *desc))
{
struct kobject *kobj = &channel->kobj;
- channel->mmap_ring_buffer = hv_mmap_ring_buffer;
+ channel->mmap_prepare_ring_buffer = hv_mmap_prepare_ring_buffer;
channel->ring_sysfs_visible = true;
return sysfs_update_group(kobj, &vmbus_chan_group);
@@ -2098,7 +2105,7 @@ int hv_remove_ring_sysfs(struct vmbus_channel *channel)
channel->ring_sysfs_visible = false;
ret = sysfs_update_group(kobj, &vmbus_chan_group);
- channel->mmap_ring_buffer = NULL;
+ channel->mmap_prepare_ring_buffer = NULL;
return ret;
}
EXPORT_SYMBOL_GPL(hv_remove_ring_sysfs);
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
index 3f8e2e27697f..29ec2d15ada8 100644
--- a/drivers/uio/uio_hv_generic.c
+++ b/drivers/uio/uio_hv_generic.c
@@ -154,15 +154,16 @@ static void hv_uio_rescind(struct vmbus_channel *channel)
* The ring buffer is allocated as contiguous memory by vmbus_open
*/
static int
-hv_uio_ring_mmap(struct vmbus_channel *channel, struct vm_area_struct *vma)
+hv_uio_ring_mmap_prepare(struct vmbus_channel *channel, struct vm_area_desc *desc)
{
void *ring_buffer = page_address(channel->ringbuffer_page);
if (channel->state != CHANNEL_OPENED_STATE)
return -ENODEV;
- return vm_iomap_memory(vma, virt_to_phys(ring_buffer),
- channel->ringbuffer_pagecount << PAGE_SHIFT);
+ mmap_action_simple_ioremap(desc, virt_to_phys(ring_buffer),
+ channel->ringbuffer_pagecount << PAGE_SHIFT);
+ return 0;
}
/* Callback from VMBUS subsystem when new channel created. */
@@ -183,7 +184,7 @@ hv_uio_new_channel(struct vmbus_channel *new_sc)
}
set_channel_read_mode(new_sc, HV_CALL_ISR);
- ret = hv_create_ring_sysfs(new_sc, hv_uio_ring_mmap);
+ ret = hv_create_ring_sysfs(new_sc, hv_uio_ring_mmap_prepare);
if (ret) {
dev_err(device, "sysfs create ring bin file failed; %d\n", ret);
vmbus_close(new_sc);
@@ -366,7 +367,7 @@ hv_uio_probe(struct hv_device *dev,
* or decoupled from uio_hv_generic probe. Userspace programs can make use of inotify
* APIs to make sure that ring is created.
*/
- hv_create_ring_sysfs(channel, hv_uio_ring_mmap);
+ hv_create_ring_sysfs(channel, hv_uio_ring_mmap_prepare);
hv_set_drvdata(dev, pdata);
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index dfc516c1c719..3a721b1853a4 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1015,8 +1015,8 @@ struct vmbus_channel {
/* The max size of a packet on this channel */
u32 max_pkt_size;
- /* function to mmap ring buffer memory to the channel's sysfs ring attribute */
- int (*mmap_ring_buffer)(struct vmbus_channel *channel, struct vm_area_struct *vma);
+ /* function to mmap_prepare ring buffer memory to the channel's sysfs ring attribute */
+ int (*mmap_prepare_ring_buffer)(struct vmbus_channel *channel, struct vm_area_desc *desc);
/* boolean to control visibility of sysfs for ring buffer */
bool ring_sysfs_visible;
--
2.53.0
^ permalink raw reply related
* [PATCH v4 17/21] mm: allow handling of stacked mmap_prepare hooks in more drivers
From: Lorenzo Stoakes (Oracle) @ 2026-03-20 22:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jann Horn,
Pedro Falcato, linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <cover.1774045440.git.ljs@kernel.org>
While the conversion of mmap hooks to mmap_prepare is underway, we will
encounter situations where mmap hooks need to invoke nested mmap_prepare
hooks.
The nesting of mmap hooks is termed 'stacking'. In order to flexibly
facilitate the conversion of custom mmap hooks in drivers which stack, we
must split up the existing __compat_vma_mmap() function into two separate
functions:
* compat_set_desc_from_vma() - This allows the setting of a vm_area_desc
object's fields to the relevant fields of a VMA.
* __compat_vma_mmap() - Once an mmap_prepare hook has been executed upon a
vm_area_desc object, this function performs any mmap actions specified by
the mmap_prepare hook and then invokes its vm_ops->mapped() hook if any
were specified.
In ordinary cases, where a file's f_op->mmap_prepare() hook simply needs
to be invoked in a stacked mmap() hook, compat_vma_mmap() can be used.
However some drivers define their own nested hooks, which are invoked in
turn by another hook.
A concrete example is vmbus_channel->mmap_ring_buffer(), which is invoked
in turn by bin_attribute->mmap():
vmbus_channel->mmap_ring_buffer() has a signature of:
int (*mmap_ring_buffer)(struct vmbus_channel *channel,
struct vm_area_struct *vma);
And bin_attribute->mmap() has a signature of:
int (*mmap)(struct file *, struct kobject *,
const struct bin_attribute *attr,
struct vm_area_struct *vma);
And so compat_vma_mmap() cannot be used here for incremental conversion of
hooks from mmap() to mmap_prepare().
There are many such instances like this, where conversion to mmap_prepare
would otherwise cascade to a huge change set due to nesting of this kind.
The changes in this patch mean we could now instead convert
vmbus_channel->mmap_ring_buffer() to
vmbus_channel->mmap_prepare_ring_buffer(), and implement something like:
struct vm_area_desc desc;
int err;
compat_set_desc_from_vma(&desc, file, vma);
err = channel->mmap_prepare_ring_buffer(channel, &desc);
if (err)
return err;
return __compat_vma_mmap(&desc, vma);
Allowing us to incrementally update this logic, and other logic like it.
Unfortunately, as part of this change, we need to be able to flexibly
assign to the VMA descriptor, so have to remove some of the const
declarations within the structure.
Also update the VMA tests to reflect the changes.
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
---
include/linux/fs.h | 3 +
include/linux/mm_types.h | 4 +-
mm/util.c | 119 +++++++++++++++++++++++---------
mm/vma.h | 2 +-
tools/testing/vma/include/dup.h | 68 +++++++++++-------
5 files changed, 136 insertions(+), 60 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c390f5c667e3..0bdccfa70b44 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2058,6 +2058,9 @@ static inline bool can_mmap_file(struct file *file)
return true;
}
+void compat_set_desc_from_vma(struct vm_area_desc *desc, const struct file *file,
+ const struct vm_area_struct *vma);
+int __compat_vma_mmap(struct vm_area_desc *desc, struct vm_area_struct *vma);
int compat_vma_mmap(struct file *file, struct vm_area_struct *vma);
int __vma_check_mmap_hook(struct vm_area_struct *vma);
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 174286f9ecf0..d60eefde1db8 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -891,8 +891,8 @@ static __always_inline bool vma_flags_empty(const vma_flags_t *flags)
*/
struct vm_area_desc {
/* Immutable state. */
- const struct mm_struct *const mm;
- struct file *const file; /* May vary from vm_file in stacked callers. */
+ struct mm_struct *mm;
+ struct file *file; /* May vary from vm_file in stacked callers. */
unsigned long start;
unsigned long end;
diff --git a/mm/util.c b/mm/util.c
index a19f062b84dc..5ae20876ef2c 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -1163,38 +1163,78 @@ void flush_dcache_folio(struct folio *folio)
EXPORT_SYMBOL(flush_dcache_folio);
#endif
-static int __compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct vm_area_desc desc = {
- .mm = vma->vm_mm,
- .file = file,
- .start = vma->vm_start,
- .end = vma->vm_end,
-
- .pgoff = vma->vm_pgoff,
- .vm_file = vma->vm_file,
- .vma_flags = vma->flags,
- .page_prot = vma->vm_page_prot,
-
- .action.type = MMAP_NOTHING, /* Default */
- };
- struct mmap_action *action = &desc.action;
- int err;
+/**
+ * compat_set_desc_from_vma() - assigns VMA descriptor @desc fields from a VMA.
+ * @desc: A VMA descriptor whose fields need to be set.
+ * @file: The file object describing the file being mmap()'d.
+ * @vma: The VMA whose fields we wish to assign to @desc.
+ *
+ * This is a compatibility function to allow an mmap() hook to call
+ * mmap_prepare() hooks when drivers nest these. This function specifically
+ * allows the construction of a vm_area_desc value, @desc, from a VMA @vma for
+ * the purposes of doing this.
+ *
+ * Once the conversion of drivers is complete this function will no longer be
+ * required and will be removed.
+ */
+void compat_set_desc_from_vma(struct vm_area_desc *desc,
+ const struct file *file,
+ const struct vm_area_struct *vma)
+{
+ memset(desc, 0, sizeof(*desc));
- err = vfs_mmap_prepare(file, &desc);
- if (err)
- return err;
+ desc->mm = vma->vm_mm;
+ desc->file = (struct file *)file;
+ desc->start = vma->vm_start;
+ desc->end = vma->vm_end;
- err = mmap_action_prepare(&desc);
- if (err)
- return err;
+ desc->pgoff = vma->vm_pgoff;
+ desc->vm_file = vma->vm_file;
+ desc->vma_flags = vma->flags;
+ desc->page_prot = vma->vm_page_prot;
- /* being invoked from .mmmap means we don't have to enforce this. */
- action->hide_from_rmap_until_complete = false;
+ /* Default. */
+ desc->action.type = MMAP_NOTHING;
+}
+EXPORT_SYMBOL(compat_set_desc_from_vma);
+
+/**
+ * __compat_vma_mmap() - Similar to compat_vma_mmap(), only it allows
+ * flexibility as to how the mmap_prepare callback is invoked, which is useful
+ * for drivers which invoke nested mmap_prepare callbacks in an mmap() hook.
+ * @desc: A VMA descriptor upon which an mmap_prepare() hook has already been
+ * executed.
+ * @vma: The VMA to which @desc should be applied.
+ *
+ * The function assumes that you have obtained a VMA descriptor @desc from
+ * compat_set_desc_from_vma(), and already executed the mmap_prepare() hook upon
+ * it.
+ *
+ * It then performs any specified mmap actions, and invokes the vm_ops->mapped()
+ * hook if one is present.
+ *
+ * See the description of compat_vma_mmap() for more details.
+ *
+ * Once the conversion of drivers is complete this function will no longer be
+ * required and will be removed.
+ *
+ * Returns: 0 on success or error.
+ */
+int __compat_vma_mmap(struct vm_area_desc *desc,
+ struct vm_area_struct *vma)
+{
+ int err;
- set_vma_from_desc(vma, &desc);
- return mmap_action_complete(vma, action);
+ /* Perform any preparatory tasks for mmap action. */
+ err = mmap_action_prepare(desc);
+ if (err)
+ return err;
+ /* Update the VMA from the descriptor. */
+ compat_set_vma_from_desc(vma, desc);
+ /* Complete any specified mmap actions. */
+ return mmap_action_complete(vma, &desc->action);
}
+EXPORT_SYMBOL(__compat_vma_mmap);
/**
* compat_vma_mmap() - Apply the file's .mmap_prepare() hook to an
@@ -1203,10 +1243,10 @@ static int __compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
* @vma: The VMA to apply the .mmap_prepare() hook to.
*
* Ordinarily, .mmap_prepare() is invoked directly upon mmap(). However, certain
- * stacked filesystems invoke a nested mmap hook of an underlying file.
+ * stacked drivers invoke a nested mmap hook of an underlying file.
*
- * Until all filesystems are converted to use .mmap_prepare(), we must be
- * conservative and continue to invoke these stacked filesystems using the
+ * Until all drivers are converted to use .mmap_prepare(), we must be
+ * conservative and continue to invoke these stacked drivers using the
* deprecated .mmap() hook.
*
* However we have a problem if the underlying file system possesses an
@@ -1217,14 +1257,27 @@ static int __compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
* establishes a struct vm_area_desc descriptor, passes to the underlying
* .mmap_prepare() hook and applies any changes performed by it.
*
- * Once the conversion of filesystems is complete this function will no longer
- * be required and will be removed.
+ * Once the conversion of drivers is complete this function will no longer be
+ * required and will be removed.
*
* Returns: 0 on success or error.
*/
int compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
{
- return __compat_vma_mmap(file, vma);
+ struct vm_area_desc desc;
+ struct mmap_action *action;
+ int err;
+
+ compat_set_desc_from_vma(&desc, file, vma);
+ err = vfs_mmap_prepare(file, &desc);
+ if (err)
+ return err;
+ action = &desc.action;
+
+ /* being invoked from .mmmap means we don't have to enforce this. */
+ action->hide_from_rmap_until_complete = false;
+
+ return __compat_vma_mmap(&desc, vma);
}
EXPORT_SYMBOL(compat_vma_mmap);
diff --git a/mm/vma.h b/mm/vma.h
index adc18f7dd9f1..a76046c39b14 100644
--- a/mm/vma.h
+++ b/mm/vma.h
@@ -300,7 +300,7 @@ static inline int vma_iter_store_gfp(struct vma_iterator *vmi,
* f_op->mmap() but which might have an underlying file system which implements
* f_op->mmap_prepare().
*/
-static inline void set_vma_from_desc(struct vm_area_struct *vma,
+static inline void compat_set_vma_from_desc(struct vm_area_struct *vma,
struct vm_area_desc *desc)
{
/*
diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
index a0c2379bd42b..f5f7c45f1808 100644
--- a/tools/testing/vma/include/dup.h
+++ b/tools/testing/vma/include/dup.h
@@ -519,8 +519,8 @@ enum vma_operation {
*/
struct vm_area_desc {
/* Immutable state. */
- const struct mm_struct *const mm;
- struct file *const file; /* May vary from vm_file in stacked callers. */
+ struct mm_struct *mm;
+ struct file *file; /* May vary from vm_file in stacked callers. */
unsigned long start;
unsigned long end;
@@ -1274,50 +1274,70 @@ static inline void vma_set_anonymous(struct vm_area_struct *vma)
}
/* Declared in vma.h. */
-static inline void set_vma_from_desc(struct vm_area_struct *vma,
+static inline void compat_set_vma_from_desc(struct vm_area_struct *vma,
struct vm_area_desc *desc);
-static inline int vfs_mmap_prepare(struct file *file, struct vm_area_desc *desc)
+static inline void compat_set_desc_from_vma(struct vm_area_desc *desc,
+ const struct file *file,
+ const struct vm_area_struct *vma)
{
- return file->f_op->mmap_prepare(desc);
+ memset(desc, 0, sizeof(*desc));
+
+ desc->mm = vma->vm_mm;
+ desc->file = (struct file *)file;
+ desc->start = vma->vm_start;
+ desc->end = vma->vm_end;
+
+ desc->pgoff = vma->vm_pgoff;
+ desc->vm_file = vma->vm_file;
+ desc->vma_flags = vma->flags;
+ desc->page_prot = vma->vm_page_prot;
+
+ /* Default. */
+ desc->action.type = MMAP_NOTHING;
}
-static inline unsigned long vma_pages(struct vm_area_struct *vma)
+static inline unsigned long vma_pages(const struct vm_area_struct *vma)
{
return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
}
-static inline int compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
+static inline int vfs_mmap_prepare(struct file *file, struct vm_area_desc *desc)
{
- struct vm_area_desc desc = {
- .mm = vma->vm_mm,
- .file = file,
- .start = vma->vm_start,
- .end = vma->vm_end,
-
- .pgoff = vma->vm_pgoff,
- .vm_file = vma->vm_file,
- .vma_flags = vma->flags,
- .page_prot = vma->vm_page_prot,
+ return file->f_op->mmap_prepare(desc);
+}
- .action.type = MMAP_NOTHING, /* Default */
- };
- struct mmap_action *action = &desc.action;
+static inline int __compat_vma_mmap(struct vm_area_desc *desc,
+ struct vm_area_struct *vma)
+{
int err;
- err = vfs_mmap_prepare(file, &desc);
+ /* Perform any preparatory tasks for mmap action. */
+ err = mmap_action_prepare(desc);
if (err)
return err;
+ /* Update the VMA from the descriptor. */
+ compat_set_vma_from_desc(vma, desc);
+ /* Complete any specified mmap actions. */
+ return mmap_action_complete(vma, &desc->action);
+}
- err = mmap_action_prepare(&desc);
+static inline int compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct vm_area_desc desc;
+ struct mmap_action *action;
+ int err;
+
+ compat_set_desc_from_vma(&desc, file, vma);
+ err = vfs_mmap_prepare(file, &desc);
if (err)
return err;
+ action = &desc.action;
/* being invoked from .mmmap means we don't have to enforce this. */
action->hide_from_rmap_until_complete = false;
- set_vma_from_desc(vma, &desc);
- return mmap_action_complete(vma, action);
+ return __compat_vma_mmap(&desc, vma);
}
static inline void vma_iter_init(struct vma_iterator *vmi,
--
2.53.0
^ permalink raw reply related
* [PATCH v4 16/21] staging: vme_user: replace deprecated mmap hook with mmap_prepare
From: Lorenzo Stoakes (Oracle) @ 2026-03-20 22:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jann Horn,
Pedro Falcato, linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <cover.1774045440.git.ljs@kernel.org>
The f_op->mmap interface is deprecated, so update driver to use its
successor, mmap_prepare.
The driver previously used vm_iomap_memory(), so this change replaces it
with its mmap_prepare equivalent, mmap_action_simple_ioremap().
Functions that wrap mmap() are also converted to wrap mmap_prepare()
instead.
Also update the documentation accordingly.
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
---
Documentation/driver-api/vme.rst | 2 +-
drivers/staging/vme_user/vme.c | 20 +++++------
drivers/staging/vme_user/vme.h | 2 +-
drivers/staging/vme_user/vme_user.c | 51 +++++++++++++++++------------
4 files changed, 42 insertions(+), 33 deletions(-)
diff --git a/Documentation/driver-api/vme.rst b/Documentation/driver-api/vme.rst
index c0b475369de0..7111999abc14 100644
--- a/Documentation/driver-api/vme.rst
+++ b/Documentation/driver-api/vme.rst
@@ -107,7 +107,7 @@ The function :c:func:`vme_master_read` can be used to read from and
In addition to simple reads and writes, :c:func:`vme_master_rmw` is provided to
do a read-modify-write transaction. Parts of a VME window can also be mapped
-into user space memory using :c:func:`vme_master_mmap`.
+into user space memory using :c:func:`vme_master_mmap_prepare`.
Slave windows
diff --git a/drivers/staging/vme_user/vme.c b/drivers/staging/vme_user/vme.c
index f10a00c05f12..7220aba7b919 100644
--- a/drivers/staging/vme_user/vme.c
+++ b/drivers/staging/vme_user/vme.c
@@ -735,9 +735,9 @@ unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask,
EXPORT_SYMBOL(vme_master_rmw);
/**
- * vme_master_mmap - Mmap region of VME master window.
+ * vme_master_mmap_prepare - Mmap region of VME master window.
* @resource: Pointer to VME master resource.
- * @vma: Pointer to definition of user mapping.
+ * @desc: Pointer to descriptor of user mapping.
*
* Memory map a region of the VME master window into user space.
*
@@ -745,12 +745,13 @@ EXPORT_SYMBOL(vme_master_rmw);
* resource or -EFAULT if map exceeds window size. Other generic mmap
* errors may also be returned.
*/
-int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma)
+int vme_master_mmap_prepare(struct vme_resource *resource,
+ struct vm_area_desc *desc)
{
+ const unsigned long vma_size = vma_desc_size(desc);
struct vme_bridge *bridge = find_bridge(resource);
struct vme_master_resource *image;
phys_addr_t phys_addr;
- unsigned long vma_size;
if (resource->type != VME_MASTER) {
dev_err(bridge->parent, "Not a master resource\n");
@@ -758,19 +759,18 @@ int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma)
}
image = list_entry(resource->entry, struct vme_master_resource, list);
- phys_addr = image->bus_resource.start + (vma->vm_pgoff << PAGE_SHIFT);
- vma_size = vma->vm_end - vma->vm_start;
+ phys_addr = image->bus_resource.start + (desc->pgoff << PAGE_SHIFT);
if (phys_addr + vma_size > image->bus_resource.end + 1) {
dev_err(bridge->parent, "Map size cannot exceed the window size\n");
return -EFAULT;
}
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- return vm_iomap_memory(vma, phys_addr, vma->vm_end - vma->vm_start);
+ desc->page_prot = pgprot_noncached(desc->page_prot);
+ mmap_action_simple_ioremap(desc, phys_addr, vma_size);
+ return 0;
}
-EXPORT_SYMBOL(vme_master_mmap);
+EXPORT_SYMBOL(vme_master_mmap_prepare);
/**
* vme_master_free - Free VME master window
diff --git a/drivers/staging/vme_user/vme.h b/drivers/staging/vme_user/vme.h
index 797e9940fdd1..b6413605ea49 100644
--- a/drivers/staging/vme_user/vme.h
+++ b/drivers/staging/vme_user/vme.h
@@ -151,7 +151,7 @@ ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count,
ssize_t vme_master_write(struct vme_resource *resource, void *buf, size_t count, loff_t offset);
unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, unsigned int compare,
unsigned int swap, loff_t offset);
-int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma);
+int vme_master_mmap_prepare(struct vme_resource *resource, struct vm_area_desc *desc);
void vme_master_free(struct vme_resource *resource);
struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route);
diff --git a/drivers/staging/vme_user/vme_user.c b/drivers/staging/vme_user/vme_user.c
index d95dd7d9190a..11e25c2f6b0a 100644
--- a/drivers/staging/vme_user/vme_user.c
+++ b/drivers/staging/vme_user/vme_user.c
@@ -446,24 +446,14 @@ static void vme_user_vm_close(struct vm_area_struct *vma)
kfree(vma_priv);
}
-static const struct vm_operations_struct vme_user_vm_ops = {
- .open = vme_user_vm_open,
- .close = vme_user_vm_close,
-};
-
-static int vme_user_master_mmap(unsigned int minor, struct vm_area_struct *vma)
+static int vme_user_vm_mapped(unsigned long start, unsigned long end, pgoff_t pgoff,
+ const struct file *file, void **vm_private_data)
{
- int err;
+ const unsigned int minor = iminor(file_inode(file));
struct vme_user_vma_priv *vma_priv;
mutex_lock(&image[minor].mutex);
- err = vme_master_mmap(image[minor].resource, vma);
- if (err) {
- mutex_unlock(&image[minor].mutex);
- return err;
- }
-
vma_priv = kmalloc_obj(*vma_priv);
if (!vma_priv) {
mutex_unlock(&image[minor].mutex);
@@ -472,22 +462,41 @@ static int vme_user_master_mmap(unsigned int minor, struct vm_area_struct *vma)
vma_priv->minor = minor;
refcount_set(&vma_priv->refcnt, 1);
- vma->vm_ops = &vme_user_vm_ops;
- vma->vm_private_data = vma_priv;
-
+ *vm_private_data = vma_priv;
image[minor].mmap_count++;
mutex_unlock(&image[minor].mutex);
-
return 0;
}
-static int vme_user_mmap(struct file *file, struct vm_area_struct *vma)
+static const struct vm_operations_struct vme_user_vm_ops = {
+ .mapped = vme_user_vm_mapped,
+ .open = vme_user_vm_open,
+ .close = vme_user_vm_close,
+};
+
+static int vme_user_master_mmap_prepare(unsigned int minor,
+ struct vm_area_desc *desc)
+{
+ int err;
+
+ mutex_lock(&image[minor].mutex);
+
+ err = vme_master_mmap_prepare(image[minor].resource, desc);
+ if (!err)
+ desc->vm_ops = &vme_user_vm_ops;
+
+ mutex_unlock(&image[minor].mutex);
+ return err;
+}
+
+static int vme_user_mmap_prepare(struct vm_area_desc *desc)
{
- unsigned int minor = iminor(file_inode(file));
+ const struct file *file = desc->file;
+ const unsigned int minor = iminor(file_inode(file));
if (type[minor] == MASTER_MINOR)
- return vme_user_master_mmap(minor, vma);
+ return vme_user_master_mmap_prepare(minor, desc);
return -ENODEV;
}
@@ -498,7 +507,7 @@ static const struct file_operations vme_user_fops = {
.llseek = vme_user_llseek,
.unlocked_ioctl = vme_user_unlocked_ioctl,
.compat_ioctl = compat_ptr_ioctl,
- .mmap = vme_user_mmap,
+ .mmap_prepare = vme_user_mmap_prepare,
};
static int vme_user_match(struct vme_dev *vdev)
--
2.53.0
^ permalink raw reply related
* [PATCH v4 15/21] stm: replace deprecated mmap hook with mmap_prepare
From: Lorenzo Stoakes (Oracle) @ 2026-03-20 22:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jann Horn,
Pedro Falcato, linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <cover.1774045440.git.ljs@kernel.org>
The f_op->mmap interface is deprecated, so update driver to use its
successor, mmap_prepare.
The driver previously used vm_iomap_memory(), so this change replaces it
with its mmap_prepare equivalent, mmap_action_simple_ioremap().
Also, in order to correctly maintain reference counting, add a
vm_ops->mapped callback to increment the reference count when successfully
mapped.
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
---
drivers/hwtracing/stm/core.c | 31 +++++++++++++++++++++----------
1 file changed, 21 insertions(+), 10 deletions(-)
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index 37584e786bb5..f48c6a8a0654 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -666,6 +666,16 @@ static ssize_t stm_char_write(struct file *file, const char __user *buf,
return count;
}
+static int stm_mmap_mapped(unsigned long start, unsigned long end, pgoff_t pgoff,
+ const struct file *file, void **vm_private_data)
+{
+ struct stm_file *stmf = file->private_data;
+ struct stm_device *stm = stmf->stm;
+
+ pm_runtime_get_sync(&stm->dev);
+ return 0;
+}
+
static void stm_mmap_open(struct vm_area_struct *vma)
{
struct stm_file *stmf = vma->vm_file->private_data;
@@ -684,12 +694,14 @@ static void stm_mmap_close(struct vm_area_struct *vma)
}
static const struct vm_operations_struct stm_mmap_vmops = {
+ .mapped = stm_mmap_mapped,
.open = stm_mmap_open,
.close = stm_mmap_close,
};
-static int stm_char_mmap(struct file *file, struct vm_area_struct *vma)
+static int stm_char_mmap_prepare(struct vm_area_desc *desc)
{
+ struct file *file = desc->file;
struct stm_file *stmf = file->private_data;
struct stm_device *stm = stmf->stm;
unsigned long size, phys;
@@ -697,10 +709,10 @@ static int stm_char_mmap(struct file *file, struct vm_area_struct *vma)
if (!stm->data->mmio_addr)
return -EOPNOTSUPP;
- if (vma->vm_pgoff)
+ if (desc->pgoff)
return -EINVAL;
- size = vma->vm_end - vma->vm_start;
+ size = vma_desc_size(desc);
if (stmf->output.nr_chans * stm->data->sw_mmiosz != size)
return -EINVAL;
@@ -712,13 +724,12 @@ static int stm_char_mmap(struct file *file, struct vm_area_struct *vma)
if (!phys)
return -EINVAL;
- pm_runtime_get_sync(&stm->dev);
-
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
- vma->vm_ops = &stm_mmap_vmops;
- vm_iomap_memory(vma, phys, size);
+ desc->page_prot = pgprot_noncached(desc->page_prot);
+ vma_desc_set_flags(desc, VMA_IO_BIT, VMA_DONTEXPAND_BIT,
+ VMA_DONTDUMP_BIT);
+ desc->vm_ops = &stm_mmap_vmops;
+ mmap_action_simple_ioremap(desc, phys, size);
return 0;
}
@@ -836,7 +847,7 @@ static const struct file_operations stm_fops = {
.open = stm_char_open,
.release = stm_char_release,
.write = stm_char_write,
- .mmap = stm_char_mmap,
+ .mmap_prepare = stm_char_mmap_prepare,
.unlocked_ioctl = stm_char_ioctl,
.compat_ioctl = compat_ptr_ioctl,
};
--
2.53.0
^ permalink raw reply related
* [PATCH v4 14/21] mtdchar: replace deprecated mmap hook with mmap_prepare, clean up
From: Lorenzo Stoakes (Oracle) @ 2026-03-20 22:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jann Horn,
Pedro Falcato, linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <cover.1774045440.git.ljs@kernel.org>
Replace the deprecated mmap callback with mmap_prepare.
Commit f5cf8f07423b ("mtd: Disable mtdchar mmap on MMU systems") commented
out the CONFIG_MMU part of this function back in 2012, so after ~14 years
it's probably reasonable to remove this altogether rather than updating
dead code.
Acked-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
---
drivers/mtd/mtdchar.c | 21 +++------------------
1 file changed, 3 insertions(+), 18 deletions(-)
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 55a43682c567..bf01e6ac7293 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1376,27 +1376,12 @@ static unsigned mtdchar_mmap_capabilities(struct file *file)
/*
* set up a mapping for shared memory segments
*/
-static int mtdchar_mmap(struct file *file, struct vm_area_struct *vma)
+static int mtdchar_mmap_prepare(struct vm_area_desc *desc)
{
#ifdef CONFIG_MMU
- struct mtd_file_info *mfi = file->private_data;
- struct mtd_info *mtd = mfi->mtd;
- struct map_info *map = mtd->priv;
-
- /* This is broken because it assumes the MTD device is map-based
- and that mtd->priv is a valid struct map_info. It should be
- replaced with something that uses the mtd_get_unmapped_area()
- operation properly. */
- if (0 /*mtd->type == MTD_RAM || mtd->type == MTD_ROM*/) {
-#ifdef pgprot_noncached
- if (file->f_flags & O_DSYNC || map->phys >= __pa(high_memory))
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-#endif
- return vm_iomap_memory(vma, map->phys, map->size);
- }
return -ENODEV;
#else
- return vma->vm_flags & VM_SHARED ? 0 : -EACCES;
+ return vma_desc_test(desc, VMA_SHARED_BIT) ? 0 : -EACCES;
#endif
}
@@ -1411,7 +1396,7 @@ static const struct file_operations mtd_fops = {
#endif
.open = mtdchar_open,
.release = mtdchar_close,
- .mmap = mtdchar_mmap,
+ .mmap_prepare = mtdchar_mmap_prepare,
#ifndef CONFIG_MMU
.get_unmapped_area = mtdchar_get_unmapped_area,
.mmap_capabilities = mtdchar_mmap_capabilities,
--
2.53.0
^ permalink raw reply related
* [PATCH v4 13/21] hpet: replace deprecated mmap hook with mmap_prepare
From: Lorenzo Stoakes (Oracle) @ 2026-03-20 22:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jann Horn,
Pedro Falcato, linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <cover.1774045440.git.ljs@kernel.org>
The f_op->mmap interface is deprecated, so update driver to use its
successor, mmap_prepare.
The driver previously used vm_iomap_memory(), so this change replaces it
with its mmap_prepare equivalent, mmap_action_simple_ioremap().
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
---
drivers/char/hpet.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 60dd09a56f50..8f128cc40147 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -354,8 +354,9 @@ static __init int hpet_mmap_enable(char *str)
}
__setup("hpet_mmap=", hpet_mmap_enable);
-static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
+static int hpet_mmap_prepare(struct vm_area_desc *desc)
{
+ struct file *file = desc->file;
struct hpet_dev *devp;
unsigned long addr;
@@ -368,11 +369,12 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
if (addr & (PAGE_SIZE - 1))
return -ENOSYS;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- return vm_iomap_memory(vma, addr, PAGE_SIZE);
+ desc->page_prot = pgprot_noncached(desc->page_prot);
+ mmap_action_simple_ioremap(desc, addr, PAGE_SIZE);
+ return 0;
}
#else
-static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
+static int hpet_mmap_prepare(struct vm_area_desc *desc)
{
return -ENOSYS;
}
@@ -710,7 +712,7 @@ static const struct file_operations hpet_fops = {
.open = hpet_open,
.release = hpet_release,
.fasync = hpet_fasync,
- .mmap = hpet_mmap,
+ .mmap_prepare = hpet_mmap_prepare,
};
static int hpet_is_known(struct hpet_data *hdp)
--
2.53.0
^ permalink raw reply related
* [PATCH v4 12/21] misc: open-dice: replace deprecated mmap hook with mmap_prepare
From: Lorenzo Stoakes (Oracle) @ 2026-03-20 22:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
Jan Kara, David Hildenbrand, Liam R . Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jann Horn,
Pedro Falcato, linux-kernel, linux-doc, linux-hyperv, linux-stm32,
linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <cover.1774045440.git.ljs@kernel.org>
The f_op->mmap interface is deprecated, so update driver to use its
successor, mmap_prepare.
The driver previously used vm_iomap_memory(), so this change replaces it
with its mmap_prepare equivalent, mmap_action_simple_ioremap().
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
---
drivers/misc/open-dice.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/drivers/misc/open-dice.c b/drivers/misc/open-dice.c
index 24c29e0f00ef..45060fb4ea27 100644
--- a/drivers/misc/open-dice.c
+++ b/drivers/misc/open-dice.c
@@ -86,29 +86,32 @@ static ssize_t open_dice_write(struct file *filp, const char __user *ptr,
/*
* Creates a mapping of the reserved memory region in user address space.
*/
-static int open_dice_mmap(struct file *filp, struct vm_area_struct *vma)
+static int open_dice_mmap_prepare(struct vm_area_desc *desc)
{
+ struct file *filp = desc->file;
struct open_dice_drvdata *drvdata = to_open_dice_drvdata(filp);
- if (vma->vm_flags & VM_MAYSHARE) {
+ if (vma_desc_test(desc, VMA_MAYSHARE_BIT)) {
/* Do not allow userspace to modify the underlying data. */
- if (vma->vm_flags & VM_WRITE)
+ if (vma_desc_test(desc, VMA_WRITE_BIT))
return -EPERM;
/* Ensure userspace cannot acquire VM_WRITE later. */
- vm_flags_clear(vma, VM_MAYWRITE);
+ vma_desc_clear_flags(desc, VMA_MAYWRITE_BIT);
}
/* Create write-combine mapping so all clients observe a wipe. */
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- vm_flags_set(vma, VM_DONTCOPY | VM_DONTDUMP);
- return vm_iomap_memory(vma, drvdata->rmem->base, drvdata->rmem->size);
+ desc->page_prot = pgprot_writecombine(desc->page_prot);
+ vma_desc_set_flags(desc, VMA_DONTCOPY_BIT, VMA_DONTDUMP_BIT);
+ mmap_action_simple_ioremap(desc, drvdata->rmem->base,
+ drvdata->rmem->size);
+ return 0;
}
static const struct file_operations open_dice_fops = {
.owner = THIS_MODULE,
.read = open_dice_read,
.write = open_dice_write,
- .mmap = open_dice_mmap,
+ .mmap_prepare = open_dice_mmap_prepare,
};
static int __init open_dice_probe(struct platform_device *pdev)
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox