linux/fs/btrfs/root-tree.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007 Oracle.  All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public
   6 * License v2 as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11 * General Public License for more details.
  12 *
  13 * You should have received a copy of the GNU General Public
  14 * License along with this program; if not, write to the
  15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  16 * Boston, MA 021110-1307, USA.
  17 */
  18
  19#include "ctree.h"
  20#include "transaction.h"
  21#include "disk-io.h"
  22#include "print-tree.h"
  23
  24/*
  25 *  search forward for a root, starting with objectid 'search_start'
  26 *  if a root key is found, the objectid we find is filled into 'found_objectid'
  27 *  and 0 is returned.  < 0 is returned on error, 1 if there is nothing
  28 *  left in the tree.
  29 */
  30int btrfs_search_root(struct btrfs_root *root, u64 search_start,
  31                      u64 *found_objectid)
  32{
  33        struct btrfs_path *path;
  34        struct btrfs_key search_key;
  35        int ret;
  36
  37        root = root->fs_info->tree_root;
  38        search_key.objectid = search_start;
  39        search_key.type = (u8)-1;
  40        search_key.offset = (u64)-1;
  41
  42        path = btrfs_alloc_path();
  43        BUG_ON(!path);
  44again:
  45        ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
  46        if (ret < 0)
  47                goto out;
  48        if (ret == 0) {
  49                ret = 1;
  50                goto out;
  51        }
  52        if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
  53                ret = btrfs_next_leaf(root, path);
  54                if (ret)
  55                        goto out;
  56        }
  57        btrfs_item_key_to_cpu(path->nodes[0], &search_key, path->slots[0]);
  58        if (search_key.type != BTRFS_ROOT_ITEM_KEY) {
  59                search_key.offset++;
  60                btrfs_release_path(root, path);
  61                goto again;
  62        }
  63        ret = 0;
  64        *found_objectid = search_key.objectid;
  65
  66out:
  67        btrfs_free_path(path);
  68        return ret;
  69}
  70
  71/*
  72 * lookup the root with the highest offset for a given objectid.  The key we do
  73 * find is copied into 'key'.  If we find something return 0, otherwise 1, < 0
  74 * on error.
  75 */
  76int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
  77                        struct btrfs_root_item *item, struct btrfs_key *key)
  78{
  79        struct btrfs_path *path;
  80        struct btrfs_key search_key;
  81        struct btrfs_key found_key;
  82        struct extent_buffer *l;
  83        int ret;
  84        int slot;
  85
  86        search_key.objectid = objectid;
  87        search_key.type = BTRFS_ROOT_ITEM_KEY;
  88        search_key.offset = (u64)-1;
  89
  90        path = btrfs_alloc_path();
  91        BUG_ON(!path);
  92        ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
  93        if (ret < 0)
  94                goto out;
  95
  96        BUG_ON(ret == 0);
  97        if (path->slots[0] == 0) {
  98                ret = 1;
  99                goto out;
 100        }
 101        l = path->nodes[0];
 102        slot = path->slots[0] - 1;
 103        btrfs_item_key_to_cpu(l, &found_key, slot);
 104        if (found_key.objectid != objectid ||
 105            found_key.type != BTRFS_ROOT_ITEM_KEY) {
 106                ret = 1;
 107                goto out;
 108        }
 109        if (item)
 110                read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot),
 111                                   sizeof(*item));
 112        if (key)
 113                memcpy(key, &found_key, sizeof(found_key));
 114        ret = 0;
 115out:
 116        btrfs_free_path(path);
 117        return ret;
 118}
 119
 120int btrfs_set_root_node(struct btrfs_root_item *item,
 121                        struct extent_buffer *node)
 122{
 123        btrfs_set_root_bytenr(item, node->start);
 124        btrfs_set_root_level(item, btrfs_header_level(node));
 125        btrfs_set_root_generation(item, btrfs_header_generation(node));
 126        return 0;
 127}
 128
 129/*
 130 * copy the data in 'item' into the btree
 131 */
 132int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
 133                      *root, struct btrfs_key *key, struct btrfs_root_item
 134                      *item)
 135{
 136        struct btrfs_path *path;
 137        struct extent_buffer *l;
 138        int ret;
 139        int slot;
 140        unsigned long ptr;
 141
 142        path = btrfs_alloc_path();
 143        BUG_ON(!path);
 144        ret = btrfs_search_slot(trans, root, key, path, 0, 1);
 145        if (ret < 0)
 146                goto out;
 147
 148        if (ret != 0) {
 149                btrfs_print_leaf(root, path->nodes[0]);
 150                printk(KERN_CRIT "unable to update root key %llu %u %llu\n",
 151                       (unsigned long long)key->objectid, key->type,
 152                       (unsigned long long)key->offset);
 153                BUG_ON(1);
 154        }
 155
 156        l = path->nodes[0];
 157        slot = path->slots[0];
 158        ptr = btrfs_item_ptr_offset(l, slot);
 159        write_extent_buffer(l, item, ptr, sizeof(*item));
 160        btrfs_mark_buffer_dirty(path->nodes[0]);
 161out:
 162        btrfs_free_path(path);
 163        return ret;
 164}
 165
 166int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
 167                      *root, struct btrfs_key *key, struct btrfs_root_item
 168                      *item)
 169{
 170        int ret;
 171        ret = btrfs_insert_item(trans, root, key, item, sizeof(*item));
 172        return ret;
 173}
 174
 175/*
 176 * at mount time we want to find all the old transaction snapshots that were in
 177 * the process of being deleted if we crashed.  This is any root item with an
 178 * offset lower than the latest root.  They need to be queued for deletion to
 179 * finish what was happening when we crashed.
 180 */
 181int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid)
 182{
 183        struct btrfs_root *dead_root;
 184        struct btrfs_item *item;
 185        struct btrfs_root_item *ri;
 186        struct btrfs_key key;
 187        struct btrfs_key found_key;
 188        struct btrfs_path *path;
 189        int ret;
 190        u32 nritems;
 191        struct extent_buffer *leaf;
 192        int slot;
 193
 194        key.objectid = objectid;
 195        btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
 196        key.offset = 0;
 197        path = btrfs_alloc_path();
 198        if (!path)
 199                return -ENOMEM;
 200
 201again:
 202        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 203        if (ret < 0)
 204                goto err;
 205        while (1) {
 206                leaf = path->nodes[0];
 207                nritems = btrfs_header_nritems(leaf);
 208                slot = path->slots[0];
 209                if (slot >= nritems) {
 210                        ret = btrfs_next_leaf(root, path);
 211                        if (ret)
 212                                break;
 213                        leaf = path->nodes[0];
 214                        nritems = btrfs_header_nritems(leaf);
 215                        slot = path->slots[0];
 216                }
 217                item = btrfs_item_nr(leaf, slot);
 218                btrfs_item_key_to_cpu(leaf, &key, slot);
 219                if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY)
 220                        goto next;
 221
 222                if (key.objectid < objectid)
 223                        goto next;
 224
 225                if (key.objectid > objectid)
 226                        break;
 227
 228                ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item);
 229                if (btrfs_disk_root_refs(leaf, ri) != 0)
 230                        goto next;
 231
 232                memcpy(&found_key, &key, sizeof(key));
 233                key.offset++;
 234                btrfs_release_path(root, path);
 235                dead_root =
 236                        btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
 237                                                    &found_key);
 238                if (IS_ERR(dead_root)) {
 239                        ret = PTR_ERR(dead_root);
 240                        goto err;
 241                }
 242
 243                ret = btrfs_add_dead_root(dead_root);
 244                if (ret)
 245                        goto err;
 246                goto again;
 247next:
 248                slot++;
 249                path->slots[0]++;
 250        }
 251        ret = 0;
 252err:
 253        btrfs_free_path(path);
 254        return ret;
 255}
 256
 257int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
 258{
 259        struct extent_buffer *leaf;
 260        struct btrfs_path *path;
 261        struct btrfs_key key;
 262        int err = 0;
 263        int ret;
 264
 265        path = btrfs_alloc_path();
 266        if (!path)
 267                return -ENOMEM;
 268
 269        key.objectid = BTRFS_ORPHAN_OBJECTID;
 270        key.type = BTRFS_ORPHAN_ITEM_KEY;
 271        key.offset = 0;
 272
 273        while (1) {
 274                ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
 275                if (ret < 0) {
 276                        err = ret;
 277                        break;
 278                }
 279
 280                leaf = path->nodes[0];
 281                if (path->slots[0] >= btrfs_header_nritems(leaf)) {
 282                        ret = btrfs_next_leaf(tree_root, path);
 283                        if (ret < 0)
 284                                err = ret;
 285                        if (ret != 0)
 286                                break;
 287                        leaf = path->nodes[0];
 288                }
 289
 290                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 291                btrfs_release_path(tree_root, path);
 292
 293                if (key.objectid != BTRFS_ORPHAN_OBJECTID ||
 294                    key.type != BTRFS_ORPHAN_ITEM_KEY)
 295                        break;
 296
 297                ret = btrfs_find_dead_roots(tree_root, key.offset);
 298                if (ret) {
 299                        err = ret;
 300                        break;
 301                }
 302
 303                key.offset++;
 304        }
 305
 306        btrfs_free_path(path);
 307        return err;
 308}
 309
 310/* drop the root item for 'key' from 'root' */
 311int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 312                   struct btrfs_key *key)
 313{
 314        struct btrfs_path *path;
 315        int ret;
 316        u32 refs;
 317        struct btrfs_root_item *ri;
 318        struct extent_buffer *leaf;
 319
 320        path = btrfs_alloc_path();
 321        BUG_ON(!path);
 322        ret = btrfs_search_slot(trans, root, key, path, -1, 1);
 323        if (ret < 0)
 324                goto out;
 325
 326        BUG_ON(ret != 0);
 327        leaf = path->nodes[0];
 328        ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item);
 329
 330        refs = btrfs_disk_root_refs(leaf, ri);
 331        BUG_ON(refs != 0);
 332        ret = btrfs_del_item(trans, root, path);
 333out:
 334        btrfs_free_path(path);
 335        return ret;
 336}
 337
 338int btrfs_del_root_ref(struct btrfs_trans_handle *trans,
 339                       struct btrfs_root *tree_root,
 340                       u64 root_id, u64 ref_id, u64 dirid, u64 *sequence,
 341                       const char *name, int name_len)
 342
 343{
 344        struct btrfs_path *path;
 345        struct btrfs_root_ref *ref;
 346        struct extent_buffer *leaf;
 347        struct btrfs_key key;
 348        unsigned long ptr;
 349        int err = 0;
 350        int ret;
 351
 352        path = btrfs_alloc_path();
 353        if (!path)
 354                return -ENOMEM;
 355
 356        key.objectid = root_id;
 357        key.type = BTRFS_ROOT_BACKREF_KEY;
 358        key.offset = ref_id;
 359again:
 360        ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
 361        BUG_ON(ret < 0);
 362        if (ret == 0) {
 363                leaf = path->nodes[0];
 364                ref = btrfs_item_ptr(leaf, path->slots[0],
 365                                     struct btrfs_root_ref);
 366
 367                WARN_ON(btrfs_root_ref_dirid(leaf, ref) != dirid);
 368                WARN_ON(btrfs_root_ref_name_len(leaf, ref) != name_len);
 369                ptr = (unsigned long)(ref + 1);
 370                WARN_ON(memcmp_extent_buffer(leaf, name, ptr, name_len));
 371                *sequence = btrfs_root_ref_sequence(leaf, ref);
 372
 373                ret = btrfs_del_item(trans, tree_root, path);
 374                BUG_ON(ret);
 375        } else
 376                err = -ENOENT;
 377
 378        if (key.type == BTRFS_ROOT_BACKREF_KEY) {
 379                btrfs_release_path(tree_root, path);
 380                key.objectid = ref_id;
 381                key.type = BTRFS_ROOT_REF_KEY;
 382                key.offset = root_id;
 383                goto again;
 384        }
 385
 386        btrfs_free_path(path);
 387        return err;
 388}
 389
 390int btrfs_find_root_ref(struct btrfs_root *tree_root,
 391                   struct btrfs_path *path,
 392                   u64 root_id, u64 ref_id)
 393{
 394        struct btrfs_key key;
 395        int ret;
 396
 397        key.objectid = root_id;
 398        key.type = BTRFS_ROOT_REF_KEY;
 399        key.offset = ref_id;
 400
 401        ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
 402        return ret;
 403}
 404
 405/*
 406 * add a btrfs_root_ref item.  type is either BTRFS_ROOT_REF_KEY
 407 * or BTRFS_ROOT_BACKREF_KEY.
 408 *
 409 * The dirid, sequence, name and name_len refer to the directory entry
 410 * that is referencing the root.
 411 *
 412 * For a forward ref, the root_id is the id of the tree referencing
 413 * the root and ref_id is the id of the subvol  or snapshot.
 414 *
 415 * For a back ref the root_id is the id of the subvol or snapshot and
 416 * ref_id is the id of the tree referencing it.
 417 */
 418int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
 419                       struct btrfs_root *tree_root,
 420                       u64 root_id, u64 ref_id, u64 dirid, u64 sequence,
 421                       const char *name, int name_len)
 422{
 423        struct btrfs_key key;
 424        int ret;
 425        struct btrfs_path *path;
 426        struct btrfs_root_ref *ref;
 427        struct extent_buffer *leaf;
 428        unsigned long ptr;
 429
 430        path = btrfs_alloc_path();
 431        if (!path)
 432                return -ENOMEM;
 433
 434        key.objectid = root_id;
 435        key.type = BTRFS_ROOT_BACKREF_KEY;
 436        key.offset = ref_id;
 437again:
 438        ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
 439                                      sizeof(*ref) + name_len);
 440        BUG_ON(ret);
 441
 442        leaf = path->nodes[0];
 443        ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
 444        btrfs_set_root_ref_dirid(leaf, ref, dirid);
 445        btrfs_set_root_ref_sequence(leaf, ref, sequence);
 446        btrfs_set_root_ref_name_len(leaf, ref, name_len);
 447        ptr = (unsigned long)(ref + 1);
 448        write_extent_buffer(leaf, name, ptr, name_len);
 449        btrfs_mark_buffer_dirty(leaf);
 450
 451        if (key.type == BTRFS_ROOT_BACKREF_KEY) {
 452                btrfs_release_path(tree_root, path);
 453                key.objectid = ref_id;
 454                key.type = BTRFS_ROOT_REF_KEY;
 455                key.offset = root_id;
 456                goto again;
 457        }
 458
 459        btrfs_free_path(path);
 460        return 0;
 461}
 462