|
@@ -3432,6 +3432,50 @@ void mem_cgroup_end_migration(struct mem_cgroup *memcg,
|
|
cgroup_release_and_wakeup_rmdir(&memcg->css);
|
|
cgroup_release_and_wakeup_rmdir(&memcg->css);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * At replace page cache, newpage is not under any memcg but it's on
|
|
|
|
+ * LRU. So, this function doesn't touch res_counter but handles LRU
|
|
|
|
+ * in correct way. Both pages are locked so we cannot race with uncharge.
|
|
|
|
+ */
|
|
|
|
+void mem_cgroup_replace_page_cache(struct page *oldpage,
|
|
|
|
+ struct page *newpage)
|
|
|
|
+{
|
|
|
|
+ struct mem_cgroup *memcg;
|
|
|
|
+ struct page_cgroup *pc;
|
|
|
|
+ struct zone *zone;
|
|
|
|
+ enum charge_type type = MEM_CGROUP_CHARGE_TYPE_CACHE;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+
|
|
|
|
+ if (mem_cgroup_disabled())
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ pc = lookup_page_cgroup(oldpage);
|
|
|
|
+ /* fix accounting on old pages */
|
|
|
|
+ lock_page_cgroup(pc);
|
|
|
|
+ memcg = pc->mem_cgroup;
|
|
|
|
+ mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), -1);
|
|
|
|
+ ClearPageCgroupUsed(pc);
|
|
|
|
+ unlock_page_cgroup(pc);
|
|
|
|
+
|
|
|
|
+ if (PageSwapBacked(oldpage))
|
|
|
|
+ type = MEM_CGROUP_CHARGE_TYPE_SHMEM;
|
|
|
|
+
|
|
|
|
+ zone = page_zone(newpage);
|
|
|
|
+ pc = lookup_page_cgroup(newpage);
|
|
|
|
+ /*
|
|
|
|
+ * Even if newpage->mapping was NULL before starting replacement,
|
|
|
|
+ * the newpage may be on LRU(or pagevec for LRU) already. We lock
|
|
|
|
+ * LRU while we overwrite pc->mem_cgroup.
|
|
|
|
+ */
|
|
|
|
+ spin_lock_irqsave(&zone->lru_lock, flags);
|
|
|
|
+ if (PageLRU(newpage))
|
|
|
|
+ del_page_from_lru_list(zone, newpage, page_lru(newpage));
|
|
|
|
+ __mem_cgroup_commit_charge(memcg, newpage, 1, pc, type);
|
|
|
|
+ if (PageLRU(newpage))
|
|
|
|
+ add_page_to_lru_list(zone, newpage, page_lru(newpage));
|
|
|
|
+ spin_unlock_irqrestore(&zone->lru_lock, flags);
|
|
|
|
+}
|
|
|
|
+
|
|
#ifdef CONFIG_DEBUG_VM
|
|
#ifdef CONFIG_DEBUG_VM
|
|
static struct page_cgroup *lookup_page_cgroup_used(struct page *page)
|
|
static struct page_cgroup *lookup_page_cgroup_used(struct page *page)
|
|
{
|
|
{
|