Linux Device Mapper development
 help / color / mirror / Atom feed
From: Mike Snitzer <snitzer@redhat.com>
To: dm-devel@redhat.com
Cc: ejt@redhat.com
Subject: [for-3.19 PATCH 01/17] dm bufio: switch from a huge hash table to an rbtree
Date: Fri, 17 Oct 2014 02:06:51 -0400	[thread overview]
Message-ID: <1413526027-21630-2-git-send-email-snitzer@redhat.com> (raw)
In-Reply-To: <1413526027-21630-1-git-send-email-snitzer@redhat.com>

From: Joe Thornber <ejt@redhat.com>

Converting over to using an rbtree eliminates a fixed 8MB allocation
from vmalloc space for the hash table.

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 drivers/md/dm-bufio.c | 97 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 54 insertions(+), 43 deletions(-)

diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index 0be200b..dcaa1d9 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -14,6 +14,7 @@
 #include <linux/vmalloc.h>
 #include <linux/shrinker.h>
 #include <linux/module.h>
+#include <linux/rbtree.h>
 
 #define DM_MSG_PREFIX "bufio"
 
@@ -48,14 +49,6 @@
 #define DM_BUFIO_INLINE_VECS		16
 
 /*
- * Buffer hash
- */
-#define DM_BUFIO_HASH_BITS	20
-#define DM_BUFIO_HASH(block) \
-	((((block) >> DM_BUFIO_HASH_BITS) ^ (block)) & \
-	 ((1 << DM_BUFIO_HASH_BITS) - 1))
-
-/*
  * Don't try to use kmem_cache_alloc for blocks larger than this.
  * For explanation, see alloc_buffer_data below.
  */
@@ -106,7 +99,7 @@ struct dm_bufio_client {
 
 	unsigned minimum_buffers;
 
-	struct hlist_head *cache_hash;
+	struct rb_root buffer_tree;
 	wait_queue_head_t free_buffer_wait;
 
 	int async_write_error;
@@ -135,7 +128,7 @@ enum data_mode {
 };
 
 struct dm_buffer {
-	struct hlist_node hash_list;
+	struct rb_node node;
 	struct list_head lru_list;
 	sector_t block;
 	void *data;
@@ -253,6 +246,53 @@ static LIST_HEAD(dm_bufio_all_clients);
  */
 static DEFINE_MUTEX(dm_bufio_clients_lock);
 
+/*----------------------------------------------------------------
+ * A red/black tree acts as an index for all the buffers.
+ *--------------------------------------------------------------*/
+static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
+{
+	struct rb_node *n = c->buffer_tree.rb_node;
+	struct dm_buffer *b;
+
+	while (n) {
+		b = container_of(n, struct dm_buffer, node);
+
+		if (b->block == block)
+			return b;
+
+		n = (b->block < block) ? n->rb_left : n->rb_right;
+	}
+
+	return NULL;
+}
+
+static void __insert(struct dm_bufio_client *c, struct dm_buffer *b)
+{
+	struct rb_node **new = &c->buffer_tree.rb_node, *parent = NULL;
+	struct dm_buffer *found;
+
+	while (*new) {
+		found = container_of(*new, struct dm_buffer, node);
+
+		if (found->block == b->block) {
+			BUG_ON(found != b);
+			return;
+		}
+
+		parent = *new;
+		new = (found->block < b->block) ?
+			&((*new)->rb_left) : &((*new)->rb_right);
+	}
+
+	rb_link_node(&b->node, parent, new);
+	rb_insert_color(&b->node, &c->buffer_tree);
+}
+
+static void __remove(struct dm_bufio_client *c, struct dm_buffer *b)
+{
+	rb_erase(&b->node, &c->buffer_tree);
+}
+
 /*----------------------------------------------------------------*/
 
 static void adjust_total_allocated(enum data_mode data_mode, long diff)
@@ -434,7 +474,7 @@ static void __link_buffer(struct dm_buffer *b, sector_t block, int dirty)
 	b->block = block;
 	b->list_mode = dirty;
 	list_add(&b->lru_list, &c->lru[dirty]);
-	hlist_add_head(&b->hash_list, &c->cache_hash[DM_BUFIO_HASH(block)]);
+	__insert(b->c, b);
 	b->last_accessed = jiffies;
 }
 
@@ -448,7 +488,7 @@ static void __unlink_buffer(struct dm_buffer *b)
 	BUG_ON(!c->n_buffers[b->list_mode]);
 
 	c->n_buffers[b->list_mode]--;
-	hlist_del(&b->hash_list);
+	__remove(b->c, b);
 	list_del(&b->lru_list);
 }
 
@@ -888,23 +928,6 @@ static void __check_watermark(struct dm_bufio_client *c,
 		__write_dirty_buffers_async(c, 1, write_list);
 }
 
-/*
- * Find a buffer in the hash.
- */
-static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
-{
-	struct dm_buffer *b;
-
-	hlist_for_each_entry(b, &c->cache_hash[DM_BUFIO_HASH(block)],
-			     hash_list) {
-		dm_bufio_cond_resched();
-		if (b->block == block)
-			return b;
-	}
-
-	return NULL;
-}
-
 /*----------------------------------------------------------------
  * Getting a buffer
  *--------------------------------------------------------------*/
@@ -1534,11 +1557,7 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
 		r = -ENOMEM;
 		goto bad_client;
 	}
-	c->cache_hash = vmalloc(sizeof(struct hlist_head) << DM_BUFIO_HASH_BITS);
-	if (!c->cache_hash) {
-		r = -ENOMEM;
-		goto bad_hash;
-	}
+	c->buffer_tree = RB_ROOT;
 
 	c->bdev = bdev;
 	c->block_size = block_size;
@@ -1557,9 +1576,6 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
 		c->n_buffers[i] = 0;
 	}
 
-	for (i = 0; i < 1 << DM_BUFIO_HASH_BITS; i++)
-		INIT_HLIST_HEAD(&c->cache_hash[i]);
-
 	mutex_init(&c->lock);
 	INIT_LIST_HEAD(&c->reserved_buffers);
 	c->need_reserved_buffers = reserved_buffers;
@@ -1633,8 +1649,6 @@ bad_cache:
 	}
 	dm_io_client_destroy(c->dm_io);
 bad_dm_io:
-	vfree(c->cache_hash);
-bad_hash:
 	kfree(c);
 bad_client:
 	return ERR_PTR(r);
@@ -1661,9 +1675,7 @@ void dm_bufio_client_destroy(struct dm_bufio_client *c)
 
 	mutex_unlock(&dm_bufio_clients_lock);
 
-	for (i = 0; i < 1 << DM_BUFIO_HASH_BITS; i++)
-		BUG_ON(!hlist_empty(&c->cache_hash[i]));
-
+	BUG_ON(!RB_EMPTY_ROOT(&c->buffer_tree));
 	BUG_ON(c->need_reserved_buffers);
 
 	while (!list_empty(&c->reserved_buffers)) {
@@ -1681,7 +1693,6 @@ void dm_bufio_client_destroy(struct dm_bufio_client *c)
 		BUG_ON(c->n_buffers[i]);
 
 	dm_io_client_destroy(c->dm_io);
-	vfree(c->cache_hash);
 	kfree(c);
 }
 EXPORT_SYMBOL_GPL(dm_bufio_client_destroy);
-- 
1.9.3

  reply	other threads:[~2014-10-17  6:06 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-17  6:06 [for-3.19 PATCH 00/17] dm thin: performance improvements Mike Snitzer
2014-10-17  6:06 ` Mike Snitzer [this message]
2014-10-17  6:06 ` [for-3.19 PATCH 02/17] dm bufio: evict buffers that are past the max age but retain some buffers Mike Snitzer
2014-10-17  6:06 ` [for-3.19 PATCH 03/17] dm bio prison: switch to using a red black tree Mike Snitzer
2014-10-17  6:06 ` [for-3.19 PATCH 04/17] dm thin metadata: change dm_thin_find_block to allow blocking, but not issuing, IO Mike Snitzer
2014-10-17  6:06 ` [for-3.19 PATCH 05/17] dm transaction manager: add support for prefetching blocks of metadata Mike Snitzer
2014-10-17  6:06 ` [for-3.19 PATCH 06/17] dm thin: prefetch missing metadata pages Mike Snitzer
2014-10-17  6:06 ` [for-3.19 PATCH 07/17] dm thin: throttle incoming IO Mike Snitzer
2014-10-17  6:06 ` [for-3.19 PATCH 08/17] dm thin: adjust max_sectors_kb based on thinp blocksize Mike Snitzer
2014-10-17  6:06 ` [for-3.19 PATCH 09/17] dm: improve documentation and code clarity in dm_merge_bvec Mike Snitzer
2014-10-17  6:07 ` [for-3.19 PATCH 10/17] dm thin: implement thin_merge Mike Snitzer
2014-10-17  6:07 ` [for-3.19 PATCH 11/17] dm thin: grab a virtual cell before looking up the mapping Mike Snitzer
2014-10-17  6:07 ` [for-3.19 PATCH 12/17] dm thin: performance improvement to discard processing Mike Snitzer
2014-10-17  6:07 ` [for-3.19 PATCH 13/17] dm thin: factor out remap_and_issue_overwrite Mike Snitzer
2014-10-17  6:07 ` [for-3.19 PATCH 14/17] dm thin: defer whole cells rather than individual bios Mike Snitzer
2014-10-17  6:07 ` [for-3.19 PATCH 15/17] dm thin: remap the bios in a cell immediately Mike Snitzer
2014-10-17  6:07 ` [for-3.19 PATCH 16/17] dm thin: direct dispatch when breaking sharing Mike Snitzer
2014-10-17  6:07 ` [for-3.19 PATCH 17/17] dm thin: sort the deferred cells Mike Snitzer
2014-10-17 18:31 ` [for-3.19 PATCH 00/17] dm thin: performance improvements Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 01/17] dm bufio: switch from a huge hash table to an rbtree Mike Snitzer
2014-10-21 22:48     ` Mikulas Patocka
2014-10-22  9:41       ` Joe Thornber
2014-10-17 18:37   ` [for-3.19 PATCH v2 02/17] dm bufio: evict buffers that are past the max age but retain some buffers Mike Snitzer
2014-10-31 16:37     ` Mikulas Patocka
2014-10-17 18:37   ` [for-3.19 PATCH v2 03/17] dm bio prison: switch to using a red black tree Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 04/17] dm thin metadata: change dm_thin_find_block to allow blocking, but not issuing, IO Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 05/17] dm transaction manager: add support for prefetching blocks of metadata Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 06/17] dm thin: prefetch missing metadata pages Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 07/17] dm thin: throttle incoming IO Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 08/17] dm thin: adjust max_sectors_kb based on thinp blocksize Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 09/17] dm: improve documentation and code clarity in dm_merge_bvec Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 10/17] dm thin: implement thin_merge Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 11/17] dm thin: grab a virtual cell before looking up the mapping Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 12/17] dm thin: performance improvement to discard processing Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 13/17] dm thin: factor out remap_and_issue_overwrite Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 14/17] dm thin: defer whole cells rather than individual bios Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 15/17] dm thin: remap the bios in a cell immediately Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 16/17] dm thin: direct dispatch when breaking sharing Mike Snitzer
2014-10-17 18:37   ` [for-3.19 PATCH v2 17/17] dm thin: sort the deferred cells Mike Snitzer
2014-10-19 23:02   ` [for-3.19 PATCH v2 fix 18/17] dm thin: fix process_shared_bio (fixes SnapshotTests) Mike Snitzer
2014-10-19 23:02   ` [for-3.19 PATCH v2 fix 19/17] dm thin: requeue deferred_cells when in requeue_mode Mike Snitzer
2014-10-19 23:02   ` [for-3.19 PATCH v2 20/17] dm thin: optimize retry_bios_on_resume Mike Snitzer
2014-10-19 23:02   ` [for-3.19 PATCH v2 21/17] dm thin: refactor requeue_io to eliminate spinlock bouncing Mike Snitzer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1413526027-21630-2-git-send-email-snitzer@redhat.com \
    --to=snitzer@redhat.com \
    --cc=dm-devel@redhat.com \
    --cc=ejt@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox