18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2001-2002 Sistina Software (UK) Limited. 38c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Red Hat GmbH 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file is released under the GPL. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "dm-exception-store.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/ctype.h> 118c2ecf20Sopenharmony_ci#include <linux/mm.h> 128c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 138c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "snapshot exception stores" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic LIST_HEAD(_exception_store_types); 208c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(_lock); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic struct dm_exception_store_type *__find_exception_store_type(const char *name) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct dm_exception_store_type *type; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci list_for_each_entry(type, &_exception_store_types, list) 278c2ecf20Sopenharmony_ci if (!strcmp(name, type->name)) 288c2ecf20Sopenharmony_ci return type; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci return NULL; 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic struct dm_exception_store_type *_get_exception_store_type(const char *name) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct dm_exception_store_type *type; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci spin_lock(&_lock); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci type = __find_exception_store_type(name); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (type && !try_module_get(type->module)) 428c2ecf20Sopenharmony_ci type = NULL; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci spin_unlock(&_lock); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci return type; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* 508c2ecf20Sopenharmony_ci * get_type 518c2ecf20Sopenharmony_ci * @type_name 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * Attempt to retrieve the dm_exception_store_type by name. If not already 548c2ecf20Sopenharmony_ci * available, attempt to load the appropriate module. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * Exstore modules are named "dm-exstore-" followed by the 'type_name'. 578c2ecf20Sopenharmony_ci * Modules may contain multiple types. 588c2ecf20Sopenharmony_ci * This function will first try the module "dm-exstore-<type_name>", 598c2ecf20Sopenharmony_ci * then truncate 'type_name' on the last '-' and try again. 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * For example, if type_name was "clustered-shared", it would search 628c2ecf20Sopenharmony_ci * 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * 'dm-exception-store-<type_name>' is too long of a name in my 658c2ecf20Sopenharmony_ci * opinion, which is why I've chosen to have the files 668c2ecf20Sopenharmony_ci * containing exception store implementations be 'dm-exstore-<type_name>'. 678c2ecf20Sopenharmony_ci * If you want your module to be autoloaded, you will follow this 688c2ecf20Sopenharmony_ci * naming convention. 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * Returns: dm_exception_store_type* on success, NULL on failure 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_cistatic struct dm_exception_store_type *get_type(const char *type_name) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci char *p, *type_name_dup; 758c2ecf20Sopenharmony_ci struct dm_exception_store_type *type; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci type = _get_exception_store_type(type_name); 788c2ecf20Sopenharmony_ci if (type) 798c2ecf20Sopenharmony_ci return type; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci type_name_dup = kstrdup(type_name, GFP_KERNEL); 828c2ecf20Sopenharmony_ci if (!type_name_dup) { 838c2ecf20Sopenharmony_ci DMERR("No memory left to attempt load for \"%s\"", type_name); 848c2ecf20Sopenharmony_ci return NULL; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci while (request_module("dm-exstore-%s", type_name_dup) || 888c2ecf20Sopenharmony_ci !(type = _get_exception_store_type(type_name))) { 898c2ecf20Sopenharmony_ci p = strrchr(type_name_dup, '-'); 908c2ecf20Sopenharmony_ci if (!p) 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci p[0] = '\0'; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (!type) 968c2ecf20Sopenharmony_ci DMWARN("Module for exstore type \"%s\" not found.", type_name); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci kfree(type_name_dup); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return type; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void put_type(struct dm_exception_store_type *type) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci spin_lock(&_lock); 1068c2ecf20Sopenharmony_ci module_put(type->module); 1078c2ecf20Sopenharmony_ci spin_unlock(&_lock); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ciint dm_exception_store_type_register(struct dm_exception_store_type *type) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci int r = 0; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci spin_lock(&_lock); 1158c2ecf20Sopenharmony_ci if (!__find_exception_store_type(type->name)) 1168c2ecf20Sopenharmony_ci list_add(&type->list, &_exception_store_types); 1178c2ecf20Sopenharmony_ci else 1188c2ecf20Sopenharmony_ci r = -EEXIST; 1198c2ecf20Sopenharmony_ci spin_unlock(&_lock); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return r; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_exception_store_type_register); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciint dm_exception_store_type_unregister(struct dm_exception_store_type *type) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci spin_lock(&_lock); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (!__find_exception_store_type(type->name)) { 1308c2ecf20Sopenharmony_ci spin_unlock(&_lock); 1318c2ecf20Sopenharmony_ci return -EINVAL; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci list_del(&type->list); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci spin_unlock(&_lock); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_exception_store_type_unregister); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int set_chunk_size(struct dm_exception_store *store, 1438c2ecf20Sopenharmony_ci const char *chunk_size_arg, char **error) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci unsigned chunk_size; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (kstrtouint(chunk_size_arg, 10, &chunk_size)) { 1488c2ecf20Sopenharmony_ci *error = "Invalid chunk size"; 1498c2ecf20Sopenharmony_ci return -EINVAL; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (!chunk_size) { 1538c2ecf20Sopenharmony_ci store->chunk_size = store->chunk_mask = store->chunk_shift = 0; 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return dm_exception_store_set_chunk_size(store, chunk_size, error); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ciint dm_exception_store_set_chunk_size(struct dm_exception_store *store, 1618c2ecf20Sopenharmony_ci unsigned chunk_size, 1628c2ecf20Sopenharmony_ci char **error) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci /* Check chunk_size is a power of 2 */ 1658c2ecf20Sopenharmony_ci if (!is_power_of_2(chunk_size)) { 1668c2ecf20Sopenharmony_ci *error = "Chunk size is not a power of 2"; 1678c2ecf20Sopenharmony_ci return -EINVAL; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Validate the chunk size against the device block size */ 1718c2ecf20Sopenharmony_ci if (chunk_size % 1728c2ecf20Sopenharmony_ci (bdev_logical_block_size(dm_snap_cow(store->snap)->bdev) >> 9) || 1738c2ecf20Sopenharmony_ci chunk_size % 1748c2ecf20Sopenharmony_ci (bdev_logical_block_size(dm_snap_origin(store->snap)->bdev) >> 9)) { 1758c2ecf20Sopenharmony_ci *error = "Chunk size is not a multiple of device blocksize"; 1768c2ecf20Sopenharmony_ci return -EINVAL; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (chunk_size > INT_MAX >> SECTOR_SHIFT) { 1808c2ecf20Sopenharmony_ci *error = "Chunk size is too high"; 1818c2ecf20Sopenharmony_ci return -EINVAL; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci store->chunk_size = chunk_size; 1858c2ecf20Sopenharmony_ci store->chunk_mask = chunk_size - 1; 1868c2ecf20Sopenharmony_ci store->chunk_shift = __ffs(chunk_size); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ciint dm_exception_store_create(struct dm_target *ti, int argc, char **argv, 1928c2ecf20Sopenharmony_ci struct dm_snapshot *snap, 1938c2ecf20Sopenharmony_ci unsigned *args_used, 1948c2ecf20Sopenharmony_ci struct dm_exception_store **store) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci int r = 0; 1978c2ecf20Sopenharmony_ci struct dm_exception_store_type *type = NULL; 1988c2ecf20Sopenharmony_ci struct dm_exception_store *tmp_store; 1998c2ecf20Sopenharmony_ci char persistent; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (argc < 2) { 2028c2ecf20Sopenharmony_ci ti->error = "Insufficient exception store arguments"; 2038c2ecf20Sopenharmony_ci return -EINVAL; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci tmp_store = kzalloc(sizeof(*tmp_store), GFP_KERNEL); 2078c2ecf20Sopenharmony_ci if (!tmp_store) { 2088c2ecf20Sopenharmony_ci ti->error = "Exception store allocation failed"; 2098c2ecf20Sopenharmony_ci return -ENOMEM; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci persistent = toupper(*argv[0]); 2138c2ecf20Sopenharmony_ci if (persistent == 'P') 2148c2ecf20Sopenharmony_ci type = get_type("P"); 2158c2ecf20Sopenharmony_ci else if (persistent == 'N') 2168c2ecf20Sopenharmony_ci type = get_type("N"); 2178c2ecf20Sopenharmony_ci else { 2188c2ecf20Sopenharmony_ci ti->error = "Exception store type is not P or N"; 2198c2ecf20Sopenharmony_ci r = -EINVAL; 2208c2ecf20Sopenharmony_ci goto bad_type; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (!type) { 2248c2ecf20Sopenharmony_ci ti->error = "Exception store type not recognised"; 2258c2ecf20Sopenharmony_ci r = -EINVAL; 2268c2ecf20Sopenharmony_ci goto bad_type; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci tmp_store->type = type; 2308c2ecf20Sopenharmony_ci tmp_store->snap = snap; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci r = set_chunk_size(tmp_store, argv[1], &ti->error); 2338c2ecf20Sopenharmony_ci if (r) 2348c2ecf20Sopenharmony_ci goto bad; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci r = type->ctr(tmp_store, (strlen(argv[0]) > 1 ? &argv[0][1] : NULL)); 2378c2ecf20Sopenharmony_ci if (r) { 2388c2ecf20Sopenharmony_ci ti->error = "Exception store type constructor failed"; 2398c2ecf20Sopenharmony_ci goto bad; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci *args_used = 2; 2438c2ecf20Sopenharmony_ci *store = tmp_store; 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cibad: 2478c2ecf20Sopenharmony_ci put_type(type); 2488c2ecf20Sopenharmony_cibad_type: 2498c2ecf20Sopenharmony_ci kfree(tmp_store); 2508c2ecf20Sopenharmony_ci return r; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_exception_store_create); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_civoid dm_exception_store_destroy(struct dm_exception_store *store) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci store->type->dtr(store); 2578c2ecf20Sopenharmony_ci put_type(store->type); 2588c2ecf20Sopenharmony_ci kfree(store); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_exception_store_destroy); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ciint dm_exception_store_init(void) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci int r; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci r = dm_transient_snapshot_init(); 2678c2ecf20Sopenharmony_ci if (r) { 2688c2ecf20Sopenharmony_ci DMERR("Unable to register transient exception store type."); 2698c2ecf20Sopenharmony_ci goto transient_fail; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci r = dm_persistent_snapshot_init(); 2738c2ecf20Sopenharmony_ci if (r) { 2748c2ecf20Sopenharmony_ci DMERR("Unable to register persistent exception store type"); 2758c2ecf20Sopenharmony_ci goto persistent_fail; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return 0; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cipersistent_fail: 2818c2ecf20Sopenharmony_ci dm_transient_snapshot_exit(); 2828c2ecf20Sopenharmony_citransient_fail: 2838c2ecf20Sopenharmony_ci return r; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_civoid dm_exception_store_exit(void) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci dm_persistent_snapshot_exit(); 2898c2ecf20Sopenharmony_ci dm_transient_snapshot_exit(); 2908c2ecf20Sopenharmony_ci} 291