[PATCH -mm -v7 3/9] mm, THP, swap: Add swap cluster allocate/free functions

2017-03-27 Thread Huang, Ying
From: Huang Ying 

The swap cluster allocation/free functions are added based on the
existing swap cluster management mechanism for SSD.  These functions
don't work for the rotating hard disks because the existing swap cluster
management mechanism doesn't work for them.  The hard disks support may
be added if someone really need it.  But that needn't be included in
this patchset.

This will be used for the THP (Transparent Huge Page) swap support.
Where one swap cluster will hold the contents of each THP swapped out.

Cc: Andrea Arcangeli 
Cc: Kirill A. Shutemov 
Cc: Hugh Dickins 
Cc: Shaohua Li 
Cc: Minchan Kim 
Cc: Rik van Riel 
Signed-off-by: "Huang, Ying" 
---
 mm/swapfile.c | 217 +-
 1 file changed, 156 insertions(+), 61 deletions(-)

diff --git a/mm/swapfile.c b/mm/swapfile.c
index 1ef4fc82c0fa..54480acbbeef 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -378,6 +378,14 @@ static void swap_cluster_schedule_discard(struct 
swap_info_struct *si,
schedule_work(>discard_work);
 }
 
+static void __free_cluster(struct swap_info_struct *si, unsigned long idx)
+{
+   struct swap_cluster_info *ci = si->cluster_info;
+
+   cluster_set_flag(ci + idx, CLUSTER_FLAG_FREE);
+   cluster_list_add_tail(>free_clusters, ci, idx);
+}
+
 /*
  * Doing discard actually. After a cluster discard is finished, the cluster
  * will be added to free cluster list. caller should hold si->lock.
@@ -398,10 +406,7 @@ static void swap_do_scheduled_discard(struct 
swap_info_struct *si)
 
spin_lock(>lock);
ci = lock_cluster(si, idx * SWAPFILE_CLUSTER);
-   cluster_set_flag(ci, CLUSTER_FLAG_FREE);
-   unlock_cluster(ci);
-   cluster_list_add_tail(>free_clusters, info, idx);
-   ci = lock_cluster(si, idx * SWAPFILE_CLUSTER);
+   __free_cluster(si, idx);
memset(si->swap_map + idx * SWAPFILE_CLUSTER,
0, SWAPFILE_CLUSTER);
unlock_cluster(ci);
@@ -419,6 +424,34 @@ static void swap_discard_work(struct work_struct *work)
spin_unlock(>lock);
 }
 
+static void alloc_cluster(struct swap_info_struct *si, unsigned long idx)
+{
+   struct swap_cluster_info *ci = si->cluster_info;
+
+   VM_BUG_ON(cluster_list_first(>free_clusters) != idx);
+   cluster_list_del_first(>free_clusters, ci);
+   cluster_set_count_flag(ci + idx, 0, 0);
+}
+
+static void free_cluster(struct swap_info_struct *si, unsigned long idx)
+{
+   struct swap_cluster_info *ci = si->cluster_info + idx;
+
+   VM_BUG_ON(cluster_count(ci) != 0);
+   /*
+* If the swap is discardable, prepare discard the cluster
+* instead of free it immediately. The cluster will be freed
+* after discard.
+*/
+   if ((si->flags & (SWP_WRITEOK | SWP_PAGE_DISCARD)) ==
+   (SWP_WRITEOK | SWP_PAGE_DISCARD)) {
+   swap_cluster_schedule_discard(si, idx);
+   return;
+   }
+
+   __free_cluster(si, idx);
+}
+
 /*
  * The cluster corresponding to page_nr will be used. The cluster will be
  * removed from free cluster list and its usage counter will be increased.
@@ -430,11 +463,8 @@ static void inc_cluster_info_page(struct swap_info_struct 
*p,
 
if (!cluster_info)
return;
-   if (cluster_is_free(_info[idx])) {
-   VM_BUG_ON(cluster_list_first(>free_clusters) != idx);
-   cluster_list_del_first(>free_clusters, cluster_info);
-   cluster_set_count_flag(_info[idx], 0, 0);
-   }
+   if (cluster_is_free(_info[idx]))
+   alloc_cluster(p, idx);
 
VM_BUG_ON(cluster_count(_info[idx]) >= SWAPFILE_CLUSTER);
cluster_set_count(_info[idx],
@@ -458,21 +488,8 @@ static void dec_cluster_info_page(struct swap_info_struct 
*p,
cluster_set_count(_info[idx],
cluster_count(_info[idx]) - 1);
 
-   if (cluster_count(_info[idx]) == 0) {
-   /*
-* If the swap is discardable, prepare discard the cluster
-* instead of free it immediately. The cluster will be freed
-* after discard.
-*/
-   if ((p->flags & (SWP_WRITEOK | SWP_PAGE_DISCARD)) ==
-(SWP_WRITEOK | SWP_PAGE_DISCARD)) {
-   swap_cluster_schedule_discard(p, idx);
-   return;
-   }
-
-   cluster_set_flag(_info[idx], CLUSTER_FLAG_FREE);
-   cluster_list_add_tail(>free_clusters, cluster_info, idx);
-   }
+   if (cluster_count(_info[idx]) == 0)
+   free_cluster(p, idx);
 }
 
 /*
@@ -562,6 +579,71 @@ static bool 

[PATCH -mm -v7 3/9] mm, THP, swap: Add swap cluster allocate/free functions

2017-03-27 Thread Huang, Ying
From: Huang Ying 

The swap cluster allocation/free functions are added based on the
existing swap cluster management mechanism for SSD.  These functions
don't work for the rotating hard disks because the existing swap cluster
management mechanism doesn't work for them.  The hard disks support may
be added if someone really need it.  But that needn't be included in
this patchset.

This will be used for the THP (Transparent Huge Page) swap support.
Where one swap cluster will hold the contents of each THP swapped out.

Cc: Andrea Arcangeli 
Cc: Kirill A. Shutemov 
Cc: Hugh Dickins 
Cc: Shaohua Li 
Cc: Minchan Kim 
Cc: Rik van Riel 
Signed-off-by: "Huang, Ying" 
---
 mm/swapfile.c | 217 +-
 1 file changed, 156 insertions(+), 61 deletions(-)

diff --git a/mm/swapfile.c b/mm/swapfile.c
index 1ef4fc82c0fa..54480acbbeef 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -378,6 +378,14 @@ static void swap_cluster_schedule_discard(struct 
swap_info_struct *si,
schedule_work(>discard_work);
 }
 
+static void __free_cluster(struct swap_info_struct *si, unsigned long idx)
+{
+   struct swap_cluster_info *ci = si->cluster_info;
+
+   cluster_set_flag(ci + idx, CLUSTER_FLAG_FREE);
+   cluster_list_add_tail(>free_clusters, ci, idx);
+}
+
 /*
  * Doing discard actually. After a cluster discard is finished, the cluster
  * will be added to free cluster list. caller should hold si->lock.
@@ -398,10 +406,7 @@ static void swap_do_scheduled_discard(struct 
swap_info_struct *si)
 
spin_lock(>lock);
ci = lock_cluster(si, idx * SWAPFILE_CLUSTER);
-   cluster_set_flag(ci, CLUSTER_FLAG_FREE);
-   unlock_cluster(ci);
-   cluster_list_add_tail(>free_clusters, info, idx);
-   ci = lock_cluster(si, idx * SWAPFILE_CLUSTER);
+   __free_cluster(si, idx);
memset(si->swap_map + idx * SWAPFILE_CLUSTER,
0, SWAPFILE_CLUSTER);
unlock_cluster(ci);
@@ -419,6 +424,34 @@ static void swap_discard_work(struct work_struct *work)
spin_unlock(>lock);
 }
 
+static void alloc_cluster(struct swap_info_struct *si, unsigned long idx)
+{
+   struct swap_cluster_info *ci = si->cluster_info;
+
+   VM_BUG_ON(cluster_list_first(>free_clusters) != idx);
+   cluster_list_del_first(>free_clusters, ci);
+   cluster_set_count_flag(ci + idx, 0, 0);
+}
+
+static void free_cluster(struct swap_info_struct *si, unsigned long idx)
+{
+   struct swap_cluster_info *ci = si->cluster_info + idx;
+
+   VM_BUG_ON(cluster_count(ci) != 0);
+   /*
+* If the swap is discardable, prepare discard the cluster
+* instead of free it immediately. The cluster will be freed
+* after discard.
+*/
+   if ((si->flags & (SWP_WRITEOK | SWP_PAGE_DISCARD)) ==
+   (SWP_WRITEOK | SWP_PAGE_DISCARD)) {
+   swap_cluster_schedule_discard(si, idx);
+   return;
+   }
+
+   __free_cluster(si, idx);
+}
+
 /*
  * The cluster corresponding to page_nr will be used. The cluster will be
  * removed from free cluster list and its usage counter will be increased.
@@ -430,11 +463,8 @@ static void inc_cluster_info_page(struct swap_info_struct 
*p,
 
if (!cluster_info)
return;
-   if (cluster_is_free(_info[idx])) {
-   VM_BUG_ON(cluster_list_first(>free_clusters) != idx);
-   cluster_list_del_first(>free_clusters, cluster_info);
-   cluster_set_count_flag(_info[idx], 0, 0);
-   }
+   if (cluster_is_free(_info[idx]))
+   alloc_cluster(p, idx);
 
VM_BUG_ON(cluster_count(_info[idx]) >= SWAPFILE_CLUSTER);
cluster_set_count(_info[idx],
@@ -458,21 +488,8 @@ static void dec_cluster_info_page(struct swap_info_struct 
*p,
cluster_set_count(_info[idx],
cluster_count(_info[idx]) - 1);
 
-   if (cluster_count(_info[idx]) == 0) {
-   /*
-* If the swap is discardable, prepare discard the cluster
-* instead of free it immediately. The cluster will be freed
-* after discard.
-*/
-   if ((p->flags & (SWP_WRITEOK | SWP_PAGE_DISCARD)) ==
-(SWP_WRITEOK | SWP_PAGE_DISCARD)) {
-   swap_cluster_schedule_discard(p, idx);
-   return;
-   }
-
-   cluster_set_flag(_info[idx], CLUSTER_FLAG_FREE);
-   cluster_list_add_tail(>free_clusters, cluster_info, idx);
-   }
+   if (cluster_count(_info[idx]) == 0)
+   free_cluster(p, idx);
 }
 
 /*
@@ -562,6 +579,71 @@ static bool scan_swap_map_try_ssd_cluster(struct 
swap_info_struct *si,
return found_free;
 }
 
+#ifdef CONFIG_THP_SWAP_CLUSTER
+static inline unsigned int huge_cluster_nr_entries(bool huge)
+{
+   return