Skip to content

Commit

Permalink
libnvdimm, pmem, pfn: make pmem_rw_bytes generic and refactor pfn setup
Browse files Browse the repository at this point in the history
In preparation for providing an alternative (to block device) access
mechanism to persistent memory, convert pmem_rw_bytes() to
nsio_rw_bytes().  This allows ->rw_bytes() functionality without
requiring a 'struct pmem_device' to be instantiated.

In other words, when ->rw_bytes() is in use i/o is driven through
'struct nd_namespace_io', otherwise it is driven through 'struct
pmem_device' and the block layer.  This consolidates the disjoint calls
to devm_exit_badblocks() and devm_memunmap() into a common
devm_nsio_disable() and cleans up the init path to use a unified
pmem_attach_disk() implementation.

Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
  • Loading branch information
Dan Williams committed Apr 22, 2016
1 parent 947df02 commit 200c79d
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 173 deletions.
2 changes: 1 addition & 1 deletion drivers/nvdimm/blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ static int nd_blk_probe(struct device *dev)
ndns->rw_bytes = nsblk_rw_bytes;
if (is_nd_btt(dev))
return nvdimm_namespace_attach_btt(ndns);
else if (nd_btt_probe(dev, ndns, nsblk) == 0) {
else if (nd_btt_probe(dev, ndns) == 0) {
/* we'll come back as btt-blk */
return -ENXIO;
} else
Expand Down
4 changes: 1 addition & 3 deletions drivers/nvdimm/btt_devs.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,7 @@ static int __nd_btt_probe(struct nd_btt *nd_btt,
return 0;
}

int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns,
void *drvdata)
int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns)
{
int rc;
struct device *btt_dev;
Expand All @@ -289,7 +288,6 @@ int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns,
nvdimm_bus_unlock(&ndns->dev);
if (!btt_dev)
return -ENOMEM;
dev_set_drvdata(btt_dev, drvdata);
btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL);
rc = __nd_btt_probe(to_nd_btt(btt_dev), ndns, btt_sb);
dev_dbg(dev, "%s: btt: %s\n", __func__,
Expand Down
61 changes: 61 additions & 0 deletions drivers/nvdimm/claim.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
#include <linux/device.h>
#include <linux/sizes.h>
#include <linux/pmem.h>
#include "nd-core.h"
#include "pfn.h"
#include "btt.h"
Expand Down Expand Up @@ -199,3 +200,63 @@ u64 nd_sb_checksum(struct nd_gen_sb *nd_gen_sb)
return sum;
}
EXPORT_SYMBOL(nd_sb_checksum);

static int nsio_rw_bytes(struct nd_namespace_common *ndns,
resource_size_t offset, void *buf, size_t size, int rw)
{
struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);

if (unlikely(offset + size > nsio->size)) {
dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n");
return -EFAULT;
}

if (rw == READ) {
unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);

if (unlikely(is_bad_pmem(&nsio->bb, offset / 512, sz_align)))
return -EIO;
return memcpy_from_pmem(buf, nsio->addr + offset, size);
} else {
memcpy_to_pmem(nsio->addr + offset, buf, size);
wmb_pmem();
}

return 0;
}

int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
{
struct resource *res = &nsio->res;
struct nd_namespace_common *ndns = &nsio->common;

nsio->size = resource_size(res);
if (!devm_request_mem_region(dev, res->start, resource_size(res),
dev_name(dev))) {
dev_warn(dev, "could not reserve region %pR\n", res);
return -EBUSY;
}

ndns->rw_bytes = nsio_rw_bytes;
if (devm_init_badblocks(dev, &nsio->bb))
return -ENOMEM;
nvdimm_badblocks_populate(to_nd_region(ndns->dev.parent), &nsio->bb,
&nsio->res);

nsio->addr = devm_memremap(dev, res->start, resource_size(res),
ARCH_MEMREMAP_PMEM);
if (IS_ERR(nsio->addr))
return PTR_ERR(nsio->addr);
return 0;
}
EXPORT_SYMBOL_GPL(devm_nsio_enable);

void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio)
{
struct resource *res = &nsio->res;

devm_memunmap(dev, nsio->addr);
devm_exit_badblocks(dev, &nsio->bb);
devm_release_mem_region(dev, res->start, resource_size(res));
}
EXPORT_SYMBOL_GPL(devm_nsio_disable);
40 changes: 33 additions & 7 deletions drivers/nvdimm/nd.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef __ND_H__
#define __ND_H__
#include <linux/libnvdimm.h>
#include <linux/badblocks.h>
#include <linux/blkdev.h>
#include <linux/device.h>
#include <linux/mutex.h>
Expand Down Expand Up @@ -197,13 +198,12 @@ struct nd_gen_sb {

u64 nd_sb_checksum(struct nd_gen_sb *sb);
#if IS_ENABLED(CONFIG_BTT)
int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns,
void *drvdata);
int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns);
bool is_nd_btt(struct device *dev);
struct device *nd_btt_create(struct nd_region *nd_region);
#else
static inline int nd_btt_probe(struct device *dev,
struct nd_namespace_common *ndns, void *drvdata)
struct nd_namespace_common *ndns)
{
return -ENODEV;
}
Expand All @@ -221,14 +221,13 @@ static inline struct device *nd_btt_create(struct nd_region *nd_region)

struct nd_pfn *to_nd_pfn(struct device *dev);
#if IS_ENABLED(CONFIG_NVDIMM_PFN)
int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
void *drvdata);
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);
int nd_pfn_validate(struct nd_pfn *nd_pfn);
#else
static inline int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
void *drvdata)
static inline int nd_pfn_probe(struct device *dev,
struct nd_namespace_common *ndns)
{
return -ENODEV;
}
Expand Down Expand Up @@ -272,6 +271,20 @@ const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns,
char *name);
void nvdimm_badblocks_populate(struct nd_region *nd_region,
struct badblocks *bb, const struct resource *res);
#if IS_ENABLED(CONFIG_ND_CLAIM)
int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio);
void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio);
#else
static inline int devm_nsio_enable(struct device *dev,
struct nd_namespace_io *nsio)
{
return -ENXIO;
}
static inline void devm_nsio_disable(struct device *dev,
struct nd_namespace_io *nsio)
{
}
#endif
int nd_blk_region_init(struct nd_region *nd_region);
void __nd_iostat_start(struct bio *bio, unsigned long *start);
static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
Expand All @@ -285,6 +298,19 @@ static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
return true;
}
void nd_iostat_end(struct bio *bio, unsigned long start);
static inline bool is_bad_pmem(struct badblocks *bb, sector_t sector,
unsigned int len)
{
if (bb->count) {
sector_t first_bad;
int num_bad;

return !!badblocks_check(bb, sector, len / 512, &first_bad,
&num_bad);
}

return false;
}
resource_size_t nd_namespace_blk_validate(struct nd_namespace_blk *nsblk);
const u8 *nd_dev_to_uuid(struct device *dev);
bool pmem_should_map_pages(struct device *dev);
Expand Down
4 changes: 1 addition & 3 deletions drivers/nvdimm/pfn_devs.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,8 +410,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn)
}
EXPORT_SYMBOL(nd_pfn_validate);

int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
void *drvdata)
int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns)
{
int rc;
struct nd_pfn *nd_pfn;
Expand All @@ -427,7 +426,6 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns,
nvdimm_bus_unlock(&ndns->dev);
if (!pfn_dev)
return -ENOMEM;
dev_set_drvdata(pfn_dev, drvdata);
pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
nd_pfn = to_nd_pfn(pfn_dev);
nd_pfn->pfn_sb = pfn_sb;
Expand Down
Loading

0 comments on commit 200c79d

Please sign in to comment.