Commit 913a89f0 authored by Corey Minyard's avatar Corey Minyard

ipmi: Don't initialize anything in the core until something uses it

The IPMI driver was recently modified to use SRCU, but it turns out
this uses a chunk of percpu memory, even if IPMI is never used.

So modify thing to on initialize on the first use.  There was already
code to sort of handle this for handling init races, so piggy back
on top of that, and simplify it in the process.
Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
Reported-by: default avatarTejun Heo <tj@kernel.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: stable@vger.kernel.org # 4.18
parent 77f82696
...@@ -63,7 +63,8 @@ static void ipmi_debug_msg(const char *title, unsigned char *data, ...@@ -63,7 +63,8 @@ static void ipmi_debug_msg(const char *title, unsigned char *data,
{ } { }
#endif #endif
static int initialized; static bool initialized;
static bool drvregistered;
enum ipmi_panic_event_op { enum ipmi_panic_event_op {
IPMI_SEND_PANIC_EVENT_NONE, IPMI_SEND_PANIC_EVENT_NONE,
...@@ -613,7 +614,7 @@ static DEFINE_MUTEX(ipmidriver_mutex); ...@@ -613,7 +614,7 @@ static DEFINE_MUTEX(ipmidriver_mutex);
static LIST_HEAD(ipmi_interfaces); static LIST_HEAD(ipmi_interfaces);
static DEFINE_MUTEX(ipmi_interfaces_mutex); static DEFINE_MUTEX(ipmi_interfaces_mutex);
DEFINE_STATIC_SRCU(ipmi_interfaces_srcu); struct srcu_struct ipmi_interfaces_srcu;
/* /*
* List of watchers that want to know when smi's are added and deleted. * List of watchers that want to know when smi's are added and deleted.
...@@ -721,7 +722,15 @@ struct watcher_entry { ...@@ -721,7 +722,15 @@ struct watcher_entry {
int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
{ {
struct ipmi_smi *intf; struct ipmi_smi *intf;
int index; int index, rv;
/*
* Make sure the driver is actually initialized, this handles
* problems with initialization order.
*/
rv = ipmi_init_msghandler();
if (rv)
return rv;
mutex_lock(&smi_watchers_mutex); mutex_lock(&smi_watchers_mutex);
...@@ -1077,7 +1086,7 @@ int ipmi_create_user(unsigned int if_num, ...@@ -1077,7 +1086,7 @@ int ipmi_create_user(unsigned int if_num,
{ {
unsigned long flags; unsigned long flags;
struct ipmi_user *new_user; struct ipmi_user *new_user;
int rv = 0, index; int rv, index;
struct ipmi_smi *intf; struct ipmi_smi *intf;
/* /*
...@@ -1095,19 +1104,10 @@ int ipmi_create_user(unsigned int if_num, ...@@ -1095,19 +1104,10 @@ int ipmi_create_user(unsigned int if_num,
* Make sure the driver is actually initialized, this handles * Make sure the driver is actually initialized, this handles
* problems with initialization order. * problems with initialization order.
*/ */
if (!initialized) {
rv = ipmi_init_msghandler(); rv = ipmi_init_msghandler();
if (rv) if (rv)
return rv; return rv;
/*
* The init code doesn't return an error if it was turned
* off, but it won't initialize. Check that.
*/
if (!initialized)
return -ENODEV;
}
new_user = kmalloc(sizeof(*new_user), GFP_KERNEL); new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
if (!new_user) if (!new_user)
return -ENOMEM; return -ENOMEM;
...@@ -3301,17 +3301,9 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, ...@@ -3301,17 +3301,9 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
* Make sure the driver is actually initialized, this handles * Make sure the driver is actually initialized, this handles
* problems with initialization order. * problems with initialization order.
*/ */
if (!initialized) {
rv = ipmi_init_msghandler(); rv = ipmi_init_msghandler();
if (rv) if (rv)
return rv; return rv;
/*
* The init code doesn't return an error if it was turned
* off, but it won't initialize. Check that.
*/
if (!initialized)
return -ENODEV;
}
intf = kzalloc(sizeof(*intf), GFP_KERNEL); intf = kzalloc(sizeof(*intf), GFP_KERNEL);
if (!intf) if (!intf)
...@@ -5027,6 +5019,22 @@ static int panic_event(struct notifier_block *this, ...@@ -5027,6 +5019,22 @@ static int panic_event(struct notifier_block *this,
return NOTIFY_DONE; return NOTIFY_DONE;
} }
/* Must be called with ipmi_interfaces_mutex held. */
static int ipmi_register_driver(void)
{
int rv;
if (drvregistered)
return 0;
rv = driver_register(&ipmidriver.driver);
if (rv)
pr_err("Could not register IPMI driver\n");
else
drvregistered = true;
return rv;
}
static struct notifier_block panic_block = { static struct notifier_block panic_block = {
.notifier_call = panic_event, .notifier_call = panic_event,
.next = NULL, .next = NULL,
...@@ -5037,41 +5045,47 @@ static int ipmi_init_msghandler(void) ...@@ -5037,41 +5045,47 @@ static int ipmi_init_msghandler(void)
{ {
int rv; int rv;
mutex_lock(&ipmi_interfaces_mutex);
rv = ipmi_register_driver();
if (rv)
goto out;
if (initialized) if (initialized)
return 0; goto out;
rv = driver_register(&ipmidriver.driver);
if (rv) {
pr_err("Could not register IPMI driver\n");
return rv;
}
pr_info("version " IPMI_DRIVER_VERSION "\n"); init_srcu_struct(&ipmi_interfaces_srcu);
timer_setup(&ipmi_timer, ipmi_timeout, 0); timer_setup(&ipmi_timer, ipmi_timeout, 0);
mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
atomic_notifier_chain_register(&panic_notifier_list, &panic_block); atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
initialized = 1; initialized = true;
return 0; out:
mutex_unlock(&ipmi_interfaces_mutex);
return rv;
} }
static int __init ipmi_init_msghandler_mod(void) static int __init ipmi_init_msghandler_mod(void)
{ {
ipmi_init_msghandler(); int rv;
return 0;
pr_info("version " IPMI_DRIVER_VERSION "\n");
mutex_lock(&ipmi_interfaces_mutex);
rv = ipmi_register_driver();
mutex_unlock(&ipmi_interfaces_mutex);
return rv;
} }
static void __exit cleanup_ipmi(void) static void __exit cleanup_ipmi(void)
{ {
int count; int count;
if (!initialized) if (initialized) {
return; atomic_notifier_chain_unregister(&panic_notifier_list,
&panic_block);
atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
/* /*
* This can't be called if any interfaces exist, so no worry * This can't be called if any interfaces exist, so no worry
...@@ -5086,9 +5100,7 @@ static void __exit cleanup_ipmi(void) ...@@ -5086,9 +5100,7 @@ static void __exit cleanup_ipmi(void)
atomic_inc(&stop_operation); atomic_inc(&stop_operation);
del_timer_sync(&ipmi_timer); del_timer_sync(&ipmi_timer);
driver_unregister(&ipmidriver.driver); initialized = false;
initialized = 0;
/* Check for buffer leaks. */ /* Check for buffer leaks. */
count = atomic_read(&smi_msg_inuse_count); count = atomic_read(&smi_msg_inuse_count);
...@@ -5097,6 +5109,11 @@ static void __exit cleanup_ipmi(void) ...@@ -5097,6 +5109,11 @@ static void __exit cleanup_ipmi(void)
count = atomic_read(&recv_msg_inuse_count); count = atomic_read(&recv_msg_inuse_count);
if (count != 0) if (count != 0)
pr_warn("recv message count %d at exit\n", count); pr_warn("recv message count %d at exit\n", count);
cleanup_srcu_struct(&ipmi_interfaces_srcu);
}
if (drvregistered)
driver_unregister(&ipmidriver.driver);
} }
module_exit(cleanup_ipmi); module_exit(cleanup_ipmi);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment