diff options
author | Dan Williams <dan.j.williams@intel.com> | 2017-03-17 12:48:09 -0600 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-03-21 06:44:32 +0100 |
commit | ed01e50acdd3e4a640cf9ebd28a7e810c3ceca97 (patch) | |
tree | 831c42c463fbf11a2e6da50ab68b5e8854de68c2 /drivers/dax | |
parent | 233ed09d7fdacf592ee91e6c97ce5f4364fbe7c0 (diff) | |
download | linux-ed01e50acdd3e4a640cf9ebd28a7e810c3ceca97.tar.gz linux-ed01e50acdd3e4a640cf9ebd28a7e810c3ceca97.tar.bz2 linux-ed01e50acdd3e4a640cf9ebd28a7e810c3ceca97.zip |
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>
Diffstat (limited to 'drivers/dax')
-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) kfree(dax_dev); } -static void unregister_dax_dev(void *dev) +static void kill_dax_dev(struct dax_dev *dax_dev) { - struct dax_dev *dax_dev = to_dax_dev(dev); struct cdev *cdev = &dax_dev->cdev; - dev_dbg(dev, "%s\n", __func__); - /* * Note, rcu is not protecting the liveness of dax_dev, rcu is * ensuring that any fault handlers that might have seen @@ -693,6 +690,15 @@ static void unregister_dax_dev(void *dev) synchronize_rcu(); unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1); cdev_del(cdev); +} + +static void unregister_dax_dev(void *dev) +{ + struct dax_dev *dax_dev = to_dax_dev(dev); + + dev_dbg(dev, "%s\n", __func__); + + kill_dax_dev(dax_dev); device_unregister(dev); } @@ -769,6 +775,7 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id); rc = device_add(dev); if (rc) { + kill_dax_dev(dax_dev); put_device(dev); return ERR_PTR(rc); } |