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
16int 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		btrfs_release_path(path);
70	}
71
72	btrfs_free_path(path);
73	return ret;
74}
75
76static int btrfs_insert_one_raid_extent(struct btrfs_trans_handle *trans,
77					struct btrfs_io_context *bioc)
78{
79	struct btrfs_fs_info *fs_info = trans->fs_info;
80	struct btrfs_key stripe_key;
81	struct btrfs_root *stripe_root = fs_info->stripe_root;
82	const int num_stripes = btrfs_bg_type_to_factor(bioc->map_type);
83	u8 encoding = btrfs_bg_flags_to_raid_index(bioc->map_type);
84	struct btrfs_stripe_extent *stripe_extent;
85	const size_t item_size = struct_size(stripe_extent, strides, num_stripes);
86	int ret;
87
88	stripe_extent = kzalloc(item_size, GFP_NOFS);
89	if (!stripe_extent) {
90		btrfs_abort_transaction(trans, -ENOMEM);
91		btrfs_end_transaction(trans);
92		return -ENOMEM;
93	}
94
95	trace_btrfs_insert_one_raid_extent(fs_info, bioc->logical, bioc->size,
96					   num_stripes);
97	btrfs_set_stack_stripe_extent_encoding(stripe_extent, encoding);
98	for (int i = 0; i < num_stripes; i++) {
99		u64 devid = bioc->stripes[i].dev->devid;
100		u64 physical = bioc->stripes[i].physical;
101		u64 length = bioc->stripes[i].length;
102		struct btrfs_raid_stride *raid_stride = &stripe_extent->strides[i];
103
104		if (length == 0)
105			length = bioc->size;
106
107		btrfs_set_stack_raid_stride_devid(raid_stride, devid);
108		btrfs_set_stack_raid_stride_physical(raid_stride, physical);
109	}
110
111	stripe_key.objectid = bioc->logical;
112	stripe_key.type = BTRFS_RAID_STRIPE_KEY;
113	stripe_key.offset = bioc->size;
114
115	ret = btrfs_insert_item(trans, stripe_root, &stripe_key, stripe_extent,
116				item_size);
117	if (ret)
118		btrfs_abort_transaction(trans, ret);
119
120	kfree(stripe_extent);
121
122	return ret;
123}
124
125int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
126			     struct btrfs_ordered_extent *ordered_extent)
127{
128	struct btrfs_io_context *bioc;
129	int ret;
130
131	if (!btrfs_fs_incompat(trans->fs_info, RAID_STRIPE_TREE))
132		return 0;
133
134	list_for_each_entry(bioc, &ordered_extent->bioc_list, rst_ordered_entry) {
135		ret = btrfs_insert_one_raid_extent(trans, bioc);
136		if (ret)
137			return ret;
138	}
139
140	while (!list_empty(&ordered_extent->bioc_list)) {
141		bioc = list_first_entry(&ordered_extent->bioc_list,
142					typeof(*bioc), rst_ordered_entry);
143		list_del(&bioc->rst_ordered_entry);
144		btrfs_put_bioc(bioc);
145	}
146
147	return 0;
148}
149
150int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
151				 u64 logical, u64 *length, u64 map_type,
152				 u32 stripe_index, struct btrfs_io_stripe *stripe)
153{
154	struct btrfs_root *stripe_root = fs_info->stripe_root;
155	struct btrfs_stripe_extent *stripe_extent;
156	struct btrfs_key stripe_key;
157	struct btrfs_key found_key;
158	struct btrfs_path *path;
159	struct extent_buffer *leaf;
160	const u64 end = logical + *length;
161	int num_stripes;
162	u8 encoding;
163	u64 offset;
164	u64 found_logical;
165	u64 found_length;
166	u64 found_end;
167	int slot;
168	int ret;
169
170	stripe_key.objectid = logical;
171	stripe_key.type = BTRFS_RAID_STRIPE_KEY;
172	stripe_key.offset = 0;
173
174	path = btrfs_alloc_path();
175	if (!path)
176		return -ENOMEM;
177
178	if (stripe->is_scrub) {
179		path->skip_locking = 1;
180		path->search_commit_root = 1;
181	}
182
183	ret = btrfs_search_slot(NULL, stripe_root, &stripe_key, path, 0, 0);
184	if (ret < 0)
185		goto free_path;
186	if (ret) {
187		if (path->slots[0] != 0)
188			path->slots[0]--;
189	}
190
191	while (1) {
192		leaf = path->nodes[0];
193		slot = path->slots[0];
194
195		btrfs_item_key_to_cpu(leaf, &found_key, slot);
196		found_logical = found_key.objectid;
197		found_length = found_key.offset;
198		found_end = found_logical + found_length;
199
200		if (found_logical > end) {
201			ret = -ENOENT;
202			goto out;
203		}
204
205		if (in_range(logical, found_logical, found_length))
206			break;
207
208		ret = btrfs_next_item(stripe_root, path);
209		if (ret)
210			goto out;
211	}
212
213	offset = logical - found_logical;
214
215	/*
216	 * If we have a logically contiguous, but physically non-continuous
217	 * range, we need to split the bio. Record the length after which we
218	 * must split the bio.
219	 */
220	if (end > found_end)
221		*length -= end - found_end;
222
223	num_stripes = btrfs_num_raid_stripes(btrfs_item_size(leaf, slot));
224	stripe_extent = btrfs_item_ptr(leaf, slot, struct btrfs_stripe_extent);
225	encoding = btrfs_stripe_extent_encoding(leaf, stripe_extent);
226
227	if (encoding != btrfs_bg_flags_to_raid_index(map_type)) {
228		ret = -EUCLEAN;
229		btrfs_handle_fs_error(fs_info, ret,
230				      "on-disk stripe encoding %d doesn't match RAID index %d",
231				      encoding,
232				      btrfs_bg_flags_to_raid_index(map_type));
233		goto out;
234	}
235
236	for (int i = 0; i < num_stripes; i++) {
237		struct btrfs_raid_stride *stride = &stripe_extent->strides[i];
238		u64 devid = btrfs_raid_stride_devid(leaf, stride);
239		u64 physical = btrfs_raid_stride_physical(leaf, stride);
240
241		if (devid != stripe->dev->devid)
242			continue;
243
244		if ((map_type & BTRFS_BLOCK_GROUP_DUP) && stripe_index != i)
245			continue;
246
247		stripe->physical = physical + offset;
248
249		trace_btrfs_get_raid_extent_offset(fs_info, logical, *length,
250						   stripe->physical, devid);
251
252		ret = 0;
253		goto free_path;
254	}
255
256	/* If we're here, we haven't found the requested devid in the stripe. */
257	ret = -ENOENT;
258out:
259	if (ret > 0)
260		ret = -ENOENT;
261	if (ret && ret != -EIO && !stripe->is_scrub) {
262		if (IS_ENABLED(CONFIG_BTRFS_DEBUG))
263			btrfs_print_tree(leaf, 1);
264		btrfs_err(fs_info,
265		"cannot find raid-stripe for logical [%llu, %llu] devid %llu, profile %s",
266			  logical, logical + *length, stripe->dev->devid,
267			  btrfs_bg_type_to_raid_name(map_type));
268	}
269free_path:
270	btrfs_free_path(path);
271
272	return ret;
273}
274