diff options
| -rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index e8ba67834746..00bf4b17edbf 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
| @@ -214,6 +214,9 @@ struct ipmi_user { | |||
| 214 | 214 | ||
| 215 | /* Does this interface receive IPMI events? */ | 215 | /* Does this interface receive IPMI events? */ |
| 216 | bool gets_events; | 216 | bool gets_events; |
| 217 | |||
| 218 | /* Free must run in process context for RCU cleanup. */ | ||
| 219 | struct work_struct remove_work; | ||
| 217 | }; | 220 | }; |
| 218 | 221 | ||
| 219 | static struct ipmi_user *acquire_ipmi_user(struct ipmi_user *user, int *index) | 222 | static struct ipmi_user *acquire_ipmi_user(struct ipmi_user *user, int *index) |
| @@ -1157,6 +1160,15 @@ static int intf_err_seq(struct ipmi_smi *intf, | |||
| 1157 | return rv; | 1160 | return rv; |
| 1158 | } | 1161 | } |
| 1159 | 1162 | ||
| 1163 | static void free_user_work(struct work_struct *work) | ||
| 1164 | { | ||
| 1165 | struct ipmi_user *user = container_of(work, struct ipmi_user, | ||
| 1166 | remove_work); | ||
| 1167 | |||
| 1168 | cleanup_srcu_struct(&user->release_barrier); | ||
| 1169 | kfree(user); | ||
| 1170 | } | ||
| 1171 | |||
| 1160 | int ipmi_create_user(unsigned int if_num, | 1172 | int ipmi_create_user(unsigned int if_num, |
| 1161 | const struct ipmi_user_hndl *handler, | 1173 | const struct ipmi_user_hndl *handler, |
| 1162 | void *handler_data, | 1174 | void *handler_data, |
| @@ -1200,6 +1212,8 @@ int ipmi_create_user(unsigned int if_num, | |||
| 1200 | goto out_kfree; | 1212 | goto out_kfree; |
| 1201 | 1213 | ||
| 1202 | found: | 1214 | found: |
| 1215 | INIT_WORK(&new_user->remove_work, free_user_work); | ||
| 1216 | |||
| 1203 | rv = init_srcu_struct(&new_user->release_barrier); | 1217 | rv = init_srcu_struct(&new_user->release_barrier); |
| 1204 | if (rv) | 1218 | if (rv) |
| 1205 | goto out_kfree; | 1219 | goto out_kfree; |
| @@ -1260,8 +1274,9 @@ EXPORT_SYMBOL(ipmi_get_smi_info); | |||
| 1260 | static void free_user(struct kref *ref) | 1274 | static void free_user(struct kref *ref) |
| 1261 | { | 1275 | { |
| 1262 | struct ipmi_user *user = container_of(ref, struct ipmi_user, refcount); | 1276 | struct ipmi_user *user = container_of(ref, struct ipmi_user, refcount); |
| 1263 | cleanup_srcu_struct(&user->release_barrier); | 1277 | |
| 1264 | kfree(user); | 1278 | /* SRCU cleanup must happen in task context. */ |
| 1279 | schedule_work(&user->remove_work); | ||
| 1265 | } | 1280 | } |
| 1266 | 1281 | ||
| 1267 | static void _ipmi_destroy_user(struct ipmi_user *user) | 1282 | static void _ipmi_destroy_user(struct ipmi_user *user) |
