The release-callback is not used before the device is attached to the device hierarchy. This caused resources not to cleanup properly if the device driver initialization failed before tpm_chip_register(). This patch fixes the issue by adding the cleanup function to the devres list of the platform device in tpmm_chip_alloc(). Fixes: 313d21eeab ("tpm: device class for tpm") Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@xxxxxxxxxxxxxxx> cc: stable@xxxxxxxxxxxxxxx --- drivers/char/tpm/tpm-chip.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 1a9dcee..cf2b351 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -75,16 +75,15 @@ static void tpm_dev_release(struct device *dev) } /** - * tpmm_chip_alloc() - allocate a new struct tpm_chip instance - * @dev: device to which the chip is associated + * tpmm_chip_alloc() - allocate and initialize a TPM chip + * @pdev: the platform device who is the parent of the chip * @ops: struct tpm_class_ops instance * - * Allocates a new struct tpm_chip instance and assigns a free - * device number for it. Caller does not have to worry about - * freeing the allocated resources. When the devices is removed - * devres calls tpmm_chip_remove() to do the job. + * Allocates a new struct tpm_chip instance, prepares the character device and + * assigns a free device number for it. The memory is freed automatically when + * the platform device is detached. */ -struct tpm_chip *tpmm_chip_alloc(struct device *dev, +struct tpm_chip *tpmm_chip_alloc(struct device *pdev, const struct tpm_class_ops *ops) { struct tpm_chip *chip; @@ -103,7 +102,7 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, spin_unlock(&driver_lock); if (chip->dev_num >= TPM_NUM_DEVICES) { - dev_err(dev, "No available tpm device numbers\n"); + dev_err(pdev, "No available tpm device numbers\n"); kfree(chip); return ERR_PTR(-ENOMEM); } @@ -112,9 +111,7 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num); - chip->pdev = dev; - - dev_set_drvdata(dev, chip); + chip->pdev = pdev; chip->dev.class = tpm_class; chip->dev.release = tpm_dev_release; @@ -136,6 +133,12 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, chip->cdev.owner = chip->pdev->driver->owner; chip->cdev.kobj.parent = &chip->dev.kobj; + /* Associate character device with the platform device only after + * it is properly initialized. + */ + dev_set_drvdata(pdev, chip); + devm_add_action(pdev, (void (*)(void *)) tpm_dev_release, &chip->dev); + return chip; } EXPORT_SYMBOL_GPL(tpmm_chip_alloc); @@ -162,7 +165,10 @@ static int tpm_add_char_device(struct tpm_chip *chip) MINOR(chip->dev.devt), rc); cdev_del(&chip->cdev); - return rc; + } else { + devm_remove_action(chip->dev.parent, + (void (*)(void *)) tpm_dev_release, + &chip->dev); } return rc; @@ -202,15 +208,14 @@ static void tpm1_chip_unregister(struct tpm_chip *chip) } /* - * tpm_chip_register() - create a character device for the TPM chip - * @chip: TPM chip to use. + * tpm_chip_register() - add a TPM chip to the device hierarchy + * @chip: the TPM chip to be added * - * Creates a character device for the TPM chip and adds sysfs attributes for - * the device. As the last step this function adds the chip to the list of TPM - * chips available for in-kernel use. + * Adds a TPM chip to the device hierarchy and makes it available to for + * in-kernel use. * - * This function should be only called after the chip initialization is - * complete. + * This function should be called only after the device driver is otherwise + * initialized because it will become available for client access. */ int tpm_chip_register(struct tpm_chip *chip) { -- 2.7.0 -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html