@@ -163,6 +163,7 @@ bool hugetlb_reserve_pages(struct inode *inode, long from, long to,
long hugetlb_unreserve_pages(struct inode *inode, long start, long end,
long freed);
bool isolate_hugetlb(struct folio *folio, struct list_head *list);
+struct folio *hugetlb_pfn_folio(unsigned long pfn);
int get_hwpoison_hugetlb_folio(struct folio *folio, bool *hugetlb, bool unpoison);
int get_huge_page_for_hwpoison(unsigned long pfn, int flags,
bool *migratable_cleared);
@@ -124,6 +124,33 @@ bool folio_test_hugetlb(const struct folio *folio)
}
EXPORT_SYMBOL_GPL(folio_test_hugetlb);
+/**
+ * hugetlb_pfn_folio - Convert a pfn to a hugetlb folio.
+ * @pfn: The Page Frame Number.
+ *
+ * If this function returns NULL, the pfn definitely wasn't part of
+ * a hugetlb folio. If a folio pointer is returned, this pfn was
+ * part of that hugetlb folio at some point. If the caller holds
+ * the @hugetlb_lock, hugetlb folios may not be returned to the page
+ * allocator, so the folio will still be valid (it may or may not
+ * be free).
+ *
+ * Return: NULL if the pfn is not part of a hugetlb folio.
+ */
+struct folio *hugetlb_pfn_folio(unsigned long pfn)
+{
+ struct page *page = pfn_to_page(pfn);
+ struct folio *folio;
+
+ if (!PageCompound(page))
+ return NULL;
+ folio = page_folio(page);
+ if (folio->large_id != &hugetlb_lock)
+ return NULL;
+
+ return folio;
+}
+
static inline bool subpool_is_free(struct hugepage_subpool *spool)
{
if (spool->count)
Returns the hugetlb folio containing this PFN or NULL if the PFN is not within a hugetlb folio. Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> --- include/linux/hugetlb.h | 1 + mm/hugetlb.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+)