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

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

dax: convert to the cdev api



A goal of the device-DAX interface is to be able to support many
exclusive allocations (partitions) of performance / feature
differentiated memory.  This count may exceed the default minors limit
of 256.

As a result of switching to an embedded cdev the inode-to-dax_dev
conversion is simplified, as well as reference counting which can switch
to the cdev kobject lifetime.

Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent ebd84d72
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -23,4 +23,9 @@ config DEV_DAX_PMEM


	  Say Y if unsure
	  Say Y if unsure


config NR_DEV_DAX
	int "Maximum number of Device-DAX instances"
	default 32768
	range 256 2147483647

endif
endif
+41 −41
Original line number Original line Diff line number Diff line
@@ -14,15 +14,19 @@
#include <linux/module.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/device.h>
#include <linux/pfn_t.h>
#include <linux/pfn_t.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/dax.h>
#include <linux/dax.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include "dax.h"
#include "dax.h"


static int dax_major;
static dev_t dax_devt;
static struct class *dax_class;
static struct class *dax_class;
static DEFINE_IDA(dax_minor_ida);
static DEFINE_IDA(dax_minor_ida);
static int nr_dax = CONFIG_NR_DEV_DAX;
module_param(nr_dax, int, S_IRUGO);
MODULE_PARM_DESC(nr_dax, "max number of device-dax instances");


/**
/**
 * struct dax_region - mapping infrastructure for dax devices
 * struct dax_region - mapping infrastructure for dax devices
@@ -49,6 +53,7 @@ struct dax_region {
 * struct dax_dev - subdivision of a dax region
 * struct dax_dev - subdivision of a dax region
 * @region - parent region
 * @region - parent region
 * @dev - device backing the character device
 * @dev - device backing the character device
 * @cdev - core chardev data
 * @alive - !alive + rcu grace period == no new mappings can be established
 * @alive - !alive + rcu grace period == no new mappings can be established
 * @id - child id in the region
 * @id - child id in the region
 * @num_resources - number of physical address extents in this device
 * @num_resources - number of physical address extents in this device
@@ -57,6 +62,7 @@ struct dax_region {
struct dax_dev {
struct dax_dev {
	struct dax_region *region;
	struct dax_region *region;
	struct device dev;
	struct device dev;
	struct cdev cdev;
	bool alive;
	bool alive;
	int id;
	int id;
	int num_resources;
	int num_resources;
@@ -367,29 +373,12 @@ static unsigned long dax_get_unmapped_area(struct file *filp,
	return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags);
	return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags);
}
}


static int __match_devt(struct device *dev, const void *data)
{
	const dev_t *devt = data;

	return dev->devt == *devt;
}

static struct device *dax_dev_find(dev_t dev_t)
{
	return class_find_device(dax_class, NULL, &dev_t, __match_devt);
}

static int dax_open(struct inode *inode, struct file *filp)
static int dax_open(struct inode *inode, struct file *filp)
{
{
	struct dax_dev *dax_dev = NULL;
	struct dax_dev *dax_dev;
	struct device *dev;

	dev = dax_dev_find(inode->i_rdev);
	if (!dev)
		return -ENXIO;


	dax_dev = to_dax_dev(dev);
	dax_dev = container_of(inode->i_cdev, struct dax_dev, cdev);
	dev_dbg(dev, "%s\n", __func__);
	dev_dbg(&dax_dev->dev, "%s\n", __func__);
	filp->private_data = dax_dev;
	filp->private_data = dax_dev;
	inode->i_flags = S_DAX;
	inode->i_flags = S_DAX;


@@ -399,11 +388,8 @@ static int dax_open(struct inode *inode, struct file *filp)
static int dax_release(struct inode *inode, struct file *filp)
static int dax_release(struct inode *inode, struct file *filp)
{
{
	struct dax_dev *dax_dev = filp->private_data;
	struct dax_dev *dax_dev = filp->private_data;
	struct device *dev = &dax_dev->dev;

	dev_dbg(dev, "%s\n", __func__);
	put_device(dev);


	dev_dbg(&dax_dev->dev, "%s\n", __func__);
	return 0;
	return 0;
}
}


@@ -430,6 +416,7 @@ static void dax_dev_release(struct device *dev)
static void unregister_dax_dev(void *dev)
static void unregister_dax_dev(void *dev)
{
{
	struct dax_dev *dax_dev = to_dax_dev(dev);
	struct dax_dev *dax_dev = to_dax_dev(dev);
	struct cdev *cdev = &dax_dev->cdev;


	dev_dbg(dev, "%s\n", __func__);
	dev_dbg(dev, "%s\n", __func__);


@@ -442,6 +429,7 @@ static void unregister_dax_dev(void *dev)
	 */
	 */
	dax_dev->alive = false;
	dax_dev->alive = false;
	synchronize_rcu();
	synchronize_rcu();
	cdev_del(cdev);
	device_unregister(dev);
	device_unregister(dev);
}
}


@@ -451,17 +439,13 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res,
	struct device *parent = dax_region->dev;
	struct device *parent = dax_region->dev;
	struct dax_dev *dax_dev;
	struct dax_dev *dax_dev;
	struct device *dev;
	struct device *dev;
	struct cdev *cdev;
	int rc, minor;
	int rc, minor;
	dev_t dev_t;
	dev_t dev_t;


	dax_dev = kzalloc(sizeof(*dax_dev) + sizeof(*res) * count, GFP_KERNEL);
	dax_dev = kzalloc(sizeof(*dax_dev) + sizeof(*res) * count, GFP_KERNEL);
	if (!dax_dev)
	if (!dax_dev)
		return -ENOMEM;
		return -ENOMEM;
	memcpy(dax_dev->res, res, sizeof(*res) * count);
	dax_dev->num_resources = count;
	dax_dev->alive = true;
	dax_dev->region = dax_region;
	kref_get(&dax_region->kref);


	dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL);
	dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL);
	if (dax_dev->id < 0) {
	if (dax_dev->id < 0) {
@@ -475,10 +459,26 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res,
		goto err_minor;
		goto err_minor;
	}
	}


	dev_t = MKDEV(dax_major, minor);
	/* device_initialize() so cdev can reference kobj parent */

	dev_t = MKDEV(MAJOR(dax_devt), minor);
	dev = &dax_dev->dev;
	dev = &dax_dev->dev;
	device_initialize(dev);
	device_initialize(dev);

	cdev = &dax_dev->cdev;
	cdev_init(cdev, &dax_fops);
	cdev->owner = parent->driver->owner;
	cdev->kobj.parent = &dev->kobj;
	rc = cdev_add(&dax_dev->cdev, dev_t, 1);
	if (rc)
		goto err_cdev;

	/* from here on we're committed to teardown via dax_dev_release() */
	memcpy(dax_dev->res, res, sizeof(*res) * count);
	dax_dev->num_resources = count;
	dax_dev->alive = true;
	dax_dev->region = dax_region;
	kref_get(&dax_region->kref);

	dev->devt = dev_t;
	dev->devt = dev_t;
	dev->class = dax_class;
	dev->class = dax_class;
	dev->parent = parent;
	dev->parent = parent;
@@ -493,6 +493,8 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res,


	return devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev);
	return devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev);


 err_cdev:
	ida_simple_remove(&dax_minor_ida, minor);
 err_minor:
 err_minor:
	ida_simple_remove(&dax_region->ida, dax_dev->id);
	ida_simple_remove(&dax_region->ida, dax_dev->id);
 err_id:
 err_id:
@@ -506,24 +508,22 @@ static int __init dax_init(void)
{
{
	int rc;
	int rc;


	rc = register_chrdev(0, "dax", &dax_fops);
	nr_dax = max(nr_dax, 256);
	if (rc < 0)
	rc = alloc_chrdev_region(&dax_devt, 0, nr_dax, "dax");
	if (rc)
		return rc;
		return rc;
	dax_major = rc;


	dax_class = class_create(THIS_MODULE, "dax");
	dax_class = class_create(THIS_MODULE, "dax");
	if (IS_ERR(dax_class)) {
	if (IS_ERR(dax_class))
		unregister_chrdev(dax_major, "dax");
		unregister_chrdev_region(dax_devt, nr_dax);
		return PTR_ERR(dax_class);
	}


	return 0;
	return PTR_ERR_OR_ZERO(dax_class);
}
}


static void __exit dax_exit(void)
static void __exit dax_exit(void)
{
{
	class_destroy(dax_class);
	class_destroy(dax_class);
	unregister_chrdev(dax_major, "dax");
	unregister_chrdev_region(dax_devt, nr_dax);
	ida_destroy(&dax_minor_ida);
	ida_destroy(&dax_minor_ida);
}
}