1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2023 Western Digital Corporation or its affiliates.
4 */
5
6 #include <linux/btrfs_tree.h>
7 #include "ctree.h"
8 #include "fs.h"
9 #include "accessors.h"
10 #include "transaction.h"
11 #include "disk-io.h"
12 #include "raid-stripe-tree.h"
13 #include "volumes.h"
14 #include "print-tree.h"
15
btrfs_delete_raid_extent(struct btrfs_trans_handle * trans,u64 start,u64 length)16 int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 length)
17 {
18 struct btrfs_fs_info *fs_info = trans->fs_info;
19 struct btrfs_root *stripe_root = fs_info->stripe_root;
20 struct btrfs_path *path;
21 struct btrfs_key key;
22 struct extent_buffer *leaf;
23 u64 found_start;
24 u64 found_end;
25 u64 end = start + length;
26 int slot;
27 int ret;
28
29 if (!stripe_root)
30 return 0;
31
32 path = btrfs_alloc_path();
33 if (!path)
34 return -ENOMEM;
35
36 while (1) {
37 key.objectid = start;
38 key.type = BTRFS_RAID_STRIPE_KEY;
39 key.offset = length;
40
41 ret = btrfs_search_slot(trans, stripe_root, &key, path, -1, 1);
42 if (ret < 0)
43 break;
44 if (ret > 0) {
45 ret = 0;
46 if (path->slots[0] == 0)
47 break;
48 path->slots[0]--;
49 }
50
51 leaf = path->nodes[0];
52 slot = path->slots[0];
53 btrfs_item_key_to_cpu(leaf, &key, slot);
54 found_start = key.objectid;
55 found_end = found_start + key.offset;
56
57 /* That stripe ends before we start, we're done. */
58 if (found_end <= start)
59 break;
60
61 trace_btrfs_raid_extent_delete(fs_info, start, end,
62 found_start, found_end);
63
64 ASSERT(found_start >= start && found_end <= end);
65 ret = btrfs_del_item(trans, stripe_root, path);
66 if (ret)
67 break;
68
69 start += key.offset;
70 length -= key.offset;
71 if (length == 0)
72 break;
73
74 btrfs_release_path(path);
75 }
76
77 btrfs_free_path(path);
78 return ret;
79 }
80
update_raid_extent_item(struct btrfs_trans_handle * trans,struct btrfs_key * key,struct btrfs_stripe_extent * stripe_extent,const size_t item_size)81 static int update_raid_extent_item(struct btrfs_trans_handle *trans,
82 struct btrfs_key *key,
83 struct btrfs_stripe_extent *stripe_extent,
84 const size_t item_size)
85 {
86 struct btrfs_path *path;
87 struct extent_buffer *leaf;
88 int ret;
89 int slot;
90
91 path = btrfs_alloc_path();
92 if (!path)
93 return -ENOMEM;
94
95 ret = btrfs_search_slot(trans, trans->fs_info->stripe_root, key, path,
96 0, 1);
97 if (ret)
98 return (ret == 1 ? ret : -EINVAL);
99
100 leaf = path->nodes[0];
101 slot = path->slots[0];
102
103 write_extent_buffer(leaf, stripe_extent, btrfs_item_ptr_offset(leaf, slot),
104 item_size);
105 btrfs_mark_buffer_dirty(trans, leaf);
106 btrfs_free_path(path);
107
108 return ret;
109 }
110
btrfs_insert_one_raid_extent(struct btrfs_trans_handle * trans,struct btrfs_io_context * bioc)111 static int btrfs_insert_one_raid_extent(struct btrfs_trans_handle *trans,
112 struct btrfs_io_context *bioc)
113 {
114 struct btrfs_fs_info *fs_info = trans->fs_info;
115 struct btrfs_key stripe_key;
116 struct btrfs_root *stripe_root = fs_info->stripe_root;
117 const int num_stripes = btrfs_bg_type_to_factor(bioc->map_type);
118 struct btrfs_stripe_extent *stripe_extent;
119 const size_t item_size = struct_size(stripe_extent, strides, num_stripes);
120 int ret;
121
122 stripe_extent = kzalloc(item_size, GFP_NOFS);
123 if (!stripe_extent) {
124 btrfs_abort_transaction(trans, -ENOMEM);
125 btrfs_end_transaction(trans);
126 return -ENOMEM;
127 }
128
129 trace_btrfs_insert_one_raid_extent(fs_info, bioc->logical, bioc->size,
130 num_stripes);
131 for (int i = 0; i < num_stripes; i++) {
132 u64 devid = bioc->stripes[i].dev->devid;
133 u64 physical = bioc->stripes[i].physical;
134 u64 length = bioc->stripes[i].length;
135 struct btrfs_raid_stride *raid_stride = &stripe_extent->strides[i];
136
137 if (length == 0)
138 length = bioc->size;
139
140 btrfs_set_stack_raid_stride_devid(raid_stride, devid);
141 btrfs_set_stack_raid_stride_physical(raid_stride, physical);
142 }
143
144 stripe_key.objectid = bioc->logical;
145 stripe_key.type = BTRFS_RAID_STRIPE_KEY;
146 stripe_key.offset = bioc->size;
147
148 ret = btrfs_insert_item(trans, stripe_root, &stripe_key, stripe_extent,
149 item_size);
150 if (ret == -EEXIST)
151 ret = update_raid_extent_item(trans, &stripe_key, stripe_extent,
152 item_size);
153 if (ret)
154 btrfs_abort_transaction(trans, ret);
155
156 kfree(stripe_extent);
157
158 return ret;
159 }
160
btrfs_insert_raid_extent(struct btrfs_trans_handle * trans,struct btrfs_ordered_extent * ordered_extent)161 int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
162 struct btrfs_ordered_extent *ordered_extent)
163 {
164 struct btrfs_io_context *bioc;
165 int ret;
166
167 if (!btrfs_fs_incompat(trans->fs_info, RAID_STRIPE_TREE))
168 return 0;
169
170 list_for_each_entry(bioc, &ordered_extent->bioc_list, rst_ordered_entry) {
171 ret = btrfs_insert_one_raid_extent(trans, bioc);
172 if (ret)
173 return ret;
174 }
175
176 while (!list_empty(&ordered_extent->bioc_list)) {
177 bioc = list_first_entry(&ordered_extent->bioc_list,
178 typeof(*bioc), rst_ordered_entry);
179 list_del(&bioc->rst_ordered_entry);
180 btrfs_put_bioc(bioc);
181 }
182
183 return 0;
184 }
185
btrfs_get_raid_extent_offset(struct btrfs_fs_info * fs_info,u64 logical,u64 * length,u64 map_type,u32 stripe_index,struct btrfs_io_stripe * stripe)186 int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
187 u64 logical, u64 *length, u64 map_type,
188 u32 stripe_index, struct btrfs_io_stripe *stripe)
189 {
190 struct btrfs_root *stripe_root = fs_info->stripe_root;
191 struct btrfs_stripe_extent *stripe_extent;
192 struct btrfs_key stripe_key;
193 struct btrfs_key found_key;
194 struct btrfs_path *path;
195 struct extent_buffer *leaf;
196 const u64 end = logical + *length;
197 int num_stripes;
198 u64 offset;
199 u64 found_logical;
200 u64 found_length;
201 u64 found_end;
202 int slot;
203 int ret;
204
205 stripe_key.objectid = logical;
206 stripe_key.type = BTRFS_RAID_STRIPE_KEY;
207 stripe_key.offset = 0;
208
209 path = btrfs_alloc_path();
210 if (!path)
211 return -ENOMEM;
212
213 if (stripe->rst_search_commit_root) {
214 path->skip_locking = 1;
215 path->search_commit_root = 1;
216 }
217
218 ret = btrfs_search_slot(NULL, stripe_root, &stripe_key, path, 0, 0);
219 if (ret < 0)
220 goto free_path;
221 if (ret) {
222 if (path->slots[0] != 0)
223 path->slots[0]--;
224 }
225
226 while (1) {
227 leaf = path->nodes[0];
228 slot = path->slots[0];
229
230 btrfs_item_key_to_cpu(leaf, &found_key, slot);
231 found_logical = found_key.objectid;
232 found_length = found_key.offset;
233 found_end = found_logical + found_length;
234
235 if (found_logical > end) {
236 ret = -ENOENT;
237 goto out;
238 }
239
240 if (in_range(logical, found_logical, found_length))
241 break;
242
243 ret = btrfs_next_item(stripe_root, path);
244 if (ret)
245 goto out;
246 }
247
248 offset = logical - found_logical;
249
250 /*
251 * If we have a logically contiguous, but physically non-continuous
252 * range, we need to split the bio. Record the length after which we
253 * must split the bio.
254 */
255 if (end > found_end)
256 *length -= end - found_end;
257
258 num_stripes = btrfs_num_raid_stripes(btrfs_item_size(leaf, slot));
259 stripe_extent = btrfs_item_ptr(leaf, slot, struct btrfs_stripe_extent);
260
261 for (int i = 0; i < num_stripes; i++) {
262 struct btrfs_raid_stride *stride = &stripe_extent->strides[i];
263 u64 devid = btrfs_raid_stride_devid(leaf, stride);
264 u64 physical = btrfs_raid_stride_physical(leaf, stride);
265
266 if (devid != stripe->dev->devid)
267 continue;
268
269 if ((map_type & BTRFS_BLOCK_GROUP_DUP) && stripe_index != i)
270 continue;
271
272 stripe->physical = physical + offset;
273
274 trace_btrfs_get_raid_extent_offset(fs_info, logical, *length,
275 stripe->physical, devid);
276
277 ret = 0;
278 goto free_path;
279 }
280
281 /* If we're here, we haven't found the requested devid in the stripe. */
282 ret = -ENOENT;
283 out:
284 if (ret > 0)
285 ret = -ENOENT;
286 if (ret && ret != -EIO && !stripe->rst_search_commit_root) {
287 btrfs_debug(fs_info,
288 "cannot find raid-stripe for logical [%llu, %llu] devid %llu, profile %s",
289 logical, logical + *length, stripe->dev->devid,
290 btrfs_bg_type_to_raid_name(map_type));
291 }
292 free_path:
293 btrfs_free_path(path);
294
295 return ret;
296 }
297