]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/alloc_foreground.h
Update bcachefs sources to 5963d1b1a4 bcacehfs: Fix bch2_get_alloc_in_memory_pos()
[bcachefs-tools-debian] / libbcachefs / alloc_foreground.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _BCACHEFS_ALLOC_FOREGROUND_H
3 #define _BCACHEFS_ALLOC_FOREGROUND_H
4
5 #include "bcachefs.h"
6 #include "alloc_types.h"
7 #include "extents.h"
8 #include "super.h"
9
10 #include <linux/hash.h>
11
12 struct bkey;
13 struct bch_dev;
14 struct bch_fs;
15 struct bch_devs_List;
16
17 extern const char * const bch2_alloc_reserves[];
18
19 struct dev_alloc_list {
20         unsigned        nr;
21         u8              devs[BCH_SB_MEMBERS_MAX];
22 };
23
24 struct dev_alloc_list bch2_dev_alloc_list(struct bch_fs *,
25                                           struct dev_stripe_state *,
26                                           struct bch_devs_mask *);
27 void bch2_dev_stripe_increment(struct bch_dev *, struct dev_stripe_state *);
28
29 long bch2_bucket_alloc_new_fs(struct bch_dev *);
30
31 struct open_bucket *bch2_bucket_alloc(struct bch_fs *, struct bch_dev *,
32                                       enum alloc_reserve, bool,
33                                       struct closure *);
34
35 static inline void ob_push(struct bch_fs *c, struct open_buckets *obs,
36                            struct open_bucket *ob)
37 {
38         BUG_ON(obs->nr >= ARRAY_SIZE(obs->v));
39
40         obs->v[obs->nr++] = ob - c->open_buckets;
41 }
42
43 #define open_bucket_for_each(_c, _obs, _ob, _i)                         \
44         for ((_i) = 0;                                                  \
45              (_i) < (_obs)->nr &&                                       \
46              ((_ob) = (_c)->open_buckets + (_obs)->v[_i], true);        \
47              (_i)++)
48
49 static inline struct open_bucket *ec_open_bucket(struct bch_fs *c,
50                                                  struct open_buckets *obs)
51 {
52         struct open_bucket *ob;
53         unsigned i;
54
55         open_bucket_for_each(c, obs, ob, i)
56                 if (ob->ec)
57                         return ob;
58
59         return NULL;
60 }
61
62 void bch2_open_bucket_write_error(struct bch_fs *,
63                         struct open_buckets *, unsigned);
64
65 void __bch2_open_bucket_put(struct bch_fs *, struct open_bucket *);
66
67 static inline void bch2_open_bucket_put(struct bch_fs *c, struct open_bucket *ob)
68 {
69         if (atomic_dec_and_test(&ob->pin))
70                 __bch2_open_bucket_put(c, ob);
71 }
72
73 static inline void bch2_open_buckets_put(struct bch_fs *c,
74                                          struct open_buckets *ptrs)
75 {
76         struct open_bucket *ob;
77         unsigned i;
78
79         open_bucket_for_each(c, ptrs, ob, i)
80                 bch2_open_bucket_put(c, ob);
81         ptrs->nr = 0;
82 }
83
84 static inline void bch2_alloc_sectors_done_inlined(struct bch_fs *c, struct write_point *wp)
85 {
86         struct open_buckets ptrs = { .nr = 0 }, keep = { .nr = 0 };
87         struct open_bucket *ob;
88         unsigned i;
89
90         open_bucket_for_each(c, &wp->ptrs, ob, i)
91                 ob_push(c, !ob->sectors_free ? &ptrs : &keep, ob);
92         wp->ptrs = keep;
93
94         mutex_unlock(&wp->lock);
95
96         bch2_open_buckets_put(c, &ptrs);
97 }
98
99 static inline void bch2_open_bucket_get(struct bch_fs *c,
100                                         struct write_point *wp,
101                                         struct open_buckets *ptrs)
102 {
103         struct open_bucket *ob;
104         unsigned i;
105
106         open_bucket_for_each(c, &wp->ptrs, ob, i) {
107                 ob->data_type = wp->data_type;
108                 atomic_inc(&ob->pin);
109                 ob_push(c, ptrs, ob);
110         }
111 }
112
113 static inline open_bucket_idx_t *open_bucket_hashslot(struct bch_fs *c,
114                                                   unsigned dev, u64 bucket)
115 {
116         return c->open_buckets_hash +
117                 (jhash_3words(dev, bucket, bucket >> 32, 0) &
118                  (OPEN_BUCKETS_COUNT - 1));
119 }
120
121 static inline bool bch2_bucket_is_open(struct bch_fs *c, unsigned dev, u64 bucket)
122 {
123         open_bucket_idx_t slot = *open_bucket_hashslot(c, dev, bucket);
124
125         while (slot) {
126                 struct open_bucket *ob = &c->open_buckets[slot];
127
128                 if (ob->dev == dev && ob->bucket == bucket)
129                         return true;
130
131                 slot = ob->hash;
132         }
133
134         return false;
135 }
136
137 static inline bool bch2_bucket_is_open_safe(struct bch_fs *c, unsigned dev, u64 bucket)
138 {
139         bool ret;
140
141         if (bch2_bucket_is_open(c, dev, bucket))
142                 return true;
143
144         spin_lock(&c->freelist_lock);
145         ret = bch2_bucket_is_open(c, dev, bucket);
146         spin_unlock(&c->freelist_lock);
147
148         return ret;
149 }
150
151 int bch2_bucket_alloc_set(struct bch_fs *, struct open_buckets *,
152                       struct dev_stripe_state *, struct bch_devs_mask *,
153                       unsigned, unsigned *, bool *, enum alloc_reserve,
154                       unsigned, struct closure *);
155
156 int bch2_alloc_sectors_start_trans(struct btree_trans *,
157                                    unsigned, unsigned,
158                                    struct write_point_specifier,
159                                    struct bch_devs_list *,
160                                    unsigned, unsigned,
161                                    enum alloc_reserve,
162                                    unsigned,
163                                    struct closure *,
164                                    struct write_point **);
165
166 struct bch_extent_ptr bch2_ob_ptr(struct bch_fs *, struct open_bucket *);
167
168 /*
169  * Append pointers to the space we just allocated to @k, and mark @sectors space
170  * as allocated out of @ob
171  */
172 static inline void
173 bch2_alloc_sectors_append_ptrs_inlined(struct bch_fs *c, struct write_point *wp,
174                                        struct bkey_i *k, unsigned sectors,
175                                        bool cached)
176 {
177         struct open_bucket *ob;
178         unsigned i;
179
180         BUG_ON(sectors > wp->sectors_free);
181         wp->sectors_free -= sectors;
182
183         open_bucket_for_each(c, &wp->ptrs, ob, i) {
184                 struct bch_dev *ca = bch_dev_bkey_exists(c, ob->dev);
185                 struct bch_extent_ptr ptr = bch2_ob_ptr(c, ob);
186
187                 ptr.cached = cached ||
188                         (!ca->mi.durability &&
189                          wp->data_type == BCH_DATA_user);
190
191                 bch2_bkey_append_ptr(k, ptr);
192
193                 BUG_ON(sectors > ob->sectors_free);
194                 ob->sectors_free -= sectors;
195         }
196 }
197
198 void bch2_alloc_sectors_append_ptrs(struct bch_fs *, struct write_point *,
199                                     struct bkey_i *, unsigned, bool);
200 void bch2_alloc_sectors_done(struct bch_fs *, struct write_point *);
201
202 void bch2_open_buckets_stop_dev(struct bch_fs *, struct bch_dev *,
203                                 struct open_buckets *);
204
205 void bch2_writepoint_stop(struct bch_fs *, struct bch_dev *,
206                           struct write_point *);
207
208 static inline struct write_point_specifier writepoint_hashed(unsigned long v)
209 {
210         return (struct write_point_specifier) { .v = v | 1 };
211 }
212
213 static inline struct write_point_specifier writepoint_ptr(struct write_point *wp)
214 {
215         return (struct write_point_specifier) { .v = (unsigned long) wp };
216 }
217
218 void bch2_fs_allocator_foreground_init(struct bch_fs *);
219
220 void bch2_open_buckets_to_text(struct printbuf *, struct bch_fs *);
221
222 #endif /* _BCACHEFS_ALLOC_FOREGROUND_H */