Hi,
The v5 series of the device-dax-subdivision series landed upstream which
missed some of the late breaking fixups in v6 [1]. The Xen one is
cosmetic, the kmem one is a functional problem. I will handle the kmem
in a device-dax follow-on pull request post-rc1. The Xen one can go
through the Xen tree at its own pace.
My thanks to Andrew for wrangling the thrash up to v5, and my apologies
to Andrew et al for not highlighting this gap sooner.
[1]: http://lore.kernel.org/r/160196728453.2166475.12832711415715687418.stgit@dwillia2-desk3.amr.corp.intel.com
---
Dan Williams (2):
device-dax/kmem: Fix resource release
xen/unpopulated-alloc: Consolidate pgmap manipulation
drivers/dax/kmem.c | 48 ++++++++++++++++++++++++++++-----------
drivers/xen/unpopulated-alloc.c | 14 ++++++-----
2 files changed, 41 insertions(+), 21 deletions(-)
base-commit: 4da9af0014b51c8b015ed8c622440ef28912efe6
Cleanup fill_list() to keep all the pgmap manipulations in a single
location of the function. Update the exit unwind path accordingly.
Link: http://lore.kernel.org/r/[email protected]
Cc: Juergen Gross <[email protected]>
Cc: Stefano Stabellini <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: <[email protected]>
Reported-by: Boris Ostrovsky <[email protected]>
Signed-off-by: Dan Williams <[email protected]>
---
drivers/xen/unpopulated-alloc.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/xen/unpopulated-alloc.c b/drivers/xen/unpopulated-alloc.c
index 8c512ea550bb..75ab5de99868 100644
--- a/drivers/xen/unpopulated-alloc.c
+++ b/drivers/xen/unpopulated-alloc.c
@@ -27,11 +27,6 @@ static int fill_list(unsigned int nr_pages)
if (!res)
return -ENOMEM;
- pgmap = kzalloc(sizeof(*pgmap), GFP_KERNEL);
- if (!pgmap)
- goto err_pgmap;
-
- pgmap->type = MEMORY_DEVICE_GENERIC;
res->name = "Xen scratch";
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
@@ -43,6 +38,11 @@ static int fill_list(unsigned int nr_pages)
goto err_resource;
}
+ pgmap = kzalloc(sizeof(*pgmap), GFP_KERNEL);
+ if (!pgmap)
+ goto err_pgmap;
+
+ pgmap->type = MEMORY_DEVICE_GENERIC;
pgmap->range = (struct range) {
.start = res->start,
.end = res->end,
@@ -91,10 +91,10 @@ static int fill_list(unsigned int nr_pages)
return 0;
err_memremap:
- release_resource(res);
-err_resource:
kfree(pgmap);
err_pgmap:
+ release_resource(res);
+err_resource:
kfree(res);
return ret;
}
The conversion to request_mem_region() is broken because it assumes that
the range is marked busy prior to release. However, due to the way that
the kmem driver manipulates the IORESOURCE_BUSY flag (clears it to
let {add,remove}_memory() handle busy) it requires a manual
release_resource() to perform cleanup.
Given that the actual 'struct resource *' needs to be recalled, not just
the range, add that tracking to the kmem driver-data.
Reported-by: David Hildenbrand <[email protected]>
Fixes: 0513bd5bb114 ("device-dax/kmem: replace release_resource() with release_mem_region()")
Cc: Vishal Verma <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: Pavel Tatashin <[email protected]>
Cc: Brice Goglin <[email protected]>
Cc: Dave Jiang <[email protected]>
Cc: Ira Weiny <[email protected]>
Cc: Jia He <[email protected]>
Cc: Joao Martins <[email protected]>
Cc: Jonathan Cameron <[email protected]>
Signed-off-by: Dan Williams <[email protected]>
---
drivers/dax/kmem.c | 48 ++++++++++++++++++++++++++++++++++--------------
1 file changed, 34 insertions(+), 14 deletions(-)
diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c
index 6c933f2b604e..af04b6d1d263 100644
--- a/drivers/dax/kmem.c
+++ b/drivers/dax/kmem.c
@@ -35,11 +35,17 @@ static int dax_kmem_range(struct dev_dax *dev_dax, int i, struct range *r)
return 0;
}
+struct dax_kmem_data {
+ const char *res_name;
+ struct resource *res[];
+};
+
static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
{
struct device *dev = &dev_dax->dev;
+ struct dax_kmem_data *data;
+ int rc = -ENOMEM;
int i, mapped = 0;
- char *res_name;
int numa_node;
/*
@@ -55,14 +61,17 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
return -EINVAL;
}
- res_name = kstrdup(dev_name(dev), GFP_KERNEL);
- if (!res_name)
+ data = kzalloc(sizeof(*data) + sizeof(struct resource *) * dev_dax->nr_range, GFP_KERNEL);
+ if (!data)
return -ENOMEM;
+ data->res_name = kstrdup(dev_name(dev), GFP_KERNEL);
+ if (!data->res_name)
+ goto err_res_name;
+
for (i = 0; i < dev_dax->nr_range; i++) {
struct resource *res;
struct range range;
- int rc;
rc = dax_kmem_range(dev_dax, i, &range);
if (rc) {
@@ -72,7 +81,7 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
}
/* Region is permanently reserved if hotremove fails. */
- res = request_mem_region(range.start, range_len(&range), res_name);
+ res = request_mem_region(range.start, range_len(&range), data->res_name);
if (!res) {
dev_warn(dev, "mapping%d: %#llx-%#llx could not reserve region\n",
i, range.start, range.end);
@@ -82,9 +91,10 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
*/
if (mapped)
continue;
- kfree(res_name);
- return -EBUSY;
+ rc = -EBUSY;
+ goto err_request_mem;
}
+ data->res[i] = res;
/*
* Set flags appropriate for System RAM. Leave ..._BUSY clear
@@ -104,18 +114,25 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
if (rc) {
dev_warn(dev, "mapping%d: %#llx-%#llx memory add failed\n",
i, range.start, range.end);
- release_mem_region(range.start, range_len(&range));
+ release_resource(res);
+ kfree(res);
+ data->res[i] = NULL;
if (mapped)
continue;
- kfree(res_name);
- return rc;
+ goto err_request_mem;
}
mapped++;
}
- dev_set_drvdata(dev, res_name);
+ dev_set_drvdata(dev, data);
return 0;
+
+err_request_mem:
+ kfree(data->res_name);
+err_res_name:
+ kfree(data);
+ return rc;
}
#ifdef CONFIG_MEMORY_HOTREMOVE
@@ -123,7 +140,7 @@ static int dev_dax_kmem_remove(struct dev_dax *dev_dax)
{
int i, success = 0;
struct device *dev = &dev_dax->dev;
- const char *res_name = dev_get_drvdata(dev);
+ struct dax_kmem_data *data = dev_get_drvdata(dev);
/*
* We have one shot for removing memory, if some memory blocks were not
@@ -142,7 +159,9 @@ static int dev_dax_kmem_remove(struct dev_dax *dev_dax)
rc = remove_memory(dev_dax->target_node, range.start,
range_len(&range));
if (rc == 0) {
- release_mem_region(range.start, range_len(&range));
+ release_resource(data->res[i]);
+ kfree(data->res[i]);
+ data->res[i] = NULL;
success++;
continue;
}
@@ -153,7 +172,8 @@ static int dev_dax_kmem_remove(struct dev_dax *dev_dax)
}
if (success >= dev_dax->nr_range) {
- kfree(res_name);
+ kfree(data->res_name);
+ kfree(data);
dev_set_drvdata(dev, NULL);
}
On 15.10.20 02:42, Dan Williams wrote:
> The conversion to request_mem_region() is broken because it assumes that
> the range is marked busy prior to release. However, due to the way that
> the kmem driver manipulates the IORESOURCE_BUSY flag (clears it to
> let {add,remove}_memory() handle busy) it requires a manual
> release_resource() to perform cleanup.
>
> Given that the actual 'struct resource *' needs to be recalled, not just
> the range, add that tracking to the kmem driver-data.
>
> Reported-by: David Hildenbrand <[email protected]>
> Fixes: 0513bd5bb114 ("device-dax/kmem: replace release_resource() with release_mem_region()")
> Cc: Vishal Verma <[email protected]>
> Cc: Dave Hansen <[email protected]>
> Cc: Pavel Tatashin <[email protected]>
> Cc: Brice Goglin <[email protected]>
> Cc: Dave Jiang <[email protected]>
> Cc: Ira Weiny <[email protected]>
> Cc: Jia He <[email protected]>
> Cc: Joao Martins <[email protected]>
> Cc: Jonathan Cameron <[email protected]>
> Signed-off-by: Dan Williams <[email protected]>
> ---
> drivers/dax/kmem.c | 48 ++++++++++++++++++++++++++++++++++--------------
> 1 file changed, 34 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c
> index 6c933f2b604e..af04b6d1d263 100644
> --- a/drivers/dax/kmem.c
> +++ b/drivers/dax/kmem.c
> @@ -35,11 +35,17 @@ static int dax_kmem_range(struct dev_dax *dev_dax, int i, struct range *r)
> return 0;
> }
>
> +struct dax_kmem_data {
> + const char *res_name;
> + struct resource *res[];
> +};
> +
> static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
> {
> struct device *dev = &dev_dax->dev;
> + struct dax_kmem_data *data;
> + int rc = -ENOMEM;
> int i, mapped = 0;
> - char *res_name;
> int numa_node;
>
> /*
> @@ -55,14 +61,17 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
> return -EINVAL;
> }
>
> - res_name = kstrdup(dev_name(dev), GFP_KERNEL);
> - if (!res_name)
> + data = kzalloc(sizeof(*data) + sizeof(struct resource *) * dev_dax->nr_range, GFP_KERNEL);
> + if (!data)
> return -ENOMEM;
>
> + data->res_name = kstrdup(dev_name(dev), GFP_KERNEL);
> + if (!data->res_name)
> + goto err_res_name;
> +
> for (i = 0; i < dev_dax->nr_range; i++) {
> struct resource *res;
> struct range range;
> - int rc;
>
> rc = dax_kmem_range(dev_dax, i, &range);
> if (rc) {
> @@ -72,7 +81,7 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
> }
>
> /* Region is permanently reserved if hotremove fails. */
> - res = request_mem_region(range.start, range_len(&range), res_name);
> + res = request_mem_region(range.start, range_len(&range), data->res_name);
> if (!res) {
> dev_warn(dev, "mapping%d: %#llx-%#llx could not reserve region\n",
> i, range.start, range.end);
> @@ -82,9 +91,10 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
> */
> if (mapped)
> continue;
> - kfree(res_name);
> - return -EBUSY;
> + rc = -EBUSY;
> + goto err_request_mem;
> }
> + data->res[i] = res;
>
> /*
> * Set flags appropriate for System RAM. Leave ..._BUSY clear
> @@ -104,18 +114,25 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
> if (rc) {
> dev_warn(dev, "mapping%d: %#llx-%#llx memory add failed\n",
> i, range.start, range.end);
> - release_mem_region(range.start, range_len(&range));
> + release_resource(res);
> + kfree(res);
> + data->res[i] = NULL;
> if (mapped)
> continue;
> - kfree(res_name);
> - return rc;
> + goto err_request_mem;
> }
> mapped++;
> }
>
> - dev_set_drvdata(dev, res_name);
> + dev_set_drvdata(dev, data);
>
> return 0;
> +
> +err_request_mem:
> + kfree(data->res_name);
> +err_res_name:
> + kfree(data);
> + return rc;
> }
>
> #ifdef CONFIG_MEMORY_HOTREMOVE
> @@ -123,7 +140,7 @@ static int dev_dax_kmem_remove(struct dev_dax *dev_dax)
> {
> int i, success = 0;
> struct device *dev = &dev_dax->dev;
> - const char *res_name = dev_get_drvdata(dev);
> + struct dax_kmem_data *data = dev_get_drvdata(dev);
>
> /*
> * We have one shot for removing memory, if some memory blocks were not
> @@ -142,7 +159,9 @@ static int dev_dax_kmem_remove(struct dev_dax *dev_dax)
> rc = remove_memory(dev_dax->target_node, range.start,
> range_len(&range));
> if (rc == 0) {
> - release_mem_region(range.start, range_len(&range));
> + release_resource(data->res[i]);
> + kfree(data->res[i]);
> + data->res[i] = NULL;
> success++;
> continue;
> }
> @@ -153,7 +172,8 @@ static int dev_dax_kmem_remove(struct dev_dax *dev_dax)
> }
>
> if (success >= dev_dax->nr_range) {
> - kfree(res_name);
> + kfree(data->res_name);
> + kfree(data);
> dev_set_drvdata(dev, NULL);
> }
>
>
Looks sane to me
Reviewed-by: David Hildenbrand <[email protected]>
--
Thanks,
David / dhildenb