diff options
-rw-r--r-- | drivers/md/bcache/btree.c | 43 | ||||
-rw-r--r-- | drivers/md/bcache/btree.h | 12 | ||||
-rw-r--r-- | drivers/md/bcache/gc.c | 3 | ||||
-rw-r--r-- | drivers/md/bcache/inode.c | 2 | ||||
-rw-r--r-- | drivers/md/bcache/io.c | 3 | ||||
-rw-r--r-- | drivers/md/bcache/journal.c | 2 | ||||
-rw-r--r-- | drivers/md/bcache/writeback.c | 4 |
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); |