Skip to content

Commit 3db2776

Browse files
David Jefferysnitm
authored andcommitted
dm snapshot: improve performance by switching out_of_order_list to rbtree
copy_complete()'s processing of out_of_order_list can result in quadratic complexity in the worst case. As such it was the source of consuming too much cpu and the source of significant loss in performance. Fix this by converting out_of_order_list to an rbtree. This improved a dm-snapshot test copy workload from 32 seconds to 4 seconds. Signed-off-by: David Jeffery <djeffery@redhat.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Tested-by: Brett Hull <bhull@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
1 parent 784c9a2 commit 3db2776

File tree

1 file changed

+26
-13
lines changed

1 file changed

+26
-13
lines changed

drivers/md/dm-snap.c

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ struct dm_snapshot {
8585
* A list of pending exceptions that completed out of order.
8686
* Protected by kcopyd single-threaded callback.
8787
*/
88-
struct list_head out_of_order_list;
88+
struct rb_root out_of_order_tree;
8989

9090
mempool_t pending_pool;
9191

@@ -200,7 +200,7 @@ struct dm_snap_pending_exception {
200200
/* A sequence number, it is used for in-order completion. */
201201
sector_t exception_sequence;
202202

203-
struct list_head out_of_order_entry;
203+
struct rb_node out_of_order_node;
204204

205205
/*
206206
* For writing a complete chunk, bypassing the copy.
@@ -1173,7 +1173,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
11731173
atomic_set(&s->pending_exceptions_count, 0);
11741174
s->exception_start_sequence = 0;
11751175
s->exception_complete_sequence = 0;
1176-
INIT_LIST_HEAD(&s->out_of_order_list);
1176+
s->out_of_order_tree = RB_ROOT;
11771177
mutex_init(&s->lock);
11781178
INIT_LIST_HEAD(&s->list);
11791179
spin_lock_init(&s->pe_lock);
@@ -1539,28 +1539,41 @@ static void copy_callback(int read_err, unsigned long write_err, void *context)
15391539
pe->copy_error = read_err || write_err;
15401540

15411541
if (pe->exception_sequence == s->exception_complete_sequence) {
1542+
struct rb_node *next;
1543+
15421544
s->exception_complete_sequence++;
15431545
complete_exception(pe);
15441546

1545-
while (!list_empty(&s->out_of_order_list)) {
1546-
pe = list_entry(s->out_of_order_list.next,
1547-
struct dm_snap_pending_exception, out_of_order_entry);
1547+
next = rb_first(&s->out_of_order_tree);
1548+
while (next) {
1549+
pe = rb_entry(next, struct dm_snap_pending_exception,
1550+
out_of_order_node);
15481551
if (pe->exception_sequence != s->exception_complete_sequence)
15491552
break;
1553+
next = rb_next(next);
15501554
s->exception_complete_sequence++;
1551-
list_del(&pe->out_of_order_entry);
1555+
rb_erase(&pe->out_of_order_node, &s->out_of_order_tree);
15521556
complete_exception(pe);
1557+
cond_resched();
15531558
}
15541559
} else {
1555-
struct list_head *lh;
1560+
struct rb_node *parent = NULL;
1561+
struct rb_node **p = &s->out_of_order_tree.rb_node;
15561562
struct dm_snap_pending_exception *pe2;
15571563

1558-
list_for_each_prev(lh, &s->out_of_order_list) {
1559-
pe2 = list_entry(lh, struct dm_snap_pending_exception, out_of_order_entry);
1560-
if (pe2->exception_sequence < pe->exception_sequence)
1561-
break;
1564+
while (*p) {
1565+
pe2 = rb_entry(*p, struct dm_snap_pending_exception, out_of_order_node);
1566+
parent = *p;
1567+
1568+
BUG_ON(pe->exception_sequence == pe2->exception_sequence);
1569+
if (pe->exception_sequence < pe2->exception_sequence)
1570+
p = &((*p)->rb_left);
1571+
else
1572+
p = &((*p)->rb_right);
15621573
}
1563-
list_add(&pe->out_of_order_entry, lh);
1574+
1575+
rb_link_node(&pe->out_of_order_node, parent, p);
1576+
rb_insert_color(&pe->out_of_order_node, &s->out_of_order_tree);
15641577
}
15651578
}
15661579

0 commit comments

Comments
 (0)