blob: 48407f33316f68d8c63578683b9226a372306f33 [file] [log] [blame]
Marek BehĂșn29387542017-09-03 17:00:28 +02001/*
2 * BTRFS filesystem implementation for U-Boot
3 *
4 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 */
8
9#include "btrfs.h"
10#include <malloc.h>
11
12struct chunk_map_item {
13 struct rb_node node;
14 u64 logical;
15 u64 length;
16 u64 physical;
17};
18
19static int add_chunk_mapping(struct btrfs_key *key, struct btrfs_chunk *chunk)
20{
21 struct btrfs_stripe *stripe;
22 u64 block_profile = chunk->type & BTRFS_BLOCK_GROUP_PROFILE_MASK;
23 struct rb_node **new = &(btrfs_info.chunks_root.rb_node), *prnt = NULL;
24 struct chunk_map_item *map_item;
25
26 if (block_profile && block_profile != BTRFS_BLOCK_GROUP_DUP) {
27 printf("%s: unsupported chunk profile %llu\n", __func__,
28 block_profile);
29 return -1;
30 } else if (!chunk->length) {
31 printf("%s: zero length chunk\n", __func__);
32 return -1;
33 }
34
35 stripe = &chunk->stripe;
36 btrfs_stripe_to_cpu(stripe);
37
38 while (*new) {
39 struct chunk_map_item *this;
40
41 this = rb_entry(*new, struct chunk_map_item, node);
42
43 prnt = *new;
44 if (key->offset < this->logical) {
45 new = &((*new)->rb_left);
46 } else if (key->offset > this->logical) {
47 new = &((*new)->rb_right);
48 } else {
49 debug("%s: Logical address %llu already in map!\n",
50 __func__, key->offset);
51 return 0;
52 }
53 }
54
55 map_item = malloc(sizeof(struct chunk_map_item));
56 if (!map_item)
57 return -1;
58
59 map_item->logical = key->offset;
60 map_item->length = chunk->length;
61 map_item->physical = le64_to_cpu(chunk->stripe.offset);
62 rb_link_node(&map_item->node, prnt, new);
63 rb_insert_color(&map_item->node, &btrfs_info.chunks_root);
64
65 debug("%s: Mapping %llu to %llu\n", __func__, map_item->logical,
66 map_item->physical);
67
68 return 0;
69}
70
71u64 btrfs_map_logical_to_physical(u64 logical)
72{
73 struct rb_node *node = btrfs_info.chunks_root.rb_node;
74
75 while (node) {
76 struct chunk_map_item *item;
77
78 item = rb_entry(node, struct chunk_map_item, node);
79
80 if (item->logical > logical)
81 node = node->rb_left;
82 else if (logical > item->logical + item->length)
83 node = node->rb_right;
84 else
85 return item->physical + logical - item->logical;
86 }
87
88 printf("%s: Cannot map logical address %llu to physical\n", __func__,
89 logical);
90
91 return -1ULL;
92}
93
94void btrfs_chunk_map_exit(void)
95{
96 struct rb_node *now, *next;
97 struct chunk_map_item *item;
98
99 for (now = rb_first_postorder(&btrfs_info.chunks_root); now; now = next)
100 {
101 item = rb_entry(now, struct chunk_map_item, node);
102 next = rb_next_postorder(now);
103 free(item);
104 }
105}
106
107int btrfs_chunk_map_init(void)
108{
109 u8 sys_chunk_array_copy[sizeof(btrfs_info.sb.sys_chunk_array)];
110 u8 * const start = sys_chunk_array_copy;
111 u8 * const end = start + btrfs_info.sb.sys_chunk_array_size;
112 u8 *cur;
113 struct btrfs_key *key;
114 struct btrfs_chunk *chunk;
115
116 btrfs_info.chunks_root = RB_ROOT;
117
118 memcpy(sys_chunk_array_copy, btrfs_info.sb.sys_chunk_array,
119 sizeof(sys_chunk_array_copy));
120
121 for (cur = start; cur < end;) {
122 key = (struct btrfs_key *) cur;
123 cur += sizeof(struct btrfs_key);
124 chunk = (struct btrfs_chunk *) cur;
125
126 btrfs_key_to_cpu(key);
127 btrfs_chunk_to_cpu(chunk);
128
129 if (key->type != BTRFS_CHUNK_ITEM_KEY) {
130 printf("%s: invalid key type %u\n", __func__,
131 key->type);
132 return -1;
133 }
134
135 if (add_chunk_mapping(key, chunk))
136 return -1;
137
138 cur += sizeof(struct btrfs_chunk);
139 cur += sizeof(struct btrfs_stripe) * (chunk->num_stripes - 1);
140 }
141
142 return 0;
143}
144
145int btrfs_read_chunk_tree(void)
146{
147 struct btrfs_path path;
148 struct btrfs_key key, *found_key;
149 struct btrfs_chunk *chunk;
150 int res;
151
152 key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
153 key.type = BTRFS_CHUNK_ITEM_KEY;
154 key.offset = 0;
155
156 if (btrfs_search_tree(&btrfs_info.chunk_root, &key, &path))
157 return -1;
158
159 do {
160 found_key = btrfs_path_leaf_key(&path);
161 if (btrfs_comp_keys_type(&key, found_key))
162 break;
163
164 chunk = btrfs_path_item_ptr(&path, struct btrfs_chunk);
165 btrfs_chunk_to_cpu(chunk);
166 if (add_chunk_mapping(found_key, chunk)) {
167 res = -1;
168 break;
169 }
170 } while (!(res = btrfs_next_slot(&path)));
171
172 btrfs_free_path(&path);
173
174 if (res < 0)
175 return -1;
176
177 return 0;
178}