mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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
					
				
					 1 changed files with 281 additions and 211 deletions
				
			
		| 
						 | 
				
			
			@ -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 @@ static int i_ipmi_request(struct ipmi_user     *user,
 | 
			
		|||
	}
 | 
			
		||||
	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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue