From: j.glisse@gmail.com
To: linux-mm@kvack.org, linux-kernel@vger.kernel.org,
linux-fsdevel@vger.kernel.org
Cc: "Jérôme Glisse" <jglisse@redhat.com>
Subject: [PATCH 05/11] mm/memcg: support accounting null page and transfering null charge to new page.
Date: Fri, 2 May 2014 09:52:04 -0400 [thread overview]
Message-ID: <1399038730-25641-6-git-send-email-j.glisse@gmail.com> (raw)
In-Reply-To: <1399038730-25641-1-git-send-email-j.glisse@gmail.com>
From: Jérôme Glisse <jglisse@redhat.com>
When migrating memory to some device specific memory we still want to properly
account memcg memory usage. To do so we need to be able to account for page not
allocated in system memory. We also need to be able to transfer previous charge
from device memory to a page in an atomic way from memcg point of view.
Also introduce helper function to clear page memcg.
Signed-off-by: Jérôme Glisse <jglisse@redhat.com>
---
include/linux/memcontrol.h | 17 +++++
mm/memcontrol.c | 161 +++++++++++++++++++++++++++++++++++++++------
2 files changed, 159 insertions(+), 19 deletions(-)
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 1fa2324..1737323 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -67,6 +67,8 @@ struct mem_cgroup_reclaim_cookie {
extern int mem_cgroup_charge_anon(struct page *page, struct mm_struct *mm,
gfp_t gfp_mask);
+extern void mem_cgroup_transfer_charge_anon(struct page *page,
+ struct mm_struct *mm);
/* for swap handling */
extern int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
struct page *page, gfp_t mask, struct mem_cgroup **memcgp);
@@ -85,6 +87,8 @@ extern void mem_cgroup_uncharge_start(void);
extern void mem_cgroup_uncharge_end(void);
extern void mem_cgroup_uncharge_page(struct page *page);
+extern void mem_cgroup_uncharge_mm(struct mm_struct *mm);
+extern void mem_cgroup_clear_page(struct page *page);
extern void mem_cgroup_uncharge_cache_page(struct page *page);
bool __mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
@@ -245,6 +249,11 @@ static inline int mem_cgroup_charge_file(struct page *page,
return 0;
}
+static inline void mem_cgroup_transfer_charge_anon(struct page *page,
+ struct mm_struct *mm)
+{
+}
+
static inline int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
struct page *page, gfp_t gfp_mask, struct mem_cgroup **memcgp)
{
@@ -272,6 +281,14 @@ static inline void mem_cgroup_uncharge_page(struct page *page)
{
}
+static inline void mem_cgroup_uncharge_mm(struct mm_struct *mm)
+{
+}
+
+static inline void mem_cgroup_clear_page(struct page *page)
+{
+}
+
static inline void mem_cgroup_uncharge_cache_page(struct page *page)
{
}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 19d620b..ceaf4d7 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -940,7 +940,7 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
__this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_CACHE],
nr_pages);
- if (PageTransHuge(page))
+ if (page && PageTransHuge(page))
__this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS_HUGE],
nr_pages);
@@ -2842,12 +2842,17 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
enum charge_type ctype,
bool lrucare)
{
- struct page_cgroup *pc = lookup_page_cgroup(page);
+ struct page_cgroup *pc;
struct zone *uninitialized_var(zone);
struct lruvec *lruvec;
bool was_on_lru = false;
bool anon;
+ if (page == NULL) {
+ goto charge;
+ }
+
+ pc = lookup_page_cgroup(page);
lock_page_cgroup(pc);
VM_BUG_ON_PAGE(PageCgroupUsed(pc), page);
/*
@@ -2891,20 +2896,24 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
spin_unlock_irq(&zone->lru_lock);
}
+charge:
if (ctype == MEM_CGROUP_CHARGE_TYPE_ANON)
anon = true;
else
anon = false;
mem_cgroup_charge_statistics(memcg, page, anon, nr_pages);
- unlock_page_cgroup(pc);
- /*
- * "charge_statistics" updated event counter. Then, check it.
- * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
- * if they exceeds softlimit.
- */
- memcg_check_events(memcg, page);
+ if (page) {
+ unlock_page_cgroup(pc);
+
+ /*
+ * "charge_statistics" updated event counter. Then, check it.
+ * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
+ * if they exceeds softlimit.
+ */
+ memcg_check_events(memcg, page);
+ }
}
static DEFINE_MUTEX(set_limit_mutex);
@@ -3745,20 +3754,23 @@ int mem_cgroup_charge_anon(struct page *page,
if (mem_cgroup_disabled())
return 0;
- VM_BUG_ON_PAGE(page_mapped(page), page);
- VM_BUG_ON_PAGE(page->mapping && !PageAnon(page), page);
VM_BUG_ON(!mm);
+ if (page) {
+ VM_BUG_ON_PAGE(page_mapped(page), page);
+ VM_BUG_ON_PAGE(page->mapping && !PageAnon(page), page);
- if (PageTransHuge(page)) {
- nr_pages <<= compound_order(page);
- VM_BUG_ON_PAGE(!PageTransHuge(page), page);
- /*
- * Never OOM-kill a process for a huge page. The
- * fault handler will fall back to regular pages.
- */
- oom = false;
+ if (PageTransHuge(page)) {
+ nr_pages <<= compound_order(page);
+ VM_BUG_ON_PAGE(!PageTransHuge(page), page);
+ /*
+ * Never OOM-kill a process for a huge page. The
+ * fault handler will fall back to regular pages.
+ */
+ oom = false;
+ }
}
+
memcg = mem_cgroup_try_charge_mm(mm, gfp_mask, nr_pages, oom);
if (!memcg)
return -ENOMEM;
@@ -3767,6 +3779,60 @@ int mem_cgroup_charge_anon(struct page *page,
return 0;
}
+void mem_cgroup_transfer_charge_anon(struct page *page, struct mm_struct *mm)
+{
+ struct page_cgroup *pc;
+ struct task_struct *task;
+ struct mem_cgroup *memcg;
+ struct zone *uninitialized_var(zone);
+
+ if (mem_cgroup_disabled())
+ return;
+
+ VM_BUG_ON(page->mapping && !PageAnon(page));
+ VM_BUG_ON(!mm);
+
+ rcu_read_lock();
+ task = rcu_dereference(mm->owner);
+ /*
+ * Because we don't have task_lock(), "p" can exit.
+ * In that case, "memcg" can point to root or p can be NULL with
+ * race with swapoff. Then, we have small risk of mis-accouning.
+ * But such kind of mis-account by race always happens because
+ * we don't have cgroup_mutex(). It's overkill and we allo that
+ * small race, here.
+ * (*) swapoff at el will charge against mm-struct not against
+ * task-struct. So, mm->owner can be NULL.
+ */
+ memcg = mem_cgroup_from_task(task);
+ if (!memcg) {
+ memcg = root_mem_cgroup;
+ }
+ rcu_read_unlock();
+
+ pc = lookup_page_cgroup(page);
+ lock_page_cgroup(pc);
+ VM_BUG_ON(PageCgroupUsed(pc));
+ /*
+ * we don't need page_cgroup_lock about tail pages, becase they are not
+ * accessed by any other context at this point.
+ */
+
+ pc->mem_cgroup = memcg;
+ /*
+ * We access a page_cgroup asynchronously without lock_page_cgroup().
+ * Especially when a page_cgroup is taken from a page, pc->mem_cgroup
+ * is accessed after testing USED bit. To make pc->mem_cgroup visible
+ * before USED bit, we need memory barrier here.
+ * See mem_cgroup_add_lru_list(), etc.
+ */
+ smp_wmb();
+ SetPageCgroupUsed(pc);
+
+ unlock_page_cgroup(pc);
+ memcg_check_events(memcg, page);
+}
+
/*
* While swap-in, try_charge -> commit or cancel, the page is locked.
* And when try_charge() successfully returns, one refcnt to memcg without
@@ -4087,6 +4153,63 @@ void mem_cgroup_uncharge_page(struct page *page)
__mem_cgroup_uncharge_common(page, MEM_CGROUP_CHARGE_TYPE_ANON, false);
}
+void mem_cgroup_uncharge_mm(struct mm_struct *mm)
+{
+ struct mem_cgroup *memcg;
+ struct task_struct *task;
+
+ if (mem_cgroup_disabled())
+ return;
+
+ VM_BUG_ON(!mm);
+
+ rcu_read_lock();
+ task = rcu_dereference(mm->owner);
+ /*
+ * Because we don't have task_lock(), "p" can exit.
+ * In that case, "memcg" can point to root or p can be NULL with
+ * race with swapoff. Then, we have small risk of mis-accouning.
+ * But such kind of mis-account by race always happens because
+ * we don't have cgroup_mutex(). It's overkill and we allo that
+ * small race, here.
+ * (*) swapoff at el will charge against mm-struct not against
+ * task-struct. So, mm->owner can be NULL.
+ */
+ memcg = mem_cgroup_from_task(task);
+ if (!memcg) {
+ memcg = root_mem_cgroup;
+ }
+ rcu_read_unlock();
+
+ mem_cgroup_charge_statistics(memcg, NULL, true, -1);
+ if (!mem_cgroup_is_root(memcg))
+ mem_cgroup_do_uncharge(memcg, 1, MEM_CGROUP_CHARGE_TYPE_ANON);
+}
+
+void mem_cgroup_clear_page(struct page *page)
+{
+ struct page_cgroup *pc;
+
+ if (mem_cgroup_disabled())
+ return;
+
+ /*
+ * Check if our page_cgroup is valid
+ */
+ pc = lookup_page_cgroup(page);
+ if (unlikely(!PageCgroupUsed(pc)))
+ return;
+ lock_page_cgroup(pc);
+ ClearPageCgroupUsed(pc);
+ /*
+ * pc->mem_cgroup is not cleared here. It will be accessed when it's
+ * freed from LRU. This is safe because uncharged page is expected not
+ * to be reused (freed soon). Exception is SwapCache, it's handled by
+ * special functions.
+ */
+ unlock_page_cgroup(pc);
+}
+
void mem_cgroup_uncharge_cache_page(struct page *page)
{
VM_BUG_ON_PAGE(page_mapped(page), page);
--
1.9.0
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next prev parent reply other threads:[~2014-05-02 13:52 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-02 13:51 [RFC] Heterogeneous memory management (mirror process address space on a device mmu) j.glisse
2014-05-02 13:52 ` [PATCH 01/11] mm: differentiate unmap for vmscan from other unmap j.glisse
2014-05-02 13:52 ` [PATCH 02/11] mmu_notifier: add action information to address invalidation j.glisse
2014-05-02 13:52 ` [PATCH 03/11] mmu_notifier: pass through vma to invalidate_range and invalidate_page j.glisse
2014-05-02 13:52 ` [PATCH 04/11] interval_tree: helper to find previous item of a node in rb interval tree j.glisse
2014-05-02 13:52 ` j.glisse [this message]
2014-05-02 13:52 ` [PATCH 06/11] hmm: heterogeneous memory management j.glisse
2014-05-02 13:52 ` [PATCH 07/11] hmm: support moving anonymous page to remote memory j.glisse
2014-05-02 13:52 ` [PATCH 08/11] hmm: support for migrate file backed pages " j.glisse
2014-05-02 13:52 ` [PATCH 09/11] fs/ext4: add support for hmm migration to remote memory of pagecache j.glisse
2014-05-02 13:52 ` [PATCH 10/11] hmm/dummy: dummy driver to showcase the hmm api j.glisse
2014-05-02 13:52 ` [PATCH 11/11] hmm/dummy_driver: add support for fake remote memory using pages j.glisse
2014-05-06 10:29 ` [RFC] Heterogeneous memory management (mirror process address space on a device mmu) Peter Zijlstra
2014-05-06 14:57 ` Linus Torvalds
2014-05-06 15:00 ` Jerome Glisse
2014-05-06 15:18 ` Linus Torvalds
2014-05-06 15:33 ` Jerome Glisse
2014-05-06 15:42 ` Rik van Riel
2014-05-06 15:47 ` Linus Torvalds
2014-05-06 16:18 ` Jerome Glisse
2014-05-06 16:32 ` Linus Torvalds
2014-05-06 16:49 ` Jerome Glisse
2014-05-06 17:28 ` Jerome Glisse
2014-05-06 17:43 ` Linus Torvalds
2014-05-06 18:13 ` Jerome Glisse
2014-05-06 18:22 ` Linus Torvalds
2014-05-06 18:38 ` Jerome Glisse
2014-05-07 7:18 ` Benjamin Herrenschmidt
2014-05-07 7:14 ` Benjamin Herrenschmidt
2014-05-07 12:39 ` Jerome Glisse
2014-05-09 1:26 ` Jerome Glisse
2014-05-10 4:28 ` Benjamin Herrenschmidt
2014-05-11 0:48 ` Jerome Glisse
2014-05-06 16:30 ` Rik van Riel
2014-05-06 16:34 ` Linus Torvalds
2014-05-06 16:47 ` Rik van Riel
2014-05-06 16:54 ` Jerome Glisse
2014-05-06 18:02 ` H. Peter Anvin
2014-05-06 18:26 ` Jerome Glisse
2014-05-06 22:44 ` David Airlie
2014-05-07 2:33 ` Davidlohr Bueso
2014-05-07 13:00 ` Peter Zijlstra
2014-05-07 17:34 ` Davidlohr Bueso
2014-05-07 16:21 ` Linus Torvalds
2014-05-08 16:47 ` sagi grimberg
2014-05-08 17:56 ` Jerome Glisse
2014-05-09 1:42 ` Davidlohr Bueso
2014-05-09 1:45 ` Jerome Glisse
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1399038730-25641-6-git-send-email-j.glisse@gmail.com \
--to=j.glisse@gmail.com \
--cc=jglisse@redhat.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).