mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-01 22:54:01 +00:00
hugetlb: fix update_and_free_page contig page struct assumption
commitdbfee5aee7
upstream. page structs are not guaranteed to be contiguous for gigantic pages. The routine update_and_free_page can encounter a gigantic page, yet it assumes page structs are contiguous when setting page flags in subpages. If update_and_free_page encounters non-contiguous page structs, we can see “BUG: Bad page state in process …” errors. Non-contiguous page structs are generally not an issue. However, they can exist with a specific kernel configuration and hotplug operations. For example: Configure the kernel with CONFIG_SPARSEMEM and !CONFIG_SPARSEMEM_VMEMMAP. Then, hotplug add memory for the area where the gigantic page will be allocated. Zi Yan outlined steps to reproduce here [1]. [1] https://lore.kernel.org/linux-mm/16F7C58B-4D79-41C5-9B64-A1A1628F4AF2@nvidia.com/ Link: https://lkml.kernel.org/r/20210217184926.33567-1-mike.kravetz@oracle.com Fixes:944d9fec8d
("hugetlb: add support for gigantic page allocation at runtime") Signed-off-by: Zi Yan <ziy@nvidia.com> Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com> Cc: Zi Yan <ziy@nvidia.com> Cc: Davidlohr Bueso <dbueso@suse.de> Cc: "Kirill A . Shutemov" <kirill.shutemov@linux.intel.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Oscar Salvador <osalvador@suse.de> Cc: Joao Martins <joao.m.martins@oracle.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
1b1a949b40
commit
65f6dc3616
1 changed files with 4 additions and 2 deletions
|
@ -1312,14 +1312,16 @@ static inline void destroy_compound_gigantic_page(struct page *page,
|
|||
static void update_and_free_page(struct hstate *h, struct page *page)
|
||||
{
|
||||
int i;
|
||||
struct page *subpage = page;
|
||||
|
||||
if (hstate_is_gigantic(h) && !gigantic_page_runtime_supported())
|
||||
return;
|
||||
|
||||
h->nr_huge_pages--;
|
||||
h->nr_huge_pages_node[page_to_nid(page)]--;
|
||||
for (i = 0; i < pages_per_huge_page(h); i++) {
|
||||
page[i].flags &= ~(1 << PG_locked | 1 << PG_error |
|
||||
for (i = 0; i < pages_per_huge_page(h);
|
||||
i++, subpage = mem_map_next(subpage, page, i)) {
|
||||
subpage->flags &= ~(1 << PG_locked | 1 << PG_error |
|
||||
1 << PG_referenced | 1 << PG_dirty |
|
||||
1 << PG_active | 1 << PG_private |
|
||||
1 << PG_writeback);
|
||||
|
|
Loading…
Reference in a new issue