Skip to content

Commit cd03412

Browse files
committed
libnvdimm, dax: introduce device-dax infrastructure
Device DAX is the device-centric analogue of Filesystem DAX (CONFIG_FS_DAX). It allows persistent memory ranges to be allocated and mapped without need of an intervening file system. This initial infrastructure arranges for a libnvdimm pfn-device to be represented as a different device-type so that it can be attached to a driver other than the pmem driver. Signed-off-by: Dan Williams <[email protected]>
1 parent 0bfb8dd commit cd03412

File tree

13 files changed

+264
-34
lines changed

13 files changed

+264
-34
lines changed

drivers/nvdimm/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,17 @@ config NVDIMM_PFN
8888

8989
Select Y if unsure
9090

91+
config NVDIMM_DAX
92+
bool "NVDIMM DAX: Raw access to persistent memory"
93+
default LIBNVDIMM
94+
depends on NVDIMM_PFN
95+
help
96+
Support raw device dax access to a persistent memory
97+
namespace. For environments that want to hard partition
98+
peristent memory, this capability provides a mechanism to
99+
sub-divide a namespace into character devices that can only be
100+
accessed via DAX (mmap(2)).
101+
102+
Select Y if unsure
103+
91104
endif

drivers/nvdimm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ libnvdimm-y += label.o
2323
libnvdimm-$(CONFIG_ND_CLAIM) += claim.o
2424
libnvdimm-$(CONFIG_BTT) += btt_devs.o
2525
libnvdimm-$(CONFIG_NVDIMM_PFN) += pfn_devs.o
26+
libnvdimm-$(CONFIG_NVDIMM_DAX) += dax_devs.o

drivers/nvdimm/bus.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ static int to_nd_device_type(struct device *dev)
4040
return ND_DEVICE_REGION_PMEM;
4141
else if (is_nd_blk(dev))
4242
return ND_DEVICE_REGION_BLK;
43+
else if (is_nd_dax(dev))
44+
return ND_DEVICE_DAX_PMEM;
4345
else if (is_nd_pmem(dev->parent) || is_nd_blk(dev->parent))
4446
return nd_region_to_nstype(to_nd_region(dev->parent));
4547

@@ -246,6 +248,8 @@ static void nd_async_device_unregister(void *d, async_cookie_t cookie)
246248

247249
void __nd_device_register(struct device *dev)
248250
{
251+
if (!dev)
252+
return;
249253
dev->bus = &nvdimm_bus_type;
250254
get_device(dev);
251255
async_schedule_domain(nd_async_device_register, dev,

drivers/nvdimm/claim.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ static bool is_idle(struct device *dev, struct nd_namespace_common *ndns)
8585
seed = nd_region->btt_seed;
8686
else if (is_nd_pfn(dev))
8787
seed = nd_region->pfn_seed;
88+
else if (is_nd_dax(dev))
89+
seed = nd_region->dax_seed;
8890

8991
if (seed == dev || ndns || dev->driver)
9092
return false;

drivers/nvdimm/dax_devs.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright(c) 2013-2016 Intel Corporation. All rights reserved.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of version 2 of the GNU General Public License as
6+
* published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful, but
9+
* WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+
* General Public License for more details.
12+
*/
13+
#include <linux/device.h>
14+
#include <linux/sizes.h>
15+
#include <linux/slab.h>
16+
#include <linux/mm.h>
17+
#include "nd-core.h"
18+
#include "nd.h"
19+
20+
static void nd_dax_release(struct device *dev)
21+
{
22+
struct nd_region *nd_region = to_nd_region(dev->parent);
23+
struct nd_dax *nd_dax = to_nd_dax(dev);
24+
struct nd_pfn *nd_pfn = &nd_dax->nd_pfn;
25+
26+
dev_dbg(dev, "%s\n", __func__);
27+
nd_detach_ndns(dev, &nd_pfn->ndns);
28+
ida_simple_remove(&nd_region->dax_ida, nd_pfn->id);
29+
kfree(nd_pfn->uuid);
30+
kfree(nd_dax);
31+
}
32+
33+
static struct device_type nd_dax_device_type = {
34+
.name = "nd_dax",
35+
.release = nd_dax_release,
36+
};
37+
38+
bool is_nd_dax(struct device *dev)
39+
{
40+
return dev ? dev->type == &nd_dax_device_type : false;
41+
}
42+
EXPORT_SYMBOL(is_nd_dax);
43+
44+
struct nd_dax *to_nd_dax(struct device *dev)
45+
{
46+
struct nd_dax *nd_dax = container_of(dev, struct nd_dax, nd_pfn.dev);
47+
48+
WARN_ON(!is_nd_dax(dev));
49+
return nd_dax;
50+
}
51+
EXPORT_SYMBOL(to_nd_dax);
52+
53+
static const struct attribute_group *nd_dax_attribute_groups[] = {
54+
&nd_pfn_attribute_group,
55+
&nd_device_attribute_group,
56+
&nd_numa_attribute_group,
57+
NULL,
58+
};
59+
60+
static struct nd_dax *nd_dax_alloc(struct nd_region *nd_region)
61+
{
62+
struct nd_pfn *nd_pfn;
63+
struct nd_dax *nd_dax;
64+
struct device *dev;
65+
66+
nd_dax = kzalloc(sizeof(*nd_dax), GFP_KERNEL);
67+
if (!nd_dax)
68+
return NULL;
69+
70+
nd_pfn = &nd_dax->nd_pfn;
71+
nd_pfn->id = ida_simple_get(&nd_region->dax_ida, 0, 0, GFP_KERNEL);
72+
if (nd_pfn->id < 0) {
73+
kfree(nd_dax);
74+
return NULL;
75+
}
76+
77+
dev = &nd_pfn->dev;
78+
dev_set_name(dev, "dax%d.%d", nd_region->id, nd_pfn->id);
79+
dev->groups = nd_dax_attribute_groups;
80+
dev->type = &nd_dax_device_type;
81+
dev->parent = &nd_region->dev;
82+
83+
return nd_dax;
84+
}
85+
86+
struct device *nd_dax_create(struct nd_region *nd_region)
87+
{
88+
struct device *dev = NULL;
89+
struct nd_dax *nd_dax;
90+
91+
if (!is_nd_pmem(&nd_region->dev))
92+
return NULL;
93+
94+
nd_dax = nd_dax_alloc(nd_region);
95+
if (nd_dax)
96+
dev = nd_pfn_devinit(&nd_dax->nd_pfn, NULL);
97+
__nd_device_register(dev);
98+
return dev;
99+
}

drivers/nvdimm/namespace_devs.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,8 @@ static ssize_t mode_show(struct device *dev,
12881288
mode = "safe";
12891289
else if (claim && is_nd_pfn(claim))
12901290
mode = "memory";
1291+
else if (claim && is_nd_dax(claim))
1292+
mode = "dax";
12911293
else if (!claim && pmem_should_map_pages(dev))
12921294
mode = "memory";
12931295
else
@@ -1379,14 +1381,17 @@ struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev)
13791381
{
13801382
struct nd_btt *nd_btt = is_nd_btt(dev) ? to_nd_btt(dev) : NULL;
13811383
struct nd_pfn *nd_pfn = is_nd_pfn(dev) ? to_nd_pfn(dev) : NULL;
1384+
struct nd_dax *nd_dax = is_nd_dax(dev) ? to_nd_dax(dev) : NULL;
13821385
struct nd_namespace_common *ndns = NULL;
13831386
resource_size_t size;
13841387

1385-
if (nd_btt || nd_pfn) {
1388+
if (nd_btt || nd_pfn || nd_dax) {
13861389
if (nd_btt)
13871390
ndns = nd_btt->ndns;
13881391
else if (nd_pfn)
13891392
ndns = nd_pfn->ndns;
1393+
else if (nd_dax)
1394+
ndns = nd_dax->nd_pfn.ndns;
13901395

13911396
if (!ndns)
13921397
return ERR_PTR(-ENODEV);
@@ -1779,6 +1784,18 @@ void nd_region_create_blk_seed(struct nd_region *nd_region)
17791784
nd_device_register(nd_region->ns_seed);
17801785
}
17811786

1787+
void nd_region_create_dax_seed(struct nd_region *nd_region)
1788+
{
1789+
WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev));
1790+
nd_region->dax_seed = nd_dax_create(nd_region);
1791+
/*
1792+
* Seed creation failures are not fatal, provisioning is simply
1793+
* disabled until memory becomes available
1794+
*/
1795+
if (!nd_region->dax_seed)
1796+
dev_err(&nd_region->dev, "failed to create dax namespace\n");
1797+
}
1798+
17821799
void nd_region_create_pfn_seed(struct nd_region *nd_region)
17831800
{
17841801
WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev));

drivers/nvdimm/nd-core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ struct nd_region;
5454
void nd_region_create_blk_seed(struct nd_region *nd_region);
5555
void nd_region_create_btt_seed(struct nd_region *nd_region);
5656
void nd_region_create_pfn_seed(struct nd_region *nd_region);
57+
void nd_region_create_dax_seed(struct nd_region *nd_region);
5758
void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev);
5859
int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus);
5960
void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus);

drivers/nvdimm/nd.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,12 @@ struct nd_region {
101101
struct ida ns_ida;
102102
struct ida btt_ida;
103103
struct ida pfn_ida;
104+
struct ida dax_ida;
104105
unsigned long flags;
105106
struct device *ns_seed;
106107
struct device *btt_seed;
107108
struct device *pfn_seed;
109+
struct device *dax_seed;
108110
u16 ndr_mappings;
109111
u64 ndr_size;
110112
u64 ndr_start;
@@ -161,6 +163,10 @@ struct nd_pfn {
161163
struct nd_namespace_common *ndns;
162164
};
163165

166+
struct nd_dax {
167+
struct nd_pfn nd_pfn;
168+
};
169+
164170
enum nd_async_mode {
165171
ND_SYNC,
166172
ND_ASYNC,
@@ -224,7 +230,10 @@ struct nd_pfn *to_nd_pfn(struct device *dev);
224230
int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns);
225231
bool is_nd_pfn(struct device *dev);
226232
struct device *nd_pfn_create(struct nd_region *nd_region);
233+
struct device *nd_pfn_devinit(struct nd_pfn *nd_pfn,
234+
struct nd_namespace_common *ndns);
227235
int nd_pfn_validate(struct nd_pfn *nd_pfn);
236+
extern struct attribute_group nd_pfn_attribute_group;
228237
#else
229238
static inline int nd_pfn_probe(struct device *dev,
230239
struct nd_namespace_common *ndns)
@@ -248,6 +257,22 @@ static inline int nd_pfn_validate(struct nd_pfn *nd_pfn)
248257
}
249258
#endif
250259

260+
struct nd_dax *to_nd_dax(struct device *dev);
261+
#if IS_ENABLED(CONFIG_NVDIMM_DAX)
262+
bool is_nd_dax(struct device *dev);
263+
struct device *nd_dax_create(struct nd_region *nd_region);
264+
#else
265+
static inline bool is_nd_dax(struct device *dev)
266+
{
267+
return false;
268+
}
269+
270+
static inline struct device *nd_dax_create(struct nd_region *nd_region)
271+
{
272+
return NULL;
273+
}
274+
#endif
275+
251276
struct nd_region *to_nd_region(struct device *dev);
252277
int nd_region_to_nstype(struct nd_region *nd_region);
253278
int nd_region_register_namespaces(struct nd_region *nd_region, int *err);

0 commit comments

Comments
 (0)