This patch implements charge and uncharge of swapcgroup.

- what will be charged ?
  charge the number of swap entries in bytes.

- when to charge/uncharge ?
  charge at get_swap_entry(), and uncharge at swap_entry_free().

- to what group charge the swap entry ?
  To determine to what mem_cgroup the swap entry should be charged,
  I changed the argument of get_swap_entry() from (void) to
  (struct page *). As a result, get_swap_entry() can determine
  to what mem_cgroup it should charge the swap entry
  by referring to page->page_cgroup->mem_cgroup.

- from what group uncharge the swap entry ?
  I added to swap_info_struct a member 'struct swap_cgroup **',
  array of pointer to which swap_cgroup the swap entry is
  charged.


Signed-off-by: Daisuke Nishimura <[EMAIL PROTECTED]>

---
 include/linux/memcontrol.h |   21 +++++++++++++++++++
 include/linux/swap.h       |    4 +-
 mm/memcontrol.c            |   47 ++++++++++++++++++++++++++++++++++++++++++++
 mm/shmem.c                 |    2 +-
 mm/swap_state.c            |    2 +-
 mm/swapfile.c              |   14 ++++++++++++-
 6 files changed, 85 insertions(+), 5 deletions(-)

diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index fdf3967..a7e6621 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -24,6 +24,7 @@ struct mem_cgroup;
 struct page_cgroup;
 struct page;
 struct mm_struct;
+struct swap_info_struct;
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
 
@@ -172,5 +173,25 @@ static inline long mem_cgroup_calc_reclaim_inactive(struct 
mem_cgroup *mem,
 }
 #endif /* CONFIG_CGROUP_MEM_CONT */
 
+#ifdef CONFIG_CGROUP_SWAP_RES_CTLR
+extern int swap_cgroup_charge(struct page *page,
+                       struct swap_info_struct *si,
+                       unsigned long offset);
+extern void swap_cgroup_uncharge(struct swap_info_struct *si,
+                               unsigned long offset);
+#else /* CONFIG_CGROUP_SWAP_RES_CTLR */
+static inline int swap_cgroup_charge(struct page *page,
+                       struct swap_info_struct *si,
+                       unsigned long offset)
+{
+       return 0;
+}
+
+static inline void swap_cgroup_uncharge(struct swap_info_struct *si,
+                               unsigned long offset)
+{
+}
+#endif /* CONFIG_CGROUP_SWAP_RES_CTLR */
+
 #endif /* _LINUX_MEMCONTROL_H */
 
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 67de27b..18887f0 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -241,7 +241,7 @@ extern struct page *swapin_readahead(swp_entry_t, gfp_t,
 /* linux/mm/swapfile.c */
 extern long total_swap_pages;
 extern void si_swapinfo(struct sysinfo *);
-extern swp_entry_t get_swap_page(void);
+extern swp_entry_t get_swap_page(struct page *);
 extern swp_entry_t get_swap_page_of_type(int);
 extern int swap_duplicate(swp_entry_t);
 extern int valid_swaphandles(swp_entry_t, unsigned long *);
@@ -342,7 +342,7 @@ static inline int remove_exclusive_swap_page(struct page *p)
        return 0;
 }
 
-static inline swp_entry_t get_swap_page(void)
+static inline swp_entry_t get_swap_page(struct page *page)
 {
        swp_entry_t entry;
        entry.val = 0;
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index a837215..84e803d 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1220,3 +1220,50 @@ struct cgroup_subsys mem_cgroup_subsys = {
        .attach = mem_cgroup_move_task,
        .early_init = 0,
 };
+
+#ifdef CONFIG_CGROUP_SWAP_RES_CTLR
+int swap_cgroup_charge(struct page *page,
+                       struct swap_info_struct *si,
+                       unsigned long offset)
+{
+       int ret;
+       struct page_cgroup *pc;
+       struct mem_cgroup *mem;
+
+       lock_page_cgroup(page);
+       pc = page_get_page_cgroup(page);
+       if (unlikely(!pc))
+               mem = &init_mem_cgroup;
+       else
+               mem = pc->mem_cgroup;
+       unlock_page_cgroup(page);
+
+       css_get(&mem->css);
+       ret = res_counter_charge(&mem->swap_res, PAGE_SIZE);
+       if (!ret)
+               si->memcg[offset] = mem;
+       else
+               css_put(&mem->css);
+
+       return ret;
+}
+
+void swap_cgroup_uncharge(struct swap_info_struct *si,
+                               unsigned long offset)
+{
+       struct mem_cgroup *mem = si->memcg[offset];
+
+       /* "mem" would be NULL:
+        * 1. when get_swap_page() failed at charging swap_cgroup,
+        *    and called swap_entry_free().
+        * 2. when this swap entry had been assigned by
+        *    get_swap_page_of_type() (via SWSUSP?).
+        */
+       if (mem) {
+               res_counter_uncharge(&mem->swap_res, PAGE_SIZE);
+               si->memcg[offset] = NULL;
+               css_put(&mem->css);
+       }
+}
+#endif
+
diff --git a/mm/shmem.c b/mm/shmem.c
index 95b056d..69f8909 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1029,7 +1029,7 @@ static int shmem_writepage(struct page *page, struct 
writeback_control *wbc)
         * want to check if there's a redundant swappage to be discarded.
         */
        if (wbc->for_reclaim)
-               swap = get_swap_page();
+               swap = get_swap_page(page);
        else
                swap.val = 0;
 
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 676e191..a78d617 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -130,7 +130,7 @@ int add_to_swap(struct page * page, gfp_t gfp_mask)
        BUG_ON(!PageUptodate(page));
 
        for (;;) {
-               entry = get_swap_page();
+               entry = get_swap_page(page);
                if (!entry.val)
                        return 0;
 
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 232bf20..682b71e 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -172,7 +172,10 @@ no_page:
        return 0;
 }
 
-swp_entry_t get_swap_page(void)
+/* get_swap_page() calls this */
+static int swap_entry_free(struct swap_info_struct *, unsigned long);
+
+swp_entry_t get_swap_page(struct page *page)
 {
        struct swap_info_struct *si;
        pgoff_t offset;
@@ -201,6 +204,14 @@ swp_entry_t get_swap_page(void)
                swap_list.next = next;
                offset = scan_swap_map(si);
                if (offset) {
+                       /*
+                        * This should be the first use of this swap entry.
+                        * So, charge this swap entry here.
+                        */
+                       if (swap_cgroup_charge(page, si, offset)) {
+                               swap_entry_free(si, offset);
+                               goto noswap;
+                       }
                        spin_unlock(&swap_lock);
                        return swp_entry(type, offset);
                }
@@ -285,6 +296,7 @@ static int swap_entry_free(struct swap_info_struct *p, 
unsigned long offset)
                                swap_list.next = p - swap_info;
                        nr_swap_pages++;
                        p->inuse_pages--;
+                       swap_cgroup_uncharge(p, offset);
                }
        }
        return count;


_______________________________________________
Containers mailing list
[EMAIL PROTECTED]
https://lists.linux-foundation.org/mailman/listinfo/containers

_______________________________________________
Devel mailing list
Devel@openvz.org
https://openvz.org/mailman/listinfo/devel

Reply via email to