aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dax
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dax')
-rw-r--r--drivers/dax/dax-private.h2
-rw-r--r--drivers/dax/kmem.c46
2 files changed, 43 insertions, 5 deletions
diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h
index c915889d1769..6ccca3b890d6 100644
--- a/drivers/dax/dax-private.h
+++ b/drivers/dax/dax-private.h
@@ -43,6 +43,7 @@ struct dax_region {
43 * @target_node: effective numa node if dev_dax memory range is onlined 43 * @target_node: effective numa node if dev_dax memory range is onlined
44 * @dev - device core 44 * @dev - device core
45 * @pgmap - pgmap for memmap setup / lifetime (driver owned) 45 * @pgmap - pgmap for memmap setup / lifetime (driver owned)
46 * @dax_mem_res: physical address range of hotadded DAX memory
46 */ 47 */
47struct dev_dax { 48struct dev_dax {
48 struct dax_region *region; 49 struct dax_region *region;
@@ -50,6 +51,7 @@ struct dev_dax {
50 int target_node; 51 int target_node;
51 struct device dev; 52 struct device dev;
52 struct dev_pagemap pgmap; 53 struct dev_pagemap pgmap;
54 struct resource *dax_kmem_res;
53}; 55};
54 56
55static inline struct dev_dax *to_dev_dax(struct device *dev) 57static inline struct dev_dax *to_dev_dax(struct device *dev)
diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c
index a02318c6d28a..3d0a7e702c94 100644
--- a/drivers/dax/kmem.c
+++ b/drivers/dax/kmem.c
@@ -66,23 +66,59 @@ int dev_dax_kmem_probe(struct device *dev)
66 new_res->name = dev_name(dev); 66 new_res->name = dev_name(dev);
67 67
68 rc = add_memory(numa_node, new_res->start, resource_size(new_res)); 68 rc = add_memory(numa_node, new_res->start, resource_size(new_res));
69 if (rc) 69 if (rc) {
70 release_resource(new_res);
71 kfree(new_res);
70 return rc; 72 return rc;
73 }
74 dev_dax->dax_kmem_res = new_res;
71 75
72 return 0; 76 return 0;
73} 77}
74 78
79#ifdef CONFIG_MEMORY_HOTREMOVE
80static int dev_dax_kmem_remove(struct device *dev)
81{
82 struct dev_dax *dev_dax = to_dev_dax(dev);
83 struct resource *res = dev_dax->dax_kmem_res;
84 resource_size_t kmem_start = res->start;
85 resource_size_t kmem_size = resource_size(res);
86 int rc;
87
88 /*
89 * We have one shot for removing memory, if some memory blocks were not
90 * offline prior to calling this function remove_memory() will fail, and
91 * there is no way to hotremove this memory until reboot because device
92 * unbind will succeed even if we return failure.
93 */
94 rc = remove_memory(dev_dax->target_node, kmem_start, kmem_size);
95 if (rc) {
96 dev_err(dev,
97 "DAX region %pR cannot be hotremoved until the next reboot\n",
98 res);
99 return rc;
100 }
101
102 /* Release and free dax resources */
103 release_resource(res);
104 kfree(res);
105 dev_dax->dax_kmem_res = NULL;
106
107 return 0;
108}
109#else
75static int dev_dax_kmem_remove(struct device *dev) 110static int dev_dax_kmem_remove(struct device *dev)
76{ 111{
77 /* 112 /*
78 * Purposely leak the request_mem_region() for the device-dax 113 * Without hotremove purposely leak the request_mem_region() for the
79 * range and return '0' to ->remove() attempts. The removal of 114 * device-dax range and return '0' to ->remove() attempts. The removal
80 * the device from the driver always succeeds, but the region 115 * of the device from the driver always succeeds, but the region is
81 * is permanently pinned as reserved by the unreleased 116 * permanently pinned as reserved by the unreleased
82 * request_mem_region(). 117 * request_mem_region().
83 */ 118 */
84 return 0; 119 return 0;
85} 120}
121#endif /* CONFIG_MEMORY_HOTREMOVE */
86 122
87static struct dax_device_driver device_dax_kmem_driver = { 123static struct dax_device_driver device_dax_kmem_driver = {
88 .drv = { 124 .drv = {