[PATCH 13/15] mm/hmm: factor out pte and pmd handling to simplify hmm_vma_walk_pmd() v2

2018-03-22 Thread jglisse
From: Jérôme Glisse 

No functional change, just create one function to handle pmd and one
to handle pte (hmm_vma_handle_pmd() and hmm_vma_handle_pte()).

Changed since v1:
  - s/pfns/pfn for pte as in that case we are dealing with a single pfn

Signed-off-by: Jérôme Glisse 
Reviewed-by: John Hubbard 
Cc: Evgeny Baskakov 
Cc: Ralph Campbell 
Cc: Mark Hairgrove 
---
 mm/hmm.c | 174 +--
 1 file changed, 102 insertions(+), 72 deletions(-)

diff --git a/mm/hmm.c b/mm/hmm.c
index 05b49a5d6674..2cc4dda1fd2e 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -375,6 +375,99 @@ static int hmm_vma_walk_hole(unsigned long addr,
return hmm_vma_walk->fault ? -EAGAIN : 0;
 }
 
+static int hmm_vma_handle_pmd(struct mm_walk *walk,
+ unsigned long addr,
+ unsigned long end,
+ uint64_t *pfns,
+ pmd_t pmd)
+{
+   struct hmm_vma_walk *hmm_vma_walk = walk->private;
+   unsigned long pfn, i;
+   uint64_t flag = 0;
+
+   if (pmd_protnone(pmd))
+   return hmm_vma_walk_hole(addr, end, walk);
+
+   if ((hmm_vma_walk->fault & hmm_vma_walk->write) && !pmd_write(pmd))
+   return hmm_vma_walk_hole(addr, end, walk);
+
+   pfn = pmd_pfn(pmd) + pte_index(addr);
+   flag |= pmd_write(pmd) ? HMM_PFN_WRITE : 0;
+   for (i = 0; addr < end; addr += PAGE_SIZE, i++, pfn++)
+   pfns[i] = hmm_pfn_from_pfn(pfn) | flag;
+   hmm_vma_walk->last = end;
+   return 0;
+}
+
+static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
+ unsigned long end, pmd_t *pmdp, pte_t *ptep,
+ uint64_t *pfn)
+{
+   struct hmm_vma_walk *hmm_vma_walk = walk->private;
+   struct vm_area_struct *vma = walk->vma;
+   pte_t pte = *ptep;
+
+   *pfn = 0;
+
+   if (pte_none(pte)) {
+   *pfn = 0;
+   if (hmm_vma_walk->fault)
+   goto fault;
+   return 0;
+   }
+
+   if (!pte_present(pte)) {
+   swp_entry_t entry = pte_to_swp_entry(pte);
+
+   if (!non_swap_entry(entry)) {
+   if (hmm_vma_walk->fault)
+   goto fault;
+   return 0;
+   }
+
+   /*
+* This is a special swap entry, ignore migration, use
+* device and report anything else as error.
+*/
+   if (is_device_private_entry(entry)) {
+   *pfn = hmm_pfn_from_pfn(swp_offset(entry));
+   if (is_write_device_private_entry(entry)) {
+   *pfn |= HMM_PFN_WRITE;
+   } else if ((hmm_vma_walk->fault & hmm_vma_walk->write))
+   goto fault;
+   *pfn |= HMM_PFN_DEVICE_PRIVATE;
+   return 0;
+   }
+
+   if (is_migration_entry(entry)) {
+   if (hmm_vma_walk->fault) {
+   pte_unmap(ptep);
+   hmm_vma_walk->last = addr;
+   migration_entry_wait(vma->vm_mm,
+   pmdp, addr);
+   return -EAGAIN;
+   }
+   return 0;
+   }
+
+   /* Report error for everything else */
+   *pfn = HMM_PFN_ERROR;
+   return -EFAULT;
+   }
+
+   if ((hmm_vma_walk->fault & hmm_vma_walk->write) && !pte_write(pte))
+   goto fault;
+
+   *pfn = hmm_pfn_from_pfn(pte_pfn(pte));
+   *pfn |= pte_write(pte) ? HMM_PFN_WRITE : 0;
+   return 0;
+
+fault:
+   pte_unmap(ptep);
+   /* Fault any virtual address we were asked to fault */
+   return hmm_vma_walk_hole(addr, end, walk);
+}
+
 static int hmm_vma_walk_pmd(pmd_t *pmdp,
unsigned long start,
unsigned long end,
@@ -382,25 +475,20 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
 {
struct hmm_vma_walk *hmm_vma_walk = walk->private;
struct hmm_range *range = hmm_vma_walk->range;
-   struct vm_area_struct *vma = walk->vma;
uint64_t *pfns = range->pfns;
unsigned long addr = start, i;
-   bool write_fault;
pte_t *ptep;
 
i = (addr - range->start) >> PAGE_SHIFT;
-   write_fault = hmm_vma_walk->fault & hmm_vma_walk->write;
 
 again:
if (pmd_none(*pmdp))
return hmm_vma_walk_hole(start, end, walk);
 
-   if (pmd_huge(*pmdp) && vma->vm_flags & VM_HUGETLB)
+   if (pmd_huge(*pmdp) && (range->vma->vm_flags & VM_HUGETLB))
  

[PATCH 13/15] mm/hmm: factor out pte and pmd handling to simplify hmm_vma_walk_pmd() v2

2018-03-22 Thread jglisse
From: Jérôme Glisse 

No functional change, just create one function to handle pmd and one
to handle pte (hmm_vma_handle_pmd() and hmm_vma_handle_pte()).

Changed since v1:
  - s/pfns/pfn for pte as in that case we are dealing with a single pfn

Signed-off-by: Jérôme Glisse 
Reviewed-by: John Hubbard 
Cc: Evgeny Baskakov 
Cc: Ralph Campbell 
Cc: Mark Hairgrove 
---
 mm/hmm.c | 174 +--
 1 file changed, 102 insertions(+), 72 deletions(-)

diff --git a/mm/hmm.c b/mm/hmm.c
index 05b49a5d6674..2cc4dda1fd2e 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -375,6 +375,99 @@ static int hmm_vma_walk_hole(unsigned long addr,
return hmm_vma_walk->fault ? -EAGAIN : 0;
 }
 
+static int hmm_vma_handle_pmd(struct mm_walk *walk,
+ unsigned long addr,
+ unsigned long end,
+ uint64_t *pfns,
+ pmd_t pmd)
+{
+   struct hmm_vma_walk *hmm_vma_walk = walk->private;
+   unsigned long pfn, i;
+   uint64_t flag = 0;
+
+   if (pmd_protnone(pmd))
+   return hmm_vma_walk_hole(addr, end, walk);
+
+   if ((hmm_vma_walk->fault & hmm_vma_walk->write) && !pmd_write(pmd))
+   return hmm_vma_walk_hole(addr, end, walk);
+
+   pfn = pmd_pfn(pmd) + pte_index(addr);
+   flag |= pmd_write(pmd) ? HMM_PFN_WRITE : 0;
+   for (i = 0; addr < end; addr += PAGE_SIZE, i++, pfn++)
+   pfns[i] = hmm_pfn_from_pfn(pfn) | flag;
+   hmm_vma_walk->last = end;
+   return 0;
+}
+
+static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
+ unsigned long end, pmd_t *pmdp, pte_t *ptep,
+ uint64_t *pfn)
+{
+   struct hmm_vma_walk *hmm_vma_walk = walk->private;
+   struct vm_area_struct *vma = walk->vma;
+   pte_t pte = *ptep;
+
+   *pfn = 0;
+
+   if (pte_none(pte)) {
+   *pfn = 0;
+   if (hmm_vma_walk->fault)
+   goto fault;
+   return 0;
+   }
+
+   if (!pte_present(pte)) {
+   swp_entry_t entry = pte_to_swp_entry(pte);
+
+   if (!non_swap_entry(entry)) {
+   if (hmm_vma_walk->fault)
+   goto fault;
+   return 0;
+   }
+
+   /*
+* This is a special swap entry, ignore migration, use
+* device and report anything else as error.
+*/
+   if (is_device_private_entry(entry)) {
+   *pfn = hmm_pfn_from_pfn(swp_offset(entry));
+   if (is_write_device_private_entry(entry)) {
+   *pfn |= HMM_PFN_WRITE;
+   } else if ((hmm_vma_walk->fault & hmm_vma_walk->write))
+   goto fault;
+   *pfn |= HMM_PFN_DEVICE_PRIVATE;
+   return 0;
+   }
+
+   if (is_migration_entry(entry)) {
+   if (hmm_vma_walk->fault) {
+   pte_unmap(ptep);
+   hmm_vma_walk->last = addr;
+   migration_entry_wait(vma->vm_mm,
+   pmdp, addr);
+   return -EAGAIN;
+   }
+   return 0;
+   }
+
+   /* Report error for everything else */
+   *pfn = HMM_PFN_ERROR;
+   return -EFAULT;
+   }
+
+   if ((hmm_vma_walk->fault & hmm_vma_walk->write) && !pte_write(pte))
+   goto fault;
+
+   *pfn = hmm_pfn_from_pfn(pte_pfn(pte));
+   *pfn |= pte_write(pte) ? HMM_PFN_WRITE : 0;
+   return 0;
+
+fault:
+   pte_unmap(ptep);
+   /* Fault any virtual address we were asked to fault */
+   return hmm_vma_walk_hole(addr, end, walk);
+}
+
 static int hmm_vma_walk_pmd(pmd_t *pmdp,
unsigned long start,
unsigned long end,
@@ -382,25 +475,20 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
 {
struct hmm_vma_walk *hmm_vma_walk = walk->private;
struct hmm_range *range = hmm_vma_walk->range;
-   struct vm_area_struct *vma = walk->vma;
uint64_t *pfns = range->pfns;
unsigned long addr = start, i;
-   bool write_fault;
pte_t *ptep;
 
i = (addr - range->start) >> PAGE_SHIFT;
-   write_fault = hmm_vma_walk->fault & hmm_vma_walk->write;
 
 again:
if (pmd_none(*pmdp))
return hmm_vma_walk_hole(start, end, walk);
 
-   if (pmd_huge(*pmdp) && vma->vm_flags & VM_HUGETLB)
+   if (pmd_huge(*pmdp) && (range->vma->vm_flags & VM_HUGETLB))
return hmm_pfns_bad(start, end, walk);
 
if (pmd_devmap(*pmdp) || pmd_trans_huge(*pmdp)) {
-