linux/fs/btrfs/backref.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2011 STRATO.  All rights reserved.
   4 */
   5
   6#include <linux/mm.h>
   7#include <linux/rbtree.h>
   8#include <trace/events/btrfs.h>
   9#include "ctree.h"
  10#include "disk-io.h"
  11#include "backref.h"
  12#include "ulist.h"
  13#include "transaction.h"
  14#include "delayed-ref.h"
  15#include "locking.h"
  16#include "misc.h"
  17#include "tree-mod-log.h"
  18
  19/* Just an arbitrary number so we can be sure this happened */
  20#define BACKREF_FOUND_SHARED 6
  21
  22struct extent_inode_elem {
  23        u64 inum;
  24        u64 offset;
  25        struct extent_inode_elem *next;
  26};
  27
  28static int check_extent_in_eb(const struct btrfs_key *key,
  29                              const struct extent_buffer *eb,
  30                              const struct btrfs_file_extent_item *fi,
  31                              u64 extent_item_pos,
  32                              struct extent_inode_elem **eie,
  33                              bool ignore_offset)
  34{
  35        u64 offset = 0;
  36        struct extent_inode_elem *e;
  37
  38        if (!ignore_offset &&
  39            !btrfs_file_extent_compression(eb, fi) &&
  40            !btrfs_file_extent_encryption(eb, fi) &&
  41            !btrfs_file_extent_other_encoding(eb, fi)) {
  42                u64 data_offset;
  43                u64 data_len;
  44
  45                data_offset = btrfs_file_extent_offset(eb, fi);
  46                data_len = btrfs_file_extent_num_bytes(eb, fi);
  47
  48                if (extent_item_pos < data_offset ||
  49                    extent_item_pos >= data_offset + data_len)
  50                        return 1;
  51                offset = extent_item_pos - data_offset;
  52        }
  53
  54        e = kmalloc(sizeof(*e), GFP_NOFS);
  55        if (!e)
  56                return -ENOMEM;
  57
  58        e->next = *eie;
  59        e->inum = key->objectid;
  60        e->offset = key->offset + offset;
  61        *eie = e;
  62
  63        return 0;
  64}
  65
  66static void free_inode_elem_list(struct extent_inode_elem *eie)
  67{
  68        struct extent_inode_elem *eie_next;
  69
  70        for (; eie; eie = eie_next) {
  71                eie_next = eie->next;
  72                kfree(eie);
  73        }
  74}
  75
  76static int find_extent_in_eb(const struct extent_buffer *eb,
  77                             u64 wanted_disk_byte, u64 extent_item_pos,
  78                             struct extent_inode_elem **eie,
  79                             bool ignore_offset)
  80{
  81        u64 disk_byte;
  82        struct btrfs_key key;
  83        struct btrfs_file_extent_item *fi;
  84        int slot;
  85        int nritems;
  86        int extent_type;
  87        int ret;
  88
  89        /*
  90         * from the shared data ref, we only have the leaf but we need
  91         * the key. thus, we must look into all items and see that we
  92         * find one (some) with a reference to our extent item.
  93         */
  94        nritems = btrfs_header_nritems(eb);
  95        for (slot = 0; slot < nritems; ++slot) {
  96                btrfs_item_key_to_cpu(eb, &key, slot);
  97                if (key.type != BTRFS_EXTENT_DATA_KEY)
  98                        continue;
  99                fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
 100                extent_type = btrfs_file_extent_type(eb, fi);
 101                if (extent_type == BTRFS_FILE_EXTENT_INLINE)
 102                        continue;
 103                /* don't skip BTRFS_FILE_EXTENT_PREALLOC, we can handle that */
 104                disk_byte = btrfs_file_extent_disk_bytenr(eb, fi);
 105                if (disk_byte != wanted_disk_byte)
 106                        continue;
 107
 108                ret = check_extent_in_eb(&key, eb, fi, extent_item_pos, eie, ignore_offset);
 109                if (ret < 0)
 110                        return ret;
 111        }
 112
 113        return 0;
 114}
 115
 116struct preftree {
 117        struct rb_root_cached root;
 118        unsigned int count;
 119};
 120
 121#define PREFTREE_INIT   { .root = RB_ROOT_CACHED, .count = 0 }
 122
 123struct preftrees {
 124        struct preftree direct;    /* BTRFS_SHARED_[DATA|BLOCK]_REF_KEY */
 125        struct preftree indirect;  /* BTRFS_[TREE_BLOCK|EXTENT_DATA]_REF_KEY */
 126        struct preftree indirect_missing_keys;
 127};
 128
 129/*
 130 * Checks for a shared extent during backref search.
 131 *
 132 * The share_count tracks prelim_refs (direct and indirect) having a
 133 * ref->count >0:
 134 *  - incremented when a ref->count transitions to >0
 135 *  - decremented when a ref->count transitions to <1
 136 */
 137struct share_check {
 138        u64 root_objectid;
 139        u64 inum;
 140        int share_count;
 141};
 142
 143static inline int extent_is_shared(struct share_check *sc)
 144{
 145        return (sc && sc->share_count > 1) ? BACKREF_FOUND_SHARED : 0;
 146}
 147
 148static struct kmem_cache *btrfs_prelim_ref_cache;
 149
 150int __init btrfs_prelim_ref_init(void)
 151{
 152        btrfs_prelim_ref_cache = kmem_cache_create("btrfs_prelim_ref",
 153                                        sizeof(struct prelim_ref),
 154                                        0,
 155                                        SLAB_MEM_SPREAD,
 156                                        NULL);
 157        if (!btrfs_prelim_ref_cache)
 158                return -ENOMEM;
 159        return 0;
 160}
 161
 162void __cold btrfs_prelim_ref_exit(void)
 163{
 164        kmem_cache_destroy(btrfs_prelim_ref_cache);
 165}
 166
 167static void free_pref(struct prelim_ref *ref)
 168{
 169        kmem_cache_free(btrfs_prelim_ref_cache, ref);
 170}
 171
 172/*
 173 * Return 0 when both refs are for the same block (and can be merged).
 174 * A -1 return indicates ref1 is a 'lower' block than ref2, while 1
 175 * indicates a 'higher' block.
 176 */
 177static int prelim_ref_compare(struct prelim_ref *ref1,
 178                              struct prelim_ref *ref2)
 179{
 180        if (ref1->level < ref2->level)
 181                return -1;
 182        if (ref1->level > ref2->level)
 183                return 1;
 184        if (ref1->root_id < ref2->root_id)
 185                return -1;
 186        if (ref1->root_id > ref2->root_id)
 187                return 1;
 188        if (ref1->key_for_search.type < ref2->key_for_search.type)
 189                return -1;
 190        if (ref1->key_for_search.type > ref2->key_for_search.type)
 191                return 1;
 192        if (ref1->key_for_search.objectid < ref2->key_for_search.objectid)
 193                return -1;
 194        if (ref1->key_for_search.objectid > ref2->key_for_search.objectid)
 195                return 1;
 196        if (ref1->key_for_search.offset < ref2->key_for_search.offset)
 197                return -1;
 198        if (ref1->key_for_search.offset > ref2->key_for_search.offset)
 199                return 1;
 200        if (ref1->parent < ref2->parent)
 201                return -1;
 202        if (ref1->parent > ref2->parent)
 203                return 1;
 204
 205        return 0;
 206}
 207
 208static void update_share_count(struct share_check *sc, int oldcount,
 209                               int newcount)
 210{
 211        if ((!sc) || (oldcount == 0 && newcount < 1))
 212                return;
 213
 214        if (oldcount > 0 && newcount < 1)
 215                sc->share_count--;
 216        else if (oldcount < 1 && newcount > 0)
 217                sc->share_count++;
 218}
 219
 220/*
 221 * Add @newref to the @root rbtree, merging identical refs.
 222 *
 223 * Callers should assume that newref has been freed after calling.
 224 */
 225static void prelim_ref_insert(const struct btrfs_fs_info *fs_info,
 226                              struct preftree *preftree,
 227                              struct prelim_ref *newref,
 228                              struct share_check *sc)
 229{
 230        struct rb_root_cached *root;
 231        struct rb_node **p;
 232        struct rb_node *parent = NULL;
 233        struct prelim_ref *ref;
 234        int result;
 235        bool leftmost = true;
 236
 237        root = &preftree->root;
 238        p = &root->rb_root.rb_node;
 239
 240        while (*p) {
 241                parent = *p;
 242                ref =