]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
bcache: try to set b->parent properly
authorSlava Pestov <sp@daterainc.com>
Sat, 12 Jul 2014 07:22:53 +0000 (00:22 -0700)
committerKent Overstreet <kmo@daterainc.com>
Mon, 4 Aug 2014 22:23:04 +0000 (15:23 -0700)
bcache_flash_dev.ktest would reliably crash with 8k and 16k bucket size
before; now it passes.

Change-Id: Ib542232235e39298c3a7548fe52b645cabb823d1

drivers/md/bcache/btree.c
drivers/md/bcache/btree.h
drivers/md/bcache/super.c

index 776583f7247db449cbf05b8835ebc521185d810f..00cde40db57269bb173104ab3632b8a99e95c4f6 100644 (file)
 ({                                                                     \
        int _r, l = (b)->level - 1;                                     \
        bool _w = l <= (op)->lock;                                      \
-       struct btree *_child = bch_btree_node_get((b)->c, op, key, l, _w);\
+       struct btree *_child = bch_btree_node_get((b)->c, op, key, l,   \
+                                                 _w, b);               \
        if (!IS_ERR(_child)) {                                          \
-               _child->parent = (b);                                   \
                _r = bch_btree_ ## fn(_child, op, ##__VA_ARGS__);       \
                rw_unlock(_w, _child);                                  \
        } else                                                          \
                rw_lock(_w, _b, _b->level);                             \
                if (_b == (c)->root &&                                  \
                    _w == insert_lock(op, _b)) {                        \
-                       _b->parent = NULL;                              \
                        _r = bch_btree_ ## fn(_b, op, ##__VA_ARGS__);   \
                }                                                       \
                rw_unlock(_w, _b);                                      \
@@ -967,7 +966,8 @@ err:
  * level and op->lock.
  */
 struct btree *bch_btree_node_get(struct cache_set *c, struct btree_op *op,
-                                struct bkey *k, int level, bool write)
+                                struct bkey *k, int level, bool write,
+                                struct btree *parent)
 {
        int i = 0;
        struct btree *b;
@@ -1002,6 +1002,7 @@ retry:
                BUG_ON(b->level != level);
        }
 
+       b->parent = parent;
        b->accessed = 1;
 
        for (; i <= b->keys.nsets && b->keys.set[i].size; i++) {
@@ -1022,15 +1023,16 @@ retry:
        return b;
 }
 
-static void btree_node_prefetch(struct cache_set *c, struct bkey *k, int level)
+static void btree_node_prefetch(struct btree *parent, struct bkey *k)
 {
        struct btree *b;
 
-       mutex_lock(&c->bucket_lock);
-       b = mca_alloc(c, NULL, k, level);
-       mutex_unlock(&c->bucket_lock);
+       mutex_lock(&parent->c->bucket_lock);
+       b = mca_alloc(parent->c, NULL, k, parent->level - 1);
+       mutex_unlock(&parent->c->bucket_lock);
 
        if (!IS_ERR_OR_NULL(b)) {
+               b->parent = parent;
                bch_btree_node_read(b);
                rw_unlock(true, b);
        }
@@ -1061,7 +1063,8 @@ static void btree_node_free(struct btree *b)
 }
 
 struct btree *__bch_btree_node_alloc(struct cache_set *c, struct btree_op *op,
-                                    int level, bool wait)
+                                    int level, bool wait,
+                                    struct btree *parent)
 {
        BKEY_PADDED(key) k;
        struct btree *b = ERR_PTR(-EAGAIN);
@@ -1085,6 +1088,7 @@ retry:
        }
 
        b->accessed = 1;
+       b->parent = parent;
        bch_bset_init_next(&b->keys, b->keys.set->data, bset_magic(&b->c->sb));
 
        mutex_unlock(&c->bucket_lock);
@@ -1101,15 +1105,16 @@ err:
 }
 
 static struct btree *bch_btree_node_alloc(struct cache_set *c,
-                                         struct btree_op *op, int level)
+                                         struct btree_op *op, int level,
+                                         struct btree *parent)
 {
-       return __bch_btree_node_alloc(c, op, level, op != NULL);
+       return __bch_btree_node_alloc(c, op, level, op != NULL, parent);
 }
 
 static struct btree *btree_node_alloc_replacement(struct btree *b,
                                                  struct btree_op *op)
 {
-       struct btree *n = bch_btree_node_alloc(b->c, op, b->level);
+       struct btree *n = bch_btree_node_alloc(b->c, op, b->level, b->parent);
        if (!IS_ERR_OR_NULL(n)) {
                mutex_lock(&n->write_lock);
                bch_btree_sort_into(&b->keys, &n->keys, &b->c->sort);
@@ -1523,7 +1528,7 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
                k = bch_btree_iter_next_filter(&iter, &b->keys, bch_ptr_bad);
                if (k) {
                        r->b = bch_btree_node_get(b->c, op, k, b->level - 1,
-                                                 true);
+                                                 true, b);
                        if (IS_ERR(r->b)) {
                                ret = PTR_ERR(r->b);
                                break;
@@ -1818,7 +1823,7 @@ static int bch_btree_check_recurse(struct btree *b, struct btree_op *op)
                        k = bch_btree_iter_next_filter(&iter, &b->keys,
                                                       bch_ptr_bad);
                        if (k)
-                               btree_node_prefetch(b->c, k, b->level - 1);
+                               btree_node_prefetch(b, k);
 
                        if (p)
                                ret = btree(check_recurse, p, b, op);
@@ -1983,12 +1988,12 @@ static int btree_split(struct btree *b, struct btree_op *op,
 
                trace_bcache_btree_node_split(b, btree_bset_first(n1)->keys);
 
-               n2 = bch_btree_node_alloc(b->c, op, b->level);
+               n2 = bch_btree_node_alloc(b->c, op, b->level, b->parent);
                if (IS_ERR(n2))
                        goto err_free1;
 
                if (!b->parent) {
-                       n3 = bch_btree_node_alloc(b->c, op, b->level + 1);
+                       n3 = bch_btree_node_alloc(b->c, op, b->level + 1, NULL);
                        if (IS_ERR(n3))
                                goto err_free2;
                }
index 00441821f5adbe68d31e3c4225e52f83e1ec7dfe..5c391fa01bedbfba3f1dea062605460ccadc1c6a 100644 (file)
@@ -243,9 +243,9 @@ void bch_btree_node_write(struct btree *, struct closure *);
 
 void bch_btree_set_root(struct btree *);
 struct btree *__bch_btree_node_alloc(struct cache_set *, struct btree_op *,
-                                    int, bool);
+                                    int, bool, struct btree *);
 struct btree *bch_btree_node_get(struct cache_set *, struct btree_op *,
-                                struct bkey *, int, bool);
+                                struct bkey *, int, bool, struct btree *);
 
 int bch_btree_insert_check_key(struct btree *, struct btree_op *,
                               struct bkey *);
index 12ad381bdbab9ca5560a342383e4103ae9051644..b6114d672413004273b91cf743e0b872f899245c 100644 (file)
@@ -1601,7 +1601,7 @@ static void run_cache_set(struct cache_set *c)
                        goto err;
 
                err = "error reading btree root";
-               c->root = bch_btree_node_get(c, NULL, k, j->btree_level, true);
+               c->root = bch_btree_node_get(c, NULL, k, j->btree_level, true, NULL);
                if (IS_ERR_OR_NULL(c->root))
                        goto err;
 
@@ -1676,7 +1676,7 @@ static void run_cache_set(struct cache_set *c)
                        goto err;
 
                err = "cannot allocate new btree root";
-               c->root = __bch_btree_node_alloc(c, NULL, 0, true);
+               c->root = __bch_btree_node_alloc(c, NULL, 0, true, NULL);
                if (IS_ERR_OR_NULL(c->root))
                        goto err;