diff options
Diffstat (limited to 'libbcachefs/btree_io.h')
-rw-r--r-- | libbcachefs/btree_io.h | 34 |
1 files changed, 26 insertions, 8 deletions
diff --git a/libbcachefs/btree_io.h b/libbcachefs/btree_io.h index c8417ac3..66053d53 100644 --- a/libbcachefs/btree_io.h +++ b/libbcachefs/btree_io.h @@ -19,7 +19,6 @@ struct btree_read_bio { }; struct btree_write_bio { - struct closure *cl; void *data; struct work_struct work; struct bch_write_bio wbio; @@ -91,22 +90,41 @@ void bch2_btree_complete_write(struct bch_fs *, struct btree *, void bch2_btree_write_error_work(struct work_struct *); void __bch2_btree_node_write(struct bch_fs *, struct btree *, - struct closure *, enum six_lock_type); + enum six_lock_type); 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); + enum six_lock_type); + +/* + * 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; -#define bch2_btree_node_write_dirty(_c, _b, _cl, cond) \ + 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, SIX_LOCK_read); \ break; \ } \ \ |