diff options
author | Heinz Mauelshagen <hjm@redhat.com> | 2007-05-09 05:33:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-09 15:30:47 -0400 |
commit | c8b03afe3d38a635861e4bfa5c563d844e754a91 (patch) | |
tree | d23d2aa8d6cec93bab6e23ffd2199509e7d85113 /drivers/md | |
parent | 891ce207011d3d9219f79fd5114c8594bbacc653 (diff) |
dm io: new interface
Add a new API to dm-io.c that uses a private mempool and bio_set for each
client.
The new functions to use are dm_io_client_create(), dm_io_client_destroy(),
dm_io_client_resize() and dm_io().
Signed-off-by: Heinz Mauelshagen <hjm@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Cc: Milan Broz <mbroz@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-io.c | 122 | ||||
-rw-r--r-- | drivers/md/dm-io.h | 52 |
2 files changed, 173 insertions, 1 deletions
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 66db79208c1d..0c63809ab70e 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c | |||
@@ -103,6 +103,51 @@ void dm_io_put(unsigned int num_pages) | |||
103 | resize_pool(_num_ios - pages_to_ios(num_pages)); | 103 | resize_pool(_num_ios - pages_to_ios(num_pages)); |
104 | } | 104 | } |
105 | 105 | ||
106 | /* | ||
107 | * Create a client with mempool and bioset. | ||
108 | */ | ||
109 | struct dm_io_client *dm_io_client_create(unsigned num_pages) | ||
110 | { | ||
111 | unsigned ios = pages_to_ios(num_pages); | ||
112 | struct dm_io_client *client; | ||
113 | |||
114 | client = kmalloc(sizeof(*client), GFP_KERNEL); | ||
115 | if (!client) | ||
116 | return ERR_PTR(-ENOMEM); | ||
117 | |||
118 | client->pool = mempool_create_kmalloc_pool(ios, sizeof(struct io)); | ||
119 | if (!client->pool) | ||
120 | goto bad; | ||
121 | |||
122 | client->bios = bioset_create(16, 16); | ||
123 | if (!client->bios) | ||
124 | goto bad; | ||
125 | |||
126 | return client; | ||
127 | |||
128 | bad: | ||
129 | if (client->pool) | ||
130 | mempool_destroy(client->pool); | ||
131 | kfree(client); | ||
132 | return ERR_PTR(-ENOMEM); | ||
133 | } | ||
134 | EXPORT_SYMBOL(dm_io_client_create); | ||
135 | |||
136 | int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client) | ||
137 | { | ||
138 | return mempool_resize(client->pool, pages_to_ios(num_pages), | ||
139 | GFP_KERNEL); | ||
140 | } | ||
141 | EXPORT_SYMBOL(dm_io_client_resize); | ||
142 | |||
143 | void dm_io_client_destroy(struct dm_io_client *client) | ||
144 | { | ||
145 | mempool_destroy(client->pool); | ||
146 | bioset_free(client->bios); | ||
147 | kfree(client); | ||
148 | } | ||
149 | EXPORT_SYMBOL(dm_io_client_destroy); | ||
150 | |||
106 | /*----------------------------------------------------------------- | 151 | /*----------------------------------------------------------------- |
107 | * We need to keep track of which region a bio is doing io for. | 152 | * We need to keep track of which region a bio is doing io for. |
108 | * In order to save a memory allocation we store this the last | 153 | * In order to save a memory allocation we store this the last |
@@ -236,6 +281,9 @@ static void bvec_dp_init(struct dpages *dp, struct bio_vec *bvec) | |||
236 | dp->context_ptr = bvec; | 281 | dp->context_ptr = bvec; |
237 | } | 282 | } |
238 | 283 | ||
284 | /* | ||
285 | * Functions for getting the pages from a VMA. | ||
286 | */ | ||
239 | static void vm_get_page(struct dpages *dp, | 287 | static void vm_get_page(struct dpages *dp, |
240 | struct page **p, unsigned long *len, unsigned *offset) | 288 | struct page **p, unsigned long *len, unsigned *offset) |
241 | { | 289 | { |
@@ -265,6 +313,31 @@ static void dm_bio_destructor(struct bio *bio) | |||
265 | bio_free(bio, bios(io->client)); | 313 | bio_free(bio, bios(io->client)); |
266 | } | 314 | } |
267 | 315 | ||
316 | /* | ||
317 | * Functions for getting the pages from kernel memory. | ||
318 | */ | ||
319 | static void km_get_page(struct dpages *dp, struct page **p, unsigned long *len, | ||
320 | unsigned *offset) | ||
321 | { | ||
322 | *p = virt_to_page(dp->context_ptr); | ||
323 | *offset = dp->context_u; | ||
324 | *len = PAGE_SIZE - dp->context_u; | ||
325 | } | ||
326 | |||
327 | static void km_next_page(struct dpages *dp) | ||
328 | { | ||
329 | dp->context_ptr += PAGE_SIZE - dp->context_u; | ||
330 | dp->context_u = 0; | ||
331 | } | ||
332 | |||
333 | static void km_dp_init(struct dpages *dp, void *data) | ||
334 | { | ||
335 | dp->get_page = km_get_page; | ||
336 | dp->next_page = km_next_page; | ||
337 | dp->context_u = ((unsigned long) data) & (PAGE_SIZE - 1); | ||
338 | dp->context_ptr = data; | ||
339 | } | ||
340 | |||
268 | /*----------------------------------------------------------------- | 341 | /*----------------------------------------------------------------- |
269 | * IO routines that accept a list of pages. | 342 | * IO routines that accept a list of pages. |
270 | *---------------------------------------------------------------*/ | 343 | *---------------------------------------------------------------*/ |
@@ -451,6 +524,55 @@ int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw, | |||
451 | return async_io(NULL, num_regions, where, rw, &dp, fn, context); | 524 | return async_io(NULL, num_regions, where, rw, &dp, fn, context); |
452 | } | 525 | } |
453 | 526 | ||
527 | static int dp_init(struct dm_io_request *io_req, struct dpages *dp) | ||
528 | { | ||
529 | /* Set up dpages based on memory type */ | ||
530 | switch (io_req->mem.type) { | ||
531 | case DM_IO_PAGE_LIST: | ||
532 | list_dp_init(dp, io_req->mem.ptr.pl, io_req->mem.offset); | ||
533 | break; | ||
534 | |||
535 | case DM_IO_BVEC: | ||
536 | bvec_dp_init(dp, io_req->mem.ptr.bvec); | ||
537 | break; | ||
538 | |||
539 | case DM_IO_VMA: | ||
540 | vm_dp_init(dp, io_req->mem.ptr.vma); | ||
541 | break; | ||
542 | |||
543 | case DM_IO_KMEM: | ||
544 | km_dp_init(dp, io_req->mem.ptr.addr); | ||
545 | break; | ||
546 | |||
547 | default: | ||
548 | return -EINVAL; | ||
549 | } | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | /* | ||
555 | * New collapsed (a)synchronous interface | ||
556 | */ | ||
557 | int dm_io(struct dm_io_request *io_req, unsigned num_regions, | ||
558 | struct io_region *where, unsigned long *sync_error_bits) | ||
559 | { | ||
560 | int r; | ||
561 | struct dpages dp; | ||
562 | |||
563 | r = dp_init(io_req, &dp); | ||
564 | if (r) | ||
565 | return r; | ||
566 | |||
567 | if (!io_req->notify.fn) | ||
568 | return sync_io(io_req->client, num_regions, where, | ||
569 | io_req->bi_rw, &dp, sync_error_bits); | ||
570 | |||
571 | return async_io(io_req->client, num_regions, where, io_req->bi_rw, | ||
572 | &dp, io_req->notify.fn, io_req->notify.context); | ||
573 | } | ||
574 | EXPORT_SYMBOL(dm_io); | ||
575 | |||
454 | EXPORT_SYMBOL(dm_io_get); | 576 | EXPORT_SYMBOL(dm_io_get); |
455 | EXPORT_SYMBOL(dm_io_put); | 577 | EXPORT_SYMBOL(dm_io_put); |
456 | EXPORT_SYMBOL(dm_io_sync); | 578 | EXPORT_SYMBOL(dm_io_sync); |
diff --git a/drivers/md/dm-io.h b/drivers/md/dm-io.h index f9035bfd1a9f..05b133825580 100644 --- a/drivers/md/dm-io.h +++ b/drivers/md/dm-io.h | |||
@@ -20,13 +20,47 @@ struct page_list { | |||
20 | struct page *page; | 20 | struct page *page; |
21 | }; | 21 | }; |
22 | 22 | ||
23 | |||
24 | /* | 23 | /* |
25 | * 'error' is a bitset, with each bit indicating whether an error | 24 | * 'error' is a bitset, with each bit indicating whether an error |
26 | * occurred doing io to the corresponding region. | 25 | * occurred doing io to the corresponding region. |
27 | */ | 26 | */ |
28 | typedef void (*io_notify_fn)(unsigned long error, void *context); | 27 | typedef void (*io_notify_fn)(unsigned long error, void *context); |
29 | 28 | ||
29 | enum dm_io_mem_type { | ||
30 | DM_IO_PAGE_LIST,/* Page list */ | ||
31 | DM_IO_BVEC, /* Bio vector */ | ||
32 | DM_IO_VMA, /* Virtual memory area */ | ||
33 | DM_IO_KMEM, /* Kernel memory */ | ||
34 | }; | ||
35 | |||
36 | struct dm_io_memory { | ||
37 | enum dm_io_mem_type type; | ||
38 | |||
39 | union { | ||
40 | struct page_list *pl; | ||
41 | struct bio_vec *bvec; | ||
42 | void *vma; | ||
43 | void *addr; | ||
44 | } ptr; | ||
45 | |||
46 | unsigned offset; | ||
47 | }; | ||
48 | |||
49 | struct dm_io_notify { | ||
50 | io_notify_fn fn; /* Callback for asynchronous requests */ | ||
51 | void *context; /* Passed to callback */ | ||
52 | }; | ||
53 | |||
54 | /* | ||
55 | * IO request structure | ||
56 | */ | ||
57 | struct dm_io_client; | ||
58 | struct dm_io_request { | ||
59 | int bi_rw; /* READ|WRITE - not READA */ | ||
60 | struct dm_io_memory mem; /* Memory to use for io */ | ||
61 | struct dm_io_notify notify; /* Synchronous if notify.fn is NULL */ | ||
62 | struct dm_io_client *client; /* Client memory handler */ | ||
63 | }; | ||
30 | 64 | ||
31 | /* | 65 | /* |
32 | * Before anyone uses the IO interface they should call | 66 | * Before anyone uses the IO interface they should call |
@@ -39,6 +73,16 @@ int dm_io_get(unsigned int num_pages); | |||
39 | void dm_io_put(unsigned int num_pages); | 73 | void dm_io_put(unsigned int num_pages); |
40 | 74 | ||
41 | /* | 75 | /* |
76 | * 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. | ||
78 | * | ||
79 | * Create/destroy may block. | ||
80 | */ | ||
81 | struct dm_io_client *dm_io_client_create(unsigned num_pages); | ||
82 | int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client); | ||
83 | void dm_io_client_destroy(struct dm_io_client *client); | ||
84 | |||
85 | /* | ||
42 | * Synchronous IO. | 86 | * Synchronous IO. |
43 | * | 87 | * |
44 | * Please ensure that the rw flag in the next two functions is | 88 | * Please ensure that the rw flag in the next two functions is |
@@ -71,4 +115,10 @@ int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw, | |||
71 | int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw, | 115 | int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw, |
72 | void *data, io_notify_fn fn, void *context); | 116 | void *data, io_notify_fn fn, void *context); |
73 | 117 | ||
118 | /* | ||
119 | * IO interface using private per-client pools. | ||
120 | */ | ||
121 | int dm_io(struct dm_io_request *io_req, unsigned num_regions, | ||
122 | struct io_region *region, unsigned long *sync_error_bits); | ||
123 | |||
74 | #endif | 124 | #endif |