dm-exception-store.c revision 2defcc3fb4661e7351cb2ac48d843efc4c64db13
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 Brassow/*
142fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow * Round a number up to the nearest 'size' boundary.  size must
143fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow * be a power of 2.
144fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow */
145fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowstatic ulong round_up(ulong n, ulong size)
146fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow{
147fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	size--;
148fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	return (n + size) & ~size;
149fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow}
150fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
151fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowstatic int set_chunk_size(struct dm_exception_store *store,
152fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow			  const char *chunk_size_arg, char **error)
153fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow{
154fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	unsigned long chunk_size_ulong;
155fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	char *value;
156fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
157fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	chunk_size_ulong = simple_strtoul(chunk_size_arg, &value, 10);
158fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (*chunk_size_arg == '\0' || *value != '\0') {
159fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		*error = "Invalid chunk size";
160fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
161fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
162fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
163fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (!chunk_size_ulong) {
164fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
165fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return 0;
166fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
167fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
168fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	/*
169fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	 * Chunk size must be multiple of page size.  Silently
170fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	 * round up if it's not.
171fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	 */
172fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	chunk_size_ulong = round_up(chunk_size_ulong, PAGE_SIZE >> 9);
173fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
1742defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka	return dm_exception_store_set_chunk_size(store, chunk_size_ulong,
1752defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka						 error);
1762defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka}
1772defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka
1782defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patockaint dm_exception_store_set_chunk_size(struct dm_exception_store *store,
1792defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka				      unsigned long chunk_size_ulong,
1802defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka				      char **error)
1812defcc3fb4661e7351cb2ac48d843efc4c64db13Mikulas Patocka{
182fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	/* Check chunk_size is a power of 2 */
183fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (!is_power_of_2(chunk_size_ulong)) {
184fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		*error = "Chunk size is not a power of 2";
185fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
186fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
187fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
188fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	/* Validate the chunk size against the device block size */
189e1defc4ff0cf57aca6c5e3ff99fa503f5943c1f1Martin K. Petersen	if (chunk_size_ulong % (bdev_logical_block_size(store->cow->bdev) >> 9)) {
190fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		*error = "Chunk size is not a multiple of device blocksize";
191fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
192fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
193fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
194fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	store->chunk_size = chunk_size_ulong;
195fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	store->chunk_mask = chunk_size_ulong - 1;
196fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	store->chunk_shift = ffs(chunk_size_ulong) - 1;
197fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
198fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	return 0;
199fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow}
200fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
201fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowint dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
202fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow			      unsigned *args_used,
203493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow			      struct dm_exception_store **store)
204493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
205493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	int r = 0;
206874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	struct dm_exception_store_type *type = NULL;
207493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	struct dm_exception_store *tmp_store;
208fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	char persistent;
209fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
210fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (argc < 3) {
211fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Insufficient exception store arguments";
212fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		return -EINVAL;
213fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
214493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
215493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL);
216fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (!tmp_store) {
217fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Exception store allocation failed";
218493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		return -ENOMEM;
219fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
220493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
221fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	persistent = toupper(*argv[1]);
222874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	if (persistent == 'P')
223874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz		type = get_type("P");
224874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	else if (persistent == 'N')
225874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz		type = get_type("N");
226874d2f61d31e596c36af7732dc1b3aa2dc233824Milan Broz	else {
227fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Persistent flag is not P or N";
228493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow		return -EINVAL;
229493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
230493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
231fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (!type) {
232fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Exception store type not recognised";
233fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		r = -EINVAL;
234fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		goto bad_type;
235fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
236fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
237493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	tmp_store->type = type;
2380cea9c78270cdf1d2ad74ce0e083d5555a0842e8Jonathan Brassow	tmp_store->ti = ti;
239493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
240fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	r = dm_get_device(ti, argv[0], 0, 0,
241fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow			  FMODE_READ | FMODE_WRITE, &tmp_store->cow);
242fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (r) {
243fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Cannot get COW device";
244fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		goto bad_cow;
245fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	}
246d0216849519bec8dc96301a3cd80316e71243839Jonathan Brassow
247fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	r = set_chunk_size(tmp_store, argv[2], &ti->error);
248fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	if (r)
249fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		goto bad_cow;
25049beb2b87a972a994ff77633234ca3bf0d30a1d8Jonathan Brassow
251493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	r = type->ctr(tmp_store, 0, NULL);
252493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	if (r) {
253fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		ti->error = "Exception store type constructor failed";
254fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow		goto bad_ctr;
255493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	}
256493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
257fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	*args_used = 3;
258493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	*store = tmp_store;
259493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	return 0;
260fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow
261fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowbad_ctr:
262fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	dm_put_device(ti, tmp_store->cow);
263fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowbad_cow:
264fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	put_type(type);
265fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassowbad_type:
266fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	kfree(tmp_store);
267fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	return r;
268493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
269493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_create);
270493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
271493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassowvoid dm_exception_store_destroy(struct dm_exception_store *store)
272493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow{
273493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	store->type->dtr(store);
274fee1998e9c690f9920671e1e0ef187a48cfbbde4Jonathan Brassow	dm_put_device(store->ti, store->cow);
275493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	put_type(store->type);
276493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow	kfree(store);
277493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow}
278493df71c6420b211a68ae82b889c1e8a5fe701beJonathan BrassowEXPORT_SYMBOL(dm_exception_store_destroy);
279493df71c6420b211a68ae82b889c1e8a5fe701beJonathan Brassow
2804db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonint dm_exception_store_init(void)
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int r;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2844db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	r = dm_transient_snapshot_init();
2854db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	if (r) {
2864db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		DMERR("Unable to register transient exception store type.");
2874db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		goto transient_fail;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2904db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	r = dm_persistent_snapshot_init();
2914db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	if (r) {
2924db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		DMERR("Unable to register persistent exception store type");
2934db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon		goto persistent_fail;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2984db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonpersistent_fail:
2994db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	dm_persistent_snapshot_exit();
3004db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergontransient_fail:
3014db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	return r;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3044db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergonvoid dm_exception_store_exit(void)
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3064db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	dm_persistent_snapshot_exit();
3074db6bfe02bdc7dc5048f46dd682a94801d029adcAlasdair G Kergon	dm_transient_snapshot_exit();
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
309