FAILED: patch "[PATCH] mm/memory: do not populate page table entries beyond i_size" failed to apply to 6.12-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 74207de2ba10c2973334906822dc94d2e859ffc5
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025112023-nearest-surname-60bf@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 74207de2ba10c2973334906822dc94d2e859ffc5 Mon Sep 17 00:00:00 2001
From: Kiryl Shutsemau <[email protected]>
Date: Mon, 27 Oct 2025 11:56:35 +0000
Subject: [PATCH] mm/memory: do not populate page table entries beyond i_size
Patch series "Fix SIGBUS semantics with large folios", v3.
Accessing memory within a VMA, but beyond i_size rounded up to the next page size, is supposed to generate SIGBUS.
Darrick reported[1] an xfstests regression in v6.18-rc1. generic/749 failed due to missing SIGBUS. This was caused by my recent changes that try to fault in the whole folio where possible:
19773df031bc ("mm/fault: try to map the entire file folio in finish_fault()") 357b92761d94 ("mm/filemap: map entire large folio faultaround")
These changes did not consider i_size when setting up PTEs, leading to xfstest breakage.
However, the problem has been present in the kernel for a long time - since huge tmpfs was introduced in 2016. The kernel happily maps PMD-sized folios as PMD without checking i_size. And huge=always tmpfs allocates PMD-size folios on any writes.
I considered this corner case when I implemented a large tmpfs, and my conclusion was that no one in their right mind should rely on receiving a SIGBUS signal when accessing beyond i_size. I cannot imagine how it could be useful for the workload.
But apparently filesystem folks care a lot about preserving strict SIGBUS semantics.
Generic/749 was introduced last year with reference to POSIX, but no real workloads were mentioned. It also acknowledged the tmpfs deviation from the test case.
POSIX indeed says[3]:
References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object shall result in delivery of a SIGBUS signal.
The patchset fixes the regression introduced by recent changes as well as more subtle SIGBUS breakage due to split failure on truncation.
This patch (of 2):
Accesses within VMA, but beyond i_size rounded up to PAGE_SIZE are supposed to generate SIGBUS.
Recent changes attempted to fault in full folio where possible. They did not respect i_size, which led to populating PTEs beyond i_size and breaking SIGBUS semantics.
Darrick reported generic/749 breakage because of this.
However, the problem existed before the recent changes. With huge=always tmpfs, any write to a file leads to PMD-size allocation. Following the fault-in of the folio will install PMD mapping regardless of i_size.
Fix filemap_map_pages() and finish_fault() to not install:
- PTEs beyond i_size;
- PMD mappings across i_size;
Make an exception for shmem/tmpfs that for long time intentionally mapped with PMDs across i_size.
mm/filemap.c +20 -8
@@ -3681,7 +3681,8 @@ static struct folio *next_uptodate_folio(struct xa_state *xas,static vm_fault_t filemap_map_folio_range (struct vm_fault *vmf,struct folio *folio,unsigned long start,unsigned long addr,unsigned int nr_pages, -unsigned long *rss,unsigned short *mmap_miss) +unsigned long *rss,unsigned short *mmap_miss, +bool can_map_large) {unsigned int ref_from_caller =1 ;vm_fault_t ret =0 ;
@@ -3696,7 +3697,7 @@ static vm_fault_t filemap_map_folio_range(struct vm_fault *vmf,* The folio must not cross VMA or page table boundary. */ addr0 = addr - start *PAGE_SIZE ; -if (folio_within_vma (folio, vmf->vma) && +if (can_map_large &&folio_within_vma (folio, vmf->vma) && (addr0 &PMD_MASK ) == ((addr0 +folio_size (folio) -1 ) &PMD_MASK )) { vmf->pte -= start; page -= start;
@@ -3811,13 +3812,27 @@ vm_fault_t filemap_map_pages(struct vm_fault *vmf,unsigned long rss =0 ;unsigned int nr_pages =0 , folio_type;unsigned short mmap_miss =0 , mmap_miss_saved; +bool can_map_large;rcu_read_lock (); folio =next_uptodate_folio (&xas, mapping, end_pgoff);if (!folio) goto out; -if (filemap_map_pmd (vmf, folio, start_pgoff)) { + file_end =DIV_ROUND_UP (i_size_read (mapping->host),PAGE_SIZE ) -1 ; + end_pgoff =min (end_pgoff, file_end); + +/* +* Do not allow to map with PTEs beyond i_size and with PMD +* across i_size to preserve SIGBUS semantics. +* +* Make an exception for shmem/tmpfs that for long time +* intentionally mapped with PMDs across i_size. +*/ + can_map_large =shmem_mapping (mapping) || + file_end >=folio_next_index (folio); + +if (can_map_large &&filemap_map_pmd (vmf, folio, start_pgoff)) { ret =VM_FAULT_NOPAGE ; goto out; }
@@ -3830,10 +3845,6 @@ vm_fault_t filemap_map_pages(struct vm_fault *vmf, goto out; } - file_end =DIV_ROUND_UP (i_size_read (mapping->host),PAGE_SIZE ) -1 ; -if (end_pgoff > file_end) - end_pgoff = file_end; - folio_type =mm_counter_file (folio); do { unsigned long end;
@@ -3850,7 +3861,8 @@ vm_fault_t filemap_map_pages(struct vm_fault *vmf,else ret |=filemap_map_folio_range (vmf, folio, xas.xa_index - folio->index, addr, - nr_pages, &rss, &mmap_miss); + nr_pages, &rss, &mmap_miss, + can_map_large);folio_unlock (folio); }while ((folio =next_uptodate_folio (&xas, mapping, end_pgoff)) !=NULL );
mm/memory.c +19 -1
@@ -65,6 +65,7 @@#include <linux/gfp.h> #include <linux/migrate.h> #include <linux/string.h> +#include <linux/shmem_fs.h> #include <linux/memory-tiers.h> #include <linux/debugfs.h> #include <linux/userfaultfd_k.h>
@@ -5501,8 +5502,25 @@ vm_fault_t finish_fault(struct vm_fault *vmf)return ret; } +if (!needs_fallback && vma->vm_file) { +struct address_space *mapping = vma->vm_file->f_mapping; +pgoff_t file_end; + + file_end =DIV_ROUND_UP (i_size_read (mapping->host),PAGE_SIZE ); + +/* +* Do not allow to map with PTEs beyond i_size and with PMD +* across i_size to preserve SIGBUS semantics. +* +* Make an exception for shmem/tmpfs that for long time +* intentionally mapped with PMDs across i_size. +*/ + needs_fallback = !shmem_mapping (mapping) && + file_end <folio_next_index (folio); + } +if (pmd_none (*vmf->pmd)) { -if (folio_test_pmd_mappable (folio)) { +if (!needs_fallback &&folio_test_pmd_mappable (folio)) { ret =do_set_pmd (vmf, folio, page);if (ret !=VM_FAULT_FALLBACK )return ret;
PATCH 1/1 mm/memory: do not populate page table entries beyond i_size
Patch series "Fix SIGBUS semantics with large folios", v3.
Accessing memory within a VMA, but beyond i_size rounded up to the next page size, is supposed to generate SIGBUS.
Darrick reported[1] an xfstests regression in v6.18-rc1. generic/749 failed due to missing SIGBUS. This was caused by my recent changes that try to fault in the whole folio where possible:
19773df031bc ("mm/fault: try to map the entire file folio in finish_fault()") 357b92761d94 ("mm/filemap: map entire large folio faultaround")
These changes did not consider i_size when setting up PTEs, leading to xfstest breakage.
However, the problem has been present in the kernel for a long time - since huge tmpfs was introduced in 2016. The kernel happily maps PMD-sized folios as PMD without checking i_size. And huge=always tmpfs allocates PMD-size folios on any writes.
I considered this corner case when I implemented a large tmpfs, and my conclusion was that no one in their right mind should rely on receiving a SIGBUS signal when accessing beyond i_size. I cannot imagine how it could be useful for the workload.
But apparently filesystem folks care a lot about preserving strict SIGBUS semantics.
Generic/749 was introduced last year with reference to POSIX, but no real workloads were mentioned. It also acknowledged the tmpfs deviation from the test case.
POSIX indeed says[3]:
References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object shall result in delivery of a SIGBUS signal.
The patchset fixes the regression introduced by recent changes as well as more subtle SIGBUS breakage due to split failure on truncation.
This patch (of 2):
Accesses within VMA, but beyond i_size rounded up to PAGE_SIZE are supposed to generate SIGBUS.
Recent changes attempted to fault in full folio where possible. They did not respect i_size, which led to populating PTEs beyond i_size and breaking SIGBUS semantics.
Darrick reported generic/749 breakage because of this.
However, the problem existed before the recent changes. With huge=always tmpfs, any write to a file leads to PMD-size allocation. Following the fault-in of the folio will install PMD mapping regardless of i_size.
Fix filemap_map_pages() and finish_fault() to not install:
- PTEs beyond i_size;
- PMD mappings across i_size;
Make an exception for shmem/tmpfs that for long time intentionally mapped with PMDs across i_size.
--- mm/filemap.c | 20 +++++++++++++++----- mm/memory.c | 23 +++++++++++++++++++++-- 2 files changed, 36 insertions(+), 7 deletions(-)
mm/filemap.c +15 -5
@@ -3653,13 +3653,27 @@ vm_fault_t filemap_map_pages(struct vm_fault *vmf,vm_fault_t ret =0 ;unsigned long rss =0 ;unsigned int nr_pages =0 , mmap_miss =0 , mmap_miss_saved, folio_type; +bool can_map_large;rcu_read_lock (); folio =next_uptodate_folio (&xas, mapping, end_pgoff);if (!folio) goto out; -if (filemap_map_pmd (vmf, folio, start_pgoff)) { + file_end =DIV_ROUND_UP (i_size_read (mapping->host),PAGE_SIZE ) -1 ; + end_pgoff =min (end_pgoff, file_end); + +/* +* Do not allow to map with PTEs beyond i_size and with PMD +* across i_size to preserve SIGBUS semantics. +* +* Make an exception for shmem/tmpfs that for long time +* intentionally mapped with PMDs across i_size. +*/ + can_map_large =shmem_mapping (mapping) || + file_end >=folio_next_index (folio); + +if (can_map_large &&filemap_map_pmd (vmf, folio, start_pgoff)) { ret =VM_FAULT_NOPAGE ; goto out; }
@@ -3672,10 +3686,6 @@ vm_fault_t filemap_map_pages(struct vm_fault *vmf, goto out; } - file_end =DIV_ROUND_UP (i_size_read (mapping->host),PAGE_SIZE ) -1 ; -if (end_pgoff > file_end) - end_pgoff = file_end; - folio_type =mm_counter_file (folio); do { unsigned long end;
mm/memory.c +21 -2
@@ -68,6 +68,7 @@#include <linux/gfp.h> #include <linux/migrate.h> #include <linux/string.h> +#include <linux/shmem_fs.h> #include <linux/memory-tiers.h> #include <linux/debugfs.h> #include <linux/userfaultfd_k.h>
@@ -5088,6 +5089,8 @@ vm_fault_t finish_fault(struct vm_fault *vmf)else page = vmf->page; + folio =page_folio (page); +/* * check even for read faults because we might have lost our CoWed * page
@@ -5098,8 +5101,25 @@ vm_fault_t finish_fault(struct vm_fault *vmf)return ret; } +if (!needs_fallback && vma->vm_file) { +struct address_space *mapping = vma->vm_file->f_mapping; +pgoff_t file_end; + + file_end =DIV_ROUND_UP (i_size_read (mapping->host),PAGE_SIZE ); + +/* +* Do not allow to map with PTEs beyond i_size and with PMD +* across i_size to preserve SIGBUS semantics. +* +* Make an exception for shmem/tmpfs that for long time +* intentionally mapped with PMDs across i_size. +*/ + needs_fallback = !shmem_mapping (mapping) && + file_end <folio_next_index (folio); + } +if (pmd_none (*vmf->pmd)) { -if (PageTransCompound (page)) { +if (!needs_fallback &&PageTransCompound (page)) { ret =do_set_pmd (vmf, page);if (ret !=VM_FAULT_FALLBACK )return ret;
@@ -5111,7 +5131,6 @@ vm_fault_t finish_fault(struct vm_fault *vmf)return VM_FAULT_OOM ; } - folio =page_folio (page); nr_pages =folio_nr_pages (folio);/*
Signature · 1 line
2.51.0