diff options
Diffstat (limited to 'drivers/char/tpm/tpm.c')
-rw-r--r-- | drivers/char/tpm/tpm.c | 96 |
1 files changed, 46 insertions, 50 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index ae766d868454..1fee7034a386 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -954,72 +954,63 @@ EXPORT_SYMBOL_GPL(tpm_store_cancel); | |||
954 | 954 | ||
955 | /* | 955 | /* |
956 | * Device file system interface to the TPM | 956 | * Device file system interface to the TPM |
957 | * | ||
958 | * It's assured that the chip will be opened just once, | ||
959 | * by the check of is_open variable, which is protected | ||
960 | * by driver_lock. | ||
957 | */ | 961 | */ |
958 | int tpm_open(struct inode *inode, struct file *file) | 962 | int tpm_open(struct inode *inode, struct file *file) |
959 | { | 963 | { |
960 | int rc = 0, minor = iminor(inode); | 964 | int minor = iminor(inode); |
961 | struct tpm_chip *chip = NULL, *pos; | 965 | struct tpm_chip *chip = NULL, *pos; |
962 | 966 | ||
963 | lock_kernel(); | 967 | rcu_read_lock(); |
964 | spin_lock(&driver_lock); | 968 | list_for_each_entry_rcu(pos, &tpm_chip_list, list) { |
965 | |||
966 | list_for_each_entry(pos, &tpm_chip_list, list) { | ||
967 | if (pos->vendor.miscdev.minor == minor) { | 969 | if (pos->vendor.miscdev.minor == minor) { |
968 | chip = pos; | 970 | chip = pos; |
971 | get_device(chip->dev); | ||
969 | break; | 972 | break; |
970 | } | 973 | } |
971 | } | 974 | } |
975 | rcu_read_unlock(); | ||
972 | 976 | ||
973 | if (chip == NULL) { | 977 | if (!chip) |
974 | rc = -ENODEV; | 978 | return -ENODEV; |
975 | goto err_out; | ||
976 | } | ||
977 | 979 | ||
978 | if (chip->num_opens) { | 980 | if (test_and_set_bit(0, &chip->is_open)) { |
979 | dev_dbg(chip->dev, "Another process owns this TPM\n"); | 981 | dev_dbg(chip->dev, "Another process owns this TPM\n"); |
980 | rc = -EBUSY; | 982 | put_device(chip->dev); |
981 | goto err_out; | 983 | return -EBUSY; |
982 | } | 984 | } |
983 | 985 | ||
984 | chip->num_opens++; | ||
985 | get_device(chip->dev); | ||
986 | |||
987 | spin_unlock(&driver_lock); | ||
988 | |||
989 | chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); | 986 | chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); |
990 | if (chip->data_buffer == NULL) { | 987 | if (chip->data_buffer == NULL) { |
991 | chip->num_opens--; | 988 | clear_bit(0, &chip->is_open); |
992 | put_device(chip->dev); | 989 | put_device(chip->dev); |
993 | unlock_kernel(); | ||
994 | return -ENOMEM; | 990 | return -ENOMEM; |
995 | } | 991 | } |
996 | 992 | ||
997 | atomic_set(&chip->data_pending, 0); | 993 | atomic_set(&chip->data_pending, 0); |
998 | 994 | ||
999 | file->private_data = chip; | 995 | file->private_data = chip; |
1000 | unlock_kernel(); | ||
1001 | return 0; | 996 | return 0; |
1002 | |||
1003 | err_out: | ||
1004 | spin_unlock(&driver_lock); | ||
1005 | unlock_kernel(); | ||
1006 | return rc; | ||
1007 | } | 997 | } |
1008 | EXPORT_SYMBOL_GPL(tpm_open); | 998 | EXPORT_SYMBOL_GPL(tpm_open); |
1009 | 999 | ||
1000 | /* | ||
1001 | * Called on file close | ||
1002 | */ | ||
1010 | int tpm_release(struct inode *inode, struct file *file) | 1003 | int tpm_release(struct inode *inode, struct file *file) |
1011 | { | 1004 | { |
1012 | struct tpm_chip *chip = file->private_data; | 1005 | struct tpm_chip *chip = file->private_data; |
1013 | 1006 | ||
1007 | del_singleshot_timer_sync(&chip->user_read_timer); | ||
1014 | flush_scheduled_work(); | 1008 | flush_scheduled_work(); |
1015 | spin_lock(&driver_lock); | ||
1016 | file->private_data = NULL; | 1009 | file->private_data = NULL; |
1017 | del_singleshot_timer_sync(&chip->user_read_timer); | ||
1018 | atomic_set(&chip->data_pending, 0); | 1010 | atomic_set(&chip->data_pending, 0); |
1019 | chip->num_opens--; | ||
1020 | put_device(chip->dev); | ||
1021 | kfree(chip->data_buffer); | 1011 | kfree(chip->data_buffer); |
1022 | spin_unlock(&driver_lock); | 1012 | clear_bit(0, &chip->is_open); |
1013 | put_device(chip->dev); | ||
1023 | return 0; | 1014 | return 0; |
1024 | } | 1015 | } |
1025 | EXPORT_SYMBOL_GPL(tpm_release); | 1016 | EXPORT_SYMBOL_GPL(tpm_release); |
@@ -1093,13 +1084,11 @@ void tpm_remove_hardware(struct device *dev) | |||
1093 | } | 1084 | } |
1094 | 1085 | ||
1095 | spin_lock(&driver_lock); | 1086 | spin_lock(&driver_lock); |
1096 | 1087 | list_del_rcu(&chip->list); | |
1097 | list_del(&chip->list); | ||
1098 | |||
1099 | spin_unlock(&driver_lock); | 1088 | spin_unlock(&driver_lock); |
1089 | synchronize_rcu(); | ||
1100 | 1090 | ||
1101 | misc_deregister(&chip->vendor.miscdev); | 1091 | misc_deregister(&chip->vendor.miscdev); |
1102 | |||
1103 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); | 1092 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); |
1104 | tpm_bios_log_teardown(chip->bios_dir); | 1093 | tpm_bios_log_teardown(chip->bios_dir); |
1105 | 1094 | ||
@@ -1144,25 +1133,33 @@ int tpm_pm_resume(struct device *dev) | |||
1144 | } | 1133 | } |
1145 | EXPORT_SYMBOL_GPL(tpm_pm_resume); | 1134 | EXPORT_SYMBOL_GPL(tpm_pm_resume); |
1146 | 1135 | ||
1136 | /* In case vendor provided release function, call it too.*/ | ||
1137 | |||
1138 | void tpm_dev_vendor_release(struct tpm_chip *chip) | ||
1139 | { | ||
1140 | if (chip->vendor.release) | ||
1141 | chip->vendor.release(chip->dev); | ||
1142 | |||
1143 | clear_bit(chip->dev_num, dev_mask); | ||
1144 | kfree(chip->vendor.miscdev.name); | ||
1145 | } | ||
1146 | EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); | ||
1147 | |||
1148 | |||
1147 | /* | 1149 | /* |
1148 | * Once all references to platform device are down to 0, | 1150 | * Once all references to platform device are down to 0, |
1149 | * release all allocated structures. | 1151 | * release all allocated structures. |
1150 | * In case vendor provided release function, | ||
1151 | * call it too. | ||
1152 | */ | 1152 | */ |
1153 | static void tpm_dev_release(struct device *dev) | 1153 | static void tpm_dev_release(struct device *dev) |
1154 | { | 1154 | { |
1155 | struct tpm_chip *chip = dev_get_drvdata(dev); | 1155 | struct tpm_chip *chip = dev_get_drvdata(dev); |
1156 | 1156 | ||
1157 | if (chip->vendor.release) | 1157 | tpm_dev_vendor_release(chip); |
1158 | chip->vendor.release(dev); | ||
1159 | 1158 | ||
1160 | chip->release(dev); | 1159 | chip->release(dev); |
1161 | |||
1162 | clear_bit(chip->dev_num, dev_mask); | ||
1163 | kfree(chip->vendor.miscdev.name); | ||
1164 | kfree(chip); | 1160 | kfree(chip); |
1165 | } | 1161 | } |
1162 | EXPORT_SYMBOL_GPL(tpm_dev_release); | ||
1166 | 1163 | ||
1167 | /* | 1164 | /* |
1168 | * Called from tpm_<specific>.c probe function only for devices | 1165 | * Called from tpm_<specific>.c probe function only for devices |
@@ -1171,8 +1168,8 @@ static void tpm_dev_release(struct device *dev) | |||
1171 | * upon errant exit from this function specific probe function should call | 1168 | * upon errant exit from this function specific probe function should call |
1172 | * pci_disable_device | 1169 | * pci_disable_device |
1173 | */ | 1170 | */ |
1174 | struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific | 1171 | struct tpm_chip *tpm_register_hardware(struct device *dev, |
1175 | *entry) | 1172 | const struct tpm_vendor_specific *entry) |
1176 | { | 1173 | { |
1177 | #define DEVNAME_SIZE 7 | 1174 | #define DEVNAME_SIZE 7 |
1178 | 1175 | ||
@@ -1231,21 +1228,20 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend | |||
1231 | return NULL; | 1228 | return NULL; |
1232 | } | 1229 | } |
1233 | 1230 | ||
1234 | spin_lock(&driver_lock); | ||
1235 | |||
1236 | list_add(&chip->list, &tpm_chip_list); | ||
1237 | |||
1238 | spin_unlock(&driver_lock); | ||
1239 | |||
1240 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { | 1231 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { |
1241 | list_del(&chip->list); | ||
1242 | misc_deregister(&chip->vendor.miscdev); | 1232 | misc_deregister(&chip->vendor.miscdev); |
1243 | put_device(chip->dev); | 1233 | put_device(chip->dev); |
1234 | |||
1244 | return NULL; | 1235 | return NULL; |
1245 | } | 1236 | } |
1246 | 1237 | ||
1247 | chip->bios_dir = tpm_bios_log_setup(devname); | 1238 | chip->bios_dir = tpm_bios_log_setup(devname); |
1248 | 1239 | ||
1240 | /* Make chip available */ | ||
1241 | spin_lock(&driver_lock); | ||
1242 | list_add_rcu(&chip->list, &tpm_chip_list); | ||
1243 | spin_unlock(&driver_lock); | ||
1244 | |||
1249 | return chip; | 1245 | return chip; |
1250 | } | 1246 | } |
1251 | EXPORT_SYMBOL_GPL(tpm_register_hardware); | 1247 | EXPORT_SYMBOL_GPL(tpm_register_hardware); |