[PATCH -v4 RESEND 2/9] mm, memcg: Support to charge/uncharge multiple swap entries

2016-10-28 Thread Huang, Ying
From: Huang Ying 

This patch make it possible to charge or uncharge a set of continuous
swap entries in the swap cgroup.  The number of swap entries is
specified via an added parameter.

This will be used for the THP (Transparent Huge Page) swap support.
Where a swap cluster backing a THP may be allocated and freed as a
whole.  So a set of (HPAGE_PMD_NR) continuous swap entries backing one
THP need to be charged or uncharged together.  This will batch the
cgroup operations for the THP swap too.

Cc: Andrea Arcangeli 
Cc: Kirill A. Shutemov 
Cc: Vladimir Davydov 
Cc: Johannes Weiner 
Cc: Michal Hocko 
Cc: Tejun Heo 
Cc: cgro...@vger.kernel.org
Signed-off-by: "Huang, Ying" 
---
 include/linux/swap.h| 12 ++
 include/linux/swap_cgroup.h |  6 +++--
 mm/memcontrol.c | 55 +
 mm/shmem.c  |  2 +-
 mm/swap_cgroup.c| 40 -
 mm/swap_state.c |  2 +-
 mm/swapfile.c   |  2 +-
 7 files changed, 76 insertions(+), 43 deletions(-)

diff --git a/include/linux/swap.h b/include/linux/swap.h
index a56523c..001b506 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -552,8 +552,10 @@ static inline int mem_cgroup_swappiness(struct mem_cgroup 
*mem)
 
 #ifdef CONFIG_MEMCG_SWAP
 extern void mem_cgroup_swapout(struct page *page, swp_entry_t entry);
-extern int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry);
-extern void mem_cgroup_uncharge_swap(swp_entry_t entry);
+extern int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry,
+ unsigned int nr_entries);
+extern void mem_cgroup_uncharge_swap(swp_entry_t entry,
+unsigned int nr_entries);
 extern long mem_cgroup_get_nr_swap_pages(struct mem_cgroup *memcg);
 extern bool mem_cgroup_swap_full(struct page *page);
 #else
@@ -562,12 +564,14 @@ static inline void mem_cgroup_swapout(struct page *page, 
swp_entry_t entry)
 }
 
 static inline int mem_cgroup_try_charge_swap(struct page *page,
-swp_entry_t entry)
+swp_entry_t entry,
+unsigned int nr_entries)
 {
return 0;
 }
 
-static inline void mem_cgroup_uncharge_swap(swp_entry_t entry)
+static inline void mem_cgroup_uncharge_swap(swp_entry_t entry,
+   unsigned int nr_entries)
 {
 }
 
diff --git a/include/linux/swap_cgroup.h b/include/linux/swap_cgroup.h
index 145306b..b2b8ec7 100644
--- a/include/linux/swap_cgroup.h
+++ b/include/linux/swap_cgroup.h
@@ -7,7 +7,8 @@
 
 extern unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
unsigned short old, unsigned short new);
-extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id);
+extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id,
+unsigned int nr_ents);
 extern unsigned short lookup_swap_cgroup_id(swp_entry_t ent);
 extern int swap_cgroup_swapon(int type, unsigned long max_pages);
 extern void swap_cgroup_swapoff(int type);
@@ -15,7 +16,8 @@ extern void swap_cgroup_swapoff(int type);
 #else
 
 static inline
-unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
+unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id,
+ unsigned int nr_ents)
 {
return 0;
 }
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index ae052b5..581f705 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2383,10 +2383,9 @@ void mem_cgroup_split_huge_fixup(struct page *head)
 
 #ifdef CONFIG_MEMCG_SWAP
 static void mem_cgroup_swap_statistics(struct mem_cgroup *memcg,
-bool charge)
+  int nr_entries)
 {
-   int val = (charge) ? 1 : -1;
-   this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_SWAP], val);
+   this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_SWAP], nr_entries);
 }
 
 /**
@@ -2412,8 +2411,8 @@ static int mem_cgroup_move_swap_account(swp_entry_t entry,
new_id = mem_cgroup_id(to);
 
if (swap_cgroup_cmpxchg(entry, old_id, new_id) == old_id) {
-   mem_cgroup_swap_statistics(from, false);
-   mem_cgroup_swap_statistics(to, true);
+   mem_cgroup_swap_statistics(from, -1);
+   mem_cgroup_swap_statistics(to, 1);
return 0;
}
return -EINVAL;
@@ -5433,7 +5432,7 @@ void mem_cgroup_commit_charge(struct page *page, struct 
mem_cgroup *memcg,
 * let's not wait for it.  The page already received a
 * memory+swap 

[PATCH -v4 RESEND 2/9] mm, memcg: Support to charge/uncharge multiple swap entries

2016-10-28 Thread Huang, Ying
From: Huang Ying 

This patch make it possible to charge or uncharge a set of continuous
swap entries in the swap cgroup.  The number of swap entries is
specified via an added parameter.

This will be used for the THP (Transparent Huge Page) swap support.
Where a swap cluster backing a THP may be allocated and freed as a
whole.  So a set of (HPAGE_PMD_NR) continuous swap entries backing one
THP need to be charged or uncharged together.  This will batch the
cgroup operations for the THP swap too.

Cc: Andrea Arcangeli 
Cc: Kirill A. Shutemov 
Cc: Vladimir Davydov 
Cc: Johannes Weiner 
Cc: Michal Hocko 
Cc: Tejun Heo 
Cc: cgro...@vger.kernel.org
Signed-off-by: "Huang, Ying" 
---
 include/linux/swap.h| 12 ++
 include/linux/swap_cgroup.h |  6 +++--
 mm/memcontrol.c | 55 +
 mm/shmem.c  |  2 +-
 mm/swap_cgroup.c| 40 -
 mm/swap_state.c |  2 +-
 mm/swapfile.c   |  2 +-
 7 files changed, 76 insertions(+), 43 deletions(-)

diff --git a/include/linux/swap.h b/include/linux/swap.h
index a56523c..001b506 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -552,8 +552,10 @@ static inline int mem_cgroup_swappiness(struct mem_cgroup 
*mem)
 
 #ifdef CONFIG_MEMCG_SWAP
 extern void mem_cgroup_swapout(struct page *page, swp_entry_t entry);
-extern int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry);
-extern void mem_cgroup_uncharge_swap(swp_entry_t entry);
+extern int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry,
+ unsigned int nr_entries);
+extern void mem_cgroup_uncharge_swap(swp_entry_t entry,
+unsigned int nr_entries);
 extern long mem_cgroup_get_nr_swap_pages(struct mem_cgroup *memcg);
 extern bool mem_cgroup_swap_full(struct page *page);
 #else
@@ -562,12 +564,14 @@ static inline void mem_cgroup_swapout(struct page *page, 
swp_entry_t entry)
 }
 
 static inline int mem_cgroup_try_charge_swap(struct page *page,
-swp_entry_t entry)
+swp_entry_t entry,
+unsigned int nr_entries)
 {
return 0;
 }
 
-static inline void mem_cgroup_uncharge_swap(swp_entry_t entry)
+static inline void mem_cgroup_uncharge_swap(swp_entry_t entry,
+   unsigned int nr_entries)
 {
 }
 
diff --git a/include/linux/swap_cgroup.h b/include/linux/swap_cgroup.h
index 145306b..b2b8ec7 100644
--- a/include/linux/swap_cgroup.h
+++ b/include/linux/swap_cgroup.h
@@ -7,7 +7,8 @@
 
 extern unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
unsigned short old, unsigned short new);
-extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id);
+extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id,
+unsigned int nr_ents);
 extern unsigned short lookup_swap_cgroup_id(swp_entry_t ent);
 extern int swap_cgroup_swapon(int type, unsigned long max_pages);
 extern void swap_cgroup_swapoff(int type);
@@ -15,7 +16,8 @@ extern void swap_cgroup_swapoff(int type);
 #else
 
 static inline
-unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
+unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id,
+ unsigned int nr_ents)
 {
return 0;
 }
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index ae052b5..581f705 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2383,10 +2383,9 @@ void mem_cgroup_split_huge_fixup(struct page *head)
 
 #ifdef CONFIG_MEMCG_SWAP
 static void mem_cgroup_swap_statistics(struct mem_cgroup *memcg,
-bool charge)
+  int nr_entries)
 {
-   int val = (charge) ? 1 : -1;
-   this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_SWAP], val);
+   this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_SWAP], nr_entries);
 }
 
 /**
@@ -2412,8 +2411,8 @@ static int mem_cgroup_move_swap_account(swp_entry_t entry,
new_id = mem_cgroup_id(to);
 
if (swap_cgroup_cmpxchg(entry, old_id, new_id) == old_id) {
-   mem_cgroup_swap_statistics(from, false);
-   mem_cgroup_swap_statistics(to, true);
+   mem_cgroup_swap_statistics(from, -1);
+   mem_cgroup_swap_statistics(to, 1);
return 0;
}
return -EINVAL;
@@ -5433,7 +5432,7 @@ void mem_cgroup_commit_charge(struct page *page, struct 
mem_cgroup *memcg,
 * let's not wait for it.  The page already received a
 * memory+swap charge, drop the swap entry duplicate.
 */
-   mem_cgroup_uncharge_swap(entry);
+   mem_cgroup_uncharge_swap(entry, nr_pages);
}