diff options
author | Kent Overstreet <kmo@daterainc.com> | 2014-03-05 04:42:42 +0400 |
---|---|---|
committer | Kent Overstreet <kmo@daterainc.com> | 2014-03-18 23:23:35 +0400 |
commit | 2a285686c109816ba71a00b9278262cf02648258 (patch) | |
tree | 83be424d1b213a72a36de69b7ed98357c28cbfca /drivers/md/bcache/super.c | |
parent | 05335cff9f01555b769ac97b7bacc472b7ed047a (diff) | |
download | linux-2a285686c109816ba71a00b9278262cf02648258.tar.xz |
bcache: btree locking rework
Add a new lock, b->write_lock, which is required to actually modify - or write -
a btree node; this lock is only held for short durations.
This means we can write out a btree node without taking b->lock, which _is_ held
for long durations - solving a deadlock when btree_flush_write() (from the
journalling code) is called with a btree node locked.
Right now just occurs in bch_btree_set_root(), but with an upcoming journalling
rework is going to happen a lot more.
This also turns b->lock is now more of a read/intent lock instead of a
read/write lock - but not completely, since it still blocks readers. May turn it
into a real intent lock at some point in the future.
Signed-off-by: Kent Overstreet <kmo@daterainc.com>
Diffstat (limited to 'drivers/md/bcache/super.c')
-rw-r--r-- | drivers/md/bcache/super.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index ddfde380b49f..9ded06434e11 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1398,9 +1398,12 @@ static void cache_set_flush(struct closure *cl) list_add(&c->root->list, &c->btree_cache); /* Should skip this if we're unregistering because of an error */ - list_for_each_entry(b, &c->btree_cache, list) + list_for_each_entry(b, &c->btree_cache, list) { + mutex_lock(&b->write_lock); if (btree_node_dirty(b)) - bch_btree_node_write(b, NULL); + __bch_btree_node_write(b, NULL); + mutex_unlock(&b->write_lock); + } for_each_cache(ca, c, i) if (ca->alloc_thread) @@ -1667,8 +1670,10 @@ static void run_cache_set(struct cache_set *c) if (IS_ERR_OR_NULL(c->root)) goto err; + mutex_lock(&c->root->write_lock); bkey_copy_key(&c->root->key, &MAX_KEY); bch_btree_node_write(c->root, &cl); + mutex_unlock(&c->root->write_lock); bch_btree_set_root(c->root); rw_unlock(true, c->root); |