diff options
| author | Corey Minyard <cminyard@mvista.com> | 2018-04-05 23:05:04 -0400 |
|---|---|---|
| committer | Corey Minyard <cminyard@mvista.com> | 2018-04-18 11:22:58 -0400 |
| commit | e86ee2d44b44056243da17c120ad258717cedf9b (patch) | |
| tree | 8ea784b7af816612379aa0ecb26f4a754c973ae2 /drivers/char/ipmi | |
| parent | ac93bd0c9e163fd3e2edfb4b5af22955b408431a (diff) | |
ipmi: Rework locking and shutdown for hot remove
To handle hot remove of interfaces, a lot of rework had to be
done to the locking. Several things were switched over to srcu
and shutdown for users and interfaces was added for cleaner
shutdown.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Diffstat (limited to 'drivers/char/ipmi')
| -rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 490 |
1 files changed, 280 insertions, 210 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index c21c4e021dab..a27b50ac2b7f 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
| @@ -197,8 +197,12 @@ MODULE_PARM_DESC(default_max_retries, | |||
| 197 | struct ipmi_user { | 197 | struct ipmi_user { |
| 198 | struct list_head link; | 198 | struct list_head link; |
| 199 | 199 | ||
| 200 | /* Set to false when the user is destroyed. */ | 200 | /* |
| 201 | bool valid; | 201 | * Set to NULL when the user is destroyed, a pointer to myself |
| 202 | * so srcu_dereference can be used on it. | ||
| 203 | */ | ||
| 204 | struct ipmi_user *self; | ||
| 205 | struct srcu_struct release_barrier; | ||
| 202 | 206 | ||
| 203 | struct kref refcount; | 207 | struct kref refcount; |
| 204 | 208 | ||
| @@ -213,6 +217,23 @@ struct ipmi_user { | |||
| 213 | bool gets_events; | 217 | bool gets_events; |
| 214 | }; | 218 | }; |
| 215 | 219 | ||
| 220 | static struct ipmi_user *acquire_ipmi_user(struct ipmi_user *user, int *index) | ||
| 221 | __acquires(user->release_barrier) | ||
| 222 | { | ||
| 223 | struct ipmi_user *ruser; | ||
| 224 | |||
| 225 | *index = srcu_read_lock(&user->release_barrier); | ||
| 226 | ruser = srcu_dereference(user->self, &user->release_barrier); | ||
| 227 | if (!ruser) | ||
| 228 | srcu_read_unlock(&user->release_barrier, *index); | ||
| 229 | return ruser; | ||
| 230 | } | ||
| 231 | |||
| 232 | static void release_ipmi_user(struct ipmi_user *user, int index) | ||
| 233 | { | ||
| 234 | srcu_read_unlock(&user->release_barrier, index); | ||
| 235 | } | ||
| 236 | |||
| 216 | struct cmd_rcvr { | 237 | struct cmd_rcvr { |
| 217 | struct list_head link; | 238 | struct list_head link; |
| 218 | 239 | ||
| @@ -444,10 +465,11 @@ struct ipmi_smi { | |||
| 444 | struct list_head link; | 465 | struct list_head link; |
| 445 | 466 | ||
| 446 | /* | 467 | /* |
| 447 | * The list of upper layers that are using me. seq_lock | 468 | * The list of upper layers that are using me. seq_lock write |
| 448 | * protects this. | 469 | * protects this. Read protection is with srcu. |
| 449 | */ | 470 | */ |
| 450 | struct list_head users; | 471 | struct list_head users; |
| 472 | struct srcu_struct users_srcu; | ||
| 451 | 473 | ||
| 452 | /* Used for wake ups at startup. */ | 474 | /* Used for wake ups at startup. */ |
| 453 | wait_queue_head_t waitq; | 475 | wait_queue_head_t waitq; |
| @@ -467,12 +489,6 @@ struct ipmi_smi { | |||
| 467 | bool in_bmc_register; /* Handle recursive situations. Yuck. */ | 489 | bool in_bmc_register; /* Handle recursive situations. Yuck. */ |
| 468 | struct work_struct bmc_reg_work; | 490 | struct work_struct bmc_reg_work; |
| 469 | 491 | ||
| 470 | /* | ||
| 471 | * This is the lower-layer's sender routine. Note that you | ||
| 472 | * must either be holding the ipmi_interfaces_mutex or be in | ||
| 473 | * an umpreemptible region to use this. You must fetch the | ||
| 474 | * value into a local variable and make sure it is not NULL. | ||
| 475 | */ | ||
| 476 | const struct ipmi_smi_handlers *handlers; | 492 | const struct ipmi_smi_handlers *handlers; |
| 477 | void *send_info; | 493 | void *send_info; |
| 478 | 494 | ||
| @@ -615,6 +631,7 @@ static DEFINE_MUTEX(ipmidriver_mutex); | |||
| 615 | 631 | ||
| 616 | static LIST_HEAD(ipmi_interfaces); | 632 | static LIST_HEAD(ipmi_interfaces); |
| 617 | static DEFINE_MUTEX(ipmi_interfaces_mutex); | 633 | static DEFINE_MUTEX(ipmi_interfaces_mutex); |
| 634 | DEFINE_STATIC_SRCU(ipmi_interfaces_srcu); | ||
| 618 | 635 | ||
| 619 | /* | 636 | /* |
| 620 | * List of watchers that want to know when smi's are added and deleted. | 637 | * List of watchers that want to know when smi's are added and deleted. |
| @@ -715,58 +732,32 @@ static void intf_free(struct kref *ref) | |||
| 715 | 732 | ||
| 716 | struct watcher_entry { | 733 | struct watcher_entry { |
| 717 | int intf_num; | 734 | int intf_num; |
| 718 | struct ipmi_smi *intf; | 735 | struct ipmi_smi *intf; |
| 719 | struct list_head link; | 736 | struct list_head link; |
| 720 | }; | 737 | }; |
| 721 | 738 | ||
| 722 | int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) | 739 | int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) |
| 723 | { | 740 | { |
| 724 | struct ipmi_smi *intf; | 741 | struct ipmi_smi *intf; |
| 725 | LIST_HEAD(to_deliver); | 742 | int index; |
| 726 | struct watcher_entry *e, *e2; | ||
| 727 | 743 | ||
| 728 | mutex_lock(&smi_watchers_mutex); | 744 | mutex_lock(&smi_watchers_mutex); |
| 729 | 745 | ||
| 730 | mutex_lock(&ipmi_interfaces_mutex); | ||
| 731 | |||
| 732 | /* Build a list of things to deliver. */ | ||
| 733 | list_for_each_entry(intf, &ipmi_interfaces, link) { | ||
| 734 | if (intf->intf_num == -1) | ||
| 735 | continue; | ||
| 736 | e = kmalloc(sizeof(*e), GFP_KERNEL); | ||
| 737 | if (!e) | ||
| 738 | goto out_err; | ||
| 739 | kref_get(&intf->refcount); | ||
| 740 | e->intf = intf; | ||
| 741 | e->intf_num = intf->intf_num; | ||
| 742 | list_add_tail(&e->link, &to_deliver); | ||
| 743 | } | ||
| 744 | |||
| 745 | /* We will succeed, so add it to the list. */ | ||
| 746 | list_add(&watcher->link, &smi_watchers); | 746 | list_add(&watcher->link, &smi_watchers); |
| 747 | 747 | ||
| 748 | mutex_unlock(&ipmi_interfaces_mutex); | 748 | index = srcu_read_lock(&ipmi_interfaces_srcu); |
| 749 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { | ||
| 750 | int intf_num = READ_ONCE(intf->intf_num); | ||
| 749 | 751 | ||
| 750 | list_for_each_entry_safe(e, e2, &to_deliver, link) { | 752 | if (intf_num == -1) |
| 751 | list_del(&e->link); | 753 | continue; |
| 752 | watcher->new_smi(e->intf_num, e->intf->si_dev); | 754 | watcher->new_smi(intf_num, intf->si_dev); |
| 753 | kref_put(&e->intf->refcount, intf_free); | ||
| 754 | kfree(e); | ||
| 755 | } | 755 | } |
| 756 | srcu_read_unlock(&ipmi_interfaces_srcu, index); | ||
| 756 | 757 | ||
| 757 | mutex_unlock(&smi_watchers_mutex); | 758 | mutex_unlock(&smi_watchers_mutex); |
| 758 | 759 | ||
| 759 | return 0; | 760 | return 0; |
| 760 | |||
| 761 | out_err: | ||
| 762 | mutex_unlock(&ipmi_interfaces_mutex); | ||
| 763 | mutex_unlock(&smi_watchers_mutex); | ||
| 764 | list_for_each_entry_safe(e, e2, &to_deliver, link) { | ||
| 765 | list_del(&e->link); | ||
| 766 | kref_put(&e->intf->refcount, intf_free); | ||
| 767 | kfree(e); | ||
| 768 | } | ||
| 769 | return -ENOMEM; | ||
| 770 | } | 761 | } |
| 771 | EXPORT_SYMBOL(ipmi_smi_watcher_register); | 762 | EXPORT_SYMBOL(ipmi_smi_watcher_register); |
| 772 | 763 | ||
| @@ -787,12 +778,14 @@ call_smi_watchers(int i, struct device *dev) | |||
| 787 | { | 778 | { |
| 788 | struct ipmi_smi_watcher *w; | 779 | struct ipmi_smi_watcher *w; |
| 789 | 780 | ||
| 781 | mutex_lock(&smi_watchers_mutex); | ||
| 790 | list_for_each_entry(w, &smi_watchers, link) { | 782 | list_for_each_entry(w, &smi_watchers, link) { |
| 791 | if (try_module_get(w->owner)) { | 783 | if (try_module_get(w->owner)) { |
| 792 | w->new_smi(i, dev); | 784 | w->new_smi(i, dev); |
| 793 | module_put(w->owner); | 785 | module_put(w->owner); |
| 794 | } | 786 | } |
| 795 | } | 787 | } |
| 788 | mutex_unlock(&smi_watchers_mutex); | ||
| 796 | } | 789 | } |
| 797 | 790 | ||
| 798 | static int | 791 | static int |
| @@ -905,9 +898,17 @@ static int deliver_response(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) | |||
| 905 | * receive handler doesn't much meaning and has a deadlock | 898 | * receive handler doesn't much meaning and has a deadlock |
| 906 | * risk. At this moment, simply skip it in that case. | 899 | * risk. At this moment, simply skip it in that case. |
| 907 | */ | 900 | */ |
| 901 | int index; | ||
| 902 | struct ipmi_user *user = acquire_ipmi_user(msg->user, &index); | ||
| 908 | 903 | ||
| 909 | struct ipmi_user *user = msg->user; | 904 | if (user) { |
| 910 | user->handler->ipmi_recv_hndl(msg, user->handler_data); | 905 | user->handler->ipmi_recv_hndl(msg, user->handler_data); |
| 906 | release_ipmi_user(msg->user, index); | ||
| 907 | } else { | ||
| 908 | /* User went away, give up. */ | ||
| 909 | ipmi_free_recv_msg(msg); | ||
| 910 | rv = -EINVAL; | ||
| 911 | } | ||
| 911 | } | 912 | } |
| 912 | 913 | ||
| 913 | return rv; | 914 | return rv; |
| @@ -1094,7 +1095,7 @@ int ipmi_create_user(unsigned int if_num, | |||
| 1094 | { | 1095 | { |
| 1095 | unsigned long flags; | 1096 | unsigned long flags; |
| 1096 | struct ipmi_user *new_user; | 1097 | struct ipmi_user *new_user; |
| 1097 | int rv = 0; | 1098 | int rv = 0, index; |
| 1098 | struct ipmi_smi *intf; | 1099 | struct ipmi_smi *intf; |
| 1099 | 1100 | ||
| 1100 | /* | 1101 | /* |
| @@ -1129,7 +1130,7 @@ int ipmi_create_user(unsigned int if_num, | |||
| 1129 | if (!new_user) | 1130 | if (!new_user) |
| 1130 | return -ENOMEM; | 1131 | return -ENOMEM; |
| 1131 | 1132 | ||
| 1132 | mutex_lock(&ipmi_interfaces_mutex); | 1133 | index = srcu_read_lock(&ipmi_interfaces_srcu); |
| 1133 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { | 1134 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { |
| 1134 | if (intf->intf_num == if_num) | 1135 | if (intf->intf_num == if_num) |
| 1135 | goto found; | 1136 | goto found; |
| @@ -1139,6 +1140,10 @@ int ipmi_create_user(unsigned int if_num, | |||
| 1139 | goto out_kfree; | 1140 | goto out_kfree; |
| 1140 | 1141 | ||
| 1141 | found: | 1142 | found: |
| 1143 | rv = init_srcu_struct(&new_user->release_barrier); | ||
| 1144 | if (rv) | ||
| 1145 | goto out_kfree; | ||
| 1146 | |||
| 1142 | /* Note that each existing user holds a refcount to the interface. */ | 1147 | /* Note that each existing user holds a refcount to the interface. */ |
| 1143 | kref_get(&intf->refcount); | 1148 | kref_get(&intf->refcount); |
| 1144 | 1149 | ||
| @@ -1148,26 +1153,7 @@ int ipmi_create_user(unsigned int if_num, | |||
| 1148 | new_user->intf = intf; | 1153 | new_user->intf = intf; |
| 1149 | new_user->gets_events = false; | 1154 | new_user->gets_events = false; |
| 1150 | 1155 | ||
| 1151 | if (!try_module_get(intf->handlers->owner)) { | 1156 | rcu_assign_pointer(new_user->self, new_user); |
| 1152 | rv = -ENODEV; | ||
| 1153 | goto out_kref; | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | if (intf->handlers->inc_usecount) { | ||
| 1157 | rv = intf->handlers->inc_usecount(intf->send_info); | ||
| 1158 | if (rv) { | ||
| 1159 | module_put(intf->handlers->owner); | ||
| 1160 | goto out_kref; | ||
| 1161 | } | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | /* | ||
| 1165 | * Hold the lock so intf->handlers is guaranteed to be good | ||
| 1166 | * until now | ||
| 1167 | */ | ||
| 1168 | mutex_unlock(&ipmi_interfaces_mutex); | ||
| 1169 | |||
| 1170 | new_user->valid = true; | ||
| 1171 | spin_lock_irqsave(&intf->seq_lock, flags); | 1157 | spin_lock_irqsave(&intf->seq_lock, flags); |
| 1172 | list_add_rcu(&new_user->link, &intf->users); | 1158 | list_add_rcu(&new_user->link, &intf->users); |
| 1173 | spin_unlock_irqrestore(&intf->seq_lock, flags); | 1159 | spin_unlock_irqrestore(&intf->seq_lock, flags); |
| @@ -1176,13 +1162,12 @@ int ipmi_create_user(unsigned int if_num, | |||
| 1176 | if (atomic_inc_return(&intf->event_waiters) == 1) | 1162 | if (atomic_inc_return(&intf->event_waiters) == 1) |
| 1177 | need_waiter(intf); | 1163 | need_waiter(intf); |
| 1178 | } | 1164 | } |
| 1165 | srcu_read_unlock(&ipmi_interfaces_srcu, index); | ||
| 1179 | *user = new_user; | 1166 | *user = new_user; |
| 1180 | return 0; | 1167 | return 0; |
| 1181 | 1168 | ||
| 1182 | out_kref: | ||
| 1183 | kref_put(&intf->refcount, intf_free); | ||
| 1184 | out_kfree: | 1169 | out_kfree: |
| 1185 | mutex_unlock(&ipmi_interfaces_mutex); | 1170 | srcu_read_unlock(&ipmi_interfaces_srcu, index); |
| 1186 | kfree(new_user); | 1171 | kfree(new_user); |
| 1187 | return rv; | 1172 | return rv; |
| 1188 | } | 1173 | } |
| @@ -1190,26 +1175,25 @@ EXPORT_SYMBOL(ipmi_create_user); | |||
| 1190 | 1175 | ||
| 1191 | int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data) | 1176 | int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data) |
| 1192 | { | 1177 | { |
| 1193 | int rv = 0; | 1178 | int rv, index; |
| 1194 | struct ipmi_smi *intf; | 1179 | struct ipmi_smi *intf; |
| 1195 | const struct ipmi_smi_handlers *handlers; | ||
| 1196 | 1180 | ||
| 1197 | mutex_lock(&ipmi_interfaces_mutex); | 1181 | index = srcu_read_lock(&ipmi_interfaces_srcu); |
| 1198 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { | 1182 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { |
| 1199 | if (intf->intf_num == if_num) | 1183 | if (intf->intf_num == if_num) |
| 1200 | goto found; | 1184 | goto found; |
| 1201 | } | 1185 | } |
| 1186 | srcu_read_unlock(&ipmi_interfaces_srcu, index); | ||
| 1187 | |||
| 1202 | /* Not found, return an error */ | 1188 | /* Not found, return an error */ |
| 1203 | rv = -EINVAL; | 1189 | return -EINVAL; |
| 1204 | mutex_unlock(&ipmi_interfaces_mutex); | ||
| 1205 | return rv; | ||
| 1206 | 1190 | ||
| 1207 | found: | 1191 | found: |
| 1208 | handlers = intf->handlers; | 1192 | if (!intf->handlers->get_smi_info) |
| 1209 | rv = -ENOSYS; | 1193 | rv = -ENOTTY; |
| 1210 | if (handlers->get_smi_info) | 1194 | else |
| 1211 | rv = handlers->get_smi_info(intf->send_info, data); | 1195 | rv = intf->handlers->get_smi_info(intf->send_info, data); |
| 1212 | mutex_unlock(&ipmi_interfaces_mutex); | 1196 | srcu_read_unlock(&ipmi_interfaces_srcu, index); |
| 1213 | 1197 | ||
| 1214 | return rv; | 1198 | return rv; |
| 1215 | } | 1199 | } |
| @@ -1221,7 +1205,7 @@ static void free_user(struct kref *ref) | |||
| 1221 | kfree(user); | 1205 | kfree(user); |
| 1222 | } | 1206 | } |
| 1223 | 1207 | ||
| 1224 | int ipmi_destroy_user(struct ipmi_user *user) | 1208 | static void _ipmi_destroy_user(struct ipmi_user *user) |
| 1225 | { | 1209 | { |
| 1226 | struct ipmi_smi *intf = user->intf; | 1210 | struct ipmi_smi *intf = user->intf; |
| 1227 | int i; | 1211 | int i; |
| @@ -1229,7 +1213,22 @@ int ipmi_destroy_user(struct ipmi_user *user) | |||
| 1229 | struct cmd_rcvr *rcvr; | 1213 | struct cmd_rcvr *rcvr; |
| 1230 | struct cmd_rcvr *rcvrs = NULL; | 1214 | struct cmd_rcvr *rcvrs = NULL; |
| 1231 | 1215 | ||
| 1232 | user->valid = false; | 1216 | if (!acquire_ipmi_user(user, &i)) { |
| 1217 | /* | ||
| 1218 | * The user has already been cleaned up, just make sure | ||
| 1219 | * nothing is using it and return. | ||
| 1220 | */ | ||
| 1221 | synchronize_srcu(&user->release_barrier); | ||
| 1222 | return; | ||
| 1223 | } | ||
| 1224 | |||
| 1225 | rcu_assign_pointer(user->self, NULL); | ||
| 1226 | release_ipmi_user(user, i); | ||
| 1227 | |||
| 1228 | synchronize_srcu(&user->release_barrier); | ||
| 1229 | |||
| 1230 | if (user->handler->shutdown) | ||
| 1231 | user->handler->shutdown(user->handler_data); | ||
| 1233 | 1232 | ||
| 1234 | if (user->handler->ipmi_watchdog_pretimeout) | 1233 | if (user->handler->ipmi_watchdog_pretimeout) |
| 1235 | atomic_dec(&intf->event_waiters); | 1234 | atomic_dec(&intf->event_waiters); |
| @@ -1254,7 +1253,7 @@ int ipmi_destroy_user(struct ipmi_user *user) | |||
| 1254 | * Remove the user from the command receiver's table. First | 1253 | * Remove the user from the command receiver's table. First |
| 1255 | * we build a list of everything (not using the standard link, | 1254 | * we build a list of everything (not using the standard link, |
| 1256 | * since other things may be using it till we do | 1255 | * since other things may be using it till we do |
| 1257 | * synchronize_rcu()) then free everything in that list. | 1256 | * synchronize_srcu()) then free everything in that list. |
| 1258 | */ | 1257 | */ |
| 1259 | mutex_lock(&intf->cmd_rcvrs_mutex); | 1258 | mutex_lock(&intf->cmd_rcvrs_mutex); |
| 1260 | list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { | 1259 | list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { |
| @@ -1272,16 +1271,14 @@ int ipmi_destroy_user(struct ipmi_user *user) | |||
| 1272 | kfree(rcvr); | 1271 | kfree(rcvr); |
| 1273 | } | 1272 | } |
| 1274 | 1273 | ||
| 1275 | mutex_lock(&ipmi_interfaces_mutex); | ||
| 1276 | if (intf->handlers) { | ||
| 1277 | module_put(intf->handlers->owner); | ||
| 1278 | if (intf->handlers->dec_usecount) | ||
| 1279 | intf->handlers->dec_usecount(intf->send_info); | ||
| 1280 | } | ||
| 1281 | mutex_unlock(&ipmi_interfaces_mutex); | ||
| 1282 | |||
| 1283 | kref_put(&intf->refcount, intf_free); | 1274 | kref_put(&intf->refcount, intf_free); |
| 1275 | } | ||
| 1276 | |||
| 1277 | int ipmi_destroy_user(struct ipmi_user *user) | ||
| 1278 | { | ||
| 1279 | _ipmi_destroy_user(user); | ||
| 1284 | 1280 | ||
| 1281 | cleanup_srcu_struct(&user->release_barrier); | ||
| 1285 | kref_put(&user->refcount, free_user); | 1282 | kref_put(&user->refcount, free_user); |
| 1286 | 1283 | ||
| 1287 | return 0; | 1284 | return 0; |
| @@ -1293,16 +1290,20 @@ int ipmi_get_version(struct ipmi_user *user, | |||
| 1293 | unsigned char *minor) | 1290 | unsigned char *minor) |
| 1294 | { | 1291 | { |
| 1295 | struct ipmi_device_id id; | 1292 | struct ipmi_device_id id; |
| 1296 | int rv; | 1293 | int rv, index; |
| 1297 | 1294 | ||
| 1298 | rv = bmc_get_device_id(user->intf, NULL, &id, NULL, NULL); | 1295 | user = acquire_ipmi_user(user, &index); |
| 1299 | if (rv) | 1296 | if (!user) |
| 1300 | return rv; | 1297 | return -ENODEV; |
| 1301 | 1298 | ||
| 1302 | *major = ipmi_version_major(&id); | 1299 | rv = bmc_get_device_id(user->intf, NULL, &id, NULL, NULL); |
| 1303 | *minor = ipmi_version_minor(&id); | 1300 | if (!rv) { |
| 1301 | *major = ipmi_version_major(&id); | ||
| 1302 | *minor = ipmi_version_minor(&id); | ||
| 1303 | } | ||
| 1304 | release_ipmi_user(user, index); | ||
| 1304 | 1305 | ||
| 1305 | return 0; | 1306 | return rv; |
| 1306 | } | 1307 | } |
| 1307 | EXPORT_SYMBOL(ipmi_get_version); | 1308 | EXPORT_SYMBOL(ipmi_get_version); |
| 1308 | 1309 | ||
| @@ -1310,9 +1311,17 @@ int ipmi_set_my_address(struct ipmi_user *user, | |||
| 1310 | unsigned int channel, | 1311 | unsigned int channel, |
| 1311 | unsigned char address) | 1312 | unsigned char address) |
| 1312 | { | 1313 | { |
| 1314 | int index; | ||
| 1315 | |||
| 1316 | user = acquire_ipmi_user(user, &index); | ||
| 1317 | if (!user) | ||
| 1318 | return -ENODEV; | ||
| 1319 | |||
| 1313 | if (channel >= IPMI_MAX_CHANNELS) | 1320 | if (channel >= IPMI_MAX_CHANNELS) |
| 1314 | return -EINVAL; | 1321 | return -EINVAL; |
| 1315 | user->intf->addrinfo[channel].address = address; | 1322 | user->intf->addrinfo[channel].address = address; |
| 1323 | release_ipmi_user(user, index); | ||
| 1324 | |||
| 1316 | return 0; | 1325 | return 0; |
| 1317 | } | 1326 | } |
| 1318 | EXPORT_SYMBOL(ipmi_set_my_address); | 1327 | EXPORT_SYMBOL(ipmi_set_my_address); |
| @@ -1321,9 +1330,17 @@ int ipmi_get_my_address(struct ipmi_user *user, | |||
| 1321 | unsigned int channel, | 1330 | unsigned int channel, |
| 1322 | unsigned char *address) | 1331 | unsigned char *address) |
| 1323 | { | 1332 | { |
| 1333 | int index; | ||
| 1334 | |||
| 1335 | user = acquire_ipmi_user(user, &index); | ||
| 1336 | if (!user) | ||
| 1337 | return -ENODEV; | ||
| 1338 | |||
| 1324 | if (channel >= IPMI_MAX_CHANNELS) | 1339 | if (channel >= IPMI_MAX_CHANNELS) |
| 1325 | return -EINVAL; | 1340 | return -EINVAL; |
| 1326 | *address = user->intf->addrinfo[channel].address; | 1341 | *address = user->intf->addrinfo[channel].address; |
| 1342 | release_ipmi_user(user, index); | ||
| 1343 | |||
| 1327 | return 0; | 1344 | return 0; |
| 1328 | } | 1345 | } |
| 1329 | EXPORT_SYMBOL(ipmi_get_my_address); | 1346 | EXPORT_SYMBOL(ipmi_get_my_address); |
| @@ -1332,9 +1349,17 @@ int ipmi_set_my_LUN(struct ipmi_user *user, | |||
| 1332 | unsigned int channel, | 1349 | unsigned int channel, |
| 1333 | unsigned char LUN) | 1350 | unsigned char LUN) |
| 1334 | { | 1351 | { |
| 1352 | int index; | ||
| 1353 | |||
| 1354 | user = acquire_ipmi_user(user, &index); | ||
| 1355 | if (!user) | ||
| 1356 | return -ENODEV; | ||
| 1357 | |||
| 1335 | if (channel >= IPMI_MAX_CHANNELS) | 1358 | if (channel >= IPMI_MAX_CHANNELS) |
| 1336 | return -EINVAL; | 1359 | return -EINVAL; |
| 1337 | user->intf->addrinfo[channel].lun = LUN & 0x3; | 1360 | user->intf->addrinfo[channel].lun = LUN & 0x3; |
| 1361 | release_ipmi_user(user, index); | ||
| 1362 | |||
| 1338 | return 0; | 1363 | return 0; |
| 1339 | } | 1364 | } |
| 1340 | EXPORT_SYMBOL(ipmi_set_my_LUN); | 1365 | EXPORT_SYMBOL(ipmi_set_my_LUN); |
| @@ -1343,21 +1368,34 @@ int ipmi_get_my_LUN(struct ipmi_user *user, | |||
| 1343 | unsigned int channel, | 1368 | unsigned int channel, |
| 1344 | unsigned char *address) | 1369 | unsigned char *address) |
| 1345 | { | 1370 | { |
| 1371 | int index; | ||
| 1372 | |||
| 1373 | user = acquire_ipmi_user(user, &index); | ||
| 1374 | if (!user) | ||
| 1375 | return -ENODEV; | ||
| 1376 | |||
| 1346 | if (channel >= IPMI_MAX_CHANNELS) | 1377 | if (channel >= IPMI_MAX_CHANNELS) |
| 1347 | return -EINVAL; | 1378 | return -EINVAL; |
| 1348 | *address = user->intf->addrinfo[channel].lun; | 1379 | *address = user->intf->addrinfo[channel].lun; |
| 1380 | release_ipmi_user(user, index); | ||
| 1381 | |||
| 1349 | return 0; | 1382 | return 0; |
| 1350 | } | 1383 | } |
| 1351 | EXPORT_SYMBOL(ipmi_get_my_LUN); | 1384 | EXPORT_SYMBOL(ipmi_get_my_LUN); |
| 1352 | 1385 | ||
| 1353 | int ipmi_get_maintenance_mode(struct ipmi_user *user) | 1386 | int ipmi_get_maintenance_mode(struct ipmi_user *user) |
| 1354 | { | 1387 | { |
| 1355 | int mode; | 1388 | int mode, index; |
| 1356 | unsigned long flags; | 1389 | unsigned long flags; |
| 1357 | 1390 | ||
| 1391 | user = acquire_ipmi_user(user, &index); | ||
| 1392 | if (!user) | ||
| 1393 | return -ENODEV; | ||
| 1394 | |||
| 1358 | spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags); | 1395 | spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags); |
| 1359 | mode = user->intf->maintenance_mode; | 1396 | mode = user->intf->maintenance_mode; |
| 1360 | spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags); | 1397 | spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags); |
| 1398 | release_ipmi_user(user, index); | ||
| 1361 | 1399 | ||
| 1362 | return mode; | 1400 | return mode; |
| 1363 | } | 1401 | } |
| @@ -1372,10 +1410,14 @@ static void maintenance_mode_update(struct ipmi_smi *intf) | |||
| 1372 | 1410 | ||
| 1373 | int ipmi_set_maintenance_mode(struct ipmi_user *user, int mode) | 1411 | int ipmi_set_maintenance_mode(struct ipmi_user *user, int mode) |
| 1374 | { | 1412 | { |
| 1375 | int rv = 0; | 1413 | int rv = 0, index; |
| 1376 | unsigned long flags; | 1414 | unsigned long flags; |
| 1377 | struct ipmi_smi *intf = user->intf; | 1415 | struct ipmi_smi *intf = user->intf; |
| 1378 | 1416 | ||
| 1417 | user = acquire_ipmi_user(user, &index); | ||
| 1418 | if (!user) | ||
| 1419 | return -ENODEV; | ||
| 1420 | |||
| 1379 | spin_lock_irqsave(&intf->maintenance_mode_lock, flags); | 1421 | spin_lock_irqsave(&intf->maintenance_mode_lock, flags); |
| 1380 | if (intf->maintenance_mode != mode) { | 1422 | if (intf->maintenance_mode != mode) { |
| 1381 | switch (mode) { | 1423 | switch (mode) { |
| @@ -1402,6 +1444,7 @@ int ipmi_set_maintenance_mode(struct ipmi_user *user, int mode) | |||
| 1402 | } | 1444 | } |
| 1403 | out_unlock: | 1445 | out_unlock: |
| 1404 | spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags); | 1446 | spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags); |
| 1447 | release_ipmi_user(user, index); | ||
| 1405 | 1448 | ||
| 1406 | return rv; | 1449 | return rv; |
| 1407 | } | 1450 | } |
| @@ -1413,6 +1456,11 @@ int ipmi_set_gets_events(struct ipmi_user *user, bool val) | |||
| 1413 | struct ipmi_smi *intf = user->intf; | 1456 | struct ipmi_smi *intf = user->intf; |
| 1414 | struct ipmi_recv_msg *msg, *msg2; | 1457 | struct ipmi_recv_msg *msg, *msg2; |
| 1415 | struct list_head msgs; | 1458 | struct list_head msgs; |
| 1459 | int index; | ||
| 1460 | |||
| 1461 | user = acquire_ipmi_user(user, &index); | ||
| 1462 | if (!user) | ||
| 1463 | return -ENODEV; | ||
| 1416 | 1464 | ||
| 1417 | INIT_LIST_HEAD(&msgs); | 1465 | INIT_LIST_HEAD(&msgs); |
| 1418 | 1466 | ||
| @@ -1462,6 +1510,7 @@ int ipmi_set_gets_events(struct ipmi_user *user, bool val) | |||
| 1462 | 1510 | ||
| 1463 | out: | 1511 | out: |
| 1464 | spin_unlock_irqrestore(&intf->events_lock, flags); | 1512 | spin_unlock_irqrestore(&intf->events_lock, flags); |
| 1513 | release_ipmi_user(user, index); | ||
| 1465 | 1514 | ||
| 1466 | return 0; | 1515 | return 0; |
| 1467 | } | 1516 | } |
| @@ -1504,8 +1553,11 @@ int ipmi_register_for_cmd(struct ipmi_user *user, | |||
| 1504 | { | 1553 | { |
| 1505 | struct ipmi_smi *intf = user->intf; | 1554 | struct ipmi_smi *intf = user->intf; |
| 1506 | struct cmd_rcvr *rcvr; | 1555 | struct cmd_rcvr *rcvr; |
| 1507 | int rv = 0; | 1556 | int rv = 0, index; |
| 1508 | 1557 | ||
| 1558 | user = acquire_ipmi_user(user, &index); | ||
| 1559 | if (!user) | ||
| 1560 | return -ENODEV; | ||
| 1509 | 1561 | ||
| 1510 | rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL); | 1562 | rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL); |
| 1511 | if (!rcvr) | 1563 | if (!rcvr) |
| @@ -1531,6 +1583,7 @@ int ipmi_register_for_cmd(struct ipmi_user *user, | |||
| 1531 | mutex_unlock(&intf->cmd_rcvrs_mutex); | 1583 | mutex_unlock(&intf->cmd_rcvrs_mutex); |
| 1532 | if (rv) | 1584 | if (rv) |
| 1533 | kfree(rcvr); | 1585 | kfree(rcvr); |
| 1586 | release_ipmi_user(user, index); | ||
| 1534 | 1587 | ||
| 1535 | return rv; | 1588 | return rv; |
| 1536 | } | 1589 | } |
| @@ -1544,7 +1597,11 @@ int ipmi_unregister_for_cmd(struct ipmi_user *user, | |||
| 1544 | struct ipmi_smi *intf = user->intf; | 1597 | struct ipmi_smi *intf = user->intf; |
| 1545 | struct cmd_rcvr *rcvr; | 1598 | struct cmd_rcvr *rcvr; |
| 1546 | struct cmd_rcvr *rcvrs = NULL; | 1599 | struct cmd_rcvr *rcvrs = NULL; |
| 1547 | int i, rv = -ENOENT; | 1600 | int i, rv = -ENOENT, index; |
| 1601 | |||
| 1602 | user = acquire_ipmi_user(user, &index); | ||
| 1603 | if (!user) | ||
| 1604 | return -ENODEV; | ||
| 1548 | 1605 | ||
| 1549 | mutex_lock(&intf->cmd_rcvrs_mutex); | 1606 | mutex_lock(&intf->cmd_rcvrs_mutex); |
| 1550 | for (i = 0; i < IPMI_NUM_CHANNELS; i++) { | 1607 | for (i = 0; i < IPMI_NUM_CHANNELS; i++) { |
| @@ -1565,12 +1622,14 @@ int ipmi_unregister_for_cmd(struct ipmi_user *user, | |||
| 1565 | } | 1622 | } |
| 1566 | mutex_unlock(&intf->cmd_rcvrs_mutex); | 1623 | mutex_unlock(&intf->cmd_rcvrs_mutex); |
| 1567 | synchronize_rcu(); | 1624 | synchronize_rcu(); |
| 1625 | release_ipmi_user(user, index); | ||
| 1568 | while (rcvrs) { | 1626 | while (rcvrs) { |
| 1569 | atomic_dec(&intf->event_waiters); | 1627 | atomic_dec(&intf->event_waiters); |
| 1570 | rcvr = rcvrs; | 1628 | rcvr = rcvrs; |
| 1571 | rcvrs = rcvr->next; | 1629 | rcvrs = rcvr->next; |
| 1572 | kfree(rcvr); | 1630 | kfree(rcvr); |
| 1573 | } | 1631 | } |
| 1632 | |||
| 1574 | return rv; | 1633 | return rv; |
| 1575 | } | 1634 | } |
| 1576 | EXPORT_SYMBOL(ipmi_unregister_for_cmd); | 1635 | EXPORT_SYMBOL(ipmi_unregister_for_cmd); |
| @@ -2065,8 +2124,10 @@ static int i_ipmi_request(struct ipmi_user *user, | |||
| 2065 | recv_msg = supplied_recv; | 2124 | recv_msg = supplied_recv; |
| 2066 | else { | 2125 | else { |
| 2067 | recv_msg = ipmi_alloc_recv_msg(); | 2126 | recv_msg = ipmi_alloc_recv_msg(); |
| 2068 | if (recv_msg == NULL) | 2127 | if (recv_msg == NULL) { |
| 2069 | return -ENOMEM; | 2128 | rv = -ENOMEM; |
| 2129 | goto out; | ||
| 2130 | } | ||
| 2070 | } | 2131 | } |
| 2071 | recv_msg->user_msg_data = user_msg_data; | 2132 | recv_msg->user_msg_data = user_msg_data; |
| 2072 | 2133 | ||
| @@ -2076,7 +2137,8 @@ static int i_ipmi_request(struct ipmi_user *user, | |||
| 2076 | smi_msg = ipmi_alloc_smi_msg(); | 2137 | smi_msg = ipmi_alloc_smi_msg(); |
| 2077 | if (smi_msg == NULL) { | 2138 | if (smi_msg == NULL) { |
| 2078 | ipmi_free_recv_msg(recv_msg); | 2139 | ipmi_free_recv_msg(recv_msg); |
| 2079 | return -ENOMEM; | 2140 | rv = -ENOMEM; |
| 2141 | goto out; | ||
| 2080 | } | 2142 | } |
| 2081 | } | 2143 | } |
| 2082 | 2144 | ||
| @@ -2088,6 +2150,7 @@ static int i_ipmi_request(struct ipmi_user *user, | |||
| 2088 | 2150 | ||
| 2089 | recv_msg->user = user; | 2151 | recv_msg->user = user; |
| 2090 | if (user) | 2152 | if (user) |
| 2153 | /* The put happens when the message is freed. */ | ||
| 2091 | kref_get(&user->refcount); | 2154 | kref_get(&user->refcount); |
| 2092 | recv_msg->msgid = msgid; | 2155 | recv_msg->msgid = msgid; |
| 2093 | /* | 2156 | /* |
| @@ -2123,6 +2186,7 @@ out_err: | |||
| 2123 | } | 2186 | } |
| 2124 | rcu_read_unlock(); | 2187 | rcu_read_unlock(); |
| 2125 | 2188 | ||
| 2189 | out: | ||
| 2126 | return rv; | 2190 | return rv; |
| 2127 | } | 2191 | } |
| 2128 | 2192 | ||
| @@ -2148,25 +2212,32 @@ int ipmi_request_settime(struct ipmi_user *user, | |||
| 2148 | unsigned int retry_time_ms) | 2212 | unsigned int retry_time_ms) |
| 2149 | { | 2213 | { |
| 2150 | unsigned char saddr = 0, lun = 0; | 2214 | unsigned char saddr = 0, lun = 0; |
| 2151 | int rv; | 2215 | int rv, index; |
| 2152 | 2216 | ||
| 2153 | if (!user) | 2217 | if (!user) |
| 2154 | return -EINVAL; | 2218 | return -EINVAL; |
| 2219 | |||
| 2220 | user = acquire_ipmi_user(user, &index); | ||
| 2221 | if (!user) | ||
| 2222 | return -ENODEV; | ||
| 2223 | |||
| 2155 | rv = check_addr(user->intf, addr, &saddr, &lun); | 2224 | rv = check_addr(user->intf, addr, &saddr, &lun); |
| 2156 | if (rv) | 2225 | if (!rv) |
| 2157 | return rv; | 2226 | rv = i_ipmi_request(user, |
| 2158 | return i_ipmi_request(user, | 2227 | user->intf, |
| 2159 | user->intf, | 2228 | addr, |
| 2160 | addr, | 2229 | msgid, |
| 2161 | msgid, | 2230 | msg, |
| 2162 | msg, | 2231 | user_msg_data, |
| 2163 | user_msg_data, | 2232 | NULL, NULL, |
| 2164 | NULL, NULL, | 2233 | priority, |
| 2165 | priority, | 2234 | saddr, |
| 2166 | saddr, | 2235 | lun, |
| 2167 | lun, | 2236 | retries, |
| 2168 | retries, | 2237 | retry_time_ms); |
| 2169 | retry_time_ms); | 2238 | |
| 2239 | release_ipmi_user(user, index); | ||
| 2240 | return rv; | ||
| 2170 | } | 2241 | } |
| 2171 | EXPORT_SYMBOL(ipmi_request_settime); | 2242 | EXPORT_SYMBOL(ipmi_request_settime); |
| 2172 | 2243 | ||
| @@ -2180,25 +2251,32 @@ int ipmi_request_supply_msgs(struct ipmi_user *user, | |||
| 2180 | int priority) | 2251 | int priority) |
| 2181 | { | 2252 | { |
| 2182 | unsigned char saddr = 0, lun = 0; | 2253 | unsigned char saddr = 0, lun = 0; |
| 2183 | int rv; | 2254 | int rv, index; |
| 2184 | 2255 | ||
| 2185 | if (!user) | 2256 | if (!user) |
| 2186 | return -EINVAL; | 2257 | return -EINVAL; |
| 2258 | |||
| 2259 | user = acquire_ipmi_user(user, &index); | ||
| 2260 | if (!user) | ||
| 2261 | return -ENODEV; | ||
| 2262 | |||
| 2187 | rv = check_addr(user->intf, addr, &saddr, &lun); | 2263 | rv = check_addr(user->intf, addr, &saddr, &lun); |
| 2188 | if (rv) | 2264 | if (!rv) |
| 2189 | return rv; | 2265 | rv = i_ipmi_request(user, |
| 2190 | return i_ipmi_request(user, | 2266 | user->intf, |
| 2191 | user->intf, | 2267 | addr, |
| 2192 | addr, | 2268 | msgid, |
| 2193 | msgid, | 2269 | msg, |
| 2194 | msg, | 2270 | user_msg_data, |
| 2195 | user_msg_data, | 2271 | supplied_smi, |
| 2196 | supplied_smi, | 2272 | supplied_recv, |
| 2197 | supplied_recv, | 2273 | priority, |
| 2198 | priority, | 2274 | saddr, |
| 2199 | saddr, | 2275 | lun, |
| 2200 | lun, | 2276 | -1, 0); |
| 2201 | -1, 0); | 2277 | |
| 2278 | release_ipmi_user(user, index); | ||
| 2279 | return rv; | ||
| 2202 | } | 2280 | } |
| 2203 | EXPORT_SYMBOL(ipmi_request_supply_msgs); | 2281 | EXPORT_SYMBOL(ipmi_request_supply_msgs); |
| 2204 | 2282 | ||
| @@ -3455,6 +3533,13 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, | |||
| 3455 | if (!intf) | 3533 | if (!intf) |
| 3456 | return -ENOMEM; | 3534 | return -ENOMEM; |
| 3457 | 3535 | ||
| 3536 | rv = init_srcu_struct(&intf->users_srcu); | ||
| 3537 | if (rv) { | ||
| 3538 | kfree(intf); | ||
| 3539 | return rv; | ||
| 3540 | } | ||
| 3541 | |||
| 3542 | |||
| 3458 | intf->bmc = &intf->tmp_bmc; | 3543 | intf->bmc = &intf->tmp_bmc; |
| 3459 | INIT_LIST_HEAD(&intf->bmc->intfs); | 3544 | INIT_LIST_HEAD(&intf->bmc->intfs); |
| 3460 | mutex_init(&intf->bmc->dyn_mutex); | 3545 | mutex_init(&intf->bmc->dyn_mutex); |
| @@ -3507,7 +3592,6 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, | |||
| 3507 | intf->proc_dir = NULL; | 3592 | intf->proc_dir = NULL; |
| 3508 | #endif | 3593 | #endif |
| 3509 | 3594 | ||
| 3510 | mutex_lock(&smi_watchers_mutex); | ||
| 3511 | mutex_lock(&ipmi_interfaces_mutex); | 3595 | mutex_lock(&ipmi_interfaces_mutex); |
| 3512 | /* Look for a hole in the numbers. */ | 3596 | /* Look for a hole in the numbers. */ |
| 3513 | i = 0; | 3597 | i = 0; |
| @@ -3552,11 +3636,10 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, | |||
| 3552 | if (intf->proc_dir) | 3636 | if (intf->proc_dir) |
| 3553 | remove_proc_entries(intf); | 3637 | remove_proc_entries(intf); |
| 3554 | #endif | 3638 | #endif |
| 3555 | intf->handlers = NULL; | ||
| 3556 | list_del_rcu(&intf->link); | 3639 | list_del_rcu(&intf->link); |
| 3557 | mutex_unlock(&ipmi_interfaces_mutex); | 3640 | mutex_unlock(&ipmi_interfaces_mutex); |
| 3558 | mutex_unlock(&smi_watchers_mutex); | 3641 | synchronize_srcu(&ipmi_interfaces_srcu); |
| 3559 | synchronize_rcu(); | 3642 | cleanup_srcu_struct(&intf->users_srcu); |
| 3560 | kref_put(&intf->refcount, intf_free); | 3643 | kref_put(&intf->refcount, intf_free); |
| 3561 | } else { | 3644 | } else { |
| 3562 | /* | 3645 | /* |
| @@ -3567,9 +3650,9 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, | |||
| 3567 | smp_wmb(); | 3650 | smp_wmb(); |
| 3568 | intf->intf_num = i; | 3651 | intf->intf_num = i; |
| 3569 | mutex_unlock(&ipmi_interfaces_mutex); | 3652 | mutex_unlock(&ipmi_interfaces_mutex); |
| 3653 | |||
| 3570 | /* After this point the interface is legal to use. */ | 3654 | /* After this point the interface is legal to use. */ |
| 3571 | call_smi_watchers(i, intf->si_dev); | 3655 | call_smi_watchers(i, intf->si_dev); |
| 3572 | mutex_unlock(&smi_watchers_mutex); | ||
| 3573 | } | 3656 | } |
| 3574 | 3657 | ||
| 3575 | return rv; | 3658 | return rv; |
| @@ -3631,45 +3714,49 @@ static void cleanup_smi_msgs(struct ipmi_smi *intf) | |||
| 3631 | int ipmi_unregister_smi(struct ipmi_smi *intf) | 3714 | int ipmi_unregister_smi(struct ipmi_smi *intf) |
| 3632 | { | 3715 | { |
| 3633 | struct ipmi_smi_watcher *w; | 3716 | struct ipmi_smi_watcher *w; |
| 3634 | int intf_num = intf->intf_num; | 3717 | int intf_num = intf->intf_num, index; |
| 3635 | struct ipmi_user *user; | ||
| 3636 | 3718 | ||
| 3637 | mutex_lock(&smi_watchers_mutex); | ||
| 3638 | mutex_lock(&ipmi_interfaces_mutex); | 3719 | mutex_lock(&ipmi_interfaces_mutex); |
| 3639 | intf->intf_num = -1; | 3720 | intf->intf_num = -1; |
| 3640 | intf->in_shutdown = true; | 3721 | intf->in_shutdown = true; |
| 3641 | list_del_rcu(&intf->link); | 3722 | list_del_rcu(&intf->link); |
| 3642 | mutex_unlock(&ipmi_interfaces_mutex); | 3723 | mutex_unlock(&ipmi_interfaces_mutex); |
| 3643 | synchronize_rcu(); | 3724 | synchronize_srcu(&ipmi_interfaces_srcu); |
| 3644 | |||
| 3645 | cleanup_smi_msgs(intf); | ||
| 3646 | |||
| 3647 | /* Clean up the effects of users on the lower-level software. */ | ||
| 3648 | mutex_lock(&ipmi_interfaces_mutex); | ||
| 3649 | rcu_read_lock(); | ||
| 3650 | list_for_each_entry_rcu(user, &intf->users, link) { | ||
| 3651 | module_put(intf->handlers->owner); | ||
| 3652 | if (intf->handlers->dec_usecount) | ||
| 3653 | intf->handlers->dec_usecount(intf->send_info); | ||
| 3654 | } | ||
| 3655 | rcu_read_unlock(); | ||
| 3656 | intf->handlers = NULL; | ||
| 3657 | mutex_unlock(&ipmi_interfaces_mutex); | ||
| 3658 | 3725 | ||
| 3659 | #ifdef CONFIG_IPMI_PROC_INTERFACE | 3726 | /* At this point no users can be added to the interface. */ |
| 3660 | remove_proc_entries(intf); | ||
| 3661 | #endif | ||
| 3662 | ipmi_bmc_unregister(intf); | ||
| 3663 | 3727 | ||
| 3664 | /* | 3728 | /* |
| 3665 | * Call all the watcher interfaces to tell them that | 3729 | * Call all the watcher interfaces to tell them that |
| 3666 | * an interface is gone. | 3730 | * an interface is going away. |
| 3667 | */ | 3731 | */ |
| 3732 | mutex_lock(&smi_watchers_mutex); | ||
| 3668 | list_for_each_entry(w, &smi_watchers, link) | 3733 | list_for_each_entry(w, &smi_watchers, link) |
| 3669 | w->smi_gone(intf_num); | 3734 | w->smi_gone(intf_num); |
| 3670 | mutex_unlock(&smi_watchers_mutex); | 3735 | mutex_unlock(&smi_watchers_mutex); |
| 3671 | 3736 | ||
| 3737 | index = srcu_read_lock(&intf->users_srcu); | ||
| 3738 | while (!list_empty(&intf->users)) { | ||
| 3739 | struct ipmi_user *user = | ||
| 3740 | container_of(list_next_rcu(&intf->users), | ||
| 3741 | struct ipmi_user, link); | ||
| 3742 | |||
| 3743 | _ipmi_destroy_user(user); | ||
| 3744 | } | ||
| 3745 | srcu_read_unlock(&intf->users_srcu, index); | ||
| 3746 | |||
| 3747 | if (intf->handlers->shutdown) | ||
| 3748 | intf->handlers->shutdown(intf->send_info); | ||
| 3749 | |||
| 3750 | cleanup_smi_msgs(intf); | ||
| 3751 | |||
| 3752 | #ifdef CONFIG_IPMI_PROC_INTERFACE | ||
| 3753 | remove_proc_entries(intf); | ||
| 3754 | #endif | ||
| 3755 | ipmi_bmc_unregister(intf); | ||
| 3756 | |||
| 3757 | cleanup_srcu_struct(&intf->users_srcu); | ||
| 3672 | kref_put(&intf->refcount, intf_free); | 3758 | kref_put(&intf->refcount, intf_free); |
| 3759 | |||
| 3673 | return 0; | 3760 | return 0; |
| 3674 | } | 3761 | } |
| 3675 | EXPORT_SYMBOL(ipmi_unregister_smi); | 3762 | EXPORT_SYMBOL(ipmi_unregister_smi); |
| @@ -4141,8 +4228,7 @@ static int handle_read_event_rsp(struct ipmi_smi *intf, | |||
| 4141 | struct ipmi_recv_msg *recv_msg, *recv_msg2; | 4228 | struct ipmi_recv_msg *recv_msg, *recv_msg2; |
| 4142 | struct list_head msgs; | 4229 | struct list_head msgs; |
| 4143 | struct ipmi_user *user; | 4230 | struct ipmi_user *user; |
| 4144 | int rv = 0; | 4231 | int rv = 0, deliver_count = 0, index; |
| 4145 | int deliver_count = 0; | ||
| 4146 | unsigned long flags; | 4232 | unsigned long flags; |
| 4147 | 4233 | ||
| 4148 | if (msg->rsp_size < 19) { | 4234 | if (msg->rsp_size < 19) { |
| @@ -4166,7 +4252,7 @@ static int handle_read_event_rsp(struct ipmi_smi *intf, | |||
| 4166 | * Allocate and fill in one message for every user that is | 4252 | * Allocate and fill in one message for every user that is |
| 4167 | * getting events. | 4253 | * getting events. |
| 4168 | */ | 4254 | */ |
| 4169 | rcu_read_lock(); | 4255 | index = srcu_read_lock(&intf->users_srcu); |
| 4170 | list_for_each_entry_rcu(user, &intf->users, link) { | 4256 | list_for_each_entry_rcu(user, &intf->users, link) { |
| 4171 | if (!user->gets_events) | 4257 | if (!user->gets_events) |
| 4172 | continue; | 4258 | continue; |
| @@ -4195,7 +4281,7 @@ static int handle_read_event_rsp(struct ipmi_smi *intf, | |||
| 4195 | kref_get(&user->refcount); | 4281 | kref_get(&user->refcount); |
| 4196 | list_add_tail(&recv_msg->link, &msgs); | 4282 | list_add_tail(&recv_msg->link, &msgs); |
| 4197 | } | 4283 | } |
| 4198 | rcu_read_unlock(); | 4284 | srcu_read_unlock(&intf->users_srcu, index); |
| 4199 | 4285 | ||
| 4200 | if (deliver_count) { | 4286 | if (deliver_count) { |
| 4201 | /* Now deliver all the messages. */ | 4287 | /* Now deliver all the messages. */ |
| @@ -4242,7 +4328,7 @@ static int handle_bmc_rsp(struct ipmi_smi *intf, | |||
| 4242 | struct ipmi_smi_msg *msg) | 4328 | struct ipmi_smi_msg *msg) |
| 4243 | { | 4329 | { |
| 4244 | struct ipmi_recv_msg *recv_msg; | 4330 | struct ipmi_recv_msg *recv_msg; |
| 4245 | struct ipmi_user *user; | 4331 | struct ipmi_system_interface_addr *smi_addr; |
| 4246 | 4332 | ||
| 4247 | recv_msg = (struct ipmi_recv_msg *) msg->user_data; | 4333 | recv_msg = (struct ipmi_recv_msg *) msg->user_data; |
| 4248 | if (recv_msg == NULL) { | 4334 | if (recv_msg == NULL) { |
| @@ -4251,30 +4337,19 @@ static int handle_bmc_rsp(struct ipmi_smi *intf, | |||
| 4251 | return 0; | 4337 | return 0; |
| 4252 | } | 4338 | } |
| 4253 | 4339 | ||
| 4254 | user = recv_msg->user; | 4340 | recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; |
| 4255 | /* Make sure the user still exists. */ | 4341 | recv_msg->msgid = msg->msgid; |
| 4256 | if (user && !user->valid) { | 4342 | smi_addr = ((struct ipmi_system_interface_addr *) |
| 4257 | /* The user for the message went away, so give up. */ | 4343 | &recv_msg->addr); |
| 4258 | ipmi_inc_stat(intf, unhandled_local_responses); | 4344 | smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; |
| 4259 | ipmi_free_recv_msg(recv_msg); | 4345 | smi_addr->channel = IPMI_BMC_CHANNEL; |
| 4260 | } else { | 4346 | smi_addr->lun = msg->rsp[0] & 3; |
| 4261 | struct ipmi_system_interface_addr *smi_addr; | 4347 | recv_msg->msg.netfn = msg->rsp[0] >> 2; |
| 4262 | 4348 | recv_msg->msg.cmd = msg->rsp[1]; | |
| 4263 | ipmi_inc_stat(intf, handled_local_responses); | 4349 | memcpy(recv_msg->msg_data, &msg->rsp[2], msg->rsp_size - 2); |
| 4264 | recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; | 4350 | recv_msg->msg.data = recv_msg->msg_data; |
| 4265 | recv_msg->msgid = msg->msgid; | 4351 | recv_msg->msg.data_len = msg->rsp_size - 2; |
| 4266 | smi_addr = ((struct ipmi_system_interface_addr *) | 4352 | deliver_local_response(intf, recv_msg); |
| 4267 | &recv_msg->addr); | ||
| 4268 | smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; | ||
| 4269 | smi_addr->channel = IPMI_BMC_CHANNEL; | ||
| 4270 | smi_addr->lun = msg->rsp[0] & 3; | ||
| 4271 | recv_msg->msg.netfn = msg->rsp[0] >> 2; | ||
| 4272 | recv_msg->msg.cmd = msg->rsp[1]; | ||
| 4273 | memcpy(recv_msg->msg_data, &msg->rsp[2], msg->rsp_size - 2); | ||
| 4274 | recv_msg->msg.data = recv_msg->msg_data; | ||
| 4275 | recv_msg->msg.data_len = msg->rsp_size - 2; | ||
| 4276 | deliver_local_response(intf, recv_msg); | ||
| 4277 | } | ||
| 4278 | 4353 | ||
| 4279 | return 0; | 4354 | return 0; |
| 4280 | } | 4355 | } |
| @@ -4327,7 +4402,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf, | |||
| 4327 | * It's a response to a response we sent. For this we | 4402 | * It's a response to a response we sent. For this we |
| 4328 | * deliver a send message response to the user. | 4403 | * deliver a send message response to the user. |
| 4329 | */ | 4404 | */ |
| 4330 | struct ipmi_recv_msg *recv_msg = msg->user_data; | 4405 | struct ipmi_recv_msg *recv_msg = msg->user_data; |
| 4331 | 4406 | ||
| 4332 | requeue = 0; | 4407 | requeue = 0; |
| 4333 | if (msg->rsp_size < 2) | 4408 | if (msg->rsp_size < 2) |
| @@ -4342,10 +4417,6 @@ static int handle_one_recv_msg(struct ipmi_smi *intf, | |||
| 4342 | if (!recv_msg) | 4417 | if (!recv_msg) |
| 4343 | goto out; | 4418 | goto out; |
| 4344 | 4419 | ||
| 4345 | /* Make sure the user still exists. */ | ||
| 4346 | if (!recv_msg->user || !recv_msg->user->valid) | ||
| 4347 | goto out; | ||
| 4348 | |||
| 4349 | recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE; | 4420 | recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE; |
| 4350 | recv_msg->msg.data = recv_msg->msg_data; | 4421 | recv_msg->msg.data = recv_msg->msg_data; |
| 4351 | recv_msg->msg.data_len = 1; | 4422 | recv_msg->msg.data_len = 1; |
| @@ -4488,14 +4559,15 @@ static void handle_new_recv_msgs(struct ipmi_smi *intf) | |||
| 4488 | */ | 4559 | */ |
| 4489 | if (atomic_add_unless(&intf->watchdog_pretimeouts_to_deliver, -1, 0)) { | 4560 | if (atomic_add_unless(&intf->watchdog_pretimeouts_to_deliver, -1, 0)) { |
| 4490 | struct ipmi_user *user; | 4561 | struct ipmi_user *user; |
| 4562 | int index; | ||
| 4491 | 4563 | ||
| 4492 | rcu_read_lock(); | 4564 | index = srcu_read_lock(&intf->users_srcu); |
| 4493 | list_for_each_entry_rcu(user, &intf->users, link) { | 4565 | list_for_each_entry_rcu(user, &intf->users, link) { |
| 4494 | if (user->handler->ipmi_watchdog_pretimeout) | 4566 | if (user->handler->ipmi_watchdog_pretimeout) |
| 4495 | user->handler->ipmi_watchdog_pretimeout( | 4567 | user->handler->ipmi_watchdog_pretimeout( |
| 4496 | user->handler_data); | 4568 | user->handler_data); |
| 4497 | } | 4569 | } |
| 4498 | rcu_read_unlock(); | 4570 | srcu_read_unlock(&intf->users_srcu, index); |
| 4499 | } | 4571 | } |
| 4500 | } | 4572 | } |
| 4501 | 4573 | ||
| @@ -4662,8 +4734,7 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent, | |||
| 4662 | int slot, unsigned long *flags, | 4734 | int slot, unsigned long *flags, |
| 4663 | unsigned int *waiting_msgs) | 4735 | unsigned int *waiting_msgs) |
| 4664 | { | 4736 | { |
| 4665 | struct ipmi_recv_msg *msg; | 4737 | struct ipmi_recv_msg *msg; |
| 4666 | const struct ipmi_smi_handlers *handlers; | ||
| 4667 | 4738 | ||
| 4668 | if (intf->in_shutdown) | 4739 | if (intf->in_shutdown) |
| 4669 | return; | 4740 | return; |
| @@ -4721,8 +4792,7 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent, | |||
| 4721 | * only for messages to the local MC, which don't get | 4792 | * only for messages to the local MC, which don't get |
| 4722 | * resent. | 4793 | * resent. |
| 4723 | */ | 4794 | */ |
| 4724 | handlers = intf->handlers; | 4795 | if (intf->handlers) { |
| 4725 | if (handlers) { | ||
| 4726 | if (is_lan_addr(&ent->recv_msg->addr)) | 4796 | if (is_lan_addr(&ent->recv_msg->addr)) |
| 4727 | ipmi_inc_stat(intf, | 4797 | ipmi_inc_stat(intf, |
| 4728 | retransmitted_lan_commands); | 4798 | retransmitted_lan_commands); |
| @@ -4730,7 +4800,7 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent, | |||
| 4730 | ipmi_inc_stat(intf, | 4800 | ipmi_inc_stat(intf, |
| 4731 | retransmitted_ipmb_commands); | 4801 | retransmitted_ipmb_commands); |
| 4732 | 4802 | ||
| 4733 | smi_send(intf, handlers, smi_msg, 0); | 4803 | smi_send(intf, intf->handlers, smi_msg, 0); |
| 4734 | } else | 4804 | } else |
| 4735 | ipmi_free_smi_msg(smi_msg); | 4805 | ipmi_free_smi_msg(smi_msg); |
| 4736 | 4806 | ||
| @@ -4822,12 +4892,12 @@ static atomic_t stop_operation; | |||
| 4822 | static void ipmi_timeout(struct timer_list *unused) | 4892 | static void ipmi_timeout(struct timer_list *unused) |
| 4823 | { | 4893 | { |
| 4824 | struct ipmi_smi *intf; | 4894 | struct ipmi_smi *intf; |
| 4825 | int nt = 0; | 4895 | int nt = 0, index; |
| 4826 | 4896 | ||
| 4827 | if (atomic_read(&stop_operation)) | 4897 | if (atomic_read(&stop_operation)) |
| 4828 | return; | 4898 | return; |
| 4829 | 4899 | ||
| 4830 | rcu_read_lock(); | 4900 | index = srcu_read_lock(&ipmi_interfaces_srcu); |
| 4831 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { | 4901 | list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { |
| 4832 | int lnt = 0; | 4902 | int lnt = 0; |
| 4833 | 4903 | ||
| @@ -4850,7 +4920,7 @@ static void ipmi_timeout(struct timer_list *unused) | |||
| 4850 | 4920 | ||
| 4851 | nt += lnt; | 4921 | nt += lnt; |
| 4852 | } | 4922 | } |
| 4853 | rcu_read_unlock(); | 4923 | srcu_read_unlock(&ipmi_interfaces_srcu, index); |
| 4854 | 4924 | ||
| 4855 | if (nt) | 4925 | if (nt) |
| 4856 | mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); | 4926 | mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); |
