uboot/fs/btrfs/chunk-map.c
<<
>>
Prefs
   1/*
   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 = 0;
 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}
 179