aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dax/dax.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-12-18 18:49:10 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-18 18:49:10 -0500
commit3be134e5152f08e8bd3c2afdaac723f64d93c2bb (patch)
treeba325ebb1a9f79a4a8451a8f5eaeed9cbd1c2e04 /drivers/dax/dax.c
parent8421c60446290c0fef1858a806261871a40ebf76 (diff)
parentc44ef859ceff45db1c72f9ccbfae96843c4b1501 (diff)
Merge tag 'libnvdimm-for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm updates from Dan Williams: "The libnvdimm pull request is relatively small this time around due to some development topics being deferred to 4.11. As for this pull request the bulk of it has been in -next for several releases leading to one late fix being added (commit 868f036fee4b ("libnvdimm: fix mishandled nvdimm_clear_poison() return value")). It has received a build success notification from the 0day-kbuild robot and passes the latest libnvdimm unit tests. Summary: - Dynamic label support: To date namespace label support has been limited to disambiguating cases where PMEM (direct load/store) and BLK (mmio aperture) accessed-capacity alias on the same DIMM. Since 4.9 added support for multiple namespaces per PMEM-region there is value to support namespace labels even in the non-aliasing case. The presence of a valid namespace index block force-enables label support when the kernel would otherwise rely on region boundaries, and permits the region to be sub-divided. - Handle media errors in namespace metadata: Complement the error handling for media errors in namespace data areas with support for clearing errors on writes, and downgrading potential machine-check exceptions to simple i/o errors on read. - Device-DAX region attributes: Add 'align', 'id', and 'size' as attributes for device-dax regions. In particular this enables userspace tooling to generically size memory mapping and i/o operations. Prevent userspace from growing assumptions / dependencies about the parent device topology for a dax region. A libnvdimm namespace may not always be the parent device of a dax region. - Various cleanups and small fixes" * tag 'libnvdimm-for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: dax: add region 'id', 'size', and 'align' attributes libnvdimm: fix mishandled nvdimm_clear_poison() return value libnvdimm: replace mutex_is_locked() warnings with lockdep_assert_held libnvdimm, pfn: fix align attribute libnvdimm, e820: use module_platform_driver libnvdimm, namespace: use octal for permissions libnvdimm, namespace: avoid multiple sector calculations libnvdimm: remove else after return in nsio_rw_bytes() libnvdimm, namespace: fix the type of name variable libnvdimm: use consistent naming for request_mem_region() nvdimm: use the right length of "pmem" libnvdimm: check and clear poison before writing to pmem tools/testing/nvdimm: dynamic label support libnvdimm: allow a platform to force enable label support libnvdimm: use generic iostat interfaces
Diffstat (limited to 'drivers/dax/dax.c')
-rw-r--r--drivers/dax/dax.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c
index 26ec39ddf21f..ed758b74ddf0 100644
--- a/drivers/dax/dax.c
+++ b/drivers/dax/dax.c
@@ -75,6 +75,73 @@ struct dax_dev {
75 struct resource res[0]; 75 struct resource res[0];
76}; 76};
77 77
78static ssize_t id_show(struct device *dev,
79 struct device_attribute *attr, char *buf)
80{
81 struct dax_region *dax_region;
82 ssize_t rc = -ENXIO;
83
84 device_lock(dev);
85 dax_region = dev_get_drvdata(dev);
86 if (dax_region)
87 rc = sprintf(buf, "%d\n", dax_region->id);
88 device_unlock(dev);
89
90 return rc;
91}
92static DEVICE_ATTR_RO(id);
93
94static ssize_t region_size_show(struct device *dev,
95 struct device_attribute *attr, char *buf)
96{
97 struct dax_region *dax_region;
98 ssize_t rc = -ENXIO;
99
100 device_lock(dev);
101 dax_region = dev_get_drvdata(dev);
102 if (dax_region)
103 rc = sprintf(buf, "%llu\n", (unsigned long long)
104 resource_size(&dax_region->res));
105 device_unlock(dev);
106
107 return rc;
108}
109static struct device_attribute dev_attr_region_size = __ATTR(size, 0444,
110 region_size_show, NULL);
111
112static ssize_t align_show(struct device *dev,
113 struct device_attribute *attr, char *buf)
114{
115 struct dax_region *dax_region;
116 ssize_t rc = -ENXIO;
117
118 device_lock(dev);
119 dax_region = dev_get_drvdata(dev);
120 if (dax_region)
121 rc = sprintf(buf, "%u\n", dax_region->align);
122 device_unlock(dev);
123
124 return rc;
125}
126static DEVICE_ATTR_RO(align);
127
128static struct attribute *dax_region_attributes[] = {
129 &dev_attr_region_size.attr,
130 &dev_attr_align.attr,
131 &dev_attr_id.attr,
132 NULL,
133};
134
135static const struct attribute_group dax_region_attribute_group = {
136 .name = "dax_region",
137 .attrs = dax_region_attributes,
138};
139
140static const struct attribute_group *dax_region_attribute_groups[] = {
141 &dax_region_attribute_group,
142 NULL,
143};
144
78static struct inode *dax_alloc_inode(struct super_block *sb) 145static struct inode *dax_alloc_inode(struct super_block *sb)
79{ 146{
80 return kmem_cache_alloc(dax_cache, GFP_KERNEL); 147 return kmem_cache_alloc(dax_cache, GFP_KERNEL);
@@ -200,12 +267,31 @@ void dax_region_put(struct dax_region *dax_region)
200} 267}
201EXPORT_SYMBOL_GPL(dax_region_put); 268EXPORT_SYMBOL_GPL(dax_region_put);
202 269
270static void dax_region_unregister(void *region)
271{
272 struct dax_region *dax_region = region;
273
274 sysfs_remove_groups(&dax_region->dev->kobj,
275 dax_region_attribute_groups);
276 dax_region_put(dax_region);
277}
278
203struct dax_region *alloc_dax_region(struct device *parent, int region_id, 279struct dax_region *alloc_dax_region(struct device *parent, int region_id,
204 struct resource *res, unsigned int align, void *addr, 280 struct resource *res, unsigned int align, void *addr,
205 unsigned long pfn_flags) 281 unsigned long pfn_flags)
206{ 282{
207 struct dax_region *dax_region; 283 struct dax_region *dax_region;
208 284
285 /*
286 * The DAX core assumes that it can store its private data in
287 * parent->driver_data. This WARN is a reminder / safeguard for
288 * developers of device-dax drivers.
289 */
290 if (dev_get_drvdata(parent)) {
291 dev_WARN(parent, "dax core failed to setup private data\n");
292 return NULL;
293 }
294
209 if (!IS_ALIGNED(res->start, align) 295 if (!IS_ALIGNED(res->start, align)
210 || !IS_ALIGNED(resource_size(res), align)) 296 || !IS_ALIGNED(resource_size(res), align))
211 return NULL; 297 return NULL;
@@ -214,6 +300,7 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
214 if (!dax_region) 300 if (!dax_region)
215 return NULL; 301 return NULL;
216 302
303 dev_set_drvdata(parent, dax_region);
217 memcpy(&dax_region->res, res, sizeof(*res)); 304 memcpy(&dax_region->res, res, sizeof(*res));
218 dax_region->pfn_flags = pfn_flags; 305 dax_region->pfn_flags = pfn_flags;
219 kref_init(&dax_region->kref); 306 kref_init(&dax_region->kref);
@@ -222,7 +309,14 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
222 dax_region->align = align; 309 dax_region->align = align;
223 dax_region->dev = parent; 310 dax_region->dev = parent;
224 dax_region->base = addr; 311 dax_region->base = addr;
312 if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) {
313 kfree(dax_region);
314 return NULL;;
315 }
225 316
317 kref_get(&dax_region->kref);
318 if (devm_add_action_or_reset(parent, dax_region_unregister, dax_region))
319 return NULL;
226 return dax_region; 320 return dax_region;
227} 321}
228EXPORT_SYMBOL_GPL(alloc_dax_region); 322EXPORT_SYMBOL_GPL(alloc_dax_region);