Blame view
drivers/md/dm-exception-store.c
6.54 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
1da177e4c Linux-2.6.12-rc2 |
2 |
* Copyright (C) 2001-2002 Sistina Software (UK) Limited. |
4db6bfe02 dm snapshot: spli... |
3 |
* Copyright (C) 2006-2008 Red Hat GmbH |
1da177e4c Linux-2.6.12-rc2 |
4 5 6 |
* * This file is released under the GPL. */ |
aea53d92f dm snapshot: sepa... |
7 |
#include "dm-exception-store.h" |
1da177e4c Linux-2.6.12-rc2 |
8 |
|
fee1998e9 dm snapshot: move... |
9 |
#include <linux/ctype.h> |
1da177e4c Linux-2.6.12-rc2 |
10 11 12 |
#include <linux/mm.h> #include <linux/pagemap.h> #include <linux/vmalloc.h> |
056075c76 md: Add module.h ... |
13 |
#include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
14 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
15 |
|
4db6bfe02 dm snapshot: spli... |
16 |
#define DM_MSG_PREFIX "snapshot exception stores" |
1da177e4c Linux-2.6.12-rc2 |
17 |
|
493df71c6 dm exception stor... |
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 dm snapshot: move... |
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 dm snapshot: use ... |
147 148 |
if (*chunk_size_arg == '\0' || *value != '\0' || chunk_size_ulong > UINT_MAX) { |
fee1998e9 dm snapshot: move... |
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 dm snapshot: use ... |
157 158 |
return dm_exception_store_set_chunk_size(store, (unsigned) chunk_size_ulong, |
2defcc3fb dm exception stor... |
159 160 161 162 |
error); } int dm_exception_store_set_chunk_size(struct dm_exception_store *store, |
df96eee67 dm snapshot: use ... |
163 |
unsigned chunk_size, |
2defcc3fb dm exception stor... |
164 165 |
char **error) { |
fee1998e9 dm snapshot: move... |
166 |
/* Check chunk_size is a power of 2 */ |
df96eee67 dm snapshot: use ... |
167 |
if (!is_power_of_2(chunk_size)) { |
fee1998e9 dm snapshot: move... |
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 dm snapshot: move... |
173 |
if (chunk_size % |
c24110450 dm snapshot: test... |
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 dm snapshot: move... |
177 178 179 |
*error = "Chunk size is not a multiple of device blocksize"; return -EINVAL; } |
df96eee67 dm snapshot: use ... |
180 |
if (chunk_size > INT_MAX >> SECTOR_SHIFT) { |
ae0b7448e dm snapshot: fix ... |
181 182 183 |
*error = "Chunk size is too high"; return -EINVAL; } |
df96eee67 dm snapshot: use ... |
184 185 186 |
store->chunk_size = chunk_size; store->chunk_mask = chunk_size - 1; store->chunk_shift = ffs(chunk_size) - 1; |
fee1998e9 dm snapshot: move... |
187 188 189 190 191 |
return 0; } int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, |
fc56f6fbc dm snapshot: move... |
192 |
struct dm_snapshot *snap, |
fee1998e9 dm snapshot: move... |
193 |
unsigned *args_used, |
493df71c6 dm exception stor... |
194 195 196 |
struct dm_exception_store **store) { int r = 0; |
874d2f61d dm exception stor... |
197 |
struct dm_exception_store_type *type = NULL; |
493df71c6 dm exception stor... |
198 |
struct dm_exception_store *tmp_store; |
fee1998e9 dm snapshot: move... |
199 |
char persistent; |
fc56f6fbc dm snapshot: move... |
200 |
if (argc < 2) { |
fee1998e9 dm snapshot: move... |
201 202 203 |
ti->error = "Insufficient exception store arguments"; return -EINVAL; } |
493df71c6 dm exception stor... |
204 205 |
tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL); |
fee1998e9 dm snapshot: move... |
206 207 |
if (!tmp_store) { ti->error = "Exception store allocation failed"; |
493df71c6 dm exception stor... |
208 |
return -ENOMEM; |
fee1998e9 dm snapshot: move... |
209 |
} |
493df71c6 dm exception stor... |
210 |
|
fc56f6fbc dm snapshot: move... |
211 |
persistent = toupper(*argv[0]); |
874d2f61d dm exception stor... |
212 213 214 215 216 |
if (persistent == 'P') type = get_type("P"); else if (persistent == 'N') type = get_type("N"); else { |
fee1998e9 dm snapshot: move... |
217 |
ti->error = "Persistent flag is not P or N"; |
613978f87 dm exception stor... |
218 219 |
r = -EINVAL; goto bad_type; |
493df71c6 dm exception stor... |
220 |
} |
fee1998e9 dm snapshot: move... |
221 222 223 224 225 |
if (!type) { ti->error = "Exception store type not recognised"; r = -EINVAL; goto bad_type; } |
493df71c6 dm exception stor... |
226 |
tmp_store->type = type; |
fc56f6fbc dm snapshot: move... |
227 |
tmp_store->snap = snap; |
493df71c6 dm exception stor... |
228 |
|
fc56f6fbc dm snapshot: move... |
229 |
r = set_chunk_size(tmp_store, argv[1], &ti->error); |
fee1998e9 dm snapshot: move... |
230 |
if (r) |
fc56f6fbc dm snapshot: move... |
231 |
goto bad; |
49beb2b87 dm exception stor... |
232 |
|
493df71c6 dm exception stor... |
233 234 |
r = type->ctr(tmp_store, 0, NULL); if (r) { |
fee1998e9 dm snapshot: move... |
235 |
ti->error = "Exception store type constructor failed"; |
fc56f6fbc dm snapshot: move... |
236 |
goto bad; |
493df71c6 dm exception stor... |
237 |
} |
fc56f6fbc dm snapshot: move... |
238 |
*args_used = 2; |
493df71c6 dm exception stor... |
239 240 |
*store = tmp_store; return 0; |
fee1998e9 dm snapshot: move... |
241 |
|
fc56f6fbc dm snapshot: move... |
242 |
bad: |
fee1998e9 dm snapshot: move... |
243 244 245 246 |
put_type(type); bad_type: kfree(tmp_store); return r; |
493df71c6 dm exception stor... |
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 dm snapshot: spli... |
257 |
int dm_exception_store_init(void) |
1da177e4c Linux-2.6.12-rc2 |
258 259 |
{ int r; |
1da177e4c Linux-2.6.12-rc2 |
260 |
|
4db6bfe02 dm snapshot: spli... |
261 262 263 264 |
r = dm_transient_snapshot_init(); if (r) { DMERR("Unable to register transient exception store type."); goto transient_fail; |
1da177e4c Linux-2.6.12-rc2 |
265 |
} |
4db6bfe02 dm snapshot: spli... |
266 267 268 269 |
r = dm_persistent_snapshot_init(); if (r) { DMERR("Unable to register persistent exception store type"); goto persistent_fail; |
1da177e4c Linux-2.6.12-rc2 |
270 271 272 |
} return 0; |
1da177e4c Linux-2.6.12-rc2 |
273 |
|
4db6bfe02 dm snapshot: spli... |
274 275 276 277 |
persistent_fail: dm_persistent_snapshot_exit(); transient_fail: return r; |
1da177e4c Linux-2.6.12-rc2 |
278 |
} |
4db6bfe02 dm snapshot: spli... |
279 |
void dm_exception_store_exit(void) |
1da177e4c Linux-2.6.12-rc2 |
280 |
{ |
4db6bfe02 dm snapshot: spli... |
281 282 |
dm_persistent_snapshot_exit(); dm_transient_snapshot_exit(); |
1da177e4c Linux-2.6.12-rc2 |
283 |
} |