dm-exception-store.c revision 0cea9c78270cdf1d2ad74ce0e083d5555a0842e8
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001-2002 Sistina Software (UK) Limited. 34db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon * Copyright (C) 2006-2008 Red Hat GmbH 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file is released under the GPL. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8aea53d92f70eeb00ae480e399a997dd55fd5055dJonathan Brassow#include "dm-exception-store.h" 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pagemap.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 154db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon#define DM_MSG_PREFIX "snapshot exception stores" 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic LIST_HEAD(_exception_store_types); 18493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic DEFINE_SPINLOCK(_lock); 19493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 20493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic struct dm_exception_store_type *__find_exception_store_type(const char *name) 21493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{ 22493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow struct dm_exception_store_type *type; 23493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 24493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow list_for_each_entry(type, &_exception_store_types, list) 25493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow if (!strcmp(name, type->name)) 26493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return type; 27493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 28493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return NULL; 29493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow} 30493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 31493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic struct dm_exception_store_type *_get_exception_store_type(const char *name) 32493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{ 33493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow struct dm_exception_store_type *type; 34493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 35493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow spin_lock(&_lock); 36493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 37493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow type = __find_exception_store_type(name); 38493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 39493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow if (type && !try_module_get(type->module)) 40493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow type = NULL; 41493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 42493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow spin_unlock(&_lock); 43493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 44493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return type; 45493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow} 46493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 47493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow/* 48493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * get_type 49493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * @type_name 50493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * 51493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Attempt to retrieve the dm_exception_store_type by name. If not already 52493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * available, attempt to load the appropriate module. 53493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * 54493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Exstore modules are named "dm-exstore-" followed by the 'type_name'. 55493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Modules may contain multiple types. 56493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * This function will first try the module "dm-exstore-<type_name>", 57493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * then truncate 'type_name' on the last '-' and try again. 58493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * 59493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * For example, if type_name was "clustered-shared", it would search 60493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'. 61493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * 62493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * 'dm-exception-store-<type_name>' is too long of a name in my 63493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * opinion, which is why I've chosen to have the files 64493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * containing exception store implementations be 'dm-exstore-<type_name>'. 65493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * If you want your module to be autoloaded, you will follow this 66493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * naming convention. 67493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * 68493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Returns: dm_exception_store_type* on success, NULL on failure 69493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow */ 70493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic struct dm_exception_store_type *get_type(const char *type_name) 71493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{ 72493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow char *p, *type_name_dup; 73493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow struct dm_exception_store_type *type; 74493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 75493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow type = _get_exception_store_type(type_name); 76493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow if (type) 77493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return type; 78493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 79493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow type_name_dup = kstrdup(type_name, GFP_KERNEL); 80493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow if (!type_name_dup) { 81493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow DMERR("No memory left to attempt load for \"%s\"", type_name); 82493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return NULL; 83493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow } 84493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 85493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow while (request_module("dm-exstore-%s", type_name_dup) || 86493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow !(type = _get_exception_store_type(type_name))) { 87493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow p = strrchr(type_name_dup, '-'); 88493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow if (!p) 89493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow break; 90493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow p[0] = '\0'; 91493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow } 92493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 93493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow if (!type) 94493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow DMWARN("Module for exstore type \"%s\" not found.", type_name); 95493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 96493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow kfree(type_name_dup); 97493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 98493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return type; 99493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow} 100493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 101493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic void put_type(struct dm_exception_store_type *type) 102493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{ 103493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow spin_lock(&_lock); 104493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow module_put(type->module); 105493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow spin_unlock(&_lock); 106493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow} 107493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 108493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowint dm_exception_store_type_register(struct dm_exception_store_type *type) 109493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{ 110493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow int r = 0; 111493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 112493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow spin_lock(&_lock); 113493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow if (!__find_exception_store_type(type->name)) 114493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow list_add(&type->list, &_exception_store_types); 115493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow else 116493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow r = -EEXIST; 117493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow spin_unlock(&_lock); 118493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 119493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return r; 120493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow} 121493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_type_register); 122493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 123493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowint dm_exception_store_type_unregister(struct dm_exception_store_type *type) 124493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{ 125493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow spin_lock(&_lock); 126493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 127493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow if (!__find_exception_store_type(type->name)) { 128493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow spin_unlock(&_lock); 129493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return -EINVAL; 130493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow } 131493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 132493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow list_del(&type->list); 133493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 134493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow spin_unlock(&_lock); 135493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 136493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return 0; 137493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow} 138493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_type_unregister); 139493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 1400cea9c78270cdf1d2ad74ce0e083d5555a0842e8Jonathan Brassowint dm_exception_store_create(const char *type_name, struct dm_target *ti, 141493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow struct dm_exception_store **store) 142493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{ 143493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow int r = 0; 144493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow struct dm_exception_store_type *type; 145493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow struct dm_exception_store *tmp_store; 146493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 147493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL); 148493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow if (!tmp_store) 149493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return -ENOMEM; 150493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 151493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow type = get_type(type_name); 152493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow if (!type) { 153493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow kfree(tmp_store); 154493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return -EINVAL; 155493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow } 156493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 157493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow tmp_store->type = type; 1580cea9c78270cdf1d2ad74ce0e083d5555a0842e8Jonathan Brassow tmp_store->ti = ti; 159493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 160493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow r = type->ctr(tmp_store, 0, NULL); 161493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow if (r) { 162493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow put_type(type); 163493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow kfree(tmp_store); 164493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return r; 165493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow } 166493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 167493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow *store = tmp_store; 168493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow return 0; 169493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow} 170493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_create); 171493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 172493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowvoid dm_exception_store_destroy(struct dm_exception_store *store) 173493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{ 174493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow store->type->dtr(store); 175493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow put_type(store->type); 176493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow kfree(store); 177493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow} 178493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_destroy); 179493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow 1804db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonint dm_exception_store_init(void) 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int r; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1844db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon r = dm_transient_snapshot_init(); 1854db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon if (r) { 1864db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon DMERR("Unable to register transient exception store type."); 1874db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon goto transient_fail; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1904db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon r = dm_persistent_snapshot_init(); 1914db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon if (r) { 1924db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon DMERR("Unable to register persistent exception store type"); 1934db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon goto persistent_fail; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1984db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonpersistent_fail: 1994db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon dm_persistent_snapshot_exit(); 2004db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergontransient_fail: 2014db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon return r; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2044db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonvoid dm_exception_store_exit(void) 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2064db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon dm_persistent_snapshot_exit(); 2074db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon dm_transient_snapshot_exit(); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 209