CIFS: Clarify SMB1 code for POSIX Lock
[linux-2.6-microblaze.git] / mm / memcontrol.c
index 64ada9e..4ee243c 100644 (file)
@@ -78,12 +78,13 @@ struct mem_cgroup *root_mem_cgroup __read_mostly;
 
 /* Active memory cgroup to use from an interrupt context */
 DEFINE_PER_CPU(struct mem_cgroup *, int_active_memcg);
+EXPORT_PER_CPU_SYMBOL_GPL(int_active_memcg);
 
 /* Socket memory accounting disabled? */
 static bool cgroup_memory_nosocket;
 
 /* Kernel memory accounting disabled? */
-static bool cgroup_memory_nokmem;
+bool cgroup_memory_nokmem;
 
 /* Whether the swap controller is active */
 #ifdef CONFIG_MEMCG_SWAP
@@ -261,7 +262,6 @@ static void obj_cgroup_uncharge_pages(struct obj_cgroup *objcg,
 static void obj_cgroup_release(struct percpu_ref *ref)
 {
        struct obj_cgroup *objcg = container_of(ref, struct obj_cgroup, refcnt);
-       struct mem_cgroup *memcg;
        unsigned int nr_bytes;
        unsigned int nr_pages;
        unsigned long flags;
@@ -290,12 +290,11 @@ static void obj_cgroup_release(struct percpu_ref *ref)
        WARN_ON_ONCE(nr_bytes & (PAGE_SIZE - 1));
        nr_pages = nr_bytes >> PAGE_SHIFT;
 
-       spin_lock_irqsave(&css_set_lock, flags);
-       memcg = obj_cgroup_memcg(objcg);
        if (nr_pages)
                obj_cgroup_uncharge_pages(objcg, nr_pages);
+
+       spin_lock_irqsave(&css_set_lock, flags);
        list_del(&objcg->list);
-       mem_cgroup_put(memcg);
        spin_unlock_irqrestore(&css_set_lock, flags);
 
        percpu_ref_exit(ref);
@@ -330,17 +329,12 @@ static void memcg_reparent_objcgs(struct mem_cgroup *memcg,
 
        spin_lock_irq(&css_set_lock);
 
-       /* Move active objcg to the parent's list */
-       xchg(&objcg->memcg, parent);
-       css_get(&parent->css);
-       list_add(&objcg->list, &parent->objcg_list);
-
-       /* Move already reparented objcgs to the parent's list */
-       list_for_each_entry(iter, &memcg->objcg_list, list) {
-               css_get(&parent->css);
-               xchg(&iter->memcg, parent);
-               css_put(&memcg->css);
-       }
+       /* 1) Ready to reparent active objcg. */
+       list_add(&objcg->list, &memcg->objcg_list);
+       /* 2) Reparent active objcg and already reparented objcgs to parent. */
+       list_for_each_entry(iter, &memcg->objcg_list, list)
+               WRITE_ONCE(iter->memcg, parent);
+       /* 3) Move already reparented objcgs to the parent's list */
        list_splice(&memcg->objcg_list, &parent->objcg_list);
 
        spin_unlock_irq(&css_set_lock);
@@ -782,6 +776,24 @@ void __mod_lruvec_kmem_state(void *p, enum node_stat_item idx, int val)
        rcu_read_unlock();
 }
 
+/*
+ * mod_objcg_mlstate() may be called with irq enabled, so
+ * mod_memcg_lruvec_state() should be used.
+ */
+static inline void mod_objcg_mlstate(struct obj_cgroup *objcg,
+                                    struct pglist_data *pgdat,
+                                    enum node_stat_item idx, int nr)
+{
+       struct mem_cgroup *memcg;
+       struct lruvec *lruvec;
+
+       rcu_read_lock();
+       memcg = obj_cgroup_memcg(objcg);
+       lruvec = mem_cgroup_lruvec(memcg, pgdat);
+       mod_memcg_lruvec_state(lruvec, idx, nr);
+       rcu_read_unlock();
+}
+
 /**
  * __count_memcg_events - account VM events in a cgroup
  * @memcg: the memory cgroup
@@ -886,13 +898,24 @@ struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p)
 }
 EXPORT_SYMBOL(mem_cgroup_from_task);
 
+static __always_inline struct mem_cgroup *active_memcg(void)
+{
+       if (in_interrupt())
+               return this_cpu_read(int_active_memcg);
+       else
+               return current->active_memcg;
+}
+
 /**
  * get_mem_cgroup_from_mm: Obtain a reference on given mm_struct's memcg.
  * @mm: mm from which memcg should be extracted. It can be NULL.
  *
- * Obtain a reference on mm->memcg and returns it if successful. Otherwise
- * root_mem_cgroup is returned. However if mem_cgroup is disabled, NULL is
- * returned.
+ * Obtain a reference on mm->memcg and returns it if successful. If mm
+ * is NULL, then the memcg is chosen as follows:
+ * 1) The active memcg, if set.
+ * 2) current->mm->memcg, if available
+ * 3) root memcg
+ * If mem_cgroup is disabled, NULL is returned.
  */
 struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
 {
@@ -901,34 +924,38 @@ struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
        if (mem_cgroup_disabled())
                return NULL;
 
+       /*
+        * Page cache insertions can happen without an
+        * actual mm context, e.g. during disk probing
+        * on boot, loopback IO, acct() writes etc.
+        *
+        * No need to css_get on root memcg as the reference
+        * counting is disabled on the root level in the
+        * cgroup core. See CSS_NO_REF.
+        */
+       if (unlikely(!mm)) {
+               memcg = active_memcg();
+               if (unlikely(memcg)) {
+                       /* remote memcg must hold a ref */
+                       css_get(&memcg->css);
+                       return memcg;
+               }
+               mm = current->mm;
+               if (unlikely(!mm))
+                       return root_mem_cgroup;
+       }
+
        rcu_read_lock();
        do {
-               /*
-                * Page cache insertions can happen without an
-                * actual mm context, e.g. during disk probing
-                * on boot, loopback IO, acct() writes etc.
-                */
-               if (unlikely(!mm))
+               memcg = mem_cgroup_from_task(rcu_dereference(mm->owner));
+               if (unlikely(!memcg))
                        memcg = root_mem_cgroup;
-               else {
-                       memcg = mem_cgroup_from_task(rcu_dereference(mm->owner));
-                       if (unlikely(!memcg))
-                               memcg = root_mem_cgroup;
-               }
        } while (!css_tryget(&memcg->css));
        rcu_read_unlock();
        return memcg;
 }
 EXPORT_SYMBOL(get_mem_cgroup_from_mm);
 
-static __always_inline struct mem_cgroup *active_memcg(void)
-{
-       if (in_interrupt())
-               return this_cpu_read(int_active_memcg);
-       else
-               return current->active_memcg;
-}
-
 static __always_inline bool memcg_kmem_bypass(void)
 {
        /* Allow remote memcg charging from any context. */
@@ -1178,9 +1205,8 @@ void lruvec_memcg_debug(struct lruvec *lruvec, struct page *page)
 struct lruvec *lock_page_lruvec(struct page *page)
 {
        struct lruvec *lruvec;
-       struct pglist_data *pgdat = page_pgdat(page);
 
-       lruvec = mem_cgroup_page_lruvec(page, pgdat);
+       lruvec = mem_cgroup_page_lruvec(page);
        spin_lock(&lruvec->lru_lock);
 
        lruvec_memcg_debug(lruvec, page);
@@ -1191,9 +1217,8 @@ struct lruvec *lock_page_lruvec(struct page *page)
 struct lruvec *lock_page_lruvec_irq(struct page *page)
 {
        struct lruvec *lruvec;
-       struct pglist_data *pgdat = page_pgdat(page);
 
-       lruvec = mem_cgroup_page_lruvec(page, pgdat);
+       lruvec = mem_cgroup_page_lruvec(page);
        spin_lock_irq(&lruvec->lru_lock);
 
        lruvec_memcg_debug(lruvec, page);
@@ -1204,9 +1229,8 @@ struct lruvec *lock_page_lruvec_irq(struct page *page)
 struct lruvec *lock_page_lruvec_irqsave(struct page *page, unsigned long *flags)
 {
        struct lruvec *lruvec;
-       struct pglist_data *pgdat = page_pgdat(page);
 
-       lruvec = mem_cgroup_page_lruvec(page, pgdat);
+       lruvec = mem_cgroup_page_lruvec(page);
        spin_lock_irqsave(&lruvec->lru_lock, *flags);
 
        lruvec_memcg_debug(lruvec, page);
@@ -2040,14 +2064,23 @@ void unlock_page_memcg(struct page *page)
 }
 EXPORT_SYMBOL(unlock_page_memcg);
 
-struct memcg_stock_pcp {
-       struct mem_cgroup *cached; /* this never be root cgroup */
-       unsigned int nr_pages;
-
+struct obj_stock {
 #ifdef CONFIG_MEMCG_KMEM
        struct obj_cgroup *cached_objcg;
+       struct pglist_data *cached_pgdat;
        unsigned int nr_bytes;
+       int nr_slab_reclaimable_b;
+       int nr_slab_unreclaimable_b;
+#else
+       int dummy[0];
 #endif
+};
+
+struct memcg_stock_pcp {
+       struct mem_cgroup *cached; /* this never be root cgroup */
+       unsigned int nr_pages;
+       struct obj_stock task_obj;
+       struct obj_stock irq_obj;
 
        struct work_struct work;
        unsigned long flags;
@@ -2057,12 +2090,12 @@ static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock);
 static DEFINE_MUTEX(percpu_charge_mutex);
 
 #ifdef CONFIG_MEMCG_KMEM
-static void drain_obj_stock(struct memcg_stock_pcp *stock);
+static void drain_obj_stock(struct obj_stock *stock);
 static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
                                     struct mem_cgroup *root_memcg);
 
 #else
-static inline void drain_obj_stock(struct memcg_stock_pcp *stock)
+static inline void drain_obj_stock(struct obj_stock *stock)
 {
 }
 static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
@@ -2072,6 +2105,41 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
 }
 #endif
 
+/*
+ * Most kmem_cache_alloc() calls are from user context. The irq disable/enable
+ * sequence used in this case to access content from object stock is slow.
+ * To optimize for user context access, there are now two object stocks for
+ * task context and interrupt context access respectively.
+ *
+ * The task context object stock can be accessed by disabling preemption only
+ * which is cheap in non-preempt kernel. The interrupt context object stock
+ * can only be accessed after disabling interrupt. User context code can
+ * access interrupt object stock, but not vice versa.
+ */
+static inline struct obj_stock *get_obj_stock(unsigned long *pflags)
+{
+       struct memcg_stock_pcp *stock;
+
+       if (likely(in_task())) {
+               *pflags = 0UL;
+               preempt_disable();
+               stock = this_cpu_ptr(&memcg_stock);
+               return &stock->task_obj;
+       }
+
+       local_irq_save(*pflags);
+       stock = this_cpu_ptr(&memcg_stock);
+       return &stock->irq_obj;
+}
+
+static inline void put_obj_stock(unsigned long flags)
+{
+       if (likely(in_task()))
+               preempt_enable();
+       else
+               local_irq_restore(flags);
+}
+
 /**
  * consume_stock: Try to consume stocked charge on this cpu.
  * @memcg: memcg to consume from.
@@ -2138,7 +2206,9 @@ static void drain_local_stock(struct work_struct *dummy)
        local_irq_save(flags);
 
        stock = this_cpu_ptr(&memcg_stock);
-       drain_obj_stock(stock);
+       drain_obj_stock(&stock->irq_obj);
+       if (in_task())
+               drain_obj_stock(&stock->task_obj);
        drain_stock(stock);
        clear_bit(FLUSHING_CACHED_CHARGE, &stock->flags);
 
@@ -2504,8 +2574,8 @@ out:
        css_put(&memcg->css);
 }
 
-static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
-                     unsigned int nr_pages)
+static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask,
+                       unsigned int nr_pages)
 {
        unsigned int batch = max(MEMCG_CHARGE_BATCH, nr_pages);
        int nr_retries = MAX_RECLAIM_RETRIES;
@@ -2517,8 +2587,6 @@ static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
        bool drained = false;
        unsigned long pflags;
 
-       if (mem_cgroup_is_root(memcg))
-               return 0;
 retry:
        if (consume_stock(memcg, nr_pages))
                return 0;
@@ -2698,6 +2766,15 @@ done_restock:
        return 0;
 }
 
+static inline int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
+                            unsigned int nr_pages)
+{
+       if (mem_cgroup_is_root(memcg))
+               return 0;
+
+       return try_charge_memcg(memcg, gfp_mask, nr_pages);
+}
+
 #if defined(CONFIG_MEMCG_KMEM) || defined(CONFIG_MMU)
 static void cancel_charge(struct mem_cgroup *memcg, unsigned int nr_pages)
 {
@@ -2739,6 +2816,13 @@ retry:
 }
 
 #ifdef CONFIG_MEMCG_KMEM
+/*
+ * The allocated objcg pointers array is not accounted directly.
+ * Moreover, it should not come from DMA buffer and is not readily
+ * reclaimable. So those GFP bits should be masked off.
+ */
+#define OBJCGS_CLEAR_MASK      (__GFP_DMA | __GFP_RECLAIMABLE | __GFP_ACCOUNT)
+
 int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s,
                                 gfp_t gfp, bool new_page)
 {
@@ -2746,6 +2830,7 @@ int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s,
        unsigned long memcg_data;
        void *vec;
 
+       gfp &= ~OBJCGS_CLEAR_MASK;
        vec = kcalloc_node(objects, sizeof(struct obj_cgroup *), gfp,
                           page_to_nid(page));
        if (!vec)
@@ -2925,7 +3010,7 @@ static int obj_cgroup_charge_pages(struct obj_cgroup *objcg, gfp_t gfp,
 
        memcg = get_mem_cgroup_from_objcg(objcg);
 
-       ret = try_charge(memcg, gfp, nr_pages);
+       ret = try_charge_memcg(memcg, gfp, nr_pages);
        if (ret)
                goto out;
 
@@ -2995,26 +3080,81 @@ void __memcg_kmem_uncharge_page(struct page *page, int order)
        obj_cgroup_put(objcg);
 }
 
+void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat,
+                    enum node_stat_item idx, int nr)
+{
+       unsigned long flags;
+       struct obj_stock *stock = get_obj_stock(&flags);
+       int *bytes;
+
+       /*
+        * Save vmstat data in stock and skip vmstat array update unless
+        * accumulating over a page of vmstat data or when pgdat or idx
+        * changes.
+        */
+       if (stock->cached_objcg != objcg) {
+               drain_obj_stock(stock);
+               obj_cgroup_get(objcg);
+               stock->nr_bytes = atomic_read(&objcg->nr_charged_bytes)
+                               ? atomic_xchg(&objcg->nr_charged_bytes, 0) : 0;
+               stock->cached_objcg = objcg;
+               stock->cached_pgdat = pgdat;
+       } else if (stock->cached_pgdat != pgdat) {
+               /* Flush the existing cached vmstat data */
+               if (stock->nr_slab_reclaimable_b) {
+                       mod_objcg_mlstate(objcg, pgdat, NR_SLAB_RECLAIMABLE_B,
+                                         stock->nr_slab_reclaimable_b);
+                       stock->nr_slab_reclaimable_b = 0;
+               }
+               if (stock->nr_slab_unreclaimable_b) {
+                       mod_objcg_mlstate(objcg, pgdat, NR_SLAB_UNRECLAIMABLE_B,
+                                         stock->nr_slab_unreclaimable_b);
+                       stock->nr_slab_unreclaimable_b = 0;
+               }
+               stock->cached_pgdat = pgdat;
+       }
+
+       bytes = (idx == NR_SLAB_RECLAIMABLE_B) ? &stock->nr_slab_reclaimable_b
+                                              : &stock->nr_slab_unreclaimable_b;
+       /*
+        * Even for large object >= PAGE_SIZE, the vmstat data will still be
+        * cached locally at least once before pushing it out.
+        */
+       if (!*bytes) {
+               *bytes = nr;
+               nr = 0;
+       } else {
+               *bytes += nr;
+               if (abs(*bytes) > PAGE_SIZE) {
+                       nr = *bytes;
+                       *bytes = 0;
+               } else {
+                       nr = 0;
+               }
+       }
+       if (nr)
+               mod_objcg_mlstate(objcg, pgdat, idx, nr);
+
+       put_obj_stock(flags);
+}
+
 static bool consume_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes)
 {
-       struct memcg_stock_pcp *stock;
        unsigned long flags;
+       struct obj_stock *stock = get_obj_stock(&flags);
        bool ret = false;
 
-       local_irq_save(flags);
-
-       stock = this_cpu_ptr(&memcg_stock);
        if (objcg == stock->cached_objcg && stock->nr_bytes >= nr_bytes) {
                stock->nr_bytes -= nr_bytes;
                ret = true;
        }
 
-       local_irq_restore(flags);
+       put_obj_stock(flags);
 
        return ret;
 }
 
-static void drain_obj_stock(struct memcg_stock_pcp *stock)
+static void drain_obj_stock(struct obj_stock *stock)
 {
        struct obj_cgroup *old = stock->cached_objcg;
 
@@ -3042,6 +3182,25 @@ static void drain_obj_stock(struct memcg_stock_pcp *stock)
                stock->nr_bytes = 0;
        }
 
+       /*
+        * Flush the vmstat data in current stock
+        */
+       if (stock->nr_slab_reclaimable_b || stock->nr_slab_unreclaimable_b) {
+               if (stock->nr_slab_reclaimable_b) {
+                       mod_objcg_mlstate(old, stock->cached_pgdat,
+                                         NR_SLAB_RECLAIMABLE_B,
+                                         stock->nr_slab_reclaimable_b);
+                       stock->nr_slab_reclaimable_b = 0;
+               }
+               if (stock->nr_slab_unreclaimable_b) {
+                       mod_objcg_mlstate(old, stock->cached_pgdat,
+                                         NR_SLAB_UNRECLAIMABLE_B,
+                                         stock->nr_slab_unreclaimable_b);
+                       stock->nr_slab_unreclaimable_b = 0;
+               }
+               stock->cached_pgdat = NULL;
+       }
+
        obj_cgroup_put(old);
        stock->cached_objcg = NULL;
 }
@@ -3051,8 +3210,13 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
 {
        struct mem_cgroup *memcg;
 
-       if (stock->cached_objcg) {
-               memcg = obj_cgroup_memcg(stock->cached_objcg);
+       if (in_task() && stock->task_obj.cached_objcg) {
+               memcg = obj_cgroup_memcg(stock->task_obj.cached_objcg);
+               if (memcg && mem_cgroup_is_descendant(memcg, root_memcg))
+                       return true;
+       }
+       if (stock->irq_obj.cached_objcg) {
+               memcg = obj_cgroup_memcg(stock->irq_obj.cached_objcg);
                if (memcg && mem_cgroup_is_descendant(memcg, root_memcg))
                        return true;
        }
@@ -3060,26 +3224,32 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
        return false;
 }
 
-static void refill_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes)
+static void refill_obj_stock(struct obj_cgroup *objcg, unsigned int nr_bytes,
+                            bool allow_uncharge)
 {
-       struct memcg_stock_pcp *stock;
        unsigned long flags;
+       struct obj_stock *stock = get_obj_stock(&flags);
+       unsigned int nr_pages = 0;
 
-       local_irq_save(flags);
-
-       stock = this_cpu_ptr(&memcg_stock);
        if (stock->cached_objcg != objcg) { /* reset if necessary */
                drain_obj_stock(stock);
                obj_cgroup_get(objcg);
                stock->cached_objcg = objcg;
-               stock->nr_bytes = atomic_xchg(&objcg->nr_charged_bytes, 0);
+               stock->nr_bytes = atomic_read(&objcg->nr_charged_bytes)
+                               ? atomic_xchg(&objcg->nr_charged_bytes, 0) : 0;
+               allow_uncharge = true;  /* Allow uncharge when objcg changes */
        }
        stock->nr_bytes += nr_bytes;
 
-       if (stock->nr_bytes > PAGE_SIZE)
-               drain_obj_stock(stock);
+       if (allow_uncharge && (stock->nr_bytes > PAGE_SIZE)) {
+               nr_pages = stock->nr_bytes >> PAGE_SHIFT;
+               stock->nr_bytes &= (PAGE_SIZE - 1);
+       }
 
-       local_irq_restore(flags);
+       put_obj_stock(flags);
+
+       if (nr_pages)
+               obj_cgroup_uncharge_pages(objcg, nr_pages);
 }
 
 int obj_cgroup_charge(struct obj_cgroup *objcg, gfp_t gfp, size_t size)
@@ -3091,14 +3261,27 @@ int obj_cgroup_charge(struct obj_cgroup *objcg, gfp_t gfp, size_t size)
                return 0;
 
        /*
-        * In theory, memcg->nr_charged_bytes can have enough
+        * In theory, objcg->nr_charged_bytes can have enough
         * pre-charged bytes to satisfy the allocation. However,
-        * flushing memcg->nr_charged_bytes requires two atomic
-        * operations, and memcg->nr_charged_bytes can't be big,
-        * so it's better to ignore it and try grab some new pages.
-        * memcg->nr_charged_bytes will be flushed in
-        * refill_obj_stock(), called from this function or
-        * independently later.
+        * flushing objcg->nr_charged_bytes requires two atomic
+        * operations, and objcg->nr_charged_bytes can't be big.
+        * The shared objcg->nr_charged_bytes can also become a
+        * performance bottleneck if all tasks of the same memcg are
+        * trying to update it. So it's better to ignore it and try
+        * grab some new pages. The stock's nr_bytes will be flushed to
+        * objcg->nr_charged_bytes later on when objcg changes.
+        *
+        * The stock's nr_bytes may contain enough pre-charged bytes
+        * to allow one less page from being charged, but we can't rely
+        * on the pre-charged bytes not being changed outside of
+        * consume_obj_stock() or refill_obj_stock(). So ignore those
+        * pre-charged bytes as well when charging pages. To avoid a
+        * page uncharge right after a page charge, we set the
+        * allow_uncharge flag to false when calling refill_obj_stock()
+        * to temporarily allow the pre-charged bytes to exceed the page
+        * size limit. The maximum reachable value of the pre-charged
+        * bytes is (sizeof(object) + PAGE_SIZE - 2) if there is no data
+        * race.
         */
        nr_pages = size >> PAGE_SHIFT;
        nr_bytes = size & (PAGE_SIZE - 1);
@@ -3108,14 +3291,14 @@ int obj_cgroup_charge(struct obj_cgroup *objcg, gfp_t gfp, size_t size)
 
        ret = obj_cgroup_charge_pages(objcg, gfp, nr_pages);
        if (!ret && nr_bytes)
-               refill_obj_stock(objcg, PAGE_SIZE - nr_bytes);
+               refill_obj_stock(objcg, PAGE_SIZE - nr_bytes, false);
 
        return ret;
 }
 
 void obj_cgroup_uncharge(struct obj_cgroup *objcg, size_t size)
 {
-       refill_obj_stock(objcg, size);
+       refill_obj_stock(objcg, size, true);
 }
 
 #endif /* CONFIG_MEMCG_KMEM */
@@ -6541,7 +6724,8 @@ out:
  * @gfp_mask: reclaim mode
  *
  * Try to charge @page to the memcg that @mm belongs to, reclaiming
- * pages according to @gfp_mask if necessary.
+ * pages according to @gfp_mask if necessary. if @mm is NULL, try to
+ * charge to the active memcg.
  *
  * Do not use this for pages allocated for swapin.
  *
@@ -6671,6 +6855,7 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
        unsigned long nr_pages;
        struct mem_cgroup *memcg;
        struct obj_cgroup *objcg;
+       bool use_objcg = PageMemcgKmem(page);
 
        VM_BUG_ON_PAGE(PageLRU(page), page);
 
@@ -6679,7 +6864,7 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
         * page memcg or objcg at this point, we have fully
         * exclusive access to the page.
         */
-       if (PageMemcgKmem(page)) {
+       if (use_objcg) {
                objcg = __page_objcg(page);
                /*
                 * This get matches the put at the end of the function and
@@ -6707,7 +6892,7 @@ static void uncharge_page(struct page *page, struct uncharge_gather *ug)
 
        nr_pages = compound_nr(page);
 
-       if (PageMemcgKmem(page)) {
+       if (use_objcg) {
                ug->nr_memory += nr_pages;
                ug->nr_kmem += nr_pages;
 
@@ -6806,9 +6991,11 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage)
        /* Force-charge the new page. The old one will be freed soon */
        nr_pages = thp_nr_pages(newpage);
 
-       page_counter_charge(&memcg->memory, nr_pages);
-       if (do_memsw_account())
-               page_counter_charge(&memcg->memsw, nr_pages);
+       if (!mem_cgroup_is_root(memcg)) {
+               page_counter_charge(&memcg->memory, nr_pages);
+               if (do_memsw_account())
+                       page_counter_charge(&memcg->memsw, nr_pages);
+       }
 
        css_get(&memcg->css);
        commit_charge(newpage, memcg);