|
@@ -99,6 +99,13 @@ static const char *op_type(struct btree_op *op)
|
|
|
return op_types[op->type];
|
|
|
}
|
|
|
|
|
|
+enum {
|
|
|
+ BTREE_INSERT_STATUS_INSERT,
|
|
|
+ BTREE_INSERT_STATUS_BACK_MERGE,
|
|
|
+ BTREE_INSERT_STATUS_OVERWROTE,
|
|
|
+ BTREE_INSERT_STATUS_FRONT_MERGE,
|
|
|
+};
|
|
|
+
|
|
|
#define MAX_NEED_GC 64
|
|
|
#define MAX_SAVE_PRIO 72
|
|
|
|
|
@@ -116,6 +123,78 @@ void bch_btree_op_init_stack(struct btree_op *op)
|
|
|
op->lock = -1;
|
|
|
}
|
|
|
|
|
|
+static inline bool should_split(struct btree *b)
|
|
|
+{
|
|
|
+ struct bset *i = write_block(b);
|
|
|
+ return b->written >= btree_blocks(b) ||
|
|
|
+ (b->written + __set_blocks(i, i->keys + 15, b->c)
|
|
|
+ > btree_blocks(b));
|
|
|
+}
|
|
|
+
|
|
|
+#define insert_lock(s, b) ((b)->level <= (s)->lock)
|
|
|
+
|
|
|
+/*
|
|
|
+ * These macros are for recursing down the btree - they handle the details of
|
|
|
+ * locking and looking up nodes in the cache for you. They're best treated as
|
|
|
+ * mere syntax when reading code that uses them.
|
|
|
+ *
|
|
|
+ * op->lock determines whether we take a read or a write lock at a given depth.
|
|
|
+ * If you've got a read lock and find that you need a write lock (i.e. you're
|
|
|
+ * going to have to split), set op->lock and return -EINTR; btree_root() will
|
|
|
+ * call you again and you'll have the correct lock.
|
|
|
+ */
|
|
|
+
|
|
|
+/**
|
|
|
+ * btree - recurse down the btree on a specified key
|
|
|
+ * @fn: function to call, which will be passed the child node
|
|
|
+ * @key: key to recurse on
|
|
|
+ * @b: parent btree node
|
|
|
+ * @op: pointer to struct btree_op
|
|
|
+ */
|
|
|
+#define btree(fn, key, b, op, ...) \
|
|
|
+({ \
|
|
|
+ int _r, l = (b)->level - 1; \
|
|
|
+ bool _w = l <= (op)->lock; \
|
|
|
+ struct btree *_child = bch_btree_node_get((b)->c, key, l, _w); \
|
|
|
+ if (!IS_ERR(_child)) { \
|
|
|
+ _child->parent = (b); \
|
|
|
+ _r = bch_btree_ ## fn(_child, op, ##__VA_ARGS__); \
|
|
|
+ rw_unlock(_w, _child); \
|
|
|
+ } else \
|
|
|
+ _r = PTR_ERR(_child); \
|
|
|
+ _r; \
|
|
|
+})
|
|
|
+
|
|
|
+/**
|
|
|
+ * btree_root - call a function on the root of the btree
|
|
|
+ * @fn: function to call, which will be passed the child node
|
|
|
+ * @c: cache set
|
|
|
+ * @op: pointer to struct btree_op
|
|
|
+ */
|
|
|
+#define btree_root(fn, c, op, ...) \
|
|
|
+({ \
|
|
|
+ int _r = -EINTR; \
|
|
|
+ do { \
|
|
|
+ struct btree *_b = (c)->root; \
|
|
|
+ bool _w = insert_lock(op, _b); \
|
|
|
+ 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); \
|
|
|
+ bch_cannibalize_unlock(c); \
|
|
|
+ if (_r == -ENOSPC) { \
|
|
|
+ wait_event((c)->try_wait, \
|
|
|
+ !(c)->try_harder); \
|
|
|
+ _r = -EINTR; \
|
|
|
+ } \
|
|
|
+ } while (_r == -EINTR); \
|
|
|
+ \
|
|
|
+ _r; \
|
|
|
+})
|
|
|
+
|
|
|
/* Btree key manipulation */
|
|
|
|
|
|
void __bkey_put(struct cache_set *c, struct bkey *k)
|
|
@@ -811,7 +890,7 @@ static struct btree *mca_cannibalize(struct cache_set *c, struct bkey *k)
|
|
|
* cannibalize_bucket() will take. This means every time we unlock the root of
|
|
|
* the btree, we need to release this lock if we have it held.
|
|
|
*/
|
|
|
-void bch_cannibalize_unlock(struct cache_set *c)
|
|
|
+static void bch_cannibalize_unlock(struct cache_set *c)
|
|
|
{
|
|
|
if (c->try_harder == current) {
|
|
|
bch_time_stats_update(&c->try_harder_time, c->try_harder_start);
|
|
@@ -2262,7 +2341,7 @@ static int submit_partial_cache_hit(struct btree *b, struct btree_op *op,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int bch_btree_search_recurse(struct btree *b, struct btree_op *op)
|
|
|
+static int bch_btree_search_recurse(struct btree *b, struct btree_op *op)
|
|
|
{
|
|
|
struct search *s = container_of(op, struct search, op);
|
|
|
struct bio *bio = &s->bio.bio;
|
|
@@ -2296,6 +2375,18 @@ int bch_btree_search_recurse(struct btree *b, struct btree_op *op)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+void bch_btree_search_async(struct closure *cl)
|
|
|
+{
|
|
|
+ struct btree_op *op = container_of(cl, struct btree_op, cl);
|
|
|
+
|
|
|
+ int ret = btree_root(search_recurse, op->c, op);
|
|
|
+
|
|
|
+ if (ret == -EAGAIN)
|
|
|
+ continue_at(cl, bch_btree_search_async, bcache_wq);
|
|
|
+
|
|
|
+ closure_return(cl);
|
|
|
+}
|
|
|
+
|
|
|
/* Map across nodes or keys */
|
|
|
|
|
|
static int bch_btree_map_nodes_recurse(struct btree *b, struct btree_op *op,
|