diff options
Diffstat (limited to 'drivers/md/dm-io.c')
-rw-r--r-- | drivers/md/dm-io.c | 232 |
1 files changed, 133 insertions, 99 deletions
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 8bdc8a87b249..352c6fbeac53 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2003 Sistina Software | 2 | * Copyright (C) 2003 Sistina Software |
3 | * Copyright (C) 2006 Red Hat GmbH | ||
3 | * | 4 | * |
4 | * This file is released under the GPL. | 5 | * This file is released under the GPL. |
5 | */ | 6 | */ |
@@ -12,13 +13,17 @@ | |||
12 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
13 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
14 | 15 | ||
15 | static struct bio_set *_bios; | 16 | struct dm_io_client { |
17 | mempool_t *pool; | ||
18 | struct bio_set *bios; | ||
19 | }; | ||
16 | 20 | ||
17 | /* FIXME: can we shrink this ? */ | 21 | /* FIXME: can we shrink this ? */ |
18 | struct io { | 22 | struct io { |
19 | unsigned long error; | 23 | unsigned long error; |
20 | atomic_t count; | 24 | atomic_t count; |
21 | struct task_struct *sleeper; | 25 | struct task_struct *sleeper; |
26 | struct dm_io_client *client; | ||
22 | io_notify_fn callback; | 27 | io_notify_fn callback; |
23 | void *context; | 28 | void *context; |
24 | }; | 29 | }; |
@@ -26,63 +31,58 @@ struct io { | |||
26 | /* | 31 | /* |
27 | * io contexts are only dynamically allocated for asynchronous | 32 | * io contexts are only dynamically allocated for asynchronous |
28 | * io. Since async io is likely to be the majority of io we'll | 33 | * io. Since async io is likely to be the majority of io we'll |
29 | * have the same number of io contexts as buffer heads ! (FIXME: | 34 | * have the same number of io contexts as bios! (FIXME: must reduce this). |
30 | * must reduce this). | ||
31 | */ | 35 | */ |
32 | static unsigned _num_ios; | ||
33 | static mempool_t *_io_pool; | ||
34 | 36 | ||
35 | static unsigned int pages_to_ios(unsigned int pages) | 37 | static unsigned int pages_to_ios(unsigned int pages) |
36 | { | 38 | { |
37 | return 4 * pages; /* too many ? */ | 39 | return 4 * pages; /* too many ? */ |
38 | } | 40 | } |
39 | 41 | ||
40 | static int resize_pool(unsigned int new_ios) | 42 | /* |
43 | * Create a client with mempool and bioset. | ||
44 | */ | ||
45 | struct dm_io_client *dm_io_client_create(unsigned num_pages) | ||
41 | { | 46 | { |
42 | int r = 0; | 47 | unsigned ios = pages_to_ios(num_pages); |
43 | 48 | struct dm_io_client *client; | |
44 | if (_io_pool) { | ||
45 | if (new_ios == 0) { | ||
46 | /* free off the pool */ | ||
47 | mempool_destroy(_io_pool); | ||
48 | _io_pool = NULL; | ||
49 | bioset_free(_bios); | ||
50 | |||
51 | } else { | ||
52 | /* resize the pool */ | ||
53 | r = mempool_resize(_io_pool, new_ios, GFP_KERNEL); | ||
54 | } | ||
55 | 49 | ||
56 | } else { | 50 | client = kmalloc(sizeof(*client), GFP_KERNEL); |
57 | /* create new pool */ | 51 | if (!client) |
58 | _io_pool = mempool_create_kmalloc_pool(new_ios, | 52 | return ERR_PTR(-ENOMEM); |
59 | sizeof(struct io)); | 53 | |
60 | if (!_io_pool) | 54 | client->pool = mempool_create_kmalloc_pool(ios, sizeof(struct io)); |
61 | return -ENOMEM; | 55 | if (!client->pool) |
62 | 56 | goto bad; | |
63 | _bios = bioset_create(16, 16); | ||
64 | if (!_bios) { | ||
65 | mempool_destroy(_io_pool); | ||
66 | _io_pool = NULL; | ||
67 | return -ENOMEM; | ||
68 | } | ||
69 | } | ||
70 | 57 | ||
71 | if (!r) | 58 | client->bios = bioset_create(16, 16); |
72 | _num_ios = new_ios; | 59 | if (!client->bios) |
60 | goto bad; | ||
73 | 61 | ||
74 | return r; | 62 | return client; |
63 | |||
64 | bad: | ||
65 | if (client->pool) | ||
66 | mempool_destroy(client->pool); | ||
67 | kfree(client); | ||
68 | return ERR_PTR(-ENOMEM); | ||
75 | } | 69 | } |
70 | EXPORT_SYMBOL(dm_io_client_create); | ||
76 | 71 | ||
77 | int dm_io_get(unsigned int num_pages) | 72 | int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client) |
78 | { | 73 | { |
79 | return resize_pool(_num_ios + pages_to_ios(num_pages)); | 74 | return mempool_resize(client->pool, pages_to_ios(num_pages), |
75 | GFP_KERNEL); | ||
80 | } | 76 | } |
77 | EXPORT_SYMBOL(dm_io_client_resize); | ||
81 | 78 | ||
82 | void dm_io_put(unsigned int num_pages) | 79 | void dm_io_client_destroy(struct dm_io_client *client) |
83 | { | 80 | { |
84 | resize_pool(_num_ios - pages_to_ios(num_pages)); | 81 | mempool_destroy(client->pool); |
82 | bioset_free(client->bios); | ||
83 | kfree(client); | ||
85 | } | 84 | } |
85 | EXPORT_SYMBOL(dm_io_client_destroy); | ||
86 | 86 | ||
87 | /*----------------------------------------------------------------- | 87 | /*----------------------------------------------------------------- |
88 | * We need to keep track of which region a bio is doing io for. | 88 | * We need to keep track of which region a bio is doing io for. |
@@ -118,7 +118,7 @@ static void dec_count(struct io *io, unsigned int region, int error) | |||
118 | io_notify_fn fn = io->callback; | 118 | io_notify_fn fn = io->callback; |
119 | void *context = io->context; | 119 | void *context = io->context; |
120 | 120 | ||
121 | mempool_free(io, _io_pool); | 121 | mempool_free(io, io->client->pool); |
122 | fn(r, context); | 122 | fn(r, context); |
123 | } | 123 | } |
124 | } | 124 | } |
@@ -126,7 +126,8 @@ static void dec_count(struct io *io, unsigned int region, int error) | |||
126 | 126 | ||
127 | static int endio(struct bio *bio, unsigned int done, int error) | 127 | static int endio(struct bio *bio, unsigned int done, int error) |
128 | { | 128 | { |
129 | struct io *io = (struct io *) bio->bi_private; | 129 | struct io *io; |
130 | unsigned region; | ||
130 | 131 | ||
131 | /* keep going until we've finished */ | 132 | /* keep going until we've finished */ |
132 | if (bio->bi_size) | 133 | if (bio->bi_size) |
@@ -135,10 +136,17 @@ static int endio(struct bio *bio, unsigned int done, int error) | |||
135 | if (error && bio_data_dir(bio) == READ) | 136 | if (error && bio_data_dir(bio) == READ) |
136 | zero_fill_bio(bio); | 137 | zero_fill_bio(bio); |
137 | 138 | ||
138 | dec_count(io, bio_get_region(bio), error); | 139 | /* |
140 | * The bio destructor in bio_put() may use the io object. | ||
141 | */ | ||
142 | io = bio->bi_private; | ||
143 | region = bio_get_region(bio); | ||
144 | |||
139 | bio->bi_max_vecs++; | 145 | bio->bi_max_vecs++; |
140 | bio_put(bio); | 146 | bio_put(bio); |
141 | 147 | ||
148 | dec_count(io, region, error); | ||
149 | |||
142 | return 0; | 150 | return 0; |
143 | } | 151 | } |
144 | 152 | ||
@@ -209,6 +217,9 @@ static void bvec_dp_init(struct dpages *dp, struct bio_vec *bvec) | |||
209 | dp->context_ptr = bvec; | 217 | dp->context_ptr = bvec; |
210 | } | 218 | } |
211 | 219 | ||
220 | /* | ||
221 | * Functions for getting the pages from a VMA. | ||
222 | */ | ||
212 | static void vm_get_page(struct dpages *dp, | 223 | static void vm_get_page(struct dpages *dp, |
213 | struct page **p, unsigned long *len, unsigned *offset) | 224 | struct page **p, unsigned long *len, unsigned *offset) |
214 | { | 225 | { |
@@ -233,7 +244,34 @@ static void vm_dp_init(struct dpages *dp, void *data) | |||
233 | 244 | ||
234 | static void dm_bio_destructor(struct bio *bio) | 245 | static void dm_bio_destructor(struct bio *bio) |
235 | { | 246 | { |
236 | bio_free(bio, _bios); | 247 | struct io *io = bio->bi_private; |
248 | |||
249 | bio_free(bio, io->client->bios); | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * Functions for getting the pages from kernel memory. | ||
254 | */ | ||
255 | static void km_get_page(struct dpages *dp, struct page **p, unsigned long *len, | ||
256 | unsigned *offset) | ||
257 | { | ||
258 | *p = virt_to_page(dp->context_ptr); | ||
259 | *offset = dp->context_u; | ||
260 | *len = PAGE_SIZE - dp->context_u; | ||
261 | } | ||
262 | |||
263 | static void km_next_page(struct dpages *dp) | ||
264 | { | ||
265 | dp->context_ptr += PAGE_SIZE - dp->context_u; | ||
266 | dp->context_u = 0; | ||
267 | } | ||
268 | |||
269 | static void km_dp_init(struct dpages *dp, void *data) | ||
270 | { | ||
271 | dp->get_page = km_get_page; | ||
272 | dp->next_page = km_next_page; | ||
273 | dp->context_u = ((unsigned long) data) & (PAGE_SIZE - 1); | ||
274 | dp->context_ptr = data; | ||
237 | } | 275 | } |
238 | 276 | ||
239 | /*----------------------------------------------------------------- | 277 | /*----------------------------------------------------------------- |
@@ -256,7 +294,7 @@ static void do_region(int rw, unsigned int region, struct io_region *where, | |||
256 | * to hide it from bio_add_page(). | 294 | * to hide it from bio_add_page(). |
257 | */ | 295 | */ |
258 | num_bvecs = (remaining / (PAGE_SIZE >> SECTOR_SHIFT)) + 2; | 296 | num_bvecs = (remaining / (PAGE_SIZE >> SECTOR_SHIFT)) + 2; |
259 | bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, _bios); | 297 | bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios); |
260 | bio->bi_sector = where->sector + (where->count - remaining); | 298 | bio->bi_sector = where->sector + (where->count - remaining); |
261 | bio->bi_bdev = where->bdev; | 299 | bio->bi_bdev = where->bdev; |
262 | bio->bi_end_io = endio; | 300 | bio->bi_end_io = endio; |
@@ -311,8 +349,9 @@ static void dispatch_io(int rw, unsigned int num_regions, | |||
311 | dec_count(io, 0, 0); | 349 | dec_count(io, 0, 0); |
312 | } | 350 | } |
313 | 351 | ||
314 | static int sync_io(unsigned int num_regions, struct io_region *where, | 352 | static int sync_io(struct dm_io_client *client, unsigned int num_regions, |
315 | int rw, struct dpages *dp, unsigned long *error_bits) | 353 | struct io_region *where, int rw, struct dpages *dp, |
354 | unsigned long *error_bits) | ||
316 | { | 355 | { |
317 | struct io io; | 356 | struct io io; |
318 | 357 | ||
@@ -324,6 +363,7 @@ static int sync_io(unsigned int num_regions, struct io_region *where, | |||
324 | io.error = 0; | 363 | io.error = 0; |
325 | atomic_set(&io.count, 1); /* see dispatch_io() */ | 364 | atomic_set(&io.count, 1); /* see dispatch_io() */ |
326 | io.sleeper = current; | 365 | io.sleeper = current; |
366 | io.client = client; | ||
327 | 367 | ||
328 | dispatch_io(rw, num_regions, where, dp, &io, 1); | 368 | dispatch_io(rw, num_regions, where, dp, &io, 1); |
329 | 369 | ||
@@ -340,12 +380,15 @@ static int sync_io(unsigned int num_regions, struct io_region *where, | |||
340 | if (atomic_read(&io.count)) | 380 | if (atomic_read(&io.count)) |
341 | return -EINTR; | 381 | return -EINTR; |
342 | 382 | ||
343 | *error_bits = io.error; | 383 | if (error_bits) |
384 | *error_bits = io.error; | ||
385 | |||
344 | return io.error ? -EIO : 0; | 386 | return io.error ? -EIO : 0; |
345 | } | 387 | } |
346 | 388 | ||
347 | static int async_io(unsigned int num_regions, struct io_region *where, int rw, | 389 | static int async_io(struct dm_io_client *client, unsigned int num_regions, |
348 | struct dpages *dp, io_notify_fn fn, void *context) | 390 | struct io_region *where, int rw, struct dpages *dp, |
391 | io_notify_fn fn, void *context) | ||
349 | { | 392 | { |
350 | struct io *io; | 393 | struct io *io; |
351 | 394 | ||
@@ -355,10 +398,11 @@ static int async_io(unsigned int num_regions, struct io_region *where, int rw, | |||
355 | return -EIO; | 398 | return -EIO; |
356 | } | 399 | } |
357 | 400 | ||
358 | io = mempool_alloc(_io_pool, GFP_NOIO); | 401 | io = mempool_alloc(client->pool, GFP_NOIO); |
359 | io->error = 0; | 402 | io->error = 0; |
360 | atomic_set(&io->count, 1); /* see dispatch_io() */ | 403 | atomic_set(&io->count, 1); /* see dispatch_io() */ |
361 | io->sleeper = NULL; | 404 | io->sleeper = NULL; |
405 | io->client = client; | ||
362 | io->callback = fn; | 406 | io->callback = fn; |
363 | io->context = context; | 407 | io->context = context; |
364 | 408 | ||
@@ -366,61 +410,51 @@ static int async_io(unsigned int num_regions, struct io_region *where, int rw, | |||
366 | return 0; | 410 | return 0; |
367 | } | 411 | } |
368 | 412 | ||
369 | int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw, | 413 | static int dp_init(struct dm_io_request *io_req, struct dpages *dp) |
370 | struct page_list *pl, unsigned int offset, | ||
371 | unsigned long *error_bits) | ||
372 | { | 414 | { |
373 | struct dpages dp; | 415 | /* Set up dpages based on memory type */ |
374 | list_dp_init(&dp, pl, offset); | 416 | switch (io_req->mem.type) { |
375 | return sync_io(num_regions, where, rw, &dp, error_bits); | 417 | case DM_IO_PAGE_LIST: |
376 | } | 418 | list_dp_init(dp, io_req->mem.ptr.pl, io_req->mem.offset); |
419 | break; | ||
420 | |||
421 | case DM_IO_BVEC: | ||
422 | bvec_dp_init(dp, io_req->mem.ptr.bvec); | ||
423 | break; | ||
424 | |||
425 | case DM_IO_VMA: | ||
426 | vm_dp_init(dp, io_req->mem.ptr.vma); | ||
427 | break; | ||
428 | |||
429 | case DM_IO_KMEM: | ||
430 | km_dp_init(dp, io_req->mem.ptr.addr); | ||
431 | break; | ||
432 | |||
433 | default: | ||
434 | return -EINVAL; | ||
435 | } | ||
377 | 436 | ||
378 | int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw, | 437 | return 0; |
379 | struct bio_vec *bvec, unsigned long *error_bits) | ||
380 | { | ||
381 | struct dpages dp; | ||
382 | bvec_dp_init(&dp, bvec); | ||
383 | return sync_io(num_regions, where, rw, &dp, error_bits); | ||
384 | } | 438 | } |
385 | 439 | ||
386 | int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw, | 440 | /* |
387 | void *data, unsigned long *error_bits) | 441 | * New collapsed (a)synchronous interface |
442 | */ | ||
443 | int dm_io(struct dm_io_request *io_req, unsigned num_regions, | ||
444 | struct io_region *where, unsigned long *sync_error_bits) | ||
388 | { | 445 | { |
446 | int r; | ||
389 | struct dpages dp; | 447 | struct dpages dp; |
390 | vm_dp_init(&dp, data); | ||
391 | return sync_io(num_regions, where, rw, &dp, error_bits); | ||
392 | } | ||
393 | 448 | ||
394 | int dm_io_async(unsigned int num_regions, struct io_region *where, int rw, | 449 | r = dp_init(io_req, &dp); |
395 | struct page_list *pl, unsigned int offset, | 450 | if (r) |
396 | io_notify_fn fn, void *context) | 451 | return r; |
397 | { | ||
398 | struct dpages dp; | ||
399 | list_dp_init(&dp, pl, offset); | ||
400 | return async_io(num_regions, where, rw, &dp, fn, context); | ||
401 | } | ||
402 | 452 | ||
403 | int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw, | 453 | if (!io_req->notify.fn) |
404 | struct bio_vec *bvec, io_notify_fn fn, void *context) | 454 | return sync_io(io_req->client, num_regions, where, |
405 | { | 455 | io_req->bi_rw, &dp, sync_error_bits); |
406 | struct dpages dp; | ||
407 | bvec_dp_init(&dp, bvec); | ||
408 | return async_io(num_regions, where, rw, &dp, fn, context); | ||
409 | } | ||
410 | 456 | ||
411 | int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw, | 457 | return async_io(io_req->client, num_regions, where, io_req->bi_rw, |
412 | void *data, io_notify_fn fn, void *context) | 458 | &dp, io_req->notify.fn, io_req->notify.context); |
413 | { | ||
414 | struct dpages dp; | ||
415 | vm_dp_init(&dp, data); | ||
416 | return async_io(num_regions, where, rw, &dp, fn, context); | ||
417 | } | 459 | } |
418 | 460 | EXPORT_SYMBOL(dm_io); | |
419 | EXPORT_SYMBOL(dm_io_get); | ||
420 | EXPORT_SYMBOL(dm_io_put); | ||
421 | EXPORT_SYMBOL(dm_io_sync); | ||
422 | EXPORT_SYMBOL(dm_io_async); | ||
423 | EXPORT_SYMBOL(dm_io_sync_bvec); | ||
424 | EXPORT_SYMBOL(dm_io_async_bvec); | ||
425 | EXPORT_SYMBOL(dm_io_sync_vm); | ||
426 | EXPORT_SYMBOL(dm_io_async_vm); | ||