From cbb79863fc3175ed5ac506465948b02a893a8235 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 14 Oct 2019 10:35:56 -0500 Subject: ipmi: Don't allow device module unload when in use If something has the IPMI driver open, don't allow the device module to be unloaded. Before it would unload and the user would get errors on use. This change is made on user request, and it makes it consistent with the I2C driver, which has the same behavior. It does change things a little bit with respect to kernel users. If the ACPI or IPMI watchdog (or any other kernel user) has created a user, then the device module cannot be unloaded. Before it could be unloaded, This does not affect hot-plug. If the device goes away (it's on something removable that is removed or is hot-removed via sysfs) then it still behaves as it did before. Reported-by: tony camuso Signed-off-by: Corey Minyard Tested-by: tony camuso --- drivers/char/ipmi/ipmi_msghandler.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 2aab80e19ae0..3c8a559506e8 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -448,6 +448,8 @@ enum ipmi_stat_indexes { #define IPMI_IPMB_NUM_SEQ 64 struct ipmi_smi { + struct module *owner; + /* What interface number are we? */ int intf_num; @@ -1220,6 +1222,11 @@ int ipmi_create_user(unsigned int if_num, if (rv) goto out_kfree; + if (!try_module_get(intf->owner)) { + rv = -ENODEV; + goto out_kfree; + } + /* Note that each existing user holds a refcount to the interface. */ kref_get(&intf->refcount); @@ -1349,6 +1356,7 @@ static void _ipmi_destroy_user(struct ipmi_user *user) } kref_put(&intf->refcount, intf_free); + module_put(intf->owner); } int ipmi_destroy_user(struct ipmi_user *user) @@ -2459,7 +2467,7 @@ static int __get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc) * been recently fetched, this will just use the cached data. Otherwise * it will run a new fetch. * - * Except for the first time this is called (in ipmi_register_smi()), + * Except for the first time this is called (in ipmi_add_smi()), * this will always return good data; */ static int __bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc, @@ -3377,10 +3385,11 @@ static void redo_bmc_reg(struct work_struct *work) kref_put(&intf->refcount, intf_free); } -int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, - void *send_info, - struct device *si_dev, - unsigned char slave_addr) +int ipmi_add_smi(struct module *owner, + const struct ipmi_smi_handlers *handlers, + void *send_info, + struct device *si_dev, + unsigned char slave_addr) { int i, j; int rv; @@ -3406,7 +3415,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, return rv; } - + intf->owner = owner; intf->bmc = &intf->tmp_bmc; INIT_LIST_HEAD(&intf->bmc->intfs); mutex_init(&intf->bmc->dyn_mutex); @@ -3514,7 +3523,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, return rv; } -EXPORT_SYMBOL(ipmi_register_smi); +EXPORT_SYMBOL(ipmi_add_smi); static void deliver_smi_err_response(struct ipmi_smi *intf, struct ipmi_smi_msg *msg, -- cgit From 8ee7b485bbfbd182aa2c1a0a45812e151c1000bd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 11 Oct 2019 18:50:36 +0300 Subject: ipmi: use %*ph to print small buffer Use %*ph format to print small buffer as hex string. The change is safe since the specifier can handle up to 64 bytes and taking into account the buffer size of 100 bytes on stack the function has never been used to dump more than 32 bytes. Note, this also avoids potential buffer overflow if the length of the input buffer is bigger. This completely eliminates ipmi_debug_msg() in favour of Dynamic Debug. Signed-off-by: Andy Shevchenko Signed-off-by: Andy Shevchenko Message-Id: <20191011155036.36748-1-andriy.shevchenko@linux.intel.com> Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 3c8a559506e8..2bac299db201 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -44,25 +44,6 @@ static void need_waiter(struct ipmi_smi *intf); static int handle_one_recv_msg(struct ipmi_smi *intf, struct ipmi_smi_msg *msg); -#ifdef DEBUG -static void ipmi_debug_msg(const char *title, unsigned char *data, - unsigned int len) -{ - int i, pos; - char buf[100]; - - pos = snprintf(buf, sizeof(buf), "%s: ", title); - for (i = 0; i < len; i++) - pos += snprintf(buf + pos, sizeof(buf) - pos, - " %2.2x", data[i]); - pr_debug("%s\n", buf); -} -#else -static void ipmi_debug_msg(const char *title, unsigned char *data, - unsigned int len) -{ } -#endif - static bool initialized; static bool drvregistered; @@ -2275,7 +2256,7 @@ out_err: ipmi_free_smi_msg(smi_msg); ipmi_free_recv_msg(recv_msg); } else { - ipmi_debug_msg("Send", smi_msg->data, smi_msg->data_size); + pr_debug("Send: %*ph\n", smi_msg->data_size, smi_msg->data); smi_send(intf, intf->handlers, smi_msg, priority); } @@ -3739,7 +3720,7 @@ static int handle_ipmb_get_msg_cmd(struct ipmi_smi *intf, msg->data[10] = ipmb_checksum(&msg->data[6], 4); msg->data_size = 11; - ipmi_debug_msg("Invalid command:", msg->data, msg->data_size); + pr_debug("Invalid command: %*ph\n", msg->data_size, msg->data); rcu_read_lock(); if (!intf->in_shutdown) { @@ -4226,7 +4207,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf, int requeue; int chan; - ipmi_debug_msg("Recv:", msg->rsp, msg->rsp_size); + pr_debug("Recv: %*ph\n", msg->rsp_size, msg->rsp); if ((msg->data_size >= 2) && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2)) @@ -4585,7 +4566,7 @@ 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); - ipmi_debug_msg("Resend: ", smi_msg->data, smi_msg->data_size); + pr_debug("Resend: %*ph\n", smi_msg->data_size, smi_msg->data); return smi_msg; } -- cgit From 2a21d858f96bdfd3de28abc1341935d06fb47373 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 16 Oct 2019 17:21:31 +0800 Subject: ipmi: bt-bmc: use devm_platform_ioremap_resource() to simplify code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Signed-off-by: YueHaibing Message-Id: <20191016092131.23096-1-yuehaibing@huawei.com> Reviewed-by: Cédric Le Goater Signed-off-by: Corey Minyard --- drivers/char/ipmi/bt-bmc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c index 40b9927c072c..d36aeacb290e 100644 --- a/drivers/char/ipmi/bt-bmc.c +++ b/drivers/char/ipmi/bt-bmc.c @@ -444,15 +444,13 @@ static int bt_bmc_probe(struct platform_device *pdev) bt_bmc->map = syscon_node_to_regmap(pdev->dev.parent->of_node); if (IS_ERR(bt_bmc->map)) { - struct resource *res; void __iomem *base; /* * Assume it's not the MFD-based devicetree description, in * which case generate a regmap ourselves */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); -- cgit From 4aa7afb0ee20a97fbf0c5bab3df028d5fb85fdab Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Mon, 21 Oct 2019 15:06:48 -0500 Subject: ipmi: Fix memory leak in __ipmi_bmc_register In the impelementation of __ipmi_bmc_register() the allocated memory for bmc should be released in case ida_simple_get() fails. Fixes: 68e7e50f195f ("ipmi: Don't use BMC product/dev ids in the BMC name") Signed-off-by: Navid Emamdoost Message-Id: <20191021200649.1511-1-navid.emamdoost@gmail.com> Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 2bac299db201..cad9563f8f48 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3020,8 +3020,11 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf, bmc->pdev.name = "ipmi_bmc"; rv = ida_simple_get(&ipmi_bmc_ida, 0, 0, GFP_KERNEL); - if (rv < 0) + if (rv < 0) { + kfree(bmc); goto out; + } + bmc->pdev.dev.driver = &ipmidriver.driver; bmc->pdev.id = rv; bmc->pdev.dev.release = release_bmc_device; -- cgit From 0d8633bf5311177c9a26d75daec677cd87e3261b Mon Sep 17 00:00:00 2001 From: Vijay Khemka Date: Wed, 6 Nov 2019 10:29:21 -0800 Subject: drivers: ipmi: Support for both IPMB Req and Resp Removed check for request or response in IPMB packets coming from device as well as from host. Now it supports both way communication to device via IPMB. Both request and response will be passed to application. Signed-off-by: Vijay Khemka Message-Id: <20191106182921.1086795-1-vijaykhemka@fb.com> Reviewed-by: Asmaa Mnebhi Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmb_dev_int.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmb_dev_int.c b/drivers/char/ipmi/ipmb_dev_int.c index 285e0b8f9a97..ae3bfba27526 100644 --- a/drivers/char/ipmi/ipmb_dev_int.c +++ b/drivers/char/ipmi/ipmb_dev_int.c @@ -133,9 +133,6 @@ static ssize_t ipmb_write(struct file *file, const char __user *buf, rq_sa = GET_7BIT_ADDR(msg[RQ_SA_8BIT_IDX]); netf_rq_lun = msg[NETFN_LUN_IDX]; - if (!(netf_rq_lun & NETFN_RSP_BIT_MASK)) - return -EINVAL; - /* * subtract rq_sa and netf_rq_lun from the length of the msg passed to * i2c_smbus_xfer @@ -203,25 +200,16 @@ static u8 ipmb_verify_checksum1(struct ipmb_dev *ipmb_dev, u8 rs_sa) ipmb_dev->request.checksum1); } -static bool is_ipmb_request(struct ipmb_dev *ipmb_dev, u8 rs_sa) +/* + * Verify if message has proper ipmb header with minimum length + * and correct checksum byte. + */ +static bool is_ipmb_msg(struct ipmb_dev *ipmb_dev, u8 rs_sa) { - if (ipmb_dev->msg_idx >= IPMB_REQUEST_LEN_MIN) { - if (ipmb_verify_checksum1(ipmb_dev, rs_sa)) - return false; + if ((ipmb_dev->msg_idx >= IPMB_REQUEST_LEN_MIN) && + (!ipmb_verify_checksum1(ipmb_dev, rs_sa))) + return true; - /* - * Check whether this is an IPMB request or - * response. - * The 6 MSB of netfn_rs_lun are dedicated to the netfn - * while the remaining bits are dedicated to the lun. - * If the LSB of the netfn is cleared, it is associated - * with an IPMB request. - * If the LSB of the netfn is set, it is associated with - * an IPMB response. - */ - if (!(ipmb_dev->request.netfn_rs_lun & NETFN_RSP_BIT_MASK)) - return true; - } return false; } @@ -273,8 +261,7 @@ static int ipmb_slave_cb(struct i2c_client *client, case I2C_SLAVE_STOP: ipmb_dev->request.len = ipmb_dev->msg_idx; - - if (is_ipmb_request(ipmb_dev, GET_8BIT_ADDR(client->addr))) + if (is_ipmb_msg(ipmb_dev, GET_8BIT_ADDR(client->addr))) ipmb_handle_request(ipmb_dev); break; -- cgit From 8d73b2aeb8088517b0895f209b68237ea1bc1c02 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 8 Nov 2019 21:34:27 +0100 Subject: ipmi: kill off 'timespec' usage again 'struct timespec' is getting removed from the kernel. The usage in ipmi was fixed before in commit 48862ea2ce86 ("ipmi: Update timespec usage to timespec64"), but unfortunately it crept back in. The busy looping code can better use ktime_t anyway, so use that there to simplify the implementation. Fixes: cbb19cb1eef0 ("ipmi_si: Convert timespec64 to timespec") Signed-off-by: Arnd Bergmann Message-Id: <20191108203435.112759-5-arnd@arndb.de> Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 40 +++++++++++++--------------------------- 1 file changed, 13 insertions(+), 27 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 6b9a0593d2eb..c7cc8538b84a 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -265,10 +265,10 @@ static void cleanup_ipmi_si(void); #ifdef DEBUG_TIMING void debug_timestamp(char *msg) { - struct timespec t; + struct timespec64 t; - ktime_get_ts(&t); - pr_debug("**%s: %ld.%9.9ld\n", msg, (long) t.tv_sec, t.tv_nsec); + ktime_get_ts64(&t); + pr_debug("**%s: %lld.%9.9ld\n", msg, t.tv_sec, t.tv_nsec); } #else #define debug_timestamp(x) @@ -935,38 +935,25 @@ static void set_run_to_completion(void *send_info, bool i_run_to_completion) } /* - * Use -1 in the nsec value of the busy waiting timespec to tell that - * we are spinning in kipmid looking for something and not delaying - * between checks + * Use -1 as a special constant to tell that we are spinning in kipmid + * looking for something and not delaying between checks */ -static inline void ipmi_si_set_not_busy(struct timespec *ts) -{ - ts->tv_nsec = -1; -} -static inline int ipmi_si_is_busy(struct timespec *ts) -{ - return ts->tv_nsec != -1; -} - +#define IPMI_TIME_NOT_BUSY ns_to_ktime(-1ull) static inline bool ipmi_thread_busy_wait(enum si_sm_result smi_result, const struct smi_info *smi_info, - struct timespec *busy_until) + ktime_t *busy_until) { unsigned int max_busy_us = 0; if (smi_info->si_num < num_max_busy_us) max_busy_us = kipmid_max_busy_us[smi_info->si_num]; if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY) - ipmi_si_set_not_busy(busy_until); - else if (!ipmi_si_is_busy(busy_until)) { - ktime_get_ts(busy_until); - timespec_add_ns(busy_until, max_busy_us * NSEC_PER_USEC); + *busy_until = IPMI_TIME_NOT_BUSY; + else if (*busy_until == IPMI_TIME_NOT_BUSY) { + *busy_until = ktime_get() + max_busy_us * NSEC_PER_USEC; } else { - struct timespec now; - - ktime_get_ts(&now); - if (unlikely(timespec_compare(&now, busy_until) > 0)) { - ipmi_si_set_not_busy(busy_until); + if (unlikely(ktime_get() > *busy_until)) { + *busy_until = IPMI_TIME_NOT_BUSY; return false; } } @@ -988,9 +975,8 @@ static int ipmi_thread(void *data) struct smi_info *smi_info = data; unsigned long flags; enum si_sm_result smi_result; - struct timespec busy_until = { 0, 0 }; + ktime_t busy_until = IPMI_TIME_NOT_BUSY; - ipmi_si_set_not_busy(&busy_until); set_user_nice(current, MAX_NICE); while (!kthread_should_stop()) { int busy_wait; -- cgit From 8e6a5c833333e14a5023a5dcabb64b7d9e046bc6 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Wed, 20 Nov 2019 01:07:41 +0100 Subject: ipmi: fix ipmb_poll()'s return type ipmb_poll() is defined as returning 'unsigned int' but the .poll method is declared as returning '__poll_t', a bitwise type. Fix this by using the proper return type and using the EPOLL constants instead of the POLL ones, as required for __poll_t. CC: Corey Minyard CC: openipmi-developer@lists.sourceforge.net CC: Greg Kroah-Hartman Signed-off-by: Luc Van Oostenryck Message-Id: <20191120000741.30657-1-luc.vanoostenryck@gmail.com> Reviewed-by: Asmaa Mnebhi Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmb_dev_int.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmb_dev_int.c b/drivers/char/ipmi/ipmb_dev_int.c index ae3bfba27526..1ff4fb1def7c 100644 --- a/drivers/char/ipmi/ipmb_dev_int.c +++ b/drivers/char/ipmi/ipmb_dev_int.c @@ -151,16 +151,16 @@ static ssize_t ipmb_write(struct file *file, const char __user *buf, return ret ? : count; } -static unsigned int ipmb_poll(struct file *file, poll_table *wait) +static __poll_t ipmb_poll(struct file *file, poll_table *wait) { struct ipmb_dev *ipmb_dev = to_ipmb_dev(file); - unsigned int mask = POLLOUT; + __poll_t mask = EPOLLOUT; mutex_lock(&ipmb_dev->file_mutex); poll_wait(file, &ipmb_dev->wait_queue, wait); if (atomic_read(&ipmb_dev->request_queue_len)) - mask |= POLLIN; + mask |= EPOLLIN; mutex_unlock(&ipmb_dev->file_mutex); return mask; -- cgit