Re: [HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-11 Thread Andrew Morton
On Mon, 10 Apr 2017 21:33:51 -0400 (EDT) Jerome Glisse  
wrote:

> > On Mon, 10 Apr 2017 10:43:26 +0200 Michal Hocko  wrote:
> > 
> > > There are more for alpha allmodconfig
> > 
> > HMM is rather a compile catastrophe, as was the earlier version I
> > merged.
> > 
> > Jerome, I'm thinking you need to install some cross-compilers!
> 
> Sorry about that.
> 
> I tested some but obviously not all, in the v20 i did on top of Michal
> patchset i simply made everything to be x86-64 only. So if you revert
> v19 and wait for Michal to finish his v3 then i will post v20 that is
> x86-64 only which i do build and use. At least from my discussion with
> Michal i thought you were dropping v19 until Michal could finish his
> memory hotplug rework.

OK, I'll quietly drop the hmm series again for now.


Re: [HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-11 Thread Andrew Morton
On Mon, 10 Apr 2017 21:33:51 -0400 (EDT) Jerome Glisse  
wrote:

> > On Mon, 10 Apr 2017 10:43:26 +0200 Michal Hocko  wrote:
> > 
> > > There are more for alpha allmodconfig
> > 
> > HMM is rather a compile catastrophe, as was the earlier version I
> > merged.
> > 
> > Jerome, I'm thinking you need to install some cross-compilers!
> 
> Sorry about that.
> 
> I tested some but obviously not all, in the v20 i did on top of Michal
> patchset i simply made everything to be x86-64 only. So if you revert
> v19 and wait for Michal to finish his v3 then i will post v20 that is
> x86-64 only which i do build and use. At least from my discussion with
> Michal i thought you were dropping v19 until Michal could finish his
> memory hotplug rework.

OK, I'll quietly drop the hmm series again for now.


Re: [HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-10 Thread Jerome Glisse
> On Mon, 10 Apr 2017 10:43:26 +0200 Michal Hocko  wrote:
> 
> > There are more for alpha allmodconfig
> 
> HMM is rather a compile catastrophe, as was the earlier version I
> merged.
> 
> Jerome, I'm thinking you need to install some cross-compilers!

Sorry about that.

I tested some but obviously not all, in the v20 i did on top of Michal
patchset i simply made everything to be x86-64 only. So if you revert
v19 and wait for Michal to finish his v3 then i will post v20 that is
x86-64 only which i do build and use. At least from my discussion with
Michal i thought you were dropping v19 until Michal could finish his
memory hotplug rework.

Cheers,
Jérôme


Re: [HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-10 Thread Jerome Glisse
> On Mon, 10 Apr 2017 10:43:26 +0200 Michal Hocko  wrote:
> 
> > There are more for alpha allmodconfig
> 
> HMM is rather a compile catastrophe, as was the earlier version I
> merged.
> 
> Jerome, I'm thinking you need to install some cross-compilers!

Sorry about that.

I tested some but obviously not all, in the v20 i did on top of Michal
patchset i simply made everything to be x86-64 only. So if you revert
v19 and wait for Michal to finish his v3 then i will post v20 that is
x86-64 only which i do build and use. At least from my discussion with
Michal i thought you were dropping v19 until Michal could finish his
memory hotplug rework.

Cheers,
Jérôme


Re: [HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-10 Thread Andrew Morton
On Mon, 10 Apr 2017 10:43:26 +0200 Michal Hocko  wrote:

> There are more for alpha allmodconfig

HMM is rather a compile catastrophe, as was the earlier version I
merged.

Jerome, I'm thinking you need to install some cross-compilers!


Re: [HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-10 Thread Andrew Morton
On Mon, 10 Apr 2017 10:43:26 +0200 Michal Hocko  wrote:

> There are more for alpha allmodconfig

HMM is rather a compile catastrophe, as was the earlier version I
merged.

Jerome, I'm thinking you need to install some cross-compilers!


Re: [HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-10 Thread Michal Hocko
There are more for alpha allmodconfig

=== Config /home/mhocko/work/build-test/configs/alpha/allmodconfig
mm/hmm.c: In function 'hmm_vma_walk_pmd':
mm/hmm.c:370:4: error: implicit declaration of function 'pmd_pfn' 
[-Werror=implicit-function-declaration]
unsigned long pfn = pmd_pfn(pmd) + pte_index(addr);
^
mm/hmm.c:370:4: error: implicit declaration of function 'pte_index' 
[-Werror=implicit-function-declaration]
mm/hmm.c: In function 'hmm_devmem_radix_release':
mm/hmm.c:784:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this 
function)
 #define SECTION_SIZE (1UL << PA_SECTION_SHIFT)
  ^
mm/hmm.c:790:36: note: in expansion of macro 'SECTION_SIZE'
  align_start = resource->start & ~(SECTION_SIZE - 1);
^
mm/hmm.c:784:30: note: each undeclared identifier is reported only once for 
each function it appears in
 #define SECTION_SIZE (1UL << PA_SECTION_SHIFT)
  ^
mm/hmm.c:790:36: note: in expansion of macro 'SECTION_SIZE'
  align_start = resource->start & ~(SECTION_SIZE - 1);
^
mm/hmm.c: In function 'hmm_devmem_release':
mm/hmm.c:784:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this 
function)
 #define SECTION_SIZE (1UL << PA_SECTION_SHIFT)
  ^
mm/hmm.c:812:36: note: in expansion of macro 'SECTION_SIZE'
  align_start = resource->start & ~(SECTION_SIZE - 1);
^
mm/hmm.c:816:2: error: implicit declaration of function 'arch_remove_memory' 
[-Werror=implicit-function-declaration]
  arch_remove_memory(align_start, align_size, devmem->pagemap.type);
  ^
mm/hmm.c: In function 'hmm_devmem_find':
mm/hmm.c:827:54: error: 'PA_SECTION_SHIFT' undeclared (first use in this 
function)
  return radix_tree_lookup(_devmem_radix, phys >> PA_SECTION_SHIFT);
  ^
mm/hmm.c: In function 'hmm_devmem_pages_create':
mm/hmm.c:784:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this 
function)
 #define SECTION_SIZE (1UL << PA_SECTION_SHIFT)
  ^
mm/hmm.c:838:44: note: in expansion of macro 'SECTION_SIZE'
  align_start = devmem->resource->start & ~(SECTION_SIZE - 1);
^
In file included from ./include/linux/cache.h:4:0,
 from ./include/linux/printk.h:8,
 from ./include/linux/kernel.h:13,
 from ./include/asm-generic/bug.h:13,
 from ./arch/alpha/include/asm/bug.h:22,
 from ./include/linux/bug.h:4,
 from ./include/linux/mmdebug.h:4,
 from ./include/linux/mm.h:8,
 from mm/hmm.c:20:
mm/hmm.c: In function 'hmm_devmem_add':
mm/hmm.c:784:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this 
function)
 #define SECTION_SIZE (1UL << PA_SECTION_SHIFT)
  ^
./include/uapi/linux/kernel.h:10:47: note: in definition of macro 
'__ALIGN_KERNEL_MASK'
 #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
   ^
./include/linux/kernel.h:49:22: note: in expansion of macro '__ALIGN_KERNEL'
 #define ALIGN(x, a)  __ALIGN_KERNEL((x), (a))
  ^
mm/hmm.c:982:9: note: in expansion of macro 'ALIGN'
  size = ALIGN(size, SECTION_SIZE);
 ^
mm/hmm.c:982:21: note: in expansion of macro 'SECTION_SIZE'
  size = ALIGN(size, SECTION_SIZE);
 ^
mm/hmm.c: In function 'hmm_devmem_find':
mm/hmm.c:828:1: warning: control reaches end of non-void function 
[-Wreturn-type]
 }
 ^
cc1: some warnings being treated as errors
make[1]: *** [mm/hmm.o] Error 1
make[1]: *** Waiting for unfinished jobs
make: *** [mm] Error 2
make: *** Waiting for unfinished jobs
-- 
Michal Hocko
SUSE Labs


Re: [HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-10 Thread Michal Hocko
There are more for alpha allmodconfig

=== Config /home/mhocko/work/build-test/configs/alpha/allmodconfig
mm/hmm.c: In function 'hmm_vma_walk_pmd':
mm/hmm.c:370:4: error: implicit declaration of function 'pmd_pfn' 
[-Werror=implicit-function-declaration]
unsigned long pfn = pmd_pfn(pmd) + pte_index(addr);
^
mm/hmm.c:370:4: error: implicit declaration of function 'pte_index' 
[-Werror=implicit-function-declaration]
mm/hmm.c: In function 'hmm_devmem_radix_release':
mm/hmm.c:784:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this 
function)
 #define SECTION_SIZE (1UL << PA_SECTION_SHIFT)
  ^
mm/hmm.c:790:36: note: in expansion of macro 'SECTION_SIZE'
  align_start = resource->start & ~(SECTION_SIZE - 1);
^
mm/hmm.c:784:30: note: each undeclared identifier is reported only once for 
each function it appears in
 #define SECTION_SIZE (1UL << PA_SECTION_SHIFT)
  ^
mm/hmm.c:790:36: note: in expansion of macro 'SECTION_SIZE'
  align_start = resource->start & ~(SECTION_SIZE - 1);
^
mm/hmm.c: In function 'hmm_devmem_release':
mm/hmm.c:784:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this 
function)
 #define SECTION_SIZE (1UL << PA_SECTION_SHIFT)
  ^
mm/hmm.c:812:36: note: in expansion of macro 'SECTION_SIZE'
  align_start = resource->start & ~(SECTION_SIZE - 1);
^
mm/hmm.c:816:2: error: implicit declaration of function 'arch_remove_memory' 
[-Werror=implicit-function-declaration]
  arch_remove_memory(align_start, align_size, devmem->pagemap.type);
  ^
mm/hmm.c: In function 'hmm_devmem_find':
mm/hmm.c:827:54: error: 'PA_SECTION_SHIFT' undeclared (first use in this 
function)
  return radix_tree_lookup(_devmem_radix, phys >> PA_SECTION_SHIFT);
  ^
mm/hmm.c: In function 'hmm_devmem_pages_create':
mm/hmm.c:784:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this 
function)
 #define SECTION_SIZE (1UL << PA_SECTION_SHIFT)
  ^
mm/hmm.c:838:44: note: in expansion of macro 'SECTION_SIZE'
  align_start = devmem->resource->start & ~(SECTION_SIZE - 1);
^
In file included from ./include/linux/cache.h:4:0,
 from ./include/linux/printk.h:8,
 from ./include/linux/kernel.h:13,
 from ./include/asm-generic/bug.h:13,
 from ./arch/alpha/include/asm/bug.h:22,
 from ./include/linux/bug.h:4,
 from ./include/linux/mmdebug.h:4,
 from ./include/linux/mm.h:8,
 from mm/hmm.c:20:
mm/hmm.c: In function 'hmm_devmem_add':
mm/hmm.c:784:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this 
function)
 #define SECTION_SIZE (1UL << PA_SECTION_SHIFT)
  ^
./include/uapi/linux/kernel.h:10:47: note: in definition of macro 
'__ALIGN_KERNEL_MASK'
 #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
   ^
./include/linux/kernel.h:49:22: note: in expansion of macro '__ALIGN_KERNEL'
 #define ALIGN(x, a)  __ALIGN_KERNEL((x), (a))
  ^
mm/hmm.c:982:9: note: in expansion of macro 'ALIGN'
  size = ALIGN(size, SECTION_SIZE);
 ^
mm/hmm.c:982:21: note: in expansion of macro 'SECTION_SIZE'
  size = ALIGN(size, SECTION_SIZE);
 ^
mm/hmm.c: In function 'hmm_devmem_find':
mm/hmm.c:828:1: warning: control reaches end of non-void function 
[-Wreturn-type]
 }
 ^
cc1: some warnings being treated as errors
make[1]: *** [mm/hmm.o] Error 1
make[1]: *** Waiting for unfinished jobs
make: *** [mm] Error 2
make: *** Waiting for unfinished jobs
-- 
Michal Hocko
SUSE Labs


Re: [HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-10 Thread Michal Hocko
On Wed 05-04-17 16:40:20, Jérôme Glisse wrote:
> This does not use existing page table walker because we want to share
> same code for our page fault handler.

I am getting the following compilation error with sparc32
allmodconfig. I didn't check more closely yet.

mm/hmm.c: In function 'hmm_vma_walk_pmd':
mm/hmm.c:370:53: error: macro "pte_index" requires 2 arguments, but only 1 given
unsigned long pfn = pmd_pfn(pmd) + pte_index(addr);
 ^
mm/hmm.c:370:39: error: 'pte_index' undeclared (first use in this function)
unsigned long pfn = pmd_pfn(pmd) + pte_index(addr);
   ^
mm/hmm.c:370:39: note: each undeclared identifier is reported only once for 
each function it appears in
mm/hmm.c: In function 'hmm_devmem_release':
mm/hmm.c:816:2: error: implicit declaration of function 'arch_remove_memory' 
[-Werror=implicit-function-declaration]
  arch_remove_memory(align_start, align_size, devmem->pagemap.type);
  ^
cc1: some warnings being treated as errors
-- 
Michal Hocko
SUSE Labs


Re: [HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-10 Thread Michal Hocko
On Wed 05-04-17 16:40:20, Jérôme Glisse wrote:
> This does not use existing page table walker because we want to share
> same code for our page fault handler.

I am getting the following compilation error with sparc32
allmodconfig. I didn't check more closely yet.

mm/hmm.c: In function 'hmm_vma_walk_pmd':
mm/hmm.c:370:53: error: macro "pte_index" requires 2 arguments, but only 1 given
unsigned long pfn = pmd_pfn(pmd) + pte_index(addr);
 ^
mm/hmm.c:370:39: error: 'pte_index' undeclared (first use in this function)
unsigned long pfn = pmd_pfn(pmd) + pte_index(addr);
   ^
mm/hmm.c:370:39: note: each undeclared identifier is reported only once for 
each function it appears in
mm/hmm.c: In function 'hmm_devmem_release':
mm/hmm.c:816:2: error: implicit declaration of function 'arch_remove_memory' 
[-Werror=implicit-function-declaration]
  arch_remove_memory(align_start, align_size, devmem->pagemap.type);
  ^
cc1: some warnings being treated as errors
-- 
Michal Hocko
SUSE Labs


[HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-05 Thread Jérôme Glisse
This does not use existing page table walker because we want to share
same code for our page fault handler.

Changes since v1:
  - Use spinlock instead of rcu synchronized list traversal

Signed-off-by: Jérôme Glisse 
Signed-off-by: Evgeny Baskakov 
Signed-off-by: John Hubbard 
Signed-off-by: Mark Hairgrove 
Signed-off-by: Sherry Cheung 
Signed-off-by: Subhash Gutti 
---
 include/linux/hmm.h |  55 +-
 mm/hmm.c| 285 
 2 files changed, 338 insertions(+), 2 deletions(-)

diff --git a/include/linux/hmm.h b/include/linux/hmm.h
index 6668a1b..defa7cd 100644
--- a/include/linux/hmm.h
+++ b/include/linux/hmm.h
@@ -79,13 +79,26 @@ struct hmm;
  *
  * Flags:
  * HMM_PFN_VALID: pfn is valid
+ * HMM_PFN_READ:  CPU page table has read permission set
  * HMM_PFN_WRITE: CPU page table has write permission set
+ * HMM_PFN_ERROR: corresponding CPU page table entry points to poisoned memory
+ * HMM_PFN_EMPTY: corresponding CPU page table entry is pte_none()
+ * HMM_PFN_SPECIAL: corresponding CPU page table entry is special; i.e., the
+ *  result of vm_insert_pfn() or vm_insert_page(). Therefore, it should not
+ *  be mirrored by a device, because the entry will never have 
HMM_PFN_VALID
+ *  set and the pfn value is undefined.
+ * HMM_PFN_DEVICE_UNADDRESSABLE: unaddressable device memory (ZONE_DEVICE)
  */
 typedef unsigned long hmm_pfn_t;
 
 #define HMM_PFN_VALID (1 << 0)
-#define HMM_PFN_WRITE (1 << 1)
-#define HMM_PFN_SHIFT 2
+#define HMM_PFN_READ (1 << 1)
+#define HMM_PFN_WRITE (1 << 2)
+#define HMM_PFN_ERROR (1 << 3)
+#define HMM_PFN_EMPTY (1 << 4)
+#define HMM_PFN_SPECIAL (1 << 5)
+#define HMM_PFN_DEVICE_UNADDRESSABLE (1 << 6)
+#define HMM_PFN_SHIFT 7
 
 /*
  * hmm_pfn_t_to_page() - return struct page pointed to by a valid hmm_pfn_t
@@ -241,6 +254,44 @@ struct hmm_mirror {
 
 int hmm_mirror_register(struct hmm_mirror *mirror, struct mm_struct *mm);
 void hmm_mirror_unregister(struct hmm_mirror *mirror);
+
+
+/*
+ * struct hmm_range - track invalidation lock on virtual address range
+ *
+ * @list: all range lock are on a list
+ * @start: range virtual start address (inclusive)
+ * @end: range virtual end address (exclusive)
+ * @pfns: array of pfns (big enough for the range)
+ * @valid: pfns array did not change since it has been fill by an HMM function
+ */
+struct hmm_range {
+   struct list_headlist;
+   unsigned long   start;
+   unsigned long   end;
+   hmm_pfn_t   *pfns;
+   boolvalid;
+};
+
+/*
+ * To snapshot the CPU page table, call hmm_vma_get_pfns(), then take a device
+ * driver lock that serializes device page table updates, then call
+ * hmm_vma_range_done(), to check if the snapshot is still valid. The same
+ * device driver page table update lock must also be used in the
+ * hmm_mirror_ops.sync_cpu_device_pagetables() callback, so that CPU page
+ * table invalidation serializes on it.
+ *
+ * YOU MUST CALL hmm_vma_range_done() ONCE AND ONLY ONCE EACH TIME YOU CALL
+ * hmm_vma_get_pfns() WITHOUT ERROR !
+ *
+ * IF YOU DO NOT FOLLOW THE ABOVE RULE THE SNAPSHOT CONTENT MIGHT BE INVALID !
+ */
+int hmm_vma_get_pfns(struct vm_area_struct *vma,
+struct hmm_range *range,
+unsigned long start,
+unsigned long end,
+hmm_pfn_t *pfns);
+bool hmm_vma_range_done(struct vm_area_struct *vma, struct hmm_range *range);
 #endif /* IS_ENABLED(CONFIG_HMM_MIRROR) */
 
 
diff --git a/mm/hmm.c b/mm/hmm.c
index 7ed4b4c..4828b97 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -19,8 +19,12 @@
  */
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
+#include 
+#include 
 #include 
 
 static const struct mmu_notifier_ops hmm_mmu_notifier_ops;
@@ -30,14 +34,18 @@ static const struct mmu_notifier_ops hmm_mmu_notifier_ops;
  * struct hmm - HMM per mm struct
  *
  * @mm: mm struct this HMM struct is bound to
+ * @lock: lock protecting ranges list
  * @sequence: we track updates to the CPU page table with a sequence number
+ * @ranges: list of range being snapshotted
  * @mirrors: list of mirrors for this mm
  * @mmu_notifier: mmu notifier to track updates to CPU page table
  * @mirrors_sem: read/write semaphore protecting the mirrors list
  */
 struct hmm {
struct mm_struct*mm;
+   spinlock_t  lock;
atomic_tsequence;
+   struct list_headranges;
struct list_headmirrors;
struct mmu_notifier mmu_notifier;
struct rw_semaphore mirrors_sem;
@@ -71,6 +79,8 @@ static struct hmm *hmm_register(struct mm_struct *mm)
init_rwsem(>mirrors_sem);
atomic_set(>sequence, 0);
hmm->mmu_notifier.ops = NULL;
+   INIT_LIST_HEAD(>ranges);
+   

[HMM 10/16] mm/hmm/mirror: helper to snapshot CPU page table v2

2017-04-05 Thread Jérôme Glisse
This does not use existing page table walker because we want to share
same code for our page fault handler.

Changes since v1:
  - Use spinlock instead of rcu synchronized list traversal

Signed-off-by: Jérôme Glisse 
Signed-off-by: Evgeny Baskakov 
Signed-off-by: John Hubbard 
Signed-off-by: Mark Hairgrove 
Signed-off-by: Sherry Cheung 
Signed-off-by: Subhash Gutti 
---
 include/linux/hmm.h |  55 +-
 mm/hmm.c| 285 
 2 files changed, 338 insertions(+), 2 deletions(-)

diff --git a/include/linux/hmm.h b/include/linux/hmm.h
index 6668a1b..defa7cd 100644
--- a/include/linux/hmm.h
+++ b/include/linux/hmm.h
@@ -79,13 +79,26 @@ struct hmm;
  *
  * Flags:
  * HMM_PFN_VALID: pfn is valid
+ * HMM_PFN_READ:  CPU page table has read permission set
  * HMM_PFN_WRITE: CPU page table has write permission set
+ * HMM_PFN_ERROR: corresponding CPU page table entry points to poisoned memory
+ * HMM_PFN_EMPTY: corresponding CPU page table entry is pte_none()
+ * HMM_PFN_SPECIAL: corresponding CPU page table entry is special; i.e., the
+ *  result of vm_insert_pfn() or vm_insert_page(). Therefore, it should not
+ *  be mirrored by a device, because the entry will never have 
HMM_PFN_VALID
+ *  set and the pfn value is undefined.
+ * HMM_PFN_DEVICE_UNADDRESSABLE: unaddressable device memory (ZONE_DEVICE)
  */
 typedef unsigned long hmm_pfn_t;
 
 #define HMM_PFN_VALID (1 << 0)
-#define HMM_PFN_WRITE (1 << 1)
-#define HMM_PFN_SHIFT 2
+#define HMM_PFN_READ (1 << 1)
+#define HMM_PFN_WRITE (1 << 2)
+#define HMM_PFN_ERROR (1 << 3)
+#define HMM_PFN_EMPTY (1 << 4)
+#define HMM_PFN_SPECIAL (1 << 5)
+#define HMM_PFN_DEVICE_UNADDRESSABLE (1 << 6)
+#define HMM_PFN_SHIFT 7
 
 /*
  * hmm_pfn_t_to_page() - return struct page pointed to by a valid hmm_pfn_t
@@ -241,6 +254,44 @@ struct hmm_mirror {
 
 int hmm_mirror_register(struct hmm_mirror *mirror, struct mm_struct *mm);
 void hmm_mirror_unregister(struct hmm_mirror *mirror);
+
+
+/*
+ * struct hmm_range - track invalidation lock on virtual address range
+ *
+ * @list: all range lock are on a list
+ * @start: range virtual start address (inclusive)
+ * @end: range virtual end address (exclusive)
+ * @pfns: array of pfns (big enough for the range)
+ * @valid: pfns array did not change since it has been fill by an HMM function
+ */
+struct hmm_range {
+   struct list_headlist;
+   unsigned long   start;
+   unsigned long   end;
+   hmm_pfn_t   *pfns;
+   boolvalid;
+};
+
+/*
+ * To snapshot the CPU page table, call hmm_vma_get_pfns(), then take a device
+ * driver lock that serializes device page table updates, then call
+ * hmm_vma_range_done(), to check if the snapshot is still valid. The same
+ * device driver page table update lock must also be used in the
+ * hmm_mirror_ops.sync_cpu_device_pagetables() callback, so that CPU page
+ * table invalidation serializes on it.
+ *
+ * YOU MUST CALL hmm_vma_range_done() ONCE AND ONLY ONCE EACH TIME YOU CALL
+ * hmm_vma_get_pfns() WITHOUT ERROR !
+ *
+ * IF YOU DO NOT FOLLOW THE ABOVE RULE THE SNAPSHOT CONTENT MIGHT BE INVALID !
+ */
+int hmm_vma_get_pfns(struct vm_area_struct *vma,
+struct hmm_range *range,
+unsigned long start,
+unsigned long end,
+hmm_pfn_t *pfns);
+bool hmm_vma_range_done(struct vm_area_struct *vma, struct hmm_range *range);
 #endif /* IS_ENABLED(CONFIG_HMM_MIRROR) */
 
 
diff --git a/mm/hmm.c b/mm/hmm.c
index 7ed4b4c..4828b97 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -19,8 +19,12 @@
  */
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
+#include 
+#include 
 #include 
 
 static const struct mmu_notifier_ops hmm_mmu_notifier_ops;
@@ -30,14 +34,18 @@ static const struct mmu_notifier_ops hmm_mmu_notifier_ops;
  * struct hmm - HMM per mm struct
  *
  * @mm: mm struct this HMM struct is bound to
+ * @lock: lock protecting ranges list
  * @sequence: we track updates to the CPU page table with a sequence number
+ * @ranges: list of range being snapshotted
  * @mirrors: list of mirrors for this mm
  * @mmu_notifier: mmu notifier to track updates to CPU page table
  * @mirrors_sem: read/write semaphore protecting the mirrors list
  */
 struct hmm {
struct mm_struct*mm;
+   spinlock_t  lock;
atomic_tsequence;
+   struct list_headranges;
struct list_headmirrors;
struct mmu_notifier mmu_notifier;
struct rw_semaphore mirrors_sem;
@@ -71,6 +79,8 @@ static struct hmm *hmm_register(struct mm_struct *mm)
init_rwsem(>mirrors_sem);
atomic_set(>sequence, 0);
hmm->mmu_notifier.ops = NULL;
+   INIT_LIST_HEAD(>ranges);
+   spin_lock_init(>lock);
hmm->mm = mm;
 
/*
@@ -111,6 +121,22 @@ static void hmm_invalidate_range(struct hmm *hmm,