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>

Index: linux-2.6.18-rc7/drivers/md/dm-io.c
===================================================================
--- linux-2.6.18-rc7.orig/drivers/md/dm-io.c	2006-10-13 17:10:24.000000000 +0100
+++ linux-2.6.18-rc7/drivers/md/dm-io.c	2006-10-13 17:10:24.000000000 +0100
@@ -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.18-rc7/drivers/md/dm-io.h
===================================================================
--- linux-2.6.18-rc7.orig/drivers/md/dm-io.h	2006-10-06 14:42:07.000000000 +0100
+++ linux-2.6.18-rc7/drivers/md/dm-io.h	2006-10-13 17:10:24.000000000 +0100
@@ -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
