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 drivers/md/dm-io.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/md/dm-io.h | 42 ++++++++++++++++++++- 2 files changed, 142 insertions(+), 2 deletions(-) Index: linux-2.6.19/drivers/md/dm-io.c =================================================================== --- linux-2.6.19.orig/drivers/md/dm-io.c 2006-12-06 20:49:37.000000000 +0000 +++ linux-2.6.19/drivers/md/dm-io.c 2006-12-06 20:49:38.000000000 +0000 @@ -93,6 +93,9 @@ static int resize_pool(unsigned int new_ return r; } +/* + * FIXME: not multi-threaded + */ int dm_io_get(unsigned int num_pages) { return resize_pool(_num_ios + pages_to_ios(num_pages)); @@ -103,6 +106,55 @@ void dm_io_put(unsigned int num_pages) resize_pool(_num_ios - pages_to_ios(num_pages)); } +/* + * Create a mempool for a client + */ +void *dm_io_client_create(unsigned num_pages) +{ + unsigned ios = pages_to_ios(num_pages); + struct io_client *client; + + client = kmalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return NULL; + + client->pool = mempool_create_kmalloc_pool(ios, sizeof(struct io)); + if (!client->pool) + goto err; + + client->bios = bioset_create(16, 16, 4); + if (!client->bios) + goto err_mempool; + + return client; + + err_mempool: + mempool_destroy(client->pool); + err: + kfree(client); + return NULL; +} +EXPORT_SYMBOL(dm_io_client_create); + +void dm_io_client_destroy(void *context) +{ + struct io_client *client = context; + + mempool_destroy(client->pool); + bioset_free(client->bios); + kfree(client); +} +EXPORT_SYMBOL(dm_io_client_destroy); + +int dm_io_client_resize(void *context, unsigned num_pages) +{ + struct io_client *client = context; + + return mempool_resize(client->pool, pages_to_ios(num_pages), + GFP_KERNEL); +} +EXPORT_SYMBOL(dm_io_client_resize); + /*----------------------------------------------------------------- * We need to keep track of which region a bio is doing io for. * In order to save a memory allocation we store this the last @@ -366,12 +418,14 @@ static int sync_io(struct io_client *cli io_schedule(); } + set_current_state(TASK_RUNNING); if (atomic_read(&io.count)) return -EINTR; *error_bits = io.error; + return io.error ? -EIO : 0; } @@ -399,6 +453,9 @@ static int async_io(struct io_client *cl return 0; } +/* + * Synchronuos IO API + */ int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw, struct page_list *pl, unsigned int offset, unsigned long *error_bits) @@ -424,6 +481,9 @@ int dm_io_sync_vm(unsigned int num_regio return sync_io(NULL, num_regions, where, rw, &dp, error_bits); } +/* + * Asynchronuos IO API + */ int dm_io_async(unsigned int num_regions, struct io_region *where, int rw, struct page_list *pl, unsigned int offset, io_notify_fn fn, void *context) @@ -449,6 +509,48 @@ int dm_io_async_vm(unsigned int num_regi return async_io(NULL, num_regions, where, rw, &dp, fn, context); } +static int dp_init(struct io_memory *mem, struct dpages *dp) +{ + /* Set up dpages based on memory type */ + switch (mem->type) { + case IO_PAGE_LIST: + list_dp_init(dp, mem->ptr.pl, mem->offset); + break; + + case IO_BVEC: + bvec_dp_init(dp, mem->ptr.bvec); + break; + + case IO_VMA: + vm_dp_init(dp, mem->ptr.vma); + break; + + default: + return -EINVAL; + } + + return 0; +} + +int dm_io(void *client, struct io_control *control, unsigned num_regions, + struct io_region *where, unsigned long *error_bits) +{ + int r; + struct dpages dp; + + r = dp_init(&control->mem, &dp); + if (r) + return r; + + if (control->sync) + return sync_io(client, num_regions, where, control->rw, + &dp, error_bits); + + return async_io(client, num_regions, where, control->rw, + &dp, control->notify.fn, control->notify.context); +} +EXPORT_SYMBOL(dm_io); + EXPORT_SYMBOL(dm_io_get); EXPORT_SYMBOL(dm_io_put); EXPORT_SYMBOL(dm_io_sync); Index: linux-2.6.19/drivers/md/dm-io.h =================================================================== --- linux-2.6.19.orig/drivers/md/dm-io.h 2006-12-06 20:48:29.000000000 +0000 +++ linux-2.6.19/drivers/md/dm-io.h 2006-12-06 20:49:38.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Sistina Software + * Copyright (C) 2006 Red Hat GmbH * * This file is released under the GPL. */ @@ -20,16 +21,37 @@ struct page_list { struct page *page; }; - /* * 'error' is a bitset, with each bit indicating whether an error * occurred doing io to the corresponding region. */ typedef void (*io_notify_fn)(unsigned long error, void *context); +struct io_memory { + enum { IO_PAGE_LIST, IO_BVEC, IO_VMA } type; + union { + struct page_list *pl; + struct bio_vec *bvec; + void *vma; + } ptr; + unsigned int offset; +}; + +struct notify { + io_notify_fn fn; + void *context; /* Context to pass to callback */ +}; + +/* IO control structure to pass in arguments to dm_io() */ +struct io_control { + int rw; /* READ|WRITE */ + int sync; /* sync if set else async */ + struct io_memory mem; /* Memory to do io to/from */ + struct notify notify; +}; /* - * Before anyone uses the IO interface they should call + * Before anyone uses the asynchronous IO interface they should call * dm_io_get(), specifying roughly how many pages they are * expecting to perform io on concurrently. * @@ -39,6 +61,16 @@ int dm_io_get(unsigned int num_pages); void dm_io_put(unsigned int num_pages); /* + * For async io calls, use dm_io_client_create() to create + * private mempools for the client. It returns a client handle + * to pass into the dm_io() function below. + * This function may block. + */ +void *dm_io_client_create(unsigned num_pages); +void dm_io_client_destroy(void *client); +int dm_io_client_resize(void *client, unsigned num_pages); + +/* * Synchronous IO. * * Please ensure that the rw flag in the next two functions is @@ -71,4 +103,10 @@ int dm_io_async_bvec(unsigned int num_re int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw, void *data, io_notify_fn fn, void *context); +/* + * (A)synchronous I/O interface using private per-client pools. + */ +int dm_io(void *client, struct io_control *control, unsigned num_regions, + struct io_region *region, unsigned long *error_bits); + #endif