Merge tag 'char-misc-6.4-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux.git] / drivers / md / dm-exception-store.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
4  * Copyright (C) 2006-2008 Red Hat GmbH
5  *
6  * This file is released under the GPL.
7  */
8
9 #include "dm-exception-store.h"
10
11 #include <linux/ctype.h>
12 #include <linux/mm.h>
13 #include <linux/pagemap.h>
14 #include <linux/vmalloc.h>
15 #include <linux/module.h>
16 #include <linux/slab.h>
17
18 #define DM_MSG_PREFIX "snapshot exception stores"
19
20 static LIST_HEAD(_exception_store_types);
21 static DEFINE_SPINLOCK(_lock);
22
23 static struct dm_exception_store_type *__find_exception_store_type(const char *name)
24 {
25         struct dm_exception_store_type *type;
26
27         list_for_each_entry(type, &_exception_store_types, list)
28                 if (!strcmp(name, type->name))
29                         return type;
30
31         return NULL;
32 }
33
34 static struct dm_exception_store_type *_get_exception_store_type(const char *name)
35 {
36         struct dm_exception_store_type *type;
37
38         spin_lock(&_lock);
39
40         type = __find_exception_store_type(name);
41
42         if (type && !try_module_get(type->module))
43                 type = NULL;
44
45         spin_unlock(&_lock);
46
47         return type;
48 }
49
50 /*
51  * get_type
52  * @type_name
53  *
54  * Attempt to retrieve the dm_exception_store_type by name.  If not already
55  * available, attempt to load the appropriate module.
56  *
57  * Exstore modules are named "dm-exstore-" followed by the 'type_name'.
58  * Modules may contain multiple types.
59  * This function will first try the module "dm-exstore-<type_name>",
60  * then truncate 'type_name' on the last '-' and try again.
61  *
62  * For example, if type_name was "clustered-shared", it would search
63  * 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'.
64  *
65  * 'dm-exception-store-<type_name>' is too long of a name in my
66  * opinion, which is why I've chosen to have the files
67  * containing exception store implementations be 'dm-exstore-<type_name>'.
68  * If you want your module to be autoloaded, you will follow this
69  * naming convention.
70  *
71  * Returns: dm_exception_store_type* on success, NULL on failure
72  */
73 static struct dm_exception_store_type *get_type(const char *type_name)
74 {
75         char *p, *type_name_dup;
76         struct dm_exception_store_type *type;
77
78         type = _get_exception_store_type(type_name);
79         if (type)
80                 return type;
81
82         type_name_dup = kstrdup(type_name, GFP_KERNEL);
83         if (!type_name_dup) {
84                 DMERR("No memory left to attempt load for \"%s\"", type_name);
85                 return NULL;
86         }
87
88         while (request_module("dm-exstore-%s", type_name_dup) ||
89                !(type = _get_exception_store_type(type_name))) {
90                 p = strrchr(type_name_dup, '-');
91                 if (!p)
92                         break;
93                 p[0] = '\0';
94         }
95
96         if (!type)
97                 DMWARN("Module for exstore type \"%s\" not found.", type_name);
98
99         kfree(type_name_dup);
100
101         return type;
102 }
103
104 static void put_type(struct dm_exception_store_type *type)
105 {
106         spin_lock(&_lock);
107         module_put(type->module);
108         spin_unlock(&_lock);
109 }
110
111 int dm_exception_store_type_register(struct dm_exception_store_type *type)
112 {
113         int r = 0;
114
115         spin_lock(&_lock);
116         if (!__find_exception_store_type(type->name))
117                 list_add(&type->list, &_exception_store_types);
118         else
119                 r = -EEXIST;
120         spin_unlock(&_lock);
121
122         return r;
123 }
124 EXPORT_SYMBOL(dm_exception_store_type_register);
125
126 int dm_exception_store_type_unregister(struct dm_exception_store_type *type)
127 {
128         spin_lock(&_lock);
129
130         if (!__find_exception_store_type(type->name)) {
131                 spin_unlock(&_lock);
132                 return -EINVAL;
133         }
134
135         list_del(&type->list);
136
137         spin_unlock(&_lock);
138
139         return 0;
140 }
141 EXPORT_SYMBOL(dm_exception_store_type_unregister);
142
143 static int set_chunk_size(struct dm_exception_store *store,
144                           const char *chunk_size_arg, char **error)
145 {
146         unsigned int chunk_size;
147
148         if (kstrtouint(chunk_size_arg, 10, &chunk_size)) {
149                 *error = "Invalid chunk size";
150                 return -EINVAL;
151         }
152
153         if (!chunk_size) {
154                 store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
155                 return 0;
156         }
157
158         return dm_exception_store_set_chunk_size(store, chunk_size, error);
159 }
160
161 int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
162                                       unsigned int chunk_size,
163                                       char **error)
164 {
165         /* Check chunk_size is a power of 2 */
166         if (!is_power_of_2(chunk_size)) {
167                 *error = "Chunk size is not a power of 2";
168                 return -EINVAL;
169         }
170
171         /* Validate the chunk size against the device block size */
172         if (chunk_size %
173             (bdev_logical_block_size(dm_snap_cow(store->snap)->bdev) >> 9) ||
174             chunk_size %
175             (bdev_logical_block_size(dm_snap_origin(store->snap)->bdev) >> 9)) {
176                 *error = "Chunk size is not a multiple of device blocksize";
177                 return -EINVAL;
178         }
179
180         if (chunk_size > INT_MAX >> SECTOR_SHIFT) {
181                 *error = "Chunk size is too high";
182                 return -EINVAL;
183         }
184
185         store->chunk_size = chunk_size;
186         store->chunk_mask = chunk_size - 1;
187         store->chunk_shift = __ffs(chunk_size);
188
189         return 0;
190 }
191
192 int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
193                               struct dm_snapshot *snap,
194                               unsigned int *args_used,
195                               struct dm_exception_store **store)
196 {
197         int r = 0;
198         struct dm_exception_store_type *type = NULL;
199         struct dm_exception_store *tmp_store;
200         char persistent;
201
202         if (argc < 2) {
203                 ti->error = "Insufficient exception store arguments";
204                 return -EINVAL;
205         }
206
207         tmp_store = kzalloc(sizeof(*tmp_store), GFP_KERNEL);
208         if (!tmp_store) {
209                 ti->error = "Exception store allocation failed";
210                 return -ENOMEM;
211         }
212
213         persistent = toupper(*argv[0]);
214         if (persistent == 'P')
215                 type = get_type("P");
216         else if (persistent == 'N')
217                 type = get_type("N");
218         else {
219                 ti->error = "Exception store type is not P or N";
220                 r = -EINVAL;
221                 goto bad_type;
222         }
223
224         if (!type) {
225                 ti->error = "Exception store type not recognised";
226                 r = -EINVAL;
227                 goto bad_type;
228         }
229
230         tmp_store->type = type;
231         tmp_store->snap = snap;
232
233         r = set_chunk_size(tmp_store, argv[1], &ti->error);
234         if (r)
235                 goto bad;
236
237         r = type->ctr(tmp_store, (strlen(argv[0]) > 1 ? &argv[0][1] : NULL));
238         if (r) {
239                 ti->error = "Exception store type constructor failed";
240                 goto bad;
241         }
242
243         *args_used = 2;
244         *store = tmp_store;
245         return 0;
246
247 bad:
248         put_type(type);
249 bad_type:
250         kfree(tmp_store);
251         return r;
252 }
253 EXPORT_SYMBOL(dm_exception_store_create);
254
255 void dm_exception_store_destroy(struct dm_exception_store *store)
256 {
257         store->type->dtr(store);
258         put_type(store->type);
259         kfree(store);
260 }
261 EXPORT_SYMBOL(dm_exception_store_destroy);
262
263 int dm_exception_store_init(void)
264 {
265         int r;
266
267         r = dm_transient_snapshot_init();
268         if (r) {
269                 DMERR("Unable to register transient exception store type.");
270                 goto transient_fail;
271         }
272
273         r = dm_persistent_snapshot_init();
274         if (r) {
275                 DMERR("Unable to register persistent exception store type");
276                 goto persistent_fail;
277         }
278
279         return 0;
280
281 persistent_fail:
282         dm_transient_snapshot_exit();
283 transient_fail:
284         return r;
285 }
286
287 void dm_exception_store_exit(void)
288 {
289         dm_persistent_snapshot_exit();
290         dm_transient_snapshot_exit();
291 }