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
10fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow#include <linux/ctype.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pagemap.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h>
14056075c76417b112b4924e7b6386fdc6dfc9ac03Paul Gortmaker#include <linux/module.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
174db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon#define DM_MSG_PREFIX "snapshot exception stores"
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic LIST_HEAD(_exception_store_types);
20493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic DEFINE_SPINLOCK(_lock);
21493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
22493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic struct dm_exception_store_type *__find_exception_store_type(const char *name)
23493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
24493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	struct dm_exception_store_type *type;
25493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
26493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	list_for_each_entry(type, &_exception_store_types, list)
27493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		if (!strcmp(name, type->name))
28493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow			return type;
29493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
30493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return NULL;
31493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
32493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
33493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic struct dm_exception_store_type *_get_exception_store_type(const char *name)
34493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
35493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	struct dm_exception_store_type *type;
36493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
37493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_lock(&_lock);
38493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
39493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	type = __find_exception_store_type(name);
40493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
41493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (type && !try_module_get(type->module))
42493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		type = NULL;
43493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
44493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_unlock(&_lock);
45493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
46493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return type;
47493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
48493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
49493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow/*
50493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * get_type
51493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * @type_name
52493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow *
53493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Attempt to retrieve the dm_exception_store_type by name.  If not already
54493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * available, attempt to load the appropriate module.
55493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow *
56493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Exstore modules are named "dm-exstore-" followed by the 'type_name'.
57493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Modules may contain multiple types.
58493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * This function will first try the module "dm-exstore-<type_name>",
59493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * then truncate 'type_name' on the last '-' and try again.
60493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow *
61493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * For example, if type_name was "clustered-shared", it would search
62493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'.
63493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow *
64493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * 'dm-exception-store-<type_name>' is too long of a name in my
65493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * opinion, which is why I've chosen to have the files
66493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * containing exception store implementations be 'dm-exstore-<type_name>'.
67493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * If you want your module to be autoloaded, you will follow this
68493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * naming convention.
69493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow *
70493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Returns: dm_exception_store_type* on success, NULL on failure
71493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow */
72493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic struct dm_exception_store_type *get_type(const char *type_name)
73493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
74493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	char *p, *type_name_dup;
75493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	struct dm_exception_store_type *type;
76493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
77493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	type = _get_exception_store_type(type_name);
78493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (type)
79493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		return type;
80493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
81493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	type_name_dup = kstrdup(type_name, GFP_KERNEL);
82493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (!type_name_dup) {
83493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		DMERR("No memory left to attempt load for \"%s\"", type_name);
84493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		return NULL;
85493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
86493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
87493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	while (request_module("dm-exstore-%s", type_name_dup) ||
88493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	       !(type = _get_exception_store_type(type_name))) {
89493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		p = strrchr(type_name_dup, '-');
90493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		if (!p)
91493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow			break;
92493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		p[0] = '\0';
93493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
94493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
95493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (!type)
96493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		DMWARN("Module for exstore type \"%s\" not found.", type_name);
97493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
98493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	kfree(type_name_dup);
99493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
100493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return type;
101493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
102493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
103493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic void put_type(struct dm_exception_store_type *type)
104493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
105493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_lock(&_lock);
106493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	module_put(type->module);
107493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_unlock(&_lock);
108493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
109493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
110493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowint dm_exception_store_type_register(struct dm_exception_store_type *type)
111493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
112493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	int r = 0;
113493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
114493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_lock(&_lock);
115493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (!__find_exception_store_type(type->name))
116493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		list_add(&type->list, &_exception_store_types);
117493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	else
118493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		r = -EEXIST;
119493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_unlock(&_lock);
120493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
121493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return r;
122493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
123493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_type_register);
124493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
125493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowint dm_exception_store_type_unregister(struct dm_exception_store_type *type)
126493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
127493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_lock(&_lock);
128493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
129493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (!__find_exception_store_type(type->name)) {
130493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		spin_unlock(&_lock);
131493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		return -EINVAL;
132493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
133493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
134493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	list_del(&type->list);
135493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
136493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_unlock(&_lock);
137493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
138493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return 0;
139493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
140493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_type_unregister);
141493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
142fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowstatic int set_chunk_size(struct dm_exception_store *store,
143fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow			  const char *chunk_size_arg, char **error)
144fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow{
1451a66a08ae82b16eb40705ad112ff28873981af92majianpeng	unsigned chunk_size;
146fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
1471a66a08ae82b16eb40705ad112ff28873981af92majianpeng	if (kstrtouint(chunk_size_arg, 10, &chunk_size)) {
148fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		*error = "Invalid chunk size";
149fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
150fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
151fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
1521a66a08ae82b16eb40705ad112ff28873981af92majianpeng	if (!chunk_size) {
153fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
154fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return 0;
155fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
156fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
1571a66a08ae82b16eb40705ad112ff28873981af92majianpeng	return dm_exception_store_set_chunk_size(store, chunk_size, error);
1582defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka}
1592defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka
1602defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patockaint dm_exception_store_set_chunk_size(struct dm_exception_store *store,
161df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka				      unsigned chunk_size,
1622defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka				      char **error)
1632defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka{
164fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	/* Check chunk_size is a power of 2 */
165df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	if (!is_power_of_2(chunk_size)) {
166fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		*error = "Chunk size is not a power of 2";
167fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
168fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
169fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
170fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	/* Validate the chunk size against the device block size */
171fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	if (chunk_size %
172c24110450650f17f7d3ba4fbe01f01ac5a115456Mikulas Patocka	    (bdev_logical_block_size(dm_snap_cow(store->snap)->bdev) >> 9) ||
173c24110450650f17f7d3ba4fbe01f01ac5a115456Mikulas Patocka	    chunk_size %
174c24110450650f17f7d3ba4fbe01f01ac5a115456Mikulas Patocka	    (bdev_logical_block_size(dm_snap_origin(store->snap)->bdev) >> 9)) {
175fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		*error = "Chunk size is not a multiple of device blocksize";
176fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
177fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
178fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
179df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	if (chunk_size > INT_MAX >> SECTOR_SHIFT) {
180ae0b7448e91353ea5f821601a055aca6b58042cdMikulas Patocka		*error = "Chunk size is too high";
181ae0b7448e91353ea5f821601a055aca6b58042cdMikulas Patocka		return -EINVAL;
182ae0b7448e91353ea5f821601a055aca6b58042cdMikulas Patocka	}
183ae0b7448e91353ea5f821601a055aca6b58042cdMikulas Patocka
184df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	store->chunk_size = chunk_size;
185df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	store->chunk_mask = chunk_size - 1;
186df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	store->chunk_shift = ffs(chunk_size) - 1;
187fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
188fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	return 0;
189fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow}
190fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
191fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowint dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
192fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer			      struct dm_snapshot *snap,
193fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow			      unsigned *args_used,
194493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow			      struct dm_exception_store **store)
195493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
196493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	int r = 0;
197874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	struct dm_exception_store_type *type = NULL;
198493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	struct dm_exception_store *tmp_store;
199fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	char persistent;
200fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
201fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	if (argc < 2) {
202fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Insufficient exception store arguments";
203fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
204fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
205493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
206493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL);
207fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (!tmp_store) {
208fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Exception store allocation failed";
209493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		return -ENOMEM;
210fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
211493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
212fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	persistent = toupper(*argv[0]);
213874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	if (persistent == 'P')
214874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz		type = get_type("P");
215874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	else if (persistent == 'N')
216874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz		type = get_type("N");
217874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	else {
218fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Persistent flag is not P or N";
219613978f8711c7fd4d0aa856872375d2abd7c92ffJulia Lawall		r = -EINVAL;
220613978f8711c7fd4d0aa856872375d2abd7c92ffJulia Lawall		goto bad_type;
221493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
222493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
223fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (!type) {
224fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Exception store type not recognised";
225fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		r = -EINVAL;
226fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		goto bad_type;
227fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
228fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
229493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	tmp_store->type = type;
230fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	tmp_store->snap = snap;
231493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
232fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	r = set_chunk_size(tmp_store, argv[1], &ti->error);
233fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (r)
234fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer		goto bad;
23549beb2b87a972a994ff77633234ca3bf0d30a1d8Jonathan Brassow
236493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	r = type->ctr(tmp_store, 0, NULL);
237493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (r) {
238fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Exception store type constructor failed";
239fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer		goto bad;
240493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
241493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
242fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	*args_used = 2;
243493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	*store = tmp_store;
244493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return 0;
245fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
246fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzerbad:
247fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	put_type(type);
248fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowbad_type:
249fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	kfree(tmp_store);
250fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	return r;
251493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
252493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_create);
253493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
254493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowvoid dm_exception_store_destroy(struct dm_exception_store *store)
255493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
256493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	store->type->dtr(store);
257493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	put_type(store->type);
258493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	kfree(store);
259493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
260493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_destroy);
261493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
2624db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonint dm_exception_store_init(void)
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int r;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2664db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	r = dm_transient_snapshot_init();
2674db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	if (r) {
2684db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		DMERR("Unable to register transient exception store type.");
2694db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		goto transient_fail;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2724db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	r = dm_persistent_snapshot_init();
2734db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	if (r) {
2744db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		DMERR("Unable to register persistent exception store type");
2754db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		goto persistent_fail;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2804db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonpersistent_fail:
281aadbe266f2f89ccc68b52f4effc7b3a8b29521efAndrei Warkentin	dm_transient_snapshot_exit();
2824db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergontransient_fail:
2834db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	return r;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2864db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonvoid dm_exception_store_exit(void)
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2884db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	dm_persistent_snapshot_exit();
2894db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	dm_transient_snapshot_exit();
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
291