mm/memcg: Add folio_memcg() and related functions
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Mon, 28 Jun 2021 18:59:26 +0000 (14:59 -0400)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Mon, 27 Sep 2021 13:27:31 +0000 (09:27 -0400)
memcg information is only stored in the head page, so the memcg
subsystem needs to assure that all accesses are to the head page.
The first step is converting page_memcg() to folio_memcg().

The callers of page_memcg() and PageMemcgKmem() are not yet ready to be
converted to use folios, so retain them as wrappers around folio_memcg()
and folio_memcg_kmem().  They will be converted in a later patch set.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: David Howells <dhowells@redhat.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
include/linux/memcontrol.h
mm/memcontrol.c

index 3096c9a..0665967 100644 (file)
@@ -369,7 +369,7 @@ enum page_memcg_data_flags {
 
 #define MEMCG_DATA_FLAGS_MASK (__NR_MEMCG_DATA_FLAGS - 1)
 
-static inline bool PageMemcgKmem(struct page *page);
+static inline bool folio_memcg_kmem(struct folio *folio);
 
 /*
  * After the initialization objcg->memcg is always pointing at
@@ -384,73 +384,77 @@ static inline struct mem_cgroup *obj_cgroup_memcg(struct obj_cgroup *objcg)
 }
 
 /*
- * __page_memcg - get the memory cgroup associated with a non-kmem page
- * @page: a pointer to the page struct
+ * __folio_memcg - Get the memory cgroup associated with a non-kmem folio
+ * @folio: Pointer to the folio.
  *
- * Returns a pointer to the memory cgroup associated with the page,
- * or NULL. This function assumes that the page is known to have a
+ * Returns a pointer to the memory cgroup associated with the folio,
+ * or NULL. This function assumes that the folio is known to have a
  * proper memory cgroup pointer. It's not safe to call this function
- * against some type of pages, e.g. slab pages or ex-slab pages or
- * kmem pages.
+ * against some type of folios, e.g. slab folios or ex-slab folios or
+ * kmem folios.
  */
-static inline struct mem_cgroup *__page_memcg(struct page *page)
+static inline struct mem_cgroup *__folio_memcg(struct folio *folio)
 {
-       unsigned long memcg_data = page->memcg_data;
+       unsigned long memcg_data = folio->memcg_data;
 
-       VM_BUG_ON_PAGE(PageSlab(page), page);
-       VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_OBJCGS, page);
-       VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_KMEM, page);
+       VM_BUG_ON_FOLIO(folio_test_slab(folio), folio);
+       VM_BUG_ON_FOLIO(memcg_data & MEMCG_DATA_OBJCGS, folio);
+       VM_BUG_ON_FOLIO(memcg_data & MEMCG_DATA_KMEM, folio);
 
        return (struct mem_cgroup *)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
 }
 
 /*
- * __page_objcg - get the object cgroup associated with a kmem page
- * @page: a pointer to the page struct
+ * __folio_objcg - get the object cgroup associated with a kmem folio.
+ * @folio: Pointer to the folio.
  *
- * Returns a pointer to the object cgroup associated with the page,
- * or NULL. This function assumes that the page is known to have a
+ * Returns a pointer to the object cgroup associated with the folio,
+ * or NULL. This function assumes that the folio is known to have a
  * proper object cgroup pointer. It's not safe to call this function
- * against some type of pages, e.g. slab pages or ex-slab pages or
- * LRU pages.
+ * against some type of folios, e.g. slab folios or ex-slab folios or
+ * LRU folios.
  */
-static inline struct obj_cgroup *__page_objcg(struct page *page)
+static inline struct obj_cgroup *__folio_objcg(struct folio *folio)
 {
-       unsigned long memcg_data = page->memcg_data;
+       unsigned long memcg_data = folio->memcg_data;
 
-       VM_BUG_ON_PAGE(PageSlab(page), page);
-       VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_OBJCGS, page);
-       VM_BUG_ON_PAGE(!(memcg_data & MEMCG_DATA_KMEM), page);
+       VM_BUG_ON_FOLIO(folio_test_slab(folio), folio);
+       VM_BUG_ON_FOLIO(memcg_data & MEMCG_DATA_OBJCGS, folio);
+       VM_BUG_ON_FOLIO(!(memcg_data & MEMCG_DATA_KMEM), folio);
 
        return (struct obj_cgroup *)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
 }
 
 /*
- * page_memcg - get the memory cgroup associated with a page
- * @page: a pointer to the page struct
+ * folio_memcg - Get the memory cgroup associated with a folio.
+ * @folio: Pointer to the folio.
  *
- * Returns a pointer to the memory cgroup associated with the page,
- * or NULL. This function assumes that the page is known to have a
+ * Returns a pointer to the memory cgroup associated with the folio,
+ * or NULL. This function assumes that the folio is known to have a
  * proper memory cgroup pointer. It's not safe to call this function
- * against some type of pages, e.g. slab pages or ex-slab pages.
+ * against some type of folios, e.g. slab folios or ex-slab folios.
  *
- * For a non-kmem page any of the following ensures page and memcg binding
+ * For a non-kmem folio any of the following ensures folio and memcg binding
  * stability:
  *
- * - the page lock
+ * - the folio lock
  * - LRU isolation
  * - lock_page_memcg()
  * - exclusive reference
  *
- * For a kmem page a caller should hold an rcu read lock to protect memcg
- * associated with a kmem page from being released.
+ * For a kmem folio a caller should hold an rcu read lock to protect memcg
+ * associated with a kmem folio from being released.
  */
+static inline struct mem_cgroup *folio_memcg(struct folio *folio)
+{
+       if (folio_memcg_kmem(folio))
+               return obj_cgroup_memcg(__folio_objcg(folio));
+       return __folio_memcg(folio);
+}
+
 static inline struct mem_cgroup *page_memcg(struct page *page)
 {
-       if (PageMemcgKmem(page))
-               return obj_cgroup_memcg(__page_objcg(page));
-       else
-               return __page_memcg(page);
+       return folio_memcg(page_folio(page));
 }
 
 /*
@@ -523,17 +527,18 @@ static inline struct mem_cgroup *page_memcg_check(struct page *page)
 
 #ifdef CONFIG_MEMCG_KMEM
 /*
- * PageMemcgKmem - check if the page has MemcgKmem flag set
- * @page: a pointer to the page struct
+ * folio_memcg_kmem - Check if the folio has the memcg_kmem flag set.
+ * @folio: Pointer to the folio.
  *
- * Checks if the page has MemcgKmem flag set. The caller must ensure that
- * the page has an associated memory cgroup. It's not safe to call this function
- * against some types of pages, e.g. slab pages.
+ * Checks if the folio has MemcgKmem flag set. The caller must ensure
+ * that the folio has an associated memory cgroup. It's not safe to call
+ * this function against some types of folios, e.g. slab folios.
  */
-static inline bool PageMemcgKmem(struct page *page)
+static inline bool folio_memcg_kmem(struct folio *folio)
 {
-       VM_BUG_ON_PAGE(page->memcg_data & MEMCG_DATA_OBJCGS, page);
-       return page->memcg_data & MEMCG_DATA_KMEM;
+       VM_BUG_ON_PGFLAGS(PageTail(&folio->page), &folio->page);
+       VM_BUG_ON_FOLIO(folio->memcg_data & MEMCG_DATA_OBJCGS, folio);
+       return folio->memcg_data & MEMCG_DATA_KMEM;
 }
 
 /*
@@ -577,7 +582,7 @@ static inline struct obj_cgroup **page_objcgs_check(struct page *page)
 }
 
 #else
-static inline bool PageMemcgKmem(struct page *page)
+static inline bool folio_memcg_kmem(struct folio *folio)
 {
        return false;
 }
@@ -593,6 +598,11 @@ static inline struct obj_cgroup **page_objcgs_check(struct page *page)
 }
 #endif
 
+static inline bool PageMemcgKmem(struct page *page)
+{
+       return folio_memcg_kmem(page_folio(page));
+}
+
 static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg)
 {
        return (memcg == root_mem_cgroup);
@@ -1115,6 +1125,11 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
 #define MEM_CGROUP_ID_SHIFT    0
 #define MEM_CGROUP_ID_MAX      0
 
+static inline struct mem_cgroup *folio_memcg(struct folio *folio)
+{
+       return NULL;
+}
+
 static inline struct mem_cgroup *page_memcg(struct page *page)
 {
        return NULL;
@@ -1131,6 +1146,11 @@ static inline struct mem_cgroup *page_memcg_check(struct page *page)
        return NULL;
 }
 
+static inline bool folio_memcg_kmem(struct folio *folio)
+{
+       return false;
+}
+
 static inline bool PageMemcgKmem(struct page *page)
 {
        return false;
index a064a85..1385ac6 100644 (file)
@@ -2992,15 +2992,16 @@ int __memcg_kmem_charge_page(struct page *page, gfp_t gfp, int order)
  */
 void __memcg_kmem_uncharge_page(struct page *page, int order)
 {
+       struct folio *folio = page_folio(page);
        struct obj_cgroup *objcg;
        unsigned int nr_pages = 1 << order;
 
-       if (!PageMemcgKmem(page))
+       if (!folio_memcg_kmem(folio))
                return;
 
-       objcg = __page_objcg(page);
+       objcg = __folio_objcg(folio);
        obj_cgroup_uncharge_pages(objcg, nr_pages);
-       page->memcg_data = 0;
+       folio->memcg_data = 0;
        obj_cgroup_put(objcg);
 }
 
@@ -3234,17 +3235,18 @@ void obj_cgroup_uncharge(struct obj_cgroup *objcg, size_t size)
  */
 void split_page_memcg(struct page *head, unsigned int nr)
 {
-       struct mem_cgroup *memcg = page_memcg(head);
+       struct folio *folio = page_folio(head);
+       struct mem_cgroup *memcg = folio_memcg(folio);
        int i;
 
        if (mem_cgroup_disabled() || !memcg)
                return;
 
        for (i = 1; i < nr; i++)
-               head[i].memcg_data = head->memcg_data;
+               folio_page(folio, i)->memcg_data = folio->memcg_data;
 
-       if (PageMemcgKmem(head))
-               obj_cgroup_get_many(__page_objcg(head), nr - 1);
+       if (folio_memcg_kmem(folio))
+               obj_cgroup_get_many(__folio_objcg(folio), nr - 1);
        else
                css_get_many(&memcg->css, nr - 1);
 }
@@ -6811,6 +6813,7 @@ static void uncharge_batch(const struct uncharge_gather *ug)
 
 static void uncharge_page(struct page *page, struct uncharge_gather *ug)
 {
+       struct folio *folio = page_folio(page);
        unsigned long nr_pages;
        struct mem_cgroup *memcg;
        struct obj_cgroup *objcg;
@@ -6824,14 +6827,14 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
         * exclusive access to the page.
         */
        if (use_objcg) {
-               objcg = __page_objcg(page);
+               objcg = __folio_objcg(folio);
                /*
                 * This get matches the put at the end of the function and
                 * kmem pages do not hold memcg references anymore.
                 */
                memcg = get_mem_cgroup_from_objcg(objcg);
        } else {
-               memcg = __page_memcg(page);
+               memcg = __folio_memcg(folio);
        }
 
        if (!memcg)