forked from luck/tmp_suning_uos_patched
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 <tcamuso@redhat.com> Signed-off-by: Corey Minyard <cminyard@mvista.com> Tested-by: tony camuso <tcamuso@redhat.com>
This commit is contained in:
parent
3b7c59a195
commit
cbb79863fc
|
@ -448,6 +448,8 @@ enum ipmi_stat_indexes {
|
||||||
|
|
||||||
#define IPMI_IPMB_NUM_SEQ 64
|
#define IPMI_IPMB_NUM_SEQ 64
|
||||||
struct ipmi_smi {
|
struct ipmi_smi {
|
||||||
|
struct module *owner;
|
||||||
|
|
||||||
/* What interface number are we? */
|
/* What interface number are we? */
|
||||||
int intf_num;
|
int intf_num;
|
||||||
|
|
||||||
|
@ -1220,6 +1222,11 @@ int ipmi_create_user(unsigned int if_num,
|
||||||
if (rv)
|
if (rv)
|
||||||
goto out_kfree;
|
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. */
|
/* Note that each existing user holds a refcount to the interface. */
|
||||||
kref_get(&intf->refcount);
|
kref_get(&intf->refcount);
|
||||||
|
|
||||||
|
@ -1349,6 +1356,7 @@ static void _ipmi_destroy_user(struct ipmi_user *user)
|
||||||
}
|
}
|
||||||
|
|
||||||
kref_put(&intf->refcount, intf_free);
|
kref_put(&intf->refcount, intf_free);
|
||||||
|
module_put(intf->owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ipmi_destroy_user(struct ipmi_user *user)
|
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
|
* been recently fetched, this will just use the cached data. Otherwise
|
||||||
* it will run a new fetch.
|
* 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;
|
* this will always return good data;
|
||||||
*/
|
*/
|
||||||
static int __bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc,
|
static int __bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc,
|
||||||
|
@ -3377,7 +3385,8 @@ static void redo_bmc_reg(struct work_struct *work)
|
||||||
kref_put(&intf->refcount, intf_free);
|
kref_put(&intf->refcount, intf_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
|
int ipmi_add_smi(struct module *owner,
|
||||||
|
const struct ipmi_smi_handlers *handlers,
|
||||||
void *send_info,
|
void *send_info,
|
||||||
struct device *si_dev,
|
struct device *si_dev,
|
||||||
unsigned char slave_addr)
|
unsigned char slave_addr)
|
||||||
|
@ -3406,7 +3415,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intf->owner = owner;
|
||||||
intf->bmc = &intf->tmp_bmc;
|
intf->bmc = &intf->tmp_bmc;
|
||||||
INIT_LIST_HEAD(&intf->bmc->intfs);
|
INIT_LIST_HEAD(&intf->bmc->intfs);
|
||||||
mutex_init(&intf->bmc->dyn_mutex);
|
mutex_init(&intf->bmc->dyn_mutex);
|
||||||
|
@ -3514,7 +3523,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipmi_register_smi);
|
EXPORT_SYMBOL(ipmi_add_smi);
|
||||||
|
|
||||||
static void deliver_smi_err_response(struct ipmi_smi *intf,
|
static void deliver_smi_err_response(struct ipmi_smi *intf,
|
||||||
struct ipmi_smi_msg *msg,
|
struct ipmi_smi_msg *msg,
|
||||||
|
|
|
@ -224,11 +224,15 @@ 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
|
* is called, and the lower layer must get the interface from that
|
||||||
* call.
|
* call.
|
||||||
*/
|
*/
|
||||||
int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
|
int ipmi_add_smi(struct module *owner,
|
||||||
|
const struct ipmi_smi_handlers *handlers,
|
||||||
void *send_info,
|
void *send_info,
|
||||||
struct device *dev,
|
struct device *dev,
|
||||||
unsigned char slave_addr);
|
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
|
* Remove a low-level interface from the IPMI driver. This will
|
||||||
* return an error if the interface is still in use by a user.
|
* return an error if the interface is still in use by a user.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user