From f89c5edb86abfac4c914f4eb808b07684164eca0 Mon Sep 17 00:00:00 2001 From: Rajiv Andrade Date: Sat, 11 Oct 2008 09:03:39 +1100 Subject: Remove the BKL calls from the TPM driver, which were added in the overall misc-char-dev-BKL-pushdown.patch, as they are not needed. Signed-off-by: Mimi Zohar Signed-off-by: Rajiv Andrade Cc: "Serge E. Hallyn" Signed-off-by: Andrew Morton Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index ae766d86845..ceba6082bd9 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -954,13 +954,16 @@ EXPORT_SYMBOL_GPL(tpm_store_cancel); /* * Device file system interface to the TPM + * + * It's assured that the chip will be opened just once, + * by the check of is_open variable, which is protected + * by driver_lock. */ int tpm_open(struct inode *inode, struct file *file) { int rc = 0, minor = iminor(inode); struct tpm_chip *chip = NULL, *pos; - lock_kernel(); spin_lock(&driver_lock); list_for_each_entry(pos, &tpm_chip_list, list) { @@ -990,19 +993,16 @@ int tpm_open(struct inode *inode, struct file *file) if (chip->data_buffer == NULL) { chip->num_opens--; put_device(chip->dev); - unlock_kernel(); return -ENOMEM; } atomic_set(&chip->data_pending, 0); file->private_data = chip; - unlock_kernel(); return 0; err_out: spin_unlock(&driver_lock); - unlock_kernel(); return rc; } EXPORT_SYMBOL_GPL(tpm_open); -- cgit v1.2.3 From dc36d32cc5bea5e985294c79995e10a159c3019a Mon Sep 17 00:00:00 2001 From: Rajiv Andrade Date: Sat, 11 Oct 2008 09:04:02 +1100 Subject: Renames num_open to is_open, as only one process can open the file at a time. Signed-off-by: Mimi Zohar Signed-off-by: Rajiv Andrade Cc: "Serge E. Hallyn" Signed-off-by: Andrew Morton Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 7 +++---- drivers/char/tpm/tpm.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index ceba6082bd9..dfd4e7fc350 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -978,20 +978,19 @@ int tpm_open(struct inode *inode, struct file *file) goto err_out; } - if (chip->num_opens) { + if (test_and_set_bit(0, &chip->is_open)) { dev_dbg(chip->dev, "Another process owns this TPM\n"); rc = -EBUSY; goto err_out; } - chip->num_opens++; get_device(chip->dev); spin_unlock(&driver_lock); chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); if (chip->data_buffer == NULL) { - chip->num_opens--; + clear_bit(0, &chip->is_open); put_device(chip->dev); return -ENOMEM; } @@ -1016,7 +1015,7 @@ int tpm_release(struct inode *inode, struct file *file) file->private_data = NULL; del_singleshot_timer_sync(&chip->user_read_timer); atomic_set(&chip->data_pending, 0); - chip->num_opens--; + clear_bit(0, &chip->is_open); put_device(chip->dev); kfree(chip->data_buffer); spin_unlock(&driver_lock); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index e885148b4cf..2756cab9aee 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -90,7 +90,7 @@ struct tpm_chip { struct device *dev; /* Device stuff */ int dev_num; /* /dev/tpm# */ - int num_opens; /* only one allowed */ + unsigned long is_open; /* only one allowed */ int time_expired; /* Data passed to and from the tpm via the read/write calls */ -- cgit v1.2.3 From f02a93645e6200a9da0f26dac8ced28c612f5e86 Mon Sep 17 00:00:00 2001 From: Rajiv Andrade Date: Sat, 11 Oct 2008 09:04:23 +1100 Subject: Protect tpm_chip_list when transversing it. Signed-off-by: Mimi Zohar Signed-off-by: Rajiv Andrade Acked-by: Serge E. Hallyn Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 61 ++++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 37 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index dfd4e7fc350..4f18f84b498 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -961,33 +961,28 @@ EXPORT_SYMBOL_GPL(tpm_store_cancel); */ int tpm_open(struct inode *inode, struct file *file) { - int rc = 0, minor = iminor(inode); + int minor = iminor(inode); struct tpm_chip *chip = NULL, *pos; - spin_lock(&driver_lock); - - list_for_each_entry(pos, &tpm_chip_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(pos, &tpm_chip_list, list) { if (pos->vendor.miscdev.minor == minor) { chip = pos; + get_device(chip->dev); break; } } + rcu_read_unlock(); - if (chip == NULL) { - rc = -ENODEV; - goto err_out; - } + if (!chip) + return -ENODEV; if (test_and_set_bit(0, &chip->is_open)) { dev_dbg(chip->dev, "Another process owns this TPM\n"); - rc = -EBUSY; - goto err_out; + put_device(chip->dev); + return -EBUSY; } - get_device(chip->dev); - - spin_unlock(&driver_lock); - chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); if (chip->data_buffer == NULL) { clear_bit(0, &chip->is_open); @@ -999,26 +994,23 @@ int tpm_open(struct inode *inode, struct file *file) file->private_data = chip; return 0; - -err_out: - spin_unlock(&driver_lock); - return rc; } EXPORT_SYMBOL_GPL(tpm_open); +/* + * Called on file close + */ int tpm_release(struct inode *inode, struct file *file) { struct tpm_chip *chip = file->private_data; flush_scheduled_work(); - spin_lock(&driver_lock); file->private_data = NULL; del_singleshot_timer_sync(&chip->user_read_timer); atomic_set(&chip->data_pending, 0); + kfree(chip->data_buffer); clear_bit(0, &chip->is_open); put_device(chip->dev); - kfree(chip->data_buffer); - spin_unlock(&driver_lock); return 0; } EXPORT_SYMBOL_GPL(tpm_release); @@ -1092,13 +1084,11 @@ void tpm_remove_hardware(struct device *dev) } spin_lock(&driver_lock); - - list_del(&chip->list); - + list_del_rcu(&chip->list); spin_unlock(&driver_lock); + synchronize_rcu(); misc_deregister(&chip->vendor.miscdev); - sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); tpm_bios_log_teardown(chip->bios_dir); @@ -1146,8 +1136,7 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume); /* * Once all references to platform device are down to 0, * release all allocated structures. - * In case vendor provided release function, - * call it too. + * In case vendor provided release function, call it too. */ static void tpm_dev_release(struct device *dev) { @@ -1155,7 +1144,6 @@ static void tpm_dev_release(struct device *dev) if (chip->vendor.release) chip->vendor.release(dev); - chip->release(dev); clear_bit(chip->dev_num, dev_mask); @@ -1170,8 +1158,8 @@ static void tpm_dev_release(struct device *dev) * upon errant exit from this function specific probe function should call * pci_disable_device */ -struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific - *entry) +struct tpm_chip *tpm_register_hardware(struct device *dev, + const struct tpm_vendor_specific *entry) { #define DEVNAME_SIZE 7 @@ -1230,21 +1218,20 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend return NULL; } - spin_lock(&driver_lock); - - list_add(&chip->list, &tpm_chip_list); - - spin_unlock(&driver_lock); - if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { - list_del(&chip->list); misc_deregister(&chip->vendor.miscdev); put_device(chip->dev); + return NULL; } chip->bios_dir = tpm_bios_log_setup(devname); + /* Make chip available */ + spin_lock(&driver_lock); + list_add_rcu(&chip->list, &tpm_chip_list); + spin_unlock(&driver_lock); + return chip; } EXPORT_SYMBOL_GPL(tpm_register_hardware); -- cgit v1.2.3 From 253115b71fa06330bd58afbe01ccaf763a8a0cf1 Mon Sep 17 00:00:00 2001 From: Rajiv Andrade Date: Sat, 11 Oct 2008 09:04:39 +1100 Subject: The tpm_dev_release function is only called for platform devices, not pnp devices, so we implemented the .remove function for pnp ones. Since it's code is very similar to the one inside tpm_dev_release, we've created a helper function tpm_dev_vendor_release, which is called by both. Signed-off-by: Mimi Zohar Signed-off-by: Rajiv Andrade Cc: "Serge E. Hallyn" Cc: Bjorn Helgaas Signed-off-by: Andrew Morton Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 22 ++++++++++++++++------ drivers/char/tpm/tpm.h | 1 + drivers/char/tpm/tpm_tis.c | 14 +++++++++++++- 3 files changed, 30 insertions(+), 7 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 4f18f84b498..02a495c2e06 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1133,23 +1133,33 @@ int tpm_pm_resume(struct device *dev) } EXPORT_SYMBOL_GPL(tpm_pm_resume); +/* In case vendor provided release function, call it too.*/ + +void tpm_dev_vendor_release(struct tpm_chip *chip) +{ + if (chip->vendor.release) + chip->vendor.release(chip->dev); + + clear_bit(chip->dev_num, dev_mask); + kfree(chip->vendor.miscdev.name); +} +EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); + + /* * Once all references to platform device are down to 0, * release all allocated structures. - * In case vendor provided release function, call it too. */ static void tpm_dev_release(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip->vendor.release) - chip->vendor.release(dev); - chip->release(dev); + tpm_dev_vendor_release(chip); - clear_bit(chip->dev_num, dev_mask); - kfree(chip->vendor.miscdev.name); + chip->release(dev); kfree(chip); } +EXPORT_SYMBOL_GPL(tpm_dev_release); /* * Called from tpm_.c probe function only for devices diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 2756cab9aee..8e30df4a438 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -132,6 +132,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *, const struct tpm_vendor_specific *); extern int tpm_open(struct inode *, struct file *); extern int tpm_release(struct inode *, struct file *); +extern void tpm_dev_vendor_release(struct tpm_chip *); extern ssize_t tpm_write(struct file *, const char __user *, size_t, loff_t *); extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index ed1879c0dd8..717af7ad1bd 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -630,12 +630,23 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { {"", 0} /* Terminator */ }; +static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev) +{ + struct tpm_chip *chip = pnp_get_drvdata(dev); + + tpm_dev_vendor_release(chip); + + kfree(chip); +} + + static struct pnp_driver tis_pnp_driver = { .name = "tpm_tis", .id_table = tpm_pnp_tbl, .probe = tpm_tis_pnp_init, .suspend = tpm_tis_pnp_suspend, .resume = tpm_tis_pnp_resume, + .remove = tpm_tis_pnp_remove, }; #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 @@ -683,6 +694,7 @@ static void __exit cleanup_tis(void) spin_lock(&tis_lock); list_for_each_entry_safe(i, j, &tis_chips, list) { chip = to_tpm_chip(i); + tpm_remove_hardware(chip->dev); iowrite32(~TPM_GLOBAL_INT_ENABLE & ioread32(chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor. @@ -694,9 +706,9 @@ static void __exit cleanup_tis(void) free_irq(chip->vendor.irq, chip); iounmap(i->iobase); list_del(&i->list); - tpm_remove_hardware(chip->dev); } spin_unlock(&tis_lock); + if (force) { platform_device_unregister(pdev); driver_unregister(&tis_drv); -- cgit v1.2.3 From 4bdec11f560b8f405a011288a50e65b1a81b3654 Mon Sep 17 00:00:00 2001 From: Rajiv Andrade Date: Sat, 11 Oct 2008 09:05:20 +1100 Subject: As pointed out by Jonathan Corbet, the timer must be deleted before flushing the work queue in order to avoid a job being submitted after the chip had been released. Signed-off-by: Rajiv Andrade Signed-off-by: Mimi Zohar Cc: Jonathan Corbet Cc: "Serge E. Hallyn" Signed-off-by: Andrew Morton Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 02a495c2e06..1fee7034a38 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1004,9 +1004,9 @@ int tpm_release(struct inode *inode, struct file *file) { struct tpm_chip *chip = file->private_data; + del_singleshot_timer_sync(&chip->user_read_timer); flush_scheduled_work(); file->private_data = NULL; - del_singleshot_timer_sync(&chip->user_read_timer); atomic_set(&chip->data_pending, 0); kfree(chip->data_buffer); clear_bit(0, &chip->is_open); -- cgit v1.2.3