summary refs log tree commit diff
path: root/drivers/md
diff options
context:
space:
mode:
authorJonathan Brassow <jbrassow@redhat.com>2008-04-24 21:43:41 +0100
committerAlasdair G Kergon <agk@redhat.com>2008-04-25 13:26:48 +0100
commit2a23aa1ddb1f0c9eef2c929c89565c387f6bf68b (patch)
treedc029b4230dc1282363a16d8a9d9126f1c9d7ffe /drivers/md
parentb8206bc3de0b0665d47655d270c18ea46aff5372 (diff)
downloadlinux-2a23aa1ddb1f0c9eef2c929c89565c387f6bf68b.tar.gz
dm log: make module use tracking internal
Remove internal module reference fields from the interface.

Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-log.c123
-rw-r--r--drivers/md/dm-log.h2
2 files changed, 94 insertions, 31 deletions
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 82df73f67a0d..e6b6a9d5fdd2 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -16,34 +16,51 @@
 
 #define DM_MSG_PREFIX "dirty region log"
 
+struct dm_dirty_log_internal {
+	struct dm_dirty_log_type *type;
+
+	struct list_head list;
+	long use;
+};
+
 static LIST_HEAD(_log_types);
 static DEFINE_SPINLOCK(_lock);
 
-static struct dm_dirty_log_type *_get_type(const char *type_name)
+static struct dm_dirty_log_internal *__find_dirty_log_type(const char *name)
 {
-	struct dm_dirty_log_type *type;
+	struct dm_dirty_log_internal *log_type;
+
+	list_for_each_entry(log_type, &_log_types, list)
+		if (!strcmp(name, log_type->type->name))
+			return log_type;
+
+	return NULL;
+}
+
+static struct dm_dirty_log_internal *_get_dirty_log_type(const char *name)
+{
+	struct dm_dirty_log_internal *log_type;
 
 	spin_lock(&_lock);
-	list_for_each_entry (type, &_log_types, list)
-		if (!strcmp(type_name, type->name)) {
-			if (!type->use_count && !try_module_get(type->module)){
-				spin_unlock(&_lock);
-				return NULL;
-			}
-			type->use_count++;
-			spin_unlock(&_lock);
-			return type;
-		}
+
+	log_type = __find_dirty_log_type(name);
+	if (log_type) {
+		if (!log_type->use && !try_module_get(log_type->type->module))
+			log_type = NULL;
+		else
+			log_type->use++;
+	}
 
 	spin_unlock(&_lock);
-	return NULL;
+
+	return log_type;
 }
 
 /*
  * get_type
  * @type_name
  *
- * Attempt to retrieve the dirty_log_type by name.  If not already
+ * Attempt to retrieve the dm_dirty_log_type by name.  If not already
  * available, attempt to load the appropriate module.
  *
  * Log modules are named "dm-log-" followed by the 'type_name'.
@@ -59,11 +76,14 @@ static struct dm_dirty_log_type *_get_type(const char *type_name)
 static struct dm_dirty_log_type *get_type(const char *type_name)
 {
 	char *p, *type_name_dup;
-	struct dm_dirty_log_type *type;
+	struct dm_dirty_log_internal *log_type;
 
-	type = _get_type(type_name);
-	if (type)
-		return type;
+	if (!type_name)
+		return NULL;
+
+	log_type = _get_dirty_log_type(type_name);
+	if (log_type)
+		return log_type->type;
 
 	type_name_dup = kstrdup(type_name, GFP_KERNEL);
 	if (!type_name_dup) {
@@ -73,50 +93,95 @@ static struct dm_dirty_log_type *get_type(const char *type_name)
 	}
 
 	while (request_module("dm-log-%s", type_name_dup) ||
-	       !(type = _get_type(type_name))) {
+	       !(log_type = _get_dirty_log_type(type_name))) {
 		p = strrchr(type_name_dup, '-');
 		if (!p)
 			break;
 		p[0] = '\0';
 	}
 
-	if (!type)
+	if (!log_type)
 		DMWARN("Module for logging type \"%s\" not found.", type_name);
 
 	kfree(type_name_dup);
 
-	return type;
+	return log_type ? log_type->type : NULL;
 }
 
 static void put_type(struct dm_dirty_log_type *type)
 {
+	struct dm_dirty_log_internal *log_type;
+
+	if (!type)
+		return;
+
 	spin_lock(&_lock);
-	if (!--type->use_count)
+	log_type = __find_dirty_log_type(type->name);
+	if (!log_type)
+		goto out;
+
+	if (!--log_type->use)
 		module_put(type->module);
+
+	BUG_ON(log_type->use < 0);
+
+out:
 	spin_unlock(&_lock);
 }
 
+static struct dm_dirty_log_internal *_alloc_dirty_log_type(struct dm_dirty_log_type *type)
+{
+	struct dm_dirty_log_internal *log_type = kzalloc(sizeof(*log_type),
+							 GFP_KERNEL);
+
+	if (log_type)
+		log_type->type = type;
+
+	return log_type;
+}
+
 int dm_dirty_log_type_register(struct dm_dirty_log_type *type)
 {
+	struct dm_dirty_log_internal *log_type = _alloc_dirty_log_type(type);
+	int r = 0;
+
+	if (!log_type)
+		return -ENOMEM;
+
 	spin_lock(&_lock);
-	type->use_count = 0;
-	list_add(&type->list, &_log_types);
+	if (!__find_dirty_log_type(type->name))
+		list_add(&log_type->list, &_log_types);
+	else {
+		kfree(log_type);
+		r = -EEXIST;
+	}
 	spin_unlock(&_lock);
 
-	return 0;
+	return r;
 }
 EXPORT_SYMBOL(dm_dirty_log_type_register);
 
 int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type)
 {
+	struct dm_dirty_log_internal *log_type;
+
 	spin_lock(&_lock);
 
-	if (type->use_count)
-		DMWARN("Attempt to unregister a log type that is still in use");
-	else
-		list_del(&type->list);
+	log_type = __find_dirty_log_type(type->name);
+	if (!log_type) {
+		spin_unlock(&_lock);
+		return -EINVAL;
+	}
+
+	if (log_type->use) {
+		spin_unlock(&_lock);
+		return -ETXTBSY;
+	}
+
+	list_del(&log_type->list);
 
 	spin_unlock(&_lock);
+	kfree(log_type);
 
 	return 0;
 }
diff --git a/drivers/md/dm-log.h b/drivers/md/dm-log.h
index 2da48a857cb9..600c5fb2daad 100644
--- a/drivers/md/dm-log.h
+++ b/drivers/md/dm-log.h
@@ -25,10 +25,8 @@ struct dm_dirty_log {
 };
 
 struct dm_dirty_log_type {
-	struct list_head list;
 	const char *name;
 	struct module *module;
-	unsigned use_count;
 
 	int (*ctr)(struct dm_dirty_log *log, struct dm_target *ti,
 		   unsigned argc, char **argv);