if (folio_test_hugetlb_raw_hwp_unreliable(folio))
                return;
 
-       if (hugetlb_vmemmap_restore(h, &folio->page)) {
+       /*
+        * If folio is not vmemmap optimized (!clear_dtor), then the folio
+        * is no longer identified as a hugetlb page.  hugetlb_vmemmap_restore
+        * can only be passed hugetlb pages and will BUG otherwise.
+        */
+       if (clear_dtor && hugetlb_vmemmap_restore(h, &folio->page)) {
                spin_lock_irq(&hugetlb_lock);
                /*
                 * If we cannot allocate vmemmap pages, just refuse to free the
 
 static void __prep_new_hugetlb_folio(struct hstate *h, struct folio *folio)
 {
+       folio_set_hugetlb(folio);
        hugetlb_vmemmap_optimize(h, &folio->page);
        INIT_LIST_HEAD(&folio->lru);
-       folio_set_hugetlb(folio);
        hugetlb_set_folio_subpool(folio, NULL);
        set_hugetlb_cgroup(folio, NULL);
        set_hugetlb_cgroup_rsvd(folio, NULL);
        remove_hugetlb_folio_for_demote(h, folio, false);
        spin_unlock_irq(&hugetlb_lock);
 
-       rc = hugetlb_vmemmap_restore(h, &folio->page);
-       if (rc) {
-               /* Allocation of vmemmmap failed, we can not demote folio */
-               spin_lock_irq(&hugetlb_lock);
-               folio_ref_unfreeze(folio, 1);
-               add_hugetlb_folio(h, folio, false);
-               return rc;
+       /*
+        * If vmemmap already existed for folio, the remove routine above would
+        * have cleared the hugetlb folio flag.  Hence the folio is technically
+        * no longer a hugetlb folio.  hugetlb_vmemmap_restore can only be
+        * passed hugetlb folios and will BUG otherwise.
+        */
+       if (folio_test_hugetlb(folio)) {
+               rc = hugetlb_vmemmap_restore(h, &folio->page);
+               if (rc) {
+                       /* Allocation of vmemmmap failed, we can not demote folio */
+                       spin_lock_irq(&hugetlb_lock);
+                       folio_ref_unfreeze(folio, 1);
+                       add_hugetlb_folio(h, folio, false);
+                       return rc;
+               }
        }
 
        /*
 
 #include <linux/pgtable.h>
 #include <linux/moduleparam.h>
 #include <linux/bootmem_info.h>
+#include <linux/mmdebug.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include "hugetlb_vmemmap.h"
        unsigned long vmemmap_start = (unsigned long)head, vmemmap_end;
        unsigned long vmemmap_reuse;
 
+       VM_WARN_ON_ONCE(!PageHuge(head));
        if (!HPageVmemmapOptimized(head))
                return 0;
 
        unsigned long vmemmap_start = (unsigned long)head, vmemmap_end;
        unsigned long vmemmap_reuse;
 
+       VM_WARN_ON_ONCE(!PageHuge(head));
        if (!vmemmap_should_optimize(h, head))
                return;