summaryrefslogtreecommitdiff
path: root/libbcachefs/btree_io.h
blob: 66053d53616033bbc3b8bf799196b462d4166f1b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#ifndef _BCACHEFS_BTREE_IO_H
#define _BCACHEFS_BTREE_IO_H

#include "extents.h"
#include "io_types.h"

struct bch_fs;
struct btree_write;
struct btree;
struct btree_iter;

struct btree_read_bio {
	struct bch_fs		*c;
	unsigned		submit_time_us;
	u64			start_time;
	struct extent_pick_ptr	pick;
	struct work_struct	work;
	struct bio		bio;
};

struct btree_write_bio {
	void			*data;
	struct work_struct	work;
	struct bch_write_bio	wbio;
};

static inline void btree_node_io_unlock(struct btree *b)
{
	EBUG_ON(!btree_node_write_in_flight(b));
	clear_btree_node_write_in_flight(b);
	wake_up_bit(&b->flags, BTREE_NODE_write_in_flight);
}

static inline void btree_node_io_lock(struct btree *b)
{
	wait_on_bit_lock_io(&b->flags, BTREE_NODE_write_in_flight,
			    TASK_UNINTERRUPTIBLE);
}

static inline void btree_node_wait_on_io(struct btree *b)
{
	wait_on_bit_io(&b->flags, BTREE_NODE_write_in_flight,
		       TASK_UNINTERRUPTIBLE);
}

static inline bool btree_node_may_write(struct btree *b)
{
	return list_empty_careful(&b->write_blocked) &&
		!b->will_make_reachable;
}

enum compact_mode {
	COMPACT_LAZY,
	COMPACT_WRITTEN,
	COMPACT_WRITTEN_NO_WRITE_LOCK,
};

bool __bch2_compact_whiteouts(struct bch_fs *, struct btree *, enum compact_mode);

static inline bool bch2_maybe_compact_whiteouts(struct bch_fs *c, struct btree *b)
{
	struct bset_tree *t;

	for_each_bset(b, t) {
		unsigned live_u64s = b->nr.bset_u64s[t - b->set];
		unsigned bset_u64s = le16_to_cpu(bset(b, t)->u64s);

		if (live_u64s * 4 < bset_u64s * 3)
			goto compact;
	}

	return false;
compact:
	return __bch2_compact_whiteouts(c, b, COMPACT_LAZY);
}

void bch2_btree_sort_into(struct bch_fs *, struct btree *, struct btree *);

void bch2_btree_build_aux_trees(struct btree *);
void bch2_btree_init_next(struct bch_fs *, struct btree *,
			 struct btree_iter *);

int bch2_btree_node_read_done(struct bch_fs *, struct btree *, bool);
void bch2_btree_node_read(struct bch_fs *, struct btree *, bool);
int bch2_btree_root_read(struct bch_fs *, enum btree_id,
			 const struct bkey_i *, unsigned);

void bch2_btree_complete_write(struct bch_fs *, struct btree *,
			      struct btree_write *);
void bch2_btree_write_error_work(struct work_struct *);

void __bch2_btree_node_write(struct bch_fs *, struct btree *,
			    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 *,
			  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;

		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)) {	\
		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, SIX_LOCK_read);	\
			break;						\
		}							\
									\
		six_unlock_read(&(_b)->lock);				\
		btree_node_wait_on_io(_b);				\
		six_lock_read(&(_b)->lock);				\
	}								\
} while (0)

void bch2_btree_verify_flushed(struct bch_fs *);

#endif /* _BCACHEFS_BTREE_IO_H */