diff options
author | Rajiv Andrade <srajiv@linux.vnet.ibm.com> | 2008-10-10 18:04:23 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-10-10 18:04:23 -0400 |
commit | f02a93645e6200a9da0f26dac8ced28c612f5e86 (patch) | |
tree | 2fc93ca32c93f6f91af1efefa2e8c103f65931f1 /drivers/char/tpm/tpm.c | |
parent | dc36d32cc5bea5e985294c79995e10a159c3019a (diff) |
Protect tpm_chip_list when transversing it.
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
Acked-by: Serge E. Hallyn <serue@us.ibm.com>
Cc: "Paul E. McKenney" <paulmck@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'drivers/char/tpm/tpm.c')
-rw-r--r-- | drivers/char/tpm/tpm.c | 61 |
1 files changed, 24 insertions, 37 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index dfd4e7fc350b..4f18f84b498a 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -961,33 +961,28 @@ EXPORT_SYMBOL_GPL(tpm_store_cancel); | |||
961 | */ | 961 | */ |
962 | int tpm_open(struct inode *inode, struct file *file) | 962 | int tpm_open(struct inode *inode, struct file *file) |
963 | { | 963 | { |
964 | int rc = 0, minor = iminor(inode); | 964 | int minor = iminor(inode); |
965 | struct tpm_chip *chip = NULL, *pos; | 965 | struct tpm_chip *chip = NULL, *pos; |
966 | 966 | ||
967 | spin_lock(&driver_lock); | 967 | rcu_read_lock(); |
968 | 968 | list_for_each_entry_rcu(pos, &tpm_chip_list, list) { | |
969 | list_for_each_entry(pos, &tpm_chip_list, list) { | ||
970 | if (pos->vendor.miscdev.minor == minor) { | 969 | if (pos->vendor.miscdev.minor == minor) { |
971 | chip = pos; | 970 | chip = pos; |
971 | get_device(chip->dev); | ||
972 | break; | 972 | break; |
973 | } | 973 | } |
974 | } | 974 | } |
975 | rcu_read_unlock(); | ||
975 | 976 | ||
976 | if (chip == NULL) { | 977 | if (!chip) |
977 | rc = -ENODEV; | 978 | return -ENODEV; |
978 | goto err_out; | ||
979 | } | ||
980 | 979 | ||
981 | if (test_and_set_bit(0, &chip->is_open)) { | 980 | if (test_and_set_bit(0, &chip->is_open)) { |
982 | dev_dbg(chip->dev, "Another process owns this TPM\n"); | 981 | dev_dbg(chip->dev, "Another process owns this TPM\n"); |
983 | rc = -EBUSY; | 982 | put_device(chip->dev); |
984 | goto err_out; | 983 | return -EBUSY; |
985 | } | 984 | } |
986 | 985 | ||
987 | get_device(chip->dev); | ||
988 | |||
989 | spin_unlock(&driver_lock); | ||
990 | |||
991 | chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); | 986 | chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); |
992 | if (chip->data_buffer == NULL) { | 987 | if (chip->data_buffer == NULL) { |
993 | clear_bit(0, &chip->is_open); | 988 | clear_bit(0, &chip->is_open); |
@@ -999,26 +994,23 @@ int tpm_open(struct inode *inode, struct file *file) | |||
999 | 994 | ||
1000 | file->private_data = chip; | 995 | file->private_data = chip; |
1001 | return 0; | 996 | return 0; |
1002 | |||
1003 | err_out: | ||
1004 | spin_unlock(&driver_lock); | ||
1005 | return rc; | ||
1006 | } | 997 | } |
1007 | EXPORT_SYMBOL_GPL(tpm_open); | 998 | EXPORT_SYMBOL_GPL(tpm_open); |
1008 | 999 | ||
1000 | /* | ||
1001 | * Called on file close | ||
1002 | */ | ||
1009 | int tpm_release(struct inode *inode, struct file *file) | 1003 | int tpm_release(struct inode *inode, struct file *file) |
1010 | { | 1004 | { |
1011 | struct tpm_chip *chip = file->private_data; | 1005 | struct tpm_chip *chip = file->private_data; |
1012 | 1006 | ||
1013 | flush_scheduled_work(); | 1007 | flush_scheduled_work(); |
1014 | spin_lock(&driver_lock); | ||
1015 | file->private_data = NULL; | 1008 | file->private_data = NULL; |
1016 | del_singleshot_timer_sync(&chip->user_read_timer); | 1009 | del_singleshot_timer_sync(&chip->user_read_timer); |
1017 | atomic_set(&chip->data_pending, 0); | 1010 | atomic_set(&chip->data_pending, 0); |
1011 | kfree(chip->data_buffer); | ||
1018 | clear_bit(0, &chip->is_open); | 1012 | clear_bit(0, &chip->is_open); |
1019 | put_device(chip->dev); | 1013 | put_device(chip->dev); |
1020 | kfree(chip->data_buffer); | ||
1021 | spin_unlock(&driver_lock); | ||
1022 | return 0; | 1014 | return 0; |
1023 | } | 1015 | } |
1024 | EXPORT_SYMBOL_GPL(tpm_release); | 1016 | EXPORT_SYMBOL_GPL(tpm_release); |
@@ -1092,13 +1084,11 @@ void tpm_remove_hardware(struct device *dev) | |||
1092 | } | 1084 | } |
1093 | 1085 | ||
1094 | spin_lock(&driver_lock); | 1086 | spin_lock(&driver_lock); |
1095 | 1087 | list_del_rcu(&chip->list); | |
1096 | list_del(&chip->list); | ||
1097 | |||
1098 | spin_unlock(&driver_lock); | 1088 | spin_unlock(&driver_lock); |
1089 | synchronize_rcu(); | ||
1099 | 1090 | ||
1100 | misc_deregister(&chip->vendor.miscdev); | 1091 | misc_deregister(&chip->vendor.miscdev); |
1101 | |||
1102 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); | 1092 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); |
1103 | tpm_bios_log_teardown(chip->bios_dir); | 1093 | tpm_bios_log_teardown(chip->bios_dir); |
1104 | 1094 | ||
@@ -1146,8 +1136,7 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume); | |||
1146 | /* | 1136 | /* |
1147 | * Once all references to platform device are down to 0, | 1137 | * Once all references to platform device are down to 0, |
1148 | * release all allocated structures. | 1138 | * release all allocated structures. |
1149 | * In case vendor provided release function, | 1139 | * In case vendor provided release function, call it too. |
1150 | * call it too. | ||
1151 | */ | 1140 | */ |
1152 | static void tpm_dev_release(struct device *dev) | 1141 | static void tpm_dev_release(struct device *dev) |
1153 | { | 1142 | { |
@@ -1155,7 +1144,6 @@ static void tpm_dev_release(struct device *dev) | |||
1155 | 1144 | ||
1156 | if (chip->vendor.release) | 1145 | if (chip->vendor.release) |
1157 | chip->vendor.release(dev); | 1146 | chip->vendor.release(dev); |
1158 | |||
1159 | chip->release(dev); | 1147 | chip->release(dev); |
1160 | 1148 | ||
1161 | clear_bit(chip->dev_num, dev_mask); | 1149 | clear_bit(chip->dev_num, dev_mask); |
@@ -1170,8 +1158,8 @@ static void tpm_dev_release(struct device *dev) | |||
1170 | * upon errant exit from this function specific probe function should call | 1158 | * upon errant exit from this function specific probe function should call |
1171 | * pci_disable_device | 1159 | * pci_disable_device |
1172 | */ | 1160 | */ |
1173 | struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific | 1161 | struct tpm_chip *tpm_register_hardware(struct device *dev, |
1174 | *entry) | 1162 | const struct tpm_vendor_specific *entry) |
1175 | { | 1163 | { |
1176 | #define DEVNAME_SIZE 7 | 1164 | #define DEVNAME_SIZE 7 |
1177 | 1165 | ||
@@ -1230,21 +1218,20 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend | |||
1230 | return NULL; | 1218 | return NULL; |
1231 | } | 1219 | } |
1232 | 1220 | ||
1233 | spin_lock(&driver_lock); | ||
1234 | |||
1235 | list_add(&chip->list, &tpm_chip_list); | ||
1236 | |||
1237 | spin_unlock(&driver_lock); | ||
1238 | |||
1239 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { | 1221 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { |
1240 | list_del(&chip->list); | ||
1241 | misc_deregister(&chip->vendor.miscdev); | 1222 | misc_deregister(&chip->vendor.miscdev); |
1242 | put_device(chip->dev); | 1223 | put_device(chip->dev); |
1224 | |||
1243 | return NULL; | 1225 | return NULL; |
1244 | } | 1226 | } |
1245 | 1227 | ||
1246 | chip->bios_dir = tpm_bios_log_setup(devname); | 1228 | chip->bios_dir = tpm_bios_log_setup(devname); |
1247 | 1229 | ||
1230 | /* Make chip available */ | ||
1231 | spin_lock(&driver_lock); | ||
1232 | list_add_rcu(&chip->list, &tpm_chip_list); | ||
1233 | spin_unlock(&driver_lock); | ||
1234 | |||
1248 | return chip; | 1235 | return chip; |
1249 | } | 1236 | } |
1250 | EXPORT_SYMBOL_GPL(tpm_register_hardware); | 1237 | EXPORT_SYMBOL_GPL(tpm_register_hardware); |