--- drivers/md/dm-crypt.c | 85 +++++++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 48 deletions(-) Index: linux-3.2-fast/drivers/md/dm-crypt.c =================================================================== --- linux-3.2-fast.orig/drivers/md/dm-crypt.c 2012-01-31 02:44:05.000000000 +0100 +++ linux-3.2-fast/drivers/md/dm-crypt.c 2012-01-31 02:49:30.000000000 +0100 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -48,9 +49,7 @@ struct dm_crypt_io { int error; sector_t sector; - struct list_head list; - - u64 sequence; + struct rb_node rb_node; }; struct dm_crypt_request { @@ -122,10 +121,7 @@ struct crypt_config { struct task_struct *write_thread; wait_queue_head_t write_thread_wait; - struct list_head write_thread_list; - - u64 write_sequence; - atomic64_t alloc_sequence; + struct rb_root write_tree; char *cipher; char *cipher_string; @@ -708,6 +704,7 @@ pop_from_list: r = crypto_ablkcipher_encrypt(req); else r = crypto_ablkcipher_decrypt(req); + r = 0; if (unlikely(r == -EBUSY)) { wait_for_completion(&busy_wait); } else if (likely(r != -EINPROGRESS)) { @@ -1074,8 +1071,8 @@ static int dmcrypt_write(void *data) { struct crypt_config *cc = data; while (1) { - struct list_head local_list; - unsigned spinlock_breaker; + struct rb_root write_tree; + struct dm_crypt_io *io; struct blk_plug plug; DECLARE_WAITQUEUE(wait, current); @@ -1083,7 +1080,7 @@ static int dmcrypt_write(void *data) spin_lock_irq(&cc->write_thread_wait.lock); continue_locked: - if (!list_empty(&cc->write_thread_list)) + if (!RB_EMPTY_ROOT(&cc->write_tree)) goto pop_from_list; __set_current_state(TASK_INTERRUPTIBLE); @@ -1105,35 +1102,22 @@ continue_locked: goto continue_locked; pop_from_list: - INIT_LIST_HEAD(&local_list); - spinlock_breaker = 0; - do { - struct dm_crypt_io *io = container_of( - cc->write_thread_list.next, - struct dm_crypt_io, list); - - BUG_ON(io->sequence < cc->write_sequence); - if (io->sequence != cc->write_sequence) - break; - cc->write_sequence++; - - list_del(&io->list); - list_add_tail(&io->list, &local_list); - if (unlikely(!(++spinlock_breaker & 63))) { - spin_unlock_irq(&cc->write_thread_wait.lock); - spin_lock_irq(&cc->write_thread_wait.lock); - } - } while (!list_empty(&cc->write_thread_list)); - + write_tree = cc->write_tree; + cc->write_tree = RB_ROOT; spin_unlock_irq(&cc->write_thread_wait.lock); + BUG_ON(rb_parent(write_tree.rb_node)); + + /* + * Note: we cannot walk the tree here with rb_next because + * the structures may be freed when kcryptd_io_write is called. + */ blk_start_plug(&plug); - while (!list_empty(&local_list)) { - struct dm_crypt_io *io = container_of(local_list.next, - struct dm_crypt_io, list); - list_del(&io->list); + do { + io = rb_entry(rb_first(&write_tree), struct dm_crypt_io, rb_node); + rb_erase(&io->rb_node, &write_tree); kcryptd_io_write(io); - } + } while (!RB_EMPTY_ROOT(&write_tree)); blk_finish_plug(&plug); } return 0; @@ -1143,18 +1127,27 @@ static void kcryptd_crypt_write_io_submi { struct crypt_config *cc = io->cc; unsigned long flags; - struct dm_crypt_io *io_list; + sector_t sector; + struct rb_node **p, *parent; spin_lock_irqsave(&cc->write_thread_wait.lock, flags); - list_for_each_entry_reverse(io_list, &cc->write_thread_list, list) { - if (io_list->sequence < io->sequence) { - list_add(&io->list, &io_list->list); - goto added; - } + + p = &cc->write_tree.rb_node; + parent = NULL; + sector = io->sector; + while (*p) { + parent = *p; +#define io_node rb_entry(parent, struct dm_crypt_io, rb_node) + if (sector < io_node->sector) + p = &io_node->rb_node.rb_left; + else + p = &io_node->rb_node.rb_right; +#undef io_node } - list_add(&io->list, &cc->write_thread_list); + rb_link_node(&io->rb_node, parent, p); + rb_insert_color(&io->rb_node, &cc->write_tree); + wake_up_locked(&cc->write_thread_wait); -added: spin_unlock_irqrestore(&cc->write_thread_wait.lock, flags); } @@ -1169,8 +1162,6 @@ static void kcryptd_crypt_write_convert( return; } - io->sequence = atomic64_inc_return(&io->cc->alloc_sequence) - 1; - crypt_convert(io, clone); } @@ -1721,9 +1712,7 @@ static int crypt_ctr(struct dm_target *t } init_waitqueue_head(&cc->write_thread_wait); - INIT_LIST_HEAD(&cc->write_thread_list); - cc->write_sequence = 0; - atomic64_set(&cc->alloc_sequence, 0); + cc->write_tree = RB_ROOT; cc->write_thread = kthread_create(dmcrypt_write, cc, "dmcrypt_write"); if (IS_ERR(cc->write_thread)) {