Commit | Line | Data |
---|---|---|
fb8e5b4c KO |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _BCACHEFS_SB_MEMBERS_H | |
3 | #define _BCACHEFS_SB_MEMBERS_H | |
4 | ||
3f7b9713 HS |
5 | int bch2_members_v2_init(struct bch_fs *c); |
6 | int bch_members_cpy_v2_v1(struct bch_sb_handle *disk_sb); | |
7 | struct bch_member *bch2_members_v2_get_mut(struct bch_sb *sb, int i); | |
1241df58 HS |
8 | struct bch_member bch2_sb_member_get(struct bch_sb *sb, int i); |
9 | ||
fb8e5b4c KO |
10 | static inline bool bch2_dev_is_online(struct bch_dev *ca) |
11 | { | |
12 | return !percpu_ref_is_zero(&ca->io_ref); | |
13 | } | |
14 | ||
15 | static 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 | ||
21 | static 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 | ||
34 | static inline unsigned dev_mask_nr(const struct bch_devs_mask *devs) | |
35 | { | |
36 | return bitmap_weight(devs->d, BCH_SB_MEMBERS_MAX); | |
37 | } | |
38 | ||
39 | static 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 | ||
51 | static 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 | ||
63 | static 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 | ||
72 | static 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 | ||
77 | static 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 | ||
95 | static 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 | ||
115 | static 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 | */ | |
150 | static 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 | ||
157 | static 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 */ | |
167 | static 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 | 179 | extern const struct bch_sb_field_ops bch_sb_field_ops_members_v1; |
3f7b9713 HS |
180 | extern const struct bch_sb_field_ops bch_sb_field_ops_members_v2; |
181 | ||
fb8e5b4c | 182 | #endif /* _BCACHEFS_SB_MEMBERS_H */ |