]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
mm: allow set/clear page_type again
authorYu Zhao <yuzhao@google.com>
Sun, 20 Oct 2024 04:22:12 +0000 (22:22 -0600)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 31 Oct 2024 03:14:12 +0000 (20:14 -0700)
Some page flags (page->flags) were converted to page types
(page->page_types).  A recent example is PG_hugetlb.

From the exclusive writer's perspective, e.g., a thread doing
__folio_set_hugetlb(), there is a difference between the page flag and
type APIs: the former allows the same non-atomic operation to be repeated
whereas the latter does not.  For example, calling __folio_set_hugetlb()
twice triggers VM_BUG_ON_FOLIO(), since the second call expects the type
(PG_hugetlb) not to be set previously.

Using add_hugetlb_folio() as an example, it calls __folio_set_hugetlb() in
the following error-handling path.  And when that happens, it triggers the
aforementioned VM_BUG_ON_FOLIO().

  if (folio_test_hugetlb(folio)) {
    rc = hugetlb_vmemmap_restore_folio(h, folio);
    if (rc) {
      spin_lock_irq(&hugetlb_lock);
      add_hugetlb_folio(h, folio, false);
      ...

It is possible to make hugeTLB comply with the new requirements from the
page type API.  However, a straightforward fix would be to just allow the
same page type to be set or cleared again inside the API, to avoid any
changes to its callers.

Link: https://lkml.kernel.org/r/20241020042212.296781-1-yuzhao@google.com
Fixes: d99e3140a4d3 ("mm: turn folio_test_hugetlb into a PageType")
Signed-off-by: Yu Zhao <yuzhao@google.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
include/linux/page-flags.h

index 1b3a7671048788d8adbe29bc863209d66317cb06..cc839e4365c18223e68c35efd0f67e7650708e8b 100644 (file)
@@ -975,12 +975,16 @@ static __always_inline bool folio_test_##fname(const struct folio *folio) \
 }                                                                      \
 static __always_inline void __folio_set_##fname(struct folio *folio)   \
 {                                                                      \
+       if (folio_test_##fname(folio))                                  \
+               return;                                                 \
        VM_BUG_ON_FOLIO(data_race(folio->page.page_type) != UINT_MAX,   \
                        folio);                                         \
        folio->page.page_type = (unsigned int)PGTY_##lname << 24;       \
 }                                                                      \
 static __always_inline void __folio_clear_##fname(struct folio *folio) \
 {                                                                      \
+       if (folio->page.page_type == UINT_MAX)                          \
+               return;                                                 \
        VM_BUG_ON_FOLIO(!folio_test_##fname(folio), folio);             \
        folio->page.page_type = UINT_MAX;                               \
 }
@@ -993,11 +997,15 @@ static __always_inline int Page##uname(const struct page *page)           \
 }                                                                      \
 static __always_inline void __SetPage##uname(struct page *page)                \
 {                                                                      \
+       if (Page##uname(page))                                          \
+               return;                                                 \
        VM_BUG_ON_PAGE(data_race(page->page_type) != UINT_MAX, page);   \
        page->page_type = (unsigned int)PGTY_##lname << 24;             \
 }                                                                      \
 static __always_inline void __ClearPage##uname(struct page *page)      \
 {                                                                      \
+       if (page->page_type == UINT_MAX)                                \
+               return;                                                 \
        VM_BUG_ON_PAGE(!Page##uname(page), page);                       \
        page->page_type = UINT_MAX;                                     \
 }