Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 200c79da authored by Dan Williams's avatar Dan Williams
Browse files

libnvdimm, pmem, pfn: make pmem_rw_bytes generic and refactor pfn setup



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: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 947df02d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+1 −3
Original line number Diff line number Diff line
@@ -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;
@@ -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__,
+61 −0
Original line number Diff line number Diff line
@@ -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"
@@ -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);
+33 −7
Original line number Diff line number Diff line
@@ -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>
@@ -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;
}
@@ -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;
}
@@ -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)
@@ -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);
+1 −3
Original line number Diff line number Diff line
@@ -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;
@@ -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;
Loading