Re: [PATCH -mm -v3 02/12] mm, THP, swap: Support to reclaim swap space for THP swapped out

2017-07-25 Thread Rik van Riel
On Mon, 2017-07-24 at 13:18 +0800, Huang, Ying wrote:
> From: Huang Ying 
> 
> The normal swap slot reclaiming can be done when the swap count
> reaches SWAP_HAS_CACHE.  But for the swap slot which is backing a
> THP,
> all swap slots backing one THP must be reclaimed together, because
> the
> swap slot may be used again when the THP is swapped out again later.
> So the swap slots backing one THP can be reclaimed together when the
> swap count for all swap slots for the THP reached SWAP_HAS_CACHE.  In
> the patch, the functions to check whether the swap count for all swap
> slots backing one THP reached SWAP_HAS_CACHE are implemented and used
> when checking whether a swap slot can be reclaimed.
> 
> To make it easier to determine whether a swap slot is backing a THP,
> a
> new swap cluster flag named CLUSTER_FLAG_HUGE is added to mark a swap
> cluster which is backing a THP (Transparent Huge Page).  Because THP
> swap in as a whole isn't supported now.  After deleting the THP from
> the swap cache (for example, swapping out finished), the
> CLUSTER_FLAG_HUGE flag will be cleared.  So that, the normal pages
> inside THP can be swapped in individually.
> 
> Signed-off-by: "Huang, Ying" 
> Cc: Johannes Weiner 
> Cc: Minchan Kim 
> Cc: Hugh Dickins 
> Cc: Shaohua Li 
> Cc: Rik van Riel 
> 
Acked-by: Rik van Riel 

-- 
All rights reversed

signature.asc
Description: This is a digitally signed message part


Re: [PATCH -mm -v3 02/12] mm, THP, swap: Support to reclaim swap space for THP swapped out

2017-07-25 Thread Rik van Riel
On Mon, 2017-07-24 at 13:18 +0800, Huang, Ying wrote:
> From: Huang Ying 
> 
> The normal swap slot reclaiming can be done when the swap count
> reaches SWAP_HAS_CACHE.  But for the swap slot which is backing a
> THP,
> all swap slots backing one THP must be reclaimed together, because
> the
> swap slot may be used again when the THP is swapped out again later.
> So the swap slots backing one THP can be reclaimed together when the
> swap count for all swap slots for the THP reached SWAP_HAS_CACHE.  In
> the patch, the functions to check whether the swap count for all swap
> slots backing one THP reached SWAP_HAS_CACHE are implemented and used
> when checking whether a swap slot can be reclaimed.
> 
> To make it easier to determine whether a swap slot is backing a THP,
> a
> new swap cluster flag named CLUSTER_FLAG_HUGE is added to mark a swap
> cluster which is backing a THP (Transparent Huge Page).  Because THP
> swap in as a whole isn't supported now.  After deleting the THP from
> the swap cache (for example, swapping out finished), the
> CLUSTER_FLAG_HUGE flag will be cleared.  So that, the normal pages
> inside THP can be swapped in individually.
> 
> Signed-off-by: "Huang, Ying" 
> Cc: Johannes Weiner 
> Cc: Minchan Kim 
> Cc: Hugh Dickins 
> Cc: Shaohua Li 
> Cc: Rik van Riel 
> 
Acked-by: Rik van Riel 

-- 
All rights reversed

signature.asc
Description: This is a digitally signed message part


[PATCH -mm -v3 02/12] mm, THP, swap: Support to reclaim swap space for THP swapped out

2017-07-23 Thread Huang, Ying
From: Huang Ying 

The normal swap slot reclaiming can be done when the swap count
reaches SWAP_HAS_CACHE.  But for the swap slot which is backing a THP,
all swap slots backing one THP must be reclaimed together, because the
swap slot may be used again when the THP is swapped out again later.
So the swap slots backing one THP can be reclaimed together when the
swap count for all swap slots for the THP reached SWAP_HAS_CACHE.  In
the patch, the functions to check whether the swap count for all swap
slots backing one THP reached SWAP_HAS_CACHE are implemented and used
when checking whether a swap slot can be reclaimed.

To make it easier to determine whether a swap slot is backing a THP, a
new swap cluster flag named CLUSTER_FLAG_HUGE is added to mark a swap
cluster which is backing a THP (Transparent Huge Page).  Because THP
swap in as a whole isn't supported now.  After deleting the THP from
the swap cache (for example, swapping out finished), the
CLUSTER_FLAG_HUGE flag will be cleared.  So that, the normal pages
inside THP can be swapped in individually.

Signed-off-by: "Huang, Ying" 
Cc: Johannes Weiner 
Cc: Minchan Kim 
Cc: Hugh Dickins 
Cc: Shaohua Li 
Cc: Rik van Riel 
---
 include/linux/swap.h |  1 +
 mm/swapfile.c| 78 +++-
 2 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/include/linux/swap.h b/include/linux/swap.h
index d83d28e53e62..964b4f1fba4a 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -188,6 +188,7 @@ struct swap_cluster_info {
 };
 #define CLUSTER_FLAG_FREE 1 /* This cluster is free */
 #define CLUSTER_FLAG_NEXT_NULL 2 /* This cluster has no next cluster */
+#define CLUSTER_FLAG_HUGE 4 /* This cluster is backing a transparent huge page 
*/
 
 /*
  * We assign a cluster to each CPU, so each CPU can allocate swap entry from
diff --git a/mm/swapfile.c b/mm/swapfile.c
index c32e9b23d642..7db19846f8c7 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -265,6 +265,16 @@ static inline void cluster_set_null(struct 
swap_cluster_info *info)
info->data = 0;
 }
 
+static inline bool cluster_is_huge(struct swap_cluster_info *info)
+{
+   return info->flags & CLUSTER_FLAG_HUGE;
+}
+
+static inline void cluster_clear_huge(struct swap_cluster_info *info)
+{
+   info->flags &= ~CLUSTER_FLAG_HUGE;
+}
+
 static inline struct swap_cluster_info *lock_cluster(struct swap_info_struct 
*si,
 unsigned long offset)
 {
@@ -846,7 +856,7 @@ static int swap_alloc_cluster(struct swap_info_struct *si, 
swp_entry_t *slot)
offset = idx * SWAPFILE_CLUSTER;
ci = lock_cluster(si, offset);
alloc_cluster(si, idx);
-   cluster_set_count_flag(ci, SWAPFILE_CLUSTER, 0);
+   cluster_set_count_flag(ci, SWAPFILE_CLUSTER, CLUSTER_FLAG_HUGE);
 
map = si->swap_map + offset;
for (i = 0; i < SWAPFILE_CLUSTER; i++)
@@ -1176,6 +1186,7 @@ static void swapcache_free_cluster(swp_entry_t entry)
return;
 
ci = lock_cluster(si, offset);
+   VM_BUG_ON(!cluster_is_huge(ci));
map = si->swap_map + offset;
for (i = 0; i < SWAPFILE_CLUSTER; i++) {
val = map[i];
@@ -1187,6 +1198,7 @@ static void swapcache_free_cluster(swp_entry_t entry)
for (i = 0; i < SWAPFILE_CLUSTER; i++)
map[i] &= ~SWAP_HAS_CACHE;
}
+   cluster_clear_huge(ci);
unlock_cluster(ci);
if (free_entries == SWAPFILE_CLUSTER) {
spin_lock(>lock);
@@ -1350,6 +1362,54 @@ int swp_swapcount(swp_entry_t entry)
return count;
 }
 
+#ifdef CONFIG_THP_SWAP
+static bool swap_page_trans_huge_swapped(struct swap_info_struct *si,
+swp_entry_t entry)
+{
+   struct swap_cluster_info *ci;
+   unsigned char *map = si->swap_map;
+   unsigned long roffset = swp_offset(entry);
+   unsigned long offset = round_down(roffset, SWAPFILE_CLUSTER);
+   int i;
+   bool ret = false;
+
+   ci = lock_cluster_or_swap_info(si, offset);
+   if (!cluster_is_huge(ci)) {
+   if (map[roffset] != SWAP_HAS_CACHE)
+   ret = true;
+   goto unlock_out;
+   }
+   for (i = 0; i < SWAPFILE_CLUSTER; i++) {
+   if (map[offset + i] != SWAP_HAS_CACHE) {
+   ret = true;
+   break;
+   }
+   }
+unlock_out:
+   unlock_cluster_or_swap_info(si, ci);
+   return ret;
+}
+
+static bool page_swapped(struct page *page)
+{
+   swp_entry_t entry;
+   struct swap_info_struct *si;
+
+   if (likely(!PageTransCompound(page)))
+   return page_swapcount(page) != 0;
+
+   page = compound_head(page);
+   entry.val = page_private(page);
+   si = 

[PATCH -mm -v3 02/12] mm, THP, swap: Support to reclaim swap space for THP swapped out

2017-07-23 Thread Huang, Ying
From: Huang Ying 

The normal swap slot reclaiming can be done when the swap count
reaches SWAP_HAS_CACHE.  But for the swap slot which is backing a THP,
all swap slots backing one THP must be reclaimed together, because the
swap slot may be used again when the THP is swapped out again later.
So the swap slots backing one THP can be reclaimed together when the
swap count for all swap slots for the THP reached SWAP_HAS_CACHE.  In
the patch, the functions to check whether the swap count for all swap
slots backing one THP reached SWAP_HAS_CACHE are implemented and used
when checking whether a swap slot can be reclaimed.

To make it easier to determine whether a swap slot is backing a THP, a
new swap cluster flag named CLUSTER_FLAG_HUGE is added to mark a swap
cluster which is backing a THP (Transparent Huge Page).  Because THP
swap in as a whole isn't supported now.  After deleting the THP from
the swap cache (for example, swapping out finished), the
CLUSTER_FLAG_HUGE flag will be cleared.  So that, the normal pages
inside THP can be swapped in individually.

Signed-off-by: "Huang, Ying" 
Cc: Johannes Weiner 
Cc: Minchan Kim 
Cc: Hugh Dickins 
Cc: Shaohua Li 
Cc: Rik van Riel 
---
 include/linux/swap.h |  1 +
 mm/swapfile.c| 78 +++-
 2 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/include/linux/swap.h b/include/linux/swap.h
index d83d28e53e62..964b4f1fba4a 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -188,6 +188,7 @@ struct swap_cluster_info {
 };
 #define CLUSTER_FLAG_FREE 1 /* This cluster is free */
 #define CLUSTER_FLAG_NEXT_NULL 2 /* This cluster has no next cluster */
+#define CLUSTER_FLAG_HUGE 4 /* This cluster is backing a transparent huge page 
*/
 
 /*
  * We assign a cluster to each CPU, so each CPU can allocate swap entry from
diff --git a/mm/swapfile.c b/mm/swapfile.c
index c32e9b23d642..7db19846f8c7 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -265,6 +265,16 @@ static inline void cluster_set_null(struct 
swap_cluster_info *info)
info->data = 0;
 }
 
+static inline bool cluster_is_huge(struct swap_cluster_info *info)
+{
+   return info->flags & CLUSTER_FLAG_HUGE;
+}
+
+static inline void cluster_clear_huge(struct swap_cluster_info *info)
+{
+   info->flags &= ~CLUSTER_FLAG_HUGE;
+}
+
 static inline struct swap_cluster_info *lock_cluster(struct swap_info_struct 
*si,
 unsigned long offset)
 {
@@ -846,7 +856,7 @@ static int swap_alloc_cluster(struct swap_info_struct *si, 
swp_entry_t *slot)
offset = idx * SWAPFILE_CLUSTER;
ci = lock_cluster(si, offset);
alloc_cluster(si, idx);
-   cluster_set_count_flag(ci, SWAPFILE_CLUSTER, 0);
+   cluster_set_count_flag(ci, SWAPFILE_CLUSTER, CLUSTER_FLAG_HUGE);
 
map = si->swap_map + offset;
for (i = 0; i < SWAPFILE_CLUSTER; i++)
@@ -1176,6 +1186,7 @@ static void swapcache_free_cluster(swp_entry_t entry)
return;
 
ci = lock_cluster(si, offset);
+   VM_BUG_ON(!cluster_is_huge(ci));
map = si->swap_map + offset;
for (i = 0; i < SWAPFILE_CLUSTER; i++) {
val = map[i];
@@ -1187,6 +1198,7 @@ static void swapcache_free_cluster(swp_entry_t entry)
for (i = 0; i < SWAPFILE_CLUSTER; i++)
map[i] &= ~SWAP_HAS_CACHE;
}
+   cluster_clear_huge(ci);
unlock_cluster(ci);
if (free_entries == SWAPFILE_CLUSTER) {
spin_lock(>lock);
@@ -1350,6 +1362,54 @@ int swp_swapcount(swp_entry_t entry)
return count;
 }
 
+#ifdef CONFIG_THP_SWAP
+static bool swap_page_trans_huge_swapped(struct swap_info_struct *si,
+swp_entry_t entry)
+{
+   struct swap_cluster_info *ci;
+   unsigned char *map = si->swap_map;
+   unsigned long roffset = swp_offset(entry);
+   unsigned long offset = round_down(roffset, SWAPFILE_CLUSTER);
+   int i;
+   bool ret = false;
+
+   ci = lock_cluster_or_swap_info(si, offset);
+   if (!cluster_is_huge(ci)) {
+   if (map[roffset] != SWAP_HAS_CACHE)
+   ret = true;
+   goto unlock_out;
+   }
+   for (i = 0; i < SWAPFILE_CLUSTER; i++) {
+   if (map[offset + i] != SWAP_HAS_CACHE) {
+   ret = true;
+   break;
+   }
+   }
+unlock_out:
+   unlock_cluster_or_swap_info(si, ci);
+   return ret;
+}
+
+static bool page_swapped(struct page *page)
+{
+   swp_entry_t entry;
+   struct swap_info_struct *si;
+
+   if (likely(!PageTransCompound(page)))
+   return page_swapcount(page) != 0;
+
+   page = compound_head(page);
+   entry.val = page_private(page);
+   si = _swap_info_get(entry);
+   if (si)
+   return swap_page_trans_huge_swapped(si, entry);
+   return false;
+}
+#else