aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-log.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-log.c')
-rw-r--r--drivers/md/dm-log.c123
1 files changed, 94 insertions, 29 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 @@
16 16
17#define DM_MSG_PREFIX "dirty region log" 17#define DM_MSG_PREFIX "dirty region log"
18 18
19struct dm_dirty_log_internal {
20 struct dm_dirty_log_type *type;
21
22 struct list_head list;
23 long use;
24};
25
19static LIST_HEAD(_log_types); 26static LIST_HEAD(_log_types);
20static DEFINE_SPINLOCK(_lock); 27static DEFINE_SPINLOCK(_lock);
21 28
22static struct dm_dirty_log_type *_get_type(const char *type_name) 29static struct dm_dirty_log_internal *__find_dirty_log_type(const char *name)
23{ 30{
24 struct dm_dirty_log_type *type; 31 struct dm_dirty_log_internal *log_type;
32
33 list_for_each_entry(log_type, &_log_types, list)
34 if (!strcmp(name, log_type->type->name))
35 return log_type;
36
37 return NULL;
38}
39
40static struct dm_dirty_log_internal *_get_dirty_log_type(const char *name)
41{
42 struct dm_dirty_log_internal *log_type;
25 43
26 spin_lock(&_lock); 44 spin_lock(&_lock);
27 list_for_each_entry (type, &_log_types, list) 45
28 if (!strcmp(type_name, type->name)) { 46 log_type = __find_dirty_log_type(name);
29 if (!type->use_count && !try_module_get(type->module)){ 47 if (log_type) {
30 spin_unlock(&_lock); 48 if (!log_type->use && !try_module_get(log_type->type->module))
31 return NULL; 49 log_type = NULL;
32 } 50 else
33 type->use_count++; 51 log_type->use++;
34 spin_unlock(&_lock); 52 }
35 return type;
36 }
37 53
38 spin_unlock(&_lock); 54 spin_unlock(&_lock);
39 return NULL; 55
56 return log_type;
40} 57}
41 58
42/* 59/*
43 * get_type 60 * get_type
44 * @type_name 61 * @type_name
45 * 62 *
46 * Attempt to retrieve the dirty_log_type by name. If not already 63 * Attempt to retrieve the dm_dirty_log_type by name. If not already
47 * available, attempt to load the appropriate module. 64 * available, attempt to load the appropriate module.
48 * 65 *
49 * Log modules are named "dm-log-" followed by the 'type_name'. 66 * 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)
59static struct dm_dirty_log_type *get_type(const char *type_name) 76static struct dm_dirty_log_type *get_type(const char *type_name)
60{ 77{
61 char *p, *type_name_dup; 78 char *p, *type_name_dup;
62 struct dm_dirty_log_type *type; 79 struct dm_dirty_log_internal *log_type;
63 80
64 type = _get_type(type_name); 81 if (!type_name)
65 if (type) 82 return NULL;
66 return type; 83
84 log_type = _get_dirty_log_type(type_name);
85 if (log_type)
86 return log_type->type;
67 87
68 type_name_dup = kstrdup(type_name, GFP_KERNEL); 88 type_name_dup = kstrdup(type_name, GFP_KERNEL);
69 if (!type_name_dup) { 89 if (!type_name_dup) {
@@ -73,50 +93,95 @@ static struct dm_dirty_log_type *get_type(const char *type_name)
73 } 93 }
74 94
75 while (request_module("dm-log-%s", type_name_dup) || 95 while (request_module("dm-log-%s", type_name_dup) ||
76 !(type = _get_type(type_name))) { 96 !(log_type = _get_dirty_log_type(type_name))) {
77 p = strrchr(type_name_dup, '-'); 97 p = strrchr(type_name_dup, '-');
78 if (!p) 98 if (!p)
79 break; 99 break;
80 p[0] = '\0'; 100 p[0] = '\0';
81 } 101 }
82 102
83 if (!type) 103 if (!log_type)
84 DMWARN("Module for logging type \"%s\" not found.", type_name); 104 DMWARN("Module for logging type \"%s\" not found.", type_name);
85 105
86 kfree(type_name_dup); 106 kfree(type_name_dup);
87 107
88 return type; 108 return log_type ? log_type->type : NULL;
89} 109}
90 110
91static void put_type(struct dm_dirty_log_type *type) 111static void put_type(struct dm_dirty_log_type *type)
92{ 112{
113 struct dm_dirty_log_internal *log_type;
114
115 if (!type)
116 return;
117
93 spin_lock(&_lock); 118 spin_lock(&_lock);
94 if (!--type->use_count) 119 log_type = __find_dirty_log_type(type->name);
120 if (!log_type)
121 goto out;
122
123 if (!--log_type->use)
95 module_put(type->module); 124 module_put(type->module);
125
126 BUG_ON(log_type->use < 0);
127
128out:
96 spin_unlock(&_lock); 129 spin_unlock(&_lock);
97} 130}
98 131
132static struct dm_dirty_log_internal *_alloc_dirty_log_type(struct dm_dirty_log_type *type)
133{
134 struct dm_dirty_log_internal *log_type = kzalloc(sizeof(*log_type),
135 GFP_KERNEL);
136
137 if (log_type)
138 log_type->type = type;
139
140 return log_type;
141}
142
99int dm_dirty_log_type_register(struct dm_dirty_log_type *type) 143int dm_dirty_log_type_register(struct dm_dirty_log_type *type)
100{ 144{
145 struct dm_dirty_log_internal *log_type = _alloc_dirty_log_type(type);
146 int r = 0;
147
148 if (!log_type)
149 return -ENOMEM;
150
101 spin_lock(&_lock); 151 spin_lock(&_lock);
102 type->use_count = 0; 152 if (!__find_dirty_log_type(type->name))
103 list_add(&type->list, &_log_types); 153 list_add(&log_type->list, &_log_types);
154 else {
155 kfree(log_type);
156 r = -EEXIST;
157 }
104 spin_unlock(&_lock); 158 spin_unlock(&_lock);
105 159
106 return 0; 160 return r;
107} 161}
108EXPORT_SYMBOL(dm_dirty_log_type_register); 162EXPORT_SYMBOL(dm_dirty_log_type_register);
109 163
110int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type) 164int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type)
111{ 165{
166 struct dm_dirty_log_internal *log_type;
167
112 spin_lock(&_lock); 168 spin_lock(&_lock);
113 169
114 if (type->use_count) 170 log_type = __find_dirty_log_type(type->name);
115 DMWARN("Attempt to unregister a log type that is still in use"); 171 if (!log_type) {
116 else 172 spin_unlock(&_lock);
117 list_del(&type->list); 173 return -EINVAL;
174 }
175
176 if (log_type->use) {
177 spin_unlock(&_lock);
178 return -ETXTBSY;
179 }
180
181 list_del(&log_type->list);
118 182
119 spin_unlock(&_lock); 183 spin_unlock(&_lock);
184 kfree(log_type);
120 185
121 return 0; 186 return 0;
122} 187}