aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-exception-store.c
diff options
context:
space:
mode:
authorJonathan Brassow <jbrassow@redhat.com>2009-04-02 14:55:34 -0400
committerAlasdair G Kergon <agk@redhat.com>2009-04-02 14:55:34 -0400
commitfee1998e9c690f9920671e1e0ef187a48cfbbde4 (patch)
treea217e9bc2142350d9e8065c6e581be0524636498 /drivers/md/dm-exception-store.c
parent2e4a31df2b10cbcaf43c333112f6f7440a035c69 (diff)
dm snapshot: move ctr parsing to exception store
First step of having the exception stores parse their own arguments - generalizing the interface. Signed-off-by: Jonathan Brassow <jbrassow@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/dm-exception-store.c')
-rw-r--r--drivers/md/dm-exception-store.c109
1 files changed, 95 insertions, 14 deletions
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 2078b92470a1..a2e26c242141 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -7,6 +7,7 @@
7 7
8#include "dm-exception-store.h" 8#include "dm-exception-store.h"
9 9
10#include <linux/ctype.h>
10#include <linux/mm.h> 11#include <linux/mm.h>
11#include <linux/pagemap.h> 12#include <linux/pagemap.h>
12#include <linux/vmalloc.h> 13#include <linux/vmalloc.h>
@@ -137,49 +138,129 @@ int dm_exception_store_type_unregister(struct dm_exception_store_type *type)
137} 138}
138EXPORT_SYMBOL(dm_exception_store_type_unregister); 139EXPORT_SYMBOL(dm_exception_store_type_unregister);
139 140
140int dm_exception_store_create(const char *type_name, struct dm_target *ti, 141/*
141 chunk_t chunk_size, chunk_t chunk_mask, 142 * Round a number up to the nearest 'size' boundary. size must
142 chunk_t chunk_shift, struct dm_dev *cow, 143 * be a power of 2.
144 */
145static ulong round_up(ulong n, ulong size)
146{
147 size--;
148 return (n + size) & ~size;
149}
150
151static int set_chunk_size(struct dm_exception_store *store,
152 const char *chunk_size_arg, char **error)
153{
154 unsigned long chunk_size_ulong;
155 char *value;
156
157 chunk_size_ulong = simple_strtoul(chunk_size_arg, &value, 10);
158 if (*chunk_size_arg == '\0' || *value != '\0') {
159 *error = "Invalid chunk size";
160 return -EINVAL;
161 }
162
163 if (!chunk_size_ulong) {
164 store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
165 return 0;
166 }
167
168 /*
169 * Chunk size must be multiple of page size. Silently
170 * round up if it's not.
171 */
172 chunk_size_ulong = round_up(chunk_size_ulong, PAGE_SIZE >> 9);
173
174 /* Check chunk_size is a power of 2 */
175 if (!is_power_of_2(chunk_size_ulong)) {
176 *error = "Chunk size is not a power of 2";
177 return -EINVAL;
178 }
179
180 /* Validate the chunk size against the device block size */
181 if (chunk_size_ulong % (bdev_hardsect_size(store->cow->bdev) >> 9)) {
182 *error = "Chunk size is not a multiple of device blocksize";
183 return -EINVAL;
184 }
185
186 store->chunk_size = chunk_size_ulong;
187 store->chunk_mask = chunk_size_ulong - 1;
188 store->chunk_shift = ffs(chunk_size_ulong) - 1;
189
190 return 0;
191}
192
193int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
194 unsigned *args_used,
143 struct dm_exception_store **store) 195 struct dm_exception_store **store)
144{ 196{
145 int r = 0; 197 int r = 0;
146 struct dm_exception_store_type *type; 198 struct dm_exception_store_type *type;
147 struct dm_exception_store *tmp_store; 199 struct dm_exception_store *tmp_store;
200 char persistent;
201
202 if (argc < 3) {
203 ti->error = "Insufficient exception store arguments";
204 return -EINVAL;
205 }
148 206
149 tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL); 207 tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL);
150 if (!tmp_store) 208 if (!tmp_store) {
209 ti->error = "Exception store allocation failed";
151 return -ENOMEM; 210 return -ENOMEM;
211 }
152 212
153 type = get_type(type_name); 213 persistent = toupper(*argv[1]);
154 if (!type) { 214 if (persistent != 'P' && persistent != 'N') {
155 kfree(tmp_store); 215 ti->error = "Persistent flag is not P or N";
156 return -EINVAL; 216 return -EINVAL;
157 } 217 }
158 218
219 type = get_type(argv[1]);
220 if (!type) {
221 ti->error = "Exception store type not recognised";
222 r = -EINVAL;
223 goto bad_type;
224 }
225
159 tmp_store->type = type; 226 tmp_store->type = type;
160 tmp_store->ti = ti; 227 tmp_store->ti = ti;
161 228
162 tmp_store->chunk_size = chunk_size; 229 r = dm_get_device(ti, argv[0], 0, 0,
163 tmp_store->chunk_mask = chunk_mask; 230 FMODE_READ | FMODE_WRITE, &tmp_store->cow);
164 tmp_store->chunk_shift = chunk_shift; 231 if (r) {
232 ti->error = "Cannot get COW device";
233 goto bad_cow;
234 }
165 235
166 tmp_store->cow = cow; 236 r = set_chunk_size(tmp_store, argv[2], &ti->error);
237 if (r)
238 goto bad_cow;
167 239
168 r = type->ctr(tmp_store, 0, NULL); 240 r = type->ctr(tmp_store, 0, NULL);
169 if (r) { 241 if (r) {
170 put_type(type); 242 ti->error = "Exception store type constructor failed";
171 kfree(tmp_store); 243 goto bad_ctr;
172 return r;
173 } 244 }
174 245
246 *args_used = 3;
175 *store = tmp_store; 247 *store = tmp_store;
176 return 0; 248 return 0;
249
250bad_ctr:
251 dm_put_device(ti, tmp_store->cow);
252bad_cow:
253 put_type(type);
254bad_type:
255 kfree(tmp_store);
256 return r;
177} 257}
178EXPORT_SYMBOL(dm_exception_store_create); 258EXPORT_SYMBOL(dm_exception_store_create);
179 259
180void dm_exception_store_destroy(struct dm_exception_store *store) 260void dm_exception_store_destroy(struct dm_exception_store *store)
181{ 261{
182 store->type->dtr(store); 262 store->type->dtr(store);
263 dm_put_device(store->ti, store->cow);
183 put_type(store->type); 264 put_type(store->type);
184 kfree(store); 265 kfree(store);
185} 266}