]>
Commit | Line | Data |
---|---|---|
550fa228 JB |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | ||
784352fe | 3 | #include "misc.h" |
550fa228 JB |
4 | #include "ctree.h" |
5 | #include "block-rsv.h" | |
6 | #include "space-info.h" | |
67f9c220 | 7 | #include "transaction.h" |
550fa228 JB |
8 | |
9 | static u64 block_rsv_release_bytes(struct btrfs_fs_info *fs_info, | |
10 | struct btrfs_block_rsv *block_rsv, | |
11 | struct btrfs_block_rsv *dest, u64 num_bytes, | |
12 | u64 *qgroup_to_release_ret) | |
13 | { | |
14 | struct btrfs_space_info *space_info = block_rsv->space_info; | |
15 | u64 qgroup_to_release = 0; | |
16 | u64 ret; | |
17 | ||
18 | spin_lock(&block_rsv->lock); | |
19 | if (num_bytes == (u64)-1) { | |
20 | num_bytes = block_rsv->size; | |
21 | qgroup_to_release = block_rsv->qgroup_rsv_size; | |
22 | } | |
23 | block_rsv->size -= num_bytes; | |
24 | if (block_rsv->reserved >= block_rsv->size) { | |
25 | num_bytes = block_rsv->reserved - block_rsv->size; | |
26 | block_rsv->reserved = block_rsv->size; | |
27 | block_rsv->full = 1; | |
28 | } else { | |
29 | num_bytes = 0; | |
30 | } | |
31 | if (block_rsv->qgroup_rsv_reserved >= block_rsv->qgroup_rsv_size) { | |
32 | qgroup_to_release = block_rsv->qgroup_rsv_reserved - | |
33 | block_rsv->qgroup_rsv_size; | |
34 | block_rsv->qgroup_rsv_reserved = block_rsv->qgroup_rsv_size; | |
35 | } else { | |
36 | qgroup_to_release = 0; | |
37 | } | |
38 | spin_unlock(&block_rsv->lock); | |
39 | ||
40 | ret = num_bytes; | |
41 | if (num_bytes > 0) { | |
42 | if (dest) { | |
43 | spin_lock(&dest->lock); | |
44 | if (!dest->full) { | |
45 | u64 bytes_to_add; | |
46 | ||
47 | bytes_to_add = dest->size - dest->reserved; | |
48 | bytes_to_add = min(num_bytes, bytes_to_add); | |
49 | dest->reserved += bytes_to_add; | |
50 | if (dest->reserved >= dest->size) | |
51 | dest->full = 1; | |
52 | num_bytes -= bytes_to_add; | |
53 | } | |
54 | spin_unlock(&dest->lock); | |
55 | } | |
56 | if (num_bytes) | |
d05e4649 JB |
57 | btrfs_space_info_free_bytes_may_use(fs_info, |
58 | space_info, | |
59 | num_bytes); | |
550fa228 JB |
60 | } |
61 | if (qgroup_to_release_ret) | |
62 | *qgroup_to_release_ret = qgroup_to_release; | |
63 | return ret; | |
64 | } | |
65 | ||
66 | int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src, | |
67 | struct btrfs_block_rsv *dst, u64 num_bytes, | |
68 | bool update_size) | |
69 | { | |
70 | int ret; | |
71 | ||
72 | ret = btrfs_block_rsv_use_bytes(src, num_bytes); | |
73 | if (ret) | |
74 | return ret; | |
75 | ||
76 | btrfs_block_rsv_add_bytes(dst, num_bytes, update_size); | |
77 | return 0; | |
78 | } | |
79 | ||
80 | void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type) | |
81 | { | |
82 | memset(rsv, 0, sizeof(*rsv)); | |
83 | spin_lock_init(&rsv->lock); | |
84 | rsv->type = type; | |
85 | } | |
86 | ||
87 | void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info, | |
88 | struct btrfs_block_rsv *rsv, | |
89 | unsigned short type) | |
90 | { | |
91 | btrfs_init_block_rsv(rsv, type); | |
92 | rsv->space_info = btrfs_find_space_info(fs_info, | |
93 | BTRFS_BLOCK_GROUP_METADATA); | |
94 | } | |
95 | ||
96 | struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_fs_info *fs_info, | |
97 | unsigned short type) | |
98 | { | |
99 | struct btrfs_block_rsv *block_rsv; | |
100 | ||
101 | block_rsv = kmalloc(sizeof(*block_rsv), GFP_NOFS); | |
102 | if (!block_rsv) | |
103 | return NULL; | |
104 | ||
105 | btrfs_init_metadata_block_rsv(fs_info, block_rsv, type); | |
106 | return block_rsv; | |
107 | } | |
108 | ||
109 | void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info, | |
110 | struct btrfs_block_rsv *rsv) | |
111 | { | |
112 | if (!rsv) | |
113 | return; | |
114 | btrfs_block_rsv_release(fs_info, rsv, (u64)-1); | |
115 | kfree(rsv); | |
116 | } | |
117 | ||
118 | int btrfs_block_rsv_add(struct btrfs_root *root, | |
119 | struct btrfs_block_rsv *block_rsv, u64 num_bytes, | |
120 | enum btrfs_reserve_flush_enum flush) | |
121 | { | |
122 | int ret; | |
123 | ||
124 | if (num_bytes == 0) | |
125 | return 0; | |
126 | ||
127 | ret = btrfs_reserve_metadata_bytes(root, block_rsv, num_bytes, flush); | |
128 | if (!ret) | |
129 | btrfs_block_rsv_add_bytes(block_rsv, num_bytes, true); | |
130 | ||
131 | return ret; | |
132 | } | |
133 | ||
134 | int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor) | |
135 | { | |
136 | u64 num_bytes = 0; | |
137 | int ret = -ENOSPC; | |
138 | ||
139 | if (!block_rsv) | |
140 | return 0; | |
141 | ||
142 | spin_lock(&block_rsv->lock); | |
143 | num_bytes = div_factor(block_rsv->size, min_factor); | |
144 | if (block_rsv->reserved >= num_bytes) | |
145 | ret = 0; | |
146 | spin_unlock(&block_rsv->lock); | |
147 | ||
148 | return ret; | |
149 | } | |
150 | ||
151 | int btrfs_block_rsv_refill(struct btrfs_root *root, | |
152 | struct btrfs_block_rsv *block_rsv, u64 min_reserved, | |
153 | enum btrfs_reserve_flush_enum flush) | |
154 | { | |
155 | u64 num_bytes = 0; | |
156 | int ret = -ENOSPC; | |
157 | ||
158 | if (!block_rsv) | |
159 | return 0; | |
160 | ||
161 | spin_lock(&block_rsv->lock); | |
162 | num_bytes = min_reserved; | |
163 | if (block_rsv->reserved >= num_bytes) | |
164 | ret = 0; | |
165 | else | |
166 | num_bytes -= block_rsv->reserved; | |
167 | spin_unlock(&block_rsv->lock); | |
168 | ||
169 | if (!ret) | |
170 | return 0; | |
171 | ||
172 | ret = btrfs_reserve_metadata_bytes(root, block_rsv, num_bytes, flush); | |
173 | if (!ret) { | |
174 | btrfs_block_rsv_add_bytes(block_rsv, num_bytes, false); | |
175 | return 0; | |
176 | } | |
177 | ||
178 | return ret; | |
179 | } | |
180 | ||
181 | u64 __btrfs_block_rsv_release(struct btrfs_fs_info *fs_info, | |
182 | struct btrfs_block_rsv *block_rsv, | |
183 | u64 num_bytes, u64 *qgroup_to_release) | |
184 | { | |
185 | struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv; | |
186 | struct btrfs_block_rsv *delayed_rsv = &fs_info->delayed_refs_rsv; | |
187 | struct btrfs_block_rsv *target = NULL; | |
188 | ||
189 | /* | |
190 | * If we are the delayed_rsv then push to the global rsv, otherwise dump | |
191 | * into the delayed rsv if it is not full. | |
192 | */ | |
193 | if (block_rsv == delayed_rsv) | |
194 | target = global_rsv; | |
195 | else if (block_rsv != global_rsv && !delayed_rsv->full) | |
196 | target = delayed_rsv; | |
197 | ||
198 | if (target && block_rsv->space_info != target->space_info) | |
199 | target = NULL; | |
200 | ||
201 | return block_rsv_release_bytes(fs_info, block_rsv, target, num_bytes, | |
202 | qgroup_to_release); | |
203 | } | |
204 | ||
205 | int btrfs_block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv, u64 num_bytes) | |
206 | { | |
207 | int ret = -ENOSPC; | |
208 | ||
209 | spin_lock(&block_rsv->lock); | |
210 | if (block_rsv->reserved >= num_bytes) { | |
211 | block_rsv->reserved -= num_bytes; | |
212 | if (block_rsv->reserved < block_rsv->size) | |
213 | block_rsv->full = 0; | |
214 | ret = 0; | |
215 | } | |
216 | spin_unlock(&block_rsv->lock); | |
217 | return ret; | |
218 | } | |
219 | ||
220 | void btrfs_block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv, | |
221 | u64 num_bytes, bool update_size) | |
222 | { | |
223 | spin_lock(&block_rsv->lock); | |
224 | block_rsv->reserved += num_bytes; | |
225 | if (update_size) | |
226 | block_rsv->size += num_bytes; | |
227 | else if (block_rsv->reserved >= block_rsv->size) | |
228 | block_rsv->full = 1; | |
229 | spin_unlock(&block_rsv->lock); | |
230 | } | |
231 | ||
232 | int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info, | |
233 | struct btrfs_block_rsv *dest, u64 num_bytes, | |
234 | int min_factor) | |
235 | { | |
236 | struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv; | |
237 | u64 min_bytes; | |
238 | ||
239 | if (global_rsv->space_info != dest->space_info) | |
240 | return -ENOSPC; | |
241 | ||
242 | spin_lock(&global_rsv->lock); | |
243 | min_bytes = div_factor(global_rsv->size, min_factor); | |
244 | if (global_rsv->reserved < min_bytes + num_bytes) { | |
245 | spin_unlock(&global_rsv->lock); | |
246 | return -ENOSPC; | |
247 | } | |
248 | global_rsv->reserved -= num_bytes; | |
249 | if (global_rsv->reserved < global_rsv->size) | |
250 | global_rsv->full = 0; | |
251 | spin_unlock(&global_rsv->lock); | |
252 | ||
253 | btrfs_block_rsv_add_bytes(dest, num_bytes, true); | |
254 | return 0; | |
255 | } | |
67f9c220 JB |
256 | |
257 | void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info) | |
258 | { | |
259 | struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; | |
260 | struct btrfs_space_info *sinfo = block_rsv->space_info; | |
261 | u64 num_bytes; | |
3593ce30 | 262 | unsigned min_items; |
67f9c220 JB |
263 | |
264 | /* | |
265 | * The global block rsv is based on the size of the extent tree, the | |
266 | * checksum tree and the root tree. If the fs is empty we want to set | |
267 | * it to a minimal amount for safety. | |
268 | */ | |
269 | num_bytes = btrfs_root_used(&fs_info->extent_root->root_item) + | |
270 | btrfs_root_used(&fs_info->csum_root->root_item) + | |
271 | btrfs_root_used(&fs_info->tree_root->root_item); | |
3593ce30 JB |
272 | |
273 | /* | |
274 | * We at a minimum are going to modify the csum root, the tree root, and | |
275 | * the extent root. | |
276 | */ | |
277 | min_items = 3; | |
278 | ||
279 | /* | |
280 | * But we also want to reserve enough space so we can do the fallback | |
281 | * global reserve for an unlink, which is an additional 5 items (see the | |
282 | * comment in __unlink_start_trans for what we're modifying.) | |
283 | * | |
284 | * But we also need space for the delayed ref updates from the unlink, | |
285 | * so its 10, 5 for the actual operation, and 5 for the delayed ref | |
286 | * updates. | |
287 | */ | |
288 | min_items += 10; | |
289 | ||
290 | num_bytes = max_t(u64, num_bytes, | |
291 | btrfs_calc_insert_metadata_size(fs_info, min_items)); | |
67f9c220 JB |
292 | |
293 | spin_lock(&sinfo->lock); | |
294 | spin_lock(&block_rsv->lock); | |
295 | ||
296 | block_rsv->size = min_t(u64, num_bytes, SZ_512M); | |
297 | ||
298 | if (block_rsv->reserved < block_rsv->size) { | |
d792b0f1 JB |
299 | num_bytes = block_rsv->size - block_rsv->reserved; |
300 | block_rsv->reserved += num_bytes; | |
301 | btrfs_space_info_update_bytes_may_use(fs_info, sinfo, | |
302 | num_bytes); | |
67f9c220 JB |
303 | } else if (block_rsv->reserved > block_rsv->size) { |
304 | num_bytes = block_rsv->reserved - block_rsv->size; | |
305 | btrfs_space_info_update_bytes_may_use(fs_info, sinfo, | |
306 | -num_bytes); | |
67f9c220 JB |
307 | block_rsv->reserved = block_rsv->size; |
308 | } | |
309 | ||
310 | if (block_rsv->reserved == block_rsv->size) | |
311 | block_rsv->full = 1; | |
312 | else | |
313 | block_rsv->full = 0; | |
314 | ||
315 | spin_unlock(&block_rsv->lock); | |
316 | spin_unlock(&sinfo->lock); | |
317 | } | |
318 | ||
319 | void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info) | |
320 | { | |
321 | struct btrfs_space_info *space_info; | |
322 | ||
323 | space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM); | |
324 | fs_info->chunk_block_rsv.space_info = space_info; | |
325 | ||
326 | space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); | |
327 | fs_info->global_block_rsv.space_info = space_info; | |
328 | fs_info->trans_block_rsv.space_info = space_info; | |
329 | fs_info->empty_block_rsv.space_info = space_info; | |
330 | fs_info->delayed_block_rsv.space_info = space_info; | |
331 | fs_info->delayed_refs_rsv.space_info = space_info; | |
332 | ||
333 | fs_info->extent_root->block_rsv = &fs_info->delayed_refs_rsv; | |
334 | fs_info->csum_root->block_rsv = &fs_info->delayed_refs_rsv; | |
335 | fs_info->dev_root->block_rsv = &fs_info->global_block_rsv; | |
336 | fs_info->tree_root->block_rsv = &fs_info->global_block_rsv; | |
337 | if (fs_info->quota_root) | |
338 | fs_info->quota_root->block_rsv = &fs_info->global_block_rsv; | |
339 | fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv; | |
340 | ||
341 | btrfs_update_global_block_rsv(fs_info); | |
342 | } | |
343 | ||
344 | void btrfs_release_global_block_rsv(struct btrfs_fs_info *fs_info) | |
345 | { | |
346 | btrfs_block_rsv_release(fs_info, &fs_info->global_block_rsv, (u64)-1); | |
347 | WARN_ON(fs_info->trans_block_rsv.size > 0); | |
348 | WARN_ON(fs_info->trans_block_rsv.reserved > 0); | |
349 | WARN_ON(fs_info->chunk_block_rsv.size > 0); | |
350 | WARN_ON(fs_info->chunk_block_rsv.reserved > 0); | |
351 | WARN_ON(fs_info->delayed_block_rsv.size > 0); | |
352 | WARN_ON(fs_info->delayed_block_rsv.reserved > 0); | |
353 | WARN_ON(fs_info->delayed_refs_rsv.reserved > 0); | |
354 | WARN_ON(fs_info->delayed_refs_rsv.size > 0); | |
355 | } | |
356 | ||
357 | static struct btrfs_block_rsv *get_block_rsv( | |
358 | const struct btrfs_trans_handle *trans, | |
359 | const struct btrfs_root *root) | |
360 | { | |
361 | struct btrfs_fs_info *fs_info = root->fs_info; | |
362 | struct btrfs_block_rsv *block_rsv = NULL; | |
363 | ||
364 | if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) || | |
365 | (root == fs_info->csum_root && trans->adding_csums) || | |
366 | (root == fs_info->uuid_root)) | |
367 | block_rsv = trans->block_rsv; | |
368 | ||
369 | if (!block_rsv) | |
370 | block_rsv = root->block_rsv; | |
371 | ||
372 | if (!block_rsv) | |
373 | block_rsv = &fs_info->empty_block_rsv; | |
374 | ||
375 | return block_rsv; | |
376 | } | |
377 | ||
378 | struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, | |
379 | struct btrfs_root *root, | |
380 | u32 blocksize) | |
381 | { | |
382 | struct btrfs_fs_info *fs_info = root->fs_info; | |
383 | struct btrfs_block_rsv *block_rsv; | |
384 | struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv; | |
385 | int ret; | |
386 | bool global_updated = false; | |
387 | ||
388 | block_rsv = get_block_rsv(trans, root); | |
389 | ||
390 | if (unlikely(block_rsv->size == 0)) | |
391 | goto try_reserve; | |
392 | again: | |
393 | ret = btrfs_block_rsv_use_bytes(block_rsv, blocksize); | |
394 | if (!ret) | |
395 | return block_rsv; | |
396 | ||
397 | if (block_rsv->failfast) | |
398 | return ERR_PTR(ret); | |
399 | ||
400 | if (block_rsv->type == BTRFS_BLOCK_RSV_GLOBAL && !global_updated) { | |
401 | global_updated = true; | |
402 | btrfs_update_global_block_rsv(fs_info); | |
403 | goto again; | |
404 | } | |
405 | ||
406 | /* | |
407 | * The global reserve still exists to save us from ourselves, so don't | |
408 | * warn_on if we are short on our delayed refs reserve. | |
409 | */ | |
410 | if (block_rsv->type != BTRFS_BLOCK_RSV_DELREFS && | |
411 | btrfs_test_opt(fs_info, ENOSPC_DEBUG)) { | |
412 | static DEFINE_RATELIMIT_STATE(_rs, | |
413 | DEFAULT_RATELIMIT_INTERVAL * 10, | |
414 | /*DEFAULT_RATELIMIT_BURST*/ 1); | |
415 | if (__ratelimit(&_rs)) | |
416 | WARN(1, KERN_DEBUG | |
417 | "BTRFS: block rsv returned %d\n", ret); | |
418 | } | |
419 | try_reserve: | |
420 | ret = btrfs_reserve_metadata_bytes(root, block_rsv, blocksize, | |
421 | BTRFS_RESERVE_NO_FLUSH); | |
422 | if (!ret) | |
423 | return block_rsv; | |
424 | /* | |
425 | * If we couldn't reserve metadata bytes try and use some from | |
426 | * the global reserve if its space type is the same as the global | |
427 | * reservation. | |
428 | */ | |
429 | if (block_rsv->type != BTRFS_BLOCK_RSV_GLOBAL && | |
430 | block_rsv->space_info == global_rsv->space_info) { | |
431 | ret = btrfs_block_rsv_use_bytes(global_rsv, blocksize); | |
432 | if (!ret) | |
433 | return global_rsv; | |
434 | } | |
435 | return ERR_PTR(ret); | |
436 | } |