Merge branch 'akpm' (patches from Andrew)
[linux-2.6-microblaze.git] / mm / memcontrol.c
index 29459a6..605f671 100644 (file)
@@ -20,6 +20,9 @@
  * Lockless page tracking & accounting
  * Unified hierarchy configuration model
  * Copyright (C) 2015 Red Hat, Inc., Johannes Weiner
+ *
+ * Per memcg lru locking
+ * Copyright (C) 2020 Alibaba, Inc, Alex Shi
  */
 
 #include <linux/page_counter.h>
@@ -533,7 +536,7 @@ struct cgroup_subsys_state *mem_cgroup_css_from_page(struct page *page)
 {
        struct mem_cgroup *memcg;
 
-       memcg = page->mem_cgroup;
+       memcg = page_memcg(page);
 
        if (!memcg || !cgroup_subsys_on_dfl(memory_cgrp_subsys))
                memcg = root_mem_cgroup;
@@ -560,16 +563,7 @@ ino_t page_cgroup_ino(struct page *page)
        unsigned long ino = 0;
 
        rcu_read_lock();
-       memcg = page->mem_cgroup;
-
-       /*
-        * The lowest bit set means that memcg isn't a valid
-        * memcg pointer, but a obj_cgroups pointer.
-        * In this case the page is shared and doesn't belong
-        * to any specific memory cgroup.
-        */
-       if ((unsigned long) memcg & 0x1UL)
-               memcg = NULL;
+       memcg = page_memcg_check(page);
 
        while (memcg && !(memcg->css.flags & CSS_ONLINE))
                memcg = parent_mem_cgroup(memcg);
@@ -623,14 +617,9 @@ static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_node *mz,
                if (mz->usage_in_excess < mz_node->usage_in_excess) {
                        p = &(*p)->rb_left;
                        rightmost = false;
-               }
-
-               /*
-                * We can't avoid mem cgroups that are over their soft
-                * limit by the same amount
-                */
-               else if (mz->usage_in_excess >= mz_node->usage_in_excess)
+               } else {
                        p = &(*p)->rb_right;
+               }
        }
 
        if (rightmost)
@@ -858,7 +847,26 @@ void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
                __mod_memcg_lruvec_state(lruvec, idx, val);
 }
 
-void __mod_lruvec_slab_state(void *p, enum node_stat_item idx, int val)
+void __mod_lruvec_page_state(struct page *page, enum node_stat_item idx,
+                            int val)
+{
+       struct page *head = compound_head(page); /* rmap on tail pages */
+       struct mem_cgroup *memcg = page_memcg(head);
+       pg_data_t *pgdat = page_pgdat(page);
+       struct lruvec *lruvec;
+
+       /* Untracked pages have no memcg, no lruvec. Update only the node */
+       if (!memcg) {
+               __mod_node_page_state(pgdat, idx, val);
+               return;
+       }
+
+       lruvec = mem_cgroup_lruvec(memcg, pgdat);
+       __mod_lruvec_state(lruvec, idx, val);
+}
+EXPORT_SYMBOL(__mod_lruvec_page_state);
+
+void __mod_lruvec_kmem_state(void *p, enum node_stat_item idx, int val)
 {
        pg_data_t *pgdat = page_pgdat(virt_to_page(p));
        struct mem_cgroup *memcg;
@@ -882,17 +890,6 @@ void __mod_lruvec_slab_state(void *p, enum node_stat_item idx, int val)
        rcu_read_unlock();
 }
 
-void mod_memcg_obj_state(void *p, int idx, int val)
-{
-       struct mem_cgroup *memcg;
-
-       rcu_read_lock();
-       memcg = mem_cgroup_from_obj(p);
-       if (memcg)
-               mod_memcg_state(memcg, idx, val);
-       rcu_read_unlock();
-}
-
 /**
  * __count_memcg_events - account VM events in a cgroup
  * @memcg: the memory cgroup
@@ -1055,7 +1052,7 @@ EXPORT_SYMBOL(get_mem_cgroup_from_mm);
  */
 struct mem_cgroup *get_mem_cgroup_from_page(struct page *page)
 {
-       struct mem_cgroup *memcg = page->mem_cgroup;
+       struct mem_cgroup *memcg = page_memcg(page);
 
        if (mem_cgroup_disabled())
                return NULL;
@@ -1157,12 +1154,6 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
        if (prev && !reclaim)
                pos = prev;
 
-       if (!root->use_hierarchy && root != root_mem_cgroup) {
-               if (prev)
-                       goto out;
-               return root;
-       }
-
        rcu_read_lock();
 
        if (reclaim) {
@@ -1242,7 +1233,6 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
 
 out_unlock:
        rcu_read_unlock();
-out:
        if (prev && prev != root)
                css_put(&prev->css);
 
@@ -1335,43 +1325,74 @@ int mem_cgroup_scan_tasks(struct mem_cgroup *memcg,
        return ret;
 }
 
+#ifdef CONFIG_DEBUG_VM
+void lruvec_memcg_debug(struct lruvec *lruvec, struct page *page)
+{
+       struct mem_cgroup *memcg;
+
+       if (mem_cgroup_disabled())
+               return;
+
+       memcg = page_memcg(page);
+
+       if (!memcg)
+               VM_BUG_ON_PAGE(lruvec_memcg(lruvec) != root_mem_cgroup, page);
+       else
+               VM_BUG_ON_PAGE(lruvec_memcg(lruvec) != memcg, page);
+}
+#endif
+
 /**
- * mem_cgroup_page_lruvec - return lruvec for isolating/putting an LRU page
+ * lock_page_lruvec - lock and return lruvec for a given page.
  * @page: the page
- * @pgdat: pgdat of the page
  *
- * This function relies on page->mem_cgroup being stable - see the
- * access rules in commit_charge().
+ * This series functions should be used in either conditions:
+ * PageLRU is cleared or unset
+ * or page->_refcount is zero
+ * or page is locked.
  */
-struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct pglist_data *pgdat)
+struct lruvec *lock_page_lruvec(struct page *page)
 {
-       struct mem_cgroup_per_node *mz;
-       struct mem_cgroup *memcg;
        struct lruvec *lruvec;
+       struct pglist_data *pgdat = page_pgdat(page);
 
-       if (mem_cgroup_disabled()) {
-               lruvec = &pgdat->__lruvec;
-               goto out;
-       }
+       rcu_read_lock();
+       lruvec = mem_cgroup_page_lruvec(page, pgdat);
+       spin_lock(&lruvec->lru_lock);
+       rcu_read_unlock();
 
-       memcg = page->mem_cgroup;
-       /*
-        * Swapcache readahead pages are added to the LRU - and
-        * possibly migrated - before they are charged.
-        */
-       if (!memcg)
-               memcg = root_mem_cgroup;
+       lruvec_memcg_debug(lruvec, page);
+
+       return lruvec;
+}
+
+struct lruvec *lock_page_lruvec_irq(struct page *page)
+{
+       struct lruvec *lruvec;
+       struct pglist_data *pgdat = page_pgdat(page);
+
+       rcu_read_lock();
+       lruvec = mem_cgroup_page_lruvec(page, pgdat);
+       spin_lock_irq(&lruvec->lru_lock);
+       rcu_read_unlock();
+
+       lruvec_memcg_debug(lruvec, page);
+
+       return lruvec;
+}
+
+struct lruvec *lock_page_lruvec_irqsave(struct page *page, unsigned long *flags)
+{
+       struct lruvec *lruvec;
+       struct pglist_data *pgdat = page_pgdat(page);
+
+       rcu_read_lock();
+       lruvec = mem_cgroup_page_lruvec(page, pgdat);
+       spin_lock_irqsave(&lruvec->lru_lock, *flags);
+       rcu_read_unlock();
+
+       lruvec_memcg_debug(lruvec, page);
 
-       mz = mem_cgroup_page_nodeinfo(memcg, page);
-       lruvec = &mz->lruvec;
-out:
-       /*
-        * Since a node can be onlined after the mem_cgroup was created,
-        * we have to be prepared to initialize lruvec->zone here;
-        * and if offlined then reonlined, we need to reinitialize it.
-        */
-       if (unlikely(lruvec->pgdat != pgdat))
-               lruvec->pgdat = pgdat;
        return lruvec;
 }
 
@@ -1499,6 +1520,7 @@ static struct memory_stat memory_stats[] = {
        { "anon", PAGE_SIZE, NR_ANON_MAPPED },
        { "file", PAGE_SIZE, NR_FILE_PAGES },
        { "kernel_stack", 1024, NR_KERNEL_STACK_KB },
+       { "pagetables", PAGE_SIZE, NR_PAGETABLE },
        { "percpu", 1, MEMCG_PERCPU_B },
        { "sock", PAGE_SIZE, MEMCG_SOCK },
        { "shmem", PAGE_SIZE, NR_SHMEM },
@@ -1512,6 +1534,8 @@ static struct memory_stat memory_stats[] = {
         * constant(e.g. powerpc).
         */
        { "anon_thp", 0, NR_ANON_THPS },
+       { "file_thp", 0, NR_FILE_THPS },
+       { "shmem_thp", 0, NR_SHMEM_THPS },
 #endif
        { "inactive_anon", PAGE_SIZE, NR_INACTIVE_ANON },
        { "active_anon", PAGE_SIZE, NR_ACTIVE_ANON },
@@ -1542,7 +1566,9 @@ static int __init memory_stats_init(void)
 
        for (i = 0; i < ARRAY_SIZE(memory_stats); i++) {
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               if (memory_stats[i].idx == NR_ANON_THPS)
+               if (memory_stats[i].idx == NR_ANON_THPS ||
+                   memory_stats[i].idx == NR_FILE_THPS ||
+                   memory_stats[i].idx == NR_SHMEM_THPS)
                        memory_stats[i].ratio = HPAGE_PMD_SIZE;
 #endif
                VM_BUG_ON(!memory_stats[i].ratio);
@@ -2114,7 +2140,7 @@ void mem_cgroup_print_oom_group(struct mem_cgroup *memcg)
 }
 
 /**
- * lock_page_memcg - lock a page->mem_cgroup binding
+ * lock_page_memcg - lock a page and memcg binding
  * @page: the page
  *
  * This function protects unlocked LRU pages from being moved to
@@ -2146,15 +2172,21 @@ struct mem_cgroup *lock_page_memcg(struct page *page)
        if (mem_cgroup_disabled())
                return NULL;
 again:
-       memcg = head->mem_cgroup;
+       memcg = page_memcg(head);
        if (unlikely(!memcg))
                return NULL;
 
+#ifdef CONFIG_PROVE_LOCKING
+       local_irq_save(flags);
+       might_lock(&memcg->move_lock);
+       local_irq_restore(flags);
+#endif
+
        if (atomic_read(&memcg->moving_account) <= 0)
                return memcg;
 
        spin_lock_irqsave(&memcg->move_lock, flags);
-       if (memcg != head->mem_cgroup) {
+       if (memcg != page_memcg(head)) {
                spin_unlock_irqrestore(&memcg->move_lock, flags);
                goto again;
        }
@@ -2192,14 +2224,14 @@ void __unlock_page_memcg(struct mem_cgroup *memcg)
 }
 
 /**
- * unlock_page_memcg - unlock a page->mem_cgroup binding
+ * unlock_page_memcg - unlock a page and memcg binding
  * @page: the page
  */
 void unlock_page_memcg(struct page *page)
 {
        struct page *head = compound_head(page);
 
-       __unlock_page_memcg(head->mem_cgroup);
+       __unlock_page_memcg(page_memcg(head));
 }
 EXPORT_SYMBOL(unlock_page_memcg);
 
@@ -2889,16 +2921,16 @@ static void cancel_charge(struct mem_cgroup *memcg, unsigned int nr_pages)
 
 static void commit_charge(struct page *page, struct mem_cgroup *memcg)
 {
-       VM_BUG_ON_PAGE(page->mem_cgroup, page);
+       VM_BUG_ON_PAGE(page_memcg(page), page);
        /*
-        * Any of the following ensures page->mem_cgroup stability:
+        * Any of the following ensures page's memcg stability:
         *
         * - the page lock
         * - LRU isolation
         * - lock_page_memcg()
         * - exclusive reference
         */
-       page->mem_cgroup = memcg;
+       page->memcg_data = (unsigned long)memcg;
 }
 
 #ifdef CONFIG_MEMCG_KMEM
@@ -2913,8 +2945,7 @@ int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s,
        if (!vec)
                return -ENOMEM;
 
-       if (cmpxchg(&page->obj_cgroups, NULL,
-                   (struct obj_cgroup **) ((unsigned long)vec | 0x1UL)))
+       if (!set_page_objcgs(page, vec))
                kfree(vec);
        else
                kmemleak_not_leak(vec);
@@ -2925,6 +2956,12 @@ int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s,
 /*
  * Returns a pointer to the memory cgroup to which the kernel object is charged.
  *
+ * A passed kernel object can be a slab object or a generic kernel page, so
+ * different mechanisms for getting the memory cgroup pointer should be used.
+ * In certain cases (e.g. kernel stacks or large kmallocs with SLUB) the caller
+ * can not know for sure how the kernel object is implemented.
+ * mem_cgroup_from_obj() can be safely used in such cases.
+ *
  * The caller must ensure the memcg lifetime, e.g. by taking rcu_read_lock(),
  * cgroup_mutex, etc.
  */
@@ -2937,36 +2974,31 @@ struct mem_cgroup *mem_cgroup_from_obj(void *p)
 
        page = virt_to_head_page(p);
 
-       /*
-        * If page->mem_cgroup is set, it's either a simple mem_cgroup pointer
-        * or a pointer to obj_cgroup vector. In the latter case the lowest
-        * bit of the pointer is set.
-        * The page->mem_cgroup pointer can be asynchronously changed
-        * from NULL to (obj_cgroup_vec | 0x1UL), but can't be changed
-        * from a valid memcg pointer to objcg vector or back.
-        */
-       if (!page->mem_cgroup)
-               return NULL;
-
        /*
         * Slab objects are accounted individually, not per-page.
         * Memcg membership data for each individual object is saved in
         * the page->obj_cgroups.
         */
-       if (page_has_obj_cgroups(page)) {
+       if (page_objcgs_check(page)) {
                struct obj_cgroup *objcg;
                unsigned int off;
 
                off = obj_to_index(page->slab_cache, page, p);
-               objcg = page_obj_cgroups(page)[off];
+               objcg = page_objcgs(page)[off];
                if (objcg)
                        return obj_cgroup_memcg(objcg);
 
                return NULL;
        }
 
-       /* All other pages use page->mem_cgroup */
-       return page->mem_cgroup;
+       /*
+        * page_memcg_check() is used here, because page_has_obj_cgroups()
+        * check above could fail because the object cgroups vector wasn't set
+        * at that moment, but it can be set concurrently.
+        * page_memcg_check(page) will guarantee that a proper memory
+        * cgroup pointer or NULL will be returned.
+        */
+       return page_memcg_check(page);
 }
 
 __always_inline struct obj_cgroup *get_obj_cgroup_from_current(void)
@@ -2987,6 +3019,7 @@ __always_inline struct obj_cgroup *get_obj_cgroup_from_current(void)
                objcg = rcu_dereference(memcg->objcg);
                if (objcg && obj_cgroup_tryget(objcg))
                        break;
+               objcg = NULL;
        }
        rcu_read_unlock();
 
@@ -3104,8 +3137,8 @@ int __memcg_kmem_charge_page(struct page *page, gfp_t gfp, int order)
        if (memcg && !mem_cgroup_is_root(memcg)) {
                ret = __memcg_kmem_charge(memcg, gfp, 1 << order);
                if (!ret) {
-                       page->mem_cgroup = memcg;
-                       __SetPageKmemcg(page);
+                       page->memcg_data = (unsigned long)memcg |
+                               MEMCG_DATA_KMEM;
                        return 0;
                }
                css_put(&memcg->css);
@@ -3120,7 +3153,7 @@ int __memcg_kmem_charge_page(struct page *page, gfp_t gfp, int order)
  */
 void __memcg_kmem_uncharge_page(struct page *page, int order)
 {
-       struct mem_cgroup *memcg = page->mem_cgroup;
+       struct mem_cgroup *memcg = page_memcg(page);
        unsigned int nr_pages = 1 << order;
 
        if (!memcg)
@@ -3128,12 +3161,8 @@ void __memcg_kmem_uncharge_page(struct page *page, int order)
 
        VM_BUG_ON_PAGE(mem_cgroup_is_root(memcg), page);
        __memcg_kmem_uncharge(memcg, nr_pages);
-       page->mem_cgroup = NULL;
+       page->memcg_data = 0;
        css_put(&memcg->css);
-
-       /* slab pages do not have PageKmemcg flag set */
-       if (PageKmemcg(page))
-               __ClearPageKmemcg(page);
 }
 
 static bool consume_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes)
@@ -3246,8 +3275,10 @@ int obj_cgroup_charge(struct obj_cgroup *objcg, gfp_t gfp, size_t size)
         * independently later.
         */
        rcu_read_lock();
+retry:
        memcg = obj_cgroup_memcg(objcg);
-       css_get(&memcg->css);
+       if (unlikely(!css_tryget(&memcg->css)))
+               goto retry;
        rcu_read_unlock();
 
        nr_pages = size >> PAGE_SHIFT;
@@ -3272,14 +3303,12 @@ void obj_cgroup_uncharge(struct obj_cgroup *objcg, size_t size)
 #endif /* CONFIG_MEMCG_KMEM */
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-
 /*
- * Because tail pages are not marked as "used", set it. We're under
- * pgdat->lru_lock and migration entries setup in all page mappings.
+ * Because page_memcg(head) is not set on compound tails, set it now.
  */
 void mem_cgroup_split_huge_fixup(struct page *head)
 {
-       struct mem_cgroup *memcg = head->mem_cgroup;
+       struct mem_cgroup *memcg = page_memcg(head);
        int i;
 
        if (mem_cgroup_disabled())
@@ -3287,7 +3316,7 @@ void mem_cgroup_split_huge_fixup(struct page *head)
 
        for (i = 1; i < HPAGE_PMD_NR; i++) {
                css_get(&memcg->css);
-               head[i].mem_cgroup = memcg;
+               head[i].memcg_data = (unsigned long)memcg;
        }
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
@@ -3469,22 +3498,6 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
        return nr_reclaimed;
 }
 
-/*
- * Test whether @memcg has children, dead or alive.  Note that this
- * function doesn't care whether @memcg has use_hierarchy enabled and
- * returns %true if there are child csses according to the cgroup
- * hierarchy.  Testing use_hierarchy is the caller's responsibility.
- */
-static inline bool memcg_has_children(struct mem_cgroup *memcg)
-{
-       bool ret;
-
-       rcu_read_lock();
-       ret = css_next_child(NULL, &memcg->css);
-       rcu_read_unlock();
-       return ret;
-}
-
 /*
  * Reclaims as many pages from the given memcg as possible.
  *
@@ -3533,37 +3546,20 @@ static ssize_t mem_cgroup_force_empty_write(struct kernfs_open_file *of,
 static u64 mem_cgroup_hierarchy_read(struct cgroup_subsys_state *css,
                                     struct cftype *cft)
 {
-       return mem_cgroup_from_css(css)->use_hierarchy;
+       return 1;
 }
 
 static int mem_cgroup_hierarchy_write(struct cgroup_subsys_state *css,
                                      struct cftype *cft, u64 val)
 {
-       int retval = 0;
-       struct mem_cgroup *memcg = mem_cgroup_from_css(css);
-       struct mem_cgroup *parent_memcg = mem_cgroup_from_css(memcg->css.parent);
-
-       if (memcg->use_hierarchy == val)
+       if (val == 1)
                return 0;
 
-       /*
-        * If parent's use_hierarchy is set, we can't make any modifications
-        * in the child subtrees. If it is unset, then the change can
-        * occur, provided the current cgroup has no children.
-        *
-        * For the root cgroup, parent_mem is NULL, we allow value to be
-        * set if there are no children.
-        */
-       if ((!parent_memcg || !parent_memcg->use_hierarchy) &&
-                               (val == 1 || val == 0)) {
-               if (!memcg_has_children(memcg))
-                       memcg->use_hierarchy = val;
-               else
-                       retval = -EBUSY;
-       } else
-               retval = -EINVAL;
+       pr_warn_once("Non-hierarchical mode is deprecated. "
+                    "Please report your usecase to linux-mm@kvack.org if you "
+                    "depend on this functionality.\n");
 
-       return retval;
+       return -EINVAL;
 }
 
 static unsigned long mem_cgroup_usage(struct mem_cgroup *memcg, bool swap)
@@ -3712,12 +3708,6 @@ static int memcg_online_kmem(struct mem_cgroup *memcg)
 
        static_branch_enable(&memcg_kmem_enabled_key);
 
-       /*
-        * A memory cgroup is considered kmem-online as soon as it gets
-        * kmemcg_id. Setting the id after enabling static branching will
-        * guarantee no one starts accounting before all call sites are
-        * patched.
-        */
        memcg->kmemcg_id = memcg_id;
        memcg->kmem_state = KMEM_ONLINE;
 
@@ -3757,8 +3747,6 @@ static void memcg_offline_kmem(struct mem_cgroup *memcg)
                child = mem_cgroup_from_css(css);
                BUG_ON(child->kmemcg_id != kmemcg_id);
                child->kmemcg_id = parent->kmemcg_id;
-               if (!memcg->use_hierarchy)
-                       break;
        }
        rcu_read_unlock();
 
@@ -4669,7 +4657,7 @@ void mem_cgroup_wb_stats(struct bdi_writeback *wb, unsigned long *pfilepages,
 void mem_cgroup_track_foreign_dirty_slowpath(struct page *page,
                                             struct bdi_writeback *wb)
 {
-       struct mem_cgroup *memcg = page->mem_cgroup;
+       struct mem_cgroup *memcg = page_memcg(page);
        struct memcg_cgwb_frn *frn;
        u64 now = get_jiffies_64();
        u64 oldest_at = now;
@@ -5349,38 +5337,22 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
        if (parent) {
                memcg->swappiness = mem_cgroup_swappiness(parent);
                memcg->oom_kill_disable = parent->oom_kill_disable;
-       }
-       if (!parent) {
-               page_counter_init(&memcg->memory, NULL);
-               page_counter_init(&memcg->swap, NULL);
-               page_counter_init(&memcg->kmem, NULL);
-               page_counter_init(&memcg->tcpmem, NULL);
-       } else if (parent->use_hierarchy) {
-               memcg->use_hierarchy = true;
+
                page_counter_init(&memcg->memory, &parent->memory);
                page_counter_init(&memcg->swap, &parent->swap);
                page_counter_init(&memcg->kmem, &parent->kmem);
                page_counter_init(&memcg->tcpmem, &parent->tcpmem);
        } else {
-               page_counter_init(&memcg->memory, &root_mem_cgroup->memory);
-               page_counter_init(&memcg->swap, &root_mem_cgroup->swap);
-               page_counter_init(&memcg->kmem, &root_mem_cgroup->kmem);
-               page_counter_init(&memcg->tcpmem, &root_mem_cgroup->tcpmem);
-               /*
-                * Deeper hierachy with use_hierarchy == false doesn't make
-                * much sense so let cgroup subsystem know about this
-                * unfortunate state in our controller.
-                */
-               if (parent != root_mem_cgroup)
-                       memory_cgrp_subsys.broken_hierarchy = true;
-       }
+               page_counter_init(&memcg->memory, NULL);
+               page_counter_init(&memcg->swap, NULL);
+               page_counter_init(&memcg->kmem, NULL);
+               page_counter_init(&memcg->tcpmem, NULL);
 
-       /* The following stuff does not apply to the root */
-       if (!parent) {
                root_mem_cgroup = memcg;
                return &memcg->css;
        }
 
+       /* The following stuff does not apply to the root */
        error = memcg_online_kmem(memcg);
        if (error)
                goto fail;
@@ -5646,14 +5618,14 @@ static int mem_cgroup_move_account(struct page *page,
 
        /*
         * Prevent mem_cgroup_migrate() from looking at
-        * page->mem_cgroup of its source page while we change it.
+        * page's memory cgroup of its source page while we change it.
         */
        ret = -EBUSY;
        if (!trylock_page(page))
                goto out;
 
        ret = -EINVAL;
-       if (page->mem_cgroup != from)
+       if (page_memcg(page) != from)
                goto out_unlock;
 
        pgdat = page_pgdat(page);
@@ -5708,13 +5680,13 @@ static int mem_cgroup_move_account(struct page *page,
        /*
         * All state has been migrated, let's switch to the new memcg.
         *
-        * It is safe to change page->mem_cgroup here because the page
+        * It is safe to change page's memcg here because the page
         * is referenced, charged, isolated, and locked: we can't race
         * with (un)charging, migration, LRU putback, or anything else
-        * that would rely on a stable page->mem_cgroup.
+        * that would rely on a stable page's memory cgroup.
         *
         * Note that lock_page_memcg is a memcg lock, not a page lock,
-        * to save space. As soon as we switch page->mem_cgroup to a
+        * to save space. As soon as we switch page's memory cgroup to a
         * new memcg that isn't locked, the above state can change
         * concurrently again. Make sure we're truly done with it.
         */
@@ -5723,7 +5695,7 @@ static int mem_cgroup_move_account(struct page *page,
        css_get(&to->css);
        css_put(&from->css);
 
-       page->mem_cgroup = to;
+       page->memcg_data = (unsigned long)to;
 
        __unlock_page_memcg(from);
 
@@ -5789,7 +5761,7 @@ static enum mc_target_type get_mctgt_type(struct vm_area_struct *vma,
                 * mem_cgroup_move_account() checks the page is valid or
                 * not under LRU exclusion.
                 */
-               if (page->mem_cgroup == mc.from) {
+               if (page_memcg(page) == mc.from) {
                        ret = MC_TARGET_PAGE;
                        if (is_device_private_page(page))
                                ret = MC_TARGET_DEVICE;
@@ -5833,7 +5805,7 @@ static enum mc_target_type get_mctgt_type_thp(struct vm_area_struct *vma,
        VM_BUG_ON_PAGE(!page || !PageHead(page), page);
        if (!(mc.flags & MOVE_ANON))
                return ret;
-       if (page->mem_cgroup == mc.from) {
+       if (page_memcg(page) == mc.from) {
                ret = MC_TARGET_PAGE;
                if (target) {
                        get_page(page);
@@ -6217,24 +6189,6 @@ static void mem_cgroup_move_task(void)
 }
 #endif
 
-/*
- * Cgroup retains root cgroups across [un]mount cycles making it necessary
- * to verify whether we're attached to the default hierarchy on each mount
- * attempt.
- */
-static void mem_cgroup_bind(struct cgroup_subsys_state *root_css)
-{
-       /*
-        * use_hierarchy is forced on the default hierarchy.  cgroup core
-        * guarantees that @root doesn't have any children, so turning it
-        * on for the root memcg is enough.
-        */
-       if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
-               root_mem_cgroup->use_hierarchy = true;
-       else
-               root_mem_cgroup->use_hierarchy = false;
-}
-
 static int seq_puts_memcg_tunable(struct seq_file *m, unsigned long value)
 {
        if (value == PAGE_COUNTER_MAX)
@@ -6572,7 +6526,6 @@ struct cgroup_subsys memory_cgrp_subsys = {
        .can_attach = mem_cgroup_can_attach,
        .cancel_attach = mem_cgroup_cancel_attach,
        .post_attach = mem_cgroup_move_task,
-       .bind = mem_cgroup_bind,
        .dfl_cftypes = memory_files,
        .legacy_cftypes = mem_cgroup_legacy_files,
        .early_init = 0,
@@ -6779,12 +6732,12 @@ int mem_cgroup_charge(struct page *page, struct mm_struct *mm, gfp_t gfp_mask)
                /*
                 * Every swap fault against a single page tries to charge the
                 * page, bail as early as possible.  shmem_unuse() encounters
-                * already charged pages, too.  page->mem_cgroup is protected
-                * by the page lock, which serializes swap cache removal, which
-                * in turn serializes uncharging.
+                * already charged pages, too.  page and memcg binding is
+                * protected by the page lock, which serializes swap cache
+                * removal, which in turn serializes uncharging.
                 */
                VM_BUG_ON_PAGE(!PageLocked(page), page);
-               if (compound_head(page)->mem_cgroup)
+               if (page_memcg(compound_head(page)))
                        goto out;
 
                id = lookup_swap_cgroup_id(ent);
@@ -6868,21 +6821,21 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
 
        VM_BUG_ON_PAGE(PageLRU(page), page);
 
-       if (!page->mem_cgroup)
+       if (!page_memcg(page))
                return;
 
        /*
         * Nobody should be changing or seriously looking at
-        * page->mem_cgroup at this point, we have fully
+        * page_memcg(page) at this point, we have fully
         * exclusive access to the page.
         */
 
-       if (ug->memcg != page->mem_cgroup) {
+       if (ug->memcg != page_memcg(page)) {
                if (ug->memcg) {
                        uncharge_batch(ug);
                        uncharge_gather_clear(ug);
                }
-               ug->memcg = page->mem_cgroup;
+               ug->memcg = page_memcg(page);
 
                /* pairs with css_put in uncharge_batch */
                css_get(&ug->memcg->css);
@@ -6891,15 +6844,13 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
        nr_pages = compound_nr(page);
        ug->nr_pages += nr_pages;
 
-       if (!PageKmemcg(page)) {
-               ug->pgpgout++;
-       } else {
+       if (PageMemcgKmem(page))
                ug->nr_kmem += nr_pages;
-               __ClearPageKmemcg(page);
-       }
+       else
+               ug->pgpgout++;
 
        ug->dummy_page = page;
-       page->mem_cgroup = NULL;
+       page->memcg_data = 0;
        css_put(&ug->memcg->css);
 }
 
@@ -6942,7 +6893,7 @@ void mem_cgroup_uncharge(struct page *page)
                return;
 
        /* Don't touch page->lru of any random page, pre-check: */
-       if (!page->mem_cgroup)
+       if (!page_memcg(page))
                return;
 
        uncharge_gather_clear(&ug);
@@ -6992,11 +6943,11 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage)
                return;
 
        /* Page cache replacement: new page already charged? */
-       if (newpage->mem_cgroup)
+       if (page_memcg(newpage))
                return;
 
-       /* Swapcache readahead pages can get replaced before being charged */
-       memcg = oldpage->mem_cgroup;
+       memcg = page_memcg(oldpage);
+       VM_WARN_ON_ONCE_PAGE(!memcg, oldpage);
        if (!memcg)
                return;
 
@@ -7188,12 +7139,15 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
        VM_BUG_ON_PAGE(PageLRU(page), page);
        VM_BUG_ON_PAGE(page_count(page), page);
 
+       if (mem_cgroup_disabled())
+               return;
+
        if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
                return;
 
-       memcg = page->mem_cgroup;
+       memcg = page_memcg(page);
 
-       /* Readahead page, never charged */
+       VM_WARN_ON_ONCE_PAGE(!memcg, page);
        if (!memcg)
                return;
 
@@ -7212,7 +7166,7 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
        VM_BUG_ON_PAGE(oldid, page);
        mod_memcg_state(swap_memcg, MEMCG_SWAP, nr_entries);
 
-       page->mem_cgroup = NULL;
+       page->memcg_data = 0;
 
        if (!mem_cgroup_is_root(memcg))
                page_counter_uncharge(&memcg->memory, nr_entries);
@@ -7252,12 +7206,15 @@ int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry)
        struct mem_cgroup *memcg;
        unsigned short oldid;
 
+       if (mem_cgroup_disabled())
+               return 0;
+
        if (!cgroup_subsys_on_dfl(memory_cgrp_subsys))
                return 0;
 
-       memcg = page->mem_cgroup;
+       memcg = page_memcg(page);
 
-       /* Readahead page, never charged */
+       VM_WARN_ON_ONCE_PAGE(!memcg, page);
        if (!memcg)
                return 0;
 
@@ -7336,7 +7293,7 @@ bool mem_cgroup_swap_full(struct page *page)
        if (cgroup_memory_noswap || !cgroup_subsys_on_dfl(memory_cgrp_subsys))
                return false;
 
-       memcg = page->mem_cgroup;
+       memcg = page_memcg(page);
        if (!memcg)
                return false;
 
@@ -7354,9 +7311,9 @@ bool mem_cgroup_swap_full(struct page *page)
 static int __init setup_swap_account(char *s)
 {
        if (!strcmp(s, "1"))
-               cgroup_memory_noswap = 0;
+               cgroup_memory_noswap = false;
        else if (!strcmp(s, "0"))
-               cgroup_memory_noswap = 1;
+               cgroup_memory_noswap = true;
        return 1;
 }
 __setup("swapaccount=", setup_swap_account);