Commit b1b5bf16 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-linus-4.19-1' of https://github.com/cminyard/linux-ipmi

Pull IPMI update from Corey Minyard:
 "Add limits on the number of users and messages, plus sysfs interfaces
  to control those limits.

  Other than that, little cleanups, use dev_xxx() insted of pr_xxx(),
  create initializers for structures, fix a refcount leak, etc"

* tag 'for-linus-4.19-1' of https://github.com/cminyard/linux-ipmi:
  ipmi:ipmb: Fix refcount leak in ipmi_ipmb_probe
  ipmi: remove unnecessary type castings
  ipmi: Make two logs unique
  ipmi:si: Convert pr_debug() to dev_dbg()
  ipmi: Convert pr_debug() to dev_dbg()
  ipmi: Fix pr_fmt to avoid compilation issues
  ipmi: Add an intializer for ipmi_recv_msg struct
  ipmi: Add an intializer for ipmi_smi_msg struct
  ipmi:ssif: Check for NULL msg when handling events and messages
  ipmi: use simple i2c probe function
  ipmi: Add a sysfs count of total outstanding messages for an interface
  ipmi: Add a sysfs interface to view the number of users
  ipmi: Limit the number of message a user may have outstanding
  ipmi: Add a limit on the number of users that may use IPMI
parents d3353719 a508e339
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -299,8 +299,7 @@ static int ipmb_slave_cb(struct i2c_client *client,
	return 0;
}

static int ipmb_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
static int ipmb_probe(struct i2c_client *client)
{
	struct ipmb_dev *ipmb_dev;
	int ret;
@@ -369,7 +368,7 @@ static struct i2c_driver ipmb_driver = {
		.name = "ipmb-dev",
		.acpi_match_table = ACPI_PTR(acpi_ipmb_id),
	},
	.probe = ipmb_probe,
	.probe_new = ipmb_probe,
	.remove = ipmb_remove,
	.id_table = ipmb_id,
};
+3 −3
Original line number Diff line number Diff line
@@ -442,8 +442,7 @@ static int ipmi_ipmb_remove(struct i2c_client *client)
	return 0;
}

static int ipmi_ipmb_probe(struct i2c_client *client,
			   const struct i2c_device_id *id)
static int ipmi_ipmb_probe(struct i2c_client *client)
{
	struct device *dev = &client->dev;
	struct ipmi_ipmb_dev *iidev;
@@ -476,6 +475,7 @@ static int ipmi_ipmb_probe(struct i2c_client *client,
	slave_np = of_parse_phandle(dev->of_node, "slave-dev", 0);
	if (slave_np) {
		slave_adap = of_get_i2c_adapter_by_node(slave_np);
		of_node_put(slave_np);
		if (!slave_adap) {
			dev_notice(&client->dev,
				   "Could not find slave adapter\n");
@@ -570,7 +570,7 @@ static struct i2c_driver ipmi_ipmb_driver = {
		.name = DEVICE_NAME,
		.of_match_table = of_ipmi_ipmb_match,
	},
	.probe		= ipmi_ipmb_probe,
	.probe_new	= ipmi_ipmb_probe,
	.remove		= ipmi_ipmb_remove,
	.id_table	= ipmi_ipmb_id,
};
+100 −11
Original line number Diff line number Diff line
@@ -11,8 +11,8 @@
 * Copyright 2002 MontaVista Software Inc.
 */

#define pr_fmt(fmt) "%s" fmt, "IPMI message handler: "
#define dev_fmt pr_fmt
#define pr_fmt(fmt) "IPMI message handler: " fmt
#define dev_fmt(fmt) pr_fmt(fmt)

#include <linux/module.h>
#include <linux/errno.h>
@@ -145,6 +145,18 @@ module_param(default_max_retries, uint, 0644);
MODULE_PARM_DESC(default_max_retries,
		 "The time (milliseconds) between retry sends in maintenance mode");

/* The default maximum number of users that may register. */
static unsigned int max_users = 30;
module_param(max_users, uint, 0644);
MODULE_PARM_DESC(max_users,
		 "The most users that may use the IPMI stack at one time.");

/* The default maximum number of message a user may have outstanding. */
static unsigned int max_msgs_per_user = 100;
module_param(max_msgs_per_user, uint, 0644);
MODULE_PARM_DESC(max_msgs_per_user,
		 "The most message a user may have outstanding.");

/* Call every ~1000 ms. */
#define IPMI_TIMEOUT_TIME	1000

@@ -187,6 +199,8 @@ struct ipmi_user {
	/* Does this interface receive IPMI events? */
	bool gets_events;

	atomic_t nr_msgs;

	/* Free must run in process context for RCU cleanup. */
	struct work_struct remove_work;
};
@@ -442,6 +456,10 @@ struct ipmi_smi {
	 */
	struct list_head users;
	struct srcu_struct users_srcu;
	atomic_t nr_users;
	struct device_attribute nr_users_devattr;
	struct device_attribute nr_msgs_devattr;


	/* Used for wake ups at startup. */
	wait_queue_head_t waitq;
@@ -927,11 +945,13 @@ static int deliver_response(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
		 * risk.  At this moment, simply skip it in that case.
		 */
		ipmi_free_recv_msg(msg);
		atomic_dec(&msg->user->nr_msgs);
	} else {
		int index;
		struct ipmi_user *user = acquire_ipmi_user(msg->user, &index);

		if (user) {
			atomic_dec(&user->nr_msgs);
			user->handler->ipmi_recv_hndl(msg, user->handler_data);
			release_ipmi_user(user, index);
		} else {
@@ -1230,6 +1250,11 @@ int ipmi_create_user(unsigned int if_num,
	goto out_kfree;

 found:
	if (atomic_add_return(1, &intf->nr_users) > max_users) {
		rv = -EBUSY;
		goto out_kfree;
	}

	INIT_WORK(&new_user->remove_work, free_user_work);

	rv = init_srcu_struct(&new_user->release_barrier);
@@ -1244,6 +1269,7 @@ int ipmi_create_user(unsigned int if_num,
	/* Note that each existing user holds a refcount to the interface. */
	kref_get(&intf->refcount);

	atomic_set(&new_user->nr_msgs, 0);
	kref_init(&new_user->refcount);
	new_user->handler = handler;
	new_user->handler_data = handler_data;
@@ -1262,6 +1288,7 @@ int ipmi_create_user(unsigned int if_num,
	return 0;

out_kfree:
	atomic_dec(&intf->nr_users);
	srcu_read_unlock(&ipmi_interfaces_srcu, index);
	vfree(new_user);
	return rv;
@@ -1336,6 +1363,7 @@ static void _ipmi_destroy_user(struct ipmi_user *user)
	/* Remove the user from the interface's sequence table. */
	spin_lock_irqsave(&intf->seq_lock, flags);
	list_del_rcu(&user->link);
	atomic_dec(&intf->nr_users);

	for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
		if (intf->seq_table[i].inuse
@@ -2284,6 +2312,14 @@ static int i_ipmi_request(struct ipmi_user *user,
	struct ipmi_recv_msg *recv_msg;
	int rv = 0;

	if (user) {
		if (atomic_add_return(1, &user->nr_msgs) > max_msgs_per_user) {
			/* Decrement will happen at the end of the routine. */
			rv = -EBUSY;
			goto out;
		}
	}

	if (supplied_recv)
		recv_msg = supplied_recv;
	else {
@@ -2296,7 +2332,7 @@ static int i_ipmi_request(struct ipmi_user *user,
	recv_msg->user_msg_data = user_msg_data;

	if (supplied_smi)
		smi_msg = (struct ipmi_smi_msg *) supplied_smi;
		smi_msg = supplied_smi;
	else {
		smi_msg = ipmi_alloc_smi_msg();
		if (smi_msg == NULL) {
@@ -2348,13 +2384,16 @@ static int i_ipmi_request(struct ipmi_user *user,
		ipmi_free_smi_msg(smi_msg);
		ipmi_free_recv_msg(recv_msg);
	} else {
		pr_debug("Send: %*ph\n", smi_msg->data_size, smi_msg->data);
		dev_dbg(intf->si_dev, "Send: %*ph\n",
			smi_msg->data_size, smi_msg->data);

		smi_send(intf, intf->handlers, smi_msg, priority);
	}
	rcu_read_unlock();

out:
	if (rv && user)
		atomic_dec(&user->nr_msgs);
	return rv;
}

@@ -3471,6 +3510,36 @@ void ipmi_poll_interface(struct ipmi_user *user)
}
EXPORT_SYMBOL(ipmi_poll_interface);

static ssize_t nr_users_show(struct device *dev,
			     struct device_attribute *attr,
			     char *buf)
{
	struct ipmi_smi *intf = container_of(attr,
			 struct ipmi_smi, nr_users_devattr);

	return sysfs_emit(buf, "%d\n", atomic_read(&intf->nr_users));
}
static DEVICE_ATTR_RO(nr_users);

static ssize_t nr_msgs_show(struct device *dev,
			    struct device_attribute *attr,
			    char *buf)
{
	struct ipmi_smi *intf = container_of(attr,
			 struct ipmi_smi, nr_msgs_devattr);
	struct ipmi_user *user;
	int index;
	unsigned int count = 0;

	index = srcu_read_lock(&intf->users_srcu);
	list_for_each_entry_rcu(user, &intf->users, link)
		count += atomic_read(&user->nr_msgs);
	srcu_read_unlock(&intf->users_srcu, index);

	return sysfs_emit(buf, "%u\n", count);
}
static DEVICE_ATTR_RO(nr_msgs);

static void redo_bmc_reg(struct work_struct *work)
{
	struct ipmi_smi *intf = container_of(work, struct ipmi_smi,
@@ -3529,6 +3598,7 @@ int ipmi_add_smi(struct module *owner,
	if (slave_addr != 0)
		intf->addrinfo[0].address = slave_addr;
	INIT_LIST_HEAD(&intf->users);
	atomic_set(&intf->nr_users, 0);
	intf->handlers = handlers;
	intf->send_info = send_info;
	spin_lock_init(&intf->seq_lock);
@@ -3592,6 +3662,20 @@ int ipmi_add_smi(struct module *owner,
	if (rv)
		goto out_err_bmc_reg;

	intf->nr_users_devattr = dev_attr_nr_users;
	sysfs_attr_init(&intf->nr_users_devattr.attr);
	rv = device_create_file(intf->si_dev, &intf->nr_users_devattr);
	if (rv)
		goto out_err_bmc_reg;

	intf->nr_msgs_devattr = dev_attr_nr_msgs;
	sysfs_attr_init(&intf->nr_msgs_devattr.attr);
	rv = device_create_file(intf->si_dev, &intf->nr_msgs_devattr);
	if (rv) {
		device_remove_file(intf->si_dev, &intf->nr_users_devattr);
		goto out_err_bmc_reg;
	}

	/*
	 * Keep memory order straight for RCU readers.  Make
	 * sure everything else is committed to memory before
@@ -3691,6 +3775,9 @@ void ipmi_unregister_smi(struct ipmi_smi *intf)

	/* At this point no users can be added to the interface. */

	device_remove_file(intf->si_dev, &intf->nr_msgs_devattr);
	device_remove_file(intf->si_dev, &intf->nr_users_devattr);

	/*
	 * Call all the watcher interfaces to tell them that
	 * an interface is going away.
@@ -3839,7 +3926,8 @@ static int handle_ipmb_get_msg_cmd(struct ipmi_smi *intf,
		msg->data[10] = ipmb_checksum(&msg->data[6], 4);
		msg->data_size = 11;

		pr_debug("Invalid command: %*ph\n", msg->data_size, msg->data);
		dev_dbg(intf->si_dev, "Invalid command: %*ph\n",
			msg->data_size, msg->data);

		rcu_read_lock();
		if (!intf->in_shutdown) {
@@ -3992,10 +4080,10 @@ static int handle_ipmb_direct_rcv_rsp(struct ipmi_smi *intf,
	struct ipmi_recv_msg *recv_msg;
	struct ipmi_ipmb_direct_addr *daddr;

	recv_msg = (struct ipmi_recv_msg *) msg->user_data;
	recv_msg = msg->user_data;
	if (recv_msg == NULL) {
		dev_warn(intf->si_dev,
			 "IPMI message received with no owner. This could be because of a malformed message, or because of a hardware error.  Contact your hardware vendor for assistance.\n");
			 "IPMI direct message received with no owner. This could be because of a malformed message, or because of a hardware error.  Contact your hardware vendor for assistance.\n");
		return 0;
	}

@@ -4410,10 +4498,10 @@ static int handle_bmc_rsp(struct ipmi_smi *intf,
	struct ipmi_recv_msg *recv_msg;
	struct ipmi_system_interface_addr *smi_addr;

	recv_msg = (struct ipmi_recv_msg *) msg->user_data;
	recv_msg = msg->user_data;
	if (recv_msg == NULL) {
		dev_warn(intf->si_dev,
			 "IPMI message received with no owner. This could be because of a malformed message, or because of a hardware error.  Contact your hardware vendor for assistance.\n");
			 "IPMI SMI message received with no owner. This could be because of a malformed message, or because of a hardware error.  Contact your hardware vendor for assistance.\n");
		return 0;
	}

@@ -4447,7 +4535,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
	unsigned char cc;
	bool is_cmd = !((msg->rsp[0] >> 2) & 1);

	pr_debug("Recv: %*ph\n", msg->rsp_size, msg->rsp);
	dev_dbg(intf->si_dev, "Recv: %*ph\n", msg->rsp_size, msg->rsp);

	if (msg->rsp_size < 2) {
		/* Message is too small to be correct. */
@@ -4831,7 +4919,8 @@ smi_from_recv_msg(struct ipmi_smi *intf, struct ipmi_recv_msg *recv_msg,
	smi_msg->data_size = recv_msg->msg.data_len;
	smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);

	pr_debug("Resend: %*ph\n", smi_msg->data_size, smi_msg->data);
	dev_dbg(intf->si_dev, "Resend: %*ph\n",
		smi_msg->data_size, smi_msg->data);

	return smi_msg;
}
+2 −6
Original line number Diff line number Diff line
@@ -94,12 +94,8 @@ static void dummy_recv_free(struct ipmi_recv_msg *msg)
{
	atomic_dec(&dummy_count);
}
static struct ipmi_smi_msg halt_smi_msg = {
	.done = dummy_smi_free
};
static struct ipmi_recv_msg halt_recv_msg = {
	.done = dummy_recv_free
};
static struct ipmi_smi_msg halt_smi_msg = INIT_IPMI_SMI_MSG(dummy_smi_free);
static struct ipmi_recv_msg halt_recv_msg = INIT_IPMI_RECV_MSG(dummy_recv_free);


/*
+9 −8
Original line number Diff line number Diff line
@@ -264,15 +264,16 @@ static void cleanup_one_si(struct smi_info *smi_info);
static void cleanup_ipmi_si(void);

#ifdef DEBUG_TIMING
void debug_timestamp(char *msg)
void debug_timestamp(struct smi_info *smi_info, char *msg)
{
	struct timespec64 t;

	ktime_get_ts64(&t);
	pr_debug("**%s: %lld.%9.9ld\n", msg, t.tv_sec, t.tv_nsec);
	dev_dbg(smi_info->io.dev, "**%s: %lld.%9.9ld\n",
		msg, t.tv_sec, t.tv_nsec);
}
#else
#define debug_timestamp(x)
#define debug_timestamp(smi_info, x)
#endif

static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
@@ -318,7 +319,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)

		smi_info->curr_msg = smi_info->waiting_msg;
		smi_info->waiting_msg = NULL;
		debug_timestamp("Start2");
		debug_timestamp(smi_info, "Start2");
		err = atomic_notifier_call_chain(&xaction_notifier_list,
				0, smi_info);
		if (err & NOTIFY_STOP_MASK) {
@@ -538,7 +539,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
{
	struct ipmi_smi_msg *msg;

	debug_timestamp("Done");
	debug_timestamp(smi_info, "Done");
	switch (smi_info->si_state) {
	case SI_NORMAL:
		if (!smi_info->curr_msg)
@@ -901,7 +902,7 @@ static void sender(void *send_info,
	struct smi_info   *smi_info = send_info;
	unsigned long     flags;

	debug_timestamp("Enqueue");
	debug_timestamp(smi_info, "Enqueue");

	if (smi_info->run_to_completion) {
		/*
@@ -1079,7 +1080,7 @@ static void smi_timeout(struct timer_list *t)
	long		  timeout;

	spin_lock_irqsave(&(smi_info->si_lock), flags);
	debug_timestamp("Timer");
	debug_timestamp(smi_info, "Timer");

	jiffies_now = jiffies;
	time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies)
@@ -1128,7 +1129,7 @@ irqreturn_t ipmi_si_irq_handler(int irq, void *data)

	smi_inc_stat(smi_info, interrupts);

	debug_timestamp("Interrupt");
	debug_timestamp(smi_info, "Interrupt");

	smi_event_handler(smi_info, 0);
	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
Loading