summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/vmt.c
diff options
context:
space:
mode:
authorLogan Gunthorpe <logang@deltatee.com>2017-03-17 19:48:19 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-03-21 06:44:33 +0100
commit493cfaeaa0c9bc0c79ce5751193d49fdac9aaaec (patch)
tree8ccf761b9668a2c00913a4400e85984006a98f9b /drivers/mtd/ubi/vmt.c
parentmedia: utilize new cdev_device_add helper function (diff)
downloadlinux-493cfaeaa0c9bc0c79ce5751193d49fdac9aaaec.tar.xz
linux-493cfaeaa0c9bc0c79ce5751193d49fdac9aaaec.zip
mtd: utilize new cdev_device_add helper function
This is not as straightforward a conversion as the others in this series. These drivers did not originally make use of kobj.parent so they likely suffered from a use after free bug if someone unregistered the devices while they are being used. In order to make the conversions, switch from device_register to device_initialize / cdev_device_add. In build.c, this patch unwinds a complicated mess of extra get_device/put_devices and reference tracking by moving device_initialize early in the attach process. Then it always uses put_device and instead of using device_unregister and extra get_devices everywhere we just use cdev_device_del and one put_device once everything is completely done. This simplifies things dramatically and makes it easier to reason about. In vmt.c, the patch pushes device initialization up to the beginning of the device creation and then that function only needs to use put_device in the error path which simplifies things a good deal. Signed-off-by: Logan Gunthorpe <logang@deltatee.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/mtd/ubi/vmt.c')
-rw-r--r--drivers/mtd/ubi/vmt.c49
1 files changed, 16 insertions, 33 deletions
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 7ac78c13dd1c..85237cf661f9 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -155,11 +155,10 @@ static void vol_release(struct device *dev)
*/
int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
{
- int i, err, vol_id = req->vol_id, do_free = 1;
+ int i, err, vol_id = req->vol_id;
struct ubi_volume *vol;
struct ubi_vtbl_record vtbl_rec;
struct ubi_eba_table *eba_tbl = NULL;
- dev_t dev;
if (ubi->ro_mode)
return -EROFS;
@@ -168,6 +167,12 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
if (!vol)
return -ENOMEM;
+ device_initialize(&vol->dev);
+ vol->dev.release = vol_release;
+ vol->dev.parent = &ubi->dev;
+ vol->dev.class = &ubi_class;
+ vol->dev.groups = volume_dev_groups;
+
spin_lock(&ubi->volumes_lock);
if (vol_id == UBI_VOL_NUM_AUTO) {
/* Find unused volume ID */
@@ -268,24 +273,13 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Register character device for the volume */
cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
vol->cdev.owner = THIS_MODULE;
- dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1);
- err = cdev_add(&vol->cdev, dev, 1);
- if (err) {
- ubi_err(ubi, "cannot add character device");
- goto out_mapping;
- }
-
- vol->dev.release = vol_release;
- vol->dev.parent = &ubi->dev;
- vol->dev.devt = dev;
- vol->dev.class = &ubi_class;
- vol->dev.groups = volume_dev_groups;
+ vol->dev.devt = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1);
dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
- err = device_register(&vol->dev);
+ err = cdev_device_add(&vol->cdev, &vol->dev);
if (err) {
- ubi_err(ubi, "cannot register device");
- goto out_cdev;
+ ubi_err(ubi, "cannot add device");
+ goto out_mapping;
}
/* Fill volume table record */
@@ -318,28 +312,17 @@ out_sysfs:
* We have registered our device, we should not free the volume
* description object in this function in case of an error - it is
* freed by the release function.
- *
- * Get device reference to prevent the release function from being
- * called just after sysfs has been closed.
*/
- do_free = 0;
- get_device(&vol->dev);
- device_unregister(&vol->dev);
-out_cdev:
- cdev_del(&vol->cdev);
+ cdev_device_del(&vol->cdev, &vol->dev);
out_mapping:
- if (do_free)
- ubi_eba_destroy_table(eba_tbl);
+ ubi_eba_destroy_table(eba_tbl);
out_acc:
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs;
out_unlock:
spin_unlock(&ubi->volumes_lock);
- if (do_free)
- kfree(vol);
- else
- put_device(&vol->dev);
+ put_device(&vol->dev);
ubi_err(ubi, "cannot create volume %d, error %d", vol_id, err);
return err;
}
@@ -391,8 +374,8 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
goto out_err;
}
- cdev_del(&vol->cdev);
- device_unregister(&vol->dev);
+ cdev_device_del(&vol->cdev, &vol->dev);
+ put_device(&vol->dev);
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= reserved_pebs;