Skip to content

Commit 6a6dccb

Browse files
vitkyrkamszyprow
authored andcommitted
mm: cma: don't replace lowmem pages with highmem
The filesystem layer expects pages in the block device's mapping to not be in highmem (the mapping's gfp mask is set in bdget()), but CMA can currently replace lowmem pages with highmem pages, leading to crashes in filesystem code such as the one below: Unable to handle kernel NULL pointer dereference at virtual address 00000400 pgd = c0c98000 [00000400] *pgd=00c91831, *pte=00000000, *ppte=00000000 Internal error: Oops: 817 [#1] PREEMPT SMP ARM CPU: 0 Not tainted (3.5.0-rc5+ #80) PC is at __memzero+0x24/0x80 ... Process fsstress (pid: 323, stack limit = 0xc0cbc2f0) Backtrace: [<c010e3f0>] (ext4_getblk+0x0/0x180) from [<c010e58c>] (ext4_bread+0x1c/0x98) [<c010e570>] (ext4_bread+0x0/0x98) from [<c0117944>] (ext4_mkdir+0x160/0x3bc) r4:c15337f0 [<c01177e4>] (ext4_mkdir+0x0/0x3bc) from [<c00c29e0>] (vfs_mkdir+0x8c/0x98) [<c00c2954>] (vfs_mkdir+0x0/0x98) from [<c00c2a60>] (sys_mkdirat+0x74/0xac) r6:00000000 r5:c152eb40 r4:000001ff r3:c14b43f0 [<c00c29ec>] (sys_mkdirat+0x0/0xac) from [<c00c2ab8>] (sys_mkdir+0x20/0x24) r6:beccdcf0 r5:00074000 r4:beccdbbc [<c00c2a98>] (sys_mkdir+0x0/0x24) from [<c000e3c0>] (ret_fast_syscall+0x0/0x30) Fix this by replacing only highmem pages with highmem. Reported-by: Laura Abbott <[email protected]> Signed-off-by: Rabin Vincent <[email protected]> Acked-by: Michal Nazarewicz <[email protected]> Signed-off-by: Marek Szyprowski <[email protected]>
1 parent 6887a41 commit 6a6dccb

File tree

1 file changed

+6
-1
lines changed

1 file changed

+6
-1
lines changed

mm/page_alloc.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5635,7 +5635,12 @@ static struct page *
56355635
__alloc_contig_migrate_alloc(struct page *page, unsigned long private,
56365636
int **resultp)
56375637
{
5638-
return alloc_page(GFP_HIGHUSER_MOVABLE);
5638+
gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE;
5639+
5640+
if (PageHighMem(page))
5641+
gfp_mask |= __GFP_HIGHMEM;
5642+
5643+
return alloc_page(gfp_mask);
56395644
}
56405645

56415646
/* [start, end) must belong to a single zone. */

0 commit comments

Comments
 (0)