Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e86ee2d4 authored by Corey Minyard's avatar Corey Minyard
Browse files

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: default avatarCorey Minyard <cminyard@mvista.com>
parent ac93bd0c
Loading
Loading
Loading
Loading
+280 −210
Original line number Diff line number Diff line
@@ -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.
@@ -722,51 +739,25 @@ struct watcher_entry {
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;
		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);
	kref_put(&intf->refcount, intf_free);
}
	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;

	rv = bmc_get_device_id(user->intf, NULL, &id, NULL, NULL);
	if (rv)
		return rv;
	user = acquire_ipmi_user(user, &index);
	if (!user)
		return -ENODEV;

	rv = bmc_get_device_id(user->intf, NULL, &id, NULL, NULL);
	if (!rv) {
		*major = ipmi_version_major(&id);
		*minor = ipmi_version_minor(&id);
	}
	release_ipmi_user(user, index);

	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,14 +2212,18 @@ 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,
	if (!rv)
		rv = i_ipmi_request(user,
				    user->intf,
				    addr,
				    msgid,
@@ -2167,6 +2235,9 @@ int ipmi_request_settime(struct ipmi_user *user,
				    lun,
				    retries,
				    retry_time_ms);

	release_ipmi_user(user, index);
	return rv;
}
EXPORT_SYMBOL(ipmi_request_settime);

@@ -2180,14 +2251,18 @@ 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,
	if (!rv)
		rv = i_ipmi_request(user,
				    user->intf,
				    addr,
				    msgid,
@@ -2199,6 +2274,9 @@ int ipmi_request_supply_msgs(struct ipmi_user *user,
				    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);

	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);
	/* At this point no users can be added to the interface. */

	/*
	 * Call all the watcher interfaces to tell them that
	 * an interface is gone.
	 * 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);

#ifdef CONFIG_IPMI_PROC_INTERFACE
	remove_proc_entries(intf);
#endif
	ipmi_bmc_unregister(intf);

	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,16 +4337,6 @@ 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 *)
@@ -4274,7 +4350,6 @@ static int handle_bmc_rsp(struct ipmi_smi *intf,
	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;
}
@@ -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);
	}
}

@@ -4663,7 +4735,6 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
			      unsigned int *waiting_msgs)
{
	struct ipmi_recv_msg *msg;
	const struct ipmi_smi_handlers *handlers;

	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);