summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSlava Pestov <sviatoslavpestov@gmail.com>2014-06-13 11:53:08 -0700
committerKent Overstreet <kent.overstreet@gmail.com>2017-01-18 20:19:48 -0900
commit2a79a027d7ca65381cbbd52d555aad18867f42e5 (patch)
tree2cae10236819fa3095359ca570152e93186e9166
parent720a266720ce92540cfbc3f5c61cb968774c2e70 (diff)
bcache: btree node reserve for tiering
If the source tier is full, btree_check_reserve() would block. This could prevent tiering from making progress in copying to the destination tier. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--drivers/md/bcache/alloc.c2
-rw-r--r--drivers/md/bcache/bcache.h2
-rw-r--r--drivers/md/bcache/request.c30
-rw-r--r--drivers/md/bcache/request.h2
-rw-r--r--drivers/md/bcache/super.c2
-rw-r--r--drivers/md/bcache/tier.c1
6 files changed, 35 insertions, 4 deletions
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index 300aa6d7a7b0..9308c053e9fc 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -518,7 +518,7 @@ out:
BUG_ON(ca->set->gc_mark_valid &&
GC_MARK(b) != GC_MARK_DIRTY);
- if (reserve <= RESERVE_MOVINGGC_BTREE)
+ if (reserve <= RESERVE_METADATA_LAST)
SET_GC_MARK(b, GC_MARK_METADATA);
else
SET_GC_MARK(b, GC_MARK_DIRTY);
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 46524c1edeb3..b5db867a8c35 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -443,6 +443,8 @@ struct cached_dev {
enum alloc_reserve {
RESERVE_PRIO = BTREE_ID_NR,
RESERVE_MOVINGGC_BTREE,
+ RESERVE_TIERING_BTREE,
+ RESERVE_METADATA_LAST = RESERVE_TIERING_BTREE,
RESERVE_MOVINGGC,
RESERVE_NONE,
RESERVE_NR,
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 8ad057d6a84f..579cc9d289b0 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -48,6 +48,31 @@ static void bio_csum(struct bio *bio, struct bkey *k)
/* Insert data into cache */
+static enum alloc_reserve bch_btree_reserve(struct data_insert_op *op)
+{
+ if (op->moving_gc) {
+ /*
+ * free_inc.size buckets are set aside for moving GC
+ * btree node allocations. This means that if moving GC
+ * runs out of new buckets for btree nodes, it will have
+ * put back at least free_inc.size buckets back on
+ * free_inc, preventing a deadlock.
+ *
+ * XXX: figure out a less stupid way of achieving this
+ */
+ return RESERVE_MOVINGGC_BTREE;
+ } else if (op->tiering) {
+ /*
+ * Tiering needs a btree node reserve because of how
+ * btree_check_reserve() works -- if the cache tier is
+ * full, we don't want tiering to block forever.
+ */
+ return RESERVE_TIERING_BTREE;
+ }
+
+ return BTREE_ID_EXTENTS;
+}
+
/**
* bch_data_insert_keys - insert extent btree keys for a write
*/
@@ -56,12 +81,11 @@ static void bch_data_insert_keys(struct closure *cl)
struct data_insert_op *op = container_of(cl, struct data_insert_op, cl);
struct bkey *replace_key = op->replace ? &op->replace_key : NULL;
enum btree_id id = BTREE_ID_EXTENTS;
- enum alloc_reserve reserve = id;
+ enum alloc_reserve reserve;
unsigned i;
int ret;
- if (op->moving_gc)
- reserve = RESERVE_MOVINGGC_BTREE;
+ reserve = bch_btree_reserve(op);
ret = bch_btree_insert(op->c, id, reserve, &op->insert_keys,
replace_key, cl, op->flush);
diff --git a/drivers/md/bcache/request.h b/drivers/md/bcache/request.h
index 94631d33378a..38477c763884 100644
--- a/drivers/md/bcache/request.h
+++ b/drivers/md/bcache/request.h
@@ -37,6 +37,8 @@ struct data_insert_op {
/* Use moving GC reserves for buckets, btree nodes and
* open buckets? */
unsigned moving_gc:1;
+ /* Use tiering reserves for btree nodes? */
+ unsigned tiering:1;
/* Set on completion */
unsigned replace_collision:1;
/* Internal */
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 52879765c6d1..596d87f5e652 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1820,6 +1820,8 @@ static int cache_alloc(struct cache *ca)
if (!init_fifo(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) ||
!init_fifo(&ca->free[RESERVE_MOVINGGC_BTREE],
free_inc_reserve, GFP_KERNEL) ||
+ !init_fifo(&ca->free[RESERVE_TIERING_BTREE],
+ BTREE_NODE_RESERVE, GFP_KERNEL) ||
!init_fifo(&ca->free[RESERVE_MOVINGGC],
movinggc_reserve, GFP_KERNEL) ||
!init_fifo(&ca->free[RESERVE_NONE], reserve_none, GFP_KERNEL) ||
diff --git a/drivers/md/bcache/tier.c b/drivers/md/bcache/tier.c
index 6435f321d470..5ff73532996b 100644
--- a/drivers/md/bcache/tier.c
+++ b/drivers/md/bcache/tier.c
@@ -104,6 +104,7 @@ static void read_tiering(struct cache_set *c)
&io->bio.bio, 0,
false, false, false,
&io->w->key, &io->w->key);
+ io->op.tiering = 1;
io->op.tier = PTR_TIER(c, &w->key,
bch_extent_ptrs(&w->key) - 1) + 1;