Skip to content

Commit

Permalink
libnvdimm, dax: introduce device-dax infrastructure
Browse files Browse the repository at this point in the history
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 <dan.j.williams@intel.com>
  • Loading branch information
Dan Williams committed May 9, 2016
1 parent 0bfb8dd commit cd03412
Show file tree
Hide file tree
Showing 13 changed files with 264 additions and 34 deletions.
13 changes: 13 additions & 0 deletions drivers/nvdimm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,17 @@ config NVDIMM_PFN

Select Y if unsure

config NVDIMM_DAX
bool "NVDIMM DAX: Raw access to persistent memory"
default LIBNVDIMM
depends on NVDIMM_PFN
help
Support raw device dax access to a persistent memory
namespace. For environments that want to hard partition
peristent memory, this capability provides a mechanism to
sub-divide a namespace into character devices that can only be
accessed via DAX (mmap(2)).

Select Y if unsure

endif
1 change: 1 addition & 0 deletions drivers/nvdimm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ libnvdimm-y += label.o
libnvdimm-$(CONFIG_ND_CLAIM) += claim.o
libnvdimm-$(CONFIG_BTT) += btt_devs.o
libnvdimm-$(CONFIG_NVDIMM_PFN) += pfn_devs.o
libnvdimm-$(CONFIG_NVDIMM_DAX) += dax_devs.o
4 changes: 4 additions & 0 deletions drivers/nvdimm/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ static int to_nd_device_type(struct device *dev)
return ND_DEVICE_REGION_PMEM;
else if (is_nd_blk(dev))
return ND_DEVICE_REGION_BLK;
else if (is_nd_dax(dev))
return ND_DEVICE_DAX_PMEM;
else if (is_nd_pmem(dev->parent) || is_nd_blk(dev->parent))
return nd_region_to_nstype(to_nd_region(dev->parent));

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

void __nd_device_register(struct device *dev)
{
if (!dev)
return;
dev->bus = &nvdimm_bus_type;
get_device(dev);
async_schedule_domain(nd_async_device_register, dev,
Expand Down
2 changes: 2 additions & 0 deletions drivers/nvdimm/claim.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ static bool is_idle(struct device *dev, struct nd_namespace_common *ndns)
seed = nd_region->btt_seed;
else if (is_nd_pfn(dev))
seed = nd_region->pfn_seed;
else if (is_nd_dax(dev))
seed = nd_region->dax_seed;

if (seed == dev || ndns || dev->driver)
return false;
Expand Down
99 changes: 99 additions & 0 deletions drivers/nvdimm/dax_devs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright(c) 2013-2016 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/device.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include "nd-core.h"
#include "nd.h"

static void nd_dax_release(struct device *dev)
{
struct nd_region *nd_region = to_nd_region(dev->parent);
struct nd_dax *nd_dax = to_nd_dax(dev);
struct nd_pfn *nd_pfn = &nd_dax->nd_pfn;

dev_dbg(dev, "%s\n", __func__);
nd_detach_ndns(dev, &nd_pfn->ndns);
ida_simple_remove(&nd_region->dax_ida, nd_pfn->id);
kfree(nd_pfn->uuid);
kfree(nd_dax);
}

static struct device_type nd_dax_device_type = {
.name = "nd_dax",
.release = nd_dax_release,
};

bool is_nd_dax(struct device *dev)
{
return dev ? dev->type == &nd_dax_device_type : false;
}
EXPORT_SYMBOL(is_nd_dax);

struct nd_dax *to_nd_dax(struct device *dev)
{
struct nd_dax *nd_dax = container_of(dev, struct nd_dax, nd_pfn.dev);

WARN_ON(!is_nd_dax(dev));
return nd_dax;
}
EXPORT_SYMBOL(to_nd_dax);

static const struct attribute_group *nd_dax_attribute_groups[] = {
&nd_pfn_attribute_group,
&nd_device_attribute_group,
&nd_numa_attribute_group,
NULL,
};

static struct nd_dax *nd_dax_alloc(struct nd_region *nd_region)
{
struct nd_pfn *nd_pfn;
struct nd_dax *nd_dax;
struct device *dev;

nd_dax = kzalloc(sizeof(*nd_dax), GFP_KERNEL);
if (!nd_dax)
return NULL;

nd_pfn = &nd_dax->nd_pfn;
nd_pfn->id = ida_simple_get(&nd_region->dax_ida, 0, 0, GFP_KERNEL);
if (nd_pfn->id < 0) {
kfree(nd_dax);
return NULL;
}

dev = &nd_pfn->dev;
dev_set_name(dev, "dax%d.%d", nd_region->id, nd_pfn->id);
dev->groups = nd_dax_attribute_groups;
dev->type = &nd_dax_device_type;
dev->parent = &nd_region->dev;

return nd_dax;
}

struct device *nd_dax_create(struct nd_region *nd_region)
{
struct device *dev = NULL;
struct nd_dax *nd_dax;

if (!is_nd_pmem(&nd_region->dev))
return NULL;

nd_dax = nd_dax_alloc(nd_region);
if (nd_dax)
dev = nd_pfn_devinit(&nd_dax->nd_pfn, NULL);
__nd_device_register(dev);
return dev;
}
19 changes: 18 additions & 1 deletion drivers/nvdimm/namespace_devs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,8 @@ static ssize_t mode_show(struct device *dev,
mode = "safe";
else if (claim && is_nd_pfn(claim))
mode = "memory";
else if (claim && is_nd_dax(claim))
mode = "dax";
else if (!claim && pmem_should_map_pages(dev))
mode = "memory";
else
Expand Down Expand Up @@ -1379,14 +1381,17 @@ struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev)
{
struct nd_btt *nd_btt = is_nd_btt(dev) ? to_nd_btt(dev) : NULL;
struct nd_pfn *nd_pfn = is_nd_pfn(dev) ? to_nd_pfn(dev) : NULL;
struct nd_dax *nd_dax = is_nd_dax(dev) ? to_nd_dax(dev) : NULL;
struct nd_namespace_common *ndns = NULL;
resource_size_t size;

if (nd_btt || nd_pfn) {
if (nd_btt || nd_pfn || nd_dax) {
if (nd_btt)
ndns = nd_btt->ndns;
else if (nd_pfn)
ndns = nd_pfn->ndns;
else if (nd_dax)
ndns = nd_dax->nd_pfn.ndns;

if (!ndns)
return ERR_PTR(-ENODEV);
Expand Down Expand Up @@ -1779,6 +1784,18 @@ void nd_region_create_blk_seed(struct nd_region *nd_region)
nd_device_register(nd_region->ns_seed);
}

void nd_region_create_dax_seed(struct nd_region *nd_region)
{
WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev));
nd_region->dax_seed = nd_dax_create(nd_region);
/*
* Seed creation failures are not fatal, provisioning is simply
* disabled until memory becomes available
*/
if (!nd_region->dax_seed)
dev_err(&nd_region->dev, "failed to create dax namespace\n");
}

void nd_region_create_pfn_seed(struct nd_region *nd_region)
{
WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev));
Expand Down
1 change: 1 addition & 0 deletions drivers/nvdimm/nd-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ struct nd_region;
void nd_region_create_blk_seed(struct nd_region *nd_region);
void nd_region_create_btt_seed(struct nd_region *nd_region);
void nd_region_create_pfn_seed(struct nd_region *nd_region);
void nd_region_create_dax_seed(struct nd_region *nd_region);
void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev);
int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus);
void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus);
Expand Down
25 changes: 25 additions & 0 deletions drivers/nvdimm/nd.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,12 @@ struct nd_region {
struct ida ns_ida;
struct ida btt_ida;
struct ida pfn_ida;
struct ida dax_ida;
unsigned long flags;
struct device *ns_seed;
struct device *btt_seed;
struct device *pfn_seed;
struct device *dax_seed;
u16 ndr_mappings;
u64 ndr_size;
u64 ndr_start;
Expand Down Expand Up @@ -161,6 +163,10 @@ struct nd_pfn {
struct nd_namespace_common *ndns;
};

struct nd_dax {
struct nd_pfn nd_pfn;
};

enum nd_async_mode {
ND_SYNC,
ND_ASYNC,
Expand Down Expand Up @@ -224,7 +230,10 @@ struct nd_pfn *to_nd_pfn(struct device *dev);
int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns);
bool is_nd_pfn(struct device *dev);
struct device *nd_pfn_create(struct nd_region *nd_region);
struct device *nd_pfn_devinit(struct nd_pfn *nd_pfn,
struct nd_namespace_common *ndns);
int nd_pfn_validate(struct nd_pfn *nd_pfn);
extern struct attribute_group nd_pfn_attribute_group;
#else
static inline int nd_pfn_probe(struct device *dev,
struct nd_namespace_common *ndns)
Expand All @@ -248,6 +257,22 @@ static inline int nd_pfn_validate(struct nd_pfn *nd_pfn)
}
#endif

struct nd_dax *to_nd_dax(struct device *dev);
#if IS_ENABLED(CONFIG_NVDIMM_DAX)
bool is_nd_dax(struct device *dev);
struct device *nd_dax_create(struct nd_region *nd_region);
#else
static inline bool is_nd_dax(struct device *dev)
{
return false;
}

static inline struct device *nd_dax_create(struct nd_region *nd_region)
{
return NULL;
}
#endif

struct nd_region *to_nd_region(struct device *dev);
int nd_region_to_nstype(struct nd_region *nd_region);
int nd_region_register_namespaces(struct nd_region *nd_region, int *err);
Expand Down
Loading

0 comments on commit cd03412

Please sign in to comment.