summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2015-04-16 18:55:43 -0700
committerKent Overstreet <kent.overstreet@gmail.com>2016-10-07 12:33:53 -0800
commitd97ba2d11e9d0eafd4e23c81eb320fc044793fea (patch)
tree71911d253dce47cba9f79e9f1bb6fd03750d972c
parentdad5f473e5e06f830368ce1732f2d29bbf827630 (diff)
bcache: rework some -ENOSPC stuff
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--drivers/md/bcache/btree.c43
-rw-r--r--drivers/md/bcache/btree.h12
-rw-r--r--drivers/md/bcache/gc.c3
-rw-r--r--drivers/md/bcache/inode.c2
-rw-r--r--drivers/md/bcache/io.c3
-rw-r--r--drivers/md/bcache/journal.c2
-rw-r--r--drivers/md/bcache/writeback.c4
7 files changed, 44 insertions, 25 deletions
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index b6f8046ac8e1..1c69d9457d69 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -1614,18 +1614,24 @@ struct btree *btree_node_alloc_replacement(struct btree *b)
static int __btree_check_reserve(struct cache_set *c,
enum alloc_reserve reserve,
unsigned required,
- struct closure *cl)
+ struct closure *cl,
+ bool check_enospc)
{
+ struct cache_group *devs = &c->cache_tiers[0];
struct cache *ca;
unsigned i;
int ret;
- rcu_read_lock();
+ /*
+ * XXX: racy... the whole btree node reserve thing needs to be
+ * completely reworked
+ */
+ if (!devs->nr_devices)
+ return -ENOSPC;
- for_each_cache_rcu(ca, c, i) {
- if (CACHE_STATE(&ca->mi) != CACHE_ACTIVE)
- continue;
+ rcu_read_lock();
+ group_for_each_cache_rcu(ca, devs, i) {
spin_lock(&ca->freelist_lock);
if (fifo_used(&ca->free[reserve]) < required) {
@@ -1633,11 +1639,12 @@ static int __btree_check_reserve(struct cache_set *c,
fifo_used(&ca->free[reserve]),
required, cl);
- if (cl) {
+ if (!cl ||
+ (check_enospc && cache_set_full(c))) {
+ ret = -ENOSPC;
+ } else {
closure_wait(&c->freelist_wait, cl);
ret = -EAGAIN;
- } else {
- ret = -ENOSPC;
}
spin_unlock(&ca->freelist_lock);
@@ -1655,13 +1662,13 @@ static int __btree_check_reserve(struct cache_set *c,
int btree_check_reserve(struct btree *b, struct btree_iter *iter,
enum alloc_reserve reserve,
- unsigned extra_nodes)
+ unsigned extra_nodes, bool check_enospc)
{
unsigned depth = btree_node_root(b)->level - b->level;
return __btree_check_reserve(b->c, reserve,
btree_reserve_required_nodes(depth) + extra_nodes,
- iter ? &iter->cl : NULL);
+ iter ? &iter->cl : NULL, check_enospc);
}
static struct btree *__btree_root_alloc(struct cache_set *c, unsigned level,
@@ -1684,12 +1691,16 @@ int bch_btree_root_alloc(struct cache_set *c, enum btree_id id,
{
struct closure cl;
struct btree *b;
+ int ret;
closure_init_stack(&cl);
- while (__btree_check_reserve(c, id, 1, &cl))
+ while ((ret = __btree_check_reserve(c, id, 1, &cl, true)) == -EAGAIN)
closure_sync(&cl);
+ if (ret == -ENOSPC)
+ return ret;
+
b = __btree_root_alloc(c, 0, id);
bch_btree_node_write(b, writes, NULL);
@@ -1746,7 +1757,8 @@ int bch_btree_node_rewrite(struct btree *b, struct btree_iter *iter, bool wait)
if (!bch_btree_iter_upgrade(iter))
return -EINTR;
- ret = btree_check_reserve(b, wait ? iter : NULL, iter->btree_id, 1);
+ ret = btree_check_reserve(b, wait ? iter : NULL,
+ iter->btree_id, 1, true);
if (ret) {
trace_bcache_btree_gc_rewrite_node_fail(b);
return ret;
@@ -2073,7 +2085,8 @@ static int btree_split(struct btree *b,
BUG_ON(!btree_node_intent_locked(iter, btree_node_root(b)->level));
/* After this check we cannot return -EAGAIN anymore */
- ret = btree_check_reserve(b, iter, iter->btree_id, 0);
+ ret = btree_check_reserve(b, iter, iter->btree_id, 0,
+ !(flags & BTREE_INSERT_NOFAIL));
if (ret) {
/* If splitting an interior node, we've already split a leaf,
* so we should have checked for sufficient reserve. We can't
@@ -2467,7 +2480,7 @@ int bch_btree_insert_check_key(struct btree_iter *iter,
*/
int bch_btree_insert(struct cache_set *c, enum btree_id id,
struct keylist *keys, struct bch_replace_info *replace,
- struct closure *persistent, u64 *journal_seq)
+ struct closure *persistent, u64 *journal_seq, int flags)
{
struct btree_iter iter;
int ret, ret2;
@@ -2480,7 +2493,7 @@ int bch_btree_insert(struct cache_set *c, enum btree_id id,
goto out;
ret = bch_btree_insert_at(&iter, keys, replace,
- persistent, journal_seq, 0);
+ persistent, journal_seq, flags);
out: ret2 = bch_btree_iter_unlock(&iter);
return ret ?: ret2;
diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h
index e777ec4bdb8e..557c2f77fa29 100644
--- a/drivers/md/bcache/btree.h
+++ b/drivers/md/bcache/btree.h
@@ -434,7 +434,7 @@ struct btree *__btree_node_alloc_replacement(struct btree *,
struct bkey_format);
struct btree *btree_node_alloc_replacement(struct btree *);
int btree_check_reserve(struct btree *, struct btree_iter *,
- enum alloc_reserve, unsigned);
+ enum alloc_reserve, unsigned, bool);
int bch_btree_root_alloc(struct cache_set *, enum btree_id, struct closure *);
int bch_btree_root_read(struct cache_set *, enum btree_id,
@@ -455,7 +455,10 @@ int bch_btree_insert_node(struct btree *, struct btree_iter *,
* Don't drop/retake locks: instead return -EINTR if need to upgrade to intent
* locks, -EAGAIN if need to wait on btree reserve
*/
-#define BTREE_INSERT_ATOMIC 1
+#define BTREE_INSERT_ATOMIC (1 << 0)
+
+/* Don't check for -ENOSPC: */
+#define BTREE_INSERT_NOFAIL (1 << 1)
/*
* Fail a btree insert if dirty stale pointers are being added
@@ -463,14 +466,15 @@ int bch_btree_insert_node(struct btree *, struct btree_iter *,
* Needs to be set for compare exchange and device removal, and not
* set for journal replay. See big comment in bch_insert_fixup_extent()
*/
-#define FAIL_IF_STALE 2
+#define FAIL_IF_STALE (1 << 2)
int bch_btree_insert_at(struct btree_iter *, struct keylist *,
struct bch_replace_info *, struct closure *,
u64 *, unsigned);
int bch_btree_insert_check_key(struct btree_iter *, struct bkey_i *);
int bch_btree_insert(struct cache_set *, enum btree_id, struct keylist *,
- struct bch_replace_info *, struct closure *, u64 *);
+ struct bch_replace_info *, struct closure *,
+ u64 *, int flags);
int bch_btree_update(struct cache_set *, enum btree_id, struct bkey_i *,
struct closure *, u64 *);
diff --git a/drivers/md/bcache/gc.c b/drivers/md/bcache/gc.c
index 4668cd7445a4..db433b50ec63 100644
--- a/drivers/md/bcache/gc.c
+++ b/drivers/md/bcache/gc.c
@@ -420,7 +420,8 @@ static void bch_coalesce_nodes(struct btree *old_nodes[GC_MERGE_NODES],
block_bytes(c)) > blocks)
return;
- if (btree_check_reserve(parent, NULL, iter->btree_id, nr_old_nodes) ||
+ if (btree_check_reserve(parent, NULL, iter->btree_id,
+ nr_old_nodes, false) ||
bch_keylist_realloc(&keylist,
(BKEY_U64s + BKEY_EXTENT_MAX_U64s) * nr_old_nodes)) {
trace_bcache_btree_gc_coalesce_fail(c);
diff --git a/drivers/md/bcache/inode.c b/drivers/md/bcache/inode.c
index 09b21f509013..f54c89428574 100644
--- a/drivers/md/bcache/inode.c
+++ b/drivers/md/bcache/inode.c
@@ -175,7 +175,7 @@ int bch_inode_rm(struct cache_set *c, u64 inode_nr)
return bch_btree_insert(c, BTREE_ID_INODES,
&keylist_single(&delete),
- NULL, NULL, NULL);
+ NULL, NULL, NULL, 0);
}
int bch_blockdev_inode_find_by_uuid(struct cache_set *c, uuid_le *uuid,
diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c
index 9b638562a912..2cb909fa60ce 100644
--- a/drivers/md/bcache/io.c
+++ b/drivers/md/bcache/io.c
@@ -322,7 +322,8 @@ static void bch_write_index(struct closure *cl)
int ret = bch_btree_insert(op->c, BTREE_ID_EXTENTS, &op->insert_keys,
op->replace ? &op->replace_info : NULL,
op->flush ? &op->cl : NULL,
- op->journal_seq);
+ op->journal_seq,
+ op->check_enospc ? 0 : BTREE_INSERT_NOFAIL);
if (ret) {
__bcache_io_error(op->c, "btree IO error");
op->error = ret;
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index 9df11b1594e9..c616eb4caa59 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -843,7 +843,7 @@ static int bch_journal_replay_key(struct cache_set *c, enum btree_id id,
if (do_subtract)
bkey_copy(&temp.key, k);
- ret = bch_btree_insert(c, id, &keylist_single(k), NULL, NULL, NULL);
+ ret = bch_btree_insert(c, id, &keylist_single(k), NULL, NULL, NULL, 0);
if (ret)
return ret;
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
index 4f42adc75e9a..8e3854108735 100644
--- a/drivers/md/bcache/writeback.c
+++ b/drivers/md/bcache/writeback.c
@@ -119,8 +119,8 @@ static void write_dirty_finish(struct closure *cl)
SET_EXTENT_CACHED(&bkey_i_to_extent(keys.top)->v, true);
bch_keylist_enqueue(&keys);
- ret = bch_btree_insert(dc->disk.c, BTREE_ID_EXTENTS,
- &keys, &io->replace, NULL, NULL);
+ ret = bch_btree_insert(dc->disk.c, BTREE_ID_EXTENTS, &keys,
+ &io->replace, NULL, NULL, 0);
if (io->replace.successes == 0)
trace_bcache_writeback_collision(&io->replace.key.k);