Home Home > GIT Browse > SLE15-SP1
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2019-05-17 16:59:18 +0200
committerTakashi Iwai <tiwai@suse.de>2019-05-17 16:59:34 +0200
commitb2c0efc8a9a9b5e8568ab70699867dd37ad335fc (patch)
treea3c1dfa1183a45186dff10b71d1c4fd8d6667ba4
parent8c33ab8f4cea28607f0c9e4aad7f42a1d68f4e2f (diff)
ipmi: fix sleep-in-atomic in free_user at cleanup SRCU
user->release_barrier (bsc#1111666). suse-commit: 758c8551d6c19d6103af759151f2f63635131534
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index fb16514980d9..021c6d6baed7 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -215,6 +215,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)
@@ -1088,6 +1091,14 @@ static int intf_err_seq(struct ipmi_smi *intf,
return rv;
}
+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,
@@ -1141,6 +1152,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;
@@ -1203,8 +1216,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)