aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c19
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
219static struct ipmi_user *acquire_ipmi_user(struct ipmi_user *user, int *index) 222static 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
1163static 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
1160int ipmi_create_user(unsigned int if_num, 1172int 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);
1260static void free_user(struct kref *ref) 1274static 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
1267static void _ipmi_destroy_user(struct ipmi_user *user) 1282static void _ipmi_destroy_user(struct ipmi_user *user)