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 <linux/uuid.h>
  20#include "ctree.h"
  21#include "transaction.h"
  22#include "disk-io.h"
  23#include "print-tree.h"
  24
  25/*
  26 * Read a root item from the tree. In case we detect a root item smaller then
  27 * sizeof(root_item), we know it's an old version of the root structure and
  28 * initialize all new fields to zero. The same happens if we detect mismatching
  29 * generation numbers as then we know the root was once mounted with an older
  30 * kernel that was not aware of the root item structure change.
  31 */
  32void btrfs_read_root_item(struct btrfs_root *root,
  33                         struct extent_buffer *eb, int slot,
  34                         struct btrfs_root_item *item)
  35{
  36        uuid_le uuid;
  37        int len;
  38        int need_reset = 0;
  39
  40        len = btrfs_item_size_nr(eb, slot);
  41        read_extent_buffer(eb, item, btrfs_item_ptr_offset(eb, slot),
  42                        min_t(int, len, (int)sizeof(*item)));
  43        if (len < sizeof(*item))
  44                need_reset = 1;
  45        if (!need_reset && btrfs_root_generation(item)
  46                != btrfs_root_generation_v2(item)) {
  47                if (btrfs_root_generation_v2(item) != 0) {
  48                        printk(KERN_WARNING "btrfs: mismatching "
  49                                        "generation and generation_v2 "
  50                                        "found in root item. This root "
  51                                        "was probably mounted with an "
  52                                        "older kernel. Resetting all "
  53                                        "new fields.\n");
  54                }
  55                need_reset = 1;
  56        }
  57        if (need_reset) {
  58                memset(&item->generation_v2, 0,
  59                        sizeof(*item) - offsetof(struct btrfs_root_item,
  60                                        generation_v2));
  61
  62                uuid_le_gen(&uuid);
  63                memcpy(item->uuid, uuid.b, BTRFS_UUID_SIZE);
  64        }
  65}
  66
  67/*
  68 * lookup the root with the highest offset for a given objectid.  The key we do
  69 * find is copied into 'key'.  If we find something return 0, otherwise 1, < 0
  70 * on error.
  71 */
  72int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
  73                        struct btrfs_root_item *item, struct btrfs_key *key)
  74{
  75        struct btrfs_path *path;
  76        struct btrfs_key search_key;
  77        struct btrfs_key found_key;
  78        struct extent_buffer *l;
  79        int ret;
  80        int slot;
  81
  82        search_key.objectid = objectid;
  83        search_key.type = BTRFS_ROOT_ITEM_KEY;
  84        search_key.offset = (u64)-1;
  85
  86        path = btrfs_alloc_path();
  87        if (!path)
  88                return -ENOMEM;
  89        ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
  90        if (ret < 0)
  91                goto out;
  92
  93        BUG_ON(ret == 0);
  94        if (path->slots[0] == 0) {
  95                ret = 1;
  96                goto out;
  97        }
  98        l = path->nodes[0];
  99        slot = path->slots[0] - 1;
 100        btrfs_item_key_to_cpu(l, &found_key, slot);
 101        if (found_key.objectid != objectid ||
 102            found_key.type != BTRFS_ROOT_ITEM_KEY) {
 103                ret = 1;
 104                goto out;
 105        }
 106        if (item)
 107                btrfs_read_root_item(root, l, slot, item);
 108        if (key)
 109                memcpy(key, &found_key, sizeof(found_key));
 110
 111        ret = 0;
 112out:
 113        btrfs_free_path(path);
 114        return ret;
 115}
 116
 117void btrfs_set_root_node(struct btrfs_root_item *item,
 118                         struct extent_buffer *node)
 119{
 120        btrfs_set_root_bytenr(item, node->start);
 121        btrfs_set_root_level(item, btrfs_header_level(node));
 122        btrfs_set_root_generation(item, btrfs_header_generation(node));
 123}
 124
 125/*
 126 * copy the data in 'item' into the btree
 127 */
 128int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
 129                      *root, struct btrfs_key *key, struct btrfs_root_item
 130                      *item)
 131{
 132        struct btrfs_path *path;
 133        struct extent_buffer *l;
 134        int ret;
 135        int slot;
 136        unsigned long ptr;
 137        int old_len;
 138
 139        path = btrfs_alloc_path();
 140        if (!path)
 141                return -ENOMEM;
 142
 143        ret = btrfs_search_slot(trans, root, key, path, 0, 1);
 144        if (ret < 0) {
 145                btrfs_abort_transaction(trans, root, ret);
 146                goto out;
 147        }
 148
 149        if (ret != 0) {
 150                btrfs_print_leaf(root, path->nodes[0]);
 151                printk(KERN_CRIT "unable to update root key %llu %u %llu\n",
 152                       (unsigned long long)key->objectid, key->type,
 153                       (unsigned long long)key->offset);
 154                BUG_ON(1);
 155        }
 156
 157        l = path->nodes[0];
 158        slot = path->slots[0];
 159        ptr = btrfs_item_ptr_offset(l, slot);
 160        old_len = btrfs_item_size_nr(l, slot);
 161
 162        /*
 163         * If this is the first time we update the root item which originated
 164         * from an older kernel, we need to enlarge the item size to make room
 165         * for the added fields.
 166         */
 167        if (old_len < sizeof(*item)) {
 168                btrfs_release_path(path);
 169                ret = btrfs_search_slot(trans, root, key, path,
 170                                -1, 1);
 171                if (ret < 0) {
 172                        btrfs_abort_transaction(trans, root, ret);
 173                        goto out;
 174                }
 175
 176                ret = btrfs_del_item(trans, root, path);
 177                if (ret < 0) {
 178                        btrfs_abort_transaction(trans, root, ret);
 179                        goto out;
 180                }
 181                btrfs_release_path(path);
 182                ret = btrfs_insert_empty_item(trans, root, path,
 183                                key, sizeof(*item));
 184                if (ret < 0) {
 185                        btrfs_abort_transaction(trans, root, ret);
 186                        goto out;
 187                }
 188                l = path->nodes[0];
 189                slot = path->slots[0];
 190                ptr = btrfs_item_ptr_offset(l, slot);
 191        }
 192
 193        /*
 194         * Update generation_v2 so at the next mount we know the new root
 195         * fields are valid.
 196         */
 197        btrfs_set_root_generation_v2(item, btrfs_root_generation(item));
 198
 199        write_extent_buffer(l, item, ptr, sizeof(*item));
 200        btrfs_mark_buffer_dirty(path->nodes[0]);
 201out:
 202        btrfs_free_path(path);
 203        return ret;
 204}
 205
 206int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 207                      struct btrfs_key *key, struct btrfs_root_item *item)
 208{
 209        /*
 210         * Make sure generation v1 and v2 match. See update_root for details.
 211         */
 212        btrfs_set_root_generation_v2(item, btrfs_root_generation(item));
 213        return btrfs_insert_item(trans, root, key, item, sizeof(*item));
 214}
 215
 216/*
 217 * at mount time we want to find all the old transaction snapshots that were in
 218 * the process of being deleted if we crashed.  This is any root item with an
 219 * offset lower than the latest root.  They need to be queued for deletion to
 220 * finish what was happening when we crashed.
 221 */
 222int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid)
 223{
 224        struct btrfs_root *dead_root;
 225        struct btrfs_root_item *ri;
 226        struct btrfs_key key;
 227        struct btrfs_key found_key;
 228        struct btrfs_path *path;
 229        int ret;
 230        u32 nritems;
 231        struct extent_buffer *leaf;
 232        int slot;
 233
 234        key.objectid = objectid;
 235        btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
 236        key.offset = 0;
 237        path = btrfs_alloc_path();
 238        if (!path)
 239                return -ENOMEM;
 240
 241again:
 242        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 243        if (ret < 0)
 244                goto err;
 245        while (1) {
 246                leaf = path->nodes[0];
 247                nritems = btrfs_header_nritems(leaf);
 248                slot = path->slots[0];
 249                if (slot >= nritems) {
 250                        ret = btrfs_next_leaf(root, path);
 251                        if (ret)
 252                                break;
 253                        leaf = path->nodes[0];
 254                        nritems = btrfs_header_nritems(leaf);
 255                        slot = path->slots[0];
 256                }
 257                btrfs_item_key_to_cpu(leaf, &key, slot);
 258                if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY)
 259                        goto next;
 260
 261                if (key.objectid < objectid)
 262                        goto next;
 263
 264                if (key.objectid > objectid)
 265                        break;
 266
 267                ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item);
 268                if (btrfs_disk_root_refs(leaf, ri) != 0)
 269                        goto next;
 270
 271                memcpy(&found_key, &key, sizeof(key));
 272                key.offset++;
 273                btrfs_release_path(path);
 274                dead_root =
 275                        btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
 276                                                    &found_key);
 277                if (IS_ERR(dead_root)) {
 278                        ret = PTR_ERR(dead_root);
 279                        goto err;
 280                }
 281
 282                ret = btrfs_add_dead_root(dead_root);
 283                if (ret)
 284                        goto err;
 285                goto again;
 286next:
 287                slot++;
 288                path->slots[0]++;
 289        }
 290        ret = 0;
 291err:
 292        btrfs_free_path(path);
 293        return ret;
 294}
 295
 296int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
 297{
 298        struct extent_buffer *leaf;
 299        struct btrfs_path *path;
 300        struct btrfs_key key;
 301        struct btrfs_key root_key;
 302        struct btrfs_root *root;
 303        int err = 0;
 304        int ret;
 305
 306        path = btrfs_alloc_path();
 307        if (!path)
 308                return -ENOMEM;
 309
 310        key.objectid = BTRFS_ORPHAN_OBJECTID;
 311        key.type = BTRFS_ORPHAN_ITEM_KEY;
 312        key.offset = 0;
 313
 314        root_key.type = BTRFS_ROOT_ITEM_KEY;
 315        root_key.offset = (u64)-1;
 316
 317        while (1) {
 318                ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
 319                if (ret < 0) {
 320                        err = ret;
 321                        break;
 322                }
 323
 324                leaf = path->nodes[0];
 325                if (path->slots[0] >= btrfs_header_nritems(leaf)) {
 326                        ret = btrfs_next_leaf(tree_root, path);
 327                        if (ret < 0)
 328                                err = ret;
 329                        if (ret != 0)
 330                                break;
 331                        leaf = path->nodes[0];
 332                }
 333
 334                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 335                btrfs_release_path(path);
 336
 337                if (key.objectid != BTRFS_ORPHAN_OBJECTID ||
 338                    key.type != BTRFS_ORPHAN_ITEM_KEY)
 339                        break;
 340
 341                root_key.objectid = key.offset;
 342                key.offset++;
 343
 344                root = btrfs_read_fs_root_no_name(tree_root->fs_info,
 345                                                  &root_key);
 346                if (!IS_ERR(root))
 347                        continue;
 348
 349                ret = PTR_ERR(root);
 350                if (ret != -ENOENT) {
 351                        err = ret;
 352                        break;
 353                }
 354
 355                ret = btrfs_find_dead_roots(tree_root, root_key.objectid);
 356                if (ret) {
 357                        err = ret;
 358                        break;
 359                }
 360        }
 361
 362        btrfs_free_path(path);
 363        return err;
 364}
 365
 366/* drop the root item for 'key' from 'root' */
 367int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 368                   struct btrfs_key *key)
 369{
 370        struct btrfs_path *path;
 371        int ret;
 372        struct btrfs_root_item *ri;
 373        struct extent_buffer *leaf;
 374
 375        path = btrfs_alloc_path();
 376        if (!path)
 377                return -ENOMEM;
 378        ret = btrfs_search_slot(trans, root, key, path, -1, 1);
 379        if (ret < 0)
 380                goto out;
 381
 382        BUG_ON(ret != 0);
 383        leaf = path->nodes[0];
 384        ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item);
 385
 386        ret = btrfs_del_item(trans, root, path);
 387out:
 388        btrfs_free_path(path);
 389        return ret;
 390}
 391
 392int btrfs_del_root_ref(struct btrfs_trans_handle *trans,
 393                       struct btrfs_root *tree_root,
 394                       u64 root_id, u64 ref_id, u64 dirid, u64 *sequence,
 395                       const char *name, int name_len)
 396
 397{
 398        struct btrfs_path *path;
 399        struct btrfs_root_ref *ref;
 400        struct extent_buffer *leaf;
 401        struct btrfs_key key;
 402        unsigned long ptr;
 403        int err = 0;
 404        int ret;
 405
 406        path = btrfs_alloc_path();
 407        if (!path)
 408                return -ENOMEM;
 409
 410        key.objectid = root_id;
 411        key.type = BTRFS_ROOT_BACKREF_KEY;
 412        key.offset = ref_id;
 413again:
 414        ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
 415        BUG_ON(ret < 0);
 416        if (ret == 0) {
 417                leaf = path->nodes[0];
 418                ref = btrfs_item_ptr(leaf, path->slots[0],
 419                                     struct btrfs_root_ref);
 420
 421                WARN_ON(btrfs_root_ref_dirid(leaf, ref) != dirid);
 422                WARN_ON(btrfs_root_ref_name_len(leaf, ref) != name_len);
 423                ptr = (unsigned long)(ref + 1);
 424                WARN_ON(memcmp_extent_buffer(leaf, name, ptr, name_len));
 425                *sequence = btrfs_root_ref_sequence(leaf, ref);
 426
 427                ret = btrfs_del_item(trans, tree_root, path);
 428                if (ret) {
 429                        err = ret;
 430                        goto out;
 431                }
 432        } else
 433                err = -ENOENT;
 434
 435        if (key.type == BTRFS_ROOT_BACKREF_KEY) {
 436                btrfs_release_path(path);
 437                key.objectid = ref_id;
 438                key.type = BTRFS_ROOT_REF_KEY;
 439                key.offset = root_id;
 440                goto again;
 441        }
 442
 443out:
 444        btrfs_free_path(path);
 445        return err;
 446}
 447
 448int btrfs_find_root_ref(struct btrfs_root *tree_root,
 449                   struct btrfs_path *path,
 450                   u64 root_id, u64 ref_id)
 451{
 452        struct btrfs_key key;
 453        int ret;
 454
 455        key.objectid = root_id;
 456        key.type = BTRFS_ROOT_REF_KEY;
 457        key.offset = ref_id;
 458
 459        ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
 460        return ret;
 461}
 462
 463/*
 464 * add a btrfs_root_ref item.  type is either BTRFS_ROOT_REF_KEY
 465 * or BTRFS_ROOT_BACKREF_KEY.
 466 *
 467 * The dirid, sequence, name and name_len refer to the directory entry
 468 * that is referencing the root.
 469 *
 470 * For a forward ref, the root_id is the id of the tree referencing
 471 * the root and ref_id is the id of the subvol  or snapshot.
 472 *
 473 * For a back ref the root_id is the id of the subvol or snapshot and
 474 * ref_id is the id of the tree referencing it.
 475 *
 476 * Will return 0, -ENOMEM, or anything from the CoW path
 477 */
 478int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
 479                       struct btrfs_root *tree_root,
 480                       u64 root_id, u64 ref_id, u64 dirid, u64 sequence,
 481                       const char *name, int name_len)
 482{
 483        struct btrfs_key key;
 484        int ret;
 485        struct btrfs_path *path;
 486        struct btrfs_root_ref *ref;
 487        struct extent_buffer *leaf;
 488        unsigned long ptr;
 489
 490        path = btrfs_alloc_path();
 491        if (!path)
 492                return -ENOMEM;
 493
 494        key.objectid = root_id;
 495        key.type = BTRFS_ROOT_BACKREF_KEY;
 496        key.offset = ref_id;
 497again:
 498        ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
 499                                      sizeof(*ref) + name_len);
 500        if (ret) {
 501                btrfs_abort_transaction(trans, tree_root, ret);
 502                btrfs_free_path(path);
 503                return ret;
 504        }
 505
 506        leaf = path->nodes[0];
 507        ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
 508        btrfs_set_root_ref_dirid(leaf, ref, dirid);
 509        btrfs_set_root_ref_sequence(leaf, ref, sequence);
 510        btrfs_set_root_ref_name_len(leaf, ref, name_len);
 511        ptr = (unsigned long)(ref + 1);
 512        write_extent_buffer(leaf, name, ptr, name_len);
 513        btrfs_mark_buffer_dirty(leaf);
 514
 515        if (key.type == BTRFS_ROOT_BACKREF_KEY) {
 516                btrfs_release_path(path);
 517                key.objectid = ref_id;
 518                key.type = BTRFS_ROOT_REF_KEY;
 519                key.offset = root_id;
 520                goto again;
 521        }
 522
 523        btrfs_free_path(path);
 524        return 0;
 525}
 526
 527/*
 528 * Old btrfs forgets to init root_item->flags and root_item->byte_limit
 529 * for subvolumes. To work around this problem, we steal a bit from
 530 * root_item->inode_item->flags, and use it to indicate if those fields
 531 * have been properly initialized.
 532 */
 533void btrfs_check_and_init_root_item(struct btrfs_root_item *root_item)
 534{
 535        u64 inode_flags = le64_to_cpu(root_item->inode.flags);
 536
 537        if (!(inode_flags & BTRFS_INODE_ROOT_ITEM_INIT)) {
 538                inode_flags |= BTRFS_INODE_ROOT_ITEM_INIT;
 539                root_item->inode.flags = cpu_to_le64(inode_flags);
 540                root_item->flags = 0;
 541                root_item->byte_limit = 0;
 542        }
 543}
 544
 545void btrfs_update_root_times(struct btrfs_trans_handle *trans,
 546                             struct btrfs_root *root)
 547{
 548        struct btrfs_root_item *item = &root->root_item;
 549        struct timespec ct = CURRENT_TIME;
 550
 551        spin_lock(&root->root_times_lock);
 552        item->ctransid = cpu_to_le64(trans->transid);
 553        item->ctime.sec = cpu_to_le64(ct.tv_sec);
 554        item->ctime.nsec = cpu_to_le32(ct.tv_nsec);
 555        spin_unlock(&root->root_times_lock);
 556}
 557
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.