diff options
Diffstat (limited to 'drivers/md/dm-log.c')
-rw-r--r-- | drivers/md/dm-log.c | 123 |
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 | ||
19 | struct dm_dirty_log_internal { | ||
20 | struct dm_dirty_log_type *type; | ||
21 | |||
22 | struct list_head list; | ||
23 | long use; | ||
24 | }; | ||
25 | |||
19 | static LIST_HEAD(_log_types); | 26 | static LIST_HEAD(_log_types); |
20 | static DEFINE_SPINLOCK(_lock); | 27 | static DEFINE_SPINLOCK(_lock); |
21 | 28 | ||
22 | static struct dm_dirty_log_type *_get_type(const char *type_name) | 29 | static 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 | |||
40 | static 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) | |||
59 | static struct dm_dirty_log_type *get_type(const char *type_name) | 76 | static 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 | ||
91 | static void put_type(struct dm_dirty_log_type *type) | 111 | static 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 | |||
128 | out: | ||
96 | spin_unlock(&_lock); | 129 | spin_unlock(&_lock); |
97 | } | 130 | } |
98 | 131 | ||
132 | static 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 | |||
99 | int dm_dirty_log_type_register(struct dm_dirty_log_type *type) | 143 | int 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 | } |
108 | EXPORT_SYMBOL(dm_dirty_log_type_register); | 162 | EXPORT_SYMBOL(dm_dirty_log_type_register); |
109 | 163 | ||
110 | int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type) | 164 | int 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 | } |