Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2#include "bcachefs.h"
3#include "btree_update.h"
4#include "btree_update_interior.h"
5#include "buckets.h"
6#include "debug.h"
7#include "extents.h"
8#include "extent_update.h"
9
10/*
11 * This counts the number of iterators to the alloc & ec btrees we'll need
12 * inserting/removing this extent:
13 */
14static unsigned bch2_bkey_nr_alloc_ptrs(struct bkey_s_c k)
15{
16 struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
17 const union bch_extent_entry *entry;
18 unsigned ret = 0, lru = 0;
19
20 bkey_extent_entry_for_each(ptrs, entry) {
21 switch (__extent_entry_type(entry)) {
22 case BCH_EXTENT_ENTRY_ptr:
23 /* Might also be updating LRU btree */
24 if (entry->ptr.cached)
25 lru++;
26
27 fallthrough;
28 case BCH_EXTENT_ENTRY_stripe_ptr:
29 ret++;
30 }
31 }
32
33 /*
34 * Updating keys in the alloc btree may also update keys in the
35 * freespace or discard btrees:
36 */
37 return lru + ret * 2;
38}
39
40#define EXTENT_ITERS_MAX 64
41
42static int count_iters_for_insert(struct btree_trans *trans,
43 struct bkey_s_c k,
44 unsigned offset,
45 struct bpos *end,
46 unsigned *nr_iters)
47{
48 int ret = 0, ret2 = 0;
49
50 if (*nr_iters >= EXTENT_ITERS_MAX) {
51 *end = bpos_min(*end, k.k->p);
52 ret = 1;
53 }
54
55 switch (k.k->type) {
56 case KEY_TYPE_extent:
57 case KEY_TYPE_reflink_v:
58 *nr_iters += bch2_bkey_nr_alloc_ptrs(k);
59
60 if (*nr_iters >= EXTENT_ITERS_MAX) {
61 *end = bpos_min(*end, k.k->p);
62 ret = 1;
63 }
64
65 break;
66 case KEY_TYPE_reflink_p: {
67 struct bkey_s_c_reflink_p p = bkey_s_c_to_reflink_p(k);
68 u64 idx = REFLINK_P_IDX(p.v);
69 unsigned sectors = bpos_min(*end, p.k->p).offset -
70 bkey_start_offset(p.k);
71 struct btree_iter iter;
72 struct bkey_s_c r_k;
73
74 for_each_btree_key_norestart(trans, iter,
75 BTREE_ID_reflink, POS(0, idx + offset),
76 BTREE_ITER_slots, r_k, ret2) {
77 if (bkey_ge(bkey_start_pos(r_k.k), POS(0, idx + sectors)))
78 break;
79
80 /* extent_update_to_keys(), for the reflink_v update */
81 *nr_iters += 1;
82
83 *nr_iters += 1 + bch2_bkey_nr_alloc_ptrs(r_k);
84
85 if (*nr_iters >= EXTENT_ITERS_MAX) {
86 struct bpos pos = bkey_start_pos(k.k);
87 pos.offset += min_t(u64, k.k->size,
88 r_k.k->p.offset - idx);
89
90 *end = bpos_min(*end, pos);
91 ret = 1;
92 break;
93 }
94 }
95 bch2_trans_iter_exit(trans, &iter);
96
97 break;
98 }
99 }
100
101 return ret2 ?: ret;
102}
103
104int bch2_extent_atomic_end(struct btree_trans *trans,
105 struct btree_iter *iter,
106 struct bpos *end)
107{
108 unsigned nr_iters = 0;
109
110 struct btree_iter copy;
111 bch2_trans_copy_iter(trans, ©, iter);
112
113 int ret = bch2_btree_iter_traverse(trans, ©);
114 if (ret)
115 goto err;
116
117 struct bkey_s_c k;
118 for_each_btree_key_max_continue_norestart(trans, copy, *end, 0, k, ret) {
119 unsigned offset = 0;
120
121 if (bkey_gt(iter->pos, bkey_start_pos(k.k)))
122 offset = iter->pos.offset - bkey_start_offset(k.k);
123
124 ret = count_iters_for_insert(trans, k, offset, end, &nr_iters);
125 if (ret)
126 break;
127 }
128err:
129 bch2_trans_iter_exit(trans, ©);
130 return ret < 0 ? ret : 0;
131}
132
133int bch2_extent_trim_atomic(struct btree_trans *trans,
134 struct btree_iter *iter,
135 struct bkey_i *k)
136{
137 struct bpos end = k->k.p;
138 int ret = bch2_extent_atomic_end(trans, iter, &end);
139 if (ret)
140 return ret;
141
142 bch2_cut_back(end, k);
143 return 0;
144}