]> git.ipfire.org Git - people/ms/linux.git/commitdiff
mm/hugetlb: correct demote page offset logic
authorDoug Berger <opendmb@gmail.com>
Wed, 14 Sep 2022 19:09:17 +0000 (12:09 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 26 Sep 2022 19:14:34 +0000 (12:14 -0700)
With gigantic pages it may not be true that struct page structures are
contiguous across the entire gigantic page.  The nth_page macro is used
here in place of direct pointer arithmetic to correct for this.

Mike said:

: This error could cause addressing exceptions.  However, this is only
: possible in configurations where CONFIG_SPARSEMEM &&
: !CONFIG_SPARSEMEM_VMEMMAP.  Such a configuration option is rare and
: unknown to be the default anywhere.

Link: https://lkml.kernel.org/r/20220914190917.3517663-1-opendmb@gmail.com
Fixes: 8531fc6f52f5 ("hugetlb: add hugetlb demote page support")
Signed-off-by: Doug Berger <opendmb@gmail.com>
Reviewed-by: Mike Kravetz <mike.kravetz@oracle.com>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Muchun Song <songmuchun@bytedance.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/hugetlb.c

index e070b8593b3765c998bc4d742afc862a1d42adaf..0bdfc7e1c933f59c8084f9b4288201450c3d90cb 100644 (file)
@@ -3420,6 +3420,7 @@ static int demote_free_huge_page(struct hstate *h, struct page *page)
 {
        int i, nid = page_to_nid(page);
        struct hstate *target_hstate;
+       struct page *subpage;
        int rc = 0;
 
        target_hstate = size_to_hstate(PAGE_SIZE << h->demote_order);
@@ -3453,15 +3454,16 @@ static int demote_free_huge_page(struct hstate *h, struct page *page)
        mutex_lock(&target_hstate->resize_lock);
        for (i = 0; i < pages_per_huge_page(h);
                                i += pages_per_huge_page(target_hstate)) {
+               subpage = nth_page(page, i);
                if (hstate_is_gigantic(target_hstate))
-                       prep_compound_gigantic_page_for_demote(page + i,
+                       prep_compound_gigantic_page_for_demote(subpage,
                                                        target_hstate->order);
                else
-                       prep_compound_page(page + i, target_hstate->order);
-               set_page_private(page + i, 0);
-               set_page_refcounted(page + i);
-               prep_new_huge_page(target_hstate, page + i, nid);
-               put_page(page + i);
+                       prep_compound_page(subpage, target_hstate->order);
+               set_page_private(subpage, 0);
+               set_page_refcounted(subpage);
+               prep_new_huge_page(target_hstate, subpage, nid);
+               put_page(subpage);
        }
        mutex_unlock(&target_hstate->resize_lock);