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:
parent
ac93bd0c9e
commit
e86ee2d44b
|
@ -197,8 +197,12 @@ MODULE_PARM_DESC(default_max_retries,
|
||||||
struct ipmi_user {
|
struct ipmi_user {
|
||||||
struct list_head link;
|
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;
|
struct kref refcount;
|
||||||
|
|
||||||
|
@ -213,6 +217,23 @@ struct ipmi_user {
|
||||||
bool gets_events;
|
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 cmd_rcvr {
|
||||||
struct list_head link;
|
struct list_head link;
|
||||||
|
|
||||||
|
@ -444,10 +465,11 @@ struct ipmi_smi {
|
||||||
struct list_head link;
|
struct list_head link;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The list of upper layers that are using me. seq_lock
|
* The list of upper layers that are using me. seq_lock write
|
||||||
* protects this.
|
* protects this. Read protection is with srcu.
|
||||||
*/
|
*/
|
||||||
struct list_head users;
|
struct list_head users;
|
||||||
|
struct srcu_struct users_srcu;
|
||||||
|
|
||||||
/* Used for wake ups at startup. */
|
/* Used for wake ups at startup. */
|
||||||
wait_queue_head_t waitq;
|
wait_queue_head_t waitq;
|
||||||
|
@ -467,12 +489,6 @@ struct ipmi_smi {
|
||||||
bool in_bmc_register; /* Handle recursive situations. Yuck. */
|
bool in_bmc_register; /* Handle recursive situations. Yuck. */
|
||||||
struct work_struct bmc_reg_work;
|
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;
|
const struct ipmi_smi_handlers *handlers;
|
||||||
void *send_info;
|
void *send_info;
|
||||||
|
|
||||||
|
@ -615,6 +631,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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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.
|
||||||
|
@ -715,58 +732,32 @@ static void intf_free(struct kref *ref)
|
||||||
|
|
||||||
struct watcher_entry {
|
struct watcher_entry {
|
||||||
int intf_num;
|
int intf_num;
|
||||||
struct ipmi_smi *intf;
|
struct ipmi_smi *intf;
|
||||||
struct list_head link;
|
struct list_head link;
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
LIST_HEAD(to_deliver);
|
int index;
|
||||||
struct watcher_entry *e, *e2;
|
|
||||||
|
|
||||||
mutex_lock(&smi_watchers_mutex);
|
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);
|
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) {
|
if (intf_num == -1)
|
||||||
list_del(&e->link);
|
continue;
|
||||||
watcher->new_smi(e->intf_num, e->intf->si_dev);
|
watcher->new_smi(intf_num, intf->si_dev);
|
||||||
kref_put(&e->intf->refcount, intf_free);
|
|
||||||
kfree(e);
|
|
||||||
}
|
}
|
||||||
|
srcu_read_unlock(&ipmi_interfaces_srcu, index);
|
||||||
|
|
||||||
mutex_unlock(&smi_watchers_mutex);
|
mutex_unlock(&smi_watchers_mutex);
|
||||||
|
|
||||||
return 0;
|
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);
|
EXPORT_SYMBOL(ipmi_smi_watcher_register);
|
||||||
|
|
||||||
|
@ -787,12 +778,14 @@ call_smi_watchers(int i, struct device *dev)
|
||||||
{
|
{
|
||||||
struct ipmi_smi_watcher *w;
|
struct ipmi_smi_watcher *w;
|
||||||
|
|
||||||
|
mutex_lock(&smi_watchers_mutex);
|
||||||
list_for_each_entry(w, &smi_watchers, link) {
|
list_for_each_entry(w, &smi_watchers, link) {
|
||||||
if (try_module_get(w->owner)) {
|
if (try_module_get(w->owner)) {
|
||||||
w->new_smi(i, dev);
|
w->new_smi(i, dev);
|
||||||
module_put(w->owner);
|
module_put(w->owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&smi_watchers_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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
|
* receive handler doesn't much meaning and has a deadlock
|
||||||
* risk. At this moment, simply skip it in that case.
|
* 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;
|
if (user) {
|
||||||
user->handler->ipmi_recv_hndl(msg, user->handler_data);
|
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;
|
return rv;
|
||||||
|
@ -1094,7 +1095,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;
|
int rv = 0, index;
|
||||||
struct ipmi_smi *intf;
|
struct ipmi_smi *intf;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1129,7 +1130,7 @@ int ipmi_create_user(unsigned int if_num,
|
||||||
if (!new_user)
|
if (!new_user)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
mutex_lock(&ipmi_interfaces_mutex);
|
index = srcu_read_lock(&ipmi_interfaces_srcu);
|
||||||
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
|
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
|
||||||
if (intf->intf_num == if_num)
|
if (intf->intf_num == if_num)
|
||||||
goto found;
|
goto found;
|
||||||
|
@ -1139,6 +1140,10 @@ int ipmi_create_user(unsigned int if_num,
|
||||||
goto out_kfree;
|
goto out_kfree;
|
||||||
|
|
||||||
found:
|
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. */
|
/* Note that each existing user holds a refcount to the interface. */
|
||||||
kref_get(&intf->refcount);
|
kref_get(&intf->refcount);
|
||||||
|
|
||||||
|
@ -1148,26 +1153,7 @@ int ipmi_create_user(unsigned int if_num,
|
||||||
new_user->intf = intf;
|
new_user->intf = intf;
|
||||||
new_user->gets_events = false;
|
new_user->gets_events = false;
|
||||||
|
|
||||||
if (!try_module_get(intf->handlers->owner)) {
|
rcu_assign_pointer(new_user->self, new_user);
|
||||||
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;
|
|
||||||
spin_lock_irqsave(&intf->seq_lock, flags);
|
spin_lock_irqsave(&intf->seq_lock, flags);
|
||||||
list_add_rcu(&new_user->link, &intf->users);
|
list_add_rcu(&new_user->link, &intf->users);
|
||||||
spin_unlock_irqrestore(&intf->seq_lock, flags);
|
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)
|
if (atomic_inc_return(&intf->event_waiters) == 1)
|
||||||
need_waiter(intf);
|
need_waiter(intf);
|
||||||
}
|
}
|
||||||
|
srcu_read_unlock(&ipmi_interfaces_srcu, index);
|
||||||
*user = new_user;
|
*user = new_user;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_kref:
|
|
||||||
kref_put(&intf->refcount, intf_free);
|
|
||||||
out_kfree:
|
out_kfree:
|
||||||
mutex_unlock(&ipmi_interfaces_mutex);
|
srcu_read_unlock(&ipmi_interfaces_srcu, index);
|
||||||
kfree(new_user);
|
kfree(new_user);
|
||||||
return rv;
|
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 ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data)
|
||||||
{
|
{
|
||||||
int rv = 0;
|
int rv, index;
|
||||||
struct ipmi_smi *intf;
|
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) {
|
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
|
||||||
if (intf->intf_num == if_num)
|
if (intf->intf_num == if_num)
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
|
srcu_read_unlock(&ipmi_interfaces_srcu, index);
|
||||||
|
|
||||||
/* Not found, return an error */
|
/* Not found, return an error */
|
||||||
rv = -EINVAL;
|
return -EINVAL;
|
||||||
mutex_unlock(&ipmi_interfaces_mutex);
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
found:
|
found:
|
||||||
handlers = intf->handlers;
|
if (!intf->handlers->get_smi_info)
|
||||||
rv = -ENOSYS;
|
rv = -ENOTTY;
|
||||||
if (handlers->get_smi_info)
|
else
|
||||||
rv = handlers->get_smi_info(intf->send_info, data);
|
rv = intf->handlers->get_smi_info(intf->send_info, data);
|
||||||
mutex_unlock(&ipmi_interfaces_mutex);
|
srcu_read_unlock(&ipmi_interfaces_srcu, index);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -1221,7 +1205,7 @@ static void free_user(struct kref *ref)
|
||||||
kfree(user);
|
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;
|
struct ipmi_smi *intf = user->intf;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1229,7 +1213,22 @@ int ipmi_destroy_user(struct ipmi_user *user)
|
||||||
struct cmd_rcvr *rcvr;
|
struct cmd_rcvr *rcvr;
|
||||||
struct cmd_rcvr *rcvrs = NULL;
|
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)
|
if (user->handler->ipmi_watchdog_pretimeout)
|
||||||
atomic_dec(&intf->event_waiters);
|
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
|
* Remove the user from the command receiver's table. First
|
||||||
* we build a list of everything (not using the standard link,
|
* we build a list of everything (not using the standard link,
|
||||||
* since other things may be using it till we do
|
* 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);
|
mutex_lock(&intf->cmd_rcvrs_mutex);
|
||||||
list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
|
list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
|
||||||
|
@ -1272,16 +1271,14 @@ int ipmi_destroy_user(struct ipmi_user *user)
|
||||||
kfree(rcvr);
|
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);
|
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);
|
kref_put(&user->refcount, free_user);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1293,16 +1290,20 @@ int ipmi_get_version(struct ipmi_user *user,
|
||||||
unsigned char *minor)
|
unsigned char *minor)
|
||||||
{
|
{
|
||||||
struct ipmi_device_id id;
|
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);
|
rv = bmc_get_device_id(user->intf, NULL, &id, NULL, NULL);
|
||||||
if (rv)
|
if (!rv) {
|
||||||
return rv;
|
*major = ipmi_version_major(&id);
|
||||||
|
*minor = ipmi_version_minor(&id);
|
||||||
|
}
|
||||||
|
release_ipmi_user(user, index);
|
||||||
|
|
||||||
*major = ipmi_version_major(&id);
|
return rv;
|
||||||
*minor = ipmi_version_minor(&id);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipmi_get_version);
|
EXPORT_SYMBOL(ipmi_get_version);
|
||||||
|
|
||||||
|
@ -1310,9 +1311,17 @@ int ipmi_set_my_address(struct ipmi_user *user,
|
||||||
unsigned int channel,
|
unsigned int channel,
|
||||||
unsigned char address)
|
unsigned char address)
|
||||||
{
|
{
|
||||||
|
int index;
|
||||||
|
|
||||||
|
user = acquire_ipmi_user(user, &index);
|
||||||
|
if (!user)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
if (channel >= IPMI_MAX_CHANNELS)
|
if (channel >= IPMI_MAX_CHANNELS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
user->intf->addrinfo[channel].address = address;
|
user->intf->addrinfo[channel].address = address;
|
||||||
|
release_ipmi_user(user, index);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipmi_set_my_address);
|
EXPORT_SYMBOL(ipmi_set_my_address);
|
||||||
|
@ -1321,9 +1330,17 @@ int ipmi_get_my_address(struct ipmi_user *user,
|
||||||
unsigned int channel,
|
unsigned int channel,
|
||||||
unsigned char *address)
|
unsigned char *address)
|
||||||
{
|
{
|
||||||
|
int index;
|
||||||
|
|
||||||
|
user = acquire_ipmi_user(user, &index);
|
||||||
|
if (!user)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
if (channel >= IPMI_MAX_CHANNELS)
|
if (channel >= IPMI_MAX_CHANNELS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
*address = user->intf->addrinfo[channel].address;
|
*address = user->intf->addrinfo[channel].address;
|
||||||
|
release_ipmi_user(user, index);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipmi_get_my_address);
|
EXPORT_SYMBOL(ipmi_get_my_address);
|
||||||
|
@ -1332,9 +1349,17 @@ int ipmi_set_my_LUN(struct ipmi_user *user,
|
||||||
unsigned int channel,
|
unsigned int channel,
|
||||||
unsigned char LUN)
|
unsigned char LUN)
|
||||||
{
|
{
|
||||||
|
int index;
|
||||||
|
|
||||||
|
user = acquire_ipmi_user(user, &index);
|
||||||
|
if (!user)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
if (channel >= IPMI_MAX_CHANNELS)
|
if (channel >= IPMI_MAX_CHANNELS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
user->intf->addrinfo[channel].lun = LUN & 0x3;
|
user->intf->addrinfo[channel].lun = LUN & 0x3;
|
||||||
|
release_ipmi_user(user, index);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipmi_set_my_LUN);
|
EXPORT_SYMBOL(ipmi_set_my_LUN);
|
||||||
|
@ -1343,21 +1368,34 @@ int ipmi_get_my_LUN(struct ipmi_user *user,
|
||||||
unsigned int channel,
|
unsigned int channel,
|
||||||
unsigned char *address)
|
unsigned char *address)
|
||||||
{
|
{
|
||||||
|
int index;
|
||||||
|
|
||||||
|
user = acquire_ipmi_user(user, &index);
|
||||||
|
if (!user)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
if (channel >= IPMI_MAX_CHANNELS)
|
if (channel >= IPMI_MAX_CHANNELS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
*address = user->intf->addrinfo[channel].lun;
|
*address = user->intf->addrinfo[channel].lun;
|
||||||
|
release_ipmi_user(user, index);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipmi_get_my_LUN);
|
EXPORT_SYMBOL(ipmi_get_my_LUN);
|
||||||
|
|
||||||
int ipmi_get_maintenance_mode(struct ipmi_user *user)
|
int ipmi_get_maintenance_mode(struct ipmi_user *user)
|
||||||
{
|
{
|
||||||
int mode;
|
int mode, index;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
user = acquire_ipmi_user(user, &index);
|
||||||
|
if (!user)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);
|
spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);
|
||||||
mode = user->intf->maintenance_mode;
|
mode = user->intf->maintenance_mode;
|
||||||
spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);
|
spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);
|
||||||
|
release_ipmi_user(user, index);
|
||||||
|
|
||||||
return mode;
|
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 ipmi_set_maintenance_mode(struct ipmi_user *user, int mode)
|
||||||
{
|
{
|
||||||
int rv = 0;
|
int rv = 0, index;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct ipmi_smi *intf = user->intf;
|
struct ipmi_smi *intf = user->intf;
|
||||||
|
|
||||||
|
user = acquire_ipmi_user(user, &index);
|
||||||
|
if (!user)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
|
spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
|
||||||
if (intf->maintenance_mode != mode) {
|
if (intf->maintenance_mode != mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
@ -1402,6 +1444,7 @@ int ipmi_set_maintenance_mode(struct ipmi_user *user, int mode)
|
||||||
}
|
}
|
||||||
out_unlock:
|
out_unlock:
|
||||||
spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);
|
spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);
|
||||||
|
release_ipmi_user(user, index);
|
||||||
|
|
||||||
return rv;
|
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_smi *intf = user->intf;
|
||||||
struct ipmi_recv_msg *msg, *msg2;
|
struct ipmi_recv_msg *msg, *msg2;
|
||||||
struct list_head msgs;
|
struct list_head msgs;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
user = acquire_ipmi_user(user, &index);
|
||||||
|
if (!user)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&msgs);
|
INIT_LIST_HEAD(&msgs);
|
||||||
|
|
||||||
|
@ -1462,6 +1510,7 @@ int ipmi_set_gets_events(struct ipmi_user *user, bool val)
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock_irqrestore(&intf->events_lock, flags);
|
spin_unlock_irqrestore(&intf->events_lock, flags);
|
||||||
|
release_ipmi_user(user, index);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1504,8 +1553,11 @@ int ipmi_register_for_cmd(struct ipmi_user *user,
|
||||||
{
|
{
|
||||||
struct ipmi_smi *intf = user->intf;
|
struct ipmi_smi *intf = user->intf;
|
||||||
struct cmd_rcvr *rcvr;
|
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);
|
rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
|
||||||
if (!rcvr)
|
if (!rcvr)
|
||||||
|
@ -1531,6 +1583,7 @@ int ipmi_register_for_cmd(struct ipmi_user *user,
|
||||||
mutex_unlock(&intf->cmd_rcvrs_mutex);
|
mutex_unlock(&intf->cmd_rcvrs_mutex);
|
||||||
if (rv)
|
if (rv)
|
||||||
kfree(rcvr);
|
kfree(rcvr);
|
||||||
|
release_ipmi_user(user, index);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -1544,7 +1597,11 @@ int ipmi_unregister_for_cmd(struct ipmi_user *user,
|
||||||
struct ipmi_smi *intf = user->intf;
|
struct ipmi_smi *intf = user->intf;
|
||||||
struct cmd_rcvr *rcvr;
|
struct cmd_rcvr *rcvr;
|
||||||
struct cmd_rcvr *rcvrs = NULL;
|
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);
|
mutex_lock(&intf->cmd_rcvrs_mutex);
|
||||||
for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
|
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);
|
mutex_unlock(&intf->cmd_rcvrs_mutex);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
|
release_ipmi_user(user, index);
|
||||||
while (rcvrs) {
|
while (rcvrs) {
|
||||||
atomic_dec(&intf->event_waiters);
|
atomic_dec(&intf->event_waiters);
|
||||||
rcvr = rcvrs;
|
rcvr = rcvrs;
|
||||||
rcvrs = rcvr->next;
|
rcvrs = rcvr->next;
|
||||||
kfree(rcvr);
|
kfree(rcvr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipmi_unregister_for_cmd);
|
EXPORT_SYMBOL(ipmi_unregister_for_cmd);
|
||||||
|
@ -2065,8 +2124,10 @@ static int i_ipmi_request(struct ipmi_user *user,
|
||||||
recv_msg = supplied_recv;
|
recv_msg = supplied_recv;
|
||||||
else {
|
else {
|
||||||
recv_msg = ipmi_alloc_recv_msg();
|
recv_msg = ipmi_alloc_recv_msg();
|
||||||
if (recv_msg == NULL)
|
if (recv_msg == NULL) {
|
||||||
return -ENOMEM;
|
rv = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
recv_msg->user_msg_data = user_msg_data;
|
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();
|
smi_msg = ipmi_alloc_smi_msg();
|
||||||
if (smi_msg == NULL) {
|
if (smi_msg == NULL) {
|
||||||
ipmi_free_recv_msg(recv_msg);
|
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;
|
recv_msg->user = user;
|
||||||
if (user)
|
if (user)
|
||||||
|
/* The put happens when the message is freed. */
|
||||||
kref_get(&user->refcount);
|
kref_get(&user->refcount);
|
||||||
recv_msg->msgid = msgid;
|
recv_msg->msgid = msgid;
|
||||||
/*
|
/*
|
||||||
|
@ -2123,6 +2186,7 @@ out_err:
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
out:
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2148,25 +2212,32 @@ int ipmi_request_settime(struct ipmi_user *user,
|
||||||
unsigned int retry_time_ms)
|
unsigned int retry_time_ms)
|
||||||
{
|
{
|
||||||
unsigned char saddr = 0, lun = 0;
|
unsigned char saddr = 0, lun = 0;
|
||||||
int rv;
|
int rv, index;
|
||||||
|
|
||||||
if (!user)
|
if (!user)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
user = acquire_ipmi_user(user, &index);
|
||||||
|
if (!user)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
rv = check_addr(user->intf, addr, &saddr, &lun);
|
rv = check_addr(user->intf, addr, &saddr, &lun);
|
||||||
if (rv)
|
if (!rv)
|
||||||
return rv;
|
rv = i_ipmi_request(user,
|
||||||
return i_ipmi_request(user,
|
user->intf,
|
||||||
user->intf,
|
addr,
|
||||||
addr,
|
msgid,
|
||||||
msgid,
|
msg,
|
||||||
msg,
|
user_msg_data,
|
||||||
user_msg_data,
|
NULL, NULL,
|
||||||
NULL, NULL,
|
priority,
|
||||||
priority,
|
saddr,
|
||||||
saddr,
|
lun,
|
||||||
lun,
|
retries,
|
||||||
retries,
|
retry_time_ms);
|
||||||
retry_time_ms);
|
|
||||||
|
release_ipmi_user(user, index);
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipmi_request_settime);
|
EXPORT_SYMBOL(ipmi_request_settime);
|
||||||
|
|
||||||
|
@ -2180,25 +2251,32 @@ int ipmi_request_supply_msgs(struct ipmi_user *user,
|
||||||
int priority)
|
int priority)
|
||||||
{
|
{
|
||||||
unsigned char saddr = 0, lun = 0;
|
unsigned char saddr = 0, lun = 0;
|
||||||
int rv;
|
int rv, index;
|
||||||
|
|
||||||
if (!user)
|
if (!user)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
user = acquire_ipmi_user(user, &index);
|
||||||
|
if (!user)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
rv = check_addr(user->intf, addr, &saddr, &lun);
|
rv = check_addr(user->intf, addr, &saddr, &lun);
|
||||||
if (rv)
|
if (!rv)
|
||||||
return rv;
|
rv = i_ipmi_request(user,
|
||||||
return i_ipmi_request(user,
|
user->intf,
|
||||||
user->intf,
|
addr,
|
||||||
addr,
|
msgid,
|
||||||
msgid,
|
msg,
|
||||||
msg,
|
user_msg_data,
|
||||||
user_msg_data,
|
supplied_smi,
|
||||||
supplied_smi,
|
supplied_recv,
|
||||||
supplied_recv,
|
priority,
|
||||||
priority,
|
saddr,
|
||||||
saddr,
|
lun,
|
||||||
lun,
|
-1, 0);
|
||||||
-1, 0);
|
|
||||||
|
release_ipmi_user(user, index);
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipmi_request_supply_msgs);
|
EXPORT_SYMBOL(ipmi_request_supply_msgs);
|
||||||
|
|
||||||
|
@ -3455,6 +3533,13 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
|
||||||
if (!intf)
|
if (!intf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
rv = init_srcu_struct(&intf->users_srcu);
|
||||||
|
if (rv) {
|
||||||
|
kfree(intf);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
intf->bmc = &intf->tmp_bmc;
|
intf->bmc = &intf->tmp_bmc;
|
||||||
INIT_LIST_HEAD(&intf->bmc->intfs);
|
INIT_LIST_HEAD(&intf->bmc->intfs);
|
||||||
mutex_init(&intf->bmc->dyn_mutex);
|
mutex_init(&intf->bmc->dyn_mutex);
|
||||||
|
@ -3507,7 +3592,6 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
|
||||||
intf->proc_dir = NULL;
|
intf->proc_dir = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mutex_lock(&smi_watchers_mutex);
|
|
||||||
mutex_lock(&ipmi_interfaces_mutex);
|
mutex_lock(&ipmi_interfaces_mutex);
|
||||||
/* Look for a hole in the numbers. */
|
/* Look for a hole in the numbers. */
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -3552,11 +3636,10 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
|
||||||
if (intf->proc_dir)
|
if (intf->proc_dir)
|
||||||
remove_proc_entries(intf);
|
remove_proc_entries(intf);
|
||||||
#endif
|
#endif
|
||||||
intf->handlers = NULL;
|
|
||||||
list_del_rcu(&intf->link);
|
list_del_rcu(&intf->link);
|
||||||
mutex_unlock(&ipmi_interfaces_mutex);
|
mutex_unlock(&ipmi_interfaces_mutex);
|
||||||
mutex_unlock(&smi_watchers_mutex);
|
synchronize_srcu(&ipmi_interfaces_srcu);
|
||||||
synchronize_rcu();
|
cleanup_srcu_struct(&intf->users_srcu);
|
||||||
kref_put(&intf->refcount, intf_free);
|
kref_put(&intf->refcount, intf_free);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
|
@ -3567,9 +3650,9 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
|
||||||
smp_wmb();
|
smp_wmb();
|
||||||
intf->intf_num = i;
|
intf->intf_num = i;
|
||||||
mutex_unlock(&ipmi_interfaces_mutex);
|
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);
|
||||||
mutex_unlock(&smi_watchers_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -3631,45 +3714,49 @@ static void cleanup_smi_msgs(struct ipmi_smi *intf)
|
||||||
int ipmi_unregister_smi(struct ipmi_smi *intf)
|
int ipmi_unregister_smi(struct ipmi_smi *intf)
|
||||||
{
|
{
|
||||||
struct ipmi_smi_watcher *w;
|
struct ipmi_smi_watcher *w;
|
||||||
int intf_num = intf->intf_num;
|
int intf_num = intf->intf_num, index;
|
||||||
struct ipmi_user *user;
|
|
||||||
|
|
||||||
mutex_lock(&smi_watchers_mutex);
|
|
||||||
mutex_lock(&ipmi_interfaces_mutex);
|
mutex_lock(&ipmi_interfaces_mutex);
|
||||||
intf->intf_num = -1;
|
intf->intf_num = -1;
|
||||||
intf->in_shutdown = true;
|
intf->in_shutdown = true;
|
||||||
list_del_rcu(&intf->link);
|
list_del_rcu(&intf->link);
|
||||||
mutex_unlock(&ipmi_interfaces_mutex);
|
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);
|
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
|
#ifdef CONFIG_IPMI_PROC_INTERFACE
|
||||||
remove_proc_entries(intf);
|
remove_proc_entries(intf);
|
||||||
#endif
|
#endif
|
||||||
ipmi_bmc_unregister(intf);
|
ipmi_bmc_unregister(intf);
|
||||||
|
|
||||||
/*
|
cleanup_srcu_struct(&intf->users_srcu);
|
||||||
* 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);
|
|
||||||
|
|
||||||
kref_put(&intf->refcount, intf_free);
|
kref_put(&intf->refcount, intf_free);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipmi_unregister_smi);
|
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 ipmi_recv_msg *recv_msg, *recv_msg2;
|
||||||
struct list_head msgs;
|
struct list_head msgs;
|
||||||
struct ipmi_user *user;
|
struct ipmi_user *user;
|
||||||
int rv = 0;
|
int rv = 0, deliver_count = 0, index;
|
||||||
int deliver_count = 0;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (msg->rsp_size < 19) {
|
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
|
* Allocate and fill in one message for every user that is
|
||||||
* getting events.
|
* getting events.
|
||||||
*/
|
*/
|
||||||
rcu_read_lock();
|
index = srcu_read_lock(&intf->users_srcu);
|
||||||
list_for_each_entry_rcu(user, &intf->users, link) {
|
list_for_each_entry_rcu(user, &intf->users, link) {
|
||||||
if (!user->gets_events)
|
if (!user->gets_events)
|
||||||
continue;
|
continue;
|
||||||
|
@ -4195,7 +4281,7 @@ static int handle_read_event_rsp(struct ipmi_smi *intf,
|
||||||
kref_get(&user->refcount);
|
kref_get(&user->refcount);
|
||||||
list_add_tail(&recv_msg->link, &msgs);
|
list_add_tail(&recv_msg->link, &msgs);
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
srcu_read_unlock(&intf->users_srcu, index);
|
||||||
|
|
||||||
if (deliver_count) {
|
if (deliver_count) {
|
||||||
/* Now deliver all the messages. */
|
/* 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_smi_msg *msg)
|
||||||
{
|
{
|
||||||
struct ipmi_recv_msg *recv_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;
|
recv_msg = (struct ipmi_recv_msg *) msg->user_data;
|
||||||
if (recv_msg == NULL) {
|
if (recv_msg == NULL) {
|
||||||
|
@ -4251,30 +4337,19 @@ static int handle_bmc_rsp(struct ipmi_smi *intf,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
user = recv_msg->user;
|
recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
|
||||||
/* Make sure the user still exists. */
|
recv_msg->msgid = msg->msgid;
|
||||||
if (user && !user->valid) {
|
smi_addr = ((struct ipmi_system_interface_addr *)
|
||||||
/* The user for the message went away, so give up. */
|
&recv_msg->addr);
|
||||||
ipmi_inc_stat(intf, unhandled_local_responses);
|
smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
|
||||||
ipmi_free_recv_msg(recv_msg);
|
smi_addr->channel = IPMI_BMC_CHANNEL;
|
||||||
} else {
|
smi_addr->lun = msg->rsp[0] & 3;
|
||||||
struct ipmi_system_interface_addr *smi_addr;
|
recv_msg->msg.netfn = msg->rsp[0] >> 2;
|
||||||
|
recv_msg->msg.cmd = msg->rsp[1];
|
||||||
ipmi_inc_stat(intf, handled_local_responses);
|
memcpy(recv_msg->msg_data, &msg->rsp[2], msg->rsp_size - 2);
|
||||||
recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
|
recv_msg->msg.data = recv_msg->msg_data;
|
||||||
recv_msg->msgid = msg->msgid;
|
recv_msg->msg.data_len = msg->rsp_size - 2;
|
||||||
smi_addr = ((struct ipmi_system_interface_addr *)
|
deliver_local_response(intf, recv_msg);
|
||||||
&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;
|
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
|
* It's a response to a response we sent. For this we
|
||||||
* deliver a send message response to the user.
|
* 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;
|
requeue = 0;
|
||||||
if (msg->rsp_size < 2)
|
if (msg->rsp_size < 2)
|
||||||
|
@ -4342,10 +4417,6 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
|
||||||
if (!recv_msg)
|
if (!recv_msg)
|
||||||
goto out;
|
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->recv_type = IPMI_RESPONSE_RESPONSE_TYPE;
|
||||||
recv_msg->msg.data = recv_msg->msg_data;
|
recv_msg->msg.data = recv_msg->msg_data;
|
||||||
recv_msg->msg.data_len = 1;
|
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)) {
|
if (atomic_add_unless(&intf->watchdog_pretimeouts_to_deliver, -1, 0)) {
|
||||||
struct ipmi_user *user;
|
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) {
|
list_for_each_entry_rcu(user, &intf->users, link) {
|
||||||
if (user->handler->ipmi_watchdog_pretimeout)
|
if (user->handler->ipmi_watchdog_pretimeout)
|
||||||
user->handler->ipmi_watchdog_pretimeout(
|
user->handler->ipmi_watchdog_pretimeout(
|
||||||
user->handler_data);
|
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,
|
int slot, unsigned long *flags,
|
||||||
unsigned int *waiting_msgs)
|
unsigned int *waiting_msgs)
|
||||||
{
|
{
|
||||||
struct ipmi_recv_msg *msg;
|
struct ipmi_recv_msg *msg;
|
||||||
const struct ipmi_smi_handlers *handlers;
|
|
||||||
|
|
||||||
if (intf->in_shutdown)
|
if (intf->in_shutdown)
|
||||||
return;
|
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
|
* only for messages to the local MC, which don't get
|
||||||
* resent.
|
* resent.
|
||||||
*/
|
*/
|
||||||
handlers = intf->handlers;
|
if (intf->handlers) {
|
||||||
if (handlers) {
|
|
||||||
if (is_lan_addr(&ent->recv_msg->addr))
|
if (is_lan_addr(&ent->recv_msg->addr))
|
||||||
ipmi_inc_stat(intf,
|
ipmi_inc_stat(intf,
|
||||||
retransmitted_lan_commands);
|
retransmitted_lan_commands);
|
||||||
|
@ -4730,7 +4800,7 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
|
||||||
ipmi_inc_stat(intf,
|
ipmi_inc_stat(intf,
|
||||||
retransmitted_ipmb_commands);
|
retransmitted_ipmb_commands);
|
||||||
|
|
||||||
smi_send(intf, handlers, smi_msg, 0);
|
smi_send(intf, intf->handlers, smi_msg, 0);
|
||||||
} else
|
} else
|
||||||
ipmi_free_smi_msg(smi_msg);
|
ipmi_free_smi_msg(smi_msg);
|
||||||
|
|
||||||
|
@ -4822,12 +4892,12 @@ static atomic_t stop_operation;
|
||||||
static void ipmi_timeout(struct timer_list *unused)
|
static void ipmi_timeout(struct timer_list *unused)
|
||||||
{
|
{
|
||||||
struct ipmi_smi *intf;
|
struct ipmi_smi *intf;
|
||||||
int nt = 0;
|
int nt = 0, index;
|
||||||
|
|
||||||
if (atomic_read(&stop_operation))
|
if (atomic_read(&stop_operation))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rcu_read_lock();
|
index = srcu_read_lock(&ipmi_interfaces_srcu);
|
||||||
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
|
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
|
||||||
int lnt = 0;
|
int lnt = 0;
|
||||||
|
|
||||||
|
@ -4850,7 +4920,7 @@ static void ipmi_timeout(struct timer_list *unused)
|
||||||
|
|
||||||
nt += lnt;
|
nt += lnt;
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
srcu_read_unlock(&ipmi_interfaces_srcu, index);
|
||||||
|
|
||||||
if (nt)
|
if (nt)
|
||||||
mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
|
mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
|
||||||
|
|
Loading…
Reference in New Issue