summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-01-14 16:26:42 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2018-05-22 00:44:18 -0400
commitfe79e76e31f8e254d82a4d5b5019b1d89bfe2863 (patch)
treeba149304d3509b1fd490e34d886576014d0e5d42
parent479e7b1b28403b813aed98924fcf4a39d5f11960 (diff)
bcachefs: better comments/cleanups
-rw-r--r--fs/bcachefs/btree_io.h29
-rw-r--r--fs/bcachefs/btree_update_interior.c28
-rw-r--r--fs/bcachefs/btree_update_leaf.c2
3 files changed, 50 insertions, 9 deletions
diff --git a/fs/bcachefs/btree_io.h b/fs/bcachefs/btree_io.h
index c8417ac32fea..bfb437b7dd85 100644
--- a/fs/bcachefs/btree_io.h
+++ b/fs/bcachefs/btree_io.h
@@ -97,16 +97,35 @@ bool bch2_btree_post_write_cleanup(struct bch_fs *, struct btree *);
void bch2_btree_node_write(struct bch_fs *, struct btree *,
struct closure *, enum six_lock_type);
-#define bch2_btree_node_write_dirty(_c, _b, _cl, cond) \
+/*
+ * btree_node_dirty() can be cleared with only a read lock,
+ * and for bch2_btree_node_write_cond() we want to set need_write iff it's
+ * still dirty:
+ */
+static inline void set_btree_node_need_write_if_dirty(struct btree *b)
+{
+ unsigned long old, new, v = READ_ONCE(b->flags);
+
+ do {
+ old = new = v;
+
+ if (!(old & (1 << BTREE_NODE_dirty)))
+ return;
+
+ new |= (1 << BTREE_NODE_need_write);
+ } while ((v = cmpxchg(&b->flags, old, new)) != old);
+}
+
+#define bch2_btree_node_write_cond(_c, _b, cond) \
do { \
while ((_b)->written && btree_node_dirty(_b) && (cond)) { \
- set_btree_node_need_write(_b); \
- \
- if (!btree_node_may_write(_b)) \
+ if (!btree_node_may_write(_b)) { \
+ set_btree_node_need_write_if_dirty(_b); \
break; \
+ } \
\
if (!btree_node_write_in_flight(_b)) { \
- bch2_btree_node_write(_c, _b, _cl, SIX_LOCK_read);\
+ bch2_btree_node_write(_c, _b, NULL, SIX_LOCK_read);\
break; \
} \
\
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c
index a0f37c4ceb09..b307e33e41c5 100644
--- a/fs/bcachefs/btree_update_interior.c
+++ b/fs/bcachefs/btree_update_interior.c
@@ -601,8 +601,12 @@ static void btree_update_nodes_reachable(struct closure *cl)
b->will_make_reachable = NULL;
mutex_unlock(&c->btree_interior_update_lock);
+ /*
+ * b->will_make_reachable prevented it from being written, so
+ * write it now if it needs to be written:
+ */
six_lock_read(&b->lock);
- bch2_btree_node_write_dirty(c, b, NULL, btree_node_need_write(b));
+ bch2_btree_node_write_cond(c, b, btree_node_need_write(b));
six_unlock_read(&b->lock);
mutex_lock(&c->btree_interior_update_lock);
}
@@ -651,8 +655,11 @@ retry:
list_del(&as->write_blocked_list);
mutex_unlock(&c->btree_interior_update_lock);
- bch2_btree_node_write_dirty(c, b, NULL,
- btree_node_need_write(b));
+ /*
+ * b->write_blocked prevented it from being written, so
+ * write it now if it needs to be written:
+ */
+ bch2_btree_node_write_cond(c, b, btree_node_need_write(b));
six_unlock_read(&b->lock);
break;
@@ -952,6 +959,12 @@ void bch2_btree_interior_update_will_free_node(struct btree_update *as,
clear_btree_node_need_write(b);
w = btree_current_write(b);
+ /*
+ * Does this node have any btree_update operations waiting on this node
+ * to be written?
+ *
+ * If so, wake them up when this btree_update operation is reachable:
+ */
llist_for_each_entry_safe(cl, cl_n, llist_del_all(&w->wait.list), list)
llist_add(&cl->list, &as->wait.list);
@@ -972,6 +985,15 @@ void bch2_btree_interior_update_will_free_node(struct btree_update *as,
&as->journal, interior_update_flush);
bch2_journal_pin_drop(&c->journal, &w->journal);
+ /*
+ * Is this a node that isn't reachable on disk yet?
+ *
+ * Nodes that aren't reachable yet have writes blocked until they're
+ * reachable - now that we've cancelled any pending writes and moved
+ * things waiting on that write to wait on this update, we can drop this
+ * node from the list of nodes that the other update is making
+ * reachable, prior to freeing it:
+ */
if (b->will_make_reachable)
__btree_interior_update_drop_new_node(b);
diff --git a/fs/bcachefs/btree_update_leaf.c b/fs/bcachefs/btree_update_leaf.c
index e62e0d2e7fec..dbf705696973 100644
--- a/fs/bcachefs/btree_update_leaf.c
+++ b/fs/bcachefs/btree_update_leaf.c
@@ -109,7 +109,7 @@ static void __btree_node_flush(struct journal *j, struct journal_entry_pin *pin,
struct btree *b = container_of(w, struct btree, writes[i]);
six_lock_read(&b->lock);
- bch2_btree_node_write_dirty(c, b, NULL,
+ bch2_btree_node_write_cond(c, b,
(btree_current_write(b) == w &&
w->journal.pin_list == journal_seq_pin(j, seq)));
six_unlock_read(&b->lock);