]> Pileus Git - ~andy/linux/blobdiff - mm/hugetlb.c
mm: hugetlb: initialize PG_reserved for tail pages of gigantic compound pages
[~andy/linux] / mm / hugetlb.c
index 691f2264a6ce23cfd10dbb570f5342fee2d25bc5..0b7656e804d126cf0fcfa04a8b427396af86deb1 100644 (file)
@@ -696,8 +696,22 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order)
        /* we rely on prep_new_huge_page to set the destructor */
        set_compound_order(page, order);
        __SetPageHead(page);
+       __ClearPageReserved(page);
        for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) {
                __SetPageTail(p);
+               /*
+                * For gigantic hugepages allocated through bootmem at
+                * boot, it's safer to be consistent with the not-gigantic
+                * hugepages and clear the PG_reserved bit from all tail pages
+                * too.  Otherwse drivers using get_user_pages() to access tail
+                * pages may get the reference counting wrong if they see
+                * PG_reserved set on a tail page (despite the head page not
+                * having PG_reserved set).  Enforcing this consistency between
+                * head and tail pages allows drivers to optimize away a check
+                * on the head page when they need know if put_page() is needed
+                * after get_user_pages().
+                */
+               __ClearPageReserved(p);
                set_page_count(p, 0);
                p->first_page = page;
        }
@@ -1330,9 +1344,9 @@ static void __init gather_bootmem_prealloc(void)
 #else
                page = virt_to_page(m);
 #endif
-               __ClearPageReserved(page);
                WARN_ON(page_count(page) != 1);
                prep_compound_huge_page(page, h->order);
+               WARN_ON(PageReserved(page));
                prep_new_huge_page(h, page, page_to_nid(page));
                /*
                 * If we had gigantic hugepages allocated at boot time, we need