dm-exception-store.c revision c24110450650f17f7d3ba4fbe01f01ac5a115456
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>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
164db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon#define DM_MSG_PREFIX "snapshot exception stores"
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic LIST_HEAD(_exception_store_types);
19493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic DEFINE_SPINLOCK(_lock);
20493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
21493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic struct dm_exception_store_type *__find_exception_store_type(const char *name)
22493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
23493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	struct dm_exception_store_type *type;
24493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
25493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	list_for_each_entry(type, &_exception_store_types, list)
26493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		if (!strcmp(name, type->name))
27493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow			return type;
28493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
29493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return NULL;
30493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
31493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
32493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic struct dm_exception_store_type *_get_exception_store_type(const char *name)
33493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
34493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	struct dm_exception_store_type *type;
35493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
36493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_lock(&_lock);
37493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
38493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	type = __find_exception_store_type(name);
39493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
40493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (type && !try_module_get(type->module))
41493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		type = NULL;
42493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
43493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_unlock(&_lock);
44493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
45493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return type;
46493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
47493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
48493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow/*
49493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * get_type
50493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * @type_name
51493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow *
52493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Attempt to retrieve the dm_exception_store_type by name.  If not already
53493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * available, attempt to load the appropriate module.
54493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow *
55493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Exstore modules are named "dm-exstore-" followed by the 'type_name'.
56493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Modules may contain multiple types.
57493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * This function will first try the module "dm-exstore-<type_name>",
58493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * then truncate 'type_name' on the last '-' and try again.
59493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow *
60493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * For example, if type_name was "clustered-shared", it would search
61493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'.
62493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow *
63493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * 'dm-exception-store-<type_name>' is too long of a name in my
64493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * opinion, which is why I've chosen to have the files
65493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * containing exception store implementations be 'dm-exstore-<type_name>'.
66493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * If you want your module to be autoloaded, you will follow this
67493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * naming convention.
68493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow *
69493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow * Returns: dm_exception_store_type* on success, NULL on failure
70493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow */
71493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic struct dm_exception_store_type *get_type(const char *type_name)
72493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
73493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	char *p, *type_name_dup;
74493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	struct dm_exception_store_type *type;
75493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
76493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	type = _get_exception_store_type(type_name);
77493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (type)
78493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		return type;
79493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
80493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	type_name_dup = kstrdup(type_name, GFP_KERNEL);
81493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (!type_name_dup) {
82493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		DMERR("No memory left to attempt load for \"%s\"", type_name);
83493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		return NULL;
84493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
85493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
86493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	while (request_module("dm-exstore-%s", type_name_dup) ||
87493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	       !(type = _get_exception_store_type(type_name))) {
88493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		p = strrchr(type_name_dup, '-');
89493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		if (!p)
90493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow			break;
91493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		p[0] = '\0';
92493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
93493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
94493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (!type)
95493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		DMWARN("Module for exstore type \"%s\" not found.", type_name);
96493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
97493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	kfree(type_name_dup);
98493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
99493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return type;
100493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
101493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
102493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowstatic void put_type(struct dm_exception_store_type *type)
103493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
104493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_lock(&_lock);
105493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	module_put(type->module);
106493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_unlock(&_lock);
107493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
108493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
109493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowint dm_exception_store_type_register(struct dm_exception_store_type *type)
110493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
111493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	int r = 0;
112493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
113493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_lock(&_lock);
114493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (!__find_exception_store_type(type->name))
115493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		list_add(&type->list, &_exception_store_types);
116493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	else
117493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		r = -EEXIST;
118493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_unlock(&_lock);
119493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
120493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return r;
121493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
122493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_type_register);
123493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
124493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowint dm_exception_store_type_unregister(struct dm_exception_store_type *type)
125493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
126493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_lock(&_lock);
127493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
128493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (!__find_exception_store_type(type->name)) {
129493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		spin_unlock(&_lock);
130493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		return -EINVAL;
131493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
132493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
133493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	list_del(&type->list);
134493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
135493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	spin_unlock(&_lock);
136493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
137493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return 0;
138493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
139493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_type_unregister);
140493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
141fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowstatic int set_chunk_size(struct dm_exception_store *store,
142fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow			  const char *chunk_size_arg, char **error)
143fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow{
144fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	unsigned long chunk_size_ulong;
145fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	char *value;
146fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
147fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	chunk_size_ulong = simple_strtoul(chunk_size_arg, &value, 10);
148df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	if (*chunk_size_arg == '\0' || *value != '\0' ||
149df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	    chunk_size_ulong > UINT_MAX) {
150fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		*error = "Invalid chunk size";
151fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
152fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
153fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
154fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (!chunk_size_ulong) {
155fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
156fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return 0;
157fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
158fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
159df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	return dm_exception_store_set_chunk_size(store,
160df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka						 (unsigned) chunk_size_ulong,
1612defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka						 error);
1622defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka}
1632defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka
1642defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patockaint dm_exception_store_set_chunk_size(struct dm_exception_store *store,
165df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka				      unsigned chunk_size,
1662defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka				      char **error)
1672defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka{
168fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	/* Check chunk_size is a power of 2 */
169df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	if (!is_power_of_2(chunk_size)) {
170fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		*error = "Chunk size is not a power of 2";
171fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
172fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
173fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
174fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	/* Validate the chunk size against the device block size */
175fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	if (chunk_size %
176c24110450650f17f7d3ba4fbe01f01ac5a115456Mikulas Patocka	    (bdev_logical_block_size(dm_snap_cow(store->snap)->bdev) >> 9) ||
177c24110450650f17f7d3ba4fbe01f01ac5a115456Mikulas Patocka	    chunk_size %
178c24110450650f17f7d3ba4fbe01f01ac5a115456Mikulas Patocka	    (bdev_logical_block_size(dm_snap_origin(store->snap)->bdev) >> 9)) {
179fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		*error = "Chunk size is not a multiple of device blocksize";
180fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
181fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
182fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
183df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	if (chunk_size > INT_MAX >> SECTOR_SHIFT) {
184ae0b7448e91353ea5f821601a055aca6b58042cdMikulas Patocka		*error = "Chunk size is too high";
185ae0b7448e91353ea5f821601a055aca6b58042cdMikulas Patocka		return -EINVAL;
186ae0b7448e91353ea5f821601a055aca6b58042cdMikulas Patocka	}
187ae0b7448e91353ea5f821601a055aca6b58042cdMikulas Patocka
188df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	store->chunk_size = chunk_size;
189df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	store->chunk_mask = chunk_size - 1;
190df96eee679ba28c98cf722fa7c9f4286ee1ed0bdMikulas Patocka	store->chunk_shift = ffs(chunk_size) - 1;
191fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
192fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	return 0;
193fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow}
194fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
195fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowint dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
196fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer			      struct dm_snapshot *snap,
197fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow			      unsigned *args_used,
198493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow			      struct dm_exception_store **store)
199493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
200493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	int r = 0;
201874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	struct dm_exception_store_type *type = NULL;
202493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	struct dm_exception_store *tmp_store;
203fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	char persistent;
204fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
205fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	if (argc < 2) {
206fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Insufficient exception store arguments";
207fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
208fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
209493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
210493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL);
211fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (!tmp_store) {
212fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Exception store allocation failed";
213493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		return -ENOMEM;
214fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
215493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
216fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	persistent = toupper(*argv[0]);
217874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	if (persistent == 'P')
218874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz		type = get_type("P");
219874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	else if (persistent == 'N')
220874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz		type = get_type("N");
221874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	else {
222fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Persistent flag is not P or N";
223613978f8711c7fd4d0aa856872375d2abd7c92ffJulia Lawall		r = -EINVAL;
224613978f8711c7fd4d0aa856872375d2abd7c92ffJulia Lawall		goto bad_type;
225493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
226493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
227fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (!type) {
228fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Exception store type not recognised";
229fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		r = -EINVAL;
230fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		goto bad_type;
231fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
232fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
233493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	tmp_store->type = type;
234fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	tmp_store->snap = snap;
235493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
236fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	r = set_chunk_size(tmp_store, argv[1], &ti->error);
237fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (r)
238fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer		goto bad;
23949beb2b87a972a994ff77633234ca3bf0d30a1d8Jonathan Brassow
240493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	r = type->ctr(tmp_store, 0, NULL);
241493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (r) {
242fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Exception store type constructor failed";
243fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer		goto bad;
244493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
245493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
246fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzer	*args_used = 2;
247493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	*store = tmp_store;
248493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return 0;
249fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
250fc56f6fbcca3672c63c93c65f45105faacfc13cbMike Snitzerbad:
251fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	put_type(type);
252fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowbad_type:
253fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	kfree(tmp_store);
254fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	return r;
255493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
256493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_create);
257493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
258493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowvoid dm_exception_store_destroy(struct dm_exception_store *store)
259493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
260493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	store->type->dtr(store);
261493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	put_type(store->type);
262493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	kfree(store);
263493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
264493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_destroy);
265493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
2664db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonint dm_exception_store_init(void)
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int r;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2704db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	r = dm_transient_snapshot_init();
2714db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	if (r) {
2724db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		DMERR("Unable to register transient exception store type.");
2734db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		goto transient_fail;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2764db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	r = dm_persistent_snapshot_init();
2774db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	if (r) {
2784db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		DMERR("Unable to register persistent exception store type");
2794db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		goto persistent_fail;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2844db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonpersistent_fail:
2854db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	dm_persistent_snapshot_exit();
2864db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergontransient_fail:
2874db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	return r;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2904db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonvoid dm_exception_store_exit(void)
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2924db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	dm_persistent_snapshot_exit();
2934db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	dm_transient_snapshot_exit();
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
295