forked from mirrors/linux
		
	dax: add region 'id', 'size', and 'align' attributes
While this information is available by looking at the nvdimm parent device that may not always be the case when/if we add support for other memory regions. Tooling should not depend on walking a given ancestor topology that is not guaranteed by the device's class. For example, a device-dax instance will always have a dax_region parent, but it may not always have a libnvdimm "dax" device as a grandparent. Reported-by: Johannes Thumshirn <jthumshirn@suse.de> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
		
							parent
							
								
									868f036fee
								
							
						
					
					
						commit
						d7fe1a67f6
					
				
					 1 changed files with 94 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue