ipmi: Rework locking and shutdown for hot remove

To handle hot remove of interfaces, a lot of rework had to be
done to the locking.  Several things were switched over to srcu
and shutdown for users and interfaces was added for cleaner
shutdown.

Signed-off-by: Corey Minyard <cminyard@mvista.com>
This commit is contained in:
Corey Minyard 2018-04-05 22:05:04 -05:00
parent ac93bd0c9e
commit e86ee2d44b

View File

@ -197,8 +197,12 @@ MODULE_PARM_DESC(default_max_retries,
struct ipmi_user {
struct list_head link;
/* Set to false when the user is destroyed. */
bool valid;
/*
* Set to NULL when the user is destroyed, a pointer to myself
* so srcu_dereference can be used on it.
*/
struct ipmi_user *self;
struct srcu_struct release_barrier;
struct kref refcount;
@ -213,6 +217,23 @@ struct ipmi_user {
bool gets_events;
};
static struct ipmi_user *acquire_ipmi_user(struct ipmi_user *user, int *index)
__acquires(user->release_barrier)
{
struct ipmi_user *ruser;
*index = srcu_read_lock(&user->release_barrier);
ruser = srcu_dereference(user->self, &user->release_barrier);
if (!ruser)
srcu_read_unlock(&user->release_barrier, *index);
return ruser;
}
static void release_ipmi_user(struct ipmi_user *user, int index)
{
srcu_read_unlock(&user->release_barrier, index);
}
struct cmd_rcvr {
struct list_head link;
@ -444,10 +465,11 @@ struct ipmi_smi {
struct list_head link;
/*
* The list of upper layers that are using me. seq_lock
* protects this.
* The list of upper layers that are using me. seq_lock write
* protects this. Read protection is with srcu.
*/
struct list_head users;
struct srcu_struct users_srcu;
/* Used for wake ups at startup. */
wait_queue_head_t waitq;
@ -467,12 +489,6 @@ struct ipmi_smi {
bool in_bmc_register; /* Handle recursive situations. Yuck. */
struct work_struct bmc_reg_work;
/*
* This is the lower-layer's sender routine. Note that you
* must either be holding the ipmi_interfaces_mutex or be in
* an umpreemptible region to use this. You must fetch the
* value into a local variable and make sure it is not NULL.
*/
const struct ipmi_smi_handlers *handlers;
void *send_info;
@ -615,6 +631,7 @@ static DEFINE_MUTEX(ipmidriver_mutex);
static LIST_HEAD(ipmi_interfaces);
static DEFINE_MUTEX(ipmi_interfaces_mutex);
DEFINE_STATIC_SRCU(ipmi_interfaces_srcu);
/*
* List of watchers that want to know when smi's are added and deleted.
@ -715,58 +732,32 @@ static void intf_free(struct kref *ref)
struct watcher_entry {
int intf_num;
struct ipmi_smi *intf;
struct ipmi_smi *intf;
struct list_head link;
};
int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
{
struct ipmi_smi *intf;
LIST_HEAD(to_deliver);
struct watcher_entry *e, *e2;
int index;
mutex_lock(&smi_watchers_mutex);
mutex_lock(&ipmi_interfaces_mutex);
/* Build a list of things to deliver. */
list_for_each_entry(intf, &ipmi_interfaces, link) {
if (intf->intf_num == -1)
continue;
e = kmalloc(sizeof(*e), GFP_KERNEL);
if (!e)
goto out_err;
kref_get(&intf->refcount);
e->intf = intf;
e->intf_num = intf->intf_num;
list_add_tail(&e->link, &to_deliver);
}
/* We will succeed, so add it to the list. */
list_add(&watcher->link, &smi_watchers);
mutex_unlock(&ipmi_interfaces_mutex);
index = srcu_read_lock(&ipmi_interfaces_srcu);
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
int intf_num = READ_ONCE(intf->intf_num);
list_for_each_entry_safe(e, e2, &to_deliver, link) {
list_del(&e->link);
watcher->new_smi(e->intf_num, e->intf->si_dev);
kref_put(&e->intf->refcount, intf_free);
kfree(e);
if (intf_num == -1)
continue;
watcher->new_smi(intf_num, intf->si_dev);
}
srcu_read_unlock(&ipmi_interfaces_srcu, index);
mutex_unlock(&smi_watchers_mutex);
return 0;
out_err:
mutex_unlock(&ipmi_interfaces_mutex);
mutex_unlock(&smi_watchers_mutex);
list_for_each_entry_safe(e, e2, &to_deliver, link) {
list_del(&e->link);
kref_put(&e->intf->refcount, intf_free);
kfree(e);
}
return -ENOMEM;
}
EXPORT_SYMBOL(ipmi_smi_watcher_register);
@ -787,12 +778,14 @@ call_smi_watchers(int i, struct device *dev)
{
struct ipmi_smi_watcher *w;
mutex_lock(&smi_watchers_mutex);
list_for_each_entry(w, &smi_watchers, link) {
if (try_module_get(w->owner)) {
w->new_smi(i, dev);
module_put(w->owner);
}
}
mutex_unlock(&smi_watchers_mutex);
}
static int
@ -905,9 +898,17 @@ static int deliver_response(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
* receive handler doesn't much meaning and has a deadlock
* risk. At this moment, simply skip it in that case.
*/
int index;
struct ipmi_user *user = acquire_ipmi_user(msg->user, &index);
struct ipmi_user *user = msg->user;
user->handler->ipmi_recv_hndl(msg, user->handler_data);
if (user) {
user->handler->ipmi_recv_hndl(msg, user->handler_data);
release_ipmi_user(msg->user, index);
} else {
/* User went away, give up. */
ipmi_free_recv_msg(msg);
rv = -EINVAL;
}
}
return rv;
@ -1094,7 +1095,7 @@ int ipmi_create_user(unsigned int if_num,
{
unsigned long flags;
struct ipmi_user *new_user;
int rv = 0;
int rv = 0, index;
struct ipmi_smi *intf;
/*
@ -1129,7 +1130,7 @@ int ipmi_create_user(unsigned int if_num,
if (!new_user)
return -ENOMEM;
mutex_lock(&ipmi_interfaces_mutex);
index = srcu_read_lock(&ipmi_interfaces_srcu);
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
if (intf->intf_num == if_num)
goto found;
@ -1139,6 +1140,10 @@ int ipmi_create_user(unsigned int if_num,
goto out_kfree;
found:
rv = init_srcu_struct(&new_user->release_barrier);
if (rv)
goto out_kfree;
/* Note that each existing user holds a refcount to the interface. */
kref_get(&intf->refcount);
@ -1148,26 +1153,7 @@ int ipmi_create_user(unsigned int if_num,
new_user->intf = intf;
new_user->gets_events = false;
if (!try_module_get(intf->handlers->owner)) {
rv = -ENODEV;
goto out_kref;
}
if (intf->handlers->inc_usecount) {
rv = intf->handlers->inc_usecount(intf->send_info);
if (rv) {
module_put(intf->handlers->owner);
goto out_kref;
}
}
/*
* Hold the lock so intf->handlers is guaranteed to be good
* until now
*/
mutex_unlock(&ipmi_interfaces_mutex);
new_user->valid = true;
rcu_assign_pointer(new_user->self, new_user);
spin_lock_irqsave(&intf->seq_lock, flags);
list_add_rcu(&new_user->link, &intf->users);
spin_unlock_irqrestore(&intf->seq_lock, flags);
@ -1176,13 +1162,12 @@ int ipmi_create_user(unsigned int if_num,
if (atomic_inc_return(&intf->event_waiters) == 1)
need_waiter(intf);
}
srcu_read_unlock(&ipmi_interfaces_srcu, index);
*user = new_user;
return 0;
out_kref:
kref_put(&intf->refcount, intf_free);
out_kfree:
mutex_unlock(&ipmi_interfaces_mutex);
srcu_read_unlock(&ipmi_interfaces_srcu, index);
kfree(new_user);
return rv;
}
@ -1190,26 +1175,25 @@ EXPORT_SYMBOL(ipmi_create_user);
int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data)
{
int rv = 0;
int rv, index;
struct ipmi_smi *intf;
const struct ipmi_smi_handlers *handlers;
mutex_lock(&ipmi_interfaces_mutex);
index = srcu_read_lock(&ipmi_interfaces_srcu);
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
if (intf->intf_num == if_num)
goto found;
}
srcu_read_unlock(&ipmi_interfaces_srcu, index);
/* Not found, return an error */
rv = -EINVAL;
mutex_unlock(&ipmi_interfaces_mutex);
return rv;
return -EINVAL;
found:
handlers = intf->handlers;
rv = -ENOSYS;
if (handlers->get_smi_info)
rv = handlers->get_smi_info(intf->send_info, data);
mutex_unlock(&ipmi_interfaces_mutex);
if (!intf->handlers->get_smi_info)
rv = -ENOTTY;
else
rv = intf->handlers->get_smi_info(intf->send_info, data);
srcu_read_unlock(&ipmi_interfaces_srcu, index);
return rv;
}
@ -1221,7 +1205,7 @@ static void free_user(struct kref *ref)
kfree(user);
}
int ipmi_destroy_user(struct ipmi_user *user)
static void _ipmi_destroy_user(struct ipmi_user *user)
{
struct ipmi_smi *intf = user->intf;
int i;
@ -1229,7 +1213,22 @@ int ipmi_destroy_user(struct ipmi_user *user)
struct cmd_rcvr *rcvr;
struct cmd_rcvr *rcvrs = NULL;
user->valid = false;
if (!acquire_ipmi_user(user, &i)) {
/*
* The user has already been cleaned up, just make sure
* nothing is using it and return.
*/
synchronize_srcu(&user->release_barrier);
return;
}
rcu_assign_pointer(user->self, NULL);
release_ipmi_user(user, i);
synchronize_srcu(&user->release_barrier);
if (user->handler->shutdown)
user->handler->shutdown(user->handler_data);
if (user->handler->ipmi_watchdog_pretimeout)
atomic_dec(&intf->event_waiters);
@ -1254,7 +1253,7 @@ int ipmi_destroy_user(struct ipmi_user *user)
* Remove the user from the command receiver's table. First
* we build a list of everything (not using the standard link,
* since other things may be using it till we do
* synchronize_rcu()) then free everything in that list.
* synchronize_srcu()) then free everything in that list.
*/
mutex_lock(&intf->cmd_rcvrs_mutex);
list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
@ -1272,16 +1271,14 @@ int ipmi_destroy_user(struct ipmi_user *user)
kfree(rcvr);
}
mutex_lock(&ipmi_interfaces_mutex);
if (intf->handlers) {
module_put(intf->handlers->owner);
if (intf->handlers->dec_usecount)
intf->handlers->dec_usecount(intf->send_info);
}
mutex_unlock(&ipmi_interfaces_mutex);
kref_put(&intf->refcount, intf_free);
}
int ipmi_destroy_user(struct ipmi_user *user)
{
_ipmi_destroy_user(user);
cleanup_srcu_struct(&user->release_barrier);
kref_put(&user->refcount, free_user);
return 0;
@ -1293,16 +1290,20 @@ int ipmi_get_version(struct ipmi_user *user,
unsigned char *minor)
{
struct ipmi_device_id id;
int rv;
int rv, index;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
rv = bmc_get_device_id(user->intf, NULL, &id, NULL, NULL);
if (rv)
return rv;
if (!rv) {
*major = ipmi_version_major(&id);
*minor = ipmi_version_minor(&id);
}
release_ipmi_user(user, index);
*major = ipmi_version_major(&id);
*minor = ipmi_version_minor(&id);
return 0;
return rv;
}
EXPORT_SYMBOL(ipmi_get_version);
@ -1310,9 +1311,17 @@ int ipmi_set_my_address(struct ipmi_user *user,
unsigned int channel,
unsigned char address)
{
int index;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
if (channel >= IPMI_MAX_CHANNELS)
return -EINVAL;
user->intf->addrinfo[channel].address = address;
release_ipmi_user(user, index);
return 0;
}
EXPORT_SYMBOL(ipmi_set_my_address);
@ -1321,9 +1330,17 @@ int ipmi_get_my_address(struct ipmi_user *user,
unsigned int channel,
unsigned char *address)
{
int index;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
if (channel >= IPMI_MAX_CHANNELS)
return -EINVAL;
*address = user->intf->addrinfo[channel].address;
release_ipmi_user(user, index);
return 0;
}
EXPORT_SYMBOL(ipmi_get_my_address);
@ -1332,9 +1349,17 @@ int ipmi_set_my_LUN(struct ipmi_user *user,
unsigned int channel,
unsigned char LUN)
{
int index;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
if (channel >= IPMI_MAX_CHANNELS)
return -EINVAL;
user->intf->addrinfo[channel].lun = LUN & 0x3;
release_ipmi_user(user, index);
return 0;
}
EXPORT_SYMBOL(ipmi_set_my_LUN);
@ -1343,21 +1368,34 @@ int ipmi_get_my_LUN(struct ipmi_user *user,
unsigned int channel,
unsigned char *address)
{
int index;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
if (channel >= IPMI_MAX_CHANNELS)
return -EINVAL;
*address = user->intf->addrinfo[channel].lun;
release_ipmi_user(user, index);
return 0;
}
EXPORT_SYMBOL(ipmi_get_my_LUN);
int ipmi_get_maintenance_mode(struct ipmi_user *user)
{
int mode;
int mode, index;
unsigned long flags;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);
mode = user->intf->maintenance_mode;
spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);
release_ipmi_user(user, index);
return mode;
}
@ -1372,10 +1410,14 @@ static void maintenance_mode_update(struct ipmi_smi *intf)
int ipmi_set_maintenance_mode(struct ipmi_user *user, int mode)
{
int rv = 0;
int rv = 0, index;
unsigned long flags;
struct ipmi_smi *intf = user->intf;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
if (intf->maintenance_mode != mode) {
switch (mode) {
@ -1402,6 +1444,7 @@ int ipmi_set_maintenance_mode(struct ipmi_user *user, int mode)
}
out_unlock:
spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);
release_ipmi_user(user, index);
return rv;
}
@ -1413,6 +1456,11 @@ int ipmi_set_gets_events(struct ipmi_user *user, bool val)
struct ipmi_smi *intf = user->intf;
struct ipmi_recv_msg *msg, *msg2;
struct list_head msgs;
int index;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
INIT_LIST_HEAD(&msgs);
@ -1462,6 +1510,7 @@ int ipmi_set_gets_events(struct ipmi_user *user, bool val)
out:
spin_unlock_irqrestore(&intf->events_lock, flags);
release_ipmi_user(user, index);
return 0;
}
@ -1504,8 +1553,11 @@ int ipmi_register_for_cmd(struct ipmi_user *user,
{
struct ipmi_smi *intf = user->intf;
struct cmd_rcvr *rcvr;
int rv = 0;
int rv = 0, index;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
if (!rcvr)
@ -1531,6 +1583,7 @@ int ipmi_register_for_cmd(struct ipmi_user *user,
mutex_unlock(&intf->cmd_rcvrs_mutex);
if (rv)
kfree(rcvr);
release_ipmi_user(user, index);
return rv;
}
@ -1544,7 +1597,11 @@ int ipmi_unregister_for_cmd(struct ipmi_user *user,
struct ipmi_smi *intf = user->intf;
struct cmd_rcvr *rcvr;
struct cmd_rcvr *rcvrs = NULL;
int i, rv = -ENOENT;
int i, rv = -ENOENT, index;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
mutex_lock(&intf->cmd_rcvrs_mutex);
for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
@ -1565,12 +1622,14 @@ int ipmi_unregister_for_cmd(struct ipmi_user *user,
}
mutex_unlock(&intf->cmd_rcvrs_mutex);
synchronize_rcu();
release_ipmi_user(user, index);
while (rcvrs) {
atomic_dec(&intf->event_waiters);
rcvr = rcvrs;
rcvrs = rcvr->next;
kfree(rcvr);
}
return rv;
}
EXPORT_SYMBOL(ipmi_unregister_for_cmd);
@ -2065,8 +2124,10 @@ static int i_ipmi_request(struct ipmi_user *user,
recv_msg = supplied_recv;
else {
recv_msg = ipmi_alloc_recv_msg();
if (recv_msg == NULL)
return -ENOMEM;
if (recv_msg == NULL) {
rv = -ENOMEM;
goto out;
}
}
recv_msg->user_msg_data = user_msg_data;
@ -2076,7 +2137,8 @@ static int i_ipmi_request(struct ipmi_user *user,
smi_msg = ipmi_alloc_smi_msg();
if (smi_msg == NULL) {
ipmi_free_recv_msg(recv_msg);
return -ENOMEM;
rv = -ENOMEM;
goto out;
}
}
@ -2088,6 +2150,7 @@ static int i_ipmi_request(struct ipmi_user *user,
recv_msg->user = user;
if (user)
/* The put happens when the message is freed. */
kref_get(&user->refcount);
recv_msg->msgid = msgid;
/*
@ -2123,6 +2186,7 @@ out_err:
}
rcu_read_unlock();
out:
return rv;
}
@ -2148,25 +2212,32 @@ int ipmi_request_settime(struct ipmi_user *user,
unsigned int retry_time_ms)
{
unsigned char saddr = 0, lun = 0;
int rv;
int rv, index;
if (!user)
return -EINVAL;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
rv = check_addr(user->intf, addr, &saddr, &lun);
if (rv)
return rv;
return i_ipmi_request(user,
user->intf,
addr,
msgid,
msg,
user_msg_data,
NULL, NULL,
priority,
saddr,
lun,
retries,
retry_time_ms);
if (!rv)
rv = i_ipmi_request(user,
user->intf,
addr,
msgid,
msg,
user_msg_data,
NULL, NULL,
priority,
saddr,
lun,
retries,
retry_time_ms);
release_ipmi_user(user, index);
return rv;
}
EXPORT_SYMBOL(ipmi_request_settime);
@ -2180,25 +2251,32 @@ int ipmi_request_supply_msgs(struct ipmi_user *user,
int priority)
{
unsigned char saddr = 0, lun = 0;
int rv;
int rv, index;
if (!user)
return -EINVAL;
user = acquire_ipmi_user(user, &index);
if (!user)
return -ENODEV;
rv = check_addr(user->intf, addr, &saddr, &lun);
if (rv)
return rv;
return i_ipmi_request(user,
user->intf,
addr,
msgid,
msg,
user_msg_data,
supplied_smi,
supplied_recv,
priority,
saddr,
lun,
-1, 0);
if (!rv)
rv = i_ipmi_request(user,
user->intf,
addr,
msgid,
msg,
user_msg_data,
supplied_smi,
supplied_recv,
priority,
saddr,
lun,
-1, 0);
release_ipmi_user(user, index);
return rv;
}
EXPORT_SYMBOL(ipmi_request_supply_msgs);
@ -3455,6 +3533,13 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
if (!intf)
return -ENOMEM;
rv = init_srcu_struct(&intf->users_srcu);
if (rv) {
kfree(intf);
return rv;
}
intf->bmc = &intf->tmp_bmc;
INIT_LIST_HEAD(&intf->bmc->intfs);
mutex_init(&intf->bmc->dyn_mutex);
@ -3507,7 +3592,6 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
intf->proc_dir = NULL;
#endif
mutex_lock(&smi_watchers_mutex);
mutex_lock(&ipmi_interfaces_mutex);
/* Look for a hole in the numbers. */
i = 0;
@ -3552,11 +3636,10 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
if (intf->proc_dir)
remove_proc_entries(intf);
#endif
intf->handlers = NULL;
list_del_rcu(&intf->link);
mutex_unlock(&ipmi_interfaces_mutex);
mutex_unlock(&smi_watchers_mutex);
synchronize_rcu();
synchronize_srcu(&ipmi_interfaces_srcu);
cleanup_srcu_struct(&intf->users_srcu);
kref_put(&intf->refcount, intf_free);
} else {
/*
@ -3567,9 +3650,9 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
smp_wmb();
intf->intf_num = i;
mutex_unlock(&ipmi_interfaces_mutex);
/* After this point the interface is legal to use. */
call_smi_watchers(i, intf->si_dev);
mutex_unlock(&smi_watchers_mutex);
}
return rv;
@ -3631,45 +3714,49 @@ static void cleanup_smi_msgs(struct ipmi_smi *intf)
int ipmi_unregister_smi(struct ipmi_smi *intf)
{
struct ipmi_smi_watcher *w;
int intf_num = intf->intf_num;
struct ipmi_user *user;
int intf_num = intf->intf_num, index;
mutex_lock(&smi_watchers_mutex);
mutex_lock(&ipmi_interfaces_mutex);
intf->intf_num = -1;
intf->in_shutdown = true;
list_del_rcu(&intf->link);
mutex_unlock(&ipmi_interfaces_mutex);
synchronize_rcu();
synchronize_srcu(&ipmi_interfaces_srcu);
/* At this point no users can be added to the interface. */
/*
* Call all the watcher interfaces to tell them that
* an interface is going away.
*/
mutex_lock(&smi_watchers_mutex);
list_for_each_entry(w, &smi_watchers, link)
w->smi_gone(intf_num);
mutex_unlock(&smi_watchers_mutex);
index = srcu_read_lock(&intf->users_srcu);
while (!list_empty(&intf->users)) {
struct ipmi_user *user =
container_of(list_next_rcu(&intf->users),
struct ipmi_user, link);
_ipmi_destroy_user(user);
}
srcu_read_unlock(&intf->users_srcu, index);
if (intf->handlers->shutdown)
intf->handlers->shutdown(intf->send_info);
cleanup_smi_msgs(intf);
/* Clean up the effects of users on the lower-level software. */
mutex_lock(&ipmi_interfaces_mutex);
rcu_read_lock();
list_for_each_entry_rcu(user, &intf->users, link) {
module_put(intf->handlers->owner);
if (intf->handlers->dec_usecount)
intf->handlers->dec_usecount(intf->send_info);
}
rcu_read_unlock();
intf->handlers = NULL;
mutex_unlock(&ipmi_interfaces_mutex);
#ifdef CONFIG_IPMI_PROC_INTERFACE
remove_proc_entries(intf);
#endif
ipmi_bmc_unregister(intf);
/*
* Call all the watcher interfaces to tell them that
* an interface is gone.
*/
list_for_each_entry(w, &smi_watchers, link)
w->smi_gone(intf_num);
mutex_unlock(&smi_watchers_mutex);
cleanup_srcu_struct(&intf->users_srcu);
kref_put(&intf->refcount, intf_free);
return 0;
}
EXPORT_SYMBOL(ipmi_unregister_smi);
@ -4141,8 +4228,7 @@ static int handle_read_event_rsp(struct ipmi_smi *intf,
struct ipmi_recv_msg *recv_msg, *recv_msg2;
struct list_head msgs;
struct ipmi_user *user;
int rv = 0;
int deliver_count = 0;
int rv = 0, deliver_count = 0, index;
unsigned long flags;
if (msg->rsp_size < 19) {
@ -4166,7 +4252,7 @@ static int handle_read_event_rsp(struct ipmi_smi *intf,
* Allocate and fill in one message for every user that is
* getting events.
*/
rcu_read_lock();
index = srcu_read_lock(&intf->users_srcu);
list_for_each_entry_rcu(user, &intf->users, link) {
if (!user->gets_events)
continue;
@ -4195,7 +4281,7 @@ static int handle_read_event_rsp(struct ipmi_smi *intf,
kref_get(&user->refcount);
list_add_tail(&recv_msg->link, &msgs);
}
rcu_read_unlock();
srcu_read_unlock(&intf->users_srcu, index);
if (deliver_count) {
/* Now deliver all the messages. */
@ -4242,7 +4328,7 @@ static int handle_bmc_rsp(struct ipmi_smi *intf,
struct ipmi_smi_msg *msg)
{
struct ipmi_recv_msg *recv_msg;
struct ipmi_user *user;
struct ipmi_system_interface_addr *smi_addr;
recv_msg = (struct ipmi_recv_msg *) msg->user_data;
if (recv_msg == NULL) {
@ -4251,30 +4337,19 @@ static int handle_bmc_rsp(struct ipmi_smi *intf,
return 0;
}
user = recv_msg->user;
/* Make sure the user still exists. */
if (user && !user->valid) {
/* The user for the message went away, so give up. */
ipmi_inc_stat(intf, unhandled_local_responses);
ipmi_free_recv_msg(recv_msg);
} else {
struct ipmi_system_interface_addr *smi_addr;
ipmi_inc_stat(intf, handled_local_responses);
recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
recv_msg->msgid = msg->msgid;
smi_addr = ((struct ipmi_system_interface_addr *)
&recv_msg->addr);
smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
smi_addr->channel = IPMI_BMC_CHANNEL;
smi_addr->lun = msg->rsp[0] & 3;
recv_msg->msg.netfn = msg->rsp[0] >> 2;
recv_msg->msg.cmd = msg->rsp[1];
memcpy(recv_msg->msg_data, &msg->rsp[2], msg->rsp_size - 2);
recv_msg->msg.data = recv_msg->msg_data;
recv_msg->msg.data_len = msg->rsp_size - 2;
deliver_local_response(intf, recv_msg);
}
recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
recv_msg->msgid = msg->msgid;
smi_addr = ((struct ipmi_system_interface_addr *)
&recv_msg->addr);
smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
smi_addr->channel = IPMI_BMC_CHANNEL;
smi_addr->lun = msg->rsp[0] & 3;
recv_msg->msg.netfn = msg->rsp[0] >> 2;
recv_msg->msg.cmd = msg->rsp[1];
memcpy(recv_msg->msg_data, &msg->rsp[2], msg->rsp_size - 2);
recv_msg->msg.data = recv_msg->msg_data;
recv_msg->msg.data_len = msg->rsp_size - 2;
deliver_local_response(intf, recv_msg);
return 0;
}
@ -4327,7 +4402,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
* It's a response to a response we sent. For this we
* deliver a send message response to the user.
*/
struct ipmi_recv_msg *recv_msg = msg->user_data;
struct ipmi_recv_msg *recv_msg = msg->user_data;
requeue = 0;
if (msg->rsp_size < 2)
@ -4342,10 +4417,6 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
if (!recv_msg)
goto out;
/* Make sure the user still exists. */
if (!recv_msg->user || !recv_msg->user->valid)
goto out;
recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
recv_msg->msg.data = recv_msg->msg_data;
recv_msg->msg.data_len = 1;
@ -4488,14 +4559,15 @@ static void handle_new_recv_msgs(struct ipmi_smi *intf)
*/
if (atomic_add_unless(&intf->watchdog_pretimeouts_to_deliver, -1, 0)) {
struct ipmi_user *user;
int index;
rcu_read_lock();
index = srcu_read_lock(&intf->users_srcu);
list_for_each_entry_rcu(user, &intf->users, link) {
if (user->handler->ipmi_watchdog_pretimeout)
user->handler->ipmi_watchdog_pretimeout(
user->handler_data);
}
rcu_read_unlock();
srcu_read_unlock(&intf->users_srcu, index);
}
}
@ -4662,8 +4734,7 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
int slot, unsigned long *flags,
unsigned int *waiting_msgs)
{
struct ipmi_recv_msg *msg;
const struct ipmi_smi_handlers *handlers;
struct ipmi_recv_msg *msg;
if (intf->in_shutdown)
return;
@ -4721,8 +4792,7 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
* only for messages to the local MC, which don't get
* resent.
*/
handlers = intf->handlers;
if (handlers) {
if (intf->handlers) {
if (is_lan_addr(&ent->recv_msg->addr))
ipmi_inc_stat(intf,
retransmitted_lan_commands);
@ -4730,7 +4800,7 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
ipmi_inc_stat(intf,
retransmitted_ipmb_commands);
smi_send(intf, handlers, smi_msg, 0);
smi_send(intf, intf->handlers, smi_msg, 0);
} else
ipmi_free_smi_msg(smi_msg);
@ -4822,12 +4892,12 @@ static atomic_t stop_operation;
static void ipmi_timeout(struct timer_list *unused)
{
struct ipmi_smi *intf;
int nt = 0;
int nt = 0, index;
if (atomic_read(&stop_operation))
return;
rcu_read_lock();
index = srcu_read_lock(&ipmi_interfaces_srcu);
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
int lnt = 0;
@ -4850,7 +4920,7 @@ static void ipmi_timeout(struct timer_list *unused)
nt += lnt;
}
rcu_read_unlock();
srcu_read_unlock(&ipmi_interfaces_srcu, index);
if (nt)
mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);