diff options
author | Dan Williams <dan.j.williams@intel.com> | 2017-03-17 14:48:09 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-05-20 08:28:41 -0400 |
commit | 8dd114ef78c855814558472ed13e99357e098e33 (patch) | |
tree | e756e2487da8dc19c0811fda9585e189d78c7a0c | |
parent | 6240377c574b06c5ef900cab3be2625e482ae8bf (diff) |
device-dax: fix cdev leak
commit ed01e50acdd3e4a640cf9ebd28a7e810c3ceca97 upstream.
If device_add() fails, cleanup the cdev. Otherwise, we leak a kobj_map()
with a stale device number.
As Jason points out, there is a small possibility that userspace has
opened and mapped the device in the time between cdev_add() and the
device_add() failure. We need a new kill_dax_dev() helper to invalidate
any established mappings.
Fixes: ba09c01d2fa8 ("dax: convert to the cdev api")
Reported-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/dax/dax.c | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 193224889e41..586f9543de73 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c | |||
@@ -553,13 +553,10 @@ static void dax_dev_release(struct device *dev) | |||
553 | kfree(dax_dev); | 553 | kfree(dax_dev); |
554 | } | 554 | } |
555 | 555 | ||
556 | static void unregister_dax_dev(void *dev) | 556 | static void kill_dax_dev(struct dax_dev *dax_dev) |
557 | { | 557 | { |
558 | struct dax_dev *dax_dev = to_dax_dev(dev); | ||
559 | struct cdev *cdev = &dax_dev->cdev; | 558 | struct cdev *cdev = &dax_dev->cdev; |
560 | 559 | ||
561 | dev_dbg(dev, "%s\n", __func__); | ||
562 | |||
563 | /* | 560 | /* |
564 | * Note, rcu is not protecting the liveness of dax_dev, rcu is | 561 | * Note, rcu is not protecting the liveness of dax_dev, rcu is |
565 | * ensuring that any fault handlers that might have seen | 562 | * ensuring that any fault handlers that might have seen |
@@ -571,6 +568,15 @@ static void unregister_dax_dev(void *dev) | |||
571 | synchronize_srcu(&dax_srcu); | 568 | synchronize_srcu(&dax_srcu); |
572 | unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1); | 569 | unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1); |
573 | cdev_del(cdev); | 570 | cdev_del(cdev); |
571 | } | ||
572 | |||
573 | static void unregister_dax_dev(void *dev) | ||
574 | { | ||
575 | struct dax_dev *dax_dev = to_dax_dev(dev); | ||
576 | |||
577 | dev_dbg(dev, "%s\n", __func__); | ||
578 | |||
579 | kill_dax_dev(dax_dev); | ||
574 | device_unregister(dev); | 580 | device_unregister(dev); |
575 | } | 581 | } |
576 | 582 | ||
@@ -647,6 +653,7 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, | |||
647 | dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id); | 653 | dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id); |
648 | rc = device_add(dev); | 654 | rc = device_add(dev); |
649 | if (rc) { | 655 | if (rc) { |
656 | kill_dax_dev(dax_dev); | ||
650 | put_device(dev); | 657 | put_device(dev); |
651 | return ERR_PTR(rc); | 658 | return ERR_PTR(rc); |
652 | } | 659 | } |