* [PATCH v2 1/3] mm: Add unmap_mapping_file() helper
2026-07-25 21:05 [PATCH v2 0/3] mm,kernfs,proc: Unmap mmaps of removed files via file->f_mapping Krzysztof Wilczyński
@ 2026-07-25 21:05 ` Krzysztof Wilczyński
2026-07-25 21:35 ` sashiko-bot
2026-07-25 21:05 ` [PATCH v2 2/3] kernfs: Unmap mmaps of removed files via file->f_mapping Krzysztof Wilczyński
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Krzysztof Wilczyński @ 2026-07-25 21:05 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Greg Kroah-Hartman, Tejun Heo,
Bjorn Helgaas
Cc: Bjorn Helgaas, Manivannan Sadhasivam, Lorenzo Pieralisi,
Liam R . Howlett, Baoquan He, Pratyush Yadav, Pasha Tatashin,
Jaroslav Kysela, Takashi Iwai, Lorenzo Stoakes, Michal Hocko,
Mike Rapoport, Simona Vetter, Suren Baghdasaryan, Vlastimil Babka,
Dave Young, linux-mm, linux-pci, linux-sound, kexec, driver-core
Currently, unmap_mapping_pages() and unmap_mapping_range() unmap a
page offset window of an address_space, and code that removes a file,
such as kernfs_drain_open_files(), relies on them to unmap the pages
of a file that is going away.
Files with f_mapping swapped to a shared address space at open time,
such as PCI resource files using iomem_get_mapping(), have their VMAs
attached to the shared mapping instead of the file's own inode mapping,
so unmapping the inode's address space cannot reach them, and they stay
live after the file is removed. These VMAs can only be selected by the
struct file they were created through, which is recorded in
vma->vm_file.
Thus, add unmap_mapping_file(), which walks the VMA interval tree of the
file's f_mapping under i_mmap_lock_read() and unmaps the pages of the
VMAs selected by should_zap_file_vma(), using the same per-VMA zap as
unmap_mapping_pages(). When f_mapping is the file's own inode mapping,
every VMA is zapped, as unmap_mapping_range() does today. When f_mapping
was swapped, only the VMAs with vm_file set to that file are zapped, so
callers do not need to tell the two apart.
HugeTLB VMAs are skipped with a WARN_ON_ONCE(), as zapping those takes
i_mmap_rwsem for write in hugetlb_zap_begin() and would deadlock against
the read lock held over the walk.
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
---
include/linux/mm.h | 2 ++
mm/memory.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 485df9c2dbdd..e882a03eaddd 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3183,6 +3183,7 @@ extern int fixup_user_fault(struct mm_struct *mm,
bool *unlocked);
void unmap_mapping_pages(struct address_space *mapping,
pgoff_t start, pgoff_t nr, bool even_cows);
+void unmap_mapping_file(struct file *file);
void unmap_mapping_range(struct address_space *mapping,
loff_t const holebegin, loff_t const holelen, int even_cows);
#else
@@ -3203,6 +3204,7 @@ static inline int fixup_user_fault(struct mm_struct *mm, unsigned long address,
}
static inline void unmap_mapping_pages(struct address_space *mapping,
pgoff_t start, pgoff_t nr, bool even_cows) { }
+static inline void unmap_mapping_file(struct file *file) { }
static inline void unmap_mapping_range(struct address_space *mapping,
loff_t const holebegin, loff_t const holelen, int even_cows) { }
#endif
diff --git a/mm/memory.c b/mm/memory.c
index ff338c2abe92..4a09d7b6aa6b 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4423,6 +4423,54 @@ void unmap_mapping_pages(struct address_space *mapping, pgoff_t start,
}
EXPORT_SYMBOL_GPL(unmap_mapping_pages);
+static inline bool should_zap_file_vma(struct file *file,
+ struct vm_area_struct *vma)
+{
+ /* On the file's own inode mapping, zap every VMA */
+ if (file->f_mapping == file_inode(file)->i_mapping)
+ return true;
+
+ /* A swapped mapping also holds VMAs of unrelated files, zap only ours */
+ return vma->vm_file == file;
+}
+
+/**
+ * unmap_mapping_file() - Unmap folios from all mmaps of a file.
+ * @file: The file to unmap.
+ *
+ * Unmap the folios of @file from every process that has them mapped.
+ *
+ * If f_mapping is the file's own inode mapping, they are unmapped
+ * from every VMA on that mapping, as unmap_mapping_range() would do.
+ *
+ * However, if f_mapping was swapped to a different address space at
+ * open time, only the VMAs with vm_file set to @file are considered,
+ * since that address space also holds mappings of unrelated files.
+ *
+ * Must not be used on HugeTLB files. HugeTLB VMAs are skipped with
+ * a warning.
+ */
+void unmap_mapping_file(struct file *file)
+{
+ struct address_space *mapping = file->f_mapping;
+ struct vm_area_struct *vma;
+
+ i_mmap_lock_read(mapping);
+ if (unlikely(mapping_mapped(mapping))) {
+ vma_interval_tree_foreach(vma, &mapping->i_mmap, 0, ULONG_MAX) {
+ cond_resched();
+
+ if (!should_zap_file_vma(file, vma))
+ continue;
+ /* Zapping HugeTLB VMAs needs i_mmap_rwsem held for write */
+ if (WARN_ON_ONCE(is_vm_hugetlb_page(vma)))
+ continue;
+ zap_vma(vma);
+ }
+ }
+ i_mmap_unlock_read(mapping);
+}
+
/**
* unmap_mapping_range - unmap the portion of all mmaps in the specified
* address_space corresponding to the specified byte range in the underlying
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v2 1/3] mm: Add unmap_mapping_file() helper
2026-07-25 21:05 ` [PATCH v2 1/3] mm: Add unmap_mapping_file() helper Krzysztof Wilczyński
@ 2026-07-25 21:35 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-07-25 21:35 UTC (permalink / raw)
To: Krzysztof Wilczyński; +Cc: linux-pci
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] unmap_mapping_file() will inadvertently zap VMAs of all anonymous files system-wide if called on a file utilizing the singleton anonymous inode.
- [Low] The macro `vma_interval_tree_foreach` is not defined anywhere in the kernel, causing a fatal compilation error.
--
--- Patch [1]: [PATCH v2 1/3] mm: Add unmap_mapping_file() helper ---
commit 4d2549a11df2bbda156f67d12490793734715126
Author: Krzysztof Wilczyński <kwilczynski@kernel.org>
Subject: mm: Add unmap_mapping_file() helper
This commit introduces the unmap_mapping_file() helper to unmap the folios
of a specific file from all processes that have mapped them. It is designed
to handle both standard inode mappings and swapped mappings by checking the
vm_file pointer when iterating the VMA interval tree.
[ ... ]
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -4555,6 +4555,54 @@ void unmap_mapping_pages(struct address_space *mapping, pgoff_t start,
> }
> EXPORT_SYMBOL_GPL(unmap_mapping_pages);
>
> +static inline bool should_zap_file_vma(struct file *file,
> + struct vm_area_struct *vma)
> +{
> + /* On the file's own inode mapping, zap every VMA */
> + if (file->f_mapping == file_inode(file)->i_mapping)
> + return true;
[Severity: High]
Could this inadvertently zap VMAs of all anonymous files system-wide if called
on a file utilizing the singleton anonymous inode? For any anonymous file
(such as perf_event or bpf-map), file->f_mapping and
file_inode(file)->i_mapping both point to the singleton
anon_inode_inode->i_mapping. Consequently, should_zap_file_vma() would
unconditionally return true, causing unmap_mapping_file() to zap every VMA
in the global anon_inode_inode->i_mapping interval tree.
> +
> + /* A swapped mapping also holds VMAs of unrelated files, zap only ours */
> + return vma->vm_file == file;
> +}
> +
> +/**
> + * unmap_mapping_file() - Unmap folios from all mmaps of a file.
> + * @file: The file to unmap.
> + *
> + * Unmap the folios of @file from every process that has them mapped.
> + *
> + * If f_mapping is the file's own inode mapping, they are unmapped
> + * from every VMA on that mapping, as unmap_mapping_range() would do.
> + *
> + * However, if f_mapping was swapped to a different address space at
> + * open time, only the VMAs with vm_file set to @file are considered,
> + * since that address space also holds mappings of unrelated files.
> + *
> + * Must not be used on HugeTLB files. HugeTLB VMAs are skipped with
> + * a warning.
> + */
> +void unmap_mapping_file(struct file *file)
> +{
> + struct address_space *mapping = file->f_mapping;
> + struct vm_area_struct *vma;
> +
> + i_mmap_lock_read(mapping);
> + if (unlikely(mapping_mapped(mapping))) {
> + vma_interval_tree_foreach(vma, &mapping->i_mmap, 0, ULONG_MAX) {
[Severity: Low]
Is this macro invocation correct? The vma_interval_tree_foreach macro
does not appear to be defined anywhere in the kernel, which would cause a
fatal compilation error in mm/memory.c. The file-backed VMA interval tree
iterators are typically exposed via the mapping_rmap_tree_foreach macro
instead.
> + cond_resched();
> +
> + if (!should_zap_file_vma(file, vma))
> + continue;
> + /* Zapping HugeTLB VMAs needs i_mmap_rwsem held for write */
> + if (WARN_ON_ONCE(is_vm_hugetlb_page(vma)))
> + continue;
> + zap_vma(vma);
> + }
> + }
> + i_mmap_unlock_read(mapping);
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260725210549.3716546-1-kwilczynski@kernel.org?part=1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/3] kernfs: Unmap mmaps of removed files via file->f_mapping
2026-07-25 21:05 [PATCH v2 0/3] mm,kernfs,proc: Unmap mmaps of removed files via file->f_mapping Krzysztof Wilczyński
2026-07-25 21:05 ` [PATCH v2 1/3] mm: Add unmap_mapping_file() helper Krzysztof Wilczyński
@ 2026-07-25 21:05 ` Krzysztof Wilczyński
2026-07-25 21:22 ` sashiko-bot
2026-07-25 21:05 ` [PATCH v2 3/3] proc: " Krzysztof Wilczyński
2026-07-25 21:37 ` [PATCH v2 0/3] mm,kernfs,proc: " Andrew Morton
3 siblings, 1 reply; 9+ messages in thread
From: Krzysztof Wilczyński @ 2026-07-25 21:05 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Greg Kroah-Hartman, Tejun Heo,
Bjorn Helgaas
Cc: Bjorn Helgaas, Manivannan Sadhasivam, Lorenzo Pieralisi,
Liam R . Howlett, Baoquan He, Pratyush Yadav, Pasha Tatashin,
Jaroslav Kysela, Takashi Iwai, Lorenzo Stoakes, Michal Hocko,
Mike Rapoport, Simona Vetter, Suren Baghdasaryan, Vlastimil Babka,
Dave Young, linux-mm, linux-pci, linux-sound, kexec, driver-core
Currently, kernfs_drain_open_files() unmaps the mapping of the sysfs
inode, file_inode(of->file)->i_mapping, when a node with mmapped open
files is removed. Since commit 636b21b50152 ("PCI: Revoke mappings
like devmem"), PCI resource and legacy sysfs files swap their
f_mapping to iomem_get_mapping() at open time, so their VMAs are
attached to the shared iomem address space, which the drain never
unmaps.
As a result, userspace mappings of PCI BARs survive device removal
and BAR resize, keeping stale PTEs into physical address space that
the kernel may have reassigned since.
Thus, use unmap_mapping_file() for every open file, so that only the
VMAs of the node being removed are zapped, while unrelated mappings
are left intact. The same helper also covers files without a swapped
f_mapping, and the driver-claim revocation through revoke_iomem() is
unaffected, as those VMAs remain on the shared address space.
This restores the behaviour these files had before the f_mapping swap
was introduced. A read through a stale mapping after removal now
raises SIGBUS instead of returning stale data.
Fixes: 636b21b50152 ("PCI: Revoke mappings like devmem")
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
---
fs/kernfs/file.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 8e0e90c93372..eb04439e9c3e 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -815,10 +815,8 @@ void kernfs_drain_open_files(struct kernfs_node *kn)
}
list_for_each_entry(of, &on->files, list) {
- struct inode *inode = file_inode(of->file);
-
if (of->mmapped) {
- unmap_mapping_range(inode->i_mapping, 0, 0, 1);
+ unmap_mapping_file(of->file);
of->mmapped = false;
on->nr_mmapped--;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v2 2/3] kernfs: Unmap mmaps of removed files via file->f_mapping
2026-07-25 21:05 ` [PATCH v2 2/3] kernfs: Unmap mmaps of removed files via file->f_mapping Krzysztof Wilczyński
@ 2026-07-25 21:22 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-07-25 21:22 UTC (permalink / raw)
To: Krzysztof Wilczyński; +Cc: linux-pci
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] A TOCTOU race condition between mmap() and kernfs_drain_open_files() allows a newly created VMA to escape being zapped, leaving stale physical mappings accessible to user space after device removal.
--
--- Patch [2]: [PATCH v2 2/3] kernfs: Unmap mmaps of removed files via file->f_mapping ---
commit cbf76235c8b2fab1c84f41b35091ff343e6741ef
Author: Krzysztof Wilczyński <kwilczynski@kernel.org>
kernfs: Unmap mmaps of removed files via file->f_mapping
This commit replaces unmap_mapping_range() with unmap_mapping_file()
in kernfs_drain_open_files(). This ensures that only VMAs of the
removed node are zapped, preserving unrelated mappings for PCI resource
and legacy sysfs files that swap their f_mapping.
> diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
> index 8e0e90c933720..eb04439e9c3ec 100644
> --- a/fs/kernfs/file.c
> +++ b/fs/kernfs/file.c
> @@ -815,10 +815,8 @@ void kernfs_drain_open_files(struct kernfs_node *kn)
> }
>
> list_for_each_entry(of, &on->files, list) {
> - struct inode *inode = file_inode(of->file);
> -
> if (of->mmapped) {
> - unmap_mapping_range(inode->i_mapping, 0, 0, 1);
> + unmap_mapping_file(of->file);
[Severity: High]
This isn't a bug introduced by this patch, but can this race with the VMA
being linked into the interval tree?
If kernfs_fop_mmap() sets of->mmapped = true and drops the active reference,
it can wake up a concurrent kernfs_remove() thread waiting for active
references to drain.
If that thread calls kernfs_drain_open_files() and sees of->mmapped == true,
it will call unmap_mapping_file() here.
However, since kernfs_fop_mmap() hasn't yet returned to the core mm code
where vma_link_file() is called (like in __mmap_new_vma()), the VMA
might not be in the interval tree yet. Consequently, unmap_mapping_file()
could find nothing to zap, and the mmap syscall subsequently inserts the VMA,
leaving userspace with an active physical mapping to a removed device.
Could the synchronization between the mmap path and kernfs_drain_open_files()
be missing a mechanism to wait for the VMA to be fully linked?
> of->mmapped = false;
> on->nr_mmapped--;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260725210549.3716546-1-kwilczynski@kernel.org?part=2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 3/3] proc: Unmap mmaps of removed files via file->f_mapping
2026-07-25 21:05 [PATCH v2 0/3] mm,kernfs,proc: Unmap mmaps of removed files via file->f_mapping Krzysztof Wilczyński
2026-07-25 21:05 ` [PATCH v2 1/3] mm: Add unmap_mapping_file() helper Krzysztof Wilczyński
2026-07-25 21:05 ` [PATCH v2 2/3] kernfs: Unmap mmaps of removed files via file->f_mapping Krzysztof Wilczyński
@ 2026-07-25 21:05 ` Krzysztof Wilczyński
2026-07-25 21:19 ` sashiko-bot
2026-07-25 21:37 ` [PATCH v2 0/3] mm,kernfs,proc: " Andrew Morton
3 siblings, 1 reply; 9+ messages in thread
From: Krzysztof Wilczyński @ 2026-07-25 21:05 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Greg Kroah-Hartman, Tejun Heo,
Bjorn Helgaas
Cc: Bjorn Helgaas, Manivannan Sadhasivam, Lorenzo Pieralisi,
Liam R . Howlett, Baoquan He, Pratyush Yadav, Pasha Tatashin,
Jaroslav Kysela, Takashi Iwai, Lorenzo Stoakes, Michal Hocko,
Mike Rapoport, Simona Vetter, Suren Baghdasaryan, Vlastimil Babka,
Dave Young, linux-mm, linux-pci, linux-sound, kexec, driver-core
Currently, proc_entry_rundown() releases every open file of an entry
that is being removed, but never unmaps the userspace mappings created
through those files, so these stay in place after the entry is gone.
For the /proc/bus/pci device files, the VMAs of such mappings are
attached to the shared iomem address space, as these files swap their
f_mapping to iomem_get_mapping() at open time, see commit 636b21b50152
("PCI: Revoke mappings like devmem").
As a result, userspace mappings of PCI BARs survive device removal,
keeping stale PTEs into physical address space that the kernel may
have reassigned since.
Thus, use unmap_mapping_file() in close_pdeo() to unmap the pages of
each open file, so that only the VMAs created through the removed file
are zapped, while unrelated mappings on the shared address space are
left intact. Add a pde_is_removed() helper next to pde_is_permanent()
to tell a rundown from a regular close(), which leaves mappings alone,
and use it in place of the open-coded checks in proc_misc_d_revalidate()
and proc_misc_d_delete().
This reaches every removable entry with a proc_release() hook, not only
the PCI ones. Other than /proc/bus/pci, the only entries that also set
a proc_mmap() hook are /proc/vmcore and the ALSA information entries.
Mappings of /proc/vmcore are now also unmapped when the entry is
removed. The ALSA proc_mmap() hook calls a per-entry callback that no
entry implements, so these cannot be mapped and nothing changes for
them.
A read through a stale mapping after removal now raises SIGBUS instead
of returning stale data.
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
---
fs/proc/generic.c | 4 ++--
fs/proc/inode.c | 2 ++
fs/proc/internal.h | 5 +++++
3 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index adc9b9a092b0..0d090e3f3a26 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -222,14 +222,14 @@ static int proc_misc_d_revalidate(struct inode *dir, const struct qstr *name,
if (flags & LOOKUP_RCU)
return -ECHILD;
- if (atomic_read(&PDE(d_inode(dentry))->in_use) < 0)
+ if (pde_is_removed(PDE(d_inode(dentry))))
return 0; /* revalidate */
return 1;
}
static int proc_misc_d_delete(const struct dentry *dentry)
{
- return atomic_read(&PDE(d_inode(dentry))->in_use) < 0;
+ return pde_is_removed(PDE(d_inode(dentry)));
}
static const struct dentry_operations proc_misc_dentry_ops = {
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index b7634f975d98..f1ebedc85b15 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -239,6 +239,8 @@ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo)
spin_unlock(&pde->pde_unload_lock);
file = pdeo->file;
+ if (pde_is_removed(pde))
+ unmap_mapping_file(file);
pde->proc_ops->proc_release(file_inode(file), file);
spin_lock(&pde->pde_unload_lock);
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index b232e1098117..53335381ae89 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -79,6 +79,11 @@ static inline bool pde_is_permanent(const struct proc_dir_entry *pde)
return pde->flags & PROC_ENTRY_PERMANENT;
}
+static inline bool pde_is_removed(const struct proc_dir_entry *pde)
+{
+ return atomic_read(&pde->in_use) < 0;
+}
+
/* This is for builtin code, not even for modules which are compiled in. */
static inline void pde_make_permanent(struct proc_dir_entry *pde)
{
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v2 3/3] proc: Unmap mmaps of removed files via file->f_mapping
2026-07-25 21:05 ` [PATCH v2 3/3] proc: " Krzysztof Wilczyński
@ 2026-07-25 21:19 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-07-25 21:19 UTC (permalink / raw)
To: Krzysztof Wilczyński; +Cc: linux-pci
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] A TOCTOU race allows a newly mmap'd VMA to bypass the zapping process during device rundown, leaving active PTEs mapped to removed hardware.
--
--- Patch [3]: [PATCH v2 3/3] proc: Unmap mmaps of removed files via file->f_mapping ---
commit d70ab9967b02c9e0d34615bf288a6ac4be654e1f
Author: Krzysztof Wilczyński <kwilczynski@kernel.org>
proc: Unmap mmaps of removed files via file->f_mapping
This commit unmaps user space mappings associated with removable proc
entries when the entry is being removed. It does this by calling
unmap_mapping_file() in close_pdeo() for each open file.
> diff --git a/fs/proc/inode.c b/fs/proc/inode.c
> --- a/fs/proc/inode.c
> +++ b/fs/proc/inode.c
> @@ -239,6 +239,8 @@ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo)
> spin_unlock(&pde->pde_unload_lock);
>
> file = pdeo->file;
> + if (pde_is_removed(pde))
> + unmap_mapping_file(file);
[Severity: Critical]
Can this race with a concurrent mmap() operation?
Looking at proc_reg_mmap() in fs/proc/inode.c, the PDE usage count is
dropped before the VMA is linked into the address space:
fs/proc/inode.c:proc_reg_mmap() {
...
rv = pde_mmap(pde, file, vma);
unuse_pde(pde);
return rv;
}
If Thread A drops the usage count via unuse_pde(), Thread B's rundown
could proceed and execute unmap_mapping_file() here.
Because Thread A has not yet returned to the VFS layer to link the VMA
to the interval tree:
mm/vma.c:__mmap_new_vma() {
...
vma_link_file(vma, action->hide_from_rmap_until_complete);
...
}
Would unmap_mapping_file() miss this new VMA, allowing Thread A to return
to userspace with an active mapping to the removed device?
> pde->proc_ops->proc_release(file_inode(file), file);
>
> spin_lock(&pde->pde_unload_lock);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260725210549.3716546-1-kwilczynski@kernel.org?part=3
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 0/3] mm,kernfs,proc: Unmap mmaps of removed files via file->f_mapping
2026-07-25 21:05 [PATCH v2 0/3] mm,kernfs,proc: Unmap mmaps of removed files via file->f_mapping Krzysztof Wilczyński
` (2 preceding siblings ...)
2026-07-25 21:05 ` [PATCH v2 3/3] proc: " Krzysztof Wilczyński
@ 2026-07-25 21:37 ` Andrew Morton
2026-07-26 1:22 ` Krzysztof Wilczyński
3 siblings, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2026-07-25 21:37 UTC (permalink / raw)
To: Krzysztof Wilczyński
Cc: David Hildenbrand, Greg Kroah-Hartman, Tejun Heo, Bjorn Helgaas,
Bjorn Helgaas, Manivannan Sadhasivam, Lorenzo Pieralisi,
Liam R . Howlett, Baoquan He, Pratyush Yadav, Pasha Tatashin,
Jaroslav Kysela, Takashi Iwai, Lorenzo Stoakes, Michal Hocko,
Mike Rapoport, Simona Vetter, Suren Baghdasaryan, Vlastimil Babka,
Dave Young, linux-mm, linux-pci, linux-sound, kexec, driver-core
On Sat, 25 Jul 2026 21:05:46 +0000 Krzysztof Wilczyński <kwilczynski@kernel.org> wrote:
> Hello,
>
> The PCI resource files in sysfs and the /proc/bus/pci device files swap
> their f_mapping to the shared iomem address space at open time, so that
> revoke_iomem() can unmap userspace mappings when a driver claims a
> region, see commit 636b21b50152 ("PCI: Revoke mappings like devmem").
>
> Their VMAs are therefore attached to the shared address space, which
> neither removal path reaches: kernfs_drain_open_files() unmaps the
> sysfs inode's own mapping, which contains none of them, and
> proc_entry_rundown() does not unmap anything at all.
>
> As a result, userspace mappings of PCI BARs survive device removal,
> and also survive a BAR resize on the sysfs side, keeping stale PTEs
> into physical address space that the kernel may have reassigned since.
> A mapping made before the device is removed still returns the previous
> register value after the device has been released, through both
> interfaces.
Thanks. Can we please have full description of the userspace-visible
effects of this?
AI review might have found a few things:
https://sashiko.dev/#/patchset/20260725210549.3716546-1-kwilczynski@kernel.org
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v2 0/3] mm,kernfs,proc: Unmap mmaps of removed files via file->f_mapping
2026-07-25 21:37 ` [PATCH v2 0/3] mm,kernfs,proc: " Andrew Morton
@ 2026-07-26 1:22 ` Krzysztof Wilczyński
0 siblings, 0 replies; 9+ messages in thread
From: Krzysztof Wilczyński @ 2026-07-26 1:22 UTC (permalink / raw)
To: Andrew Morton
Cc: David Hildenbrand, Greg Kroah-Hartman, Tejun Heo, Bjorn Helgaas,
Bjorn Helgaas, Manivannan Sadhasivam, Lorenzo Pieralisi,
Liam R . Howlett, Baoquan He, Pratyush Yadav, Pasha Tatashin,
Jaroslav Kysela, Takashi Iwai, Lorenzo Stoakes, Michal Hocko,
Mike Rapoport, Simona Vetter, Suren Baghdasaryan, Vlastimil Babka,
Dave Young, linux-mm, linux-pci, linux-sound, kexec, driver-core
Hello,
> > The PCI resource files in sysfs and the /proc/bus/pci device files swap
> > their f_mapping to the shared iomem address space at open time, so that
> > revoke_iomem() can unmap userspace mappings when a driver claims a
> > region, see commit 636b21b50152 ("PCI: Revoke mappings like devmem").
> >
> > Their VMAs are therefore attached to the shared address space, which
> > neither removal path reaches: kernfs_drain_open_files() unmaps the
> > sysfs inode's own mapping, which contains none of them, and
> > proc_entry_rundown() does not unmap anything at all.
> >
> > As a result, userspace mappings of PCI BARs survive device removal,
> > and also survive a BAR resize on the sysfs side, keeping stale PTEs
> > into physical address space that the kernel may have reassigned since.
> > A mapping made before the device is removed still returns the previous
> > register value after the device has been released, through both
> > interfaces.
>
> Thanks. Can we please have full description of the userspace-visible
> effects of this?
Definitely. From the PCI side, to put this into perspective:
Without this series, a process that maps a BAR keeps a fully working
mapping after the device is removed or its VFs torn down. The same
applies when a BAR is resized, as the resize removes and recreates the
resource groups. Nothing faults, so the process cannot tell the device
has gone. A read returns the register contents as they were, because
removal clears Bus Master but leaves Memory Space Enable set, so the
device still decodes its BARs, and, as these attributes are writable,
a write is still accepted and reaches it. Those addresses are released
on removal and can be assigned to another device, which a BAR resize
does explicitly, and the mapping then reaches whatever occupies them.
On the sysfs side this most likely has been a regression as the
kernfs_drain_open_files() unmapped these mappings correctly until
commit 636b21b50152 ("PCI: Revoke mappings like devmem") swapped
f_mapping to the shared iomem address space, after which the drain
walked an interval tree the VMAs were no longer on. The procfs side
never unmapped anything, so there the behaviour is new.
A read here returns another device's register contents, and as read to
clear registers are common, it can also acknowledge an interrupt or clear
an error the owning driver has not seen. A write can be worse, as an
offset that was a control register on the old device may be a doorbell,
a reset bit or a DMA descriptor address on the new one.
With this series the mapping is torn down as part of the removal, and
the next access raises SIGBUS, so userspace gets an error instead of
silently reading stale or unrelated registers. Both interfaces behave
the same way afterwards.
Tested on 7.2-rc1 with and without the series applied. In each case
the file is mmap'd, the device is removed while the mapping is held,
and the mapping is then accessed:
- sysfs resource read after removal:
before: returns 0x18140241, the value read before the removal
after: SIGBUS
- sysfs resource written after removal:
before: the write is accepted and reads back 0x00000000
after: SIGBUS on the write
- sysfs resource mmap, fd closed, then read after removal:
before: returns 0x18140241
after: SIGBUS
- sysfs resource mmap, moved with mremap and split with munmap, then forked, both read after removal:
before: parent and child both return 0x18140241
after: SIGBUS in both
- two sysfs resources of different devices mmap, one device removed, both read:
before: neither is unmapped, both return their values
after: the removed device raises SIGBUS, the other still returns 0x48140240
- /proc/bus/pci used to mmap resource, read after removal:
before: returns 0x18140241
after: SIGBUS
I hope this helps!
> AI review might have found a few things:
> https://sashiko.dev/#/patchset/20260725210549.3716546-1-kwilczynski@kernel.org
I have seen the reviews. Will reply to each.
Thank you!
Krzysztof
^ permalink raw reply [flat|nested] 9+ messages in thread