On 10/14/19 11:46 AM, minyard@xxxxxxx wrote:
From: Corey Minyard <cminyard@xxxxxxxxxx>
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 <tcamuso@xxxxxxxxxx>
Signed-off-by: Corey Minyard <cminyard@xxxxxxxxxx>
---
Tony, here is a suggested change for this. Can you look it over and
see if it looks ok?
Thanks,
-corey
 drivers/char/ipmi/ipmi_msghandler.c | 23 ++++++++++++++++-------
 include/linux/ipmi_smi.h | 12 ++++++++----
 2 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 2aab80e19ae0..15680de18625 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,
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h
index 4dc66157d872..deec18b8944a 100644
--- a/include/linux/ipmi_smi.h
+++ b/include/linux/ipmi_smi.h
@@ -224,10 +224,14 @@ static inline int ipmi_demangle_device_id(uint8_t netfn, uint8_t cmd,
ÂÂ * is called, and the lower layer must get the interface from that
ÂÂ * call.
ÂÂ */
-int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
-ÂÂÂÂÂÂÂÂÂÂÂÂÂ voidÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ *send_info,
-ÂÂÂÂÂÂÂÂÂÂÂÂÂ struct deviceÂÂÂÂÂÂÂÂÂÂÂ *dev,
-ÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned charÂÂÂÂÂÂÂÂÂÂÂ slave_addr);
+int ipmi_add_smi(struct moduleÂÂÂÂÂÂÂÂÂÂÂ *owner,
+ÂÂÂÂÂÂÂÂ const struct ipmi_smi_handlers *handlers,
+ÂÂÂÂÂÂÂÂ voidÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ *send_info,
+ÂÂÂÂÂÂÂÂ struct deviceÂÂÂÂÂÂÂÂÂÂÂ *dev,
+ÂÂÂÂÂÂÂÂ unsigned charÂÂÂÂÂÂÂÂÂÂÂ slave_addr);
+
+#define ipmi_register_smi(handlers, send_info, dev, slave_addr) \
+ÂÂÂ ipmi_add_smi(THIS_MODULE, handlers, send_info, dev, slave_addr)
 /*
 * Remove a low-level interface from the IPMI driver. This will
Thanks, Corey.
Regards,
Tony