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

Commit c44ef859 authored by Dan Williams's avatar Dan Williams
Browse files

Merge branch 'for-4.10/libnvdimm' into libnvdimm-for-next

parents 325896ff d7fe1a67
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