bcachefs: Refactor memcpy into direct assignment
[linux-block.git] / fs / bcachefs / sb-members.h
CommitLineData
fb8e5b4c
KO
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _BCACHEFS_SB_MEMBERS_H
3#define _BCACHEFS_SB_MEMBERS_H
4
3f7b9713
HS
5int bch2_members_v2_init(struct bch_fs *c);
6int bch_members_cpy_v2_v1(struct bch_sb_handle *disk_sb);
7struct bch_member *bch2_members_v2_get_mut(struct bch_sb *sb, int i);
1241df58
HS
8struct bch_member bch2_sb_member_get(struct bch_sb *sb, int i);
9
fb8e5b4c
KO
10static inline bool bch2_dev_is_online(struct bch_dev *ca)
11{
12 return !percpu_ref_is_zero(&ca->io_ref);
13}
14
15static inline bool bch2_dev_is_readable(struct bch_dev *ca)
16{
17 return bch2_dev_is_online(ca) &&
18 ca->mi.state != BCH_MEMBER_STATE_failed;
19}
20
21static inline bool bch2_dev_get_ioref(struct bch_dev *ca, int rw)
22{
23 if (!percpu_ref_tryget(&ca->io_ref))
24 return false;
25
26 if (ca->mi.state == BCH_MEMBER_STATE_rw ||
27 (ca->mi.state == BCH_MEMBER_STATE_ro && rw == READ))
28 return true;
29
30 percpu_ref_put(&ca->io_ref);
31 return false;
32}
33
34static inline unsigned dev_mask_nr(const struct bch_devs_mask *devs)
35{
36 return bitmap_weight(devs->d, BCH_SB_MEMBERS_MAX);
37}
38
39static inline bool bch2_dev_list_has_dev(struct bch_devs_list devs,
40 unsigned dev)
41{
42 unsigned i;
43
44 for (i = 0; i < devs.nr; i++)
45 if (devs.devs[i] == dev)
46 return true;
47
48 return false;
49}
50
51static inline void bch2_dev_list_drop_dev(struct bch_devs_list *devs,
52 unsigned dev)
53{
54 unsigned i;
55
56 for (i = 0; i < devs->nr; i++)
57 if (devs->devs[i] == dev) {
58 array_remove_item(devs->devs, devs->nr, i);
59 return;
60 }
61}
62
63static inline void bch2_dev_list_add_dev(struct bch_devs_list *devs,
64 unsigned dev)
65{
66 if (!bch2_dev_list_has_dev(*devs, dev)) {
67 BUG_ON(devs->nr >= ARRAY_SIZE(devs->devs));
68 devs->devs[devs->nr++] = dev;
69 }
70}
71
72static inline struct bch_devs_list bch2_dev_list_single(unsigned dev)
73{
74 return (struct bch_devs_list) { .nr = 1, .devs[0] = dev };
75}
76
77static inline struct bch_dev *__bch2_next_dev(struct bch_fs *c, unsigned *iter,
78 const struct bch_devs_mask *mask)
79{
80 struct bch_dev *ca = NULL;
81
82 while ((*iter = mask
83 ? find_next_bit(mask->d, c->sb.nr_devices, *iter)
84 : *iter) < c->sb.nr_devices &&
85 !(ca = rcu_dereference_check(c->devs[*iter],
86 lockdep_is_held(&c->state_lock))))
87 (*iter)++;
88
89 return ca;
90}
91
92#define for_each_member_device_rcu(ca, c, iter, mask) \
93 for ((iter) = 0; ((ca) = __bch2_next_dev((c), &(iter), mask)); (iter)++)
94
95static inline struct bch_dev *bch2_get_next_dev(struct bch_fs *c, unsigned *iter)
96{
97 struct bch_dev *ca;
98
99 rcu_read_lock();
100 if ((ca = __bch2_next_dev(c, iter, NULL)))
101 percpu_ref_get(&ca->ref);
102 rcu_read_unlock();
103
104 return ca;
105}
106
107/*
108 * If you break early, you must drop your ref on the current device
109 */
110#define for_each_member_device(ca, c, iter) \
111 for ((iter) = 0; \
112 (ca = bch2_get_next_dev(c, &(iter))); \
113 percpu_ref_put(&ca->ref), (iter)++)
114
115static inline struct bch_dev *bch2_get_next_online_dev(struct bch_fs *c,
116 unsigned *iter,
117 int state_mask)
118{
119 struct bch_dev *ca;
120
121 rcu_read_lock();
122 while ((ca = __bch2_next_dev(c, iter, NULL)) &&
123 (!((1 << ca->mi.state) & state_mask) ||
124 !percpu_ref_tryget(&ca->io_ref)))
125 (*iter)++;
126 rcu_read_unlock();
127
128 return ca;
129}
130
131#define __for_each_online_member(ca, c, iter, state_mask) \
132 for ((iter) = 0; \
133 (ca = bch2_get_next_online_dev(c, &(iter), state_mask)); \
134 percpu_ref_put(&ca->io_ref), (iter)++)
135
136#define for_each_online_member(ca, c, iter) \
137 __for_each_online_member(ca, c, iter, ~0)
138
139#define for_each_rw_member(ca, c, iter) \
140 __for_each_online_member(ca, c, iter, 1 << BCH_MEMBER_STATE_rw)
141
142#define for_each_readable_member(ca, c, iter) \
143 __for_each_online_member(ca, c, iter, \
144 (1 << BCH_MEMBER_STATE_rw)|(1 << BCH_MEMBER_STATE_ro))
145
146/*
147 * If a key exists that references a device, the device won't be going away and
148 * we can omit rcu_read_lock():
149 */
150static inline struct bch_dev *bch_dev_bkey_exists(const struct bch_fs *c, unsigned idx)
151{
152 EBUG_ON(idx >= c->sb.nr_devices || !c->devs[idx]);
153
154 return rcu_dereference_check(c->devs[idx], 1);
155}
156
157static inline struct bch_dev *bch_dev_locked(struct bch_fs *c, unsigned idx)
158{
159 EBUG_ON(idx >= c->sb.nr_devices || !c->devs[idx]);
160
161 return rcu_dereference_protected(c->devs[idx],
162 lockdep_is_held(&c->sb_lock) ||
163 lockdep_is_held(&c->state_lock));
164}
165
166/* XXX kill, move to struct bch_fs */
167static inline struct bch_devs_mask bch2_online_devs(struct bch_fs *c)
168{
169 struct bch_devs_mask devs;
170 struct bch_dev *ca;
171 unsigned i;
172
173 memset(&devs, 0, sizeof(devs));
174 for_each_online_member(ca, c, i)
175 __set_bit(ca->dev_idx, devs.d);
176 return devs;
177}
178
9af26120 179extern const struct bch_sb_field_ops bch_sb_field_ops_members_v1;
3f7b9713
HS
180extern const struct bch_sb_field_ops bch_sb_field_ops_members_v2;
181
fb8e5b4c 182#endif /* _BCACHEFS_SB_MEMBERS_H */