[PATCH v7 6/7] mm, hmm: Replace hmm_devmem_pages_create() with devm_memremap_pages()

2018-10-12 Thread Dan Williams
Commit e8d513483300 "memremap: change devm_memremap_pages interface to
use struct dev_pagemap" refactored devm_memremap_pages() to allow a
dev_pagemap instance to be supplied. Passing in a dev_pagemap interface
simplifies the design of pgmap type drivers in that they can rely on
container_of() to lookup any private data associated with the given
dev_pagemap instance.

In addition to the cleanups this also gives hmm users multi-order-radix
improvements that arrived with commit ab1b597ee0e4 "mm,
devm_memremap_pages: use multi-order radix for ZONE_DEVICE lookups"

As part of the conversion to the devm_memremap_pages() method of
handling the percpu_ref relative to when pages are put, the percpu_ref
completion needs to move to hmm_devmem_ref_exit(). See commit
71389703839e ("mm, zone_device: Replace {get, put}_zone_device_page...")
for details.

Reviewed-by: Christoph Hellwig 
Reviewed-by: Jérôme Glisse 
Acked-by: Balbir Singh 
Cc: Logan Gunthorpe 
Signed-off-by: Dan Williams 
---
 mm/hmm.c |  196 --
 1 file changed, 26 insertions(+), 170 deletions(-)

diff --git a/mm/hmm.c b/mm/hmm.c
index 60e4b275ad78..2e72cb4188ca 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -938,17 +938,16 @@ static void hmm_devmem_ref_exit(void *data)
struct hmm_devmem *devmem;
 
devmem = container_of(ref, struct hmm_devmem, ref);
+   wait_for_completion(>completion);
percpu_ref_exit(ref);
 }
 
-static void hmm_devmem_ref_kill(void *data)
+static void hmm_devmem_ref_kill(struct percpu_ref *ref)
 {
-   struct percpu_ref *ref = data;
struct hmm_devmem *devmem;
 
devmem = container_of(ref, struct hmm_devmem, ref);
percpu_ref_kill(ref);
-   wait_for_completion(>completion);
 }
 
 static int hmm_devmem_fault(struct vm_area_struct *vma,
@@ -971,154 +970,6 @@ static void hmm_devmem_free(struct page *page, void *data)
devmem->ops->free(devmem, page);
 }
 
-static DEFINE_MUTEX(hmm_devmem_lock);
-static RADIX_TREE(hmm_devmem_radix, GFP_KERNEL);
-
-static void hmm_devmem_radix_release(struct resource *resource)
-{
-   resource_size_t key;
-
-   mutex_lock(_devmem_lock);
-   for (key = resource->start;
-key <= resource->end;
-key += PA_SECTION_SIZE)
-   radix_tree_delete(_devmem_radix, key >> PA_SECTION_SHIFT);
-   mutex_unlock(_devmem_lock);
-}
-
-static void hmm_devmem_release(void *data)
-{
-   struct hmm_devmem *devmem = data;
-   struct resource *resource = devmem->resource;
-   unsigned long start_pfn, npages;
-   struct zone *zone;
-   struct page *page;
-
-   /* pages are dead and unused, undo the arch mapping */
-   start_pfn = (resource->start & ~(PA_SECTION_SIZE - 1)) >> PAGE_SHIFT;
-   npages = ALIGN(resource_size(resource), PA_SECTION_SIZE) >> PAGE_SHIFT;
-
-   page = pfn_to_page(start_pfn);
-   zone = page_zone(page);
-
-   mem_hotplug_begin();
-   if (resource->desc == IORES_DESC_DEVICE_PRIVATE_MEMORY)
-   __remove_pages(zone, start_pfn, npages, NULL);
-   else
-   arch_remove_memory(start_pfn << PAGE_SHIFT,
-  npages << PAGE_SHIFT, NULL);
-   mem_hotplug_done();
-
-   hmm_devmem_radix_release(resource);
-}
-
-static int hmm_devmem_pages_create(struct hmm_devmem *devmem)
-{
-   resource_size_t key, align_start, align_size, align_end;
-   struct device *device = devmem->device;
-   int ret, nid, is_ram;
-
-   align_start = devmem->resource->start & ~(PA_SECTION_SIZE - 1);
-   align_size = ALIGN(devmem->resource->start +
-  resource_size(devmem->resource),
-  PA_SECTION_SIZE) - align_start;
-
-   is_ram = region_intersects(align_start, align_size,
-  IORESOURCE_SYSTEM_RAM,
-  IORES_DESC_NONE);
-   if (is_ram == REGION_MIXED) {
-   WARN_ONCE(1, "%s attempted on mixed region %pr\n",
-   __func__, devmem->resource);
-   return -ENXIO;
-   }
-   if (is_ram == REGION_INTERSECTS)
-   return -ENXIO;
-
-   if (devmem->resource->desc == IORES_DESC_DEVICE_PUBLIC_MEMORY)
-   devmem->pagemap.type = MEMORY_DEVICE_PUBLIC;
-   else
-   devmem->pagemap.type = MEMORY_DEVICE_PRIVATE;
-
-   devmem->pagemap.res = *devmem->resource;
-   devmem->pagemap.page_fault = hmm_devmem_fault;
-   devmem->pagemap.page_free = hmm_devmem_free;
-   devmem->pagemap.dev = devmem->device;
-   devmem->pagemap.ref = >ref;
-   devmem->pagemap.data = devmem;
-
-   mutex_lock(_devmem_lock);
-   align_end = align_start + align_size - 1;
-   for (key = align_start; key <= align_end; key += PA_SECTION_SIZE) {
-   struct hmm_devmem *dup;
-
-   dup = radix_tree_lookup(_devmem_radix,
-  

[PATCH v7 6/7] mm, hmm: Replace hmm_devmem_pages_create() with devm_memremap_pages()

2018-10-12 Thread Dan Williams
Commit e8d513483300 "memremap: change devm_memremap_pages interface to
use struct dev_pagemap" refactored devm_memremap_pages() to allow a
dev_pagemap instance to be supplied. Passing in a dev_pagemap interface
simplifies the design of pgmap type drivers in that they can rely on
container_of() to lookup any private data associated with the given
dev_pagemap instance.

In addition to the cleanups this also gives hmm users multi-order-radix
improvements that arrived with commit ab1b597ee0e4 "mm,
devm_memremap_pages: use multi-order radix for ZONE_DEVICE lookups"

As part of the conversion to the devm_memremap_pages() method of
handling the percpu_ref relative to when pages are put, the percpu_ref
completion needs to move to hmm_devmem_ref_exit(). See commit
71389703839e ("mm, zone_device: Replace {get, put}_zone_device_page...")
for details.

Reviewed-by: Christoph Hellwig 
Reviewed-by: Jérôme Glisse 
Acked-by: Balbir Singh 
Cc: Logan Gunthorpe 
Signed-off-by: Dan Williams 
---
 mm/hmm.c |  196 --
 1 file changed, 26 insertions(+), 170 deletions(-)

diff --git a/mm/hmm.c b/mm/hmm.c
index 60e4b275ad78..2e72cb4188ca 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -938,17 +938,16 @@ static void hmm_devmem_ref_exit(void *data)
struct hmm_devmem *devmem;
 
devmem = container_of(ref, struct hmm_devmem, ref);
+   wait_for_completion(>completion);
percpu_ref_exit(ref);
 }
 
-static void hmm_devmem_ref_kill(void *data)
+static void hmm_devmem_ref_kill(struct percpu_ref *ref)
 {
-   struct percpu_ref *ref = data;
struct hmm_devmem *devmem;
 
devmem = container_of(ref, struct hmm_devmem, ref);
percpu_ref_kill(ref);
-   wait_for_completion(>completion);
 }
 
 static int hmm_devmem_fault(struct vm_area_struct *vma,
@@ -971,154 +970,6 @@ static void hmm_devmem_free(struct page *page, void *data)
devmem->ops->free(devmem, page);
 }
 
-static DEFINE_MUTEX(hmm_devmem_lock);
-static RADIX_TREE(hmm_devmem_radix, GFP_KERNEL);
-
-static void hmm_devmem_radix_release(struct resource *resource)
-{
-   resource_size_t key;
-
-   mutex_lock(_devmem_lock);
-   for (key = resource->start;
-key <= resource->end;
-key += PA_SECTION_SIZE)
-   radix_tree_delete(_devmem_radix, key >> PA_SECTION_SHIFT);
-   mutex_unlock(_devmem_lock);
-}
-
-static void hmm_devmem_release(void *data)
-{
-   struct hmm_devmem *devmem = data;
-   struct resource *resource = devmem->resource;
-   unsigned long start_pfn, npages;
-   struct zone *zone;
-   struct page *page;
-
-   /* pages are dead and unused, undo the arch mapping */
-   start_pfn = (resource->start & ~(PA_SECTION_SIZE - 1)) >> PAGE_SHIFT;
-   npages = ALIGN(resource_size(resource), PA_SECTION_SIZE) >> PAGE_SHIFT;
-
-   page = pfn_to_page(start_pfn);
-   zone = page_zone(page);
-
-   mem_hotplug_begin();
-   if (resource->desc == IORES_DESC_DEVICE_PRIVATE_MEMORY)
-   __remove_pages(zone, start_pfn, npages, NULL);
-   else
-   arch_remove_memory(start_pfn << PAGE_SHIFT,
-  npages << PAGE_SHIFT, NULL);
-   mem_hotplug_done();
-
-   hmm_devmem_radix_release(resource);
-}
-
-static int hmm_devmem_pages_create(struct hmm_devmem *devmem)
-{
-   resource_size_t key, align_start, align_size, align_end;
-   struct device *device = devmem->device;
-   int ret, nid, is_ram;
-
-   align_start = devmem->resource->start & ~(PA_SECTION_SIZE - 1);
-   align_size = ALIGN(devmem->resource->start +
-  resource_size(devmem->resource),
-  PA_SECTION_SIZE) - align_start;
-
-   is_ram = region_intersects(align_start, align_size,
-  IORESOURCE_SYSTEM_RAM,
-  IORES_DESC_NONE);
-   if (is_ram == REGION_MIXED) {
-   WARN_ONCE(1, "%s attempted on mixed region %pr\n",
-   __func__, devmem->resource);
-   return -ENXIO;
-   }
-   if (is_ram == REGION_INTERSECTS)
-   return -ENXIO;
-
-   if (devmem->resource->desc == IORES_DESC_DEVICE_PUBLIC_MEMORY)
-   devmem->pagemap.type = MEMORY_DEVICE_PUBLIC;
-   else
-   devmem->pagemap.type = MEMORY_DEVICE_PRIVATE;
-
-   devmem->pagemap.res = *devmem->resource;
-   devmem->pagemap.page_fault = hmm_devmem_fault;
-   devmem->pagemap.page_free = hmm_devmem_free;
-   devmem->pagemap.dev = devmem->device;
-   devmem->pagemap.ref = >ref;
-   devmem->pagemap.data = devmem;
-
-   mutex_lock(_devmem_lock);
-   align_end = align_start + align_size - 1;
-   for (key = align_start; key <= align_end; key += PA_SECTION_SIZE) {
-   struct hmm_devmem *dup;
-
-   dup = radix_tree_lookup(_devmem_radix,
-