diff options
| author | Wei Yang <richard.weiyang@gmail.com> | 2025-11-19 23:53:02 +0000 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-12-07 06:27:37 +0900 |
| commit | d1b83fbacd4397a1d2f8c6b13427a8636ae2b307 (patch) | |
| tree | f142a24abe5fc4323d8e316d4d486f43e8c548da /mm | |
| parent | 39e383af172a8e2aa25681135756ebe20026a4a3 (diff) | |
| download | linux-d1b83fbacd4397a1d2f8c6b13427a8636ae2b307.tar.gz linux-d1b83fbacd4397a1d2f8c6b13427a8636ae2b307.tar.bz2 linux-d1b83fbacd4397a1d2f8c6b13427a8636ae2b307.zip | |
mm/huge_memory: fix NULL pointer deference when splitting folio
commit cff47b9e39a6abf03dde5f4f156f841b0c54bba0 upstream.
Commit c010d47f107f ("mm: thp: split huge page to any lower order pages")
introduced an early check on the folio's order via mapping->flags before
proceeding with the split work.
This check introduced a bug: for shmem folios in the swap cache and
truncated folios, the mapping pointer can be NULL. Accessing
mapping->flags in this state leads directly to a NULL pointer dereference.
This commit fixes the issue by moving the check for mapping != NULL before
any attempt to access mapping->flags.
Link: https://lkml.kernel.org/r/20251119235302.24773-1-richard.weiyang@gmail.com
Fixes: c010d47f107f ("mm: thp: split huge page to any lower order pages")
Signed-off-by: Wei Yang <richard.weiyang@gmail.com>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Acked-by: David Hildenbrand (Red Hat) <david@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'mm')
| -rw-r--r-- | mm/huge_memory.c | 22 |
1 files changed, 10 insertions, 12 deletions
diff --git a/mm/huge_memory.c b/mm/huge_memory.c index c5e1ee566841..5d63ee72c1f6 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -3626,6 +3626,16 @@ static int __folio_split(struct folio *folio, unsigned int new_order, if (folio != page_folio(split_at) || folio != page_folio(lock_at)) return -EINVAL; + /* + * Folios that just got truncated cannot get split. Signal to the + * caller that there was a race. + * + * TODO: this will also currently refuse shmem folios that are in the + * swapcache. + */ + if (!is_anon && !folio->mapping) + return -EBUSY; + if (new_order >= folio_order(folio)) return -EINVAL; @@ -3666,18 +3676,6 @@ static int __folio_split(struct folio *folio, unsigned int new_order, gfp_t gfp; mapping = folio->mapping; - - /* Truncated ? */ - /* - * TODO: add support for large shmem folio in swap cache. - * When shmem is in swap cache, mapping is NULL and - * folio_test_swapcache() is true. - */ - if (!mapping) { - ret = -EBUSY; - goto out; - } - min_order = mapping_min_folio_order(folio->mapping); if (new_order < min_order) { ret = -EINVAL; |
