diff options
| author | Dan Williams <dan.j.williams@intel.com> | 2016-07-24 18:55:42 -0400 |
|---|---|---|
| committer | Dan Williams <dan.j.williams@intel.com> | 2016-08-24 01:58:51 -0400 |
| commit | ba09c01d2fa866f22e42ac2af405fe386f491879 (patch) | |
| tree | c0028867440d5d50709bf787221bb4c64f29586b /drivers/dax | |
| parent | ebd84d724c85f22037a5c9cb04b9e6631309cb78 (diff) | |
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: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dax')
| -rw-r--r-- | drivers/dax/Kconfig | 5 | ||||
| -rw-r--r-- | drivers/dax/dax.c | 82 |
2 files changed, 46 insertions, 41 deletions
diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig index cedab7572de3..daadd20aa936 100644 --- a/drivers/dax/Kconfig +++ b/drivers/dax/Kconfig | |||
| @@ -23,4 +23,9 @@ config DEV_DAX_PMEM | |||
| 23 | 23 | ||
| 24 | Say Y if unsure | 24 | Say Y if unsure |
| 25 | 25 | ||
| 26 | config NR_DEV_DAX | ||
| 27 | int "Maximum number of Device-DAX instances" | ||
| 28 | default 32768 | ||
| 29 | range 256 2147483647 | ||
| 30 | |||
| 26 | endif | 31 | endif |
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 181d2a5a21e4..17715773c097 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c | |||
| @@ -14,15 +14,19 @@ | |||
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/device.h> | 15 | #include <linux/device.h> |
| 16 | #include <linux/pfn_t.h> | 16 | #include <linux/pfn_t.h> |
| 17 | #include <linux/cdev.h> | ||
| 17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 18 | #include <linux/dax.h> | 19 | #include <linux/dax.h> |
| 19 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
| 20 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
| 21 | #include "dax.h" | 22 | #include "dax.h" |
| 22 | 23 | ||
| 23 | static int dax_major; | 24 | static dev_t dax_devt; |
| 24 | static struct class *dax_class; | 25 | static struct class *dax_class; |
| 25 | static DEFINE_IDA(dax_minor_ida); | 26 | static DEFINE_IDA(dax_minor_ida); |
| 27 | static int nr_dax = CONFIG_NR_DEV_DAX; | ||
| 28 | module_param(nr_dax, int, S_IRUGO); | ||
| 29 | MODULE_PARM_DESC(nr_dax, "max number of device-dax instances"); | ||
| 26 | 30 | ||
| 27 | /** | 31 | /** |
| 28 | * struct dax_region - mapping infrastructure for dax devices | 32 | * struct dax_region - mapping infrastructure for dax devices |
| @@ -49,6 +53,7 @@ struct dax_region { | |||
| 49 | * struct dax_dev - subdivision of a dax region | 53 | * struct dax_dev - subdivision of a dax region |
| 50 | * @region - parent region | 54 | * @region - parent region |
| 51 | * @dev - device backing the character device | 55 | * @dev - device backing the character device |
| 56 | * @cdev - core chardev data | ||
| 52 | * @alive - !alive + rcu grace period == no new mappings can be established | 57 | * @alive - !alive + rcu grace period == no new mappings can be established |
| 53 | * @id - child id in the region | 58 | * @id - child id in the region |
| 54 | * @num_resources - number of physical address extents in this device | 59 | * @num_resources - number of physical address extents in this device |
| @@ -57,6 +62,7 @@ struct dax_region { | |||
| 57 | struct dax_dev { | 62 | struct dax_dev { |
| 58 | struct dax_region *region; | 63 | struct dax_region *region; |
| 59 | struct device dev; | 64 | struct device dev; |
| 65 | struct cdev cdev; | ||
| 60 | bool alive; | 66 | bool alive; |
| 61 | int id; | 67 | int id; |
| 62 | int num_resources; | 68 | int num_resources; |
| @@ -367,29 +373,12 @@ static unsigned long dax_get_unmapped_area(struct file *filp, | |||
| 367 | return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags); | 373 | return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags); |
| 368 | } | 374 | } |
| 369 | 375 | ||
| 370 | static int __match_devt(struct device *dev, const void *data) | ||
| 371 | { | ||
| 372 | const dev_t *devt = data; | ||
| 373 | |||
| 374 | return dev->devt == *devt; | ||
| 375 | } | ||
| 376 | |||
| 377 | static struct device *dax_dev_find(dev_t dev_t) | ||
| 378 | { | ||
| 379 | return class_find_device(dax_class, NULL, &dev_t, __match_devt); | ||
| 380 | } | ||
| 381 | |||
| 382 | static int dax_open(struct inode *inode, struct file *filp) | 376 | static int dax_open(struct inode *inode, struct file *filp) |
| 383 | { | 377 | { |
| 384 | struct dax_dev *dax_dev = NULL; | 378 | struct dax_dev *dax_dev; |
| 385 | struct device *dev; | ||
| 386 | |||
| 387 | dev = dax_dev_find(inode->i_rdev); | ||
| 388 | if (!dev) | ||
| 389 | return -ENXIO; | ||
| 390 | 379 | ||
| 391 | dax_dev = to_dax_dev(dev); | 380 | dax_dev = container_of(inode->i_cdev, struct dax_dev, cdev); |
| 392 | dev_dbg(dev, "%s\n", __func__); | 381 | dev_dbg(&dax_dev->dev, "%s\n", __func__); |
| 393 | filp->private_data = dax_dev; | 382 | filp->private_data = dax_dev; |
| 394 | inode->i_flags = S_DAX; | 383 | inode->i_flags = S_DAX; |
| 395 | 384 | ||
| @@ -399,11 +388,8 @@ static int dax_open(struct inode *inode, struct file *filp) | |||
| 399 | static int dax_release(struct inode *inode, struct file *filp) | 388 | static int dax_release(struct inode *inode, struct file *filp) |
| 400 | { | 389 | { |
| 401 | struct dax_dev *dax_dev = filp->private_data; | 390 | struct dax_dev *dax_dev = filp->private_data; |
| 402 | struct device *dev = &dax_dev->dev; | ||
| 403 | |||
| 404 | dev_dbg(dev, "%s\n", __func__); | ||
| 405 | put_device(dev); | ||
| 406 | 391 | ||
| 392 | dev_dbg(&dax_dev->dev, "%s\n", __func__); | ||
| 407 | return 0; | 393 | return 0; |
| 408 | } | 394 | } |
| 409 | 395 | ||
| @@ -430,6 +416,7 @@ static void dax_dev_release(struct device *dev) | |||
| 430 | static void unregister_dax_dev(void *dev) | 416 | static void unregister_dax_dev(void *dev) |
| 431 | { | 417 | { |
| 432 | struct dax_dev *dax_dev = to_dax_dev(dev); | 418 | struct dax_dev *dax_dev = to_dax_dev(dev); |
| 419 | struct cdev *cdev = &dax_dev->cdev; | ||
| 433 | 420 | ||
| 434 | dev_dbg(dev, "%s\n", __func__); | 421 | dev_dbg(dev, "%s\n", __func__); |
| 435 | 422 | ||
| @@ -442,6 +429,7 @@ static void unregister_dax_dev(void *dev) | |||
| 442 | */ | 429 | */ |
| 443 | dax_dev->alive = false; | 430 | dax_dev->alive = false; |
| 444 | synchronize_rcu(); | 431 | synchronize_rcu(); |
| 432 | cdev_del(cdev); | ||
| 445 | device_unregister(dev); | 433 | device_unregister(dev); |
| 446 | } | 434 | } |
| 447 | 435 | ||
| @@ -451,17 +439,13 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, | |||
| 451 | struct device *parent = dax_region->dev; | 439 | struct device *parent = dax_region->dev; |
| 452 | struct dax_dev *dax_dev; | 440 | struct dax_dev *dax_dev; |
| 453 | struct device *dev; | 441 | struct device *dev; |
| 442 | struct cdev *cdev; | ||
| 454 | int rc, minor; | 443 | int rc, minor; |
| 455 | dev_t dev_t; | 444 | dev_t dev_t; |
| 456 | 445 | ||
| 457 | dax_dev = kzalloc(sizeof(*dax_dev) + sizeof(*res) * count, GFP_KERNEL); | 446 | dax_dev = kzalloc(sizeof(*dax_dev) + sizeof(*res) * count, GFP_KERNEL); |
| 458 | if (!dax_dev) | 447 | if (!dax_dev) |
| 459 | return -ENOMEM; | 448 | return -ENOMEM; |
| 460 | memcpy(dax_dev->res, res, sizeof(*res) * count); | ||
| 461 | dax_dev->num_resources = count; | ||
| 462 | dax_dev->alive = true; | ||
| 463 | dax_dev->region = dax_region; | ||
| 464 | kref_get(&dax_region->kref); | ||
| 465 | 449 | ||
| 466 | dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL); | 450 | dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL); |
| 467 | if (dax_dev->id < 0) { | 451 | if (dax_dev->id < 0) { |
| @@ -475,10 +459,26 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, | |||
| 475 | goto err_minor; | 459 | goto err_minor; |
| 476 | } | 460 | } |
| 477 | 461 | ||
| 478 | dev_t = MKDEV(dax_major, minor); | 462 | /* device_initialize() so cdev can reference kobj parent */ |
| 479 | 463 | dev_t = MKDEV(MAJOR(dax_devt), minor); | |
| 480 | dev = &dax_dev->dev; | 464 | dev = &dax_dev->dev; |
| 481 | device_initialize(dev); | 465 | device_initialize(dev); |
| 466 | |||
| 467 | cdev = &dax_dev->cdev; | ||
| 468 | cdev_init(cdev, &dax_fops); | ||
| 469 | cdev->owner = parent->driver->owner; | ||
| 470 | cdev->kobj.parent = &dev->kobj; | ||
| 471 | rc = cdev_add(&dax_dev->cdev, dev_t, 1); | ||
| 472 | if (rc) | ||
| 473 | goto err_cdev; | ||
| 474 | |||
| 475 | /* from here on we're committed to teardown via dax_dev_release() */ | ||
| 476 | memcpy(dax_dev->res, res, sizeof(*res) * count); | ||
| 477 | dax_dev->num_resources = count; | ||
| 478 | dax_dev->alive = true; | ||
| 479 | dax_dev->region = dax_region; | ||
| 480 | kref_get(&dax_region->kref); | ||
| 481 | |||
| 482 | dev->devt = dev_t; | 482 | dev->devt = dev_t; |
| 483 | dev->class = dax_class; | 483 | dev->class = dax_class; |
| 484 | dev->parent = parent; | 484 | dev->parent = parent; |
| @@ -493,6 +493,8 @@ int devm_create_dax_dev(struct dax_region *dax_region, struct resource *res, | |||
| 493 | 493 | ||
| 494 | return devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); | 494 | return devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); |
| 495 | 495 | ||
| 496 | err_cdev: | ||
| 497 | ida_simple_remove(&dax_minor_ida, minor); | ||
| 496 | err_minor: | 498 | err_minor: |
| 497 | ida_simple_remove(&dax_region->ida, dax_dev->id); | 499 | ida_simple_remove(&dax_region->ida, dax_dev->id); |
| 498 | err_id: | 500 | err_id: |
| @@ -506,24 +508,22 @@ static int __init dax_init(void) | |||
| 506 | { | 508 | { |
| 507 | int rc; | 509 | int rc; |
| 508 | 510 | ||
| 509 | rc = register_chrdev(0, "dax", &dax_fops); | 511 | nr_dax = max(nr_dax, 256); |
| 510 | if (rc < 0) | 512 | rc = alloc_chrdev_region(&dax_devt, 0, nr_dax, "dax"); |
| 513 | if (rc) | ||
| 511 | return rc; | 514 | return rc; |
| 512 | dax_major = rc; | ||
| 513 | 515 | ||
| 514 | dax_class = class_create(THIS_MODULE, "dax"); | 516 | dax_class = class_create(THIS_MODULE, "dax"); |
| 515 | if (IS_ERR(dax_class)) { | 517 | if (IS_ERR(dax_class)) |
| 516 | unregister_chrdev(dax_major, "dax"); | 518 | unregister_chrdev_region(dax_devt, nr_dax); |
| 517 | return PTR_ERR(dax_class); | ||
| 518 | } | ||
| 519 | 519 | ||
| 520 | return 0; | 520 | return PTR_ERR_OR_ZERO(dax_class); |
| 521 | } | 521 | } |
| 522 | 522 | ||
| 523 | static void __exit dax_exit(void) | 523 | static void __exit dax_exit(void) |
| 524 | { | 524 | { |
| 525 | class_destroy(dax_class); | 525 | class_destroy(dax_class); |
| 526 | unregister_chrdev(dax_major, "dax"); | 526 | unregister_chrdev_region(dax_devt, nr_dax); |
| 527 | ida_destroy(&dax_minor_ida); | 527 | ida_destroy(&dax_minor_ida); |
| 528 | } | 528 | } |
| 529 | 529 | ||
