]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
slab: Reimplement page_slab()
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Thu, 13 Nov 2025 00:09:15 +0000 (00:09 +0000)
committerVlastimil Babka <vbabka@suse.cz>
Thu, 13 Nov 2025 10:01:08 +0000 (11:01 +0100)
In order to separate slabs from folios, we need to convert from any page
in a slab to the slab directly without going through a page to folio
conversion first.

Up to this point, page_slab() has followed the example of other memdesc
converters (page_folio(), page_ptdesc() etc) and just cast the pointer
to the requested type, regardless of whether the pointer is actually a
pointer to the correct type or not.

That changes with this commit; we check that the page actually belongs
to a slab and return NULL if it does not.  Other memdesc converters will
adopt this convention in future.

kfence was the only user of page_slab(), so adjust it to the new way
of working.  It will need to be touched again when we separate slab
from page.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Alexander Potapenko <glider@google.com>
Cc: Marco Elver <elver@google.com>
Cc: kasan-dev@googlegroups.com
Link: https://patch.msgid.link/20251113000932.1589073-2-willy@infradead.org
Acked-by: David Hildenbrand (Red Hat) <david@kernel.org>
Tested-by: Marco Elver <elver@google.com>
Reviewed-by: Harry Yoo <harry.yoo@oracle.com>
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
include/linux/page-flags.h
mm/kfence/core.c
mm/slab.h

index 0091ad1986bf777c19b434df4f5888c59e408893..6d5e44968eab0a80927f27e9819274f40a9aa1b1 100644 (file)
@@ -1048,19 +1048,7 @@ PAGE_TYPE_OPS(Table, table, pgtable)
  */
 PAGE_TYPE_OPS(Guard, guard, guard)
 
-FOLIO_TYPE_OPS(slab, slab)
-
-/**
- * PageSlab - Determine if the page belongs to the slab allocator
- * @page: The page to test.
- *
- * Context: Any context.
- * Return: True for slab pages, false for any other kind of page.
- */
-static inline bool PageSlab(const struct page *page)
-{
-       return folio_test_slab(page_folio(page));
-}
+PAGE_TYPE_OPS(Slab, slab, slab)
 
 #ifdef CONFIG_HUGETLB_PAGE
 FOLIO_TYPE_OPS(hugetlb, hugetlb)
index 727c20c94ac5964f0ad8a13e47d525be6122015c..e62b5516bf489f752d6e0a397465a9d777e4039a 100644 (file)
@@ -612,14 +612,15 @@ static unsigned long kfence_init_pool(void)
         * enters __slab_free() slow-path.
         */
        for (i = 0; i < KFENCE_POOL_SIZE / PAGE_SIZE; i++) {
-               struct slab *slab;
+               struct page *page;
 
                if (!i || (i % 2))
                        continue;
 
-               slab = page_slab(pfn_to_page(start_pfn + i));
-               __folio_set_slab(slab_folio(slab));
+               page = pfn_to_page(start_pfn + i);
+               __SetPageSlab(page);
 #ifdef CONFIG_MEMCG
+               struct slab *slab = page_slab(page);
                slab->obj_exts = (unsigned long)&kfence_metadata_init[i / 2 - 1].obj_exts |
                                 MEMCG_DATA_OBJEXTS;
 #endif
@@ -665,16 +666,17 @@ static unsigned long kfence_init_pool(void)
 
 reset_slab:
        for (i = 0; i < KFENCE_POOL_SIZE / PAGE_SIZE; i++) {
-               struct slab *slab;
+               struct page *page;
 
                if (!i || (i % 2))
                        continue;
 
-               slab = page_slab(pfn_to_page(start_pfn + i));
+               page = pfn_to_page(start_pfn + i);
 #ifdef CONFIG_MEMCG
+               struct slab *slab = page_slab(page);
                slab->obj_exts = 0;
 #endif
-               __folio_clear_slab(slab_folio(slab));
+               __ClearPageSlab(page);
        }
 
        return addr;
index 078daecc7cf50a0c01aca3c3c9c866dc8b1a756d..a64b9b2c873160cb850efc657cd9be300198c0ea 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -146,20 +146,24 @@ static_assert(IS_ALIGNED(offsetof(struct slab, freelist), sizeof(freelist_aba_t)
        struct slab *:          (struct folio *)s))
 
 /**
- * page_slab - Converts from first struct page to slab.
- * @p: The first (either head of compound or single) page of slab.
+ * page_slab - Converts from struct page to its slab.
+ * @page: A page which may or may not belong to a slab.
  *
- * A temporary wrapper to convert struct page to struct slab in situations where
- * we know the page is the compound head, or single order-0 page.
- *
- * Long-term ideally everything would work with struct slab directly or go
- * through folio to struct slab.
- *
- * Return: The slab which contains this page
+ * Return: The slab which contains this page or NULL if the page does
+ * not belong to a slab.  This includes pages returned from large kmalloc.
  */
-#define page_slab(p)           (_Generic((p),                          \
-       const struct page *:    (const struct slab *)(p),               \
-       struct page *:          (struct slab *)(p)))
+static inline struct slab *page_slab(const struct page *page)
+{
+       unsigned long head;
+
+       head = READ_ONCE(page->compound_head);
+       if (head & 1)
+               page = (struct page *)(head - 1);
+       if (data_race(page->page_type >> 24) != PGTY_slab)
+               page = NULL;
+
+       return (struct slab *)page;
+}
 
 /**
  * slab_page - The first struct page allocated for a slab