*/
struct zpool_driver {
char *type;
+ struct module *owner;
struct list_head list;
void *(*create)(gfp_t gfp, struct zpool_ops *ops);
/**
* zpool_unregister_driver() - unregister a zpool implementation.
* @driver: driver to unregister.
+ *
+ * Module usage counting is used to prevent using a driver
+ * while/after unloading. Please only call unregister from
+ * module exit function.
*/
void zpool_unregister_driver(struct zpool_driver *driver);
static struct zpool_driver zbud_zpool_driver = {
.type = "zbud",
+ .owner = THIS_MODULE,
.create = zbud_zpool_create,
.destroy = zbud_zpool_destroy,
.malloc = zbud_zpool_malloc,
{
struct zpool_driver *driver;
- assert_spin_locked(&drivers_lock);
+ spin_lock(&drivers_lock);
list_for_each_entry(driver, &drivers_head, list) {
- if (!strcmp(driver->type, type))
- return driver;
+ if (!strcmp(driver->type, type)) {
+ bool got = try_module_get(driver->owner);
+ spin_unlock(&drivers_lock);
+ return got ? driver : NULL;
+ }
}
+ spin_unlock(&drivers_lock);
return NULL;
}
+static void zpool_put_driver(struct zpool_driver *driver)
+{
+ module_put(driver->owner);
+}
+
struct zpool *zpool_create_pool(char *type, gfp_t flags,
struct zpool_ops *ops)
{
pr_info("creating pool type %s\n", type);
- spin_lock(&drivers_lock);
driver = zpool_get_driver(type);
- spin_unlock(&drivers_lock);
if (!driver) {
request_module(type);
- spin_lock(&drivers_lock);
driver = zpool_get_driver(type);
- spin_unlock(&drivers_lock);
}
if (!driver) {
zpool = kmalloc(sizeof(*zpool), GFP_KERNEL);
if (!zpool) {
pr_err("couldn't create zpool - out of memory\n");
+ zpool_put_driver(driver);
return NULL;
}
if (!zpool->pool) {
pr_err("couldn't create %s pool\n", type);
+ zpool_put_driver(driver);
kfree(zpool);
return NULL;
}
list_del(&zpool->list);
spin_unlock(&pools_lock);
zpool->driver->destroy(zpool->pool);
+ zpool_put_driver(zpool->driver);
kfree(zpool);
}