Blame view

drivers/md/dm-exception-store.c 6.42 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
   * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
4db6bfe02   Alasdair G Kergon   dm snapshot: spli...
3
   * Copyright (C) 2006-2008 Red Hat GmbH
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
   *
   * This file is released under the GPL.
   */
aea53d92f   Jonathan Brassow   dm snapshot: sepa...
7
  #include "dm-exception-store.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8

fee1998e9   Jonathan Brassow   dm snapshot: move...
9
  #include <linux/ctype.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
  #include <linux/mm.h>
  #include <linux/pagemap.h>
  #include <linux/vmalloc.h>
056075c76   Paul Gortmaker   md: Add module.h ...
13
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15

4db6bfe02   Alasdair G Kergon   dm snapshot: spli...
16
  #define DM_MSG_PREFIX "snapshot exception stores"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17

493df71c6   Jonathan Brassow   dm exception stor...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  static LIST_HEAD(_exception_store_types);
  static DEFINE_SPINLOCK(_lock);
  
  static struct dm_exception_store_type *__find_exception_store_type(const char *name)
  {
  	struct dm_exception_store_type *type;
  
  	list_for_each_entry(type, &_exception_store_types, list)
  		if (!strcmp(name, type->name))
  			return type;
  
  	return NULL;
  }
  
  static struct dm_exception_store_type *_get_exception_store_type(const char *name)
  {
  	struct dm_exception_store_type *type;
  
  	spin_lock(&_lock);
  
  	type = __find_exception_store_type(name);
  
  	if (type && !try_module_get(type->module))
  		type = NULL;
  
  	spin_unlock(&_lock);
  
  	return type;
  }
  
  /*
   * get_type
   * @type_name
   *
   * Attempt to retrieve the dm_exception_store_type by name.  If not already
   * available, attempt to load the appropriate module.
   *
   * Exstore modules are named "dm-exstore-" followed by the 'type_name'.
   * Modules may contain multiple types.
   * This function will first try the module "dm-exstore-<type_name>",
   * then truncate 'type_name' on the last '-' and try again.
   *
   * For example, if type_name was "clustered-shared", it would search
   * 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'.
   *
   * 'dm-exception-store-<type_name>' is too long of a name in my
   * opinion, which is why I've chosen to have the files
   * containing exception store implementations be 'dm-exstore-<type_name>'.
   * If you want your module to be autoloaded, you will follow this
   * naming convention.
   *
   * Returns: dm_exception_store_type* on success, NULL on failure
   */
  static struct dm_exception_store_type *get_type(const char *type_name)
  {
  	char *p, *type_name_dup;
  	struct dm_exception_store_type *type;
  
  	type = _get_exception_store_type(type_name);
  	if (type)
  		return type;
  
  	type_name_dup = kstrdup(type_name, GFP_KERNEL);
  	if (!type_name_dup) {
  		DMERR("No memory left to attempt load for \"%s\"", type_name);
  		return NULL;
  	}
  
  	while (request_module("dm-exstore-%s", type_name_dup) ||
  	       !(type = _get_exception_store_type(type_name))) {
  		p = strrchr(type_name_dup, '-');
  		if (!p)
  			break;
  		p[0] = '\0';
  	}
  
  	if (!type)
  		DMWARN("Module for exstore type \"%s\" not found.", type_name);
  
  	kfree(type_name_dup);
  
  	return type;
  }
  
  static void put_type(struct dm_exception_store_type *type)
  {
  	spin_lock(&_lock);
  	module_put(type->module);
  	spin_unlock(&_lock);
  }
  
  int dm_exception_store_type_register(struct dm_exception_store_type *type)
  {
  	int r = 0;
  
  	spin_lock(&_lock);
  	if (!__find_exception_store_type(type->name))
  		list_add(&type->list, &_exception_store_types);
  	else
  		r = -EEXIST;
  	spin_unlock(&_lock);
  
  	return r;
  }
  EXPORT_SYMBOL(dm_exception_store_type_register);
  
  int dm_exception_store_type_unregister(struct dm_exception_store_type *type)
  {
  	spin_lock(&_lock);
  
  	if (!__find_exception_store_type(type->name)) {
  		spin_unlock(&_lock);
  		return -EINVAL;
  	}
  
  	list_del(&type->list);
  
  	spin_unlock(&_lock);
  
  	return 0;
  }
  EXPORT_SYMBOL(dm_exception_store_type_unregister);
fee1998e9   Jonathan Brassow   dm snapshot: move...
140
141
142
  static int set_chunk_size(struct dm_exception_store *store,
  			  const char *chunk_size_arg, char **error)
  {
1a66a08ae   majianpeng   dm: replace simpl...
143
  	unsigned chunk_size;
fee1998e9   Jonathan Brassow   dm snapshot: move...
144

1a66a08ae   majianpeng   dm: replace simpl...
145
  	if (kstrtouint(chunk_size_arg, 10, &chunk_size)) {
fee1998e9   Jonathan Brassow   dm snapshot: move...
146
147
148
  		*error = "Invalid chunk size";
  		return -EINVAL;
  	}
1a66a08ae   majianpeng   dm: replace simpl...
149
  	if (!chunk_size) {
fee1998e9   Jonathan Brassow   dm snapshot: move...
150
151
152
  		store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
  		return 0;
  	}
1a66a08ae   majianpeng   dm: replace simpl...
153
  	return dm_exception_store_set_chunk_size(store, chunk_size, error);
2defcc3fb   Mikulas Patocka   dm exception stor...
154
155
156
  }
  
  int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
df96eee67   Mikulas Patocka   dm snapshot: use ...
157
  				      unsigned chunk_size,
2defcc3fb   Mikulas Patocka   dm exception stor...
158
159
  				      char **error)
  {
fee1998e9   Jonathan Brassow   dm snapshot: move...
160
  	/* Check chunk_size is a power of 2 */
df96eee67   Mikulas Patocka   dm snapshot: use ...
161
  	if (!is_power_of_2(chunk_size)) {
fee1998e9   Jonathan Brassow   dm snapshot: move...
162
163
164
165
166
  		*error = "Chunk size is not a power of 2";
  		return -EINVAL;
  	}
  
  	/* Validate the chunk size against the device block size */
fc56f6fbc   Mike Snitzer   dm snapshot: move...
167
  	if (chunk_size %
c24110450   Mikulas Patocka   dm snapshot: test...
168
169
170
  	    (bdev_logical_block_size(dm_snap_cow(store->snap)->bdev) >> 9) ||
  	    chunk_size %
  	    (bdev_logical_block_size(dm_snap_origin(store->snap)->bdev) >> 9)) {
fee1998e9   Jonathan Brassow   dm snapshot: move...
171
172
173
  		*error = "Chunk size is not a multiple of device blocksize";
  		return -EINVAL;
  	}
df96eee67   Mikulas Patocka   dm snapshot: use ...
174
  	if (chunk_size > INT_MAX >> SECTOR_SHIFT) {
ae0b7448e   Mikulas Patocka   dm snapshot: fix ...
175
176
177
  		*error = "Chunk size is too high";
  		return -EINVAL;
  	}
df96eee67   Mikulas Patocka   dm snapshot: use ...
178
179
  	store->chunk_size = chunk_size;
  	store->chunk_mask = chunk_size - 1;
a3d939ae7   Mikulas Patocka   dm: convert ffs t...
180
  	store->chunk_shift = __ffs(chunk_size);
fee1998e9   Jonathan Brassow   dm snapshot: move...
181
182
183
184
185
  
  	return 0;
  }
  
  int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
fc56f6fbc   Mike Snitzer   dm snapshot: move...
186
  			      struct dm_snapshot *snap,
fee1998e9   Jonathan Brassow   dm snapshot: move...
187
  			      unsigned *args_used,
493df71c6   Jonathan Brassow   dm exception stor...
188
189
190
  			      struct dm_exception_store **store)
  {
  	int r = 0;
874d2f61d   Milan Broz   dm exception stor...
191
  	struct dm_exception_store_type *type = NULL;
493df71c6   Jonathan Brassow   dm exception stor...
192
  	struct dm_exception_store *tmp_store;
fee1998e9   Jonathan Brassow   dm snapshot: move...
193
  	char persistent;
fc56f6fbc   Mike Snitzer   dm snapshot: move...
194
  	if (argc < 2) {
fee1998e9   Jonathan Brassow   dm snapshot: move...
195
196
197
  		ti->error = "Insufficient exception store arguments";
  		return -EINVAL;
  	}
493df71c6   Jonathan Brassow   dm exception stor...
198

b0d3cc011   Mike Snitzer   dm snapshot: add ...
199
  	tmp_store = kzalloc(sizeof(*tmp_store), GFP_KERNEL);
fee1998e9   Jonathan Brassow   dm snapshot: move...
200
201
  	if (!tmp_store) {
  		ti->error = "Exception store allocation failed";
493df71c6   Jonathan Brassow   dm exception stor...
202
  		return -ENOMEM;
fee1998e9   Jonathan Brassow   dm snapshot: move...
203
  	}
493df71c6   Jonathan Brassow   dm exception stor...
204

fc56f6fbc   Mike Snitzer   dm snapshot: move...
205
  	persistent = toupper(*argv[0]);
874d2f61d   Milan Broz   dm exception stor...
206
207
208
209
210
  	if (persistent == 'P')
  		type = get_type("P");
  	else if (persistent == 'N')
  		type = get_type("N");
  	else {
b0d3cc011   Mike Snitzer   dm snapshot: add ...
211
  		ti->error = "Exception store type is not P or N";
613978f87   Julia Lawall   dm exception stor...
212
213
  		r = -EINVAL;
  		goto bad_type;
493df71c6   Jonathan Brassow   dm exception stor...
214
  	}
fee1998e9   Jonathan Brassow   dm snapshot: move...
215
216
217
218
219
  	if (!type) {
  		ti->error = "Exception store type not recognised";
  		r = -EINVAL;
  		goto bad_type;
  	}
493df71c6   Jonathan Brassow   dm exception stor...
220
  	tmp_store->type = type;
fc56f6fbc   Mike Snitzer   dm snapshot: move...
221
  	tmp_store->snap = snap;
493df71c6   Jonathan Brassow   dm exception stor...
222

fc56f6fbc   Mike Snitzer   dm snapshot: move...
223
  	r = set_chunk_size(tmp_store, argv[1], &ti->error);
fee1998e9   Jonathan Brassow   dm snapshot: move...
224
  	if (r)
fc56f6fbc   Mike Snitzer   dm snapshot: move...
225
  		goto bad;
49beb2b87   Jonathan Brassow   dm exception stor...
226

b0d3cc011   Mike Snitzer   dm snapshot: add ...
227
  	r = type->ctr(tmp_store, (strlen(argv[0]) > 1 ? &argv[0][1] : NULL));
493df71c6   Jonathan Brassow   dm exception stor...
228
  	if (r) {
fee1998e9   Jonathan Brassow   dm snapshot: move...
229
  		ti->error = "Exception store type constructor failed";
fc56f6fbc   Mike Snitzer   dm snapshot: move...
230
  		goto bad;
493df71c6   Jonathan Brassow   dm exception stor...
231
  	}
fc56f6fbc   Mike Snitzer   dm snapshot: move...
232
  	*args_used = 2;
493df71c6   Jonathan Brassow   dm exception stor...
233
234
  	*store = tmp_store;
  	return 0;
fee1998e9   Jonathan Brassow   dm snapshot: move...
235

fc56f6fbc   Mike Snitzer   dm snapshot: move...
236
  bad:
fee1998e9   Jonathan Brassow   dm snapshot: move...
237
238
239
240
  	put_type(type);
  bad_type:
  	kfree(tmp_store);
  	return r;
493df71c6   Jonathan Brassow   dm exception stor...
241
242
243
244
245
246
247
248
249
250
  }
  EXPORT_SYMBOL(dm_exception_store_create);
  
  void dm_exception_store_destroy(struct dm_exception_store *store)
  {
  	store->type->dtr(store);
  	put_type(store->type);
  	kfree(store);
  }
  EXPORT_SYMBOL(dm_exception_store_destroy);
4db6bfe02   Alasdair G Kergon   dm snapshot: spli...
251
  int dm_exception_store_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
  {
  	int r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254

4db6bfe02   Alasdair G Kergon   dm snapshot: spli...
255
256
257
258
  	r = dm_transient_snapshot_init();
  	if (r) {
  		DMERR("Unable to register transient exception store type.");
  		goto transient_fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  	}
4db6bfe02   Alasdair G Kergon   dm snapshot: spli...
260
261
262
263
  	r = dm_persistent_snapshot_init();
  	if (r) {
  		DMERR("Unable to register persistent exception store type");
  		goto persistent_fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
  	}
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267

4db6bfe02   Alasdair G Kergon   dm snapshot: spli...
268
  persistent_fail:
aadbe266f   Andrei Warkentin   dm exception stor...
269
  	dm_transient_snapshot_exit();
4db6bfe02   Alasdair G Kergon   dm snapshot: spli...
270
271
  transient_fail:
  	return r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  }
4db6bfe02   Alasdair G Kergon   dm snapshot: spli...
273
  void dm_exception_store_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  {
4db6bfe02   Alasdair G Kergon   dm snapshot: spli...
275
276
  	dm_persistent_snapshot_exit();
  	dm_transient_snapshot_exit();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  }