提交 2512e40e 编写于 作者: C Corey Minyard

ipmi: Rework SMI registration failure

There were certain situations where ipmi_register_smi() would
return a failure, but the interface would still be registered
and would need to be unregistered.  This is obviously a bad
design and resulted in an oops in certain failure cases.

If the interface is started up in ipmi_register_smi(), then
an error occurs, shut down the interface there so the
cleanup can be done properly.

Fix the various smi users, too.
Signed-off-by: NCorey Minyard <cminyard@mvista.com>
Reported-by: NJustin Ernst <justin.ernst@hpe.com>
Tested-by: NJustin Ernst <justin.ernst@hpe.com>
Cc: Andrew Banman <abanman@hpe.com>
Cc: Russ Anderson <russ.anderson@hpe.com>
Cc: <stable@vger.kernel.org> # 4.18.x
上级 cd2315d4
...@@ -3381,39 +3381,45 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, ...@@ -3381,39 +3381,45 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
rv = handlers->start_processing(send_info, intf); rv = handlers->start_processing(send_info, intf);
if (rv) if (rv)
goto out; goto out_err;
rv = __bmc_get_device_id(intf, NULL, &id, NULL, NULL, i); rv = __bmc_get_device_id(intf, NULL, &id, NULL, NULL, i);
if (rv) { if (rv) {
dev_err(si_dev, "Unable to get the device id: %d\n", rv); dev_err(si_dev, "Unable to get the device id: %d\n", rv);
goto out; goto out_err_started;
} }
mutex_lock(&intf->bmc_reg_mutex); mutex_lock(&intf->bmc_reg_mutex);
rv = __scan_channels(intf, &id); rv = __scan_channels(intf, &id);
mutex_unlock(&intf->bmc_reg_mutex); mutex_unlock(&intf->bmc_reg_mutex);
if (rv)
goto out_err_bmc_reg;
out: /*
if (rv) { * Keep memory order straight for RCU readers. Make
ipmi_bmc_unregister(intf); * sure everything else is committed to memory before
list_del_rcu(&intf->link); * setting intf_num to mark the interface valid.
mutex_unlock(&ipmi_interfaces_mutex); */
synchronize_srcu(&ipmi_interfaces_srcu); smp_wmb();
cleanup_srcu_struct(&intf->users_srcu); intf->intf_num = i;
kref_put(&intf->refcount, intf_free); mutex_unlock(&ipmi_interfaces_mutex);
} else {
/*
* Keep memory order straight for RCU readers. Make
* sure everything else is committed to memory before
* setting intf_num to mark the interface valid.
*/
smp_wmb();
intf->intf_num = i;
mutex_unlock(&ipmi_interfaces_mutex);
/* After this point the interface is legal to use. */ /* After this point the interface is legal to use. */
call_smi_watchers(i, intf->si_dev); call_smi_watchers(i, intf->si_dev);
}
return 0;
out_err_bmc_reg:
ipmi_bmc_unregister(intf);
out_err_started:
if (intf->handlers->shutdown)
intf->handlers->shutdown(intf->send_info);
out_err:
list_del_rcu(&intf->link);
mutex_unlock(&ipmi_interfaces_mutex);
synchronize_srcu(&ipmi_interfaces_srcu);
cleanup_srcu_struct(&intf->users_srcu);
kref_put(&intf->refcount, intf_free);
return rv; return rv;
} }
...@@ -3504,7 +3510,8 @@ void ipmi_unregister_smi(struct ipmi_smi *intf) ...@@ -3504,7 +3510,8 @@ void ipmi_unregister_smi(struct ipmi_smi *intf)
} }
srcu_read_unlock(&intf->users_srcu, index); srcu_read_unlock(&intf->users_srcu, index);
intf->handlers->shutdown(intf->send_info); if (intf->handlers->shutdown)
intf->handlers->shutdown(intf->send_info);
cleanup_smi_msgs(intf); cleanup_smi_msgs(intf);
......
...@@ -2083,18 +2083,9 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -2083,18 +2083,9 @@ static int try_smi_init(struct smi_info *new_smi)
si_to_str[new_smi->io.si_type]); si_to_str[new_smi->io.si_type]);
WARN_ON(new_smi->io.dev->init_name != NULL); WARN_ON(new_smi->io.dev->init_name != NULL);
kfree(init_name);
return 0;
out_err:
if (new_smi->intf) {
ipmi_unregister_smi(new_smi->intf);
new_smi->intf = NULL;
}
out_err:
kfree(init_name); kfree(init_name);
return rv; return rv;
} }
...@@ -2227,6 +2218,8 @@ static void shutdown_smi(void *send_info) ...@@ -2227,6 +2218,8 @@ static void shutdown_smi(void *send_info)
kfree(smi_info->si_sm); kfree(smi_info->si_sm);
smi_info->si_sm = NULL; smi_info->si_sm = NULL;
smi_info->intf = NULL;
} }
/* /*
...@@ -2240,10 +2233,8 @@ static void cleanup_one_si(struct smi_info *smi_info) ...@@ -2240,10 +2233,8 @@ static void cleanup_one_si(struct smi_info *smi_info)
list_del(&smi_info->link); list_del(&smi_info->link);
if (smi_info->intf) { if (smi_info->intf)
ipmi_unregister_smi(smi_info->intf); ipmi_unregister_smi(smi_info->intf);
smi_info->intf = NULL;
}
if (smi_info->pdev) { if (smi_info->pdev) {
if (smi_info->pdev_registered) if (smi_info->pdev_registered)
......
...@@ -1214,18 +1214,11 @@ static void shutdown_ssif(void *send_info) ...@@ -1214,18 +1214,11 @@ static void shutdown_ssif(void *send_info)
complete(&ssif_info->wake_thread); complete(&ssif_info->wake_thread);
kthread_stop(ssif_info->thread); kthread_stop(ssif_info->thread);
} }
/*
* No message can be outstanding now, we have removed the
* upper layer and it permitted us to do so.
*/
kfree(ssif_info);
} }
static int ssif_remove(struct i2c_client *client) static int ssif_remove(struct i2c_client *client)
{ {
struct ssif_info *ssif_info = i2c_get_clientdata(client); struct ssif_info *ssif_info = i2c_get_clientdata(client);
struct ipmi_smi *intf;
struct ssif_addr_info *addr_info; struct ssif_addr_info *addr_info;
if (!ssif_info) if (!ssif_info)
...@@ -1235,9 +1228,7 @@ static int ssif_remove(struct i2c_client *client) ...@@ -1235,9 +1228,7 @@ static int ssif_remove(struct i2c_client *client)
* After this point, we won't deliver anything asychronously * After this point, we won't deliver anything asychronously
* to the message handler. We can unregister ourself. * to the message handler. We can unregister ourself.
*/ */
intf = ssif_info->intf; ipmi_unregister_smi(ssif_info->intf);
ssif_info->intf = NULL;
ipmi_unregister_smi(intf);
list_for_each_entry(addr_info, &ssif_infos, link) { list_for_each_entry(addr_info, &ssif_infos, link) {
if (addr_info->client == client) { if (addr_info->client == client) {
...@@ -1246,6 +1237,8 @@ static int ssif_remove(struct i2c_client *client) ...@@ -1246,6 +1237,8 @@ static int ssif_remove(struct i2c_client *client)
} }
} }
kfree(ssif_info);
return 0; return 0;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册