diff options
author | Jonathan Brassow <jbrassow@redhat.com> | 2009-04-02 14:55:34 -0400 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2009-04-02 14:55:34 -0400 |
commit | fee1998e9c690f9920671e1e0ef187a48cfbbde4 (patch) | |
tree | a217e9bc2142350d9e8065c6e581be0524636498 /drivers/md/dm-exception-store.c | |
parent | 2e4a31df2b10cbcaf43c333112f6f7440a035c69 (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.c | 109 |
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 | } |
138 | EXPORT_SYMBOL(dm_exception_store_type_unregister); | 139 | EXPORT_SYMBOL(dm_exception_store_type_unregister); |
139 | 140 | ||
140 | int 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 | */ | ||
145 | static ulong round_up(ulong n, ulong size) | ||
146 | { | ||
147 | size--; | ||
148 | return (n + size) & ~size; | ||
149 | } | ||
150 | |||
151 | static 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 | |||
193 | int 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 | |||
250 | bad_ctr: | ||
251 | dm_put_device(ti, tmp_store->cow); | ||
252 | bad_cow: | ||
253 | put_type(type); | ||
254 | bad_type: | ||
255 | kfree(tmp_store); | ||
256 | return r; | ||
177 | } | 257 | } |
178 | EXPORT_SYMBOL(dm_exception_store_create); | 258 | EXPORT_SYMBOL(dm_exception_store_create); |
179 | 259 | ||
180 | void dm_exception_store_destroy(struct dm_exception_store *store) | 260 | void 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 | } |