|
|
@@ -213,6 +213,9 @@ struct ipmi_user {
|
|
|
|
|
|
/* Does this interface receive IPMI events? */
|
|
|
bool gets_events;
|
|
|
+
|
|
|
+ /* Free must run in process context for RCU cleanup. */
|
|
|
+ struct work_struct remove_work;
|
|
|
};
|
|
|
|
|
|
static struct ipmi_user *acquire_ipmi_user(struct ipmi_user *user, int *index)
|
|
|
@@ -1078,6 +1081,15 @@ static int intf_err_seq(struct ipmi_smi *intf,
|
|
|
}
|
|
|
|
|
|
|
|
|
+static void free_user_work(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct ipmi_user *user = container_of(work, struct ipmi_user,
|
|
|
+ remove_work);
|
|
|
+
|
|
|
+ cleanup_srcu_struct(&user->release_barrier);
|
|
|
+ kfree(user);
|
|
|
+}
|
|
|
+
|
|
|
int ipmi_create_user(unsigned int if_num,
|
|
|
const struct ipmi_user_hndl *handler,
|
|
|
void *handler_data,
|
|
|
@@ -1121,6 +1133,8 @@ int ipmi_create_user(unsigned int if_num,
|
|
|
goto out_kfree;
|
|
|
|
|
|
found:
|
|
|
+ INIT_WORK(&new_user->remove_work, free_user_work);
|
|
|
+
|
|
|
rv = init_srcu_struct(&new_user->release_barrier);
|
|
|
if (rv)
|
|
|
goto out_kfree;
|
|
|
@@ -1183,8 +1197,9 @@ EXPORT_SYMBOL(ipmi_get_smi_info);
|
|
|
static void free_user(struct kref *ref)
|
|
|
{
|
|
|
struct ipmi_user *user = container_of(ref, struct ipmi_user, refcount);
|
|
|
- cleanup_srcu_struct(&user->release_barrier);
|
|
|
- kfree(user);
|
|
|
+
|
|
|
+ /* SRCU cleanup must happen in task context. */
|
|
|
+ schedule_work(&user->remove_work);
|
|
|
}
|
|
|
|
|
|
static void _ipmi_destroy_user(struct ipmi_user *user)
|