summaryrefslogtreecommitdiff
path: root/arch/arm64/mm/flush.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/mm/flush.c')
-rw-r--r--arch/arm64/mm/flush.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c
index a06c6ac770d4..fc4f710e9820 100644
--- a/arch/arm64/mm/flush.c
+++ b/arch/arm64/mm/flush.c
@@ -75,6 +75,20 @@ EXPORT_SYMBOL_GPL(__sync_icache_dcache);
*/
void flush_dcache_page(struct page *page)
{
+ /*
+ * Only the head page's flags of HugeTLB can be cleared since the tail
+ * vmemmap pages associated with each HugeTLB page are mapped with
+ * read-only when CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP is enabled (more
+ * details can refer to vmemmap_remap_pte()). Although
+ * __sync_icache_dcache() only set PG_dcache_clean flag on the head
+ * page struct, there is more than one page struct with PG_dcache_clean
+ * associated with the HugeTLB page since the head vmemmap page frame
+ * is reused (more details can refer to the comments above
+ * page_fixed_fake_head()).
+ */
+ if (hugetlb_optimize_vmemmap_enabled() && PageHuge(page))
+ page = compound_head(page);
+
if (test_bit(PG_dcache_clean, &page->flags))
clear_bit(PG_dcache_clean, &page->flags);
}