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-03-21 01:44:32 -0400 |
| commit | ed01e50acdd3e4a640cf9ebd28a7e810c3ceca97 (patch) | |
| tree | 831c42c463fbf11a2e6da50ab68b5e8854de68c2 | |
| parent | 233ed09d7fdacf592ee91e6c97ce5f4364fbe7c0 (diff) | |
device-dax: fix cdev leak
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")
Cc: <stable@vger.kernel.org>
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>
| -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 8d9829ff2a78..a5ed59a5a968 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c | |||
| @@ -675,13 +675,10 @@ static void dax_dev_release(struct device *dev) | |||
| 675 | kfree(dax_dev); | 675 | kfree(dax_dev); |
| 676 | } | 676 | } |
| 677 | 677 | ||
| 678 | static void unregister_dax_dev(void *dev) | 678 | static void kill_dax_dev(struct dax_dev *dax_dev) |
| 679 | { | 679 | { |
| 680 | struct dax_dev *dax_dev = to_dax_dev(dev); | ||
| 681 | struct cdev *cdev = &dax_dev->cdev; | 680 | struct cdev *cdev = &dax_dev->cdev; |
| 682 | 681 | ||
| 683 | dev_dbg(dev, "%s\n", __func__); | ||
| 684 | |||
| 685 | /* | 682 | /* |
| 686 | * Note, rcu is not protecting the liveness of dax_dev, rcu is | 683 | * Note, rcu is not protecting the liveness of dax_dev, rcu is |
| 687 | * ensuring that any fault handlers that might have seen | 684 | * ensuring that any fault handlers that might have seen |
| @@ -693,6 +690,15 @@ static void unregister_dax_dev(void *dev) | |||
| 693 | synchronize_rcu(); | 690 | synchronize_rcu(); |
| 694 | unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1); | 691 | unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1); |
| 695 | cdev_del(cdev); | 692 | cdev_del(cdev); |
| 693 | } | ||
| 694 | |||
| 695 | static void unregister_dax_dev(void *dev) | ||
| 696 | { | ||
| 697 | struct dax_dev *dax_dev = to_dax_dev(dev); | ||
| 698 | |||
| 699 | dev_dbg(dev, "%s\n", __func__); | ||
| 700 | |||
| 701 | kill_dax_dev(dax_dev); | ||
| 696 | device_unregister(dev); | 702 | device_unregister(dev); |
| 697 | } | 703 | } |
| 698 | 704 | ||
| @@ -769,6 +775,7 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, | |||
| 769 | dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id); | 775 | dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id); |
| 770 | rc = device_add(dev); | 776 | rc = device_add(dev); |
| 771 | if (rc) { | 777 | if (rc) { |
| 778 | kill_dax_dev(dax_dev); | ||
| 772 | put_device(dev); | 779 | put_device(dev); |
| 773 | return ERR_PTR(rc); | 780 | return ERR_PTR(rc); |
| 774 | } | 781 | } |
