diff options
-rw-r--r-- | drivers/md/dm-io.c | 131 | ||||
-rw-r--r-- | drivers/md/dm-io.h | 51 |
2 files changed, 7 insertions, 175 deletions
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 0c63809ab70e..352c6fbeac53 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c | |||
@@ -13,8 +13,6 @@ | |||
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | 15 | ||
16 | static struct bio_set *_bios; | ||
17 | |||
18 | struct dm_io_client { | 16 | struct dm_io_client { |
19 | mempool_t *pool; | 17 | mempool_t *pool; |
20 | struct bio_set *bios; | 18 | struct bio_set *bios; |
@@ -35,74 +33,12 @@ struct io { | |||
35 | * 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 |
36 | * have the same number of io contexts as bios! (FIXME: must reduce this). | 34 | * have the same number of io contexts as bios! (FIXME: must reduce this). |
37 | */ | 35 | */ |
38 | static unsigned _num_ios; | ||
39 | static mempool_t *_io_pool; | ||
40 | |||
41 | /* | ||
42 | * Temporary functions to allow old and new interfaces to co-exist. | ||
43 | */ | ||
44 | static struct bio_set *bios(struct dm_io_client *client) | ||
45 | { | ||
46 | return client ? client->bios : _bios; | ||
47 | } | ||
48 | |||
49 | static mempool_t *io_pool(struct dm_io_client *client) | ||
50 | { | ||
51 | return client ? client->pool : _io_pool; | ||
52 | } | ||
53 | 36 | ||
54 | static unsigned int pages_to_ios(unsigned int pages) | 37 | static unsigned int pages_to_ios(unsigned int pages) |
55 | { | 38 | { |
56 | return 4 * pages; /* too many ? */ | 39 | return 4 * pages; /* too many ? */ |
57 | } | 40 | } |
58 | 41 | ||
59 | static int resize_pool(unsigned int new_ios) | ||
60 | { | ||
61 | int r = 0; | ||
62 | |||
63 | if (_io_pool) { | ||
64 | if (new_ios == 0) { | ||
65 | /* free off the pool */ | ||
66 | mempool_destroy(_io_pool); | ||
67 | _io_pool = NULL; | ||
68 | bioset_free(_bios); | ||
69 | |||
70 | } else { | ||
71 | /* resize the pool */ | ||
72 | r = mempool_resize(_io_pool, new_ios, GFP_KERNEL); | ||
73 | } | ||
74 | |||
75 | } else { | ||
76 | /* create new pool */ | ||
77 | _io_pool = mempool_create_kmalloc_pool(new_ios, | ||
78 | sizeof(struct io)); | ||
79 | if (!_io_pool) | ||
80 | return -ENOMEM; | ||
81 | |||
82 | _bios = bioset_create(16, 16); | ||
83 | if (!_bios) { | ||
84 | mempool_destroy(_io_pool); | ||
85 | _io_pool = NULL; | ||
86 | return -ENOMEM; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | if (!r) | ||
91 | _num_ios = new_ios; | ||
92 | |||
93 | return r; | ||
94 | } | ||
95 | |||
96 | int dm_io_get(unsigned int num_pages) | ||
97 | { | ||
98 | return resize_pool(_num_ios + pages_to_ios(num_pages)); | ||
99 | } | ||
100 | |||
101 | void dm_io_put(unsigned int num_pages) | ||
102 | { | ||
103 | resize_pool(_num_ios - pages_to_ios(num_pages)); | ||
104 | } | ||
105 | |||
106 | /* | 42 | /* |
107 | * Create a client with mempool and bioset. | 43 | * Create a client with mempool and bioset. |
108 | */ | 44 | */ |
@@ -182,7 +118,7 @@ static void dec_count(struct io *io, unsigned int region, int error) | |||
182 | io_notify_fn fn = io->callback; | 118 | io_notify_fn fn = io->callback; |
183 | void *context = io->context; | 119 | void *context = io->context; |
184 | 120 | ||
185 | mempool_free(io, io_pool(io->client)); | 121 | mempool_free(io, io->client->pool); |
186 | fn(r, context); | 122 | fn(r, context); |
187 | } | 123 | } |
188 | } | 124 | } |
@@ -310,7 +246,7 @@ static void dm_bio_destructor(struct bio *bio) | |||
310 | { | 246 | { |
311 | struct io *io = bio->bi_private; | 247 | struct io *io = bio->bi_private; |
312 | 248 | ||
313 | bio_free(bio, bios(io->client)); | 249 | bio_free(bio, io->client->bios); |
314 | } | 250 | } |
315 | 251 | ||
316 | /* | 252 | /* |
@@ -358,7 +294,7 @@ static void do_region(int rw, unsigned int region, struct io_region *where, | |||
358 | * to hide it from bio_add_page(). | 294 | * to hide it from bio_add_page(). |
359 | */ | 295 | */ |
360 | num_bvecs = (remaining / (PAGE_SIZE >> SECTOR_SHIFT)) + 2; | 296 | num_bvecs = (remaining / (PAGE_SIZE >> SECTOR_SHIFT)) + 2; |
361 | bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, bios(io->client)); | 297 | bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios); |
362 | bio->bi_sector = where->sector + (where->count - remaining); | 298 | bio->bi_sector = where->sector + (where->count - remaining); |
363 | bio->bi_bdev = where->bdev; | 299 | bio->bi_bdev = where->bdev; |
364 | bio->bi_end_io = endio; | 300 | bio->bi_end_io = endio; |
@@ -462,7 +398,7 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions, | |||
462 | return -EIO; | 398 | return -EIO; |
463 | } | 399 | } |
464 | 400 | ||
465 | io = mempool_alloc(io_pool(client), GFP_NOIO); | 401 | io = mempool_alloc(client->pool, GFP_NOIO); |
466 | io->error = 0; | 402 | io->error = 0; |
467 | atomic_set(&io->count, 1); /* see dispatch_io() */ | 403 | atomic_set(&io->count, 1); /* see dispatch_io() */ |
468 | io->sleeper = NULL; | 404 | io->sleeper = NULL; |
@@ -474,56 +410,6 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions, | |||
474 | return 0; | 410 | return 0; |
475 | } | 411 | } |
476 | 412 | ||
477 | int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw, | ||
478 | struct page_list *pl, unsigned int offset, | ||
479 | unsigned long *error_bits) | ||
480 | { | ||
481 | struct dpages dp; | ||
482 | list_dp_init(&dp, pl, offset); | ||
483 | return sync_io(NULL, num_regions, where, rw, &dp, error_bits); | ||
484 | } | ||
485 | |||
486 | int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw, | ||
487 | struct bio_vec *bvec, unsigned long *error_bits) | ||
488 | { | ||
489 | struct dpages dp; | ||
490 | bvec_dp_init(&dp, bvec); | ||
491 | return sync_io(NULL, num_regions, where, rw, &dp, error_bits); | ||
492 | } | ||
493 | |||
494 | int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw, | ||
495 | void *data, unsigned long *error_bits) | ||
496 | { | ||
497 | struct dpages dp; | ||
498 | vm_dp_init(&dp, data); | ||
499 | return sync_io(NULL, num_regions, where, rw, &dp, error_bits); | ||
500 | } | ||
501 | |||
502 | int dm_io_async(unsigned int num_regions, struct io_region *where, int rw, | ||
503 | struct page_list *pl, unsigned int offset, | ||
504 | io_notify_fn fn, void *context) | ||
505 | { | ||
506 | struct dpages dp; | ||
507 | list_dp_init(&dp, pl, offset); | ||
508 | return async_io(NULL, num_regions, where, rw, &dp, fn, context); | ||
509 | } | ||
510 | |||
511 | int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw, | ||
512 | struct bio_vec *bvec, io_notify_fn fn, void *context) | ||
513 | { | ||
514 | struct dpages dp; | ||
515 | bvec_dp_init(&dp, bvec); | ||
516 | return async_io(NULL, num_regions, where, rw, &dp, fn, context); | ||
517 | } | ||
518 | |||
519 | int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw, | ||
520 | void *data, io_notify_fn fn, void *context) | ||
521 | { | ||
522 | struct dpages dp; | ||
523 | vm_dp_init(&dp, data); | ||
524 | return async_io(NULL, num_regions, where, rw, &dp, fn, context); | ||
525 | } | ||
526 | |||
527 | static int dp_init(struct dm_io_request *io_req, struct dpages *dp) | 413 | static int dp_init(struct dm_io_request *io_req, struct dpages *dp) |
528 | { | 414 | { |
529 | /* Set up dpages based on memory type */ | 415 | /* Set up dpages based on memory type */ |
@@ -572,12 +458,3 @@ int dm_io(struct dm_io_request *io_req, unsigned num_regions, | |||
572 | &dp, io_req->notify.fn, io_req->notify.context); | 458 | &dp, io_req->notify.fn, io_req->notify.context); |
573 | } | 459 | } |
574 | EXPORT_SYMBOL(dm_io); | 460 | EXPORT_SYMBOL(dm_io); |
575 | |||
576 | EXPORT_SYMBOL(dm_io_get); | ||
577 | EXPORT_SYMBOL(dm_io_put); | ||
578 | EXPORT_SYMBOL(dm_io_sync); | ||
579 | EXPORT_SYMBOL(dm_io_async); | ||
580 | EXPORT_SYMBOL(dm_io_sync_bvec); | ||
581 | EXPORT_SYMBOL(dm_io_async_bvec); | ||
582 | EXPORT_SYMBOL(dm_io_sync_vm); | ||
583 | EXPORT_SYMBOL(dm_io_async_vm); | ||
diff --git a/drivers/md/dm-io.h b/drivers/md/dm-io.h index 05b133825580..f647e2cceaa6 100644 --- a/drivers/md/dm-io.h +++ b/drivers/md/dm-io.h | |||
@@ -12,7 +12,7 @@ | |||
12 | struct io_region { | 12 | struct io_region { |
13 | struct block_device *bdev; | 13 | struct block_device *bdev; |
14 | sector_t sector; | 14 | sector_t sector; |
15 | sector_t count; | 15 | sector_t count; /* If this is zero the region is ignored. */ |
16 | }; | 16 | }; |
17 | 17 | ||
18 | struct page_list { | 18 | struct page_list { |
@@ -20,10 +20,6 @@ struct page_list { | |||
20 | struct page *page; | 20 | struct page *page; |
21 | }; | 21 | }; |
22 | 22 | ||
23 | /* | ||
24 | * 'error' is a bitset, with each bit indicating whether an error | ||
25 | * occurred doing io to the corresponding region. | ||
26 | */ | ||
27 | typedef void (*io_notify_fn)(unsigned long error, void *context); | 23 | typedef void (*io_notify_fn)(unsigned long error, void *context); |
28 | 24 | ||
29 | enum dm_io_mem_type { | 25 | enum dm_io_mem_type { |
@@ -63,16 +59,6 @@ struct dm_io_request { | |||
63 | }; | 59 | }; |
64 | 60 | ||
65 | /* | 61 | /* |
66 | * Before anyone uses the IO interface they should call | ||
67 | * dm_io_get(), specifying roughly how many pages they are | ||
68 | * expecting to perform io on concurrently. | ||
69 | * | ||
70 | * This function may block. | ||
71 | */ | ||
72 | int dm_io_get(unsigned int num_pages); | ||
73 | void dm_io_put(unsigned int num_pages); | ||
74 | |||
75 | /* | ||
76 | * For async io calls, users can alternatively use the dm_io() function below | 62 | * For async io calls, users can alternatively use the dm_io() function below |
77 | * and dm_io_client_create() to create private mempools for the client. | 63 | * and dm_io_client_create() to create private mempools for the client. |
78 | * | 64 | * |
@@ -83,40 +69,9 @@ int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client); | |||
83 | void dm_io_client_destroy(struct dm_io_client *client); | 69 | void dm_io_client_destroy(struct dm_io_client *client); |
84 | 70 | ||
85 | /* | 71 | /* |
86 | * Synchronous IO. | ||
87 | * | ||
88 | * Please ensure that the rw flag in the next two functions is | ||
89 | * either READ or WRITE, ie. we don't take READA. Any | ||
90 | * regions with a zero count field will be ignored. | ||
91 | */ | ||
92 | int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw, | ||
93 | struct page_list *pl, unsigned int offset, | ||
94 | unsigned long *error_bits); | ||
95 | |||
96 | int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw, | ||
97 | struct bio_vec *bvec, unsigned long *error_bits); | ||
98 | |||
99 | int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw, | ||
100 | void *data, unsigned long *error_bits); | ||
101 | |||
102 | /* | ||
103 | * Aynchronous IO. | ||
104 | * | ||
105 | * The 'where' array may be safely allocated on the stack since | ||
106 | * the function takes a copy. | ||
107 | */ | ||
108 | int dm_io_async(unsigned int num_regions, struct io_region *where, int rw, | ||
109 | struct page_list *pl, unsigned int offset, | ||
110 | io_notify_fn fn, void *context); | ||
111 | |||
112 | int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw, | ||
113 | struct bio_vec *bvec, io_notify_fn fn, void *context); | ||
114 | |||
115 | int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw, | ||
116 | void *data, io_notify_fn fn, void *context); | ||
117 | |||
118 | /* | ||
119 | * IO interface using private per-client pools. | 72 | * IO interface using private per-client pools. |
73 | * Each bit in the optional 'sync_error_bits' bitset indicates whether an | ||
74 | * error occurred doing io to the corresponding region. | ||
120 | */ | 75 | */ |
121 | int dm_io(struct dm_io_request *io_req, unsigned num_regions, | 76 | int dm_io(struct dm_io_request *io_req, unsigned num_regions, |
122 | struct io_region *region, unsigned long *sync_error_bits); | 77 | struct io_region *region, unsigned long *sync_error_bits); |