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