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

Commit 3be134e5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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 868f036f
  ("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
parents 8421c604 c44ef859
Loading
Loading
Loading
Loading
+94 −0
Original line number Diff line number Diff line
@@ -75,6 +75,73 @@ struct dax_dev {
	struct resource res[0];
};

static ssize_t id_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct dax_region *dax_region;
	ssize_t rc = -ENXIO;

	device_lock(dev);
	dax_region = dev_get_drvdata(dev);
	if (dax_region)
		rc = sprintf(buf, "%d\n", dax_region->id);
	device_unlock(dev);

	return rc;
}
static DEVICE_ATTR_RO(id);

static ssize_t region_size_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct dax_region *dax_region;
	ssize_t rc = -ENXIO;

	device_lock(dev);
	dax_region = dev_get_drvdata(dev);
	if (dax_region)
		rc = sprintf(buf, "%llu\n", (unsigned long long)
				resource_size(&dax_region->res));
	device_unlock(dev);

	return rc;
}
static struct device_attribute dev_attr_region_size = __ATTR(size, 0444,
		region_size_show, NULL);

static ssize_t align_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct dax_region *dax_region;
	ssize_t rc = -ENXIO;

	device_lock(dev);
	dax_region = dev_get_drvdata(dev);
	if (dax_region)
		rc = sprintf(buf, "%u\n", dax_region->align);
	device_unlock(dev);

	return rc;
}
static DEVICE_ATTR_RO(align);

static struct attribute *dax_region_attributes[] = {
	&dev_attr_region_size.attr,
	&dev_attr_align.attr,
	&dev_attr_id.attr,
	NULL,
};

static const struct attribute_group dax_region_attribute_group = {
	.name = "dax_region",
	.attrs = dax_region_attributes,
};

static const struct attribute_group *dax_region_attribute_groups[] = {
	&dax_region_attribute_group,
	NULL,
};

static struct inode *dax_alloc_inode(struct super_block *sb)
{
	return kmem_cache_alloc(dax_cache, GFP_KERNEL);
@@ -200,12 +267,31 @@ void dax_region_put(struct dax_region *dax_region)
}
EXPORT_SYMBOL_GPL(dax_region_put);

static void dax_region_unregister(void *region)
{
	struct dax_region *dax_region = region;

	sysfs_remove_groups(&dax_region->dev->kobj,
			dax_region_attribute_groups);
	dax_region_put(dax_region);
}

struct dax_region *alloc_dax_region(struct device *parent, int region_id,
		struct resource *res, unsigned int align, void *addr,
		unsigned long pfn_flags)
{
	struct dax_region *dax_region;

	/*
	 * The DAX core assumes that it can store its private data in
	 * parent->driver_data. This WARN is a reminder / safeguard for
	 * developers of device-dax drivers.
	 */
	if (dev_get_drvdata(parent)) {
		dev_WARN(parent, "dax core failed to setup private data\n");
		return NULL;
	}

	if (!IS_ALIGNED(res->start, align)
			|| !IS_ALIGNED(resource_size(res), align))
		return NULL;
@@ -214,6 +300,7 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
	if (!dax_region)
		return NULL;

	dev_set_drvdata(parent, dax_region);
	memcpy(&dax_region->res, res, sizeof(*res));
	dax_region->pfn_flags = pfn_flags;
	kref_init(&dax_region->kref);
@@ -222,7 +309,14 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
	dax_region->align = align;
	dax_region->dev = parent;
	dax_region->base = addr;
	if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) {
		kfree(dax_region);
		return NULL;;
	}

	kref_get(&dax_region->kref);
	if (devm_add_action_or_reset(parent, dax_region_unregister, dax_region))
		return NULL;
	return dax_region;
}
EXPORT_SYMBOL_GPL(alloc_dax_region);
+2 −1
Original line number Diff line number Diff line
@@ -89,7 +89,8 @@ static int dax_pmem_probe(struct device *dev)
	pfn_sb = nd_pfn->pfn_sb;

	if (!devm_request_mem_region(dev, nsio->res.start,
				resource_size(&nsio->res), dev_name(dev))) {
				resource_size(&nsio->res),
				dev_name(&ndns->dev))) {
		dev_warn(dev, "could not reserve region %pR\n", &nsio->res);
		return -EBUSY;
	}
+32 −14
Original line number Diff line number Diff line
@@ -22,9 +22,8 @@ void __nd_detach_ndns(struct device *dev, struct nd_namespace_common **_ndns)
{
	struct nd_namespace_common *ndns = *_ndns;

	dev_WARN_ONCE(dev, !mutex_is_locked(&ndns->dev.mutex)
			|| ndns->claim != dev,
			"%s: invalid claim\n", __func__);
	lockdep_assert_held(&ndns->dev.mutex);
	dev_WARN_ONCE(dev, ndns->claim != dev, "%s: invalid claim\n", __func__);
	ndns->claim = NULL;
	*_ndns = NULL;
	put_device(&ndns->dev);
@@ -49,9 +48,8 @@ bool __nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach,
{
	if (attach->claim)
		return false;
	dev_WARN_ONCE(dev, !mutex_is_locked(&attach->dev.mutex)
			|| *_ndns,
			"%s: invalid claim\n", __func__);
	lockdep_assert_held(&attach->dev.mutex);
	dev_WARN_ONCE(dev, *_ndns, "%s: invalid claim\n", __func__);
	attach->claim = dev;
	*_ndns = attach;
	get_device(&attach->dev);
@@ -226,6 +224,12 @@ 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);
	unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
	sector_t sector = offset >> 9;
	int rc = 0;

	if (unlikely(!size))
		return 0;

	if (unlikely(offset + size > nsio->size)) {
		dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n");
@@ -233,17 +237,31 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
	}

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

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

	if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) {
		if (IS_ALIGNED(offset, 512) && IS_ALIGNED(size, 512)) {
			long cleared;

			cleared = nvdimm_clear_poison(&ndns->dev, offset, size);
			if (cleared < size)
				rc = -EIO;
			if (cleared > 0 && cleared / 512) {
				cleared /= 512;
				badblocks_clear(&nsio->bb, sector, cleared);
			}
			invalidate_pmem(nsio->addr + offset, size);
		} else
			rc = -EIO;
	}

	memcpy_to_pmem(nsio->addr + offset, buf, size);
	nvdimm_flush(to_nd_region(ndns->dev.parent));
	}

	return 0;
	return rc;
}

int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
@@ -253,7 +271,7 @@ int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)

	nsio->size = resource_size(res);
	if (!devm_request_mem_region(dev, res->start, resource_size(res),
				dev_name(dev))) {
				dev_name(&ndns->dev))) {
		dev_warn(dev, "could not reserve region %pR\n", res);
		return -EBUSY;
	}
+0 −29
Original line number Diff line number Diff line
@@ -317,35 +317,6 @@ ssize_t nd_sector_size_store(struct device *dev, const char *buf,
	}
}

void __nd_iostat_start(struct bio *bio, unsigned long *start)
{
	struct gendisk *disk = bio->bi_bdev->bd_disk;
	const int rw = bio_data_dir(bio);
	int cpu = part_stat_lock();

	*start = jiffies;
	part_round_stats(cpu, &disk->part0);
	part_stat_inc(cpu, &disk->part0, ios[rw]);
	part_stat_add(cpu, &disk->part0, sectors[rw], bio_sectors(bio));
	part_inc_in_flight(&disk->part0, rw);
	part_stat_unlock();
}
EXPORT_SYMBOL(__nd_iostat_start);

void nd_iostat_end(struct bio *bio, unsigned long start)
{
	struct gendisk *disk = bio->bi_bdev->bd_disk;
	unsigned long duration = jiffies - start;
	const int rw = bio_data_dir(bio);
	int cpu = part_stat_lock();

	part_stat_add(cpu, &disk->part0, ticks[rw], duration);
	part_round_stats(cpu, &disk->part0);
	part_dec_in_flight(&disk->part0, rw);
	part_stat_unlock();
}
EXPORT_SYMBOL(nd_iostat_end);

static ssize_t commands_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
+2 −0
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ static int nvdimm_probe(struct device *dev)
	nd_label_copy(ndd, to_next_namespace_index(ndd),
			to_current_namespace_index(ndd));
	rc = nd_label_reserve_dpa(ndd);
	if (ndd->ns_current >= 0)
		nvdimm_set_aliasing(dev);
	nvdimm_bus_unlock(dev);

	if (rc)
Loading